Skip to content

[Compatibility] Camel DeepSeek V4 Flash misses structured tool call on the first tool round #1730

Closed as not planned

Description

@idguyst

Client or integration

Codex App

Provider or upstream service

Camel Stream (stream.camelai.com), model deepseek-v4-flash

Endpoint or capability

Custom-provider /v1/responses model routing and first-tool-round tool-selection behavior.

The provider-wide adapter remains openai-chat, while only deepseek-v4-flash is routed through openai-responses.

Remaining problem

This issue now tracks only whether Camel deepseek-v4-flash emits code-mode-style text/markup instead of a structured tool call on the first tool round when tool_choice: "auto" is used.

The second problem from the original report, loss of the unified exec custom-to-function input description, was fixed in #1763 and merged into dev. The exec JavaScript input contract is therefore no longer part of this issue's implementation scope.

Expected behavior

  • On the first tool round for stream.camelai.com + deepseek-v4-flash, the model should produce a structured tool call when it chooses to use a tool declared in the request.
  • Requests using an explicit tool_choice must preserve their current semantics.
  • Continuation turns containing tool results must preserve their current semantics.
  • Other hosts, models, and providers must remain unaffected.

Evidence required before implementation

The following evidence is required against current dev:

  1. A redacted raw upstream response from the first tool round showing the actual text/markup shape returned instead of a structured tool call.
  2. Confirmation that tool_choice: "auto" was used with the same request/tool catalog.
  3. The result of a control request using an explicit tool choice.
  4. Control evidence showing that a continuation turn after tool output still behaves normally.

Without this evidence, we should not add a host/model hardcode that forces first-round tool_choice: "required" only for stream.camelai.com + deepseek-v4-flash. There is no public upstream contract for that behavior, so a provider-specific policy change requires reproducible current evidence.

Minimal redacted reproduction

{
  "adapter": "openai-chat",
  "baseUrl": "https://stream.camelai.com/v1",
  "defaultModel": "deepseek-v4-flash",
  "modelAdapters": {
    "deepseek-v4-flash": "openai-responses"
  },
  "responsesPath": null
}
  1. On current dev, send a first request that includes tools.
  2. Record the upstream request's tool_choice and tool catalog.
  3. Capture the raw upstream response in redacted form.
  4. Run an explicit-tool-choice control under the same conditions.
  5. Run a continuation control that includes tool output.

Already fixed / out of scope

  • Unified exec custom-to-function JavaScript input guidance: fixed by fix(responses): preserve unified exec input contract #1763 and merged into dev.
  • Do not reimplement the bare-shell exec input problem in this issue.
  • General custom-tool conversion changes are out of scope unless new evidence shows a separate regression.

Related

Checks

  • I searched existing provider and compatibility issues.
  • The request and response must be redacted.
  • Current-dev raw first-response evidence for the remaining Camel-specific behavior is still required.

