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
- Replaced all instances of `bytes.Clone` with direct references to enhance efficiency.
- Simplified payload handling across executors and translators by eliminating unnecessary data duplication.
Apply code review feedback from gemini-code-assist:
- Move fallback strings to kirocommon package as exported constants
- Update kiro_claude_request.go to use shared constants
- Update kiro_openai_request.go to use shared constants
- Improves maintainability and avoids duplication
Problem:
- PR #181 fixed empty content for OpenAI format (kiro_openai_request.go)
- But Claude format (kiro_claude_request.go) was not fixed
- OpenCode uses Claude format (/v1/messages endpoint)
- When assistant messages have only tool_use (no text), content becomes empty
- This causes 'Improperly formed request' errors from Kiro API
Example of problematic message format:
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "...", "name": "todowrite", "input": {...}}
]
}
Solution:
- Add empty content fallback in BuildAssistantMessageStruct (Claude format)
- Same fix as PR #181 applied to kiro_openai_request.go
Fixes compaction failures for OpenCode + Quotio + CLIProxyAPIPlus + Kiro stack
- Replaced repetitive string operations with a centralized `escapeGJSONPathKey` function.
- Streamlined handling of JSON schema cleaning for Gemini and Antigravity requests.
- Improved payload management by transitioning from byte slices to strings for processing.
- Removed unnecessary cloning of byte slices in several places.
Apply code review feedback from gemini-code-assist:
- Initialize inputMap upfront instead of using nested if blocks
- Combine Exists() and IsObject() checks into single condition
- Remove redundant nil check
Problem:
- PR #162 fixed empty string content but missed array content with tool_use
- OpenCode's compaction requests send assistant messages with content as array
- When content array contains only tool_use (no text), content becomes empty
- This causes 'Improperly formed request' errors from Kiro API
Example of problematic message format:
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "...", "name": "todowrite", "input": {...}}
]
}
Solution:
- Extract tool_use from content array (Anthropic/OpenCode format)
- This is in addition to existing tool_calls handling (OpenAI format)
- The empty content fallback from PR #162 will then work correctly
Fixes compaction failures that persisted after PR #162 merge.
Google official Gemini Python SDK sends thinking_level, thinking_budget,
and include_thoughts (snake_case) instead of thinkingLevel, thinkingBudget,
and includeThoughts (camelCase). This caused thinking configuration to be
ignored when using Python SDK.
Changes:
- Extract layer: extractGeminiConfig now reads snake_case as fallback
- Apply layer: Gemini/CLI/Antigravity appliers clean up snake_case fields
- Translator layer: Gemini->OpenAI/Claude/Codex translators support fallback
- Tests: Added 4 test cases for snake_case field coverage
Fixes#1426
- Add logic to handle `image` content type during request translation.
- Map Claude base64 image data to Gemini's `inlineData` structure.
- Support automatic extraction of `media_type` and `data` for image parts.
Apply code review feedback from gemini-code-assist:
- Define default messages as local constants to improve maintainability
- Avoid magic strings in the empty content handling logic
Problem:
- OpenCode's /compaction command and auto-compaction (at 80%+ context)
sends requests that can result in empty assistant message content
- Kiro API strictly requires non-empty content for all messages
- This causes 'Bad Request: Improperly formed request' errors
- After compaction failure, the malformed message stays in history,
breaking all subsequent requests in the session
Solution:
- Add fallback content for empty assistant messages in
buildAssistantMessageFromOpenAI()
- Add history truncation (max 50 messages) to prevent oversized requests
- This ensures all messages have valid content before sending to Kiro API
Fixes issues with:
- /compaction command returning Bad Request
- Auto-compaction breaking sessions
- Conversations becoming unresponsive after compaction failure
Add support for Gemini's code_execution and url_context tools in the
request translators, enabling:
- Agentic Vision: Image analysis with Python code execution for
bounding boxes, annotations, and visual reasoning
- URL Context: Live web page content fetching and analysis
Tools are passed through using the same pattern as google_search:
- code_execution: {} -> codeExecution: {}
- url_context: {} -> urlContext: {}
Tested with Gemini 3 Flash Preview agentic vision successfully.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the Kiro/AWS CodeWhisperer API receives a Write tool request with content
that exceeds transmission limits, it truncates the tool input. This can result in:
- Empty input buffer (no input transmitted at all)
- Missing 'content' field in the parsed JSON
- Incomplete JSON that fails to parse
This fix detects these truncation scenarios and converts them to Bash tool calls
that echo an error message. This allows Claude Code to execute the Bash command,
see the error output, and the agent can then retry with smaller chunks.
Changes:
- kiro_claude_tools.go: Detect three truncation scenarios in ProcessToolUseEvent:
1. Empty input buffer (no input transmitted)
2. JSON parse failure with file_path but no content field
3. Successfully parsed JSON missing content field
When detected, emit a special '__truncated_write__' marker tool use
- kiro_executor.go: Handle '__truncated_write__' markers in streamToChannel:
1. Extract file_path from the marker for context
2. Create a Bash tool_use that echoes an error message
3. Include retry guidance (700-line chunks recommended)
4. Set hasToolUses=true to ensure stop_reason='tool_use' for agent continuation
This ensures the agent continues and can retry with smaller file chunks instead
of failing silently or showing errors to the user.
When using Gemini API format with Antigravity backend, the executor
renames usageMetadata to cpaUsageMetadata in non-terminal chunks.
The Gemini translator was returning this internal field name directly
to clients instead of the standard usageMetadata field.
Add restoreUsageMetadata() to rename cpaUsageMetadata back to
usageMetadata before returning responses to clients.
When Claude API sends an assistant message with empty text content like:
{"role":"assistant","content":[{"type":"text","text":""}]}
The translator was creating a part object {} with no data field,
causing Gemini API to return error:
"required oneof field 'data' must have one initialized field"
This fix:
1. Skips empty text parts (text="") during translation
2. Skips entire messages when their parts array becomes empty
This ensures compatibility when clients send empty assistant messages
in their conversation history.