Skip to content

fix(core): convert media blocks to text placeholders during compression (Fixes #1875)#1892

Merged
acoliver merged 4 commits intomainfrom
issue1875
Apr 10, 2026
Merged

fix(core): convert media blocks to text placeholders during compression (Fixes #1875)#1892
acoliver merged 4 commits intomainfrom
issue1875

Conversation

@acoliver
Copy link
Copy Markdown
Collaborator

@acoliver acoliver commented Apr 7, 2026

Summary

Fixes issue #1875 where Kimi compression fails with 400 error when media blocks (like PDFs) are sent during compression.

Problem

The error 400 the message at position 25 with role 'user' contains an invalid part type: file occurs during middle-out compression. This happens because sanitizeHistoryForCompression() converts tool blocks to text but passes media blocks through unchanged. When these reach Kimi via OpenAIRequestBuilder.ts, PDF media blocks get converted to type: 'file' parts that Kimi does not support.

Solution

Extend sanitizeHistoryForCompression() to convert media blocks to concise text placeholders, similar to how it handles tool blocks.

Changes

Task 1: mediaBlockToCompressionPlaceholder() helper

  • Import classifyMediaBlock from ../../providers/utils/mediaUtils.js
  • Create new helper function that:
    • Takes a MediaBlock as input
    • Uses classifyMediaBlock() to determine category (image, pdf, audio, video, unknown)
    • Returns placeholder text in format [Attached <category>: <filename or mimeType>]
    • Uses media.filename if available, otherwise uses media.mimeType

Task 2: Update sanitizeHistoryForCompression()

  • Modified hasToolBlocks detection to also check for media blocks: b.type === 'media'
  • In block transformation logic, added case for block.type === 'media' that:
    • Converts media block to text block using mediaBlockToCompressionPlaceholder()
    • Follows same pattern as existing tool block conversions
  • Updated comment to reflect media block handling

Task 3: Behavioral tests (TDD)

Added 7 new tests to utils.test.ts:

  • Media block with filename (e.g., [Attached PDF: document.pdf])
  • Media block without filename uses mimeType (e.g., [Attached image: image/png])
  • Different media categories (image, pdf, audio, video, unknown)
  • Mixed content with text + media blocks in same message
  • Messages with only media blocks get converted properly
  • Media block messages do not have speaker changed (unlike tool messages)
  • Mixed tool and media blocks in same message

Verification

  • npm run test - All tests pass (9417 passed, 33 skipped)
  • npm run lint - No new errors (59 pre-existing warnings in modified files)
  • npm run typecheck - No TypeScript errors in core package
  • npm run format - Code properly formatted
  • npm run build - Build succeeds
  • node scripts/start.js --profile-load synthetic "write me a haiku and nothing else" - Smoke test passes

Why This Fix Is Provider-Agnostic

The fix benefits any provider that may not support certain media types during compression. While the issue was specifically reported for Kimi (which doesn't support PDF file parts), the same pattern applies to any provider with similar limitations. The actual media data isn't necessary for the compression LLM to understand conversation context for summarization.

…on (Fixes #1875)

Extend sanitizeHistoryForCompression() to handle media blocks by converting
them to concise text placeholders, preventing unsupported media types
(e.g., PDF file parts) from reaching the compression LLM call.

Changes:
- Add mediaBlockToCompressionPlaceholder() helper that uses classifyMediaBlock()
  to generate format [Attached <category>: <filename or mimeType>]
- Update sanitizeHistoryForCompression() to detect and convert media blocks
  alongside existing tool block conversion
- Media block messages keep their original speaker (unlike tool messages)
- Add 7 new behavioral tests for media block handling

This fix is provider-agnostic and benefits any provider that may not support
certain media types (like PDFs) during compression, specifically addressing
the Kimi 400 error: 'invalid part type: file'.
@github-actions github-actions bot added the maintainer:e2e:ok Trusted contributor; maintainer-approved E2E run label Apr 7, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 86b4a72c-a330-45a5-96ed-c3b974aa18df

📥 Commits

Reviewing files that changed from the base of the PR and between 2b08b42 and 11dd8b8.

📒 Files selected for processing (1)
  • packages/core/src/core/compression/utils.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 270000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: E2E Test (Linux) - sandbox:none
  • GitHub Check: E2E Test (Linux) - sandbox:docker
  • GitHub Check: E2E Test (macOS)
  • GitHub Check: Lint (Javascript)
🧰 Additional context used
🧠 Learnings (27)
📓 Common learnings
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1790
File: packages/core/src/core/compression/MiddleOutStrategy.ts:307-325
Timestamp: 2026-03-27T01:40:09.382Z
Learning: In `packages/core/src/core/compression/MiddleOutStrategy.ts` (vybestack/llxprt-code), `IContent` messages with `speaker === 'human'` contain only `TextBlock` types by definition in the conversation model. Tool call and tool response blocks appear exclusively on `speaker === 'ai'` and `speaker === 'tool'` messages. Therefore, `extractTextFromMessage` (which filters for `TextBlock`) captures the full content of any human message, and calling `estimateTokens` on its output is a complete token estimate for human messages. Do not flag token estimation for human messages as incomplete due to missing non-text block handling.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/anthropic/AnthropicProvider.ts:1233-1293
Timestamp: 2026-02-28T20:19:36.726Z
Learning: In the llxprt-code IContent model (packages/core/src/providers/anthropic/AnthropicProvider.ts and related message processing), each tool speaker message (IContent with speaker='tool') contains exactly one tool_response block plus its associated media blocks. Multiple tool responses are always separate IContent entries. This structural constraint is enforced by the message format, so code that filters toolResponseBlocks from a single IContent and iterates over them will only process one tool_response per iteration.
📚 Learning: 2026-03-27T01:40:09.382Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1790
File: packages/core/src/core/compression/MiddleOutStrategy.ts:307-325
Timestamp: 2026-03-27T01:40:09.382Z
Learning: In `packages/core/src/core/compression/MiddleOutStrategy.ts` (vybestack/llxprt-code), `IContent` messages with `speaker === 'human'` contain only `TextBlock` types by definition in the conversation model. Tool call and tool response blocks appear exclusively on `speaker === 'ai'` and `speaker === 'tool'` messages. Therefore, `extractTextFromMessage` (which filters for `TextBlock`) captures the full content of any human message, and calling `estimateTokens` on its output is a complete token estimate for human messages. Do not flag token estimation for human messages as incomplete due to missing non-text block handling.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-22T04:07:00.235Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T03:22:51.631Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T15:17:37.899Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:410-421
Timestamp: 2026-03-21T15:17:37.899Z
Learning: In `packages/core/src/core/TurnProcessor.ts` and `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1743`), both classes maintain a `lastPromptTokenCount` field. After the decomposition of `geminiChat.ts`, `TurnProcessor._executeProviderCall` must update both `this.lastPromptTokenCount` AND `this.compressionHandler.lastPromptTokenCount` (via `setLastPromptTokenCount`) whenever prompt token counts are received from the non-streaming provider response. The streaming path in `StreamProcessor` already updates `compressionHandler.lastPromptTokenCount` directly. Do not flag the dual-update pattern as redundant — `CompressionHandler.shouldCompress()` reads its own field and will use stale data if only `TurnProcessor.lastPromptTokenCount` is updated. Fixed in commit bac2e4153.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T03:23:48.264Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:297-315
Timestamp: 2026-03-21T03:23:48.264Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code PR `#1743`), `convertAllFunctionResponses` intentionally packs all `functionResponse` parts into a single `IContent` with `speaker='tool'` and multiple `tool_response` blocks. This is faithfully preserved from the original `convertPartListUnionToIContent` method in `geminiChat.ts` (pre-refactor, commit 71e63cb4, lines ~2984-3001). Do not flag this as incorrect multi-block packing — it is the established upstream behavior for this input-conversion path.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-29T05:46:51.084Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1827
File: packages/core/src/core/compression/CompressionHandler.ts:714-722
Timestamp: 2026-03-29T05:46:51.084Z
Learning: In `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1827`), `lastSuccessfulCompressionTime` is intentionally set in two places when fallback compression succeeds via `runCompressionWithRetryAndFallback`: once inside `performFallbackCompression` (needed for the `forceTruncationIfIneffective`-only call path) and once in `performCompression` after `runCompressionWithRetryAndFallback` returns. The duplicate assignment is harmless (both use `Date.now()`) and is deliberately left without extra branching or flags to keep the code simple. Do not flag this dual assignment as a redundancy in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T17:57:00.539Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts:294-305
Timestamp: 2026-03-21T17:57:00.539Z
Learning: In `packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts` (vybestack/llxprt-code PR `#1740`), `blocksToText` and `concatenateTextAndCodeBlocks` are intentionally kept as separate functions. They serve different callers with different contracts: `blocksToText` uses string concatenation and calls `trimStart()` on the result, while `concatenateTextAndCodeBlocks` uses an array+join pattern and guards against null `block.text`. Consolidating them is out of scope for the decomposition PR and should be done as a dedicated follow-up if desired. Do not flag this duplication in future decomposition reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T15:59:45.670Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/utils/toolIdNormalization.ts:98-121
Timestamp: 2026-03-21T15:59:45.670Z
Learning: In `packages/core/src/providers/utils/toolIdNormalization.ts` (vybestack/llxprt-code PR `#1740`), `normalizeToAnthropicToolId` handles empty/falsy input by returning the deterministic constant `'toolu_empty'` and logging via `debugLogger.error(...)`. This path is unreachable in practice because all IDs first pass through `normalizeToHistoryToolId` (which maps empty → `hist_tool_`, then caught by the `hist_tool_` prefix handler), but the error log surfaces it if a provider ever returns an empty tool call ID. Do not suggest a random/hash-based fallback — that was a prior bug (pairing hazard: tool_use and tool_result calling separately would get different IDs). Fixed in commit adc8e9d.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-26T03:04:09.288Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentRuntimeSetup.ts:198-208
Timestamp: 2026-03-26T03:04:09.288Z
Learning: In `packages/core/src/core/subagentRuntimeSetup.ts` (vybestack/llxprt-code PR `#1779`), `applyToolWhitelistToEphemerals` treats an explicit empty `ephemerals['tools.allowed']` array as "no restriction" (falling back to `normalizedWhitelist`) because it checks `existingAllowed.length > 0` rather than `Array.isArray(ephemerals['tools.allowed'])`. This is pre-existing behavior faithfully preserved from the original `subagent.ts` (~line 370). Do not flag the empty-allowlist pass-through as a bug in decomposition or refactoring PRs — any fix to distinguish "absent" from "explicitly empty" would be a behavioral change requiring a dedicated follow-up PR.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-25T12:57:45.842Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1768
File: packages/cli/src/ui/containers/AppContainer/hooks/useModelRuntimeSync.ts:35-38
Timestamp: 2026-03-25T12:57:45.842Z
Learning: In `packages/cli/src/ui/containers/AppContainer/hooks/useModelRuntimeSync.ts` (vybestack/llxprt-code PR `#1768`), the pattern `providerModel && providerModel.trim() !== '' ? providerModel : configModel` (checking trim() for emptiness but assigning the untrimmed value) is intentional pre-existing behavior moved verbatim from the original `AppContainer.tsx`. Do not flag the lack of normalization (using the trimmed value as `effectiveModel`) as a whitespace propagation bug in decomposition or future PRs — any fix would be a behavioral change beyond the refactoring scope.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-26T03:06:11.693Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentRuntimeSetup.ts:198-208
Timestamp: 2026-03-26T03:06:11.693Z
Learning: In `packages/core/src/core/subagentRuntimeSetup.ts` (vybestack/llxprt-code PR `#1779`), `applyToolWhitelistToEphemerals` treats an explicit empty `ephemerals['tools.allowed']` array as "no restriction" (falling back to `normalizedWhitelist`) because it checks `existingAllowed.length > 0` rather than `Array.isArray(ephemerals['tools.allowed'])`. This is pre-existing behavior faithfully preserved from the original `subagent.ts` `createToolExecutionConfig` function (lines 322–331 on main, ~line 370 of the monolith). Do not flag the empty-allowlist pass-through as a bug in decomposition or refactoring PRs — any fix to distinguish "absent" from "explicitly empty" would be a behavioral change requiring a dedicated follow-up PR.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-01T17:19:16.202Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/openai-responses/buildResponsesInputFromContent.ts:64-77
Timestamp: 2026-03-01T17:19:16.202Z
Learning: In llxprt-code, MediaBlock instances in the pipeline (from fileUtils, ContentConverters, etc.) use canonically lowercase MIME types per RFC 2045. MIME type normalization is enforced at the content creation layer, so case-insensitive MIME type checks (e.g., `mimeType.toLowerCase().startsWith('image/')`) are not needed in provider code. Cross-cutting MIME type normalization would be a separate architectural concern.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T23:27:48.657Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:358-359
Timestamp: 2026-03-19T23:27:48.657Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (vybestack/llxprt-code), `state.accumulatedText` is incremented with raw delta content before Kimi/tool-call markup or `<think>` content is stripped, and the `requestContinuation()` guards check `accumulatedText.length === 0` and `accumulatedReasoningContent.length === 0`. This is intentional pre-existing behavior faithfully preserved from the original `generatePipelineChatCompletionImpl` (lines 1824, 2019, 2542-2544, 2597-2600 in the legacy file). Do not flag this as a bug or suggest replacing these guards with a `hasVisibleText` flag tracking only yielded TextBlocks — any such change would be a behavioral modification, not a refactoring, and is out of scope for extraction PRs.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-27T19:31:13.642Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1797
File: packages/cli/src/ui/utils/highlight.ts:43-45
Timestamp: 2026-03-27T19:31:13.642Z
Learning: In `packages/cli/src/ui/utils/highlight.ts` (vybestack/llxprt-code PR `#1797`), the `highlightCache` cache key intentionally omits the `transformations` payload (only encoding `index`, `isCursorInsideTransform`, `cursorCol`, and `text`). Including the full transformations serialization was deferred due to hot-path performance tradeoffs; it should only be revisited with benchmark-backed evidence when real incorrect-highlighting reports are observed. Do not re-flag the missing transformations in the cache key in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-26T20:52:08.720Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1780
File: packages/cli/src/ui/hooks/geminiStream/useStreamEventHandlers.ts:140-149
Timestamp: 2026-03-26T20:52:08.720Z
Learning: In `packages/cli/src/ui/hooks/geminiStream/useStreamEventHandlers.ts` (vybestack/llxprt-code PR `#1780`), the `applyThoughtToState` function's `setPendingHistoryItem` updater casts `item?.type as 'gemini' | 'gemini_content'` and uses `item?.text || ''` — this is intentional pre-existing behavior faithfully extracted verbatim from the original `useGeminiStream.ts` (lines 1110–1111 on main). The risk that a `tool_group` pending item type could be preserved is a known pre-existing pattern; fixing it requires careful testing of all thinking block rendering paths and is a behavioral change beyond decomposition scope. Do not flag this type cast as a bug in decomposition or refactoring PRs.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-13T14:32:11.331Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-13T14:32:11.331Z
Learning: In `packages/core/src/core/geminiChat.ts`, the `convertIContentToResponse` function already converts `ThinkingBlock` to `ThoughtPart` with `thought: true` (around line 3095). However, the `text` getter on the returned response object uses `parts.find((p) => 'text' in p)?.text`, which incorrectly matches `ThoughtPart` first (since `ThoughtPart` also has a `text` property) when Anthropic thinking blocks appear before text blocks. This causes the actual response text to not be surfaced. The fix is to exclude thought parts: `parts.find((p) => 'text' in p && !(p as ThoughtPart).thought)?.text || ''`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-24T21:07:40.805Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1767
File: packages/cli/src/ui/components/shared/golden-snapshot.test.ts:64-65
Timestamp: 2026-03-24T21:07:40.805Z
Learning: In `packages/cli/src/ui/components/shared/golden-snapshot.test.ts` (vybestack/llxprt-code PR `#1767`), `parseAction` uses `actionStr.split(':')` to parse action corpus entries. The action corpus (`project-plans/issue1577/action-corpus.json`) has been confirmed to contain zero multi-colon action strings, so the current two-element destructuring is correct for all existing entries. Do not flag this as a truncation bug in future reviews — the corpus format is validated and the parsing matches it.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-28T20:19:36.726Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/anthropic/AnthropicProvider.ts:1233-1293
Timestamp: 2026-02-28T20:19:36.726Z
Learning: In the llxprt-code IContent model (packages/core/src/providers/anthropic/AnthropicProvider.ts and related message processing), each tool speaker message (IContent with speaker='tool') contains exactly one tool_response block plus its associated media blocks. Multiple tool responses are always separate IContent entries. This structural constraint is enforced by the message format, so code that filters toolResponseBlocks from a single IContent and iterates over them will only process one tool_response per iteration.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-01-13T19:28:00.789Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-01-13T19:28:00.789Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/anthropic/AnthropicProvider.ts`), Anthropic's API returns `contentBlock.input` as an already-parsed JavaScript object, not a JSON string. The code was incorrectly calling `JSON.stringify(contentBlock.input)` before passing it to `processToolParameters()`, which was designed for OpenAI-style string parameters. This causes arrays and other complex types to be corrupted into strings (e.g., `paths` array becomes a string `"[\"**/*.toml\"]"` instead of actual array). The fix is to use `contentBlock.input` directly without stringifying for Anthropic provider.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-31T15:03:03.633Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-31T15:03:03.633Z
Learning: In vybestack/llxprt-code, `buildContinuationMessages` in `packages/core/src/providers/openai/OpenAIRequestBuilder.ts` (line 524) always appends `{ role: 'assistant', tool_calls: toolCalls }` to the history. Passing an empty `[]` array produces an invalid assistant message with `tool_calls: []` that most OpenAI-compatible APIs reject with HTTP 400. Do NOT call `requestContinuationAfterToolCalls` with an empty tool calls array for thinking-only continuation — a separate `requestContinuationAfterThinking` method is needed.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T22:50:00.853Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIRequestBuilder.test.ts:316-395
Timestamp: 2026-03-19T22:50:00.853Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/openai/OpenAIRequestBuilder.ts`, previously `OpenAIProvider.ts` around line 1250), `validateToolMessageSequence` intentionally does NOT deduplicate tool messages by `tool_call_id`. Contiguous tool messages sharing the same `tool_call_id` are legitimate in conversation history (e.g., replay artifacts or adapter-level splitting across message boundaries). The function only removes *orphaned* tool messages (those whose `tool_call_id` does not match any declared tool call in the preceding assistant message). Eager deduplication of same-id tool messages has historically caused strict-provider HTTP 400 errors and must not be introduced.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T23:27:48.689Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:110-123
Timestamp: 2026-03-19T23:27:48.689Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (extracted from the original `generatePipelineChatCompletionImpl` in `OpenAIProvider.ts`, lines 2050-2160), text-parsed tool calls from `extractKimiToolCallsFromText()` and `deps.textToolParser.parse()` (GemmaToolCallParser) are intentionally yielded directly as `ToolCallBlock[]` without being routed through `deps.toolCallPipeline.addFragment()`. The `toolCallPipeline` is exclusively used for delta-based streaming tool calls coming from the OpenAI API. This two-path design is deliberate — do not flag missing `addFragment()` calls for text-parsed tool calls as a bug.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-06T15:52:42.315Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1305
File: scripts/generate-keybindings-doc.ts:1-5
Timestamp: 2026-02-06T15:52:42.315Z
Learning: In reviews of vybestack/llxprt-code, do not suggest changing existing copyright headers from 'Google LLC' to 'Vybestack LLC' for files that originated from upstream. Preserve upstream copyrights in files that came from upstream, and only apply 'Vybestack LLC' copyright on newly created, original LLxprt files. If a file is clearly LLxprt-original, it may carry the Vybestack header; if it is upstream-originated, keep the original sponsor header.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-15T21:44:56.598Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1407
File: packages/core/src/core/geminiChatHookTriggers.ts:56-65
Timestamp: 2026-02-15T21:44:56.598Z
Learning: Enforce the canonical speaker-to-role mapping used by GeminiChat hooks: in IContent.speaker, which is strictly typed as 'human | ai | tool' (no 'system'), map 'human' to the 'user' role, 'ai' to the 'model' role, and 'tool' to the 'user' role in all hook payloads. This pattern should be applied across related hook files within packages/core/src/core/ (not just the single file) to ensure consistent role assignment.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-16T19:18:56.265Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1436
File: packages/core/src/core/nonInteractiveToolExecutor.ts:0-0
Timestamp: 2026-02-16T19:18:56.265Z
Learning: Guideline: In the core scheduler architecture, the system runs in a single mode at a time—either interactive or non-interactive, never both on the same scheduler instance. Non-interactive (CLI one-shot) runs without any interactive session; interactive mode subagents run within the parent's interactive context and inherit its mode. When reviewing code, ensure non-interactive tool executions (e.g., in nonInteractiveToolExecutor.ts) create and use a fresh completionResolver per executeToolCall, and that there is no race with interactive sessions since they cannot coexist on the same scheduler instance. This pattern applies across files in packages/core/src/core/. Only apply to relevant files, not globally.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-31T02:12:43.093Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1854
File: packages/core/src/core/subagentRuntimeSetup.test.ts:77-84
Timestamp: 2026-03-31T02:12:43.093Z
Learning: In this codebase, tool declarations should follow the single required contract `parametersJsonSchema`; do not ask to preserve or reintroduce the legacy `parameters` fallback field. Reviewers should not flag assertions/checks for missing `parameters` or suggest backward-compatibility behavior for `parameters`. Schema converters/providers are expected to error if `parametersJsonSchema` is absent instead of falling back to `parameters`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
🔇 Additional comments (2)
packages/core/src/core/compression/utils.ts (2)

351-362: Media placeholder helper looks correct and resilient.

The category classification plus identifier fallback chain is solid, and the PDF label normalization keeps output readable while remaining deterministic.


384-386: Media sanitization integration is correctly implemented.

Line 385’s updated guard and Line 421’s media-to-text conversion close the provider-compatibility gap, while retaining the existing tool-message retagging behavior at Line 429.

Also applies to: 421-424, 429-430


Summary by CodeRabbit

  • New Features

    • Media attachments are converted into compact text placeholders during compression (e.g., "[Attached image: filename]" or "[Attached PDF: mimeType]") for images, PDFs, audio, video, and unknown types.
  • Improvements

    • Mixed text+media messages preserve block order and speaker labeling; tool-related blocks are normalized alongside media. Messages containing only media retain their original speaker.
  • Tests

    • Added coverage for placeholder formats, filename vs. mimeType selection, category mapping, and mixed-block/speaker scenarios.

Walkthrough

Adds media block sanitization: media blocks are converted into standardized text placeholders via a new exported helper, and sanitization logic updated to replace media/tool blocks with text, preserve speakers for media-bearing messages, and only early-return when no tool/media blocks and speaker isn't tool.

Changes