Activity

  1. coderabbitai commented on Aug 15, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #1361 - fix(responses): restore DeepSeek streaming and routed code-mode tools [merged]
    #1479 - fix(deepseek): preserve parallel reasoning replay [open]
    #1499 - fix(deepseek): keep parallel reasoning replay on continuation [open]
    #1531 - fix(openai-chat): refuse to emit an unnamed streamed tool call [merged]
    #1763 - fix(responses): preserve unified exec input contract [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. github-actions commented on Aug 15, 2026

    @github-actions
    Contributor

    Maintainer decision respected

    A maintainer has reopened this issue. The automated closure has been deactivated.

  3. Ingwannu commented on Aug 15, 2026

    @Ingwannu
    Owner

    Confirmed one real general compatibility defect, but not enough evidence to adopt the proposed host/model hardcode as-is.

    The confirmed defect is the custom-to-function conversion for exec: current dev replaces the original freeform contract with the generic description Raw input for this client-executed custom tool. That loses the fact that the input is JavaScript evaluated by unified exec, with shell commands invoked through tools.exec_command(...) and output returned through text(...). A model can therefore reasonably emit a bare shell command that the JavaScript evaluator rejects. This should be fixed at the shared exec conversion boundary with focused regressions.

    The separate proposal to force tool_choice: required only for stream.camelai.com + deepseek-v4-flash on the first tool round is not ready to land yet. There is no public upstream contract for that behavior, and a hostname/model special case changes tool-selection semantics for every user of that route. Before adopting it, we need a redacted raw first-response capture showing the malformed text/markup shape on current dev, plus confirmation that a normal explicit tool choice and continuation turn remain unchanged.

    I will treat the shared exec input-contract repair independently so that confirmed behavior does not wait on the provider-specific policy decision.

  4. Ingwannu commented on Aug 15, 2026

    @Ingwannu
    Owner

    The confirmed shared exec conversion defect is implemented in #1763.

    The patch restores the JavaScript contract only for the converted unified exec tool, including the required tools.exec_command(...) and text(...) usage, while leaving all other custom-tool descriptions unchanged.

    Validation on current dev:

    • custom-tool compatibility plus adjacent Responses passthrough suites: 70 passed
    • typecheck passed
    • privacy scan passed
    • diff check passed

    This PR intentionally does not implement the proposed Camel-specific first-turn tool_choice: required override. The issue should remain open for that separate provider-specific reproduction unless the shared contract repair alone resolves it.

  5. lidge-jun commented on Aug 15, 2026

    @lidge-jun
    Owner

    The shared half of this is now on dev as ea06086 (squash of #1763).

    Routed custom tools are rewritten into function tools for upstreams that do not speak the custom-tool shape, and that rewrite described every tool's input as "Raw input for this client-executed custom tool" — which told a routed model that unified exec takes a bare shell command. Codex then executed the returned string as JavaScript. exec now carries its real contract in the converted schema, and every other custom tool keeps the generic description.

    Verified on the remote validation host: 89 pass / 0 fail across tests/custom-tool-compat.test.ts, tests/openai-responses-passthrough.test.ts, tests/responses-custom-tool-repair.test.ts.

    Keeping this open. That fix teaches a model that already chose exec how to format its input; it does not address the reported first-turn behavior where Camel deepseek-v4-flash emits code-mode text instead of a structured tool call while tool_choice is "auto". That part needs raw-response evidence against current dev before we decide whether a provider-specific first-turn policy is warranted.

  6. changed the title [-][호환성] Camel DeepSeek V4 Flash에서 초기 도구 호출과 unified exec 입력이 깨짐[/-] [+][호환성] Camel DeepSeek V4 Flash 첫 도구 라운드에서 structured tool call이 누락됨[/+] on Aug 16, 2026
  7. added
    needs-infoWaiting on reporter for a concrete spec or reproduction
    on Aug 16, 2026
  8. reopened this on Aug 16, 2026
  9. changed the title [-][호환성] Camel DeepSeek V4 Flash 첫 도구 라운드에서 structured tool call이 누락됨[/-] [+][Compatibility] Camel DeepSeek V4 Flash misses structured tool call on the first tool round[/+] on Aug 16, 2026
  10. lidge-jun commented on Aug 18, 2026

    @lidge-jun
    Owner

    Status after the shared-half fix: the exec conversion defect landed on dev as ea06086 (#1763) — converted unified exec now carries its real JavaScript contract instead of the raw-input description that was teaching routed models to return bare shell strings. That mitigation is generic and applies to Camel too, but it addresses the malformed tool call shape, not this issue's remaining half: Camel DeepSeek V4 Flash still skipping the structured tool call entirely on the first tool round. The proposed Camel-specific first-turn tool_choice: required override was intentionally not implemented in #1763. So this stays open, scoped to exactly that: verify on current dev whether the first-round miss still reproduces with the corrected schema, and if it does, implement the provider-scoped first-turn tool_choice nudge (or an equivalent Camel-specific mitigation) with the raw request/response capture as the regression fixture.

  11. idguyst commented on Aug 18, 2026

    @idguyst
    Author

    Thank you for keeping this open while waiting for better evidence. I’m sorry for the confusion caused by my earlier conclusions.

    After further investigation, I found that my OpenCodex configuration was routing deepseek-v4-flash through a model-specific openai-responses override. That was not the correct Camel integration path. Camel recommends Chat Completions for agentic coding, and its supported reasoning control there is reasoning_effort.

    I corrected the configuration to use:

    {
      "adapter": "openai-chat",
      "baseUrl": "https://stream.camelai.com/v1",
      "model": "deepseek-v4-flash",
      "modelReasoningEfforts": {
        "deepseek-v4-flash": ["high"]
      },
      "preserveReasoningContentModels": ["deepseek-v4-flash"]
    }

    There is now no modelAdapters.deepseek-v4-flash = "openai-responses" override and no gateway-style reasoning object. The actual upstream request uses reasoning_effort: "high".

    Camel also fixed a server-side reasoning parser issue that had previously mixed reasoning into normal content. With the corrected Chat Completions route, I repeated the tests:

    • A direct streamed request returned progressive reasoning and then a structured tool_calls delta.
    • A full Codex/OpenCodex coding run completed 8 agent turns.
    • All 8 requests returned HTTP 200 from camel/deepseek-v4-flash; there was no provider failover.
    • Structured tool calls and tool-result continuation worked normally.
    • The model edited the target file, all 4 regression tests passed, and the agent completed successfully.

    I could no longer reproduce the remaining first-round behavior described in this issue. I also agree that my earlier 774-second figure represented accumulated time across multiple agent turns and retries, rather than one upstream TTFT.

    Based on the corrected configuration and current results, I no longer think a Camel-specific first-turn tool_choice: "required" override is warranted. Please feel free to close the remaining Camel-specific part of this issue.

    The shared unified-exec contract fix in #1763 was still valid and useful independently. Thank you for separating that confirmed defect from the provider-specific hypothesis instead of implementing the proposed hardcode without sufficient evidence.

  12. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 22 / 80

    Camel Stream의 deepseek-v4-flash가 첫 도구 라운드에서 tool_choice: "auto"일 때 구조화 tool call 대신 코드 모드 텍스트/마크업을 내는지만 남은 호환 이슈입니다. exec 입력 설명 손실은 #1763으로 dev에 들어갔고, 이 이슈 범위가 아닙니다. needs-info가 붙어 있습니다.

    현재 dev에는 stream.camelai.com 전용 하드코드가 없습니다. 프로바이더 전체 어댑터는 openai-chat이고, 해당 모델만 modelAdapters로 openai-responses를 타는 구성은 이슈 재현 JSON과 같습니다. src/adapters/openai-chat.ts에 autoToolChoiceOnlyModels가 있고, Responses 쪽 tool_choice 정규화는 src/adapters/openai-responses.ts에 있습니다. Camel 첫 라운드만 required로 올리는 정책은 코드에 없습니다.

    이슈가 요구하는 현재 dev 근거는 아직입니다. 첫 라운드 원문(편집된) 응답, 같은 카탈로그에서 tool_choice: "auto"였는지, 명시적 tool choice 대조, 도구 결과 이후 연속 턴 대조가 필요합니다. 이 없이 호스트/모델 하드코드를 넣으면 다른 프로바이더의 auto 의미를 바꿀 수 있습니다.

    해결방안: 위 네 가지 근거가 오기 전에는 구현하지 않는 편이 맞습니다. 근거가 재현되면 그때만 Camel + deepseek-v4-flash 첫 라운드에 한정된 정책을 검토하고, 명시적 tool_choice와 연속 턴, 다른 호스트는 그대로 두어야 합니다. 지금은 패치는 추측하지 않음.

    이 댓글은 grok-bot이 작성했습니다

  13. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    Closing as not planned, per the reporter's own follow-up.

    Where this landed

    The report contained two problems, and separating them turned out to matter.

    The half that was ours shipped. Converting custom tools into function tools overwrote every tool's input description with "Raw input for this client-executed custom tool." For unified exec that was actively wrong — its input is JavaScript, with shell commands invoked through tools.exec_command(...) and output returned through text(...). A routed model reasonably replied with a bare shell string, which the JavaScript evaluator then rejected. Fixed in #1763, on dev as ea0608611, and src/responses/custom-tool-compat.ts now carries the real contract for exec while leaving every other custom tool's description unchanged.

    The half that was not ours does not reproduce. @idguyst found their configuration was routing deepseek-v4-flash through a model-specific openai-responses override, while Camel recommends Chat Completions with reasoning_effort for agentic coding. On the corrected route: 8 agent turns, all HTTP 200, no failover, structured tool calls and tool-result continuation normal, file edited and regression tests green. Camel also fixed a server-side reasoning-parser issue in that window.

    Why the hardcode was not added

    The proposal was a first-round tool_choice: "required" override scoped to stream.camelai.com + deepseek-v4-flash. We asked for four pieces of evidence against current dev before touching it: a redacted raw first-response, confirmation that tool_choice: "auto" was in play for the same catalog, an explicit-choice control, and a continuation-turn control.

    That evidence never arrived because the behavior stopped happening. A hostname/model special case changes tool-selection semantics for every user of that route, and there is no public upstream contract to anchor it — so "we could not reproduce it" is the right outcome, not a missed opportunity.

    Thanks for coming back with the corrected configuration and the retraction, @idguyst. Separating a confirmed defect from a provider-specific hypothesis is what made the exec fix land cleanly on its own.

    Reopen if the first-round miss returns on the Chat Completions route with a raw capture attached.

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 workingneeds-infoWaiting on reporter for a concrete spec or reproductionproviderProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions