Skip to content

chore: release main#443

Open
stainless-app[bot] wants to merge 11 commits into
mainfrom
release-please--branches--main--changes--next
Open

chore: release main#443
stainless-app[bot] wants to merge 11 commits into
mainfrom
release-please--branches--main--changes--next

Conversation

@stainless-app

@stainless-app stainless-app Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

✨ Stainless prepared a new release

agentex-client: 0.16.0

0.16.0 (2026-06-24)

Full Changelog: agentex-client-v0.15.0...agentex-client-v0.16.0

⚠ BREAKING CHANGES

  • harness: consolidate the Pydantic-AI harness + remove tracing handler (#431)
  • harness: consolidate the LangGraph harness + remove tracing handler (#430)

Features

  • cli: add claude-code init templates (sync / async / temporal) (#435) (fd9bc4a)
  • cli: add codex init templates (sync / async / temporal) (#436) (0fadfd7)
  • cli: add default-openai-agents init template (async base) (#434) (624e9c8)
  • openai-agents: single-emit + input-bearing tool spans + run_turn (#445) (53ab8ef)
  • openai-temporal: render hosted/server-side tool calls in TemporalStreamingModel (#442) (5dce9f0)

Bug Fixes

  • cli: harden init templates per Greptile feedback (suite-wide) (#444) (2d85eb0)

Refactors

  • harness: consolidate the LangGraph harness + remove tracing handler (#430) (a3fb5ad)
  • harness: consolidate the Pydantic-AI harness + remove tracing handler (#431) (48c3da8)
  • harness: move OpenAI harness into adk/_modules + facade export (#432) (58bdb16)
agentex-sdk: 0.15.0

0.15.0 (2026-06-24)

Full Changelog: agentex-sdk-v0.14.0...agentex-sdk-v0.15.0

⚠ BREAKING CHANGES

  • harness: consolidate the LangGraph harness + remove tracing handler (#430)

Refactors

  • harness: consolidate the LangGraph harness + remove tracing handler (#430) (a3fb5ad)

This pull request is managed by Stainless's GitHub App.

The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.

For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.

🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions

Greptile Summary

This release PR (v0.16.0 / agentex-sdk v0.15.0) consolidates the LangGraph and Pydantic-AI harnesses onto UnifiedEmitter, refactors TemporalStreamingHooks with independently-switchable tool-emission flags and per-tool SGP tracing, introduces run_turn as the single Temporal entry-point for OpenAI Agents, adds hosted/server-side tool rendering in TemporalStreamingModel, and ships new CLI init templates for Claude Code and Codex (sync, async, Temporal variants).

  • run_turn + hooks refactor (run.py, hooks.py): new unified entry-point correctly wires emit_tool_requests=False with the streaming model, drains orphaned tool spans in a finally block, and cleanly separates request/response/handoff emission flags.
  • Hosted tool rendering (temporal_streaming_model.py): adds _HOSTED_TOOL_TYPES + helper functions to surface web_search, file_search, code_interpreter, mcp, computer, and local_shell calls as ToolRequest/ToolResponse pairs; one inconsistency in how ToolResponseContent.content is populated (dict vs string) compared to every other tool-response path.
  • New CLI templates (init.py, template trees): six new default-claude-code, default-codex, sync-claude-code, sync-codex, temporal-claude-code, and temporal-codex scaffolds added to the init wizard.

Confidence Score: 3/5

The run_turn / hooks refactor and LangGraph consolidation are solid, but the hosted tool response content format mismatch in TemporalStreamingModel introduces a current rendering defect for any agent using web_search, file_search, or other server-side tools in the Temporal path.

The hosted tool path wraps the ToolResponseContent result in a dict while every other tool-response emission uses a plain string — a concrete mismatch on the newly-added code path that will affect UI rendering and serialization for any Temporal agent using hosted tools.

src/agentex/lib/core/temporal/plugins/openai_agents/models/temporal_streaming_model.py — specifically the _post_tool_message call sites for hosted tools around lines 1083–1092.

Important Files Changed

Filename Overview
src/agentex/lib/core/temporal/plugins/openai_agents/models/temporal_streaming_model.py Adds hosted/server-side tool rendering (_HOSTED_TOOL_TYPES, _hosted_tool_request, _hosted_tool_result, _post_tool_message). The response content for hosted tools is inconsistently wrapped in a dict while every other ToolResponseContent path uses a plain string. Also contains a dead task_id null check inside the try block.
src/agentex/lib/core/temporal/plugins/openai_agents/run.py New file: introduces run_turn() as the unified Temporal entry-point for OpenAI Agents. Correctly wires emit_tool_requests=False with the streaming model provider, drains orphaned tool spans in a finally block, and normalizes TurnUsage off the run result.
src/agentex/lib/core/temporal/plugins/openai_agents/hooks/hooks.py Refactored TemporalStreamingHooks: independently switchable tool request/response/handoff emission, per-tool SGP tracing spans (start on on_tool_start, close on on_tool_end), and a close_open_tool_spans() drain method. Logic is clean and well-guarded.
src/agentex/lib/adk/_modules/_openai_sync.py New file: converts OpenAI Agents SDK streaming events into canonical StreamTaskMessage* events. Has previously-flagged issues (reasoning stream Done events not emitted, text index reuse, unguarded json.loads).
src/agentex/lib/adk/_modules/_langgraph_sync.py Adds emit_langgraph_messages() — a non-streaming counterpart that maps AIMessage/ToolMessage objects to Agentex content types; also removes ticket references from comments.
src/agentex/lib/cli/commands/init.py Adds six new template choices (Claude Code and Codex in sync/async/temporal flavors) to the init wizard. Missing cancel guard on the package-manager prompt (previously noted in review).

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant run_turn
    participant TemporalStreamingHooks
    participant TemporalStreamingModel
    participant Runner
    participant Tool

    Caller->>run_turn: run_turn(agent, input, task_id, ...)
    run_turn->>TemporalStreamingHooks: "new(emit_tool_requests=False, emit_tool_responses=True)"
    run_turn->>Runner: "Runner.run(agent, input, hooks=hooks)"
    Runner->>TemporalStreamingModel: get_response(...)
    TemporalStreamingModel-->>Runner: stream function_call events
    TemporalStreamingModel->>TemporalStreamingModel: emit ToolRequestContent (streaming)
    Runner->>TemporalStreamingHooks: on_tool_start() [skips request emit]
    TemporalStreamingHooks->>TemporalStreamingHooks: _maybe_start_tool_span()
    Runner->>Tool: execute tool
    Tool-->>Runner: result
    Runner->>TemporalStreamingHooks: on_tool_end(result) [emits response]
    TemporalStreamingHooks->>TemporalStreamingHooks: stream_lifecycle_content(ToolResponseContent)
    TemporalStreamingHooks->>TemporalStreamingHooks: _maybe_end_tool_span()
    Runner-->>run_turn: RunResult
    run_turn->>TemporalStreamingHooks: close_open_tool_spans() [finally]
    run_turn-->>Caller: OpenAIAgentsTurnResult(result, usage)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant run_turn
    participant TemporalStreamingHooks
    participant TemporalStreamingModel
    participant Runner
    participant Tool

    Caller->>run_turn: run_turn(agent, input, task_id, ...)
    run_turn->>TemporalStreamingHooks: "new(emit_tool_requests=False, emit_tool_responses=True)"
    run_turn->>Runner: "Runner.run(agent, input, hooks=hooks)"
    Runner->>TemporalStreamingModel: get_response(...)
    TemporalStreamingModel-->>Runner: stream function_call events
    TemporalStreamingModel->>TemporalStreamingModel: emit ToolRequestContent (streaming)
    Runner->>TemporalStreamingHooks: on_tool_start() [skips request emit]
    TemporalStreamingHooks->>TemporalStreamingHooks: _maybe_start_tool_span()
    Runner->>Tool: execute tool
    Tool-->>Runner: result
    Runner->>TemporalStreamingHooks: on_tool_end(result) [emits response]
    TemporalStreamingHooks->>TemporalStreamingHooks: stream_lifecycle_content(ToolResponseContent)
    TemporalStreamingHooks->>TemporalStreamingHooks: _maybe_end_tool_span()
    Runner-->>run_turn: RunResult
    run_turn->>TemporalStreamingHooks: close_open_tool_spans() [finally]
    run_turn-->>Caller: OpenAIAgentsTurnResult(result, usage)
Loading

Reviews (9): Last reviewed commit: "chore: release main" | Re-trigger Greptile

…g handler (#430)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing handler (#431)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 38f3e69 to c26eb73 Compare June 23, 2026 23:34
…ort (#432)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: OpenAI <openai@example.com>
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from c26eb73 to 6665513 Compare June 23, 2026 23:46
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 6665513 to beee3cc Compare June 24, 2026 00:36
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from beee3cc to d470497 Compare June 24, 2026 00:46
…435)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from d470497 to 2b2856c Compare June 24, 2026 02:08
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 2b2856c to 764d347 Compare June 24, 2026 02:16
…alStreamingModel (#442)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 764d347 to 9e9e3fa Compare June 24, 2026 02:50
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 9e9e3fa to 23bb002 Compare June 24, 2026 03:44
Comment on lines +299 to +305
if seen_tool_output:
# This is the final text message after tool execution
message_index += 1
item_id_to_index[item_id] = message_index
else:
item_id_to_index[item_id] = message_index

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Text reuses index

The first text item reuses the current message_index unless seen_tool_output is true. For a reasoning-model stream, the reasoning delta above creates an index first; when the answer text arrives with a new item_id, it is mapped to that same index. This can send two Start events with the same index, route text deltas into the still-open reasoning context, or overwrite the reasoning context in auto_send's ctx_map, leaving the reasoning message unfinalized and attaching the final answer to the wrong message. Reserve a fresh index for every new text item_id, not only after tool output, or close and advance the reasoning item before starting text.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/adk/_modules/_openai_sync.py
Line: 299-305

Comment:
**Text reuses index**

The first text item reuses the current `message_index` unless `seen_tool_output` is true. For a reasoning-model stream, the reasoning delta above creates an index first; when the answer text arrives with a new `item_id`, it is mapped to that same index. This can send two `Start` events with the same index, route text deltas into the still-open reasoning context, or overwrite the reasoning context in `auto_send`'s `ctx_map`, leaving the reasoning message unfinalized and attaching the final answer to the wrong message. Reserve a fresh index for every new text `item_id`, not only after tool output, or close and advance the reasoning item before starting text.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +178 to +184
# Don't send done events for reasoning content/summary
# They just end with their last delta
if message_type not in ("reasoning_content", "reasoning_summary"):
yield StreamTaskMessageDone(
type="done",
index=item_id_to_index[item_id],
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Reasoning streams hang

Reasoning messages are opened with StreamTaskMessageStart, but this branch skips the matching Done. UnifiedEmitter.auto_send only closes contexts on StreamTaskMessageDone; otherwise it closes them during final teardown, and SpanDeriver.flush() can mark the reasoning span incomplete. When an OpenAI reasoning or summary item is emitted through OpenAITurn(result=...), sync/yield consumers never receive a normal done event for the reasoning message. Emit StreamTaskMessageDone when a reasoning content or summary output item completes, since the accumulator already rebuilds ReasoningContent from reasoning deltas.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/adk/_modules/_openai_sync.py
Line: 178-184

Comment:
**Reasoning streams hang**

Reasoning messages are opened with `StreamTaskMessageStart`, but this branch skips the matching `Done`. `UnifiedEmitter.auto_send` only closes contexts on `StreamTaskMessageDone`; otherwise it closes them during final teardown, and `SpanDeriver.flush()` can mark the reasoning span incomplete. When an OpenAI reasoning or summary item is emitted through `OpenAITurn(result=...)`, sync/yield consumers never receive a normal done event for the reasoning message. Emit `StreamTaskMessageDone` when a reasoning content or summary output item completes, since the accumulator already rebuilds `ReasoningContent` from reasoning deltas.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +73 to +77
if tool_call_item.arguments:
if isinstance(tool_call_item.arguments, str):
import json

tool_arguments = json.loads(tool_call_item.arguments) if tool_call_item.arguments else {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Bad args abort

This json.loads() runs on the OpenAI streaming conversion path without a guard. If the Agents SDK surfaces malformed, truncated, or provider-specific raw function arguments, convert_openai_to_agentex_events / OpenAITurn.events raises and stops the whole turn before later tool output or final text can be delivered. The Temporal streaming path already catches JSONDecodeError and falls back to {}; this converter should use the same defensive parsing here and in the generic arguments branch, for example by using {} or preserving the raw string under _raw.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/adk/_modules/_openai_sync.py
Line: 73-77

Comment:
**Bad args abort**

This `json.loads()` runs on the OpenAI streaming conversion path without a guard. If the Agents SDK surfaces malformed, truncated, or provider-specific raw function arguments, `convert_openai_to_agentex_events` / `OpenAITurn.events` raises and stops the whole turn before later tool output or final text can be delivered. The Temporal streaming path already catches `JSONDecodeError` and falls back to `{}`; this converter should use the same defensive parsing here and in the generic arguments branch, for example by using `{}` or preserving the raw string under `_raw`.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 23bb002 to 063fbc8 Compare June 24, 2026 18:49
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.

1 participant