Cohort / File(s) Summary
Media block sanitization implementation
packages/core/src/core/compression/utils.ts
Added exported mediaBlockToCompressionPlaceholder(media: MediaBlock): string. Updated sanitizeHistoryForCompression() to detect media blocks and replace them with text blocks containing `[Attached : <caption
Test coverage for media block sanitization
packages/core/src/core/compression/utils.test.ts
Expanded imports to include MediaBlock. Added test helpers (mediaBlock, humanMsgWithMedia, humanMsgOnlyMedia) and tests covering placeholder generation across categories (image, PDF, audio, video, unknown), filename vs. mimeType selection, speaker preservation for media-only messages, tool→human retagging, mixed text+media, and mixed tool+media behaviors.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop through bytes and files so merry,
I tuck each picture in a tidy string,
"[Attached image: sunset.jpg]" — a tiny ring,
Speakers kept true, tools turned human when needed,
Compressors grin as placeholders are seeded.

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description is comprehensive, including TLDR (Summary), Problem explanation, Solution overview, detailed Changes broken into tasks, and Verification steps. However, it does not follow the provided repository template structure. Restructure the description to align with the repository template: use 'TLDR', 'Dive Deeper', 'Reviewer Test Plan', 'Testing Matrix', and 'Linked issues / bugs' sections as specified.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: converting media blocks to text placeholders during compression. It directly addresses the issue number and the core problem being fixed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue1875

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

LLxprt PR Review – PR #1892

Issue Alignment

Issue #1875 describes a 400 error from Kimi during middle-out compression when PDF media blocks are present. The root cause: sanitizeHistoryForCompression() converted tool blocks to text but left media blocks unchanged, which then reached OpenAIRequestBuilder.ts and were converted to type: 'file' parts — unsupported by Kimi.

The fix is correct:

  • New mediaBlockToCompressionPlaceholder() helper converts media blocks to text placeholders (e.g., [Attached PDF: document.pdf])
  • sanitizeHistoryForCompression() now processes media blocks alongside tool blocks
  • Media messages retain their original speaker (unlike tool messages which get re-tagged to 'human')
  • Existing behavior for non-media messages is preserved

Side Effects

  • Low risk: Changes are isolated to the compression utility
  • No breaking changes: Only messages containing media blocks are affected; all other messages pass through unchanged
  • Correct speaker handling: Media blocks don't incorrectly trigger speaker: 'tool''human' re-tagging

Code Quality

Correctness:

  • Placeholder format [Attached <category>: <identifier>] is appropriate and consistent
  • Identifier preference order (caption → filename → mimeType → 'unknown') is sensible for accessibility
  • PDF label capitalized to 'PDF' for proper display; other categories kept lowercase
  • Helper function is exported for potential reuse

Error handling:

  • Uses existing classifyMediaBlock() utility — well-tested and handles edge cases
  • Empty string filenames correctly fall through to mimeType (tested)

Type safety:

  • All new code properly typed with MediaBlock import
  • Casts to TextBlock are appropriate in this context

Tests and Coverage

Coverage impact: Increase

  • 215 lines of new test code covering:
    • Basic media-to-placeholder conversion (filename, mimeType fallback, empty filename)
    • All 5 media categories (image, pdf, audio, video, unknown)
    • Mixed text + media in same message
    • Messages with only media blocks
    • Speaker preservation (ai/human unchanged, only 'tool' re-tagged)
    • Mixed tool + media blocks in same message
    • Caption preference over filename
    • Tool message re-tagging with media blocks
  • No mock theater detected; tests verify actual output strings and types

Verdict

Ready — The fix correctly addresses the Kimi 400 error by converting media blocks to text placeholders during compression, similar to how tool blocks are already handled. The implementation is clean, well-tested, and maintains backward compatibility for non-media messages.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/core/compression/utils.test.ts`:
- Around line 669-677: Add a regression test that covers the empty-string
filename fallback to mimeType by creating a history using
mediaBlock('image/png', '') (or equivalent) wrapped in humanMsgOnlyMedia and
asserting sanitizeHistoryForCompression returns a single block converted to text
with text '[Attached image: image/png]'; this mirrors the existing test but
supplies filename: '' so the code path in sanitizeHistoryForCompression that
checks filename fallback (referencing mediaBlock, humanMsgOnlyMedia, and
sanitizeHistoryForCompression) is exercised.

In `@packages/core/src/core/compression/utils.ts`:
- Around line 349-352: The placeholder generation in
mediaBlockToCompressionPlaceholder treats empty string filenames as valid
because it uses the nullish coalescing operator (media.filename ??
media.mimeType), producing an empty identifier; change the fallback logic to
treat empty or whitespace-only filenames as absent (e.g., use a truthy/trim
check) so identifier falls back to media.mimeType or 'unknown' instead; update
mediaBlockToCompressionPlaceholder to compute identifier using a trimmed truthy
test (or helper) rather than ?? and keep classifyMediaBlock usage unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: cc3cf5dd-f465-4235-bb92-74b8ce9d8fe1

📥 Commits

Reviewing files that changed from the base of the PR and between 344ba95 and f135b80.

📒 Files selected for processing (2)
  • packages/core/src/core/compression/utils.test.ts
  • packages/core/src/core/compression/utils.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 270000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: E2E Test (macOS)
  • GitHub Check: E2E Test (Linux) - sandbox:none
  • GitHub Check: E2E Test (Linux) - sandbox:docker
  • GitHub Check: Lint (Javascript)
🧰 Additional context used
🧠 Learnings (25)
📓 Common learnings
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.
📚 Learning: 2026-03-27T01:40:09.382Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1790
File: packages/core/src/core/compression/MiddleOutStrategy.ts:307-325
Timestamp: 2026-03-27T01:40:09.382Z
Learning: In `packages/core/src/core/compression/MiddleOutStrategy.ts` (vybestack/llxprt-code), `IContent` messages with `speaker === 'human'` contain only `TextBlock` types by definition in the conversation model. Tool call and tool response blocks appear exclusively on `speaker === 'ai'` and `speaker === 'tool'` messages. Therefore, `extractTextFromMessage` (which filters for `TextBlock`) captures the full content of any human message, and calling `estimateTokens` on its output is a complete token estimate for human messages. Do not flag token estimation for human messages as incomplete due to missing non-text block handling.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-22T04:07:00.235Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T03:22:51.631Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T15:17:37.899Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:410-421
Timestamp: 2026-03-21T15:17:37.899Z
Learning: In `packages/core/src/core/TurnProcessor.ts` and `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1743`), both classes maintain a `lastPromptTokenCount` field. After the decomposition of `geminiChat.ts`, `TurnProcessor._executeProviderCall` must update both `this.lastPromptTokenCount` AND `this.compressionHandler.lastPromptTokenCount` (via `setLastPromptTokenCount`) whenever prompt token counts are received from the non-streaming provider response. The streaming path in `StreamProcessor` already updates `compressionHandler.lastPromptTokenCount` directly. Do not flag the dual-update pattern as redundant — `CompressionHandler.shouldCompress()` reads its own field and will use stale data if only `TurnProcessor.lastPromptTokenCount` is updated. Fixed in commit bac2e4153.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T17:57:00.539Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts:294-305
Timestamp: 2026-03-21T17:57:00.539Z
Learning: In `packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts` (vybestack/llxprt-code PR `#1740`), `blocksToText` and `concatenateTextAndCodeBlocks` are intentionally kept as separate functions. They serve different callers with different contracts: `blocksToText` uses string concatenation and calls `trimStart()` on the result, while `concatenateTextAndCodeBlocks` uses an array+join pattern and guards against null `block.text`. Consolidating them is out of scope for the decomposition PR and should be done as a dedicated follow-up if desired. Do not flag this duplication in future decomposition reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T03:23:48.264Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:297-315
Timestamp: 2026-03-21T03:23:48.264Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code PR `#1743`), `convertAllFunctionResponses` intentionally packs all `functionResponse` parts into a single `IContent` with `speaker='tool'` and multiple `tool_response` blocks. This is faithfully preserved from the original `convertPartListUnionToIContent` method in `geminiChat.ts` (pre-refactor, commit 71e63cb4, lines ~2984-3001). Do not flag this as incorrect multi-block packing — it is the established upstream behavior for this input-conversion path.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-28T20:19:36.726Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/anthropic/AnthropicProvider.ts:1233-1293
Timestamp: 2026-02-28T20:19:36.726Z
Learning: In the llxprt-code IContent model (packages/core/src/providers/anthropic/AnthropicProvider.ts and related message processing), each tool speaker message (IContent with speaker='tool') contains exactly one tool_response block plus its associated media blocks. Multiple tool responses are always separate IContent entries. This structural constraint is enforced by the message format, so code that filters toolResponseBlocks from a single IContent and iterates over them will only process one tool_response per iteration.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-01-13T19:28:00.789Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-01-13T19:28:00.789Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/anthropic/AnthropicProvider.ts`), Anthropic's API returns `contentBlock.input` as an already-parsed JavaScript object, not a JSON string. The code was incorrectly calling `JSON.stringify(contentBlock.input)` before passing it to `processToolParameters()`, which was designed for OpenAI-style string parameters. This causes arrays and other complex types to be corrupted into strings (e.g., `paths` array becomes a string `"[\"**/*.toml\"]"` instead of actual array). The fix is to use `contentBlock.input` directly without stringifying for Anthropic provider.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-13T14:32:11.331Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-13T14:32:11.331Z
Learning: In `packages/core/src/core/geminiChat.ts`, the `convertIContentToResponse` function already converts `ThinkingBlock` to `ThoughtPart` with `thought: true` (around line 3095). However, the `text` getter on the returned response object uses `parts.find((p) => 'text' in p)?.text`, which incorrectly matches `ThoughtPart` first (since `ThoughtPart` also has a `text` property) when Anthropic thinking blocks appear before text blocks. This causes the actual response text to not be surfaced. The fix is to exclude thought parts: `parts.find((p) => 'text' in p && !(p as ThoughtPart).thought)?.text || ''`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T23:27:48.689Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:110-123
Timestamp: 2026-03-19T23:27:48.689Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (extracted from the original `generatePipelineChatCompletionImpl` in `OpenAIProvider.ts`, lines 2050-2160), text-parsed tool calls from `extractKimiToolCallsFromText()` and `deps.textToolParser.parse()` (GemmaToolCallParser) are intentionally yielded directly as `ToolCallBlock[]` without being routed through `deps.toolCallPipeline.addFragment()`. The `toolCallPipeline` is exclusively used for delta-based streaming tool calls coming from the OpenAI API. This two-path design is deliberate — do not flag missing `addFragment()` calls for text-parsed tool calls as a bug.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-31T15:03:03.633Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-31T15:03:03.633Z
Learning: In vybestack/llxprt-code, `buildContinuationMessages` in `packages/core/src/providers/openai/OpenAIRequestBuilder.ts` (line 524) always appends `{ role: 'assistant', tool_calls: toolCalls }` to the history. Passing an empty `[]` array produces an invalid assistant message with `tool_calls: []` that most OpenAI-compatible APIs reject with HTTP 400. Do NOT call `requestContinuationAfterToolCalls` with an empty tool calls array for thinking-only continuation — a separate `requestContinuationAfterThinking` method is needed.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T22:50:00.853Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIRequestBuilder.test.ts:316-395
Timestamp: 2026-03-19T22:50:00.853Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/openai/OpenAIRequestBuilder.ts`, previously `OpenAIProvider.ts` around line 1250), `validateToolMessageSequence` intentionally does NOT deduplicate tool messages by `tool_call_id`. Contiguous tool messages sharing the same `tool_call_id` are legitimate in conversation history (e.g., replay artifacts or adapter-level splitting across message boundaries). The function only removes *orphaned* tool messages (those whose `tool_call_id` does not match any declared tool call in the preceding assistant message). Eager deduplication of same-id tool messages has historically caused strict-provider HTTP 400 errors and must not be introduced.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-06T15:52:42.315Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1305
File: scripts/generate-keybindings-doc.ts:1-5
Timestamp: 2026-02-06T15:52:42.315Z
Learning: In reviews of vybestack/llxprt-code, do not suggest changing existing copyright headers from 'Google LLC' to 'Vybestack LLC' for files that originated from upstream. Preserve upstream copyrights in files that came from upstream, and only apply 'Vybestack LLC' copyright on newly created, original LLxprt files. If a file is clearly LLxprt-original, it may carry the Vybestack header; if it is upstream-originated, keep the original sponsor header.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-15T21:44:56.598Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1407
File: packages/core/src/core/geminiChatHookTriggers.ts:56-65
Timestamp: 2026-02-15T21:44:56.598Z
Learning: Enforce the canonical speaker-to-role mapping used by GeminiChat hooks: in IContent.speaker, which is strictly typed as 'human | ai | tool' (no 'system'), map 'human' to the 'user' role, 'ai' to the 'model' role, and 'tool' to the 'user' role in all hook payloads. This pattern should be applied across related hook files within packages/core/src/core/ (not just the single file) to ensure consistent role assignment.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-16T19:18:56.265Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1436
File: packages/core/src/core/nonInteractiveToolExecutor.ts:0-0
Timestamp: 2026-02-16T19:18:56.265Z
Learning: Guideline: In the core scheduler architecture, the system runs in a single mode at a time—either interactive or non-interactive, never both on the same scheduler instance. Non-interactive (CLI one-shot) runs without any interactive session; interactive mode subagents run within the parent's interactive context and inherit its mode. When reviewing code, ensure non-interactive tool executions (e.g., in nonInteractiveToolExecutor.ts) create and use a fresh completionResolver per executeToolCall, and that there is no race with interactive sessions since they cannot coexist on the same scheduler instance. This pattern applies across files in packages/core/src/core/. Only apply to relevant files, not globally.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-31T02:12:43.093Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1854
File: packages/core/src/core/subagentRuntimeSetup.test.ts:77-84
Timestamp: 2026-03-31T02:12:43.093Z
Learning: In this codebase, tool declarations should follow the single required contract `parametersJsonSchema`; do not ask to preserve or reintroduce the legacy `parameters` fallback field. Reviewers should not flag assertions/checks for missing `parameters` or suggest backward-compatibility behavior for `parameters`. Schema converters/providers are expected to error if `parametersJsonSchema` is absent instead of falling back to `parameters`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T23:27:49.587Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/__tests__/OpenAIProvider.e2e.test.ts:199-203
Timestamp: 2026-03-19T23:27:49.587Z
Learning: In `packages/core/src/providers/openai/__tests__/OpenAIProvider.e2e.test.ts` (vybestack/llxprt-code), Scenarios 3, 7a, 7b, and 7c use `buildMessagesWithReasoning` (imported directly from `OpenAIRequestBuilder`) rather than calling `provider.generateChatCompletion`. This is intentional and pre-existing behavior: the original tests accessed the same helper via a hacky `buildMessagesWithReasoning.call(provider, ...)` private-method pattern. The PR's direct import is an improvement, not a regression. Do not flag these scenarios as insufficiently integrated — they are helper-level tests by design, and adding full provider-path coverage is out of scope for refactoring PRs.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-30T17:36:37.126Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1797
File: packages/cli/src/ui/components/shared/text-buffer.test.ts:2647-2704
Timestamp: 2026-03-30T17:36:37.126Z
Learning: In vybestack/llxprt-code, tests for the React hook useTextBuffer (packages/cli/src/ui/components/shared/text-buffer.ts) should not read internal fields like visualLayout. For cache/identity invalidation checks in packages/cli/src/ui/components/shared/text-buffer.test.ts, assert against the public allVisualLines array instead, and reserve internal-structure assertions for lower-level helpers if needed.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-28T23:18:15.496Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1642
File: packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx:528-578
Timestamp: 2026-02-28T23:18:15.496Z
Learning: In `packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx`, tests use mocked child components (ToolConfirmationMessage, ToolMessage) for isolation and consistency with upstream gemini-cli patterns. Tests for permanent tool approval settings (`enablePermanentToolApproval`) use this mock-based approach and pass successfully as part of the cherry-picked upstream test suite.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T15:18:04.202Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/ConversationManager.ts:358-364
Timestamp: 2026-03-21T15:18:04.202Z
Learning: In `packages/core/src/core/ConversationManager.ts` (vybestack/llxprt-code PR `#1743`), `_addModelOutputToHistory` attaches `usageMetadata` to every `IContent` produced in the loop over `consolidatedOutputContents`. This is intentional behavior faithfully preserved from the original `recordHistory()` in `geminiChat.ts`. Multi-entry model output is limited to text/tool-call interleaving cases because `_consolidateModelOutput` already merges adjacent text parts. Do not flag the per-entry usageMetadata attachment as a double-counting bug in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-25T22:19:49.983Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1775
File: packages/core/src/core/coreToolScheduler.test.ts:0-0
Timestamp: 2026-03-25T22:19:49.983Z
Learning: In `packages/core/src/core/coreToolScheduler.test.ts` (vybestack/llxprt-code), `createMockMessageBus()` does not forward `publish()` calls to registered subscribers — it only records them. Integration tests that rely on bus-driven subscriber callbacks (e.g., stale-correlation invalidation via `TOOL_CONFIRMATION_RESPONSE`) will not exercise those paths through the mock. Stale-correlation invalidation coverage for `ConfirmationCoordinator` is intentionally handled in `packages/core/src/scheduler/confirmation-coordinator.test.ts` via direct `handleMessageBusResponse` invocations, not in `coreToolScheduler.test.ts`. Do not flag this as missing coverage in the scheduler integration tests.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-26T02:47:18.478Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentExecution.test.ts:142-143
Timestamp: 2026-03-26T02:47:18.478Z
Learning: In `packages/core/src/core/subagentExecution.ts` (vybestack/llxprt-code PR `#1779`), `checkGoalCompletion` returns `Promise<Content[] | null>`, not `Promise<Part[] | null>`. `Content` has the shape `{ role: string, parts: Part[] }`, so test assertions like `result![0].parts[0]` are correct and access the first Part within the first Content object. Do not flag `result![0].parts[0]` indexing in tests for this function as an invalid shape access.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-01T17:19:16.202Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/openai-responses/buildResponsesInputFromContent.ts:64-77
Timestamp: 2026-03-01T17:19:16.202Z
Learning: In llxprt-code, MediaBlock instances in the pipeline (from fileUtils, ContentConverters, etc.) use canonically lowercase MIME types per RFC 2045. MIME type normalization is enforced at the content creation layer, so case-insensitive MIME type checks (e.g., `mimeType.toLowerCase().startsWith('image/')`) are not needed in provider code. Cross-cutting MIME type normalization would be a separate architectural concern.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T22:51:20.841Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:300-305
Timestamp: 2026-03-19T22:51:20.841Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (vybestack/llxprt-code), `reasoning_content` deltas from `parseStreamingReasoningDelta` are intentionally accumulated into `state.accumulatedReasoningContent` during chunk processing and emitted as a `ThinkingBlock` only at the end of the stream, co-packaged in the same `IContent` block as tool calls. This is required for DeepSeek-reasoner compatibility: the model requires `reasoning_content` and tool calls to appear together in a single `IContent` block. Do not flag this deferred/batched emission pattern as a bug — inline streaming of reasoning was a legacy-path behavior that has been removed.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
🔇 Additional comments (2)
packages/core/src/core/compression/utils.ts (1)

377-379: Media sanitization path looks correct.

sanitizeHistoryForCompression now correctly enters rewrite mode for media blocks and converts them to plain text placeholders before request building.

Also applies to: 414-417

packages/core/src/core/compression/utils.test.ts (1)

654-777: Great media regression coverage.

These tests cover the key conversion and speaker scenarios for issue #1875 and meaningfully reduce the chance of provider-specific 400 regressions.

