feat: #2886 add tool_name and call_id properties to ToolCallItem and ToolCallOutputItem#2919
Conversation
… ToolCallOutputItem ToolApprovalItem already exposed these accessors; ToolCallItem and ToolCallOutputItem forced callers to write fragile getattr chains or a two-pass call_id join to correlate outputs back to their originating calls. - ToolCallItem.tool_name — extracts .name / "name" from the raw item (None for hosted tool types that carry no name field, such as computer-use or file-search). - ToolCallItem.call_id — extracts .call_id / .id / "call_id" / "id". - ToolCallOutputItem.call_id — extracts "call_id" from the raw dict payload; matches the call_id on the corresponding ToolCallItem so callers can correlate outputs to calls without a manual join. Tests cover function-call, dict-backed, and computer-call raw items, plus the end-to-end join pattern that motivated the request. Closes openai#2886
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d18198481
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if isinstance(self.raw_item, dict): | ||
| return self.raw_item.get("call_id") | ||
| return getattr(self.raw_item, "call_id", None) |
There was a problem hiding this comment.
Support id fallback in ToolCallOutputItem.call_id
ToolCallOutputItem.call_id only reads raw_item["call_id"], but the SDK already treats id as a fallback identifier for tool payloads (for example in extract_tool_call_id and output indexing logic), so id-only provider payloads are intentionally handled elsewhere. In that supported scenario, ToolCallItem.call_id resolves to id while ToolCallOutputItem.call_id resolves to None, which breaks the new convenience join path and contradicts the property’s stated correlation behavior.
Useful? React with 👍 / 👎.
Summary
ToolApprovalItemalready exposestool_nameandcall_idconvenience properties, butToolCallItemandToolCallOutputItemforce callers to write fragilegetattrchains or a two-passcall_idjoin to correlate outputs back to their originating calls.This PR adds the missing accessors:
ToolCallItem.tool_name— extracts.name/"name"from the raw item. ReturnsNonefor hosted tool types that carry no name field (e.g. computer-use, file-search).ToolCallItem.call_id— extracts.call_id/.id/"call_id"/"id", mirroring the logic already inToolApprovalItem._extract_call_id.ToolCallOutputItem.call_id— extracts"call_id"from the raw dict payload, matching thecall_idon the correspondingToolCallItemso callers can join without a second pass.Before this change, getting all outputs for a named tool required a verbose two-pass join:
After:
Test plan
Added 8 unit tests in
tests/test_items_helpers.pycovering:tool_namefromResponseFunctionToolCall(typed object)tool_namefrom a rawdicttool_namereturnsNoneforResponseComputerToolCall(no name field)call_idfromResponseFunctionToolCallcall_idfrom a raw dictToolCallOutputItem.call_idfrom a dict payloadToolCallOutputItem.call_idreturnsNonewhen absentToolCallItem+ToolCallOutputItemviacall_idVerified locally:
uv run pytest tests/test_items_helpers.py tests/test_run_internal_items.py— 53 passeduv run make lint— all checks passeduv run pyright src/agents/items.py— 0 errorsIssue number
Closes #2886
Checks
make lintandmake format