Skip to content

fix(codex): replace compacted tool output - #212

Open
hxy91819 wants to merge 5 commits into
vincentkoc:mainfrom
hxy91819:feature/codex-post-tool-replacement
Open

fix(codex): replace compacted tool output#212
hxy91819 wants to merge 5 commits into
vincentkoc:mainfrom
hxy91819:feature/codex-post-tool-replacement

Conversation

@hxy91819

@hxy91819 hxy91819 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • return continue: false for compacted Codex PostToolUse feedback so Codex suppresses the original tool result
  • lock the replacement contract into the Codex adapter test
  • repair the local host E2E fixture and assert replacement output explicitly
  • add pnpm e2e:codex-live, an authenticated manual regression that runs the real codex exec

Why

Codex treats hookSpecificOutput.additionalContext as additive by default. The existing adapter therefore sent both the raw tool result and the compacted summary to the model, increasing context usage instead of reducing it.

With continue: false, Codex continues the turn from the compacted feedback while keeping the original result out of model context.

The offline adapter contract remains fast, while the new live E2E prevents a regression where adapter JSON looks correct but the real Codex model context is not replaced.

Live E2E

pnpm e2e:codex-live:

  • creates an isolated temporary CODEX_HOME
  • symlinks an existing Codex login without copying credentials
  • installs the hook built from the current source
  • runs a deterministic fake gh command through the real Codex CLI
  • checks the transcript for the Tokenjuice summary and absence of the raw marker in model-visible function_call_output
  • checks hook debug output for rewrote: true
  • forces normal compaction even if the caller has TOKENJUICE_NO_OMISSION=1
  • removes the temporary home and authentication symlink

Measured with Codex CLI 0.144.5:

  • raw output: 1886 chars
  • compressed output: 139 chars
  • summary context: 188 chars
  • model-visible function output: 34 chars
  • final model context: 222 chars

This command requires an existing Codex login, invokes a model, and consumes account quota. It is intentionally manual-only and is not part of normal CI.

Verification

  • env -u TOKENJUICE_NO_OMISSION pnpm verify — 2286 tests passed
  • pnpm exec vitest run test/hosts/codex.test.ts -t "returns post-tool feedback without a block decision when tokenjuice compacts output"
  • pnpm e2e:local
  • pnpm e2e:codex-live
  • gitleaks detect --no-git --redact --no-banner --source .
  • Tokenjuice autoreview: clean, no accepted/actionable findings

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@hxy91819

hxy91819 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Correction after separating actual rewrites from keep/skip decisions and checking Codex's current PostToolUse implementation:

  • The installed hook is not an old build. hooks.json invokes /root/.nvm/versions/node/v24.15.0/bin/tokenjuice; it resolves to the global dist/hosts/codex/index.js, whose installed file contains buildCodexReplacementOutput, continue: false, and hookSpecificOutput.additionalContext. Its mtime is 2026-07-26 19:48 +08:00, and the recent evidence below is from later sessions.
  • My previous 156-record aggregate mixed actual rewrites with keep decisions. For generic-compound-command, no-compaction, etc., the debug record contains a hypothetical reduced result but Codex retains the original output. Those rows must not be counted as delivered savings. At the 03:00 UTC cutoff, 7/156 records actually had rewrote:true; the other 149 preserved the original result.
  • Five of those real rewrites were large-document compactions. Their reducer output was 96,310 -> 4,054 chars. The corresponding Codex transcripts contain 4,299 chars of injected developer summaries (including the raw-rerun hints) plus five 34-char function outputs, for 4,469 model-visible chars total. That is a directly observed 95.4% context-payload reduction for those five calls.
  • There is also a real protocol side effect: Codex treats continue:false as HookRunStatus::Stopped. Because Tokenjuice supplies neither stopReason nor reason, Codex adds the default model-visible text PostToolUse hook stopped execution. The transcripts show the compacted developer summary, then that 34-char stop message, then subsequent token-count/reasoning events. Thus the original large output is suppressed and the turn continues, but the model also receives a misleading generic stop message.

Updated conclusion: PR #212 does achieve real replacement/context savings on the rewrite path, and recent local sessions do exercise that code. It also introduces a genuine Stopped-status/default-feedback tradeoff that the current live E2E does not assert away. Setting stopReason to the full summary while retaining additionalContext would duplicate the summary; a better follow-up would use a concise stopReason/reason (or otherwise adapt to a future clean suppression primitive) and add a transcript assertion for the exact model-visible function-call output. Exact provider billing savings still require A/B or billing counters.

hxy91819 added a commit to hxy91819/tokenjuice that referenced this pull request Jul 27, 2026
@hxy91819

Copy link
Copy Markdown
Contributor Author

Follow-up fix pushed in 6b94564.

The replacement response now sets both a concise stopReason and reason:

Tokenjuice replaced the original Bash output with the compacted context above.

The full compacted result remains only in hookSpecificOutput.additionalContext, so the summary is not duplicated. Unit coverage asserts both protocol fields, and the authenticated live E2E now asserts the exact model-visible function_call_output rather than only checking that the raw marker disappeared.

Verification:

  • env -u TOKENJUICE_NO_OMISSION pnpm verify: 131 files, 2,286 tests passed
  • autoreview: clean, no accepted/actionable findings
  • env -u TOKENJUICE_NO_OMISSION pnpm e2e:codex-live: passed on codex-cli 0.144.5
    • raw: 1,886 chars
    • compressed reducer output: 139 chars
    • injected summary context: 188 chars
    • model-visible function-call output: 78 chars (the replacement reason above)
    • final model-visible context: 266 chars
  • merged into fork integration branch personal/all-fixes as e62e238
  • installed the lane3 build locally; doctor codex --local reports status: ok with no issues

@hxy91819

Copy link
Copy Markdown
Contributor Author

Documented and re-verified the Codex replacement tradeoff in bfa8544.

With the currently tested Codex CLI, suppressing the original function_call_output requires continue:false, so the terminal renders a successful Tokenjuice replacement as:

PostToolUse hook (stopped)
  hook context: <compacted output>
  stop: Tokenjuice replaced the original Bash output with the compacted context above.

This is expected only when both the Tokenjuice replacement reason and compacted hook context are present. Here, stopped means the hook stopped the original output from entering model context; it does not mean the Bash command failed. Without continue:false, Codex retains the raw result and merely adds the summary, so the intended context saving is lost.

The authenticated live E2E now also locks down turn continuation: it requires a later non-empty assistant response after the compacted developer context. Latest real run passed with:

  • raw command output: 1,886 chars
  • compacted output: 139 chars
  • final model-visible replacement payload: 266 chars
  • raw marker absent from compacted context and function_call_output
  • assistant response present after replacement

That is an 85.9% character reduction in this fixture (a context-size proxy, not an exact billed-token measurement).

Docs added/updated: docs/codex-integration.md, docs/spec.md, docs/integration-playbook.md, and the README docs index. pnpm verify passes (131 files / 2,286 tests), and pnpm e2e:codex-live passes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants