From 662d8e961e233be308ae21e0f3df7c9a9c33f267 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 19 May 2026 21:49:55 +0400 Subject: [PATCH] feat: auto-compaction for long conversations (like Claude Code/Codex /compact) Instead of just truncating old items, the proxy now auto-compacts them into a structured summary preserving key context: - User requests, assistant responses, tool calls made, files touched - Keeps original query + system messages + last 10 recent items - 38 items -> 14 items in testing, with summary of dropped turns - Similar to Claude Code's auto-compact and Codex CLI's /compact - No extra API calls needed, instant, zero cost --- CHANGELOG.md | 7 +- codex-launcher_2.1.2_all.deb | Bin 24292 -> 24910 bytes src/translate-proxy.py | 135 +++++++++++++++++++++++++++++------ 3 files changed, 117 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e15f1c..b13074b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ - Codex sends `function_call` items with `id=None` — proxy now matches tool results to calls by call_id + positional fallback - Fixed orphan message output item when response is only tool calls (no text content) - **Auto-trims long conversations (>30 items)** to prevent context overflow on providers like Crof - - 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 + - Keeps system/developer messages, original user query, and most recent 10 items + - **Auto-compacts old items into a summary** instead of just dropping them + - Summary includes: user requests, assistant responses, tool calls made, files touched + - Preserves enough context for the model to continue long tasks intelligently - **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 diff --git a/codex-launcher_2.1.2_all.deb b/codex-launcher_2.1.2_all.deb index e57cfa8e10ea7a8ce68177a215b3aeb2a0bce29f..00f3d80dffee58156bc6131c829286c632d57096 100644 GIT binary patch delta 23887 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 |89Or-ftKk5D zrwi!|4CBazJh)fTMEqrpIh+vxRx#MYv6o!eRJnHtsvp^L%hgN}`W`MLKRlKvv!2%y zB=PLEFEJRN~Qks-QF3`{P^$9eb!Eprdu)lw*Itvwk9NU zzzK__zsd-n;E(XMkI;WW9^ZJvevTQfYq3ZgK{51pQ5Gjw%A{%^4-kJWfFRV1Y`+nBbaPxvJ?R8%Qj}PTPcGTKgdYMZ+7A%qSEMB%AOaMR z_*wveW*SBHi%bprxAQCRY8H%UhHo*8f6}BB|I4&9uBBg7RAwO-kbVVU;yZzTy%7%l z<(cmYc(hIHlY%`PsU$CBVyw2OZQPOHAWPmai;8PA#yNkR5aKT$Fe%Le+SV0J4G}H} zrApq9pQgPJGwG%PWoTJEOVf$_1TIVHG2fsDs3p9kC~;FK!wssIVMxIY0POgMzi7u( z!|E=KsZsOM;+g?6vh7UiS*>>imnLK`e%d{fKsv&V9zF$F@#&xyY`(sAi{&cKPd$$j zo>YrVtrLH+nGN1YLB9aZrIX>P#?DurO+uzQpMEwv7i(zs@-8V4iaRaJNH2XrR%laU zsZ}-f=i;&0xQoBt$OKC@aJ4QEteFFdHyf~g5yw)#)yW*Dyo*S@gT-S)HGy~Or8?m? zNib(Mm5-gI_m-0QK0dUnfX96QjGV(ky@aTqs=5uFNPEiv&~ zN?Le<3@TL0(NxVTg-fRPt`r{64jzJA5o?=8kMU6 zN>qQAS=!Z&OD}I00c?q05~usQ9>)5j=b*z($-ufTiD;NX{=11i!CcT~%-buM6rDq@ zJt$rr+3RW(-%V06>wd3{8RR4y;X4Gd(_%w6FA|j`>vMVLGX^6!kH;;QVn5^JeG_)Mcd>!hrx8z#k0TO&IN zeR6LmXj>x1t#VQdA2}y87*bwbRRQ9L->3jc1_~~!f!0_iy^Yd7in7RTZ%&e z7+n!Fi>>&EI0|d-xk&!ON;I!{vuJ;ycA2a6U7i`kP~H~&Ry}M$FAYsiKAKDhztSWz zc=_cvB>u!C{`OBk^TL#d9z(0PZ$BtSaZV4^k67DXpQ=vI>dsk`Gd-tps1{P-S5;o5 zj0tyqQ4X0Mq0|EmEYg1*Wq$xe zcKqTOPakG(RwcG323zrvg_0lOK;ep?i~C&86S(0znUyk5YH7dVGhG<~0V3Ts8iU|~ z10^dx79yrZk`j{p;mwhVQ5Ks6deMu6lgRn{mx5^I1V(b}trw<6sX677+v6Z}eG^*e>rUnnP`BpoD*Qro&Q?PQ8|NwQUU^2Up=S9`{TGM3c@X8Z0UGy>jhm`qH>-&E-%$9!z29#XIMU|$|Mh}Uj)RQebRfWJ~tB!te@rZ|OR^qaX zfsvByHP1yyKo|+i*UidZVl|Hd1|Saq;1 Z5J?*PsU(pr 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

1|wKkQWgB6=Ly9eTi6Oi5}U3lRcTN%9MS)@@mk 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 _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: +def _item_summary(item, max_len=200): + t = item.get("type") + if t == "message": + role = item.get("role", "?") + text = "" + for p in item.get("content", []): + if p.get("type") in ("input_text", "output_text"): + text += p.get("text", "") + return f"[{role}] {text[:max_len]}" + elif t == "function_call": + name = item.get("name", "?") + args = item.get("arguments", "{}") + try: + a = json.loads(args) + cmd = a.get("cmd", a.get("command", "")) + if cmd: + return f"[tool call] {name}: {cmd[:max_len]}" + except Exception: + pass + return f"[tool call] {name}({args[:max_len]})" + elif t == "function_call_output": + output = item.get("output", "") + if len(output) > max_len: + return f"[tool result] {output[:max_len]}..." + return f"[tool result] {output}" + return f"[{t}]" + +def _extract_files(items): + files = set() + for item in items: + if item.get("type") == "function_call": + try: + a = json.loads(item.get("arguments", "{}")) + cmd = a.get("cmd", a.get("command", "")) + for prefix in (">", ">>", " > ", " >> "): + for part in cmd.split(prefix)[1:]: + f = part.strip().split()[0].strip("'\"") + if f and not f.startswith("-") and "/" in f: + files.add(f) + except Exception: + pass + return files + +def _compact_input(input_data): + if not isinstance(input_data, list) or len(input_data) <= _MAX_INPUT_ITEMS: + out = [] + for item in input_data: + if isinstance(item, dict) and 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"[compact] tool output truncated {len(o)} -> {_MAX_TOOL_OUTPUT_CHARS}", file=sys.stderr) + out.append(item) return out + head_end = 0 - for i, item in enumerate(out): + for i, item in enumerate(input_data): t = item.get("type") if t == "message" and item.get("role") in ("developer", "system"): head_end = i + 1 @@ -191,13 +234,61 @@ def _trim_input(input_data): head_end = i + 1 else: break - head = out[:head_end] - tail_keep = _MAX_INPUT_ITEMS - len(head) - tail = out[-tail_keep:] - trimmed = len(out) - len(head) - len(tail) - if trimmed > 0: - print(f"[trim] {len(out)} items -> {len(head) + len(tail)} (dropped {trimmed} old items)", file=sys.stderr) - return head + tail + + head = input_data[:head_end] + tail = input_data[-_COMPACT_KEEP_RECENT:] + body = input_data[head_end:-_COMPACT_KEEP_RECENT] + + if not body: + return head + tail + + for item in tail: + if isinstance(item, dict) and item.get("type") == "function_call_output": + o = item.get("output", "") + if len(o) > _MAX_TOOL_OUTPUT_CHARS: + item["output"] = o[:_MAX_TOOL_OUTPUT_CHARS] + f"\n... [truncated {len(o) - _MAX_TOOL_OUTPUT_CHARS} chars]" + + user_queries = [] + for item in body: + if item.get("type") == "message" and item.get("role") == "user": + for p in item.get("content", []): + if p.get("type") == "input_text": + user_queries.append(p.get("text", "")[:300]) + assistant_msgs = [] + for item in body: + if item.get("type") == "message" and item.get("role") == "assistant": + for p in item.get("content", []): + if p.get("type") == "output_text": + assistant_msgs.append(p.get("text", "")[:300]) + + tool_summaries = [] + for item in body: + if item.get("type") in ("function_call", "function_call_output"): + tool_summaries.append(_item_summary(item, max_len=150)) + + files = _extract_files(body) + + summary_lines = [f"[Auto-compacted: {len(body)} earlier turns summarized to preserve context]"] + if user_queries: + summary_lines.append(f"User requests: {'; '.join(user_queries[-3:])}") + if assistant_msgs: + summary_lines.append(f"Assistant responses: {'; '.join(assistant_msgs[-3:])}") + if tool_summaries: + summary_lines.append(f"Actions taken ({len(tool_summaries)} steps):") + for ts in tool_summaries[-15:]: + summary_lines.append(f" {ts}") + if files: + summary_lines.append(f"Files touched: {', '.join(sorted(files)[-10:])}") + + summary_text = "\n".join(summary_lines) + summary_msg = { + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": summary_text}] + } + + print(f"[compact] {len(input_data)} items -> {len(head) + 1 + len(tail)} (compacted {len(body)} old items into summary)", file=sys.stderr) + return head + [summary_msg] + tail # ═══════════════════════════════════════════════════════════════════ # OpenAI-compat backend @@ -750,7 +841,7 @@ class Handler(http.server.BaseHTTPRequestHandler): prev_id = body.get("previous_response_id") raw_input = body.get("input", "") input_data = resolve_previous_response(body) - input_data = _trim_input(input_data) + input_data = _compact_input(input_data) body["input"] = input_data raw_types = [i.get("type") for i in raw_input] if isinstance(raw_input, list) else "str"