Deployment mode: cloud-hosted (app.dograh.com) where observed; the responsible code is identical in the self-hosted main (api/services/pipecat/service_factory.py:972-977 as of b3bb7328).
Environment: app.dograh.com, backend v1.45.0, org on model-configurations v2
(source: "organization_v2"), BYOK mode pipeline, LLM provider openai, valid OpenAI key.
What happens
With model: gpt-5.6-luna, every turn dies silently: the user message is accepted
(rtf-user-transcription event) but no assistant reply ever follows — no error event, and
usage_info.llm stays {}. Example runs (workflow 11090): 659381, 659382, 659470.
Same workflow and config with gpt-4.1-mini: replies normally (run 659384).
Root cause
1. Where the value comes from (source, v1.45.0)
api/services/pipecat/service_factory.py:972-979:
if "gpt-5" in model:
return OpenAILLMService(
api_key=api_key,
settings=OpenAILLMSettings(
model=model,
extra={"reasoning_effort": "minimal", "verbosity": "low"},
),
**kwargs,
)
Two properties of this branch matter:
- It is a substring match on
"gpt-5", so it captures every current and future gpt-5.x
model, including gpt-5.6-luna.
- The value is hardcoded, not configurable. There is no way for an operator to override it
from the workflow or the org configuration.
2. Why the value is wrong, per OpenAI's own documentation
Two independent problems, both documented. Neither is our interpretation — these are quotes:
(a) minimal is not a supported value for these models. The model page for gpt-5.6-luna
states: "Reasoning.effort supports: none, low, medium (default), high, xhigh, and max."
(https://developers.openai.com/api/docs/models/gpt-5.6-luna.md; identical wording on
gpt-5.6-sol and gpt-5.6-terra; gpt-5.5 lists the same set minus max.) minimal survives in
the generic enum of the reasoning guide, but is absent from every current model page.
(b) Even a valid effort breaks tool calling on this endpoint. From the Responses migration
guide, section Responses benefits → Additional differences, second bullet:
Reasoning models have a richer experience in the Responses API with improved tool usage.
Starting with GPT-5.4, Chat Completions does not support tool calling with reasoning_effort
values other than none.
(https://developers.openai.com/api/docs/guides/migrate-to-responses.md) OpenAI applies this in
their own sample code on that page: the Chat Completions example that uses function tools passes
reasoning_effort: :none.
So changing "minimal" to "medium" would not fix this. On /v1/chat/completions with tools,
the only accepted value is none; anything else requires /v1/responses.
The sharpest form of the bug: medium is the documented default for gpt-5.6-luna. If
service_factory.py simply did not send the field at all, the model would fall back to
medium — which on our own bench is the best-performing setting (34/40 vs 19/40 at none).
The hardcode is strictly worse than sending nothing.
3. Confirmed on the wire
We pointed the leg's base_url at a logging relay and captured the exact upstream exchange. The
pipeline sends reasoning_effort: "minimal" together with 2 function tools to
/v1/chat/completions, and OpenAI rejects it twice over:
400 unsupported_value — gpt-5.6 models dropped "minimal"; supported values are now
none / low / medium / high / xhigh.
- After mapping minimal→low:
400 — "Function tools with reasoning_effort are not supported for
gpt-5.6-luna in /v1/chat/completions. To use function tools, use /v1/responses or set
reasoning_effort to 'none'."
With the relay rewriting reasoning_effort → "none", the same pipeline works end-to-end and the
agent replies normally (run 659477).
Note on evidence: the two quotes in §2 are OpenAI's published rules; the 400 above is our
first-hand runtime observation that those rules bite, with the model named. They corroborate each
other and are not the same kind of evidence — we keep them separate deliberately.
4. Why it is invisible
The 400 is swallowed: no error event on the run, no annotation, usage_info.llm empty. From the
operator's side it is indistinguishable from "the model decided not to answer". This is what made
the bug expensive to diagnose — several days, and it needed a proxy to see at all.
Suggested fixes
Immediate (one line): stop sending the field. Dropping reasoning_effort from the gpt-5*
branch makes each model use its own documented default (medium for the 5.6 family), which is both
valid and — on our bench — the best-performing setting. If an explicit value is preferred on
/v1/chat/completions with tools, the only accepted one is "none".
Proper: expose reasoning_effort as a configuration knob on the OpenAI LLM leg rather than a
constant. It is not a cosmetic setting: on our own bench (40 cases, same workflow, same prompt,
gpt-5.6-luna) the effort axis moved the score from 19/40 at none to 34/40 at medium.
A hardcoded value removes the single most consequential dial on the model.
Structural: the fix already exists inside your own fork, unused.
pipecat/src/pipecat/services/openai/responses/llm.py provides OpenAIResponsesLLMService with a
real reasoning.effort setting (lines 93, 126, 528), which is the documented way to combine
function tools with actual reasoning effort. As of v1.45.0 nothing under api/ imports it —
service_factory.py only ever constructs OpenAILLMService (chat/completions).
Honest caveat: we verified that the service exists in the fork and that Dograh does not use it.
We have not executed a swap, so we cannot claim it is a drop-in — the tools adapter and the
context format on the Responses path would need checking. We are flagging the asset, not
promising the patch.
Observability (independent of the above): surface upstream 4xx errors to the run as an error
event or annotation instead of a silent no-reply. Even with the effort bug fixed, any future
provider-side rejection would be equally invisible.
Adjacent findings in the same file (offered, not demanded)
While auditing v1.45.0 we noticed the same hardcoding pattern elsewhere in
api/services/pipecat/service_factory.py, which suggests a general design question rather than a
one-off:
temperature=0.1 is fixed for 7 providers (:983, :989, :998, :1005, :1012, :1020, :1052).
stability=0.8 and similarity_boost=0.75 are fixed for the ElevenLabs TTS leg (:631, :633).
- For the Deepgram Flux STT leg,
eot_timeout_ms=3000, eot_threshold=0.7 and
eager_eot_threshold=0.5 are fixed. Two of those differ from Deepgram's own documented defaults
(eot_timeout_ms 5000; eager_eot_threshold unset, i.e. eager mode off), so Dograh ships a
more aggressive turn cut-off than Deepgram's baseline and enables eager mode by default. We see
this as user-visible: it is the shape of "the agent interrupts me while I spell out a number".
We would be glad to contribute a PR that turns these into configurable fields with the current
values as defaults, so behaviour is unchanged for existing users.
Related (second issue, happy to file separately)
Per-workflow workflow_configurations model overrides (v1-style, written via PUT /workflow/{id})
persist but are ignored by the runtime once the org is on model-configurations v2 — and the legacy
PUT /api/v1/user/configurations/user returns 200 while writing nothing. If v1 config surfaces are
dead post-migration, a 4xx or a deprecation response would save integrators days of debugging.
Deployment mode: cloud-hosted (app.dograh.com) where observed; the responsible code is identical in the self-hosted
main(api/services/pipecat/service_factory.py:972-977as ofb3bb7328).Environment: app.dograh.com, backend v1.45.0, org on model-configurations v2
(
source: "organization_v2"), BYOK modepipeline, LLM provideropenai, valid OpenAI key.What happens
With
model: gpt-5.6-luna, every turn dies silently: the user message is accepted(
rtf-user-transcriptionevent) but no assistant reply ever follows — no error event, andusage_info.llmstays{}. Example runs (workflow 11090): 659381, 659382, 659470.Same workflow and config with
gpt-4.1-mini: replies normally (run 659384).Root cause
1. Where the value comes from (source, v1.45.0)
api/services/pipecat/service_factory.py:972-979:Two properties of this branch matter:
"gpt-5", so it captures every current and futuregpt-5.xmodel, including
gpt-5.6-luna.from the workflow or the org configuration.
2. Why the value is wrong, per OpenAI's own documentation
Two independent problems, both documented. Neither is our interpretation — these are quotes:
(a)
minimalis not a supported value for these models. The model page forgpt-5.6-lunastates: "Reasoning.effort supports: none, low, medium (default), high, xhigh, and max."
(https://developers.openai.com/api/docs/models/gpt-5.6-luna.md; identical wording on
gpt-5.6-solandgpt-5.6-terra;gpt-5.5lists the same set minusmax.)minimalsurvives inthe generic enum of the reasoning guide, but is absent from every current model page.
(b) Even a valid effort breaks tool calling on this endpoint. From the Responses migration
guide, section Responses benefits → Additional differences, second bullet:
(https://developers.openai.com/api/docs/guides/migrate-to-responses.md) OpenAI applies this in
their own sample code on that page: the Chat Completions example that uses function tools passes
reasoning_effort: :none.So changing
"minimal"to"medium"would not fix this. On/v1/chat/completionswith tools,the only accepted value is
none; anything else requires/v1/responses.The sharpest form of the bug:
mediumis the documented default forgpt-5.6-luna. Ifservice_factory.pysimply did not send the field at all, the model would fall back tomedium— which on our own bench is the best-performing setting (34/40 vs 19/40 atnone).The hardcode is strictly worse than sending nothing.
3. Confirmed on the wire
We pointed the leg's
base_urlat a logging relay and captured the exact upstream exchange. Thepipeline sends
reasoning_effort: "minimal"together with 2 function tools to/v1/chat/completions, and OpenAI rejects it twice over:400 unsupported_value— gpt-5.6 models dropped"minimal"; supported values are nownone/low/medium/high/xhigh.400— "Function tools with reasoning_effort are not supported forgpt-5.6-luna in /v1/chat/completions. To use function tools, use /v1/responses or set
reasoning_effort to 'none'."
With the relay rewriting
reasoning_effort→"none", the same pipeline works end-to-end and theagent replies normally (run 659477).
4. Why it is invisible
The 400 is swallowed: no error event on the run, no annotation,
usage_info.llmempty. From theoperator's side it is indistinguishable from "the model decided not to answer". This is what made
the bug expensive to diagnose — several days, and it needed a proxy to see at all.
Suggested fixes
Immediate (one line): stop sending the field. Dropping
reasoning_effortfrom thegpt-5*branch makes each model use its own documented default (
mediumfor the 5.6 family), which is bothvalid and — on our bench — the best-performing setting. If an explicit value is preferred on
/v1/chat/completionswith tools, the only accepted one is"none".Proper: expose
reasoning_effortas a configuration knob on the OpenAI LLM leg rather than aconstant. It is not a cosmetic setting: on our own bench (40 cases, same workflow, same prompt,
gpt-5.6-luna) the effort axis moved the score from 19/40 atnoneto 34/40 atmedium.A hardcoded value removes the single most consequential dial on the model.
Structural: the fix already exists inside your own fork, unused.
pipecat/src/pipecat/services/openai/responses/llm.pyprovidesOpenAIResponsesLLMServicewith areal
reasoning.effortsetting (lines 93, 126, 528), which is the documented way to combinefunction tools with actual reasoning effort. As of v1.45.0 nothing under
api/imports it —service_factory.pyonly ever constructsOpenAILLMService(chat/completions).Observability (independent of the above): surface upstream 4xx errors to the run as an error
event or annotation instead of a silent no-reply. Even with the effort bug fixed, any future
provider-side rejection would be equally invisible.
Adjacent findings in the same file (offered, not demanded)
While auditing v1.45.0 we noticed the same hardcoding pattern elsewhere in
api/services/pipecat/service_factory.py, which suggests a general design question rather than aone-off:
temperature=0.1is fixed for 7 providers (:983, :989, :998, :1005, :1012, :1020, :1052).stability=0.8andsimilarity_boost=0.75are fixed for the ElevenLabs TTS leg (:631,:633).eot_timeout_ms=3000,eot_threshold=0.7andeager_eot_threshold=0.5are fixed. Two of those differ from Deepgram's own documented defaults(
eot_timeout_ms5000;eager_eot_thresholdunset, i.e. eager mode off), so Dograh ships amore aggressive turn cut-off than Deepgram's baseline and enables eager mode by default. We see
this as user-visible: it is the shape of "the agent interrupts me while I spell out a number".
We would be glad to contribute a PR that turns these into configurable fields with the current
values as defaults, so behaviour is unchanged for existing users.
Related (second issue, happy to file separately)
Per-workflow
workflow_configurationsmodel overrides (v1-style, written viaPUT /workflow/{id})persist but are ignored by the runtime once the org is on model-configurations v2 — and the legacy
PUT /api/v1/user/configurations/userreturns 200 while writing nothing. If v1 config surfaces aredead post-migration, a 4xx or a deprecation response would save integrators days of debugging.