Skip to content

Depend on Instructor as a range and make every dependency floor true - #310

Merged
Eigenwise merged 13 commits into
mainfrom
chore/instructor-range
Oct 19, 2026
Merged

Eigenwise merged 13 commits into
mainfrom
chore/instructor-range

Conversation

@Eigenwise

@Eigenwise Eigenwise commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Targets main after the 2.12.1 release. Includes the released patch fixes and six real-Instructor transport regressions.

Why

instructor==1.14.5 was an exact pin bumped by hand since 1.9.2 (upstream 567-labs/instructor#1796: an import path removed in a patch release). Every user was stuck on whatever version we last touched. The mocked suite passed on 1.17.0 after five import renames, but a real-transport probe showed two runtime breaks the mocks hide, and testing the declared floors turned up two dishonest bounds.

What

  • instructor>=1.17.0,<2 in the root project, every example and the legacy requirements.txt; the framework references instructor.Instructor / instructor.AsyncInstructor from the package root (same classes on 1.14.5 and 1.17.0; instructor.core is not an attribute path on 1.17.0).
  • Runtime fix 1: on Instructor ≥1.15.3 the generated response-model wrapper lives in instructor.v2.core.function_calls; BaseIOSchema only exempted the two older module names from the docstring rule, so every agent.run() / run_async() raised ValueError: ... must have a non-empty docstring before the request was sent. The check now accepts any Instructor-generated class.
  • Runtime fix 2: Instructor 1.17 forwards a caller's strict into model_from_chunks; the streaming patch passed its own strict=None on top, so run_stream with model_api_parameters={"strict": True} raised "multiple values for keyword argument 'strict'". The patch now uses setdefault.
  • New tests/agents/test_instructor_transport.py drives a real Instructor client through httpx.MockTransport (run, run_async, run_stream, run_stream with strict). Without the two fixes 3 of 4 fail.
  • pydantic>=2.11.4: the MCP schema transformer passes __config__ with __base__ to create_model; allowed since pydantic 2.11.4 (pydantic#11714), 2.11.3 raises create-model-config-base. Verified on both versions.
  • mcp>=1.8.0,<2: mcp.client.streamable_http first shipped in 1.8.0; on 1.6.0 five connector test modules fail to import.
  • New CI job lowest-versions: resolves runtime deps with uv pip compile --resolution lowest-direct, installs current pytest tooling, runs the suite.
  • .release/2.13.0.md draft; codebase map updated.

Verification

Final integrated branch, after the 2.12.1 fixes:

Environment Result
Locked, Instructor 1.17.0 647 passed, 3 credential-gated skips
Minimum direct dependencies, Instructor 1.17.0, Pydantic 2.11.4, MCP 1.8.0, OpenAI 3.3.0 647 passed, 3 credential-gated skips
Real Instructor with mocked HTTP transport Six passing tests: sync/async calls, sync/async streaming, and explicit strict validation in both streaming paths
GitHub Actions Quality, clean wheel installation, and minimum-version suite pass

Black and Flake8 pass across all four directories. No live provider calls were used.

Known, not in this PR

  • max_retries counts one more attempt on 1.17: 1.14.5 used stop_after_attempt(max_retries), 1.17.0 uses stop_after_attempt(max_retries + 1). The framework never sets it; users passing it through model_api_parameters get one extra call. Noted in the 2.13.0 release notes.

  • Mode.TOOLS_STRICT (referenced in atomic_agent.py) and Mode.GENAI_TOOLS (two examples) emit DeprecationWarnings on 1.17 ("removed in v3.0"); fold into the mode-derivation work (OpenAI-compat: AtomicAgent Mode.JSON on factory and AgentConfig, not default tools mode #282/fix(agents): derive AgentConfig mode from client and warn on mismatch #293).

  • litellm <2 caps openai <3, so installs with litellm stay on openai 2.x even though Instructor 1.17 allows 3.x.

  • The streaming monkeypatch's original reason (trailing-strings partial parsing) is implemented upstream since 1.14; dropping the patch is possible but changes validation behavior and needs its own change.

🤖 Generated with Claude Code

@Eigenwise
Eigenwise changed the base branch from hotfix/2.12.1-mcp-cap to main October 18, 2026 20:07
Kenny Vaneetvelde and others added 11 commits October 18, 2026 22:07
`instructor.core.client.Instructor` relied on the submodule being
reachable as an attribute of the top-level package. Instructor 1.17.0
no longer exposes `instructor.core` that way, so attribute access
raises AttributeError, while `instructor.Instructor` and
`instructor.AsyncInstructor` are the same classes on 1.14.5 and 1.17.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The exact pin dates from 2a53b60 (instructor 1.9.2, upstream issue
567-labs/instructor#1796) and was bumped by hand ever since, which left
every user stuck on whatever version we last touched. Full suite passes
on 1.17.0 (618 passed, 3 skipped) after the client class rename in the
previous commit. Example projects and the legacy requirements.txt move
to the same range so the workspace resolves.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The MCP schema transformer passes both __config__ and __base__ to
create_model. pydantic allowed that combination in 2.11.4 (pydantic
PR #11714); 2.11.3 and below raise PydanticUserError
create-model-config-base. Resolving every direct dependency at its
declared lowest version put pydantic 2.11.0 in the environment and
failed 150 MCP tests with that error, so the old floor was never true.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The MCP connectors import mcp.client.streamable_http, which first
shipped in mcp 1.8.0 (May 2025). Resolving every direct dependency at
its declared lowest version installed mcp 1.6.0 and five connector test
modules failed to import. With mcp 1.8.0, pydantic 2.11.4, openai 2.0.0,
litellm 1.53.1 and instructor 1.17.0 the suite passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ency

Declared floors were never exercised: pydantic 2.11.0 and mcp 1.6.0
both failed the suite although pyproject allowed them. This job resolves
the runtime dependencies with uv's lowest-direct strategy, installs
current test tooling on top, and runs the suite. Locally that is
instructor 1.17.0, openai 3.3.0, pydantic 2.11.4, mcp 1.8.0,
litellm 1.53.1: 618 passed, 3 skipped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…dule

Instructor 1.15.3 moved its response-model wrapper to
instructor.v2.core.function_calls. BaseIOSchema only exempted the two
older module names from the docstring rule, so on Instructor 1.17.0
every agent.run() and run_async() raised "must have a non-empty
docstring" before the request was sent. Streaming survived because
Partial models carry from_streaming_response. The mocked suite never
saw it; a new test module drives a real Instructor client through an
httpx MockTransport and fails on the old check (3 of 4 cases).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Instructor 1.17 forwards a caller's strict setting into
model_from_chunks, and the streaming patch passed its own strict=None
on top, so run_stream with model_api_parameters={"strict": True}
raised "got multiple values for keyword argument 'strict'". The patch
now only supplies the default when the caller did not.
Covered by test_run_stream_honors_a_caller_strict_setting.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Instructor 1.14.5 used stop_after_attempt(max_retries); 1.17.0 uses
stop_after_attempt(max_retries + 1) (v2/core/retry.py:275). The
framework does not set max_retries, but the deployment and
error-handling guides pass it through model_api_parameters.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Kenny Vaneetvelde and others added 2 commits October 19, 2026 10:07
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
@Eigenwise
Eigenwise merged commit ad83278 into main Oct 19, 2026
3 checks passed
@Eigenwise Eigenwise mentioned this pull request Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant