Python: Fix Python pyright package scoping and typing remediation (#4426)

* Fix Python pyright package scoping and typing remediation

Implements issue #4407 by removing the root pyright include, adding package-level pyright includes, and resolving pyright/mypy typing issues across Python packages. Also cleans unnecessary casts and applies line-level, rule-specific ignores where external libraries are too dynamic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Reduce pyright cost in handoff cloning

Simplify cloned_options construction in HandoffAgentExecutor to avoid expensive TypedDict narrowing/inference in _handoff.py, which was causing pyright to spend a long time in orchestrations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix types

* Fix lint and type-check regressions

Resolve current Python package check failures across lint, pyright, and mypy after recent code changes, including purview/declarative pyright issues and multiple ruff simplification findings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fixed hooks

* Stabilize package tests and test tasks

Resolve cross-package non-integration test failures, simplify streaming type flow, harden locale/culture handling, and standardize package test poe tasks to exclude integration tests where applicable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* lots of small fixes

* Fix current Python test regressions

Address current failing unit tests in azure-ai, bedrock, and azure-cosmos while keeping Bedrock parsing logic inline (no new static helper methods).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* small fixes

* small fixes

* removed pydantic from json

* final updates

* fix core

* fix tests

* fix obser

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-03-05 16:32:24 +01:00
committed by GitHub
Unverified
parent 4a043c6c66
commit 55ddd841b7
122 changed files with 2328 additions and 2407 deletions
@@ -225,11 +225,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
description: str | None = None,
context_providers: Sequence[BaseContextProvider] | None = None,
middleware: Sequence[AgentMiddlewareTypes] | None = None,
tools: ToolTypes
| Callable[..., Any]
| str
| Sequence[ToolTypes | Callable[..., Any] | str]
| None = None,
tools: ToolTypes | Callable[..., Any] | str | Sequence[ToolTypes | Callable[..., Any] | str] | None = None,
default_options: OptionsT | MutableMapping[str, Any] | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
@@ -305,11 +301,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
def _normalize_tools(
self,
tools: ToolTypes
| Callable[..., Any]
| str
| Sequence[ToolTypes | Callable[..., Any] | str]
| None,
tools: ToolTypes | Callable[..., Any] | str | Sequence[ToolTypes | Callable[..., Any] | str] | None,
) -> None:
"""Separate built-in tools (strings) from custom tools.
@@ -319,21 +311,17 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
if tools is None:
return
# Normalize to sequence
if isinstance(tools, str):
tools_list: Sequence[Any] = [tools]
elif isinstance(tools, Sequence):
tools_list = list(tools)
else:
tools_list = [tools]
for tool in tools_list:
non_builtin_tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] = []
if not isinstance(tools, list):
tools = [tools] # type: ignore[assignment, reportUnknownVariableType]
for tool in tools: # type: ignore[reportUnknownVariableType]
if isinstance(tool, str):
self._builtin_tools.append(tool)
else:
# Use normalize_tools for custom tools
normalized = normalize_tools(tool)
self._custom_tools.extend(normalized)
non_builtin_tools.append(tool) # type: ignore[union-attr, reportUnknownArgumentType]
if not non_builtin_tools:
return
self._custom_tools.extend(normalize_tools(non_builtin_tools)) # type: ignore[reportUnknownVariableType]
async def __aenter__(self) -> RawClaudeAgent[OptionsT]:
"""Start the agent when entering async context."""
@@ -378,9 +366,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
session_id: The session ID to use, or None for a new session.
"""
needs_new_client = (
not self._started
or self._client is None
or (session_id and session_id != self._current_session_id)
not self._started or self._client is None or (session_id and session_id != self._current_session_id)
)
if needs_new_client:
@@ -403,9 +389,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
self._client = None
raise AgentException(f"Failed to start Claude SDK client: {ex}") from ex
def _prepare_client_options(
self, resume_session_id: str | None = None
) -> SDKOptions:
def _prepare_client_options(self, resume_session_id: str | None = None) -> SDKOptions:
"""Prepare SDK options for client initialization.
Args:
@@ -445,9 +429,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
# Prepare custom tools (FunctionTool instances)
custom_tools_server, custom_tool_names = (
self._prepare_tools(self._custom_tools)
if self._custom_tools
else (None, [])
self._prepare_tools(self._custom_tools) if self._custom_tools else (None, [])
)
# MCP servers - merge user-provided servers with custom tools server
@@ -494,13 +476,9 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
if not sdk_tools:
return None, []
return create_sdk_mcp_server(
name=TOOLS_MCP_SERVER_NAME, tools=sdk_tools
), tool_names
return create_sdk_mcp_server(name=TOOLS_MCP_SERVER_NAME, tools=sdk_tools), tool_names
def _function_tool_to_sdk_mcp_tool(
self, func_tool: FunctionTool
) -> SdkMcpTool[Any]:
def _function_tool_to_sdk_mcp_tool(self, func_tool: FunctionTool) -> SdkMcpTool[Any]:
"""Convert a FunctionTool to an SDK MCP tool.
Args:
@@ -523,9 +501,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
return {"content": [{"type": "text", "text": f"Error: {e}"}]}
# Get JSON schema from pydantic model
schema: dict[str, Any] = (
func_tool.input_model.model_json_schema() if func_tool.input_model else {}
)
schema: dict[str, Any] = func_tool.input_model.model_json_schema() if func_tool.input_model else {}
input_schema: dict[str, Any] = {
"type": "object",
"properties": schema.get("properties", {}),
@@ -586,9 +562,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
opts["instructions"] = system_prompt
return opts
def _finalize_response(
self, updates: Sequence[AgentResponseUpdate]
) -> AgentResponse[Any]:
def _finalize_response(self, updates: Sequence[AgentResponseUpdate]) -> AgentResponse[Any]:
"""Build AgentResponse and propagate structured_output as value.
Args:
@@ -627,10 +601,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
stream: bool = False,
session: AgentSession | None = None,
**kwargs: Any,
) -> (
Awaitable[AgentResponse[Any]]
| ResponseStream[AgentResponseUpdate, AgentResponse[Any]]
):
) -> Awaitable[AgentResponse[Any]] | ResponseStream[AgentResponseUpdate, AgentResponse[Any]]:
"""Run the agent with the given messages.
Args:
@@ -696,11 +667,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
if text:
yield AgentResponseUpdate(
role="assistant",
contents=[
Content.from_text(
text=text, raw_representation=message
)
],
contents=[Content.from_text(text=text, raw_representation=message)],
raw_representation=message,
)
elif delta_type == "thinking_delta":
@@ -708,11 +675,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
if thinking:
yield AgentResponseUpdate(
role="assistant",
contents=[
Content.from_text_reasoning(
text=thinking, raw_representation=message
)
],
contents=[Content.from_text_reasoning(text=thinking, raw_representation=message)],
raw_representation=message,
)
elif isinstance(message, AssistantMessage):
@@ -729,9 +692,7 @@ class RawClaudeAgent(BaseAgent, Generic[OptionsT]):
"server_error": "Claude API server error",
"unknown": "Unknown error from Claude API",
}
error_msg = error_messages.get(
message.error, f"Claude API error: {message.error}"
)
error_msg = error_messages.get(message.error, f"Claude API error: {message.error}")
# Extract any error details from content blocks
if message.content:
for block in message.content:
+2 -1
View File
@@ -61,6 +61,7 @@ omit = [
[tool.pyright]
extends = "../../pyproject.toml"
include = ["agent_framework_claude"]
exclude = ['tests']
[tool.mypy]
@@ -87,7 +88,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_claude"
test = "pytest --cov=agent_framework_claude --cov-report=term-missing:skip-covered tests"
test = "pytest -m \"not integration\" --cov=agent_framework_claude --cov-report=term-missing:skip-covered tests"
[build-system]
requires = ["flit-core >= 3.11,<4.0"]