Comment thread packages/core/src/core/compression/utils.test.ts
Comment thread packages/core/src/core/compression/utils.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 58.29% 58.29% 66.72% 80.1%
Core 78.17% 78.17% 78.13% 81.5%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   58.29 |     80.1 |   66.72 |   58.29 |                   
 src               |   56.56 |    57.47 |    62.5 |   56.56 |                   
  gemini.tsx       |    50.4 |    56.81 |   54.54 |    50.4 | ...1195,1203-1222 
  ...ractiveCli.ts |   61.01 |    55.88 |   55.55 |   61.01 | ...98-605,607-616 
  ...liCommands.ts |   97.22 |       60 |     100 |   97.22 | 39-40             
  ...ActiveAuth.ts |   59.42 |    70.58 |     100 |   59.42 | ...0,78-93,97-106 
 src/auth          |   79.19 |    88.76 |   87.26 |   79.19 |                   
  ...andlerImpl.ts |   85.71 |    87.27 |    90.9 |   85.71 | ...48,577,592-593 
  ...henticator.ts |     100 |    95.65 |   83.33 |     100 | 170               
  ...ketManager.ts |     100 |      100 |     100 |     100 |                   
  ...andlerImpl.ts |   25.49 |      100 |      50 |   25.49 | 53-92,98-102      
  ...h-provider.ts |   78.28 |    85.96 |      80 |   78.28 | ...36-451,463-486 
  ...chestrator.ts |   89.33 |    86.59 |     100 |   89.33 | ...96,650-665,671 
  ...us-service.ts |   90.84 |    88.73 |     100 |   90.84 | ...54-358,445-446 
  auth-utils.ts    |   77.35 |    83.33 |     100 |   77.35 | 23-30,84-85,89-90 
  ...h-provider.ts |   52.46 |       70 |   68.75 |   52.46 | ...68,474,484-526 
  ...h-provider.ts |   19.55 |      100 |   34.78 |   19.55 | ...53-484,502-521 
  ...l-oauth-ui.ts |   96.42 |      100 |     100 |   96.42 | 52,89             
  ...h-callback.ts |   82.94 |    75.67 |    90.9 |   82.94 | ...74-775,788-790 
  migration.ts     |       0 |        0 |       0 |       0 | 1-69              
  oauth-manager.ts |   95.58 |    97.91 |   97.29 |   95.58 | 403,469-478       
  ...vider-base.ts |     100 |    96.96 |     100 |     100 | 83                
  ...al-manager.ts |   86.68 |    96.25 |   93.75 |   86.68 | ...95-396,427-468 
  profile-utils.ts |   77.27 |    69.23 |     100 |   77.27 | ...6-87,95-96,108 
  ...r-registry.ts |   97.46 |     87.5 |     100 |   97.46 | 78-79             
  ...usage-info.ts |   99.45 |    97.22 |     100 |   99.45 | 237               
  ...h-provider.ts |   58.29 |    66.66 |   72.72 |   58.29 | ...98-336,344-385 
  ...oordinator.ts |   87.92 |    90.24 |     100 |   87.92 | ...99-903,918,934 
  ...ver-helper.ts |   89.53 |    88.88 |     100 |   89.53 | 82,96,128-133,141 
  ...e-resolver.ts |   96.07 |     90.9 |     100 |   96.07 | 42,73-74,80       
  ...esh-helper.ts |   91.51 |    86.48 |     100 |   91.51 | ...46,179,186,209 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/auth/proxy    |   82.34 |    77.74 |   82.35 |   82.34 |                   
  ...oxy-server.ts |   84.53 |    74.58 |   96.66 |   84.53 | ...-960,1079-1084 
  ...re-factory.ts |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   98.16 |    94.11 |     100 |   98.16 | 51-52             
  ...-scheduler.ts |    92.3 |    84.61 |     100 |    92.3 | 56-59             
  ...th-adapter.ts |   63.54 |    66.66 |    64.7 |   63.54 | ...44-245,256,260 
  ...oordinator.ts |   98.98 |    82.05 |     100 |   98.98 | 156               
  ...-lifecycle.ts |    59.5 |    66.66 |   33.33 |    59.5 | ...92,199,241-242 
 src/commands      |   78.35 |      100 |   44.44 |   78.35 |                   
  extensions.tsx   |   55.88 |      100 |       0 |   55.88 | 25-38,42          
  hooks.ts         |   61.53 |      100 |       0 |   61.53 | 14-17,20          
  mcp.ts           |   94.11 |      100 |      50 |   94.11 | 26                
  skills.tsx       |     100 |      100 |     100 |     100 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...nds/extensions |   74.01 |       92 |   67.34 |   74.01 |                   
  config.ts        |   93.36 |    88.88 |     100 |   93.36 | ...25-226,228-233 
  disable.ts       |     100 |      100 |     100 |     100 |                   
  enable.ts        |     100 |      100 |     100 |     100 |                   
  install.ts       |   77.61 |    71.42 |   66.66 |   77.61 | ...10,156,159-166 
  link.ts          |   64.15 |    83.33 |      25 |   64.15 | 30,53-64,66-71    
  list.ts          |      90 |      100 |   33.33 |      90 | 35-37             
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   70.62 |      100 |   66.66 |   70.62 | 32-81,223-227,230 
  uninstall.ts     |   78.43 |      100 |   66.66 |   78.43 | 54-59,62-66       
  update.ts        |   11.42 |      100 |       0 |   11.42 | ...44-159,161-166 
  utils.ts         |   13.33 |      100 |       0 |   13.33 | 29-60             
  validate.ts      |   89.36 |     87.5 |      75 |   89.36 | 50-53,60,112-116  
 .../hooks/scripts |       0 |        0 |       0 |       0 |                   
  on-start.js      |       0 |        0 |       0 |       0 | 1-8               
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.js       |       0 |        0 |       0 |       0 | 1-60              
 ...commands/hooks |    9.37 |      100 |       0 |    9.37 |                   
  migrate.ts       |    9.37 |      100 |       0 |    9.37 | ...60-170,172-174 
 src/commands/mcp  |   96.73 |    85.48 |    90.9 |   96.73 |                   
  add.ts           |   99.51 |    92.59 |     100 |   99.51 | 49                
  list.ts          |   90.43 |    82.14 |      80 |   90.43 | ...14-116,149-151 
  remove.ts        |     100 |    71.42 |     100 |     100 | 21-25             
 ...ommands/skills |   60.85 |     92.3 |   31.25 |   60.85 |                   
  disable.ts       |      54 |      100 |   33.33 |      54 | 40-52,54-63       
  enable.ts        |   72.22 |      100 |   33.33 |   72.22 | 33-37,39-43       
  install.ts       |   42.69 |      100 |      25 |   42.69 | ...71-100,102-109 
  list.ts          |   84.72 |       80 |   33.33 |   84.72 | ...78,91-95,97-99 
  uninstall.ts     |   57.89 |      100 |   33.33 |   57.89 | 47-64,66-71       
 src/config        |   88.32 |    81.27 |    83.5 |   88.32 |                   
  ...deResolver.ts |   94.54 |    95.45 |     100 |   94.54 | 50-52             
  auth.ts          |   84.61 |    82.35 |     100 |   84.61 | 18-19,22-23,53-54 
  cliArgParser.ts  |   90.57 |    86.95 |     100 |   90.57 | ...53-256,286-289 
  ...alSettings.ts |   86.66 |    88.23 |     100 |   86.66 | 40-41,44-47       
  config.ts        |     100 |      100 |     100 |     100 |                   
  configBuilder.ts |   96.28 |      100 |    87.5 |   96.28 | 109-115,235-236   
  ...mentLoader.ts |   83.78 |    60.86 |     100 |   83.78 | ...23-125,133-136 
  extension.ts     |   77.34 |    86.63 |   77.14 |   77.34 | ...1117,1120-1121 
  ...iveContext.ts |   93.66 |    91.42 |     100 |   93.66 | 79,81,87-92,232   
  ...iateConfig.ts |   94.93 |    96.66 |     100 |   94.93 | 76,84-86          
  keyBindings.ts   |     100 |      100 |     100 |     100 |                   
  ...rverConfig.ts |      86 |    94.44 |     100 |      86 | 23-36             
  paths.ts         |     100 |      100 |     100 |     100 |                   
  policy.ts        |   80.76 |      100 |      50 |   80.76 | 45-49             
  ...figRuntime.ts |   88.68 |       84 |     100 |   88.68 | ...21-428,439-442 
  ...eBootstrap.ts |   89.31 |    84.55 |      90 |   89.31 | ...72-774,783-784 
  ...Resolution.ts |   69.86 |     62.5 |   83.33 |   69.86 | ...29-230,266-285 
  ...pplication.ts |   91.17 |    76.19 |     100 |   91.17 | ...31,155,182,187 
  ...elResolver.ts |   92.59 |    83.33 |     100 |   92.59 | 40,42-43,79       
  sandboxConfig.ts |    66.9 |    48.35 |   89.47 |    66.9 | ...93-500,518-519 
  ...oxProfiles.ts |    8.53 |      100 |       0 |    8.53 | 47-48,51-129      
  settingPaths.ts  |     100 |      100 |     100 |     100 |                   
  ...validation.ts |   84.73 |    82.35 |     100 |   84.73 | ...60,263-267,270 
  settings.ts      |   79.73 |     71.3 |   74.19 |   79.73 | ...1155,1190-1191 
  ...ingsSchema.ts |    99.9 |     90.9 |     100 |    99.9 | 57-58             
  ...Governance.ts |   95.83 |    90.62 |     100 |   95.83 | 52,124-127        
  ...tedFolders.ts |    95.2 |    95.91 |     100 |    95.2 | 93,119-125        
  welcomeConfig.ts |   22.41 |      100 |       0 |   22.41 | ...71,74-79,82-83 
  yargsOptions.ts  |   98.65 |    94.44 |   85.71 |   98.65 | 116,125-128       
 ...fig/extensions |   73.18 |    83.77 |   90.78 |   73.18 |                   
  consent.ts       |    82.6 |    86.95 |   91.66 |    82.6 | ...70-371,374-375 
  ...Enablement.ts |   93.87 |    96.05 |     100 |   93.87 | ...98-204,265-267 
  ...onSettings.ts |     100 |      100 |     100 |     100 |                   
  github.ts        |   64.04 |       79 |     100 |   64.04 | ...62-565,570-571 
  hookSchema.ts    |     100 |      100 |     100 |     100 |                   
  ...ntegration.ts |    55.1 |    84.44 |      50 |    55.1 | ...61,402,426-427 
  ...ingsPrompt.ts |   72.72 |    94.44 |      80 |   72.72 | 92-121            
  ...ngsStorage.ts |   84.61 |    75.92 |     100 |   84.61 | ...86-287,305-308 
  update.ts        |   62.57 |    46.66 |   66.66 |   62.57 | ...23-151,168-176 
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   95.45 |       90 |     100 |   95.45 | 32-33             
 src/constants     |     100 |      100 |     100 |     100 |                   
  historyLimits.ts |     100 |      100 |     100 |     100 |                   
 src/extensions    |   65.75 |    57.89 |      75 |   65.75 |                   
  ...utoUpdater.ts |   65.75 |    57.89 |      75 |   65.75 | ...50-451,460,462 
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 ...egration-tests |   91.46 |    85.18 |     100 |   91.46 |                   
  test-utils.ts    |   91.46 |    85.18 |     100 |   91.46 | ...16,234-235,245 
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/providers     |   83.41 |    73.57 |   77.35 |   83.41 |                   
  IFileSystem.ts   |   65.51 |      100 |   57.14 |   65.51 | 45-46,49-54,67-68 
  ...Precedence.ts |   94.59 |    86.66 |     100 |   94.59 | 40-41             
  index.ts         |       0 |        0 |       0 |       0 | 1-19              
  ...gistration.ts |   77.94 |    68.75 |   33.33 |   77.94 | ...97-101,107-108 
  ...derAliases.ts |   82.97 |    82.97 |     100 |   82.97 | ...37-243,248-249 
  ...onfigUtils.ts |   92.45 |       75 |     100 |   92.45 | 26-30             
  ...erInstance.ts |   84.13 |    69.86 |   83.33 |   84.13 | ...89-793,911-912 
  types.ts         |       0 |        0 |       0 |       0 | 1-8               
 ...viders/logging |   87.59 |    88.63 |   63.63 |   87.59 |                   
  ...rvice-impl.ts |   44.44 |        0 |       0 |   44.44 | 21-22,25-30,36-37 
  git-stats.ts     |   94.59 |    90.69 |     100 |   94.59 | ...48-149,180-181 
 src/runtime       |   79.61 |    78.72 |   88.37 |   79.61 |                   
  ...imeAdapter.ts |   97.65 |    92.15 |     100 |   97.65 | ...18-219,308-309 
  ...etFailover.ts |   97.05 |    91.66 |     100 |   97.05 | 31-32,215         
  messages.ts      |   63.07 |    66.66 |      75 |   63.07 | 51,74-102         
  ...pplication.ts |   88.51 |    82.11 |      80 |   88.51 | ...63-666,762-763 
  ...leSnapshot.ts |   47.28 |    50.87 |   53.84 |   47.28 | ...16-518,521-545 
  ...rMutations.ts |   83.43 |    85.71 |   86.66 |   83.43 | ...19-423,437-438 
  ...iderSwitch.ts |   85.76 |    80.68 |     100 |   85.76 | ...83-600,637,742 
  ...eAccessors.ts |   70.05 |    60.97 |     100 |   70.05 | ...09-510,518-519 
  ...extFactory.ts |   91.26 |    70.96 |     100 |   91.26 | ...10-313,400-407 
  ...eLifecycle.ts |   84.31 |     87.5 |     100 |   84.31 | ...11-120,154-158 
  ...meRegistry.ts |   90.67 |    91.22 |     100 |   90.67 | ...55-159,165-166 
  ...meSettings.ts |     100 |      100 |     100 |     100 |                   
  ...gsResolver.ts |   74.52 |    75.86 |      75 |   74.52 | ...47-158,174-182 
  ...sHardening.ts |   58.42 |       85 |    87.5 |   58.42 | ...77,90-91,97-98 
 src/services      |   82.38 |    80.82 |   86.36 |   82.38 |                   
  ...mandLoader.ts |   79.48 |    71.42 |      80 |   79.48 | ...06-120,160-177 
  ...ardService.ts |    91.3 |    33.33 |     100 |    91.3 | 35-36             
  ...andService.ts |     100 |      100 |     100 |     100 |                   
  ...mandLoader.ts |   89.47 |    88.88 |     100 |   89.47 | ...82-187,261-268 
  ...omptLoader.ts |   71.05 |    76.74 |   83.33 |   71.05 | ...41,208,260-261 
  performResume.ts |   86.13 |    79.31 |     100 |   86.13 | ...85-188,194-195 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.57 |    94.11 |     100 |   97.57 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.38 |    93.61 |     100 |   97.38 | 77-78,203-204     
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...o-continuation |   85.62 |    82.14 |   94.11 |   85.62 |                   
  ...ionService.ts |   85.62 |    82.14 |   94.11 |   85.62 | ...94,553,579-580 
 src/settings      |   85.96 |     64.7 |     100 |   85.96 |                   
  ...alSettings.ts |   94.44 |       70 |     100 |   94.44 | 74-75             
  ...aramParser.ts |   71.42 |    57.14 |     100 |   71.42 | 21-22,24-25,30-31 
 src/test-utils    |    76.7 |     90.9 |   27.27 |    76.7 |                   
  async.ts         |       0 |        0 |       0 |       0 | 1-34              
  ...eExtension.ts |     100 |      100 |     100 |     100 |                   
  ...omMatchers.ts |   18.75 |      100 |       0 |   18.75 | 16-44             
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |   94.84 |    96.66 |      25 |   94.84 | ...51-156,259-260 
  ...e-testing.tsx |       0 |        0 |       0 |       0 | 1-56              
  ...iderConfig.ts |       0 |        0 |       0 |       0 | 1-19              
 src/ui            |   37.93 |    93.44 |   30.48 |   37.93 |                   
  App.tsx          |   37.25 |      100 |       0 |   37.25 | 64-91,97-104      
  AppContainer.tsx |     100 |      100 |     100 |     100 |                   
  ...erRuntime.tsx |   14.43 |      100 |   16.66 |   14.43 | 66-395            
  ...tionNudge.tsx |       8 |      100 |       0 |       8 | 27-102            
  colors.ts        |   37.14 |      100 |   20.33 |   37.14 | ...03-304,306-307 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  debug.ts         |     100 |      100 |     100 |     100 |                   
  ...derOptions.ts |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   88.63 |       84 |     100 |   88.63 | 22,24-25,32-33    
  ...ntsEnabled.ts |     100 |      100 |     100 |     100 |                   
  ...submission.ts |     100 |      100 |     100 |     100 |                   
  ...tic-colors.ts |   78.94 |      100 |      60 |   78.94 | 15-16,24-25       
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/commands   |   67.48 |     74.7 |   71.98 |   67.48 |                   
  aboutCommand.ts  |   73.13 |    26.08 |     100 |   73.13 | ...13-114,134-137 
  authCommand.ts   |   50.56 |    77.33 |   58.33 |   50.56 | ...43-646,657-695 
  ...urlCommand.ts |      30 |      100 |       0 |      30 | 20-40             
  bugCommand.ts    |    62.5 |    23.07 |     100 |    62.5 | ...,71-98,123-132 
  chatCommand.ts   |   70.02 |    80.64 |   63.63 |   70.02 | ...27-528,576-587 
  clearCommand.ts  |   86.88 |    86.66 |     100 |   86.88 | 67-74             
  ...essCommand.ts |   99.09 |    91.66 |     100 |   99.09 | 96                
  ...nueCommand.ts |     100 |      100 |     100 |     100 |                   
  copyCommand.ts   |   98.33 |    94.44 |     100 |   98.33 | 39                
  debugCommands.ts |   13.29 |      100 |       0 |   13.29 | ...48,455,462,469 
  ...icsCommand.ts |   66.83 |    45.83 |      75 |   66.83 | ...53-357,468-473 
  ...ryCommand.tsx |   88.82 |     87.5 |     100 |   88.82 | ...,46-54,178-186 
  docsCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...extCommand.ts |   93.18 |    77.77 |     100 |   93.18 | 108-113           
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...onsCommand.ts |   39.27 |    87.17 |   63.63 |   39.27 | ...94-324,334-482 
  ...ionSection.ts |   83.33 |    93.33 |     100 |   83.33 | 28-34             
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   89.62 |    87.27 |     100 |   89.62 | ...54,344-345,459 
  ideCommand.ts    |   66.97 |    68.96 |   55.55 |   66.97 | ...25-228,237-244 
  initCommand.ts   |   80.26 |    71.42 |   66.66 |   80.26 | 35-39,41-88       
  keyCommand.ts    |   89.84 |    79.74 |     100 |   89.84 | ...93,416-417,516 
  ...ileCommand.ts |   11.11 |      100 |       0 |   11.11 | 23-134            
  ...ingCommand.ts |   10.96 |      100 |       0 |   10.96 | ...59-528,545-556 
  logoutCommand.ts |   15.62 |      100 |       0 |   15.62 | 21-85             
  lspCommand.ts    |    90.9 |    87.17 |     100 |    90.9 | ...18-123,145-147 
  mcpCommand.ts    |   82.19 |    79.09 |   83.33 |   82.19 | ...91-492,510-511 
  memoryCommand.ts |   86.24 |    77.55 |     100 |   86.24 | ...73,235,261,268 
  modelCommand.ts  |   98.92 |    93.02 |     100 |   98.92 | 121               
  mouseCommand.ts  |     100 |      100 |     100 |     100 |                   
  ...onsCommand.ts |    93.9 |    88.88 |     100 |    93.9 | 58-62             
  ...iesCommand.ts |   97.08 |    80.55 |     100 |   97.08 | 27,40-41          
  ...acyCommand.ts |   61.53 |      100 |       0 |   61.53 | 22-26             
  ...ileCommand.ts |   52.84 |    58.24 |   61.53 |   52.84 | ...1047,1068-1084 
  ...derCommand.ts |   53.94 |    28.94 |      80 |   53.94 | ...63-267,275-280 
  quitCommand.ts   |   36.66 |      100 |       0 |   36.66 | 17-36             
  ...oreCommand.ts |   92.59 |     87.5 |     100 |   92.59 | ...,90-91,120-125 
  setCommand.ts    |   75.48 |    74.28 |   72.72 |   75.48 | ...41-546,588-601 
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  setupCommand.ts  |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   91.38 |    82.85 |     100 |   91.38 | ...13-216,223-227 
  skillsCommand.ts |   82.37 |       76 |     100 |   82.37 | ...86-287,300-301 
  statsCommand.ts  |   70.67 |    65.71 |      75 |   70.67 | ...31-540,548-625 
  ...entCommand.ts |   76.77 |    70.27 |   81.81 |   76.77 | ...09-615,626-632 
  tasksCommand.ts  |   78.75 |    78.78 |     100 |   78.75 | ...78-186,247-254 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  todoCommand.ts   |   65.52 |    69.53 |    92.3 |   65.52 | ...1256,1268-1275 
  ...matCommand.ts |   26.66 |      100 |       0 |   26.66 | 33-92             
  ...keyCommand.ts |    98.9 |     92.3 |     100 |    98.9 | 34                
  ...ileCommand.ts |   99.11 |    94.11 |     100 |   99.11 | 36                
  toolsCommand.ts  |   85.88 |    76.11 |     100 |   85.88 | ...87-296,309-310 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ileCommand.ts |   27.77 |        0 |       0 |   27.77 | 11-23             
  vimCommand.ts    |   44.44 |      100 |       0 |   44.44 | 14-24             
 ...ommands/schema |   96.22 |    91.13 |    92.3 |   96.22 |                   
  index.ts         |   96.45 |    91.71 |     100 |   96.45 | ...08-412,423-424 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/ui/components |   10.14 |    30.76 |    2.08 |   10.14 |                   
  AboutBox.tsx     |    4.46 |      100 |       0 |    4.46 | 26-147            
  AnsiOutput.tsx   |    8.33 |      100 |       0 |    8.33 | 25-90             
  AppHeader.tsx    |   22.58 |      100 |       0 |   22.58 | 26-54             
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  AuthDialog.tsx   |    6.29 |      100 |       0 |    6.29 | 22-189            
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-62              
  ...Indicator.tsx |   15.15 |      100 |       0 |   15.15 | 17-47             
  ...firmation.tsx |    7.43 |      100 |       0 |    7.43 | 51-180            
  ...tsDisplay.tsx |    7.69 |      100 |       0 |    7.69 | 23-34,38-156      
  CliSpinner.tsx   |       0 |        0 |       0 |       0 | 1-22              
  Composer.tsx     |    8.62 |      100 |       0 |    8.62 | 24-81             
  ...entPrompt.tsx |   18.75 |      100 |       0 |   18.75 | 21-51             
  ...ryDisplay.tsx |   21.05 |      100 |       0 |   21.05 | 17-35             
  ...ryDisplay.tsx |    5.71 |      100 |       0 |    5.71 | 30-141            
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-37              
  ...gProfiler.tsx |   16.86 |      100 |       0 |   16.86 | ...73-118,122-224 
  ...esDisplay.tsx |   10.52 |      100 |       0 |   10.52 | 24-82             
  ...ogManager.tsx |    8.62 |      100 |       0 |    8.62 | 71-591            
  ...ngsDialog.tsx |    6.53 |      100 |       0 |    6.53 | 31-193            
  ...rBoundary.tsx |   10.16 |        0 |       0 |   10.16 | ...17-162,180-192 
  ...ustDialog.tsx |   16.66 |      100 |       0 |   16.66 | 32-124            
  Footer.tsx       |    9.25 |        0 |     100 |    9.25 | ...35-518,522-539 
  ...ngSpinner.tsx |    40.9 |      100 |       0 |    40.9 | 31-47             
  Header.tsx       |    17.5 |      100 |       0 |    17.5 | 22-62             
  Help.tsx         |    3.93 |      100 |       0 |    3.93 | 18-180            
  ...emDisplay.tsx |   18.54 |      100 |       0 |   18.54 | 54-203            
  ...usDisplay.tsx |       0 |        0 |       0 |       0 | 1-47              
  InputPrompt.tsx  |   42.65 |    33.33 |   66.66 |   42.65 | ...1178,1185-1196 
  ...tsDisplay.tsx |    4.41 |      100 |       0 |    4.41 | 26-37,41-249      
  ...utManager.tsx |       0 |        0 |       0 |       0 | 1-97              
  ...ileDialog.tsx |    6.89 |      100 |       0 |    6.89 | 20-119            
  ...Indicator.tsx |   14.28 |      100 |       0 |   14.28 | 25-89             
  ...ingDialog.tsx |    4.52 |      100 |       0 |    4.52 | ...9,84-90,93-354 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-40              
  ModelDialog.tsx  |    1.79 |      100 |       0 |    1.79 | 53-76,79-629      
  ...tsDisplay.tsx |    4.84 |      100 |       0 |    4.84 | 28-220            
  ...fications.tsx |   15.65 |      100 |       0 |   15.65 | 36-151            
  ...odeDialog.tsx |    7.31 |      100 |       0 |    7.31 | 30-140            
  ...ustDialog.tsx |    6.21 |      100 |       0 |    6.21 | 30-237            
  PrepareLabel.tsx |   13.33 |      100 |       0 |   13.33 | 20-48             
  ...ailDialog.tsx |   11.58 |      100 |       0 |   11.58 | 57-68,71-343      
  ...ineEditor.tsx |    2.59 |      100 |       0 |    2.59 | 25-65,69-357      
  ...istDialog.tsx |    2.99 |      100 |       0 |    2.99 | 35-369            
  ...derDialog.tsx |    3.84 |      100 |       0 |    3.84 | 22-272            
  ...Indicator.tsx |       0 |        0 |       0 |       0 | 1-21              
  ...eKeyInput.tsx |       0 |        0 |       0 |       0 | 1-138             
  ...serDialog.tsx |    1.96 |      100 |       0 |    1.96 | 41-49,56-588      
  ...ryDisplay.tsx |      50 |      100 |       0 |      50 | 15-17             
  ...ngsDialog.tsx |    1.69 |      100 |       0 |    1.69 | ...2-161,164-1624 
  ...putPrompt.tsx |   16.21 |      100 |       0 |   16.21 | 19-53             
  ...Indicator.tsx |   44.44 |      100 |       0 |   44.44 | 12-17             
  ...MoreLines.tsx |      28 |      100 |       0 |      28 | 18-40             
  StatsDisplay.tsx |    4.82 |      100 |       0 |    4.82 | ...03-241,250-413 
  ...usDisplay.tsx |       0 |        0 |       0 |       0 | 1-59              
  StickyHeader.tsx |    7.14 |      100 |       0 |    7.14 | 20-78             
  ...nsDisplay.tsx |    7.76 |      100 |       0 |    7.76 | 49-164            
  Table.tsx        |    7.54 |      100 |       0 |    7.54 | 27-87             
  ThemeDialog.tsx  |    5.22 |      100 |       0 |    5.22 | 45-420            
  ...dGradient.tsx |      25 |      100 |       0 |      25 | 27-46             
  Tips.tsx         |      16 |      100 |       0 |      16 | 17-45             
  TodoPanel.tsx    |    5.55 |      100 |       0 |    5.55 | 26-74,77-245      
  ...tsDisplay.tsx |    7.42 |      100 |       0 |    7.42 | 30-53,56-228      
  ToolsDialog.tsx  |    7.86 |      100 |       0 |    7.86 | 23-119            
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ionDialog.tsx |    7.52 |      100 |       0 |    7.52 | 18-123            
  todo-utils.ts    |       0 |        0 |       0 |       0 | 1-7               
 ...leCreateWizard |   19.22 |       50 |       0 |   19.22 |                   
  ...aramsStep.tsx |    5.82 |      100 |       0 |    5.82 | 27-244            
  ...ationStep.tsx |    4.82 |      100 |       0 |    4.82 | 27-294            
  ...onfigStep.tsx |   11.23 |      100 |       0 |   11.23 | 25-119            
  ...electStep.tsx |    6.11 |      100 |       0 |    6.11 | 28-236            
  ...ationMenu.tsx |       0 |        0 |       0 |       0 | 1-101             
  ...eSaveStep.tsx |    6.28 |      100 |       0 |    6.28 | 33-257            
  ...ssSummary.tsx |   12.12 |      100 |       0 |   12.12 | 22-87             
  ...electStep.tsx |   16.92 |      100 |       0 |   16.92 | 27-94             
  TextInput.tsx    |     5.5 |      100 |       0 |     5.5 | 27-170            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.tsx        |    6.27 |      100 |       0 |    6.27 | 28-296            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |    5.22 |      100 |       0 |    5.22 | ...46-350,355-372 
  validation.ts    |   11.23 |      100 |       0 |   11.23 | ...97-104,107-111 
 ...gentManagement |    6.23 |      100 |       0 |    6.23 |                   
  ...entWizard.tsx |    4.06 |      100 |       0 |    4.06 | 33-239            
  ...ionWizard.tsx |    2.26 |      100 |       0 |    2.26 | 30-442            
  ...eteDialog.tsx |    6.59 |      100 |       0 |    6.59 | 21-127            
  ...tEditForm.tsx |    3.37 |      100 |       0 |    3.37 | 31-349            
  ...tListMenu.tsx |    3.97 |      100 |       0 |    3.97 | 25-236            
  ...tMainMenu.tsx |   16.66 |      100 |       0 |   16.66 | 21-61             
  ...gerDialog.tsx |    3.66 |      100 |       0 |    3.66 | 26-472            
  ...tShowView.tsx |    4.96 |      100 |       0 |    4.96 | 27-211            
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...comeOnboarding |   13.04 |        0 |       0 |   13.04 |                   
  ...ethodStep.tsx |   22.47 |      100 |       0 |   22.47 | 43-128            
  ...ationStep.tsx |    5.42 |      100 |       0 |    5.42 | 28-183            
  ...etionStep.tsx |    5.08 |      100 |       0 |    5.08 | 22-165            
  ...electStep.tsx |    7.95 |      100 |       0 |    7.95 | 30-131            
  ...electStep.tsx |   34.48 |      100 |       0 |   34.48 | 50-119            
  SkipExitStep.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...omeDialog.tsx |   12.38 |      100 |       0 |   12.38 | 37-146            
  WelcomeStep.tsx  |    10.2 |      100 |       0 |    10.2 | 23-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
 ...nents/messages |   20.14 |    88.09 |   13.33 |   20.14 |                   
  ...onMessage.tsx |   12.28 |      100 |       0 |   12.28 | 24-86             
  DiffRenderer.tsx |    3.33 |      100 |       0 |    3.33 | ...79-360,363-381 
  ErrorMessage.tsx |   22.22 |      100 |       0 |   22.22 | 16-31             
  ...niMessage.tsx |   14.51 |      100 |       0 |   14.51 | 28-95             
  ...geContent.tsx |   20.83 |      100 |       0 |   20.83 | 26-46             
  InfoMessage.tsx  |   19.23 |      100 |       0 |   19.23 | 19-41             
  ...rlMessage.tsx |   11.36 |      100 |       0 |   11.36 | 18-65             
  ...geMessage.tsx |     100 |      100 |     100 |     100 |                   
  ...ckDisplay.tsx |      20 |      100 |       0 |      20 | 43-64             
  ...onMessage.tsx |    4.01 |      100 |       0 |    4.01 | 46-464            
  ...upMessage.tsx |   10.55 |      100 |       0 |   10.55 | ...5,68-83,87-260 
  ToolMessage.tsx  |    8.38 |      100 |       0 |    8.38 | 46-219            
  ...ltDisplay.tsx |    87.5 |    84.61 |     100 |    87.5 | 58-60,116-132     
  ToolShared.tsx   |   64.61 |       90 |   33.33 |   64.61 | 78-99,102-105     
  UserMessage.tsx  |     100 |      100 |     100 |     100 |                   
  ...llMessage.tsx |   36.36 |      100 |       0 |   36.36 | 17-25             
  ...ngMessage.tsx |   26.31 |      100 |       0 |   26.31 | 17-32             
 ...ponents/shared |   41.59 |    61.12 |    43.1 |   41.59 |                   
  ...ctionList.tsx |    5.55 |      100 |       0 |    5.55 | 53-184            
  MaxSizedBox.tsx  |    48.7 |    56.16 |   88.88 |    48.7 | ...72-576,619-620 
  ...tonSelect.tsx |   12.76 |      100 |       0 |   12.76 | 66-113            
  ...lableList.tsx |    6.21 |      100 |       0 |    6.21 | 44-221            
  ...lizedList.tsx |    2.29 |      100 |       0 |    2.29 | 56-486            
  ...operations.ts |   75.67 |    48.14 |     100 |   75.67 | ...31-232,255-264 
  ...er-reducer.ts |   28.25 |    51.11 |   33.33 |   28.25 | ...30,632,644,687 
  buffer-types.ts  |     100 |      100 |     100 |     100 |                   
  text-buffer.ts   |   57.36 |    69.56 |    7.89 |   57.36 | ...15,561,566-570 
  ...formations.ts |   42.42 |    71.42 |      80 |   42.42 | ...27-134,158-204 
  ...n-handlers.ts |   33.99 |    61.53 |   23.25 |   33.99 | ...47-755,758-762 
  ...er-actions.ts |   93.84 |     87.5 |     100 |   93.84 | 91-93,100         
  visual-layout.ts |    90.2 |    71.73 |     100 |    90.2 | ...48-350,372-373 
  ...navigation.ts |   56.22 |     62.9 |   77.77 |   56.22 | ...21-333,359-381 
 ...mponents/views |    7.36 |      100 |       0 |    7.36 |                   
  ChatList.tsx     |    14.7 |      100 |       0 |    14.7 | 18-51             
  ...sionsList.tsx |    7.59 |      100 |       0 |    7.59 | 19-102            
  HooksList.tsx    |    5.06 |      100 |       0 |    5.06 | 17-106            
  SkillsList.tsx   |    6.06 |      100 |       0 |    6.06 | 18-99             
 src/ui/constants  |   56.16 |     92.3 |      50 |   56.16 |                   
  ...ollections.ts |     100 |      100 |     100 |     100 |                   
  tips.ts          |       0 |        0 |       0 |       0 | 1-164             
 src/ui/containers |       0 |        0 |       0 |       0 |                   
  ...ontroller.tsx |       0 |        0 |       0 |       0 | 1-354             
  UIStateShell.tsx |       0 |        0 |       0 |       0 | 1-15              
 ...ainer/builders |   98.37 |      100 |   83.33 |   98.37 |                   
  ...dUIActions.ts |     100 |      100 |     100 |     100 |                   
  buildUIState.ts  |     100 |      100 |     100 |     100 |                   
  ...onsBuilder.ts |   66.66 |      100 |       0 |   66.66 | 21-22             
  ...ateBuilder.ts |   66.66 |      100 |       0 |   66.66 | 21-22             
 ...ontainer/hooks |   51.42 |    82.35 |   51.28 |   51.42 |                   
  ...pBootstrap.ts |   94.71 |    58.33 |     100 |   94.71 | ...20-223,227-229 
  useAppDialogs.ts |   40.97 |      100 |   42.85 |   40.97 | ...55-157,174-376 
  ...ntHandlers.ts |     100 |      100 |     100 |     100 |                   
  useAppInput.ts   |     5.6 |      100 |       0 |     5.6 | 99-516,519-523    
  useAppLayout.ts  |    8.14 |      100 |       0 |    8.14 | 89-290,293-296    
  ...reenAction.ts |   13.63 |      100 |       0 |   13.63 | 23-42             
  ...nSelection.ts |      20 |      100 |       0 |      20 | 27-48             
  ...hestration.ts |     100 |      100 |     100 |     100 |                   
  ...references.ts |      10 |      100 |       0 |      10 | 51-104            
  ...itHandling.ts |   89.79 |      100 |     100 |   89.79 | 131-139,143       
  ...textBridge.ts |   33.33 |      100 |       0 |   33.33 | 23-30             
  ...tartHotkey.ts |   26.66 |      100 |       0 |   26.66 | 23-33             
  ...omptSubmit.ts |    6.12 |      100 |       0 |    6.12 | 26-74             
  ...utHandling.ts |   90.32 |    86.66 |     100 |   90.32 | 59,106-113        
  ...yBootstrap.ts |      30 |      100 |       0 |      30 | 28-34             
  ...eybindings.ts |   85.36 |    70.83 |     100 |   85.36 | ...05-207,241-242 
  ...easurement.ts |   15.38 |      100 |       0 |   15.38 | 44-94             
  ...reshAction.ts |   79.16 |     37.5 |     100 |   79.16 | 51,81-84,86-95    
  ...untimeSync.ts |     100 |      100 |     100 |     100 |                   
  ...elTracking.ts |   28.57 |      100 |     100 |   28.57 | 37-83             
  ...laceholder.ts |      15 |      100 |       0 |      15 | 13-18,21-34       
  ...rorTimeout.ts |   17.64 |      100 |       0 |   17.64 | 24-39             
  ...astructure.ts |   73.91 |      100 |      20 |   73.91 | 53,57,61,75-83    
  ...ebugLogger.ts |   17.24 |      100 |       0 |   17.24 | 23-51             
  ...ialization.ts |   70.93 |    84.61 |     100 |   70.93 | 68-92,124-125     
  ...sAutoReset.ts |   21.87 |      100 |       0 |   21.87 | 28-54             
  ...andActions.ts |     100 |      100 |     100 |     100 |                   
  ...eshManager.ts |     100 |      100 |     100 |     100 |                   
  ...uationFlow.ts |    7.93 |      100 |       0 |    7.93 | 54-150            
  ...csTracking.ts |   98.15 |    81.48 |     100 |   98.15 | 88,107-108        
  ...uthBridges.ts |   36.84 |      100 |     100 |   36.84 | 47-70,74-78       
 src/ui/contexts   |   54.21 |    76.75 |   46.55 |   54.21 |                   
  ...chContext.tsx |    64.7 |      100 |      50 |    64.7 | 24-29             
  FocusContext.tsx |       0 |        0 |       0 |       0 | 1-11              
  ...ssContext.tsx |   81.62 |    84.05 |     100 |   81.62 | ...78-679,734-735 
  MouseContext.tsx |   74.72 |       75 |      80 |   74.72 | ...00-101,112-125 
  ...erContext.tsx |       0 |        0 |       0 |       0 | 1-120             
  ...owContext.tsx |   21.42 |      100 |   33.33 |   21.42 | 33,39-87          
  ...meContext.tsx |   53.12 |    36.36 |   57.14 |   53.12 | ...86,194-195,200 
  ...lProvider.tsx |   90.61 |     70.9 |     100 |   90.61 | ...74-375,387-388 
  ...onContext.tsx |     6.7 |      100 |       0 |     6.7 | ...90-284,289-296 
  ...teContext.tsx |       0 |        0 |       0 |       0 | 1-61              
  ...gsContext.tsx |      50 |      100 |       0 |      50 | 15-20             
  ...ngContext.tsx |   42.85 |      100 |       0 |   42.85 | 15-22             
  TodoContext.tsx  |   54.54 |      100 |       0 |   54.54 | 28-31,33-36,39-40 
  TodoProvider.tsx |    5.55 |      100 |       0 |    5.55 | 24-126            
  ...llContext.tsx |     100 |      100 |       0 |     100 |                   
  ...lProvider.tsx |    6.75 |      100 |       0 |    6.75 | 28-122            
  ...nsContext.tsx |      25 |      100 |       0 |      25 | 202-213,216-221   
  ...teContext.tsx |      50 |       50 |      50 |      50 | 248-257,262-263   
  ...deContext.tsx |   11.11 |      100 |       0 |   11.11 | 29-81,84-89       
 src/ui/editors    |   98.18 |     87.5 |     100 |   98.18 |                   
  ...ngsManager.ts |   98.18 |     87.5 |     100 |   98.18 | 59                
 src/ui/hooks      |   62.63 |    83.84 |   73.68 |   62.63 |                   
  ...dProcessor.ts |   71.09 |     75.6 |      75 |   71.09 | ...72-694,716-722 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...dProcessor.ts |   94.81 |       75 |     100 |   94.81 | ...05-306,311-312 
  ...dProcessor.ts |   25.91 |       55 |      50 |   25.91 | ...28-429,434-975 
  toolMapping.ts   |    91.3 |    92.85 |     100 |    91.3 | 130,157-167       
  ...nateBuffer.ts |      50 |      100 |       0 |      50 | 16-18             
  ...dScrollbar.ts |   96.77 |      100 |     100 |   96.77 | 112-114           
  ...Completion.ts |   94.42 |    88.77 |     100 |   94.42 | ...19,342,388-390 
  ...uthCommand.ts |      16 |      100 |       0 |      16 | 13-36             
  ...tIndicator.ts |     100 |     92.3 |     100 |     100 | 57                
  useBanner.ts     |     100 |    81.81 |     100 |     100 | 22,45             
  ...chedScroll.ts |   16.66 |      100 |       0 |   16.66 | 14-32             
  ...ketedPaste.ts |      20 |      100 |       0 |      20 | 20-38             
  ...ompletion.tsx |   93.11 |    81.81 |      50 |   93.11 | ...34-235,239-246 
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | ...,95-96,100-101 
  ...leMessages.ts |   96.25 |    90.47 |     100 |   96.25 | 56-57,63          
  ...ntHandlers.ts |    32.6 |      100 |     100 |    32.6 | 43-68,72-80       
  ...fileDialog.ts |   16.12 |      100 |       0 |   16.12 | 17-47             
  ...orSettings.ts |   11.86 |      100 |       0 |   11.86 | 31-87             
  ...AutoUpdate.ts |    9.52 |      100 |       0 |    9.52 | 18-58             
  ...ionUpdates.ts |   67.31 |    76.92 |   66.66 |   67.31 | ...76-182,197-214 
  ...erDetector.ts |     100 |      100 |     100 |     100 |                   
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |   86.27 |    94.11 |     100 |   86.27 | 95-108            
  ...BranchName.ts |     100 |    89.47 |     100 |     100 | 58,61             
  ...oryManager.ts |   96.37 |     92.1 |     100 |   96.37 | ...75-176,219-220 
  ...splayState.ts |     100 |      100 |     100 |     100 |                   
  ...stListener.ts |   12.12 |      100 |       0 |   12.12 | 17-50             
  ...ivityTimer.ts |   76.19 |    66.66 |     100 |   76.19 | 30-35             
  ...putHistory.ts |    92.5 |    85.71 |     100 |    92.5 | 62-63,71,93-95    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 67                
  useKeypress.ts   |   22.22 |      100 |       0 |   22.22 | 24-39             
  ...rdProtocol.ts |       0 |        0 |       0 |       0 | 1-26              
  ...fileDialog.ts |    5.71 |      100 |       0 |    5.71 | 27-135            
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   93.75 |      100 |     100 |   93.75 | 26                
  useMcpStatus.ts  |   90.47 |    66.66 |     100 |   90.47 | 19,33-35          
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  useMouse.ts      |   77.77 |    66.66 |     100 |   77.77 | 31-34             
  useMouseClick.ts |     100 |      100 |     100 |     100 |                   
  ...eSelection.ts |    3.04 |      100 |       0 |    3.04 | 36-103,106-322    
  ...hestration.ts |      10 |      100 |       0 |      10 | 28-63             
  ...oviderInfo.ts |       0 |        0 |       0 |       0 | 1-80              
  ...odifyTrust.ts |    9.09 |      100 |       0 |    9.09 | 46-137            
  ...raseCycler.ts |   79.16 |    71.42 |     100 |   79.16 | ...69,72-73,89-91 
  ...cySettings.ts |   85.84 |    81.81 |     100 |   85.84 | ...,88-92,120-131 
  ...Management.ts |     2.4 |      100 |       0 |     2.4 | 21-62,74-438      
  ...Completion.ts |   29.56 |       40 |     100 |   29.56 | ...13-226,235-241 
  ...iderDialog.ts |    6.81 |      100 |       0 |    6.81 | 28-123            
  ...lScheduler.ts |   67.25 |    76.47 |      60 |   67.25 | ...60,467-489,494 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  useResponsive.ts |     100 |      100 |     100 |     100 |                   
  ...ompletion.tsx |   69.56 |      100 |     100 |   69.56 | 45-47,51-66,78-81 
  useRewind.ts     |     100 |      100 |     100 |     100 |                   
  ...ectionList.ts |   87.29 |    88.04 |     100 |   87.29 | ...10-411,420-423 
  useSession.ts    |       0 |        0 |       0 |       0 | 1-23              
  ...ionBrowser.ts |   89.59 |     84.5 |    91.3 |   89.59 | ...68-669,726-727 
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.66 |    79.41 |     100 |   91.66 | ...69,117-118,128 
  ...Completion.ts |   96.29 |    79.31 |     100 |   96.29 | 90-92,119-120     
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-62              
  ...ompletion.tsx |   82.12 |    85.02 |      75 |   82.12 | ...03-904,915-916 
  ...leCallback.ts |     100 |      100 |     100 |     100 |                   
  ...tateAndRef.ts |   59.09 |      100 |     100 |   59.09 | 23-31             
  ...oryRefresh.ts |     100 |      100 |     100 |     100 |                   
  ...rminalSize.ts |   11.42 |      100 |       0 |   11.42 | 13-55             
  ...emeCommand.ts |    6.03 |      100 |       0 |    6.03 | 26-151            
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...ntinuation.ts |   91.16 |    91.89 |     100 |   91.16 | ...54-155,180-189 
  ...ePreserver.ts |   57.14 |      100 |      80 |   57.14 | 58-76             
  ...oolsDialog.ts |    4.67 |      100 |       0 |    4.67 | 24-145            
  ...Onboarding.ts |    2.47 |      100 |       0 |    2.47 | 78-407            
  ...eMigration.ts |   11.86 |      100 |       0 |   11.86 | 15-73             
  vim.ts           |    83.6 |     79.5 |     100 |    83.6 | ...39,743-751,760 
 ...s/geminiStream |   76.44 |    74.18 |   90.62 |   76.44 |                   
  ...ersistence.ts |   98.26 |    95.23 |     100 |   98.26 | 158-160           
  index.ts         |     100 |      100 |     100 |     100 |                   
  streamUtils.ts   |   98.98 |    95.34 |     100 |   98.98 | 361-363           
  ...ionHandler.ts |   71.36 |    88.88 |     100 |   71.36 | ...92-299,333-339 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...miniStream.ts |   76.75 |    59.52 |      40 |   76.75 | ...67,574,611-613 
  ...ntHandlers.ts |   62.31 |    51.13 |     100 |   62.31 | ...12-813,816-820 
 src/ui/layouts    |   60.33 |    29.41 |   33.33 |   60.33 |                   
  ...AppLayout.tsx |   60.33 |    29.41 |   33.33 |   60.33 | ...95-689,693-718 
 ...noninteractive |      75 |      100 |    6.66 |      75 |                   
  ...eractiveUi.ts |      75 |      100 |    6.66 |      75 | 17-19,23-24,27-28 
 src/ui/privacy    |   21.98 |        0 |       0 |   21.98 |                   
  ...acyNotice.tsx |       0 |        0 |       0 |       0 | 1-123             
  ...acyNotice.tsx |       0 |        0 |       0 |       0 | 1-59              
  ...acyNotice.tsx |   12.19 |      100 |       0 |   12.19 | 16-62             
  ...acyNotice.tsx |   41.33 |      100 |       0 |   41.33 | 78-91,99-193      
  ...acyNotice.tsx |      25 |      100 |       0 |      25 | 21-43,46-48       
 src/ui/reducers   |   78.44 |     90.9 |      50 |   78.44 |                   
  appReducer.ts    |     100 |      100 |     100 |     100 |                   
  ...ionReducer.ts |       0 |        0 |       0 |       0 | 1-52              
 src/ui/state      |   54.34 |    30.76 |     100 |   54.34 |                   
  extensions.ts    |   54.34 |    30.76 |     100 |   54.34 | ...28,130-142,144 
 src/ui/themes     |   99.04 |    84.41 |   96.96 |   99.04 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |     100 |      100 |     100 |     100 |                   
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  green-screen.ts  |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  ...c-resolver.ts |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-compat.ts  |     100 |       50 |     100 |     100 | 79                
  theme-manager.ts |   88.79 |    82.81 |     100 |   88.79 | ...13-322,327-328 
  theme.ts         |    99.1 |    79.13 |    87.5 |    99.1 | 282-283,699-700   
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/types      |       0 |        0 |       0 |       0 |                   
  ...ngMetadata.ts |       0 |        0 |       0 |       0 |                   
 src/ui/utils      |   57.85 |     86.9 |   73.59 |   57.85 |                   
  ...Colorizer.tsx |    6.36 |      100 |       0 |    6.36 | ...17-129,141-233 
  ...olePatcher.ts |   68.88 |      100 |   83.33 |   68.88 | 51-64             
  ...nRenderer.tsx |   16.23 |      100 |      50 |   16.23 | 27-171            
  ...wnDisplay.tsx |    5.63 |      100 |       0 |    5.63 | ...00-425,436-440 
  ...eRenderer.tsx |   10.63 |      100 |       0 |   10.63 | ...32-247,260-395 
  ...tGenerator.ts |   72.72 |    61.53 |      60 |   72.72 | ...66,69-72,84-85 
  ...ketedPaste.ts |      60 |      100 |       0 |      60 | 13-14,17-18       
  clipboard.ts     |   97.29 |    84.61 |     100 |   97.29 | 40                
  ...boardUtils.ts |    64.7 |     77.5 |     100 |    64.7 | ...31-242,312-313 
  commandUtils.ts  |   92.75 |    95.23 |   95.45 |   92.75 | ...08-212,298-306 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  displayUtils.ts  |     100 |      100 |     100 |     100 |                   
  formatters.ts    |   90.47 |    95.23 |     100 |   90.47 | 57-60             
  fuzzyFilter.ts   |     100 |    96.55 |     100 |     100 | 75                
  highlight.ts     |   73.22 |    94.44 |      50 |   73.22 | 133-165,169-174   
  ...xportUtils.ts |     100 |      100 |     100 |     100 |                   
  ...storyItems.ts |   98.95 |    94.11 |     100 |   98.95 | 88                
  input.ts         |   64.51 |    85.71 |   33.33 |   64.51 | 18-25,51-58       
  isNarrowWidth.ts |      50 |      100 |       0 |      50 | 13-14             
  ...nUtilities.ts |   69.84 |    86.66 |     100 |   69.84 | 75-91,100-101     
  mouse.ts         |   83.69 |    71.42 |     100 |   83.69 | ...03,210,223-224 
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  ...opDetector.ts |       0 |        0 |       0 |       0 | 1-210             
  responsive.ts    |    69.9 |    73.33 |      80 |    69.9 | ...95-103,106-121 
  rewindFileOps.ts |   88.02 |     64.7 |     100 |   88.02 | ...40-244,246-251 
  ...putHandler.ts |   84.24 |    86.53 |     100 |   84.24 | ...25-134,228-229 
  ...ityManager.ts |   94.11 |     83.6 |   88.88 |   94.11 | ...96,320,348,359 
  ...alContract.ts |     100 |      100 |     100 |     100 |                   
  terminalLinks.ts |     100 |      100 |     100 |     100 |                   
  ...colCleanup.ts |     100 |      100 |     100 |     100 |                   
  ...lSequences.ts |     100 |      100 |     100 |     100 |                   
  terminalSetup.ts |    4.16 |      100 |       0 |    4.16 | 42-361            
  textUtils.ts     |   95.41 |    92.59 |   88.88 |   95.41 | 20-25             
  ...Formatters.ts |       0 |        0 |       0 |       0 | 1-52              
  ...icsTracker.ts |     100 |    94.44 |     100 |     100 | 38                
  ui-sizing.ts     |      16 |      100 |       0 |      16 | 11-23,26-36       
  updateCheck.ts   |     100 |    94.11 |     100 |     100 | 33,44             
 src/utils         |   62.66 |    87.67 |   84.48 |   62.66 |                   
  ...ionContext.ts |   76.92 |       75 |     100 |   76.92 | 38-41,63-66,81-84 
  bootstrap.ts     |    97.4 |    95.65 |     100 |    97.4 | 76-77             
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   67.21 |       80 |      60 |   67.21 | ...69-71,74,88-97 
  commands.ts      |    50.9 |    63.63 |     100 |    50.9 | 25-26,45,57-84    
  commentJson.ts   |    92.3 |     92.5 |     100 |    92.3 | 94-102            
  ...ScopeUtils.ts |   27.58 |      100 |       0 |   27.58 | 23-40,57-85       
  ...icSettings.ts |   88.61 |    89.18 |     100 |   88.61 | ...41,44-47,65-68 
  ...arResolver.ts |   96.42 |       96 |     100 |   96.42 | 111-112           
  errors.ts        |   94.36 |       88 |     100 |   94.36 | 50-51,86-87       
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...lativeTime.ts |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   93.68 |    84.21 |     100 |   93.68 | 63-64,79-82       
  ...AutoUpdate.ts |   67.18 |    76.59 |   71.42 |   67.18 | ...13-214,261-326 
  ...lationInfo.ts |   99.38 |    97.87 |     100 |   99.38 | 98                
  math.ts          |   66.66 |      100 |       0 |   66.66 | 15                
  ...stentState.ts |   95.38 |       85 |     100 |   95.38 | 43,64-65          
  readStdin.ts     |   81.03 |    91.66 |   83.33 |   81.03 | 32-39,51-53       
  relaunch.ts      |     100 |      100 |     100 |     100 |                   
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  sandbox.ts       |   32.64 |    85.27 |   70.58 |   32.64 | ...1018,1035-2226 
  ...ionCleanup.ts |   85.82 |    83.56 |     100 |   85.82 | ...54-255,336-337 
  sessionUtils.ts  |    7.89 |      100 |       0 |    7.89 | 51-120,127-141    
  settingsUtils.ts |   84.14 |    90.52 |   93.33 |   84.14 | ...12-439,478-479 
  ...ttingSaver.ts |    1.92 |      100 |       0 |    1.92 | 7-28,36-81        
  skillSettings.ts |   86.13 |       88 |     100 |   86.13 | 99-107,134-138    
  skillUtils.ts    |   57.71 |    60.71 |      75 |   57.71 | ...85-186,193-214 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdinSafety.ts   |   91.44 |    86.48 |     100 |   91.44 | ...66-167,171,246 
  terminalTheme.ts |     100 |      100 |     100 |     100 |                   
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  version.ts       |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
 src/utils/privacy |    46.3 |    68.57 |   52.63 |    46.3 |                   
  ...taRedactor.ts |   60.66 |    70.58 |   55.55 |   60.66 | ...77-479,485-506 
  ...acyManager.ts |       0 |        0 |       0 |       0 | 1-178             
 ...ed-integration |    8.29 |     92.3 |      20 |    8.29 |                   
  ...temService.ts |     100 |      100 |     100 |     100 |                   
  ...ntegration.ts |    6.27 |     87.5 |   11.11 |    6.27 | ...1538,1553-1623 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   78.17 |     81.5 |   78.13 |   78.17 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/adapters      |     100 |      100 |     100 |     100 |                   
  ...eamAdapter.ts |     100 |      100 |     100 |     100 |                   
 src/agents        |   90.01 |    74.21 |     100 |   90.01 |                   
  executor.ts      |   89.34 |    73.33 |     100 |   89.34 | ...64-765,801-807 
  invocation.ts    |   96.55 |    76.47 |     100 |   96.55 | 61,65-66          
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   78.94 |       80 |     100 |   78.94 | 32-35             
 src/auth          |   68.26 |    81.34 |   79.81 |   68.26 |                   
  ...evice-flow.ts |    7.21 |        0 |       0 |    7.21 | ...49-268,274-282 
  ...evice-flow.ts |   46.65 |    57.14 |   63.63 |   46.65 | ...95-484,494-580 
  ...oken-store.ts |   88.92 |       87 |     100 |   88.92 | ...84-387,408-414 
  oauth-errors.ts  |   94.15 |    83.33 |     100 |   94.15 | ...69,610,636-637 
  precedence.ts    |      78 |    80.07 |   94.73 |      78 | ...1072,1078-1081 
  ...evice-flow.ts |    8.33 |      100 |       0 |    8.33 | ...69-206,214-220 
  token-merge.ts   |     100 |      100 |     100 |     100 |                   
  ...nitization.ts |     100 |      100 |     100 |     100 |                   
  token-store.ts   |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/auth/proxy    |   90.37 |    84.95 |   86.27 |   90.37 |                   
  framing.ts       |    97.1 |    90.47 |     100 |    97.1 | 83-84             
  ...ey-storage.ts |   94.28 |       80 |     100 |   94.28 | 45-46             
  ...ket-client.ts |   86.51 |       88 |   78.26 |   86.51 | ...32-235,255-258 
  ...oken-store.ts |   93.02 |    77.77 |   84.61 |   93.02 | 104-108,112       
 src/code_assist   |   68.13 |    79.31 |   76.47 |   68.13 |                   
  codeAssist.ts    |   17.64 |       50 |   33.33 |   17.64 | 16-62,70-73,81-94 
  converter.ts     |   94.96 |    93.02 |     100 |   94.96 | ...88,202,219-220 
  ...al-storage.ts |   98.21 |       75 |     100 |   98.21 | 76,125            
  oauth2.ts        |   62.83 |    76.47 |   78.57 |   62.83 | ...07-708,713-714 
  server.ts        |   48.16 |    72.72 |      50 |   48.16 | ...08-249,252-255 
  setup.ts         |   82.92 |    73.91 |     100 |   82.92 | ...27-129,153-159 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/commands      |     100 |      100 |     100 |     100 |                   
  extensions.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   71.69 |    79.81 |   61.61 |   71.69 |                   
  config.ts        |   66.66 |       71 |    60.6 |   66.66 | ...67-776,803-807 
  configBase.ts    |    64.9 |    80.85 |   72.72 |    64.9 | ...18-231,244-265 
  ...igBaseCore.ts |   71.35 |    94.44 |   47.85 |   71.35 | ...82-683,685-686 
  ...onstructor.ts |   96.37 |    88.33 |     100 |   96.37 | ...08-409,412-413 
  configTypes.ts   |   60.37 |      100 |      50 |   60.37 | 187-227           
  constants.ts     |     100 |      100 |     100 |     100 |                   
  endpoints.ts     |     100 |      100 |     100 |     100 |                   
  ...ngsHelpers.ts |   67.56 |       50 |     100 |   67.56 | ...26,30-31,35-36 
  index.ts         |       0 |        0 |       0 |       0 | 1-38              
  ...ntegration.ts |   57.66 |    72.72 |   58.33 |   57.66 | ...31,348,357,366 
  models.ts        |     100 |      100 |     100 |     100 |                   
  ...ileManager.ts |    84.3 |    80.26 |     100 |    84.3 | ...09-413,415-419 
  ...rSingleton.ts |   75.43 |    80.95 |   41.66 |   75.43 | ...20,323-326,334 
  storage.ts       |   91.15 |    87.09 |    93.1 |   91.15 | ...,73,75,100-101 
  ...entManager.ts |   52.46 |     67.5 |   68.18 |   52.46 | ...76-677,695-719 
  ...tryFactory.ts |   84.45 |    78.26 |      50 |   84.45 | ...21-235,244-253 
  types.ts         |       0 |        0 |       0 |       0 |                   
 ...nfirmation-bus |   71.42 |     86.2 |      75 |   71.42 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-2               
  message-bus.ts   |   70.23 |    88.88 |   81.81 |   70.23 | ...08-242,251-259 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   80.35 |    78.28 |   76.53 |   80.35 |                   
  ...ookManager.ts |     100 |      100 |     100 |     100 |                   
  ...ionFactory.ts |   94.55 |    89.74 |     100 |   94.55 | ...80-282,328-331 
  ...ionManager.ts |   66.18 |    62.22 |   56.25 |   66.18 | ...26-434,441-445 
  ...eProcessor.ts |   53.57 |    30.18 |   68.75 |   53.57 | ...75-528,543-554 
  ...extTracker.ts |   93.62 |    88.73 |     100 |   93.62 | ...74-177,217-221 
  ...eConverter.ts |   58.92 |    74.11 |   57.14 |   58.92 | ...75,538,549-560 
  ...chestrator.ts |   88.01 |       75 |      75 |   88.01 | ...77-882,922-928 
  ...mProcessor.ts |   72.14 |    77.86 |   59.37 |   72.14 | ...89,893,905-927 
  ...ionService.ts |   91.87 |    91.81 |     100 |   91.87 | ...99,359,384-406 
  TurnProcessor.ts |   77.08 |    64.36 |   70.37 |   77.08 | ...74-675,677-727 
  baseLlmClient.ts |   95.23 |    90.74 |     100 |   95.23 | ...85-286,367-368 
  ...ntegration.ts |   96.66 |    96.07 |     100 |   96.66 | ...37-138,218-219 
  client.ts        |   62.54 |    83.09 |      68 |   62.54 | ...40-658,710-726 
  clientHelpers.ts |   89.47 |     83.6 |     100 |   89.47 | ...,82-83,103-106 
  ...mUtilities.ts |   96.77 |    70.58 |     100 |   96.77 | ...15-116,172-173 
  ...Governance.ts |   98.01 |    97.14 |     100 |   98.01 | 101-102           
  ...ion-config.ts |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   97.22 |    90.47 |     100 |   97.22 | 100-101           
  ...okTriggers.ts |   77.19 |    65.85 |     100 |   77.19 | ...70-271,295-300 
  ...lScheduler.ts |   82.25 |    88.77 |   70.45 |   82.25 | ...15-719,733-734 
  geminiChat.ts    |   82.68 |    80.76 |   60.41 |   82.68 | ...61-462,493-494 
  ...iChatTypes.ts |   94.73 |      100 |      80 |   94.73 | 112-113           
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...nAIWrapper.ts |   88.88 |      100 |   83.33 |   88.88 | 56-59             
  ...okTriggers.ts |   96.21 |    89.13 |     100 |   96.21 | ...13,157,209,256 
  logger.ts        |   80.96 |    81.81 |     100 |   80.96 | ...65-379,426-440 
  ...olExecutor.ts |   59.79 |       60 |      50 |   59.79 | ...31-136,148-177 
  prompts.ts       |   85.26 |    61.42 |    90.9 |   85.26 | ...52-455,465,487 
  subagent.ts      |   76.45 |     62.5 |   95.83 |   76.45 | ...21-826,831-833 
  ...tExecution.ts |   59.67 |    83.05 |   73.33 |   59.67 | ...94,498,500-503 
  ...chestrator.ts |   90.38 |    76.59 |   95.83 |   90.38 | ...61,664-665,670 
  ...ntimeSetup.ts |   84.95 |    78.21 |   57.89 |   84.95 | ...80-584,619-627 
  ...tScheduler.ts |       0 |        0 |       0 |       0 | 1                 
  ...Processing.ts |      88 |    84.94 |     100 |      88 | ...75,479-507,514 
  subagentTypes.ts |     100 |      100 |   83.33 |     100 |                   
  tokenLimits.ts   |   88.15 |    70.37 |     100 |   88.15 | ...79,81,83,87,97 
  ...Governance.ts |    94.2 |     90.9 |     100 |    94.2 | 34-35,51-52       
  turn.ts          |   92.69 |    80.48 |   81.81 |   92.69 | ...00-601,631-632 
  turnLogging.ts   |   75.29 |    66.66 |      80 |   75.29 | 35-58             
 ...re/compression |   84.37 |    84.91 |   88.17 |   84.37 |                   
  ...ionHandler.ts |   86.94 |    83.17 |   74.19 |   86.94 | ...24-825,833-834 
  ...tyStrategy.ts |   92.32 |    88.88 |   93.75 |   92.32 | ...34,893-894,931 
  ...utStrategy.ts |   88.51 |    76.92 |     100 |   88.51 | ...35-446,449-458 
  ...otStrategy.ts |   82.08 |    75.67 |     100 |   82.08 | ...76-287,290-299 
  ...onStrategy.ts |     100 |      100 |     100 |     100 |                   
  ...nBudgeting.ts |   36.06 |       70 |     100 |   36.06 | ...06-107,112-164 
  ...egyFactory.ts |   90.62 |    88.88 |     100 |   90.62 | 52-54             
  index.ts         |       0 |        0 |       0 |       0 | 1-17              
  types.ts         |   99.03 |    91.42 |     100 |   99.03 | 239               
  utils.ts         |   71.94 |    87.91 |      90 |   71.94 | ...98-399,416-417 
 src/debug         |   78.31 |    88.53 |    87.3 |   78.31 |                   
  ...ionManager.ts |   77.66 |    78.04 |      85 |   77.66 | ...33-234,251-255 
  DebugLogger.ts   |   90.78 |    90.47 |   88.46 |   90.78 | ...77,221-225,268 
  FileOutput.ts    |   88.13 |    94.11 |   86.66 |   88.13 | ...32-136,162-163 
  ...ionManager.ts |       0 |      100 |     100 |       0 | 18-64             
  ...FileOutput.ts |       0 |      100 |     100 |       0 | 17-39             
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/filters       |   99.19 |    98.79 |     100 |   99.19 |                   
  EmojiFilter.ts   |   99.19 |    98.79 |     100 |   99.19 | 208-209           
 src/hooks         |   84.89 |    84.74 |   83.68 |   84.89 |                   
  errors.ts        |     100 |      100 |     100 |     100 |                   
  ...Aggregator.ts |    92.7 |    89.23 |    87.5 |    92.7 | ...31,350,352,354 
  ...sContracts.ts |       0 |        0 |       0 |       0 | 1                 
  ...entHandler.ts |   91.62 |    85.82 |   93.33 |   91.62 | ...20,756-762,807 
  hookPlanner.ts   |   98.79 |    93.33 |     100 |   98.79 | 103               
  hookRegistry.ts  |   98.25 |    86.56 |     100 |   98.25 | 341,343,345,347   
  hookRunner.ts    |    83.8 |    81.48 |     100 |    83.8 | ...08-310,319-320 
  hookSystem.ts    |   71.02 |    89.47 |      70 |   71.02 | ...49-351,364-366 
  ...Translator.ts |   94.65 |     65.9 |     100 |   94.65 | ...88-289,300,349 
  ...Validators.ts |    92.3 |    88.52 |     100 |    92.3 | 57-59,78-80       
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ssion-hook.ts |   88.88 |    33.33 |     100 |   88.88 | 24,30             
  trustedHooks.ts  |   20.77 |      100 |       0 |   20.77 | ...6,82-90,96-109 
  types.ts         |    65.6 |    86.95 |   70.83 |    65.6 | ...58-379,426-427 
 ...oks/test-utils |       0 |        0 |       0 |       0 |                   
  ...igWithHook.ts |       0 |        0 |       0 |       0 | 1-139             
 src/ide           |   73.67 |    86.17 |   73.07 |   73.67 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   56.37 |    79.66 |   54.83 |   56.37 | ...21-529,557-565 
  ide-installer.ts |   90.55 |    85.18 |     100 |   90.55 | ...35,142-146,159 
  ideContext.ts    |   84.82 |      100 |     100 |   84.82 | 89-105            
  process-utils.ts |    89.2 |    82.14 |     100 |    89.2 | ...70-171,212-213 
 src/interfaces    |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 |                   
  ....interface.ts |       0 |        0 |       0 |       0 |                   
 src/lsp           |   71.03 |    73.91 |      90 |   71.03 |                   
  ...ice-client.ts |   71.03 |    73.62 |   89.47 |   71.03 | ...06,448-468,479 
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/mcp           |   79.82 |    78.71 |   72.41 |   79.82 |                   
  auth-provider.ts |       0 |        0 |       0 |       0 | 1                 
  ...oken-store.ts |    86.4 |    90.47 |   81.25 |    86.4 | ...39-340,343-344 
  ...h-provider.ts |    90.1 |      100 |      40 |    90.1 | ...97,101,105-106 
  ...h-provider.ts |   76.26 |     57.4 |     100 |   76.26 | ...39,968,975-977 
  ...en-storage.ts |    81.5 |    88.88 |   68.18 |    81.5 | ...97-198,203-204 
  oauth-utils.ts   |   72.44 |    85.36 |    92.3 |   72.44 | ...09-313,339-374 
  ...n-provider.ts |      88 |    94.73 |   33.33 |      88 | ...37,141,145-146 
  token-store.ts   |     100 |      100 |     100 |     100 |                   
 .../token-storage |   88.17 |    87.94 |   93.02 |   88.17 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   86.61 |    87.09 |   92.85 |   86.61 | ...64-172,180-181 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   83.76 |    83.11 |   84.61 |   83.76 | ...57,259,311-312 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/models        |   83.44 |    91.15 |    87.5 |   83.44 |                   
  hydration.ts     |    4.76 |      100 |       0 |    4.76 | 65-129,151-231    
  index.ts         |     100 |      100 |     100 |     100 |                   
  profiles.ts      |     100 |      100 |     100 |     100 |                   
  ...ntegration.ts |   95.31 |    85.36 |     100 |   95.31 | ...35-136,199-200 
  registry.ts      |   90.45 |    88.88 |      92 |   90.45 | ...69-270,389-402 
  schema.ts        |     100 |      100 |     100 |     100 |                   
  transformer.ts   |     100 |      100 |     100 |     100 |                   
 src/parsers       |    70.7 |       75 |    86.2 |    70.7 |                   
  ...CallParser.ts |    70.7 |       75 |    86.2 |    70.7 | ...1,983,989-1004 
 src/policy        |   83.85 |    80.13 |   91.42 |   83.85 |                   
  config.ts        |   70.08 |     72.3 |   85.71 |   70.08 | ...67,521,585-586 
  index.ts         |     100 |      100 |     100 |     100 |                   
  policy-engine.ts |   96.71 |    89.33 |     100 |   96.71 | 71-74,104         
  ...cy-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...-stringify.ts |   80.23 |    60.52 |      50 |   80.23 | ...22-126,139-140 
  toml-loader.ts   |   89.88 |    83.52 |     100 |   89.88 | ...75,477,484,486 
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   81.81 |    84.61 |     100 |   81.81 | 24-27,30-33       
 src/prompt-config |   75.67 |    84.64 |   85.55 |   75.67 |                   
  ...lateEngine.ts |   91.05 |    86.36 |     100 |   91.05 | ...18-321,332-335 
  index.ts         |       0 |      100 |     100 |       0 | 5-41              
  prompt-cache.ts  |   99.08 |    97.43 |     100 |   99.08 | 216-217           
  ...-installer.ts |   83.11 |     82.4 |     100 |   83.11 | ...1173,1253-1254 
  prompt-loader.ts |   88.02 |    91.57 |   76.92 |   88.02 | ...79-388,430-431 
  ...t-resolver.ts |   35.02 |    66.17 |   53.84 |   35.02 | ...21-772,775-803 
  ...pt-service.ts |   85.21 |     83.8 |      80 |   85.21 | ...30,547-554,585 
  ...delegation.ts |   93.54 |    91.66 |     100 |   93.54 | 33-34             
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...onfig/defaults |    50.4 |    43.53 |     100 |    50.4 |                   
  core-defaults.ts |   38.02 |    35.89 |     100 |   38.02 | ...73,284,290-298 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...est-loader.ts |   81.81 |    79.31 |     100 |   81.81 | ...02-108,116-120 
  ...t-warnings.ts |    92.3 |    33.33 |     100 |    92.3 | 18-19             
  ...r-defaults.ts |   42.61 |    31.57 |     100 |   42.61 | ...49,260,266-271 
  ...e-defaults.ts |     100 |      100 |     100 |     100 |                   
  tool-defaults.ts |   49.77 |    36.84 |     100 |   49.77 | ...14-220,233-238 
 src/prompts       |   27.77 |      100 |      25 |   27.77 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |   30.23 |      100 |   28.57 |   30.23 | ...43,49-56,69-74 
 src/providers     |   71.12 |    80.75 |   66.81 |   71.12 |                   
  BaseProvider.ts  |   80.07 |    78.57 |   78.84 |   80.07 | ...1192,1195-1196 
  ...eratorRole.ts |     100 |      100 |     100 |     100 |                   
  IModel.ts        |       0 |        0 |       0 |       0 |                   
  IProvider.ts     |       0 |        0 |       0 |       0 |                   
  ...derManager.ts |     100 |      100 |     100 |     100 |                   
  ITool.ts         |       0 |        0 |       0 |       0 |                   
  ...ngProvider.ts |   86.52 |    88.23 |   88.57 |   86.52 | ...1200,1236-1238 
  ...derWrapper.ts |    62.6 |    72.25 |    57.5 |    62.6 | ...1448,1467-1474 
  ...tGenerator.ts |    17.3 |      100 |       0 |    17.3 | ...59,62-79,82-85 
  ...derManager.ts |   57.93 |     75.1 |   60.46 |   57.93 | ...1564-1565,1568 
  ...chestrator.ts |   81.42 |    88.94 |   70.83 |   81.42 | ...77-681,683-690 
  ...taResolver.ts |   97.27 |    93.18 |     100 |   97.27 | 173-175           
  errors.ts        |   75.98 |    69.44 |   42.85 |   75.98 | ...82-283,292-293 
  ...ConfigKeys.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ders/anthropic |   88.51 |    86.08 |   88.72 |   88.51 |                   
  ...iExecution.ts |     100 |     92.3 |     100 |     100 | 201,225           
  ...Normalizer.ts |   90.07 |    86.45 |     100 |   90.07 | ...89-693,698-703 
  ...eValidator.ts |   98.38 |    99.12 |     100 |   98.38 | ...99,413-414,449 
  ...cModelData.ts |   92.26 |       95 |      75 |   92.26 | 176-189,234-235   
  ...icProvider.ts |    78.6 |    77.77 |   73.17 |    78.6 | ...00-502,633-634 
  ...mitHandler.ts |   98.61 |     97.1 |     100 |   98.61 | 130,214-215       
  ...estBuilder.ts |    88.2 |       88 |     100 |    88.2 | ...97-198,211-212 
  ...reparation.ts |   95.92 |    83.13 |   93.33 |   95.92 | ...46,588,634,721 
  ...onseParser.ts |   75.89 |     61.9 |     100 |   75.89 | ...24-128,178-179 
  ...mProcessor.ts |   84.71 |    83.78 |     100 |   84.71 | ...20,379,468,490 
  ...aConverter.ts |   50.94 |    44.11 |   71.42 |   50.94 | ...60-264,279-287 
  usageInfo.ts     |   92.24 |    96.96 |     100 |   92.24 | ...02-107,117-119 
 ...pic/test-utils |       0 |        0 |       0 |       0 |                   
  ...cTestUtils.ts |       0 |        0 |       0 |       0 |                   
 ...oviders/chutes |   78.57 |       80 |     100 |   78.57 |                   
  usageInfo.ts     |   78.57 |       80 |     100 |   78.57 | ...68-170,185-199 
 ...providers/fake |   91.62 |    78.26 |     100 |   91.62 |                   
  FakeProvider.ts  |   91.62 |    78.26 |     100 |   91.62 | ...12-215,218-221 
 ...oviders/gemini |   53.86 |     70.4 |   45.23 |   53.86 |                   
  ...niProvider.ts |   51.99 |    60.96 |   44.73 |   51.99 | ...1877,1886-1887 
  ...Signatures.ts |     100 |    98.41 |     100 |     100 | 182               
  usageInfo.ts     |   16.66 |      100 |       0 |   16.66 | 41-149            
 ...providers/kimi |   86.34 |     84.9 |     100 |   86.34 |                   
  usageInfo.ts     |   86.34 |     84.9 |     100 |   86.34 | ...16-319,331-332 
 ...viders/logging |   42.94 |    85.71 |      75 |   42.94 |                   
  ...tExtractor.ts |       0 |        0 |       0 |       0 | 1-229             
  ...nceTracker.ts |   91.33 |       90 |   81.81 |   91.33 | ...73-175,193-194 
 ...oviders/openai |   73.54 |    78.92 |   63.31 |   73.54 |                   
  ...ationCache.ts |   65.57 |    83.33 |   82.35 |   65.57 | ...79-187,216-217 
  ...rateParams.ts |       0 |        0 |       0 |       0 |                   
  ...iExecution.ts |   23.36 |    41.66 |      25 |   23.36 | ...63-171,175-246 
  ...entFactory.ts |   87.87 |    97.91 |   71.42 |   87.87 | 76-81,85-94       
  ...eamHandler.ts |   56.71 |       28 |   33.33 |   56.71 | ...43-244,262-276 
  ...AIProvider.ts |   64.11 |    72.05 |   45.16 |   64.11 | ...07,734,742-751 
  ...estBuilder.ts |   87.89 |    92.24 |   91.66 |   87.89 | ...82-491,503-511 
  ...reparation.ts |   72.91 |    55.17 |      25 |   72.91 | ...83-186,190-191 
  ...onseParser.ts |    94.7 |    89.28 |   83.33 |    94.7 | ...82-186,254-255 
  ...mProcessor.ts |   57.71 |    59.37 |    9.52 |   57.71 | ...57,885,887-906 
  ...API_MODELS.ts |     100 |      100 |     100 |     100 |                   
  ...lCollector.ts |   93.33 |    89.28 |     100 |   93.33 | ...51-153,173-174 
  ...Normalizer.ts |   92.75 |    95.83 |     100 |   92.75 | 74-78             
  ...llPipeline.ts |   64.54 |    53.33 |      75 |   64.54 | ...34-143,174-184 
  ...eValidator.ts |   94.02 |    93.75 |     100 |   94.02 | 106-109           
  ...sesRequest.ts |   83.92 |    93.24 |     100 |   83.92 | ...59,293,298-303 
  ...xUsageInfo.ts |   91.57 |    90.24 |     100 |   91.57 | ...86,190,197-199 
  ...moteTokens.ts |   89.55 |     92.3 |     100 |   89.55 | 97-103            
  ...sonMapping.ts |   82.75 |    33.33 |   33.33 |   82.75 | 45-49             
  ...oviderInfo.ts |    86.2 |    73.52 |     100 |    86.2 | ...31-133,144-145 
  ...uestParams.ts |   87.27 |    57.69 |     100 |   87.27 | ...20-121,123-124 
  ...nsesStream.ts |   87.06 |    85.57 |     100 |   87.06 | ...65,524-531,555 
  ...aConverter.ts |    53.7 |    52.63 |   71.42 |    53.7 | ...59-260,283-291 
  ...lResponses.ts |   71.98 |    73.33 |      75 |   71.98 | ...97-301,321-335 
  test-types.ts    |       0 |        0 |       0 |       0 |                   
  toolNameUtils.ts |   96.79 |    95.45 |      50 |   96.79 | 102,127,239-241   
 ...enai-responses |   62.46 |    74.39 |   41.93 |   62.46 |                   
  CODEX_MODELS.ts  |     100 |      100 |     100 |     100 |                   
  ...esProvider.ts |   66.35 |    73.29 |      50 |   66.35 | ...1156,1177-1199 
  ...romContent.ts |      90 |     87.5 |     100 |      90 | 61-65,147,186-193 
  index.ts         |       0 |        0 |       0 |       0 | 1                 
  ...aConverter.ts |    7.97 |       20 |   14.28 |    7.97 | ...52-278,281-290 
 .../openai-vercel |   70.92 |     66.5 |   62.29 |   70.92 |                   
  ...elProvider.ts |   70.51 |     63.9 |   48.71 |   70.51 | ...1654,1664-1665 
  errors.ts        |   93.23 |    82.05 |     100 |   93.23 | ...50-151,165-169 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...Conversion.ts |   71.42 |    74.68 |      80 |   71.42 | ...06-510,528-536 
  ...aConverter.ts |    53.7 |       50 |   71.42 |    53.7 | ...58-259,282-290 
  toolIdUtils.ts   |     100 |      100 |     100 |     100 |                   
 ...ders/reasoning |   47.13 |    89.65 |    87.5 |   47.13 |                   
  ...oningUtils.ts |   47.13 |    89.65 |    87.5 |   47.13 | ...47-205,241-280 
 ...ders/synthetic |    93.7 |    91.66 |     100 |    93.7 |                   
  usageInfo.ts     |    93.7 |    91.66 |     100 |    93.7 | ...19-121,155-156 
 ...ers/test-utils |     100 |      100 |     100 |     100 |                   
  ...TestConfig.ts |     100 |      100 |     100 |     100 |                   
 ...ers/tokenizers |      70 |    77.77 |      75 |      70 |                   
  ...cTokenizer.ts |   68.42 |       75 |     100 |   68.42 | 34-39             
  ITokenizer.ts    |       0 |        0 |       0 |       0 |                   
  ...ITokenizer.ts |   70.73 |       80 |   66.66 |   70.73 | 53-56,63-72       
 ...roviders/types |       0 |        0 |       0 |       0 |                   
  ...iderConfig.ts |       0 |        0 |       0 |       0 |                   
  ...derRuntime.ts |       0 |        0 |       0 |       0 |                   
 ...roviders/utils |   91.91 |    90.75 |   90.24 |   91.91 |                   
  authToken.ts     |   33.33 |       50 |      50 |   33.33 | 14-22,30-35       
  ...sExtractor.ts |   95.45 |     91.3 |     100 |   95.45 | 15-16             
  ...nerSandbox.ts |     100 |      100 |     100 |     100 |                   
  ...entPreview.ts |   88.88 |    77.77 |     100 |   88.88 | 51-52,58-59,66    
  dumpContext.ts   |    96.1 |    95.65 |     100 |    96.1 | 110-112           
  ...SDKContext.ts |   94.59 |       75 |     100 |   94.59 | 27,49             
  localEndpoint.ts |   89.28 |    92.68 |     100 |   89.28 | ...18-119,138-139 
  mediaUtils.ts    |     100 |    93.33 |     100 |     100 | 22,34             
  qwenEndpoint.ts  |     100 |      100 |     100 |     100 |                   
  retryStrategy.ts |   96.29 |    90.47 |      50 |   96.29 | 73,84             
  textSanitizer.ts |     100 |    91.66 |      50 |     100 | 54                
  ...Extraction.ts |     100 |    94.44 |      50 |     100 | 78                
  ...tDetection.ts |    97.5 |    94.44 |     100 |    97.5 | 38                
  ...malization.ts |     100 |      100 |     100 |     100 |                   
  ...malization.ts |     100 |      100 |     100 |     100 |                   
  ...nsePayload.ts |   92.63 |    86.88 |     100 |   92.63 | ...42-147,200-204 
  userMemory.ts    |   51.51 |       60 |     100 |   51.51 | 16-18,31-43       
 src/providers/zai |   89.93 |       80 |     100 |   89.93 |                   
  usageInfo.ts     |   89.93 |       80 |     100 |   89.93 | ...58-160,171-172 
 src/recording     |   90.34 |    84.51 |   98.43 |   90.34 |                   
  ...ntegration.ts |    83.9 |    74.07 |     100 |    83.9 | ...31-132,143-144 
  ReplayEngine.ts  |   98.38 |    92.53 |     100 |   98.38 | 272-275           
  ...nDiscovery.ts |   91.98 |    84.37 |     100 |   91.98 | ...29,245-247,296 
  ...ockManager.ts |   89.94 |    82.69 |     100 |   89.94 | ...95,210,247-248 
  ...ingService.ts |   82.37 |       92 |   95.23 |   82.37 | ...40,373-374,378 
  index.ts         |     100 |      100 |     100 |     100 |                   
  resumeSession.ts |    91.8 |    86.95 |     100 |    91.8 | ...32-133,174-179 
  ...eanupUtils.ts |      90 |    69.23 |     100 |      90 | ...29-230,256,269 
  ...Management.ts |   88.23 |    85.71 |     100 |   88.23 | 94,108-112        
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/resources     |   95.23 |     92.3 |     100 |   95.23 |                   
  ...e-registry.ts |   95.23 |     92.3 |     100 |   95.23 | 34-35             
 src/runtime       |   88.27 |    85.22 |    82.5 |   88.27 |                   
  ...imeContext.ts |     100 |      100 |     100 |     100 |                   
  ...timeLoader.ts |    84.9 |    69.38 |      80 |    84.9 | ...85-188,226-229 
  ...ntimeState.ts |   95.49 |    91.89 |     100 |   95.49 | ...83-484,525-526 
  ...ionContext.ts |   85.89 |    94.11 |   85.71 |   85.89 | 80-82,149-156     
  ...imeContext.ts |   91.66 |    94.02 |    87.5 |   91.66 | ...25-230,232-239 
  index.ts         |       0 |        0 |       0 |       0 | 1-15              
  ...imeContext.ts |     100 |      100 |     100 |     100 |                   
  ...meAdapters.ts |   64.81 |       65 |   56.25 |   64.81 | ...,47-50,123-149 
  ...ateFactory.ts |   96.05 |    81.48 |     100 |   96.05 | 72,87,107         
 src/safety        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  pathValidator.ts |     100 |      100 |     100 |     100 |                   
 src/scheduler     |   90.06 |    81.99 |   96.72 |   90.06 |                   
  ...oordinator.ts |   85.92 |    78.26 |     100 |   85.92 | ...18,741-742,797 
  ...aggregator.ts |   89.72 |    86.79 |     100 |   89.72 | ...04,412,416-423 
  ...ransitions.ts |   96.58 |       75 |     100 |   96.58 | ...,74-75,273-275 
  ...dispatcher.ts |   98.21 |       96 |     100 |   98.21 | 147-148           
  tool-executor.ts |   89.56 |    82.35 |   66.66 |   89.56 | ...63-165,168-169 
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   84.34 |    85.75 |   85.63 |   84.34 |                   
  ...ardService.ts |   93.33 |    92.85 |     100 |   93.33 | 63,67-68          
  ...utoTrigger.ts |   97.14 |    95.83 |     100 |   97.14 | 119-120           
  ...askManager.ts |   95.81 |    93.93 |     100 |   95.81 | 151-157,365-366   
  ...derService.ts |   98.98 |    94.28 |     100 |   98.98 | 173               
  ...y-analyzer.ts |   76.32 |    81.17 |   77.77 |   76.32 | ...79-507,513-514 
  ...extManager.ts |     100 |      100 |     100 |     100 |                   
  ...nitization.ts |   98.62 |     90.9 |     100 |   98.62 | 172-173           
  ...eryService.ts |   98.54 |    95.45 |     100 |   98.54 | 132-133           
  ...temService.ts |     100 |      100 |     100 |     100 |                   
  ...ts-service.ts |      50 |      100 |       0 |      50 | 41-42,48-49       
  gitService.ts    |    86.6 |    86.95 |      80 |    86.6 | ...34-137,141-145 
  index.ts         |       0 |        0 |       0 |       0 | 1-23              
  ...ionService.ts |   95.72 |    92.85 |     100 |   95.72 | ...90-291,301-302 
  ...ionService.ts |   79.18 |    80.51 |   78.37 |   79.18 | ...1199,1208-1230 
  ...xt-tracker.ts |   94.87 |       90 |    87.5 |   94.87 | 54-55             
  ...er-service.ts |    60.6 |    82.35 |      50 |    60.6 | ...36-139,142-160 
  ...er-service.ts |   69.45 |    55.88 |      80 |   69.45 | ...85-289,311-314 
 ...rvices/history |   83.54 |     85.2 |   90.27 |   83.54 |                   
  ...Converters.ts |   87.39 |    82.35 |   85.71 |   87.39 | ...22-334,345-351 
  HistoryEvents.ts |       0 |        0 |       0 |       0 |                   
  ...oryService.ts |   81.28 |     85.9 |   89.47 |   81.28 | ...1553,1589-1590 
  IContent.ts      |   88.05 |    80.76 |     100 |   88.05 | ...39-240,257-260 
  ...calToolIds.ts |   96.82 |     93.1 |     100 |   96.82 | 36-37             
 src/settings      |   81.55 |       87 |   56.52 |   81.55 |                   
  ...ngsService.ts |   91.69 |    75.75 |   95.23 |   91.69 | ...58-359,389-393 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...gsRegistry.ts |    79.2 |    92.74 |   36.36 |    79.2 | ...1480,1483-1500 
  ...ceInstance.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/skills        |   74.87 |     85.1 |   73.07 |   74.87 |                   
  skillLoader.ts   |    56.7 |    83.33 |   71.42 |    56.7 | ...94-226,229-264 
  skillManager.ts  |    91.2 |     86.2 |   73.68 |    91.2 | ...52-353,359-360 
 src/storage       |   90.22 |    83.25 |   92.98 |   90.22 |                   
  ...FileWriter.ts |   83.75 |       80 |    87.5 |   83.75 | 41-42,72-82       
  ...nceService.ts |   98.67 |    96.96 |     100 |   98.67 | 293-294           
  ...ey-storage.ts |   92.64 |    90.47 |     100 |   92.64 | 35-37,83-84       
  secure-store.ts  |   88.57 |    79.75 |   89.28 |   88.57 | ...66-669,685-686 
  sessionTypes.ts  |     100 |      100 |     100 |     100 |                   
 src/telemetry     |   68.36 |    82.55 |    62.4 |   68.36 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...-exporters.ts |   28.08 |      100 |       0 |   28.08 | ...14-115,118-119 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-17              
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-132             
  loggers.ts       |   65.28 |    72.91 |   60.71 |   65.28 | ...94-607,615-631 
  metrics.ts       |   62.35 |    96.29 |   66.66 |   62.35 | ...41-163,166-189 
  sdk.ts           |   77.41 |    52.38 |     100 |   77.41 | ...62,166-167,169 
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |   76.42 |       86 |    66.1 |   76.42 | ...60-662,665-669 
  uiTelemetry.ts   |   95.45 |    96.15 |   91.66 |   95.45 | 158,197-203       
 src/test-utils    |   90.86 |    88.05 |      60 |   90.86 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  mock-tool.ts     |   97.91 |      100 |   83.33 |   97.91 | 78-79             
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
  ...allOptions.ts |   93.92 |    91.66 |   63.63 |   93.92 | ...19,187,216-219 
  runtime.ts       |   89.44 |    84.84 |   42.55 |   89.44 | ...00-302,311-312 
  tools.ts         |   84.69 |    77.77 |      80 |   84.69 | ...58,180,184-185 
 src/todo          |   51.55 |    83.33 |      75 |   51.55 |                   
  todoFormatter.ts |   51.55 |    83.33 |      75 |   51.55 | ...56-160,198-199 
 src/tools         |   77.59 |     78.9 |   81.66 |   77.59 |                   
  ...lFormatter.ts |     100 |      100 |     100 |     100 |                   
  ToolFormatter.ts |   21.21 |    76.74 |   33.33 |   21.21 | ...27,534-632,647 
  ...IdStrategy.ts |   94.77 |       92 |     100 |   94.77 | ...30-231,267-270 
  ...vate-skill.ts |   92.51 |    72.22 |      90 |   92.51 | ...99,168-170,182 
  apply-patch.ts   |   52.54 |       50 |   53.84 |   52.54 | ...77-501,510-511 
  ast-edit.ts      |   95.28 |       96 |   92.85 |   95.28 | 159-167           
  ast-grep.ts      |   88.96 |    85.52 |   88.88 |   88.96 | ...57-259,280-281 
  ...sync-tasks.ts |   96.49 |    91.52 |    92.3 |   96.49 | 50-54,100,117,237 
  codesearch.ts    |   98.13 |    89.47 |    87.5 |   98.13 | 114-115,192       
  ...line_range.ts |   85.95 |    72.09 |      70 |   85.95 | ...09-310,318-319 
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  ...-web-fetch.ts |   94.39 |    79.48 |      80 |   94.39 | ...98,218,237-238 
  ...scapeUtils.ts |   61.65 |    72.97 |      50 |   61.65 | ...93,309,311-321 
  edit.ts          |   79.11 |    82.65 |   76.47 |   79.11 | ...4-925,962-1006 
  ensure-dirs.ts   |     100 |      100 |     100 |     100 |                   
  ...web-search.ts |   98.13 |    88.23 |   85.71 |   98.13 | 136-137,216       
  ...y-replacer.ts |   85.71 |    84.35 |     100 |   85.71 | ...47-448,493-494 
  glob.ts          |      91 |    81.96 |      90 |      91 | ...69-270,379-380 
  ...-web-fetch.ts |   94.11 |    87.73 |    92.3 |   94.11 | ...88-389,399-400 
  ...invocation.ts |   55.07 |    38.88 |      75 |   55.07 | ...30-134,166-211 
  ...web-search.ts |     100 |      100 |     100 |     100 |                   
  grep.ts          |   63.56 |       80 |   73.68 |   63.56 | ...99,917,928-935 
  ...rt_at_line.ts |   82.95 |    78.43 |      70 |   82.95 | ...34-335,343-344 
  ...-subagents.ts |    87.5 |    69.56 |   88.88 |    87.5 | ...,83-91,100,156 
  ls.ts            |   97.59 |    89.23 |     100 |   97.59 | 157-162           
  ...ics-helper.ts |     100 |    71.42 |     100 |     100 | 56,65,70,77,82    
  ...nt-manager.ts |   51.75 |    68.18 |   36.84 |   51.75 | ...73-396,399-400 
  mcp-client.ts    |   52.11 |    75.27 |   70.37 |   52.11 | ...1947,1951-1954 
  mcp-tool.ts      |   92.52 |     93.1 |   84.61 |   92.52 | ...75-285,349-350 
  memoryTool.ts    |    78.6 |     84.5 |   88.88 |    78.6 | ...95-396,449-502 
  ...iable-tool.ts |   92.15 |    74.07 |     100 |   92.15 | 76-81,205-210     
  read-file.ts     |   91.69 |    80.26 |    90.9 |   91.69 | ...36-237,405-406 
  ...many-files.ts |    73.1 |     78.2 |   88.88 |    73.1 | ...33-534,541-542 
  ...line_range.ts |   78.49 |       64 |      80 |   78.49 | ...56-357,361-362 
  ripGrep.ts       |   83.29 |    86.81 |   86.66 |   83.29 | ...16,419,447-472 
  shell.ts         |   85.08 |    79.08 |    90.9 |   85.08 | ...90-891,896-897 
  ...l-analysis.ts |   81.76 |    62.28 |      92 |   81.76 | ...1185,1238,1249 
  task.ts          |   83.38 |    74.11 |    92.1 |   83.38 | ...1247,1250-1259 
  todo-events.ts   |    62.5 |      100 |       0 |    62.5 | 23-24,27-28,31-32 
  todo-pause.ts    |   87.09 |       80 |     100 |   87.09 | 64-69,73-78,93-98 
  todo-read.ts     |   89.24 |    94.73 |     100 |   89.24 | 113-124           
  todo-schemas.ts  |     100 |      100 |     100 |     100 |                   
  todo-store.ts    |   76.92 |    82.35 |   77.77 |   76.92 | ...31-133,140-145 
  todo-write.ts    |   88.23 |    80.48 |   88.88 |   88.23 | ...75,210-212,290 
  ...tion-types.ts |     100 |      100 |     100 |     100 |                   
  tool-context.ts  |     100 |      100 |     100 |     100 |                   
  tool-error.ts    |   88.23 |      100 |       0 |   88.23 | 109-116           
  ...ey-storage.ts |   86.02 |    80.51 |     100 |   86.02 | ...50-355,364-369 
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |    83.4 |       75 |   82.05 |    83.4 | ...94-702,710-711 
  toolNameUtils.ts |      80 |     92.1 |     100 |      80 | 59-60,64-65,69-82 
  tools.ts         |   80.72 |     82.5 |   74.35 |   80.72 | ...16-917,920-927 
  write-file.ts    |    80.1 |    71.09 |   73.33 |    80.1 | ...10-711,737-776 
 ...tools/ast-edit |   78.98 |    76.78 |   91.89 |   78.98 |                   
  ast-config.ts    |     100 |      100 |     100 |     100 |                   
  ...invocation.ts |   84.12 |    76.62 |     100 |   84.12 | ...16-325,422-423 
  ...-extractor.ts |   82.19 |    64.51 |   66.66 |   82.19 | ...18-220,224-229 
  ...invocation.ts |    81.5 |       76 |      80 |    81.5 | ...53,155-156,162 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...-collector.ts |    80.5 |       90 |     100 |    80.5 | 141-169           
  ...-optimizer.ts |   52.54 |       75 |      50 |   52.54 | ...0,77-78,95-100 
  ...e-analyzer.ts |   47.12 |    52.94 |     100 |   47.12 | ...18-319,327-328 
  ...calculator.ts |   91.39 |    91.07 |     100 |   91.39 | ...33-237,276-277 
  edit-helpers.ts  |   77.77 |    72.72 |     100 |   77.77 | 33-34,36-37       
  ...e-analysis.ts |   97.18 |       92 |     100 |   97.18 | 99-100            
  ...t-analyzer.ts |   84.95 |    83.01 |     100 |   84.95 | ...34-243,267-272 
  ...t-provider.ts |   91.15 |     64.7 |     100 |   91.15 | ...29-130,147-148 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  ...t-provider.ts |   64.28 |       50 |     100 |   64.28 | 42-47,52-55       
 src/types         |     100 |      100 |     100 |     100 |                   
  modelParams.ts   |     100 |      100 |     100 |     100 |                   
 src/utils         |    82.9 |    86.46 |   82.81 |    82.9 |                   
  LruCache.ts      |    82.6 |      100 |   71.42 |    82.6 | 29-30,33-34       
  ...grep-utils.ts |      98 |     87.5 |     100 |      98 | 135-136           
  asyncIterator.ts |   73.07 |    86.66 |   66.66 |   73.07 | ...71,75-86,93-94 
  bfsFileSearch.ts |   89.88 |     90.9 |     100 |   89.88 | 88-96             
  browser.ts       |    8.69 |      100 |       0 |    8.69 | 17-53             
  channel.ts       |     100 |      100 |     100 |     100 |                   
  ...pointUtils.ts |   95.58 |    95.23 |     100 |   95.58 | 149-154           
  debugLogger.ts   |     100 |      100 |     100 |     100 |                   
  delay.ts         |     100 |      100 |     100 |     100 |                   
  editor.ts        |   96.44 |    90.19 |    90.9 |   96.44 | ...25-226,228-229 
  ...entContext.ts |     100 |      100 |     100 |     100 |                   
  errorParsing.ts  |   90.22 |    76.78 |     100 |   90.22 | ...13,161,204,207 
  ...rReporting.ts |   83.72 |    84.61 |     100 |   83.72 | 83-87,108-116     
  errors.ts        |   85.61 |    93.75 |   53.33 |   85.61 | ...18-119,182-183 
  events.ts        |   64.42 |      100 |      60 |   64.42 | ...66-271,277-280 
  exitCodes.ts     |     100 |      100 |     100 |     100 |                   
  ...sionLoader.ts |   81.25 |    62.85 |    92.3 |   81.25 | ...67-168,221-229 
  fetch.ts         |   31.08 |    66.66 |      25 |   31.08 | ...37,40-85,88-89 
  fileDiffUtils.ts |     100 |      100 |     100 |     100 |                   
  fileUtils.ts     |   95.49 |    90.57 |     100 |   95.49 | ...36-240,458-464 
  formatters.ts    |   54.54 |       50 |     100 |   54.54 | 12-16             
  ...eUtilities.ts |   94.83 |    93.91 |     100 |   94.83 | ...58-262,319-320 
  ...rStructure.ts |   94.82 |    94.93 |     100 |   94.82 | ...20-123,351-356 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  ...noreParser.ts |   93.33 |    88.46 |     100 |   93.33 | ...52,221-222,233 
  ...ineChanges.ts |   58.56 |    79.41 |      80 |   58.56 | ...18-256,264-270 
  gitUtils.ts      |   90.24 |       90 |     100 |   90.24 | 40-41,71-72       
  googleErrors.ts  |   72.05 |    67.56 |     100 |   72.05 | ...59,300,307-308 
  ...uotaErrors.ts |   94.58 |    81.42 |     100 |   94.58 | ...61-264,267-268 
  ide-trust.ts     |      60 |      100 |       0 |      60 | 14-15             
  ...rePatterns.ts |     100 |    96.55 |     100 |     100 | 248               
  ...ionManager.ts |     100 |       90 |     100 |     100 | 24                
  ...edit-fixer.ts |       0 |        0 |       0 |       0 | 1-156             
  ...yDiscovery.ts |   82.96 |     77.2 |   85.71 |   82.96 | ...11-712,715-716 
  ...tProcessor.ts |   93.44 |    86.51 |    92.3 |   93.44 | ...89-390,399-400 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  output-format.ts |   36.36 |      100 |       0 |   36.36 | ...53-154,164-185 
  package.ts       |     100 |      100 |     100 |     100 |                   
  ...erCoercion.ts |   83.78 |    81.15 |     100 |   83.78 | ...79-180,242-243 
  partUtils.ts     |   96.72 |    97.05 |     100 |   96.72 | 97-98             
  pathReader.ts    |       0 |        0 |       0 |       0 | 1-60              
  paths.ts         |    87.5 |     87.5 |     100 |    87.5 | ...35-236,250-251 
  ...rDetection.ts |    64.4 |       75 |     100 |    64.4 | ...4,88-89,99-100 
  ...archTarget.ts |   89.58 |    73.33 |     100 |   89.58 | 45-47,65-66       
  retry.ts         |   76.13 |    88.65 |   84.61 |   76.13 | ...23-726,731-732 
  ...thResolver.ts |      85 |    83.87 |     100 |      85 | ...07,130,179-182 
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  sanitization.ts  |     100 |      100 |     100 |     100 |                   
  ...aValidator.ts |   83.52 |    82.75 |     100 |   83.52 | 70-81,125-126     
  ...r-launcher.ts |   88.88 |    79.48 |     100 |   88.88 | ...79-184,189-190 
  session.ts       |     100 |      100 |     100 |     100 |                   
  shell-parser.ts  |   22.46 |    57.69 |   42.85 |   22.46 | ...78-392,413-457 
  shell-utils.ts   |   86.88 |    85.71 |     100 |   86.88 | ...12-514,517-522 
  ...Completion.ts |   94.16 |     92.3 |     100 |   94.16 | 68-74             
  stdio.ts         |   84.21 |    59.09 |     100 |   84.21 | ...21-125,134-138 
  ...dleTimeout.ts |     100 |      100 |     100 |     100 |                   
  summarizer.ts    |     100 |    88.88 |     100 |     100 | 93                
  ...emEncoding.ts |   97.16 |    91.42 |     100 |   97.16 | 109-110,162       
  terminal.ts      |   34.09 |      100 |       0 |   34.09 | ...55,58-59,62-66 
  ...Serializer.ts |   98.16 |    92.18 |     100 |   98.16 | ...,98-99,151-153 
  testUtils.ts     |      50 |      100 |   33.33 |      50 | ...47,53-58,64-66 
  textUtils.ts     |    12.5 |      100 |       0 |    12.5 | 15-34             
  thoughtUtils.ts  |     100 |      100 |     100 |     100 |                   
  tool-utils.ts    |   67.76 |    78.04 |      75 |   67.76 | ...37-138,159-183 
  ...putLimiter.ts |   87.85 |    79.06 |     100 |   87.85 | ...19-224,268-275 
  unicodeUtils.ts  |     100 |      100 |     100 |     100 |                   
  ...untManager.ts |   89.65 |    88.23 |     100 |   89.65 | ...0,77-82,98-100 
  version.ts       |     100 |      100 |     100 |     100 |                   
  ...aceContext.ts |   96.85 |    95.34 |    92.3 |   96.85 | 95-96,110-111     
 ...ils/filesearch |   95.65 |    91.04 |     100 |   95.65 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   93.05 |       90 |     100 |   93.05 | 72-74,86-87       
  fileSearch.ts    |   93.25 |    86.95 |     100 |   93.25 | ...29-230,232-233 
  ignore.ts        |     100 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |    91.66 |     100 |     100 | 46                
-------------------|---------|----------|---------|---------|-------------------

For detailed HTML reports, please see the 'coverage-reports-24.x-ubuntu-latest' artifact from the main CI run.

… handling

- Fix empty/whitespace filename handling in mediaBlockToCompressionPlaceholder()
  by using .trim() and || operator instead of nullish coalescing
- Add regression test for empty-string filename fallback to mimeType

Fixes review comments on PR #1892 for issue #1875
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/core/compression/utils.test.ts`:
- Around line 748-787: Add a regression test for a speaker='tool' message whose
tool_response block is followed by media blocks to ensure
sanitizeHistoryForCompression both placeholderizes media and re-tags the overall
message speaker to 'human'; create an IContent msg with speaker: 'tool', blocks:
[{ type: 'tool_response', ... }, mediaBlock(...)] (using existing mediaBlock
helper), call sanitizeHistoryForCompression([msg]) and assert result[0].speaker
=== 'human', that the tool_response block text contains the expected '[Tool
Response: ...]' marker and that the media block(s) were converted to text
placeholders like '[Attached image: ...]' (or PDF) in the output.

In `@packages/core/src/core/compression/utils.ts`:
- Around line 349-355: mediaBlockToCompressionPlaceholder currently drops
MediaBlock.caption; update it to include caption (MediaBlock.caption) in the
placeholder so captions/alt text aren't lost during compression. Change the
identifier logic to prefer a non-empty caption.trim() first, then
filename?.trim(), then mimeType, then 'unknown', and keep the existing category
handling (capitalize 'pdf' to 'PDF'). Ensure the returned string still uses the
same format (`[Attached ${label}: ${identifier}]`) but uses the caption when
available.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f89cc138-0062-45a3-aa39-7c6b2762975b

📥 Commits

Reviewing files that changed from the base of the PR and between f135b80 and 5f29e35.

📒 Files selected for processing (2)
  • packages/core/src/core/compression/utils.test.ts
  • packages/core/src/core/compression/utils.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 270000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: E2E Test (Linux) - sandbox:none
  • GitHub Check: E2E Test (macOS)
  • GitHub Check: E2E Test (Linux) - sandbox:docker
  • GitHub Check: Lint (Javascript)
🧰 Additional context used
🧠 Learnings (34)
📓 Common learnings
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.
📚 Learning: 2026-03-27T01:40:09.382Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1790
File: packages/core/src/core/compression/MiddleOutStrategy.ts:307-325
Timestamp: 2026-03-27T01:40:09.382Z
Learning: In `packages/core/src/core/compression/MiddleOutStrategy.ts` (vybestack/llxprt-code), `IContent` messages with `speaker === 'human'` contain only `TextBlock` types by definition in the conversation model. Tool call and tool response blocks appear exclusively on `speaker === 'ai'` and `speaker === 'tool'` messages. Therefore, `extractTextFromMessage` (which filters for `TextBlock`) captures the full content of any human message, and calling `estimateTokens` on its output is a complete token estimate for human messages. Do not flag token estimation for human messages as incomplete due to missing non-text block handling.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-22T04:07:00.235Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T03:22:51.631Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-29T05:46:51.084Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1827
File: packages/core/src/core/compression/CompressionHandler.ts:714-722
Timestamp: 2026-03-29T05:46:51.084Z
Learning: In `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1827`), `lastSuccessfulCompressionTime` is intentionally set in two places when fallback compression succeeds via `runCompressionWithRetryAndFallback`: once inside `performFallbackCompression` (needed for the `forceTruncationIfIneffective`-only call path) and once in `performCompression` after `runCompressionWithRetryAndFallback` returns. The duplicate assignment is harmless (both use `Date.now()`) and is deliberately left without extra branching or flags to keep the code simple. Do not flag this dual assignment as a redundancy in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-25T12:57:45.842Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1768
File: packages/cli/src/ui/containers/AppContainer/hooks/useModelRuntimeSync.ts:35-38
Timestamp: 2026-03-25T12:57:45.842Z
Learning: In `packages/cli/src/ui/containers/AppContainer/hooks/useModelRuntimeSync.ts` (vybestack/llxprt-code PR `#1768`), the pattern `providerModel && providerModel.trim() !== '' ? providerModel : configModel` (checking trim() for emptiness but assigning the untrimmed value) is intentional pre-existing behavior moved verbatim from the original `AppContainer.tsx`. Do not flag the lack of normalization (using the trimmed value as `effectiveModel`) as a whitespace propagation bug in decomposition or future PRs — any fix would be a behavioral change beyond the refactoring scope.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T15:59:45.670Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/utils/toolIdNormalization.ts:98-121
Timestamp: 2026-03-21T15:59:45.670Z
Learning: In `packages/core/src/providers/utils/toolIdNormalization.ts` (vybestack/llxprt-code PR `#1740`), `normalizeToAnthropicToolId` handles empty/falsy input by returning the deterministic constant `'toolu_empty'` and logging via `debugLogger.error(...)`. This path is unreachable in practice because all IDs first pass through `normalizeToHistoryToolId` (which maps empty → `hist_tool_`, then caught by the `hist_tool_` prefix handler), but the error log surfaces it if a provider ever returns an empty tool call ID. Do not suggest a random/hash-based fallback — that was a prior bug (pairing hazard: tool_use and tool_result calling separately would get different IDs). Fixed in commit adc8e9d.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-21T17:57:00.539Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts:294-305
Timestamp: 2026-03-21T17:57:00.539Z
Learning: In `packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts` (vybestack/llxprt-code PR `#1740`), `blocksToText` and `concatenateTextAndCodeBlocks` are intentionally kept as separate functions. They serve different callers with different contracts: `blocksToText` uses string concatenation and calls `trimStart()` on the result, while `concatenateTextAndCodeBlocks` uses an array+join pattern and guards against null `block.text`. Consolidating them is out of scope for the decomposition PR and should be done as a dedicated follow-up if desired. Do not flag this duplication in future decomposition reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-26T03:04:09.288Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentRuntimeSetup.ts:198-208
Timestamp: 2026-03-26T03:04:09.288Z
Learning: In `packages/core/src/core/subagentRuntimeSetup.ts` (vybestack/llxprt-code PR `#1779`), `applyToolWhitelistToEphemerals` treats an explicit empty `ephemerals['tools.allowed']` array as "no restriction" (falling back to `normalizedWhitelist`) because it checks `existingAllowed.length > 0` rather than `Array.isArray(ephemerals['tools.allowed'])`. This is pre-existing behavior faithfully preserved from the original `subagent.ts` (~line 370). Do not flag the empty-allowlist pass-through as a bug in decomposition or refactoring PRs — any fix to distinguish "absent" from "explicitly empty" would be a behavioral change requiring a dedicated follow-up PR.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-26T03:06:11.693Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentRuntimeSetup.ts:198-208
Timestamp: 2026-03-26T03:06:11.693Z
Learning: In `packages/core/src/core/subagentRuntimeSetup.ts` (vybestack/llxprt-code PR `#1779`), `applyToolWhitelistToEphemerals` treats an explicit empty `ephemerals['tools.allowed']` array as "no restriction" (falling back to `normalizedWhitelist`) because it checks `existingAllowed.length > 0` rather than `Array.isArray(ephemerals['tools.allowed'])`. This is pre-existing behavior faithfully preserved from the original `subagent.ts` `createToolExecutionConfig` function (lines 322–331 on main, ~line 370 of the monolith). Do not flag the empty-allowlist pass-through as a bug in decomposition or refactoring PRs — any fix to distinguish "absent" from "explicitly empty" would be a behavioral change requiring a dedicated follow-up PR.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-01T17:19:16.202Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/openai-responses/buildResponsesInputFromContent.ts:64-77
Timestamp: 2026-03-01T17:19:16.202Z
Learning: In llxprt-code, MediaBlock instances in the pipeline (from fileUtils, ContentConverters, etc.) use canonically lowercase MIME types per RFC 2045. MIME type normalization is enforced at the content creation layer, so case-insensitive MIME type checks (e.g., `mimeType.toLowerCase().startsWith('image/')`) are not needed in provider code. Cross-cutting MIME type normalization would be a separate architectural concern.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-28T20:19:36.726Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/anthropic/AnthropicProvider.ts:1233-1293
Timestamp: 2026-02-28T20:19:36.726Z
Learning: In the llxprt-code IContent model (packages/core/src/providers/anthropic/AnthropicProvider.ts and related message processing), each tool speaker message (IContent with speaker='tool') contains exactly one tool_response block plus its associated media blocks. Multiple tool responses are always separate IContent entries. This structural constraint is enforced by the message format, so code that filters toolResponseBlocks from a single IContent and iterates over them will only process one tool_response per iteration.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T03:23:48.264Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:297-315
Timestamp: 2026-03-21T03:23:48.264Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code PR `#1743`), `convertAllFunctionResponses` intentionally packs all `functionResponse` parts into a single `IContent` with `speaker='tool'` and multiple `tool_response` blocks. This is faithfully preserved from the original `convertPartListUnionToIContent` method in `geminiChat.ts` (pre-refactor, commit 71e63cb4, lines ~2984-3001). Do not flag this as incorrect multi-block packing — it is the established upstream behavior for this input-conversion path.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-01-13T19:28:00.789Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-01-13T19:28:00.789Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/anthropic/AnthropicProvider.ts`), Anthropic's API returns `contentBlock.input` as an already-parsed JavaScript object, not a JSON string. The code was incorrectly calling `JSON.stringify(contentBlock.input)` before passing it to `processToolParameters()`, which was designed for OpenAI-style string parameters. This causes arrays and other complex types to be corrupted into strings (e.g., `paths` array becomes a string `"[\"**/*.toml\"]"` instead of actual array). The fix is to use `contentBlock.input` directly without stringifying for Anthropic provider.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-13T14:32:11.331Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-13T14:32:11.331Z
Learning: In `packages/core/src/core/geminiChat.ts`, the `convertIContentToResponse` function already converts `ThinkingBlock` to `ThoughtPart` with `thought: true` (around line 3095). However, the `text` getter on the returned response object uses `parts.find((p) => 'text' in p)?.text`, which incorrectly matches `ThoughtPart` first (since `ThoughtPart` also has a `text` property) when Anthropic thinking blocks appear before text blocks. This causes the actual response text to not be surfaced. The fix is to exclude thought parts: `parts.find((p) => 'text' in p && !(p as ThoughtPart).thought)?.text || ''`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T23:27:48.689Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:110-123
Timestamp: 2026-03-19T23:27:48.689Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (extracted from the original `generatePipelineChatCompletionImpl` in `OpenAIProvider.ts`, lines 2050-2160), text-parsed tool calls from `extractKimiToolCallsFromText()` and `deps.textToolParser.parse()` (GemmaToolCallParser) are intentionally yielded directly as `ToolCallBlock[]` without being routed through `deps.toolCallPipeline.addFragment()`. The `toolCallPipeline` is exclusively used for delta-based streaming tool calls coming from the OpenAI API. This two-path design is deliberate — do not flag missing `addFragment()` calls for text-parsed tool calls as a bug.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-31T15:03:03.633Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-31T15:03:03.633Z
Learning: In vybestack/llxprt-code, `buildContinuationMessages` in `packages/core/src/providers/openai/OpenAIRequestBuilder.ts` (line 524) always appends `{ role: 'assistant', tool_calls: toolCalls }` to the history. Passing an empty `[]` array produces an invalid assistant message with `tool_calls: []` that most OpenAI-compatible APIs reject with HTTP 400. Do NOT call `requestContinuationAfterToolCalls` with an empty tool calls array for thinking-only continuation — a separate `requestContinuationAfterThinking` method is needed.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T22:50:00.853Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIRequestBuilder.test.ts:316-395
Timestamp: 2026-03-19T22:50:00.853Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/openai/OpenAIRequestBuilder.ts`, previously `OpenAIProvider.ts` around line 1250), `validateToolMessageSequence` intentionally does NOT deduplicate tool messages by `tool_call_id`. Contiguous tool messages sharing the same `tool_call_id` are legitimate in conversation history (e.g., replay artifacts or adapter-level splitting across message boundaries). The function only removes *orphaned* tool messages (those whose `tool_call_id` does not match any declared tool call in the preceding assistant message). Eager deduplication of same-id tool messages has historically caused strict-provider HTTP 400 errors and must not be introduced.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-06T15:52:42.315Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1305
File: scripts/generate-keybindings-doc.ts:1-5
Timestamp: 2026-02-06T15:52:42.315Z
Learning: In reviews of vybestack/llxprt-code, do not suggest changing existing copyright headers from 'Google LLC' to 'Vybestack LLC' for files that originated from upstream. Preserve upstream copyrights in files that came from upstream, and only apply 'Vybestack LLC' copyright on newly created, original LLxprt files. If a file is clearly LLxprt-original, it may carry the Vybestack header; if it is upstream-originated, keep the original sponsor header.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-15T21:44:56.598Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1407
File: packages/core/src/core/geminiChatHookTriggers.ts:56-65
Timestamp: 2026-02-15T21:44:56.598Z
Learning: Enforce the canonical speaker-to-role mapping used by GeminiChat hooks: in IContent.speaker, which is strictly typed as 'human | ai | tool' (no 'system'), map 'human' to the 'user' role, 'ai' to the 'model' role, and 'tool' to the 'user' role in all hook payloads. This pattern should be applied across related hook files within packages/core/src/core/ (not just the single file) to ensure consistent role assignment.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-16T19:18:56.265Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1436
File: packages/core/src/core/nonInteractiveToolExecutor.ts:0-0
Timestamp: 2026-02-16T19:18:56.265Z
Learning: Guideline: In the core scheduler architecture, the system runs in a single mode at a time—either interactive or non-interactive, never both on the same scheduler instance. Non-interactive (CLI one-shot) runs without any interactive session; interactive mode subagents run within the parent's interactive context and inherit its mode. When reviewing code, ensure non-interactive tool executions (e.g., in nonInteractiveToolExecutor.ts) create and use a fresh completionResolver per executeToolCall, and that there is no race with interactive sessions since they cannot coexist on the same scheduler instance. This pattern applies across files in packages/core/src/core/. Only apply to relevant files, not globally.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-31T02:12:43.093Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1854
File: packages/core/src/core/subagentRuntimeSetup.test.ts:77-84
Timestamp: 2026-03-31T02:12:43.093Z
Learning: In this codebase, tool declarations should follow the single required contract `parametersJsonSchema`; do not ask to preserve or reintroduce the legacy `parameters` fallback field. Reviewers should not flag assertions/checks for missing `parameters` or suggest backward-compatibility behavior for `parameters`. Schema converters/providers are expected to error if `parametersJsonSchema` is absent instead of falling back to `parameters`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T23:27:49.587Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/__tests__/OpenAIProvider.e2e.test.ts:199-203
Timestamp: 2026-03-19T23:27:49.587Z
Learning: In `packages/core/src/providers/openai/__tests__/OpenAIProvider.e2e.test.ts` (vybestack/llxprt-code), Scenarios 3, 7a, 7b, and 7c use `buildMessagesWithReasoning` (imported directly from `OpenAIRequestBuilder`) rather than calling `provider.generateChatCompletion`. This is intentional and pre-existing behavior: the original tests accessed the same helper via a hacky `buildMessagesWithReasoning.call(provider, ...)` private-method pattern. The PR's direct import is an improvement, not a regression. Do not flag these scenarios as insufficiently integrated — they are helper-level tests by design, and adding full provider-path coverage is out of scope for refactoring PRs.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-30T17:36:37.126Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1797
File: packages/cli/src/ui/components/shared/text-buffer.test.ts:2647-2704
Timestamp: 2026-03-30T17:36:37.126Z
Learning: In vybestack/llxprt-code, tests for the React hook useTextBuffer (packages/cli/src/ui/components/shared/text-buffer.ts) should not read internal fields like visualLayout. For cache/identity invalidation checks in packages/cli/src/ui/components/shared/text-buffer.test.ts, assert against the public allVisualLines array instead, and reserve internal-structure assertions for lower-level helpers if needed.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-28T23:18:15.496Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1642
File: packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx:528-578
Timestamp: 2026-02-28T23:18:15.496Z
Learning: In `packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx`, tests use mocked child components (ToolConfirmationMessage, ToolMessage) for isolation and consistency with upstream gemini-cli patterns. Tests for permanent tool approval settings (`enablePermanentToolApproval`) use this mock-based approach and pass successfully as part of the cherry-picked upstream test suite.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T15:17:37.899Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:410-421
Timestamp: 2026-03-21T15:17:37.899Z
Learning: In `packages/core/src/core/TurnProcessor.ts` and `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1743`), both classes maintain a `lastPromptTokenCount` field. After the decomposition of `geminiChat.ts`, `TurnProcessor._executeProviderCall` must update both `this.lastPromptTokenCount` AND `this.compressionHandler.lastPromptTokenCount` (via `setLastPromptTokenCount`) whenever prompt token counts are received from the non-streaming provider response. The streaming path in `StreamProcessor` already updates `compressionHandler.lastPromptTokenCount` directly. Do not flag the dual-update pattern as redundant — `CompressionHandler.shouldCompress()` reads its own field and will use stale data if only `TurnProcessor.lastPromptTokenCount` is updated. Fixed in commit bac2e4153.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T01:00:29.058Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/approvalModeParity.test.ts:351-393
Timestamp: 2026-03-27T01:00:29.058Z
Learning: In `packages/cli/src/config/__tests__/approvalModeParity.test.ts` (vybestack/llxprt-code PR `#1785`), the test suite is intentionally scoped to verifying that the extracted approval-mode resolution logic in `approvalModeResolver.ts` produces identical results to the original inline logic. Adding new combination scenarios (e.g., admin-disabled YOLO combined with an untrusted folder) is considered scope expansion beyond parity coverage. The ordering of admin checks before trust-fallback checks is preserved from the original code. Do not flag missing cross-branch combination tests in this file as a gap in refactoring PRs.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T00:46:42.685Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/parseArgumentsParity.test.ts:7-16
Timestamp: 2026-03-27T00:46:42.685Z
Learning: In `packages/cli/src/config/__tests__/parseArgumentsParity.test.ts` (vybestack/llxprt-code PR `#1785`), the test suite intentionally does NOT cover subcommand exit behavior (`mcp`, `hooks`, `extensions` via `handleSubcommandExit()`). The suite's scope is limited to verifying that the extracted `parseArguments` function produces identical results to the original inline parsing. `handleSubcommandExit()` is a direct mechanical extraction and adding integration tests for it would be new coverage beyond the refactor's scope. Do not flag missing subcommand-exit test cases in this file as a gap in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-24T21:07:40.805Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1767
File: packages/cli/src/ui/components/shared/golden-snapshot.test.ts:64-65
Timestamp: 2026-03-24T21:07:40.805Z
Learning: In `packages/cli/src/ui/components/shared/golden-snapshot.test.ts` (vybestack/llxprt-code PR `#1767`), `parseAction` uses `actionStr.split(':')` to parse action corpus entries. The action corpus (`project-plans/issue1577/action-corpus.json`) has been confirmed to contain zero multi-colon action strings, so the current two-element destructuring is correct for all existing entries. Do not flag this as a truncation bug in future reviews — the corpus format is validated and the parsing matches it.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T01:00:28.649Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/toolGovernanceParity.test.ts:458-472
Timestamp: 2026-03-27T01:00:28.649Z
Learning: In `packages/cli/src/config/__tests__/toolGovernanceParity.test.ts` (vybestack/llxprt-code PR `#1785`), the "non-interactive DEFAULT with explicit --allowed-tools" and corresponding YOLO test cases intentionally use `read_file` (a tool already in `READ_ONLY_TOOL_NAMES`) as the explicit `--allowed-tools` value. The tests are scoped to verifying that existing allowlist behavior is preserved through the refactor, not to proving union/exclusion semantics with non-read-only tools. Do not flag the choice of `read_file` as insufficient for proving merging behavior in parity or refactoring PRs — improving assertion specificity is new test design work beyond the refactoring scope.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T00:46:43.700Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/folderTrustOriginalSettingsParity.test.ts:347-383
Timestamp: 2026-03-27T00:46:43.700Z
Learning: In `packages/cli/src/config/__tests__/folderTrustOriginalSettingsParity.test.ts` (vybestack/llxprt-code PR `#1785`), the last test ("profile ephemeral folderTrust value does NOT change the trust check") intentionally omits a real profile load. Its sole purpose is to assert that `isWorkspaceTrusted` is called with the original settings object (not a profile-merged copy) in the untrusted-folder branch. The profile-merge path is covered by other parity test files. Do not suggest adding an inline profile or `LLXPRT_PROFILE` env var to this test — that would be scope expansion beyond its intended parity coverage.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-04-03T05:57:42.326Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1874
File: packages/core/src/auth/invalidateProviderCache.test.ts:107-163
Timestamp: 2026-04-03T05:57:42.326Z
Learning: In `packages/core/src/auth/invalidateProviderCache.test.ts` (vybestack/llxprt-code PR `#1874`), the profile-specific positive-match path for `invalidateProviderCache('anthropic', profileId)` is intentionally not directly tested because `resolveAuthentication` does not expose a `profileId` metadata parameter in its public API, making it impossible to construct a profile-keyed cache entry from outside. The wildcard invalidation test (`invalidateProviderCache('anthropic')` with no profileId) exercises the same matching predicate. Do not flag the missing profile-specific positive-match case as a test gap — adding it is a low-priority follow-up that requires internal API changes.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-26T02:47:18.478Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentExecution.test.ts:142-143
Timestamp: 2026-03-26T02:47:18.478Z
Learning: In `packages/core/src/core/subagentExecution.ts` (vybestack/llxprt-code PR `#1779`), `checkGoalCompletion` returns `Promise<Content[] | null>`, not `Promise<Part[] | null>`. `Content` has the shape `{ role: string, parts: Part[] }`, so test assertions like `result![0].parts[0]` are correct and access the first Part within the first Content object. Do not flag `result![0].parts[0]` indexing in tests for this function as an invalid shape access.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T22:51:20.841Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:300-305
Timestamp: 2026-03-19T22:51:20.841Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (vybestack/llxprt-code), `reasoning_content` deltas from `parseStreamingReasoningDelta` are intentionally accumulated into `state.accumulatedReasoningContent` during chunk processing and emitted as a `ThinkingBlock` only at the end of the stream, co-packaged in the same `IContent` block as tool calls. This is required for DeepSeek-reasoner compatibility: the model requires `reasoning_content` and tool calls to appear together in a single `IContent` block. Do not flag this deferred/batched emission pattern as a bug — inline streaming of reasoning was a legacy-path behavior that has been removed.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts

