Skip to content

ACP adapter does not report token usage (PromptResponse.usage empty, no usage_update emitted) #1855

Description

@Jetiaime

Summary

Kimi Code's ACP adapter does not report token usage to ACP clients. The PromptResponse.usage field is left empty and no usage_update events are emitted on turn.ended. This causes downstream ACP clients (e.g., Multica, OpenCode, Claude Code running kimi as backend) to have zero visibility into token consumption and cost.

Impact

  1. Breaking for external orchestration platforms. Multica's runtime usage command shows zero rows for Kimi runtime, while Claude/OpenAI runtimes on the same daemon return full per-model breakdowns. Cost calibration autopilots that read usage data permanently skip Kimi agents.

  2. The data exists internally. Kimi Code's internal SDK tracks usage via session.getUsage() and serializes it to wire.jsonl (inputOther/output/inputCacheRead/inputCacheCreation). It just never crosses the ACP boundary.

  3. Old Python kimi-cli had the same bug. kimi-cli#2394 reported the identical issue in the legacy Python codebase. This is a known gap.

Root Cause

In packages/acp-adapter/src/session.ts, the turn.ended handler resolves with only stopReason:

// Current (v0.26.0):
resolve({ stopReason: ... })
// No PromptResponse.usage filled
// No usage_update event emitted

The ACP protocol supports two paths for usage reporting:

  1. PromptResponse.usage — maps directly to TurnResponse and is consumed by Multica's kimi adapter (kimi.go L305–L385).
  2. session/update with usage_update — parsed by the shared ACP client with camelCase/snake_case compatibility (hermes.go L988–L1058).

Either path, if filled, would be picked up by existing downstream code immediately—no changes needed in Multica or other ACP consumers.

Proposed Fix

In the turn.ended handler (or a new prompt.ended handler), call session.getUsage() and populate PromptResponse.usage:

const usage = session.getUsage()
resolve({
  stopReason: ...,
  usage: {
    inputTokens: usage.inputTokens,
    outputTokens: usage.outputTokens,
    // cache fields if tracked:
    // cacheReadInputTokens: usage.inputCacheRead,
    // cacheCreationInputTokens: usage.inputCacheCreation,
  }
})

Alternatively (or additionally), emit a usage_update via session/update notification.

Steps to Reproduce

  1. Run kimi-code v0.26.0 in ACP mode (kimi acp)
  2. Complete any turn (simple prompt or tool-calling turn, doesn't matter)
  3. Observe the prompt response — usage field is absent or empty
  4. Compare with Claude Code / OpenCode in ACP mode — both fill usage on every turn

Environment

  • kimi-code: 0.26.0 (Nix-installed on macOS ARM64, Node.js v24.18.0)
  • ACP protocol version: 1.4
  • Model: k3 (also reproducible with kimi-for-coding)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions