Skip to content

[Feature]: extend the no-tool-call terminal continuation guard beyond the anthropic adapter (openai-chat routed models stop early) #1651

Description

@TooSpace

Client or integration

Codex App

Area

Proxy and routing

Summary

The bounded "no-tool-call terminal continuation" guard is hardwired to the anthropic adapter only. openai-chat-routed reasoning models that end a turn with a clean stop after announcing an action (e.g. "let me check X / found it, now extracting") — but without emitting the tool call — are treated as complete. Codex renders the turn as finished, and the user has to manually prompt "continue". This is the same class of premature-termination the anthropic guard already fixes, just on the chat adapter.

In practice GLM-5.2 (and combo children routing to it) hit this: the model narrates its plan, emits finish_reason: stop with no tool_calls, and the run stops early even though a tool call was clearly intended.

What I expected

The terminal guard's eligibility and analysis should be extendable to specific openai-chat routed models known to prematurely stop, not locked to adapterName === "anthropic". Either a provider/model opt-in, or applying the same analyzeTerminalTurn heuristic to openai-chat when a tool-call was announced-but-absent.

Evidence (code path)

src/server/responses/core.ts:

const terminalGuardEnabled = activeAdapter.name === "anthropic" && !options.comboAttempt && !routedCompaction;

src/server/responses/terminal-guard.ts:

const analysis = options.adapterName === "anthropic"
  ? analyzeTerminalTurn(parsed, seen)
  : { decision: "pass" as const };

Both gates are adapter-name equality checks against "anthropic". The continuation machinery (analyzeTerminalTurn, buildContinuationRequest, maxContinuations) is adapter-agnostic — only these two eligibility checks scope it to anthropic. A routed openai-chat model that exhibits the same "announce-then-stop-without-tool-call" pattern never gets the one bounded re-ask.

Reproduction

  1. Route GLM-5.2 through an openai-chat provider.
  2. Send an executable task where the model tends to narrate intent first (e.g. "check the contents of /etc/hosts and tell me what you find") with a read_file tool available.
  3. Occasionally the model emits a short "I'll check that for you" message, finish_reason: stop, and no tool_calls. The turn ends; no continuation is attempted.
  4. The same request against the anthropic adapter would get one bounded internal continuation.

Proposal (either is fine)

  1. Add a provider/model allowlist (e.g. provider.terminalGuardModels: string[]) that extends terminalGuardEnabled and the analysis branch to those openai-chat routed models; or
  2. Enable the guard for openai-chat generally when a tool was announced-but-absent, gated behind the same bounded single-continuation and short-reply constraints the anthropic path uses, so normal long answers and plan-only turns are unaffected.

Version

opencodex 2.14.2 (ocx --version); running local service confirmed via GET /healthz.

Operating system

macOS 26.5.1 (25F80)

Provider and model

GLM-5.2 routed through an openai-chat OpenAI-compatible gateway, and a failover combo whose children route to it. Reproducible with any openai-chat reasoning model that ends turns by narrating an intended tool call without emitting it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproxyHTTP proxy, routing, reverse-proxy / management authtoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions