mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-03-30 01:06:39 +00:00
Merge pull request #150 from PancakeZik/fix/write-tool-truncation-handling
fix: handle Write tool truncation when content exceeds API limits
This commit is contained in:
@@ -2372,8 +2372,8 @@ func (e *KiroExecutor) extractEventTypeFromBytes(headers []byte) string {
|
||||
func (e *KiroExecutor) streamToChannel(ctx context.Context, body io.Reader, out chan<- cliproxyexecutor.StreamChunk, targetFormat sdktranslator.Format, model string, originalReq, claudeBody []byte, reporter *usageReporter, thinkingEnabled bool) {
|
||||
reader := bufio.NewReaderSize(body, 20*1024*1024) // 20MB buffer to match other providers
|
||||
var totalUsage usage.Detail
|
||||
var hasToolUses bool // Track if any tool uses were emitted
|
||||
var upstreamStopReason string // Track stop_reason from upstream events
|
||||
var hasToolUses bool // Track if any tool uses were emitted
|
||||
var upstreamStopReason string // Track stop_reason from upstream events
|
||||
|
||||
// Tool use state tracking for input buffering and deduplication
|
||||
processedIDs := make(map[string]bool)
|
||||
@@ -3151,12 +3151,92 @@ func (e *KiroExecutor) streamToChannel(ctx context.Context, body io.Reader, out
|
||||
_ = signature // Signature can be used for verification if needed
|
||||
|
||||
case "toolUseEvent":
|
||||
// Debug: log raw toolUseEvent payload for large tool inputs
|
||||
if log.IsLevelEnabled(log.DebugLevel) {
|
||||
payloadStr := string(payload)
|
||||
if len(payloadStr) > 500 {
|
||||
payloadStr = payloadStr[:500] + "...[truncated]"
|
||||
}
|
||||
log.Debugf("kiro: raw toolUseEvent payload (%d bytes): %s", len(payload), payloadStr)
|
||||
}
|
||||
// Handle dedicated tool use events with input buffering
|
||||
completedToolUses, newState := kiroclaude.ProcessToolUseEvent(event, currentToolUse, processedIDs)
|
||||
currentToolUse = newState
|
||||
|
||||
// Emit completed tool uses
|
||||
for _, tu := range completedToolUses {
|
||||
// Check for truncated write marker - emit as a Bash tool that echoes the error
|
||||
// This way Claude Code will execute it, see the error, and the agent can retry
|
||||
if tu.Name == "__truncated_write__" {
|
||||
filePath := ""
|
||||
if fp, ok := tu.Input["file_path"].(string); ok && fp != "" {
|
||||
filePath = fp
|
||||
}
|
||||
|
||||
// Create a Bash tool that echoes the error message
|
||||
// This will be executed by Claude Code and the agent will see the result
|
||||
var errorMsg string
|
||||
if filePath != "" {
|
||||
errorMsg = fmt.Sprintf("echo '[WRITE TOOL ERROR] The file content for \"%s\" is too large to be transmitted by the upstream API. You MUST retry by writing the file in smaller chunks: First use Write to create the file with the first 700 lines, then use multiple Edit operations to append the remaining content in chunks of ~700 lines each.'", filePath)
|
||||
} else {
|
||||
errorMsg = "echo '[WRITE TOOL ERROR] The file content is too large to be transmitted by the upstream API. The Write tool input was truncated. You MUST retry by writing the file in smaller chunks: First use Write to create the file with the first 700 lines, then use multiple Edit operations to append the remaining content in chunks of ~700 lines each.'"
|
||||
}
|
||||
|
||||
log.Warnf("kiro: converting truncated write to Bash echo for file: %s", filePath)
|
||||
|
||||
hasToolUses = true
|
||||
|
||||
// Close text block if open
|
||||
if isTextBlockOpen && contentBlockIndex >= 0 {
|
||||
blockStop := kiroclaude.BuildClaudeContentBlockStopEvent(contentBlockIndex)
|
||||
sseData := sdktranslator.TranslateStream(ctx, sdktranslator.FromString("kiro"), targetFormat, model, originalReq, claudeBody, blockStop, &translatorParam)
|
||||
for _, chunk := range sseData {
|
||||
if chunk != "" {
|
||||
out <- cliproxyexecutor.StreamChunk{Payload: []byte(chunk + "\n\n")}
|
||||
}
|
||||
}
|
||||
isTextBlockOpen = false
|
||||
}
|
||||
|
||||
contentBlockIndex++
|
||||
|
||||
// Emit as Bash tool_use
|
||||
blockStart := kiroclaude.BuildClaudeContentBlockStartEvent(contentBlockIndex, "tool_use", tu.ToolUseID, "Bash")
|
||||
sseData := sdktranslator.TranslateStream(ctx, sdktranslator.FromString("kiro"), targetFormat, model, originalReq, claudeBody, blockStart, &translatorParam)
|
||||
for _, chunk := range sseData {
|
||||
if chunk != "" {
|
||||
out <- cliproxyexecutor.StreamChunk{Payload: []byte(chunk + "\n\n")}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the Bash command as input
|
||||
bashInput := map[string]interface{}{
|
||||
"command": errorMsg,
|
||||
}
|
||||
inputJSON, err := json.Marshal(bashInput)
|
||||
if err != nil {
|
||||
log.Errorf("kiro: failed to marshal bash input for truncated write error: %v", err)
|
||||
continue
|
||||
}
|
||||
inputDelta := kiroclaude.BuildClaudeInputJsonDeltaEvent(string(inputJSON), contentBlockIndex)
|
||||
sseData = sdktranslator.TranslateStream(ctx, sdktranslator.FromString("kiro"), targetFormat, model, originalReq, claudeBody, inputDelta, &translatorParam)
|
||||
for _, chunk := range sseData {
|
||||
if chunk != "" {
|
||||
out <- cliproxyexecutor.StreamChunk{Payload: []byte(chunk + "\n\n")}
|
||||
}
|
||||
}
|
||||
|
||||
blockStop := kiroclaude.BuildClaudeContentBlockStopEvent(contentBlockIndex)
|
||||
sseData = sdktranslator.TranslateStream(ctx, sdktranslator.FromString("kiro"), targetFormat, model, originalReq, claudeBody, blockStop, &translatorParam)
|
||||
for _, chunk := range sseData {
|
||||
if chunk != "" {
|
||||
out <- cliproxyexecutor.StreamChunk{Payload: []byte(chunk + "\n\n")}
|
||||
}
|
||||
}
|
||||
|
||||
continue // Skip the normal tool_use emission
|
||||
}
|
||||
|
||||
hasToolUses = true
|
||||
|
||||
// Close text block if open
|
||||
|
||||
Reference in New Issue
Block a user