fix(translator): restructure message content handling to support multiple content types
- Consolidated `input_text` and `output_text` handling into a single case.
- Added support for processing `input_image` content with associated URLs.
> Copilot Premium usage significantly amplified when using amp
- Add X-Initiator header (user/agent) based on last message role to
prevent Copilot from billing all requests as premium user-initiated
- Add flattenAssistantContent() to convert assistant content from array
to string, preventing Claude from re-answering all previous prompts
- Align Copilot headers (User-Agent, Editor-Version, Openai-Intent) with
pi-ai reference implementation
Closes#113
Amp-Thread-ID: https://ampcode.com/threads/T-019c392b-736e-7489-a06b-f94f7c75f7c0
Co-authored-by: Amp <amp@ampcode.com>
- Updated `KimiAPIBaseURL` to remove versioning from the root path.
- Integrated `ClaudeExecutor` fallback in `KimiExecutor` methods for compatibility with Claude requests.
- Simplified token counting by delegating to `ClaudeExecutor`.
- Standardized the handling of `stop_reason` and `finish_reason` across Codex and Gemini responses.
- Restricted pass-through of specific reasons (`max_tokens`, `stop`) for consistency.
- Enhanced fallback logic for undefined reasons.
Kiro API requires non-empty content on assistant messages, so
CLIProxyAPI injects placeholder text when assistant messages only
contain tool_use blocks (no text). The previous placeholders were
conversational phrases:
- DefaultAssistantContentWithTools: "I'll help you with that."
- DefaultAssistantContent: "I understand."
In agentic sessions with many tool calls, these phrases appeared
dozens of times in conversation history. Opus 4.6 (and likely other
models) picked up on this pattern and started parroting "I'll help
you with that." before every tool call in its actual responses.
Fix: Replace both placeholders with a single dot ".", which
satisfies Kiro's non-empty requirement without giving the model
a phrase to mimic.
- Added support to extract and include `cachedContentTokenCount` in `usage.prompt_tokens_details`.
- Logged warnings for failures to set cached token count for better debugging.
- Introduced `RequestKimiToken` API for Kimi authentication flow.
- Integrated device ID management throughout Kimi-related components.
- Enhanced header management for Kimi API requests with device ID context.
- Add contextUsageEvent case handler in kiro_executor.go for both
parseEventStream and streamToChannel functions
- Handle nested format: {"contextUsageEvent": {"contextUsagePercentage": 0.53}}
- Keep KiroModel struct minimal with only essential fields
- Remove unused KiroPromptCachingInfo struct from kiro_model_converter.go
- Remove unused SupportedInputTypes and PromptCaching fields from KiroAPIModel
Problem:
- PR #186 fixed empty content for assistant messages and history user messages
- But current user message (isLastMessage == true) was not fixed
- When user message contains only tool_result (no text), content becomes empty
- This causes 'Improperly formed request' errors from Kiro API
- Compaction requests from OpenCode commonly have this pattern
Solution:
- Move empty content check BEFORE the isLastMessage branch
- Apply fallback content to ALL user messages, not just history
- Add DefaultUserContentWithToolResults and DefaultUserContent constants
Fixes compaction failures for OpenCode + Quotio + CLIProxyAPIPlus + Kiro stack
- OAuth2 device authorization grant flow (RFC 8628) for authentication
- Streaming and non-streaming chat completions via OpenAI-compatible API
- Models: kimi-k2, kimi-k2-thinking, kimi-k2.5
- CLI `--kimi-login` command for device flow auth
- Token management with automatic refresh
- Thinking/reasoning effort support for thinking-enabled models
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>