Skip to content

Conversation

@marius-kilocode
Copy link
Collaborator

@marius-kilocode marius-kilocode commented Jan 5, 2026

Fixes a #4718 side-effect where api_req_started (non-partial placeholders) could be frozen into Ink <Static> without costs, and later cost updates would either never appear or show up out-of-order/duplicated.

Changes:

  • Keep api_req_started without completion indicators in the dynamic tail so it can update in-place once cost/cancel/failure arrives.
  • Render a small dynamic tail below the static history to preserve native scrollback without re-render flicker.
  • Fix CLI incremental message reconciliation to apply same-length content changes (e.g. JSON cost updates).

Includes tests and a changeset.

During requests API requests will now show like this in the CLI:
image

Once the cost info is available we update the static UI component in place to look like this:

image

@changeset-bot
Copy link

changeset-bot bot commented Jan 5, 2026

🦋 Changeset detected

Latest commit: 17a763b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@kilocode/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@kiloconnect
Copy link
Contributor

kiloconnect bot commented Jan 5, 2026

✅ No Issues Found

7 files reviewed | Confidence: 95% | Recommendation: Merge

Review Details

Files:

  • .changeset/cli-api-request-cost-updates.md - Proper changeset for CLI patch
  • cli/src/state/atoms/extension.ts - Content change detection for same-length updates
  • cli/src/ui/messages/MessageDisplay.tsx - Dynamic message rendering
  • cli/src/ui/messages/extension/say/SayApiReqStartedMessage.tsx - Extended in-progress condition
  • cli/src/ui/messages/utils/messageCompletion.ts - Recursive split for incomplete messages
  • cli/src/state/atoms/__tests__/extension-message-updates.test.ts - Test coverage
  • cli/src/ui/messages/utils/__tests__/messageCompletion.test.ts - Test coverage

Checked: Security, bugs, performance, error handling

Analysis:

  • The content change detection in extension.ts correctly handles same-length updates (e.g., cost 0.00100.0020)
  • The recursive splitMessages call is bounded and intentional - filters partials then applies normal split logic
  • The extended in-progress condition in SayApiReqStartedMessage.tsx aligns with isExtensionMessageComplete logic
  • Test coverage is appropriate for the new behaviors

@kiloconnect
Copy link
Contributor

kiloconnect bot commented Jan 5, 2026

✅ No Issues Found

7 files reviewed | Confidence: 95% | Recommendation: Merge

Review Details

Files Reviewed:

  • .changeset/cli-api-request-cost-updates.md - Changeset (patch)
  • cli/src/state/atoms/__tests__/extension-message-updates.test.ts - Test coverage
  • cli/src/state/atoms/extension.ts - Core logic change
  • cli/src/ui/messages/MessageDisplay.tsx - UI component update
  • cli/src/ui/messages/extension/say/SayApiReqStartedMessage.tsx - Message rendering
  • cli/src/ui/messages/utils/__tests__/messageCompletion.test.ts - Test coverage
  • cli/src/ui/messages/utils/messageCompletion.ts - Message completion logic

Summary:
This PR fixes a side-effect from #4718 where api_req_started messages (non-partial placeholders) could be frozen into Ink <Static> without costs, causing cost updates to either never appear or show up out-of-order/duplicated.

Key Changes:

  1. Content change detection (extension.ts:332-338): Added logic to detect content changes that may not affect length (e.g., numeric JSON fields like costs). This ensures messages update even when 0.0010 changes to 0.0020.

  2. Dynamic tail rendering (MessageDisplay.tsx): Now renders a dynamic tail below the static history, allowing in-progress messages to update in-place until they receive completion indicators.

  3. Completion indicator logic (SayApiReqStartedMessage.tsx:17): Treats api_req_started messages without completion indicators (cost, cancelReason, streamingFailedMessage) as still in progress, keeping them in the dynamic section.

  4. Recursive split logic (messageCompletion.ts:140-143): After filtering out streaming messages with hidePartialMessages, falls back to normal split logic to keep incomplete messages in the dynamic section.

Checked: Security, bugs, performance, error handling, test coverage

Notes:

  • Tests are comprehensive and cover the new same-length content update scenario
  • The recursive call in splitMessages is safe as it only recurses once (the filtered messages won't have hidePartialMessages set)
  • The metadata comparison in contentChanged uses reference equality which is appropriate for this use case since metadata objects are typically replaced, not mutated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants