Skip to content

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

Closed

Description

@tone-leh

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.

Activity

  1. coderabbitai commented on Aug 14, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #304 - fix(kiro): restore hardening and complete text turns [open]
    #394 - fix(anthropic): guard premature no-tool completions [merged]
    #419 - [WRONG BRANCH] Local/stable [open]
    #757 - feat: route GPT-5.6 Pro through standard ChatGPT [open]
    #793 - fix(openai-chat): complete streams that end after output without terminal [merged]
    #1468 - fix(openai-chat): tolerate null tool-call padding [merged]
    #1531 - fix(openai-chat): refuse to emit an unnamed streamed tool call [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added
    bugSomething isn't working
    proxyHTTP proxy, routing, reverse-proxy / management auth
    toolstool_calls, MCP, web-search / sidecar tools
    on Aug 14, 2026
  3. tone-leh commented on Aug 14, 2026

    @tone-leh
    ContributorAuthor

    Note for triage: this is distinct from #1531. #1531 makes a stream fail closed when a tool call is malformed/unnamed. This issue is the opposite direction: a model that legitimately produces no tool call while its turn is not actually finished is treated as done and the turn stops early.

    The no-tool-call terminal continuation guard (from #394) is currently bound to the anthropic adapter only. openai-chat routed models (self-hosted GLM/Kimi-family gateways) hit the same premature-completion pattern but do not get the guard, so they stop mid-work. Requesting the guard be extended to the openai-chat path. No overlap with #1531's error-termination logic.

  4. Ingwannu commented on Aug 14, 2026

    @Ingwannu
    Owner

    Confirmed as a real routing gap on the current code path. The existing terminal guard is Anthropic-only, so openai-chat providers cannot opt into the same bounded continuation even when a model exhibits the same announce-then-stop behavior.

    PR #1660 is the conservative direction I would accept: a provider-level terminalContinuationGuard opt-in, one bounded continuation, and the existing combo/compaction exclusions preserved. It should not be enabled globally because the heuristic has not been calibrated across model families and languages. Keeping this issue open until #1660 is rebased onto current dev, leaves draft, and passes exact-head review/CI.

  5. lidge-jun commented on Aug 14, 2026

    @lidge-jun
    Owner

    Closing: this is a design/enhancement proposal (opt-in provider terminal guard), not a bug fix. The current behavior is intentional — the terminal continuation guard is Anthropic-specific. Extending it to other providers requires per-provider opt-in design. Reopen as a feature request if needed.

  6. lidge-jun commented on Aug 14, 2026

    @lidge-jun
    Owner

    Reopened — reclassification does not justify closing. Keeping open as a valid enhancement request.

  7. added a commit that references this issue on Aug 15, 2026
    f6d841b
  8. added a commit that references this issue on Sep 17, 2026
    a2eac17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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