Skip to content

chore: release main#463

Merged
stainless-app[bot] merged 4 commits into
mainfrom
release-please--branches--main--changes--next
Jul 16, 2026
Merged

chore: release main#463
stainless-app[bot] merged 4 commits into
mainfrom
release-please--branches--main--changes--next

Conversation

@stainless-app

@stainless-app stainless-app Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

✨ Stainless prepared a new release

agentex-client: 0.20.0

0.20.0 (2026-07-16)

Full Changelog: agentex-client-v0.19.0...agentex-client-v0.20.0

Features

  • api: add interrupt task (936a2b1)
  • api: add task/interrupt method and INTERRUPTED status to agents/tasks (4f1c093)
  • interrupt: task/interrupt hook + protocol + resume-safe session capture (AGX1-391) (#462) (eaa3dd5)
agentex-sdk: 0.20.0

0.20.0 (2026-07-16)

Full Changelog: agentex-sdk-v0.19.0...agentex-sdk-v0.20.0

Chores

  • agentex-sdk: Synchronize agentex versions

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 (v0.20.0) adds a non-terminal task/interrupt verb that stops an agent's in-flight turn without tearing down the Temporal workflow, leaving the task continuable for the next message. It also ships a cooperative session-capture fix that records the CLI session ID from the early system/init (claude-code) or thread.started (codex) envelope — rather than only from the terminal result — so a turn that is interrupted before completion remains resumable.

  • Interrupt plumbing (end-to-end): New RPCMethod.TASK_INTERRUPT / InterruptTaskParams in the ACP protocol, BaseACPServer.on_task_interrupt decorator, TemporalACP handler, TemporalTaskService.interrupt() that sends an interrupt_turn signal (not cancel/terminate), and a non-abstract BaseWorkflow.on_interrupt signal handler so existing agents keep working unchanged.
  • Stream-converter cancellation safety: All five provider integrations (claude-code, codex, langgraph, openai, pydantic-ai) are refactored into a public wrapper + private impl pair; the wrapper owns a finally backstop that closes the underlying source iterator/subprocess handle when the consuming task is cancelled mid-turn.
  • Client SDK update: TasksResource.interrupt() (sync + async), INTERRUPTED added to the status Literal across Task, list/retrieve responses, and filter params; raw/streaming response wrappers wired consistently.

Confidence Score: 5/5

Safe to merge — the interrupt path is additive and non-breaking; existing agents that do not override on_interrupt continue to work via the no-op base implementation.

All changes are additive: new protocol enum value, new Pydantic model, new Temporal signal handler (non-abstract), and new SDK endpoint. The signal-vs-cancel distinction is correctly enforced throughout. Stream-converter wrappers use a well-understood try/finally aclose pattern. Session-id early-capture fallback is guarded (prefers result, falls back to init). Tests cover the protocol shape, routing, Temporal signal identity, and the non-terminal invariant. No existing behavior is modified.

No files require special attention.

Important Files Changed

Filename Overview
src/agentex/protocol/acp.py Adds RPCMethod.TASK_INTERRUPT enum value, InterruptTaskParams Pydantic model (mirrors CancelTaskParams shape), and registers it in PARAMS_MODEL_BY_METHOD — all correct and well-documented.
src/agentex/lib/core/temporal/workflows/workflow.py Adds on_interrupt as a non-abstract @workflow.signal('interrupt_turn') on BaseWorkflow; no-op base keeps existing agents valid, and the docstring accurately explains why the turn lock must not be acquired inside this handler.
src/agentex/lib/core/temporal/services/temporal_task_service.py Adds interrupt() that sends the interrupt_turn signal (non-terminally) rather than cancel/terminate — correctly preserves workflow continuability.
src/agentex/lib/adk/_modules/_claude_code_sync.py Refactors into public wrapper + private impl; wrapper owns aclose backstop; adds on_init async callback to surface session_id early from system/init envelope for interrupted-turn resumability.
src/agentex/lib/adk/_modules/_codex_sync.py Same wrapper/impl split as claude_code; on_init is synchronous (consistent with CodexTurn._on_init), called after processor.process() so processor.session_id is populated.
src/agentex/lib/adk/_modules/_claude_code_turn.py Adds _init_session_id fallback: session_id property prefers result envelope, falls back to init-captured id, enabling interrupted-before-completion turns to stay resumable.
src/agentex/lib/adk/_modules/_codex_turn.py Same early-capture pattern as ClaudeCodeTurn: _init_session_id from thread.started fallback makes interrupted codex turns resumable.
src/agentex/lib/sdk/fastacp/base/base_acp_server.py Adds on_task_interrupt decorator that registers handler under RPCMethod.TASK_INTERRUPT using _wrap_handler — consistent with on_task_cancel pattern.
src/agentex/lib/sdk/fastacp/impl/temporal_acp.py Wires handle_interrupt to forward task/interrupt to TemporalTaskService.interrupt(); null-guards _temporal_task_service consistently with handle_cancel.
src/agentex/resources/tasks.py Adds sync/async interrupt() method posting to /tasks/{task_id}/interrupt, adds INTERRUPTED to status Literal in list/retrieve endpoints, and wires raw/streaming response wrappers correctly.
tests/test_acp_interrupt.py Comprehensive unit tests covering protocol shape, ACP routing, Temporal signal wiring, and confirming interrupt sends a signal (not cancel/terminate).
tests/lib/adk/test_claude_code_turn.py New tests verify session_id preferring result over init, fallback to init on interrupted turn, and aclose propagation from wrapper to source iterator.
tests/lib/adk/test_codex_turn.py Mirrors claude_code turn tests for codex: early-capture fallback, aclose propagation on early break.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CP as Control Plane
    participant ACP as TemporalACP (FastACP)
    participant TS as TemporalTaskService
    participant TW as BaseWorkflow (Temporal)
    participant Agent as Agent on_interrupt hook

    CP->>ACP: POST /api  task/interrupt (JSON-RPC)
    ACP->>TS: interrupt(agent, task, request)
    TS->>TW: send_signal("interrupt_turn", InterruptTaskParams)
    Note over TW: Signal interleaves at await point<br/>WITHOUT acquiring turn lock
    TW->>Agent: on_interrupt(params) [override in interruptible agents]
    Agent-->>TW: stops in-flight turn (SIGINT / cancel asyncio.Task)
    Agent->>Agent: "calls tasks.interrupt(task_id) POST /tasks/{id}/interrupt"
    Note over Agent: Task status INTERRUPTED (non-terminal)
    Note over CP: Next event/message resumes task to RUNNING
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 CP as Control Plane
    participant ACP as TemporalACP (FastACP)
    participant TS as TemporalTaskService
    participant TW as BaseWorkflow (Temporal)
    participant Agent as Agent on_interrupt hook

    CP->>ACP: POST /api  task/interrupt (JSON-RPC)
    ACP->>TS: interrupt(agent, task, request)
    TS->>TW: send_signal("interrupt_turn", InterruptTaskParams)
    Note over TW: Signal interleaves at await point<br/>WITHOUT acquiring turn lock
    TW->>Agent: on_interrupt(params) [override in interruptible agents]
    Agent-->>TW: stops in-flight turn (SIGINT / cancel asyncio.Task)
    Agent->>Agent: "calls tasks.interrupt(task_id) POST /tasks/{id}/interrupt"
    Note over Agent: Task status INTERRUPTED (non-terminal)
    Note over CP: Next event/message resumes task to RUNNING
Loading

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

@stainless-app
stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 3ce2224 to ab3217e Compare July 16, 2026 19:24
@stainless-app
stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from ab3217e to 44dea4f Compare July 16, 2026 20:14
@stainless-app
stainless-app Bot merged commit 77a1316 into main Jul 16, 2026
67 checks passed
@stainless-app
stainless-app Bot deleted the release-please--branches--main--changes--next branch July 16, 2026 20:22
@stainless-app

stainless-app Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@stainless-app

stainless-app Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

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