Skip to content

fix: guard None text in text_message_output and add output guardrail count to RunErrorDetails#3375

Merged
seratch merged 1 commit into
openai:mainfrom
zhoufengen:fix/text-message-output-none-and-error-details-guardrail
May 12, 2026
Merged

fix: guard None text in text_message_output and add output guardrail count to RunErrorDetails#3375
seratch merged 1 commit into
openai:mainfrom
zhoufengen:fix/text-message-output-none-and-error-details-guardrail

Conversation

@zhoufengen
Copy link
Copy Markdown
Contributor

Résumé

Two small, independent defects in the same area — both are cases where a sibling code path was already hardened but the fix was not applied consistently.

1. ItemHelpers.text_message_output crashes on None text

extract_text (line 706) already applies content_item.text or "" and carries a comment explaining why: provider gateways (e.g. LiteLLM) and model_construct paths during streaming can surface None for ResponseOutputText.text. The adjacent text_message_output (line 762) was missing the same guard, so the same TypeError: can only concatenate str (not "NoneType") to str could still be triggered through text_message_outputs and the agent.py call site.

Fix: apply item.text or "" in text_message_output, matching extract_text.

2. pretty_print_run_error_details omits output_guardrail_results

pretty_print_result and pretty_print_run_result_streaming both report both guardrail counts. pretty_print_run_error_details only reported input_guardrail_results, so RunErrorDetails.__str__() silently dropped the output guardrail line.

Fix: add the missing output_guardrail_results line.

Plan de test

  • Added tests/utils/test_pretty_print_and_items.py with 5 focused tests covering both fixes (including the None-text regression and the guardrail count assertion).
  • Updated the existing inline snapshot in tests/test_pretty_print.py to include the new output guardrail line.
  • Full suite: make format && make lint && make typecheck && make tests — all pass.

tests pass

Issue number

N/A (no prior issue filed for these two defects)

Checks

  • I've added new tests (if relevant)
  • I've added/updated the relevant documentation
  • I've run make lint and make format
  • I've made sure tests pass

…ardrail count to RunErrorDetails pretty-print

- ItemHelpers.text_message_output: apply the same `or ""` guard that
  extract_text already uses. Provider gateways (e.g. LiteLLM) and
  model_construct paths during streaming can surface None for
  ResponseOutputText.text; without the guard the concatenation raises
  TypeError.

- pretty_print_run_error_details: add the missing output_guardrail_results
  line so RunErrorDetails.__str__ is consistent with pretty_print_result
  and pretty_print_run_result_streaming, which both report both guardrail
  counts.

- Add tests/utils/test_pretty_print_and_items.py covering both fixes.
- Update the existing inline snapshot in tests/test_pretty_print.py.
@github-actions github-actions Bot added bug Something isn't working feature:core labels May 12, 2026
@seratch seratch added this to the 0.17.x milestone May 12, 2026
@seratch seratch removed the bug Something isn't working label May 12, 2026
@seratch seratch merged commit 03ff10e into openai:main May 12, 2026
10 checks passed
ioleksiuk added a commit to ioleksiuk/openai-agents-python that referenced this pull request May 14, 2026
…_text

Extends the fix in openai#3375 (`fix: guard None text in text_message_output ...`)
to the two sibling helpers in `ItemHelpers` that had the same shape.

`ResponseOutputText.text` is typed as `str` per the Responses API schema,
but `items.py:714-720` already documents that provider gateways (e.g.
LiteLLM) and `model_construct` paths during streaming surface `None`
values. PR openai#3375 fixed `text_message_output` for this case, but
`extract_last_content` (declared `-> str`, line 678) still returned
`None` when the underlying `text` was `None`, silently violating its
type contract. `extract_last_text` (declared `-> str | None`) returned
`None` only by virtue of the falsy passthrough — make that explicit so
callers can rely on truthiness semantics.

Repro for `extract_last_content`:

    >>> text_part = ResponseOutputText.model_construct(
    ...     text=None, type="output_text", annotations=[])
    >>> msg = ResponseOutputMessage(id="m", role="assistant",
    ...     status="completed", type="message", content=[text_part])
    >>> ItemHelpers.extract_last_content(msg)
    None        # but the function is typed `-> str`
ioleksiuk added a commit to ioleksiuk/openai-agents-python that referenced this pull request May 14, 2026
Extends the fix in openai#3375 (`fix: guard None text in text_message_output ...`)
to one more sibling helper that had the same `-> str` type contract.

`ResponseOutputText.text` is typed as `str` per the Responses API
schema, but `src/agents/items.py:714-720` already documents that
provider gateways (e.g. LiteLLM) and `model_construct` paths during
streaming surface `None` values. PR openai#3375 fixed `text_message_output`
for this case. `extract_last_content` (declared `-> str`,
items.py:678) silently violated its type contract by returning `None`
when `last_content.text` was `None`.

Repro:

    >>> text_part = ResponseOutputText.model_construct(
    ...     text=None, type="output_text", annotations=[])
    >>> msg = ResponseOutputMessage.model_construct(
    ...     id="m", role="assistant", status="completed",
    ...     type="message", content=[text_part])
    >>> ItemHelpers.extract_last_content(msg)
    None        # but the function is typed `-> str`

Fix mirrors the openai#3375 pattern: `return last_content.text or ""`.

Note: `extract_last_text` (declared `-> str | None`) is intentionally
left alone — `None` is already a valid return per its signature, and
coalescing `""` → `None` would silently change semantics for tools that
legitimately return empty text.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants