fix: truncate large tool outputs to prevent Crof incomplete responses
Crof models (mimo, deepseek-v4-pro) return status=incomplete when tool results contain too much text (e.g. full HTML pages at 8500+ tokens). Auto-truncate tool outputs exceeding 8000 chars with truncation notice. Combined with the 30-item conversation trim from previous commit.
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
- Keeps system/developer messages, original user query, and most recent items
|
||||
- Drops oldest tool call/outputs from the middle when conversation grows too long
|
||||
- Prevents `status=incomplete` errors on providers with smaller context windows
|
||||
- **Truncates large tool outputs (>8000 chars)** to prevent model output token exhaustion
|
||||
- Crof's models return `incomplete` when tool results contain too much text (e.g., full HTML pages)
|
||||
- Truncated outputs include `[truncated N chars]` suffix so the model knows data was cut
|
||||
- Added request/response logging to `~/.cache/codex-proxy/requests.log` for debugging
|
||||
- Proxy stderr no longer discarded by launcher (visible in terminal for debugging)
|
||||
|
||||
|
||||
Binary file not shown.
@@ -166,12 +166,24 @@ def forwarded_headers(request_headers, extra=None, browser_ua=False):
|
||||
return headers
|
||||
|
||||
_MAX_INPUT_ITEMS = 30
|
||||
_MAX_TOOL_OUTPUT_CHARS = 8000
|
||||
|
||||
def _trim_input(input_data):
|
||||
if not isinstance(input_data, list) or len(input_data) <= _MAX_INPUT_ITEMS:
|
||||
if not isinstance(input_data, list):
|
||||
return input_data
|
||||
out = []
|
||||
for item in input_data:
|
||||
if item.get("type") == "function_call_output":
|
||||
o = item.get("output", "")
|
||||
if len(o) > _MAX_TOOL_OUTPUT_CHARS:
|
||||
item = dict(item)
|
||||
item["output"] = o[:_MAX_TOOL_OUTPUT_CHARS] + f"\n... [truncated {len(o) - _MAX_TOOL_OUTPUT_CHARS} chars]"
|
||||
print(f"[trim] tool output truncated {len(o)} -> {_MAX_TOOL_OUTPUT_CHARS}", file=sys.stderr)
|
||||
out.append(item)
|
||||
if len(out) <= _MAX_INPUT_ITEMS:
|
||||
return out
|
||||
head_end = 0
|
||||
for i, item in enumerate(input_data):
|
||||
for i, item in enumerate(out):
|
||||
t = item.get("type")
|
||||
if t == "message" and item.get("role") in ("developer", "system"):
|
||||
head_end = i + 1
|
||||
@@ -179,12 +191,12 @@ def _trim_input(input_data):
|
||||
head_end = i + 1
|
||||
else:
|
||||
break
|
||||
head = input_data[:head_end]
|
||||
head = out[:head_end]
|
||||
tail_keep = _MAX_INPUT_ITEMS - len(head)
|
||||
tail = input_data[-tail_keep:]
|
||||
trimmed = len(input_data) - len(head) - len(tail)
|
||||
tail = out[-tail_keep:]
|
||||
trimmed = len(out) - len(head) - len(tail)
|
||||
if trimmed > 0:
|
||||
print(f"[trim] {len(input_data)} items -> {len(head) + len(tail)} (dropped {trimmed} old items)", file=sys.stderr)
|
||||
print(f"[trim] {len(out)} items -> {len(head) + len(tail)} (dropped {trimmed} old items)", file=sys.stderr)
|
||||
return head + tail
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user