Comment thread packages/core/src/core/compression/utils.test.ts
Comment thread packages/core/src/core/compression/utils.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/core/compression/utils.ts`:
- Around line 341-355: The JSDoc for mediaBlockToCompressionPlaceholder is out
of sync with the actual identifier precedence (the code prefers caption then
filename then mimeType), so update the function comment to reflect the real
order; edit the JSDoc above mediaBlockToCompressionPlaceholder to state the
format uses the category with the identifier chosen in precedence: caption →
filename → mimeType → "unknown" (and optionally note caption is preferred for
accessibility/context), and ensure any mention of filename or mimeType alone is
removed or rewritten to match the identifier variable logic and
classifyMediaBlock usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 812c0a15-5cf0-4473-ac2a-39ccdc52f4a7

📥 Commits

Reviewing files that changed from the base of the PR and between 5f29e35 and 2b08b42.

📒 Files selected for processing (2)
  • packages/core/src/core/compression/utils.test.ts
  • packages/core/src/core/compression/utils.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 270000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: E2E Test (Linux) - sandbox:docker
  • GitHub Check: E2E Test (Linux) - sandbox:none
  • GitHub Check: E2E Test (macOS)
  • GitHub Check: Lint (Javascript)
🧰 Additional context used
🧠 Learnings (37)
📓 Common learnings
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1790
File: packages/core/src/core/compression/MiddleOutStrategy.ts:307-325
Timestamp: 2026-03-27T01:40:09.382Z
Learning: In `packages/core/src/core/compression/MiddleOutStrategy.ts` (vybestack/llxprt-code), `IContent` messages with `speaker === 'human'` contain only `TextBlock` types by definition in the conversation model. Tool call and tool response blocks appear exclusively on `speaker === 'ai'` and `speaker === 'tool'` messages. Therefore, `extractTextFromMessage` (which filters for `TextBlock`) captures the full content of any human message, and calling `estimateTokens` on its output is a complete token estimate for human messages. Do not flag token estimation for human messages as incomplete due to missing non-text block handling.
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:410-421
Timestamp: 2026-03-21T15:17:37.899Z
Learning: In `packages/core/src/core/TurnProcessor.ts` and `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1743`), both classes maintain a `lastPromptTokenCount` field. After the decomposition of `geminiChat.ts`, `TurnProcessor._executeProviderCall` must update both `this.lastPromptTokenCount` AND `this.compressionHandler.lastPromptTokenCount` (via `setLastPromptTokenCount`) whenever prompt token counts are received from the non-streaming provider response. The streaming path in `StreamProcessor` already updates `compressionHandler.lastPromptTokenCount` directly. Do not flag the dual-update pattern as redundant — `CompressionHandler.shouldCompress()` reads its own field and will use stale data if only `TurnProcessor.lastPromptTokenCount` is updated. Fixed in commit bac2e4153.
📚 Learning: 2026-03-27T01:40:09.382Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1790
File: packages/core/src/core/compression/MiddleOutStrategy.ts:307-325
Timestamp: 2026-03-27T01:40:09.382Z
Learning: In `packages/core/src/core/compression/MiddleOutStrategy.ts` (vybestack/llxprt-code), `IContent` messages with `speaker === 'human'` contain only `TextBlock` types by definition in the conversation model. Tool call and tool response blocks appear exclusively on `speaker === 'ai'` and `speaker === 'tool'` messages. Therefore, `extractTextFromMessage` (which filters for `TextBlock`) captures the full content of any human message, and calling `estimateTokens` on its output is a complete token estimate for human messages. Do not flag token estimation for human messages as incomplete due to missing non-text block handling.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-22T04:07:00.235Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:391-402
Timestamp: 2026-03-22T04:07:00.235Z
Learning: In `packages/core/src/core/StreamProcessor.ts` (vybestack/llxprt-code PR `#1743`), the streaming path in `_convertIContentStream` (or equivalent) must compute `lastPromptTokenCount` as `promptTokens + cache_read_input_tokens + cache_creation_input_tokens`, not raw `promptTokens` alone. Using only raw `promptTokens` causes `CompressionHandler.shouldCompress()` to underestimate context usage when a cached context is active, potentially suppressing needed compression. Fixed in commit c3e68b476. This cache-token inclusion is consistent with the non-streaming path in `TurnProcessor._executeProviderCall`. Do not flag the combined computation as redundant — both token types must be included to accurately reflect the full prompt token footprint.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T03:22:51.631Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:327-363
Timestamp: 2026-03-21T03:22:51.631Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code), `classifyMixedParts()`, `convertPartListUnionToIContent()`, and `convertIContentToResponse()` intentionally do not handle Gemini media parts (`inlineData`/`fileData`). This matches the original `geminiChat.ts` behavior. Adding media support would be a feature addition, not a decomposition fix — do not flag the absence of `inlineData`/`fileData` handling in these functions as a bug in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T15:17:37.899Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/TurnProcessor.ts:410-421
Timestamp: 2026-03-21T15:17:37.899Z
Learning: In `packages/core/src/core/TurnProcessor.ts` and `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1743`), both classes maintain a `lastPromptTokenCount` field. After the decomposition of `geminiChat.ts`, `TurnProcessor._executeProviderCall` must update both `this.lastPromptTokenCount` AND `this.compressionHandler.lastPromptTokenCount` (via `setLastPromptTokenCount`) whenever prompt token counts are received from the non-streaming provider response. The streaming path in `StreamProcessor` already updates `compressionHandler.lastPromptTokenCount` directly. Do not flag the dual-update pattern as redundant — `CompressionHandler.shouldCompress()` reads its own field and will use stale data if only `TurnProcessor.lastPromptTokenCount` is updated. Fixed in commit bac2e4153.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T03:23:48.264Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1743
File: packages/core/src/core/MessageConverter.ts:297-315
Timestamp: 2026-03-21T03:23:48.264Z
Learning: In `packages/core/src/core/MessageConverter.ts` (vybestack/llxprt-code PR `#1743`), `convertAllFunctionResponses` intentionally packs all `functionResponse` parts into a single `IContent` with `speaker='tool'` and multiple `tool_response` blocks. This is faithfully preserved from the original `convertPartListUnionToIContent` method in `geminiChat.ts` (pre-refactor, commit 71e63cb4, lines ~2984-3001). Do not flag this as incorrect multi-block packing — it is the established upstream behavior for this input-conversion path.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-29T05:46:51.084Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1827
File: packages/core/src/core/compression/CompressionHandler.ts:714-722
Timestamp: 2026-03-29T05:46:51.084Z
Learning: In `packages/core/src/core/compression/CompressionHandler.ts` (vybestack/llxprt-code PR `#1827`), `lastSuccessfulCompressionTime` is intentionally set in two places when fallback compression succeeds via `runCompressionWithRetryAndFallback`: once inside `performFallbackCompression` (needed for the `forceTruncationIfIneffective`-only call path) and once in `performCompression` after `runCompressionWithRetryAndFallback` returns. The duplicate assignment is harmless (both use `Date.now()`) and is deliberately left without extra branching or flags to keep the code simple. Do not flag this dual assignment as a redundancy in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T17:57:00.539Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts:294-305
Timestamp: 2026-03-21T17:57:00.539Z
Learning: In `packages/core/src/providers/anthropic/AnthropicMessageNormalizer.ts` (vybestack/llxprt-code PR `#1740`), `blocksToText` and `concatenateTextAndCodeBlocks` are intentionally kept as separate functions. They serve different callers with different contracts: `blocksToText` uses string concatenation and calls `trimStart()` on the result, while `concatenateTextAndCodeBlocks` uses an array+join pattern and guards against null `block.text`. Consolidating them is out of scope for the decomposition PR and should be done as a dedicated follow-up if desired. Do not flag this duplication in future decomposition reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-21T15:59:45.670Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1740
File: packages/core/src/providers/utils/toolIdNormalization.ts:98-121
Timestamp: 2026-03-21T15:59:45.670Z
Learning: In `packages/core/src/providers/utils/toolIdNormalization.ts` (vybestack/llxprt-code PR `#1740`), `normalizeToAnthropicToolId` handles empty/falsy input by returning the deterministic constant `'toolu_empty'` and logging via `debugLogger.error(...)`. This path is unreachable in practice because all IDs first pass through `normalizeToHistoryToolId` (which maps empty → `hist_tool_`, then caught by the `hist_tool_` prefix handler), but the error log surfaces it if a provider ever returns an empty tool call ID. Do not suggest a random/hash-based fallback — that was a prior bug (pairing hazard: tool_use and tool_result calling separately would get different IDs). Fixed in commit adc8e9d.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-26T03:04:09.288Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentRuntimeSetup.ts:198-208
Timestamp: 2026-03-26T03:04:09.288Z
Learning: In `packages/core/src/core/subagentRuntimeSetup.ts` (vybestack/llxprt-code PR `#1779`), `applyToolWhitelistToEphemerals` treats an explicit empty `ephemerals['tools.allowed']` array as "no restriction" (falling back to `normalizedWhitelist`) because it checks `existingAllowed.length > 0` rather than `Array.isArray(ephemerals['tools.allowed'])`. This is pre-existing behavior faithfully preserved from the original `subagent.ts` (~line 370). Do not flag the empty-allowlist pass-through as a bug in decomposition or refactoring PRs — any fix to distinguish "absent" from "explicitly empty" would be a behavioral change requiring a dedicated follow-up PR.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-25T12:57:45.842Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1768
File: packages/cli/src/ui/containers/AppContainer/hooks/useModelRuntimeSync.ts:35-38
Timestamp: 2026-03-25T12:57:45.842Z
Learning: In `packages/cli/src/ui/containers/AppContainer/hooks/useModelRuntimeSync.ts` (vybestack/llxprt-code PR `#1768`), the pattern `providerModel && providerModel.trim() !== '' ? providerModel : configModel` (checking trim() for emptiness but assigning the untrimmed value) is intentional pre-existing behavior moved verbatim from the original `AppContainer.tsx`. Do not flag the lack of normalization (using the trimmed value as `effectiveModel`) as a whitespace propagation bug in decomposition or future PRs — any fix would be a behavioral change beyond the refactoring scope.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-26T03:06:11.693Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentRuntimeSetup.ts:198-208
Timestamp: 2026-03-26T03:06:11.693Z
Learning: In `packages/core/src/core/subagentRuntimeSetup.ts` (vybestack/llxprt-code PR `#1779`), `applyToolWhitelistToEphemerals` treats an explicit empty `ephemerals['tools.allowed']` array as "no restriction" (falling back to `normalizedWhitelist`) because it checks `existingAllowed.length > 0` rather than `Array.isArray(ephemerals['tools.allowed'])`. This is pre-existing behavior faithfully preserved from the original `subagent.ts` `createToolExecutionConfig` function (lines 322–331 on main, ~line 370 of the monolith). Do not flag the empty-allowlist pass-through as a bug in decomposition or refactoring PRs — any fix to distinguish "absent" from "explicitly empty" would be a behavioral change requiring a dedicated follow-up PR.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-01T17:19:16.202Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/openai-responses/buildResponsesInputFromContent.ts:64-77
Timestamp: 2026-03-01T17:19:16.202Z
Learning: In llxprt-code, MediaBlock instances in the pipeline (from fileUtils, ContentConverters, etc.) use canonically lowercase MIME types per RFC 2045. MIME type normalization is enforced at the content creation layer, so case-insensitive MIME type checks (e.g., `mimeType.toLowerCase().startsWith('image/')`) are not needed in provider code. Cross-cutting MIME type normalization would be a separate architectural concern.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T23:27:48.657Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:358-359
Timestamp: 2026-03-19T23:27:48.657Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (vybestack/llxprt-code), `state.accumulatedText` is incremented with raw delta content before Kimi/tool-call markup or `<think>` content is stripped, and the `requestContinuation()` guards check `accumulatedText.length === 0` and `accumulatedReasoningContent.length === 0`. This is intentional pre-existing behavior faithfully preserved from the original `generatePipelineChatCompletionImpl` (lines 1824, 2019, 2542-2544, 2597-2600 in the legacy file). Do not flag this as a bug or suggest replacing these guards with a `hasVisibleText` flag tracking only yielded TextBlocks — any such change would be a behavioral modification, not a refactoring, and is out of scope for extraction PRs.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-27T19:31:13.642Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1797
File: packages/cli/src/ui/utils/highlight.ts:43-45
Timestamp: 2026-03-27T19:31:13.642Z
Learning: In `packages/cli/src/ui/utils/highlight.ts` (vybestack/llxprt-code PR `#1797`), the `highlightCache` cache key intentionally omits the `transformations` payload (only encoding `index`, `isCursorInsideTransform`, `cursorCol`, and `text`). Including the full transformations serialization was deferred due to hot-path performance tradeoffs; it should only be revisited with benchmark-backed evidence when real incorrect-highlighting reports are observed. Do not re-flag the missing transformations in the cache key in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-02-28T20:19:36.726Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1640
File: packages/core/src/providers/anthropic/AnthropicProvider.ts:1233-1293
Timestamp: 2026-02-28T20:19:36.726Z
Learning: In the llxprt-code IContent model (packages/core/src/providers/anthropic/AnthropicProvider.ts and related message processing), each tool speaker message (IContent with speaker='tool') contains exactly one tool_response block plus its associated media blocks. Multiple tool responses are always separate IContent entries. This structural constraint is enforced by the message format, so code that filters toolResponseBlocks from a single IContent and iterates over them will only process one tool_response per iteration.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-01-13T19:28:00.789Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-01-13T19:28:00.789Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/anthropic/AnthropicProvider.ts`), Anthropic's API returns `contentBlock.input` as an already-parsed JavaScript object, not a JSON string. The code was incorrectly calling `JSON.stringify(contentBlock.input)` before passing it to `processToolParameters()`, which was designed for OpenAI-style string parameters. This causes arrays and other complex types to be corrupted into strings (e.g., `paths` array becomes a string `"[\"**/*.toml\"]"` instead of actual array). The fix is to use `contentBlock.input` directly without stringifying for Anthropic provider.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-13T14:32:11.331Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-13T14:32:11.331Z
Learning: In `packages/core/src/core/geminiChat.ts`, the `convertIContentToResponse` function already converts `ThinkingBlock` to `ThoughtPart` with `thought: true` (around line 3095). However, the `text` getter on the returned response object uses `parts.find((p) => 'text' in p)?.text`, which incorrectly matches `ThoughtPart` first (since `ThoughtPart` also has a `text` property) when Anthropic thinking blocks appear before text blocks. This causes the actual response text to not be surfaced. The fix is to exclude thought parts: `parts.find((p) => 'text' in p && !(p as ThoughtPart).thought)?.text || ''`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T23:27:48.689Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIStreamProcessor.ts:110-123
Timestamp: 2026-03-19T23:27:48.689Z
Learning: In `packages/core/src/providers/openai/OpenAIStreamProcessor.ts` (extracted from the original `generatePipelineChatCompletionImpl` in `OpenAIProvider.ts`, lines 2050-2160), text-parsed tool calls from `extractKimiToolCallsFromText()` and `deps.textToolParser.parse()` (GemmaToolCallParser) are intentionally yielded directly as `ToolCallBlock[]` without being routed through `deps.toolCallPipeline.addFragment()`. The `toolCallPipeline` is exclusively used for delta-based streaming tool calls coming from the OpenAI API. This two-path design is deliberate — do not flag missing `addFragment()` calls for text-parsed tool calls as a bug.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-31T15:03:03.633Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-31T15:03:03.633Z
Learning: In vybestack/llxprt-code, `buildContinuationMessages` in `packages/core/src/providers/openai/OpenAIRequestBuilder.ts` (line 524) always appends `{ role: 'assistant', tool_calls: toolCalls }` to the history. Passing an empty `[]` array produces an invalid assistant message with `tool_calls: []` that most OpenAI-compatible APIs reject with HTTP 400. Do NOT call `requestContinuationAfterToolCalls` with an empty tool calls array for thinking-only continuation — a separate `requestContinuationAfterThinking` method is needed.

Applied to files:

  • packages/core/src/core/compression/utils.ts
📚 Learning: 2026-03-19T22:50:00.853Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/OpenAIRequestBuilder.test.ts:316-395
Timestamp: 2026-03-19T22:50:00.853Z
Learning: In the llxprt-code codebase (`packages/core/src/providers/openai/OpenAIRequestBuilder.ts`, previously `OpenAIProvider.ts` around line 1250), `validateToolMessageSequence` intentionally does NOT deduplicate tool messages by `tool_call_id`. Contiguous tool messages sharing the same `tool_call_id` are legitimate in conversation history (e.g., replay artifacts or adapter-level splitting across message boundaries). The function only removes *orphaned* tool messages (those whose `tool_call_id` does not match any declared tool call in the preceding assistant message). Eager deduplication of same-id tool messages has historically caused strict-provider HTTP 400 errors and must not be introduced.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-06T15:52:42.315Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1305
File: scripts/generate-keybindings-doc.ts:1-5
Timestamp: 2026-02-06T15:52:42.315Z
Learning: In reviews of vybestack/llxprt-code, do not suggest changing existing copyright headers from 'Google LLC' to 'Vybestack LLC' for files that originated from upstream. Preserve upstream copyrights in files that came from upstream, and only apply 'Vybestack LLC' copyright on newly created, original LLxprt files. If a file is clearly LLxprt-original, it may carry the Vybestack header; if it is upstream-originated, keep the original sponsor header.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-15T21:44:56.598Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1407
File: packages/core/src/core/geminiChatHookTriggers.ts:56-65
Timestamp: 2026-02-15T21:44:56.598Z
Learning: Enforce the canonical speaker-to-role mapping used by GeminiChat hooks: in IContent.speaker, which is strictly typed as 'human | ai | tool' (no 'system'), map 'human' to the 'user' role, 'ai' to the 'model' role, and 'tool' to the 'user' role in all hook payloads. This pattern should be applied across related hook files within packages/core/src/core/ (not just the single file) to ensure consistent role assignment.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-16T19:18:56.265Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1436
File: packages/core/src/core/nonInteractiveToolExecutor.ts:0-0
Timestamp: 2026-02-16T19:18:56.265Z
Learning: Guideline: In the core scheduler architecture, the system runs in a single mode at a time—either interactive or non-interactive, never both on the same scheduler instance. Non-interactive (CLI one-shot) runs without any interactive session; interactive mode subagents run within the parent's interactive context and inherit its mode. When reviewing code, ensure non-interactive tool executions (e.g., in nonInteractiveToolExecutor.ts) create and use a fresh completionResolver per executeToolCall, and that there is no race with interactive sessions since they cannot coexist on the same scheduler instance. This pattern applies across files in packages/core/src/core/. Only apply to relevant files, not globally.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-31T02:12:43.093Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1854
File: packages/core/src/core/subagentRuntimeSetup.test.ts:77-84
Timestamp: 2026-03-31T02:12:43.093Z
Learning: In this codebase, tool declarations should follow the single required contract `parametersJsonSchema`; do not ask to preserve or reintroduce the legacy `parameters` fallback field. Reviewers should not flag assertions/checks for missing `parameters` or suggest backward-compatibility behavior for `parameters`. Schema converters/providers are expected to error if `parametersJsonSchema` is absent instead of falling back to `parameters`.

Applied to files:

  • packages/core/src/core/compression/utils.ts
  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-30T17:36:37.126Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1797
File: packages/cli/src/ui/components/shared/text-buffer.test.ts:2647-2704
Timestamp: 2026-03-30T17:36:37.126Z
Learning: In vybestack/llxprt-code, tests for the React hook useTextBuffer (packages/cli/src/ui/components/shared/text-buffer.ts) should not read internal fields like visualLayout. For cache/identity invalidation checks in packages/cli/src/ui/components/shared/text-buffer.test.ts, assert against the public allVisualLines array instead, and reserve internal-structure assertions for lower-level helpers if needed.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-19T23:27:49.587Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1736
File: packages/core/src/providers/openai/__tests__/OpenAIProvider.e2e.test.ts:199-203
Timestamp: 2026-03-19T23:27:49.587Z
Learning: In `packages/core/src/providers/openai/__tests__/OpenAIProvider.e2e.test.ts` (vybestack/llxprt-code), Scenarios 3, 7a, 7b, and 7c use `buildMessagesWithReasoning` (imported directly from `OpenAIRequestBuilder`) rather than calling `provider.generateChatCompletion`. This is intentional and pre-existing behavior: the original tests accessed the same helper via a hacky `buildMessagesWithReasoning.call(provider, ...)` private-method pattern. The PR's direct import is an improvement, not a regression. Do not flag these scenarios as insufficiently integrated — they are helper-level tests by design, and adding full provider-path coverage is out of scope for refactoring PRs.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-02-28T23:18:15.496Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1642
File: packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx:528-578
Timestamp: 2026-02-28T23:18:15.496Z
Learning: In `packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx`, tests use mocked child components (ToolConfirmationMessage, ToolMessage) for isolation and consistency with upstream gemini-cli patterns. Tests for permanent tool approval settings (`enablePermanentToolApproval`) use this mock-based approach and pass successfully as part of the cherry-picked upstream test suite.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T00:46:42.685Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/parseArgumentsParity.test.ts:7-16
Timestamp: 2026-03-27T00:46:42.685Z
Learning: In `packages/cli/src/config/__tests__/parseArgumentsParity.test.ts` (vybestack/llxprt-code PR `#1785`), the test suite intentionally does NOT cover subcommand exit behavior (`mcp`, `hooks`, `extensions` via `handleSubcommandExit()`). The suite's scope is limited to verifying that the extracted `parseArguments` function produces identical results to the original inline parsing. `handleSubcommandExit()` is a direct mechanical extraction and adding integration tests for it would be new coverage beyond the refactor's scope. Do not flag missing subcommand-exit test cases in this file as a gap in future reviews.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T01:00:29.058Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/approvalModeParity.test.ts:351-393
Timestamp: 2026-03-27T01:00:29.058Z
Learning: In `packages/cli/src/config/__tests__/approvalModeParity.test.ts` (vybestack/llxprt-code PR `#1785`), the test suite is intentionally scoped to verifying that the extracted approval-mode resolution logic in `approvalModeResolver.ts` produces identical results to the original inline logic. Adding new combination scenarios (e.g., admin-disabled YOLO combined with an untrusted folder) is considered scope expansion beyond parity coverage. The ordering of admin checks before trust-fallback checks is preserved from the original code. Do not flag missing cross-branch combination tests in this file as a gap in refactoring PRs.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-24T21:07:40.805Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1767
File: packages/cli/src/ui/components/shared/golden-snapshot.test.ts:64-65
Timestamp: 2026-03-24T21:07:40.805Z
Learning: In `packages/cli/src/ui/components/shared/golden-snapshot.test.ts` (vybestack/llxprt-code PR `#1767`), `parseAction` uses `actionStr.split(':')` to parse action corpus entries. The action corpus (`project-plans/issue1577/action-corpus.json`) has been confirmed to contain zero multi-colon action strings, so the current two-element destructuring is correct for all existing entries. Do not flag this as a truncation bug in future reviews — the corpus format is validated and the parsing matches it.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T01:00:28.649Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/toolGovernanceParity.test.ts:458-472
Timestamp: 2026-03-27T01:00:28.649Z
Learning: In `packages/cli/src/config/__tests__/toolGovernanceParity.test.ts` (vybestack/llxprt-code PR `#1785`), the "non-interactive DEFAULT with explicit --allowed-tools" and corresponding YOLO test cases intentionally use `read_file` (a tool already in `READ_ONLY_TOOL_NAMES`) as the explicit `--allowed-tools` value. The tests are scoped to verifying that existing allowlist behavior is preserved through the refactor, not to proving union/exclusion semantics with non-read-only tools. Do not flag the choice of `read_file` as insufficient for proving merging behavior in parity or refactoring PRs — improving assertion specificity is new test design work beyond the refactoring scope.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-27T00:46:43.700Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1785
File: packages/cli/src/config/__tests__/folderTrustOriginalSettingsParity.test.ts:347-383
Timestamp: 2026-03-27T00:46:43.700Z
Learning: In `packages/cli/src/config/__tests__/folderTrustOriginalSettingsParity.test.ts` (vybestack/llxprt-code PR `#1785`), the last test ("profile ephemeral folderTrust value does NOT change the trust check") intentionally omits a real profile load. Its sole purpose is to assert that `isWorkspaceTrusted` is called with the original settings object (not a profile-merged copy) in the untrusted-folder branch. The profile-merge path is covered by other parity test files. Do not suggest adding an inline profile or `LLXPRT_PROFILE` env var to this test — that would be scope expansion beyond its intended parity coverage.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-04-03T05:57:42.326Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1874
File: packages/core/src/auth/invalidateProviderCache.test.ts:107-163
Timestamp: 2026-04-03T05:57:42.326Z
Learning: In `packages/core/src/auth/invalidateProviderCache.test.ts` (vybestack/llxprt-code PR `#1874`), the profile-specific positive-match path for `invalidateProviderCache('anthropic', profileId)` is intentionally not directly tested because `resolveAuthentication` does not expose a `profileId` metadata parameter in its public API, making it impossible to construct a profile-keyed cache entry from outside. The wildcard invalidation test (`invalidateProviderCache('anthropic')` with no profileId) exercises the same matching predicate. Do not flag the missing profile-specific positive-match case as a test gap — adding it is a low-priority follow-up that requires internal API changes.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-26T02:05:48.262Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagent.ts:552-597
Timestamp: 2026-03-26T02:05:48.262Z
Learning: In `packages/core/src/core/subagent.ts` (vybestack/llxprt-code), `processNonInteractiveText` intentionally calls `this.ctx.onMessage(filtered.displayText)` with the raw `textResponse` *before* `parseTextToolCalls` strips tool-call syntax into `cleanedText`. This ordering is pre-existing behavior faithfully preserved from the original `runNonInteractive` implementation. Do not flag the early `onMessage` emission (before tool-call stripping) as a bug in decomposition or refactoring PRs — any change to emit only `cleanedText` would be a behavioral improvement, not a structural fix, and should be tracked as a dedicated follow-up issue.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-31T15:03:03.633Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 0
File: :0-0
Timestamp: 2026-03-31T15:03:03.633Z
Learning: In vybestack/llxprt-code, `OpenAIStreamProcessor.ts` (processStreamingResponse) has a `hasToolsButNoText` guard that calls `requestContinuation()` only when `toolCallCount > 0 AND accumulatedText/textBuffer/accumulatedReasoningContent/accumulatedThinkingContent are all empty`. For Kimi K2 on the native Fireworks/OpenAI path, the model emits `<think>…</think>` content (landing in `accumulatedThinkingContent`) then stops without text. Because `accumulatedThinkingContent.length > 0`, `hasToolsButNoText` is false and no continuation fires. A separate `hasThinkingButNoText` guard is needed to call `requestContinuation([],…)` when thinking is present but text is absent and toolCallCount === 0.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
📚 Learning: 2026-03-26T02:47:18.478Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 1779
File: packages/core/src/core/subagentExecution.test.ts:142-143
Timestamp: 2026-03-26T02:47:18.478Z
Learning: In `packages/core/src/core/subagentExecution.ts` (vybestack/llxprt-code PR `#1779`), `checkGoalCompletion` returns `Promise<Content[] | null>`, not `Promise<Part[] | null>`. `Content` has the shape `{ role: string, parts: Part[] }`, so test assertions like `result![0].parts[0]` are correct and access the first Part within the first Content object. Do not flag `result![0].parts[0]` indexing in tests for this function as an invalid shape access.

Applied to files:

  • packages/core/src/core/compression/utils.test.ts
🔇 Additional comments (2)
packages/core/src/core/compression/utils.ts (1)

382-423: Media placeholderization in sanitization path looks correct.

Good change: media blocks are now converted to text placeholders in-order alongside tool block sanitization, which directly addresses provider-side validation failures from non-text media payloads.

packages/core/src/core/compression/utils.test.ts (1)

656-835: Excellent regression coverage for Issue #1875.

These tests exercise the key behavioral matrix (filename/mime fallback, empty filename, media categories, mixed content ordering, speaker behavior, caption preference, and tool+media interplay). This materially reduces risk of reintroducing the 400-error path.

Comment thread packages/core/src/core/compression/utils.ts
@acoliver acoliver merged commit 0a9d5ed into main Apr 10, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer:e2e:ok Trusted contributor; maintainer-approved E2E run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant