Skip to content

Conversation

@stainless-app
Copy link
Contributor

@stainless-app stainless-app bot commented Jan 13, 2026

Automated Release PR

0.3.0 (2026-02-10)

Full Changelog: v0.2.0...v0.3.0

Features

  • client: add custom JSON encoder for extended type support (30a7195)
  • client: add support for binary request streaming (48f4cca)
  • runner: dependency-aware parallel tool execution (7e6716f)
  • runner: dependency-aware parallel tool execution (#44) (a72f70f)

Bug Fixes

  • api: add byok provider model (bf52572)
  • api: default auth server (38c637a)
  • api: narrow types (3e16d98)
  • docs: fix mcp installation instructions for remote servers (e4e3619)
  • runner: allow local tool execution in mixed MCP+local scenarios (5d0ce6d)
  • runner: inject server tool results into conversation for mixed tool calls (288b70e)
  • runner: preserve thought_signature in tool call accumulation and extraction (77e5958)
  • runner: server tool results, mixed-tool execution, thought_signature passthrough (#45) (637d9b8)
  • runner: skip early break when local tools need execution alongside MCP (ad7379b)

Chores

  • api: small type fixes (2268aff)
  • ci: add missing environment (0ec49ed)
  • ci: upgrade actions/github-script (cf53a9e)
  • internal: bump dependencies (696aacf)
  • internal: update actions/checkout version (c72dfca)
  • runner: strip commented-out production version and banner comments from core.py (59350e3)

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

@stainless-app
Copy link
Contributor Author

stainless-app bot commented Jan 13, 2026

🧪 Testing

To try out this version of the SDK, run:

pip install 'https://pkg.stainless.com/s/dedalus-sdk-python/2268aff5c14821d23341baf4b65d7d7e5a26b7b7/dedalus_labs-0.2.0-py3-none-any.whl'

Expires at: Thu, 12 Mar 2026 07:53:11 GMT
Updated at: Tue, 10 Feb 2026 07:53:11 GMT

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from ac5c5d9 to c72a9be Compare January 16, 2026 18:31
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from c72a9be to 00246c5 Compare January 22, 2026 03:58
*,
cast_to: Type[ResponseT],
body: Body | None = None,
content: BinaryTypes | None = None,
Copy link

Choose a reason for hiding this comment

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

Iterator content silently lost on request retry

Medium Severity

When content is an Iterable[bytes] (like a generator), the iterator is consumed on the first request attempt. If a retryable error occurs, the retry logic uses model_copy which performs a shallow copy, so options.content still references the same exhausted iterator. Subsequent retry attempts send an empty request body. This is exacerbated by DEFAULT_MAX_RETRIES being increased from 0 to 2 in this same PR. Users passing generator-based content could experience silent data loss on transient failures.

Additional Locations (1)

Fix in Cursor Fix in Web

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 00246c5 to f4bfcf4 Compare January 23, 2026 18:15
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from f4bfcf4 to 120f4f7 Compare January 28, 2026 16:37
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 120f4f7 to b02a9df Compare February 7, 2026 10:42
@cursor
Copy link

cursor bot commented Feb 7, 2026

PR Summary

Medium Risk
Updates core HTTP request construction (JSON serialization, retries, binary streaming) and materially refactors runner tool-execution scheduling; both can affect request semantics and runtime behavior across the SDK despite being well-scoped.

Overview
Release 0.3.0 bumps package/version metadata and updates docs/CI for the new release (incl. GitHub Actions upgrades, PyPI workflow production environment, and updated MCP install links).

On the SDK side, this adds new API surfaces for OCR (POST /v1/ocr) and Responses (POST /v1/responses), wires them into the main client (including raw/streaming wrappers), and extends audio speech typing to support additional TTS model IDs and custom voices.

The HTTP client is updated to (1) support sending raw/binary request bodies via a new content parameter (sync+async, with deprecation warnings for passing bytes as body), (2) serialize JSON bodies using a new openapi_dumps encoder that handles datetime and pydantic models, and (3) change default retry behavior to 2 with increased backoff limits. The runner is refactored to forward a broader set of chat-completions parameters, preserve thought_signature during tool-call accumulation, and execute local tools via a new dependency-aware scheduler (topo-sorted, parallel per layer in async) while handling mixed MCP+local tool scenarios more robustly.

Written by Cursor Bugbot for commit 1ca826f. This will update automatically on new commits. Configure here.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from b02a9df to 3c98764 Compare February 7, 2026 11:13
[],
steps,
verbose=exec_config.verbose,
)
Copy link

Choose a reason for hiding this comment

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

Missing assistant message before tool execution in streaming paths

High Severity

Both streaming paths (_execute_streaming_async and _execute_streaming_sync) call the scheduler's execute_local_tools_async/execute_local_tools_sync without first appending an assistant message with tool_calls to the messages list. The scheduler's own docstring explicitly states the caller is responsible for this. The non-streaming paths (_execute_tool_calls at line 1204, _execute_tool_calls_sync at line 1229) correctly append {"role": "assistant", "tool_calls": ...} before calling the scheduler. The old streaming code also did this but the line was removed during the refactoring. This produces a malformed conversation (tool messages without a preceding assistant message), which will cause the API to reject subsequent requests.

Additional Locations (1)

Fix in Cursor Fix in Web

# Collect MCP tool results emitted by the server
chunk_extra = getattr(chunk, "__pydantic_extra__", None) or {}
if isinstance(chunk_extra, dict) and "mcp_tool_results" in chunk_extra:
mcp_tool_results_from_server = chunk_extra["mcp_tool_results"]
Copy link

Choose a reason for hiding this comment

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

Collected MCP tool results variable is never used

Low Severity

mcp_tool_results_from_server is assigned in both _execute_streaming_async and _execute_streaming_sync but is never read after assignment. The variable is dead code — the collected MCP tool results are silently discarded. Given the PR includes a fix for "inject server tool results into conversation for mixed tool calls," this may represent an incomplete implementation for the streaming paths.

Additional Locations (1)

Fix in Cursor Fix in Web

@cursor

This comment has been minimized.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 3c98764 to b8e048e Compare February 7, 2026 15:33
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from b8e048e to a3df0b4 Compare February 7, 2026 15:34
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from a3df0b4 to d04fc33 Compare February 9, 2026 14:37
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from d04fc33 to 2fef7e6 Compare February 10, 2026 06:32
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next branch from 2fef7e6 to 1ca826f Compare February 10, 2026 07:52
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issue.

content_chunks = 0
tool_call_chunks = 0
finish_reason = None
mcp_tool_results_from_server: list = []
Copy link

Choose a reason for hiding this comment

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

Unbound response variable when loop body never executes

Medium Severity

The newly added _extract_mcp_results(response) after the while loop in both _execute_turns_async and _execute_turns_sync references response, which is only assigned inside the loop body. If max_steps is zero or negative (allowed by the run() API and by _apply_policy override), the loop never executes, response is never bound, and this line raises an UnboundLocalError. The old code's return statement did not reference response, so this is a new crash path.

Additional Locations (1)

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Feb 10, 2026

Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.

  • ✅ Fixed: Unbound response variable when loop body never executes
    • Initialized response = None before the while loops in both _execute_turns_async and _execute_turns_sync, ensuring the variable is always bound even when max_steps <= 0.

Create PR

Or push these changes by commenting:

@cursor push 28c2d03413
Preview (28c2d03413)
diff --git a/src/dedalus_labs/lib/runner/core.py b/src/dedalus_labs/lib/runner/core.py
--- a/src/dedalus_labs/lib/runner/core.py
+++ b/src/dedalus_labs/lib/runner/core.py
@@ -508,6 +508,7 @@
         final_text = ""
         tool_results: list[ToolResult] = []
         tools_called: list[str] = []
+        response = None
 
         while steps < exec_config.max_steps:
             steps += 1
@@ -809,6 +810,7 @@
         final_text = ""
         tool_results: list[ToolResult] = []
         tools_called: list[str] = []
+        response = None
 
         while steps < exec_config.max_steps:
             steps += 1

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