Python: Lazy load root agent_framework exports (#6962)

* Lazy load root agent_framework exports

Move the root public API to lazy runtime exports backed by a typed stub, keep Runner deprecation handling in the owning workflow runner module, and document the maintenance pattern.

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

* Tighten harness factory typing

Add a private harness stub so create_harness_agent has a fully known public signature without depending on agent-framework-tools at runtime.

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

* Address lazy root export review comments

Harden the circular import guard and add root export smoke tests covering representative lazy imports, star imports, and root stub export synchronization.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-07-08 11:20:27 +02:00
committed by GitHub
parent 783e8c4568
commit 094d8d209a
17 changed files with 1235 additions and 369 deletions
+4
View File
@@ -4,3 +4,7 @@ applyTo: 'python/**'
See [AGENTS.md](../../AGENTS.md) for project structure and package documentation.
Detailed conventions are in the agent skills under `.github/skills/`.
When changing the public root API surface (`agent_framework/__init__.py`), keep the lazy runtime export
registry, explicit runtime `__all__`, and `agent_framework/__init__.pyi` synchronized. Runtime deprecation
behavior for a public alias should live in the owning module, not as a special case in the root package.
+9
View File
@@ -95,6 +95,15 @@ from ._agents import Agent
from ._types import Message, ChatResponse
```
Special case: the root `agent_framework/__init__.py` uses lazy runtime exports. For root public API changes:
- Add the symbol to `_LAZY_MODULE_EXPORTS` and keep `_LAZY_EXPORTS` derived from it.
- Keep the explicit runtime `__all__` synchronized; it is still required for `from agent_framework import *`.
- Add the same public symbol to `agent_framework/__init__.pyi` so pyright, mypy, and editors see the typed surface.
- Put runtime deprecation behavior in the owning module via that module's `__getattr__`; avoid root-level
special-case branches for individual deprecated exports.
- Identity aliases are appropriate in `.pyi` stubs because they mark re-exported names for type checkers; avoid them
in runtime `.py` modules unless there is a specific compatibility reason.
## Performance Guidelines
- Cache expensive computations (e.g., JSON schema generation)
@@ -73,6 +73,21 @@ uv run poe add-dependency-and-validate-bounds --package core --dependency "<depe
## Lazy Loading Pattern
### Root core API
The root `agent_framework` package is a lazy public API surface:
- Runtime exports live in `packages/core/agent_framework/__init__.py`.
- Typing/editor exports live in `packages/core/agent_framework/__init__.pyi`.
- Add or move root exports in `_LAZY_MODULE_EXPORTS`, keep the explicit runtime `__all__` in sync, and add the same
symbol to the `.pyi` file.
- Keep deprecation behavior in the owning module (for example, a module-level `__getattr__` that warns and returns
the deprecated alias). Do not add one-off deprecated-symbol branches to root `__getattr__`.
- Validate root API changes with `uv run poe syntax -P core`, `uv run poe pyright -P core`, and import smoke tests
for both `from agent_framework import <symbol>` and `from agent_framework import *`.
### Provider namespaces
Provider folders in core use `__getattr__` to lazy load from connector packages:
```python
+2
View File
@@ -69,6 +69,8 @@ python/
- `agent-framework-core` contains core abstractions and OpenAI/Azure OpenAI built-in
- Provider packages (`foundry`, `anthropic`, etc.) extend core with specific integrations
- The root `agent_framework` public API is lazy-loaded from `packages/core/agent_framework/__init__.py` and
described for type checkers in `packages/core/agent_framework/__init__.pyi`; keep both plus `__all__` in sync.
- Core uses lazy loading via `__getattr__` in provider folders (e.g., `agent_framework/azure/`)
## Package Documentation
+17 -1
View File
@@ -314,7 +314,8 @@ python/
│ │ ├── pyproject.toml # Defines [all] extra that includes all connector packages
│ │ ├── tests/ # Tests for core package
│ │ └── agent_framework/
│ │ ├── __init__.py # Public API exports
│ │ ├── __init__.py # Lazy runtime public API exports
│ │ ├── __init__.pyi # Public API typing surface for lazy root exports
│ │ ├── _agents.py # Agent implementations
│ │ ├── _clients.py # Chat client protocols and base classes
│ │ ├── _tools.py # Tool definitions
@@ -350,6 +351,17 @@ python/
### Lazy Loading Pattern
The root `agent_framework` package is a lazy public API surface. When adding, removing, or moving a root export:
- Add the symbol to `_LAZY_MODULE_EXPORTS` in `agent_framework/__init__.py`.
- Keep `_LAZY_EXPORTS` derived from `_LAZY_MODULE_EXPORTS`.
- Keep the explicit runtime `__all__` synchronized; it is required for `from agent_framework import *`.
- Add the same public symbol to `agent_framework/__init__.pyi` so type checkers and editors see the typed surface.
- Put runtime deprecation behavior in the owning module using that module's `__getattr__`. Do not add one-off
deprecated-symbol branches to root `agent_framework.__getattr__`.
- Validate root API changes with `uv run poe syntax -P core`, `uv run poe pyright -P core`, and import smoke tests
for both `from agent_framework import <symbol>` and `from agent_framework import *`.
Provider folders in the core package use `__getattr__` to lazy load classes from their respective connector packages. This allows users to import from a consistent location while only loading dependencies when needed:
```python
@@ -558,6 +570,10 @@ it should define ``__all__`` as well.
Also avoid identity alias imports in ``__init__`` files. Use ``from ._module import Symbol`` instead of
``from ._module import Symbol as Symbol``.
Exception: `.pyi` stubs that describe re-exported public APIs should use identity aliases (for example,
`from ._agents import Agent as Agent`) so type checkers recognize the symbol as exported. This applies to the
root `agent_framework/__init__.pyi`, which mirrors the lazy runtime exports from `agent_framework/__init__.py`.
```python
# ✅ Preferred - explicit __all__ and named imports
from ._agents import Agent
+13 -1
View File
@@ -6,7 +6,8 @@ The foundation package containing all core abstractions, types, and built-in Ope
```
agent_framework/
├── __init__.py # Public API exports
├── __init__.py # Lazy runtime public API exports
├── __init__.pyi # Public API typing surface for lazy root exports
├── security.py # Public security primitives, middleware, and tools
├── _agents.py # Agent implementations
├── _clients.py # Chat client base classes and protocols
@@ -24,6 +25,17 @@ agent_framework/
## Core Classes
### Root Public API (`__init__.py` / `__init__.pyi`)
- `agent_framework.__init__` uses lazy module-level `__getattr__` for most public exports to keep cold
`import agent_framework` lightweight.
- Keep `_LAZY_MODULE_EXPORTS`, `_LAZY_EXPORTS`, the explicit runtime `__all__`, and `__init__.pyi` synchronized
whenever adding, removing, or moving a root public export.
- Runtime `__all__` is still required for `from agent_framework import *`; the `.pyi` file is for type checkers
and editors and does not replace runtime exports.
- Public deprecation behavior for a lazy export belongs in the owning module. The root package should delegate via
the normal lazy export map instead of carrying one-off branches.
### Agents (`_agents.py`)
- **`SupportsAgentRun`** - Protocol defining the agent interface
+324 -328
View File
@@ -3,13 +3,19 @@
"""Public API surface for Agent Framework core.
This module exposes the primary abstractions for agents, chat clients, tools, sessions,
middleware, observability, and workflows. Connector namespaces such as
``agent_framework.azure`` and ``agent_framework.anthropic`` provide provider-specific
integrations, many of which are lazy-loaded from optional packages.
middleware, observability, and workflows. Most public exports are resolved lazily to keep
``import agent_framework`` lightweight; importing a specific symbol still loads the module
that owns that symbol.
"""
from __future__ import annotations
# pyright: reportUnsupportedDunderAll=false
# ruff: noqa: F822
import importlib
import importlib.metadata
from typing import TYPE_CHECKING, Any, Final
from collections.abc import Mapping
from typing import Any, Final
try:
_version = importlib.metadata.version(__name__)
@@ -17,196 +23,6 @@ except importlib.metadata.PackageNotFoundError:
_version = "0.0.0" # Fallback for development mode
__version__: Final[str] = _version
from ._agents import Agent, BaseAgent, RawAgent, SupportsAgentRun
from ._clients import (
BaseChatClient,
BaseEmbeddingClient,
SupportsChatGetResponse,
SupportsCodeInterpreterTool,
SupportsFileSearchTool,
SupportsGetEmbeddings,
SupportsImageGenerationTool,
SupportsMCPTool,
SupportsShellTool,
SupportsWebSearchTool,
)
from ._compaction import (
COMPACTION_STATE_KEY,
EXCLUDE_REASON_KEY,
EXCLUDED_KEY,
GROUP_ANNOTATION_KEY,
GROUP_HAS_REASONING_KEY,
GROUP_ID_KEY,
GROUP_INDEX_KEY,
GROUP_KIND_KEY,
GROUP_TOKEN_COUNT_KEY,
SUMMARIZED_BY_SUMMARY_ID_KEY,
SUMMARY_OF_GROUP_IDS_KEY,
SUMMARY_OF_MESSAGE_IDS_KEY,
CharacterEstimatorTokenizer,
CompactionProvider,
CompactionStrategy,
ContextWindowCompactionStrategy,
SelectiveToolCallCompactionStrategy,
SlidingWindowStrategy,
SummarizationStrategy,
TokenBudgetComposedStrategy,
TokenizerProtocol,
ToolResultCompactionStrategy,
TruncationStrategy,
annotate_message_groups,
apply_compaction,
included_messages,
included_token_count,
)
from ._evaluation import (
AgentEvalConverter,
CheckResult,
ConversationSplit,
ConversationSplitter,
EvalItem,
EvalItemResult,
EvalNotPassedError,
EvalResults,
EvalScoreResult,
Evaluator,
ExpectedToolCall,
LocalEvaluator,
RubricScore,
evaluate_agent,
evaluate_workflow,
evaluator,
keyword_check,
tool_call_args_match,
tool_called_check,
tool_calls_present,
)
from ._feature_stage import ExperimentalFeature, ReleaseCandidateFeature
from ._harness._agent import (
DEFAULT_HARNESS_INSTRUCTIONS,
create_harness_agent,
)
from ._harness._background_agents import (
DEFAULT_BACKGROUND_AGENTS_SOURCE_ID,
BackgroundAgentsProvider,
BackgroundTaskInfo,
BackgroundTaskStatus,
)
from ._harness._file_access import (
DEFAULT_FILE_ACCESS_INSTRUCTIONS,
DEFAULT_FILE_ACCESS_SOURCE_ID,
AgentFileStore,
FileAccessProvider,
FileSearchMatch,
FileSearchResult,
FileStoreEntry,
FileSystemAgentFileStore,
InMemoryAgentFileStore,
)
from ._harness._file_memory import (
DEFAULT_FILE_MEMORY_INSTRUCTIONS,
DEFAULT_FILE_MEMORY_SOURCE_ID,
FileMemoryProvider,
)
from ._harness._loop import (
AgentLoopMiddleware,
JudgeVerdict,
background_tasks_running,
background_tasks_running_message,
todos_remaining,
todos_remaining_message,
)
from ._harness._memory import (
DEFAULT_MEMORY_SOURCE_ID,
MemoryContextProvider,
MemoryFileStore,
MemoryIndexEntry,
MemoryStore,
MemoryTopicRecord,
)
from ._harness._mode import (
DEFAULT_MODE_SOURCE_ID,
AgentModeProvider,
get_agent_mode,
set_agent_mode,
)
from ._harness._todo import (
DEFAULT_TODO_SOURCE_ID,
TodoFileStore,
TodoInput,
TodoItem,
TodoProvider,
TodoSessionStore,
TodoStore,
)
from ._harness._tool_approval import (
DEFAULT_TOOL_APPROVAL_SOURCE_ID,
ToolApprovalMiddleware,
ToolApprovalRule,
ToolApprovalRuleCallback,
ToolApprovalState,
create_always_approve_tool_response,
create_always_approve_tool_with_arguments_response,
)
from ._mcp import MCPStdioTool, MCPStreamableHTTPTool, MCPTaskOptions, MCPWebsocketTool, SamplingApprovalCallback
from ._middleware import (
AgentContext,
AgentMiddleware,
AgentMiddlewareLayer,
AgentMiddlewareTypes,
ChatAndFunctionMiddlewareTypes,
ChatContext,
ChatMiddleware,
ChatMiddlewareLayer,
ChatMiddlewareTypes,
FunctionInvocationContext,
FunctionMiddleware,
FunctionMiddlewareTypes,
MiddlewareTermination,
MiddlewareType,
MiddlewareTypes,
agent_middleware,
chat_middleware,
function_middleware,
)
from ._sessions import (
AgentSession,
ContextProvider,
FileHistoryProvider,
HistoryProvider,
InMemoryHistoryProvider,
ServiceSessionId,
SessionContext,
register_state_type,
)
from ._settings import SecretString, load_settings
from ._skills import (
AggregatingSkillsSource,
CachingSkillsSource,
ClassSkill,
DeduplicatingSkillsSource,
DelegatingSkillsSource,
FileSkill,
FileSkillScript,
FileSkillsSource,
FilteringSkillsSource,
InlineSkill,
InlineSkillResource,
InlineSkillScript,
InMemorySkillsSource,
MCPSkill,
MCPSkillResource,
MCPSkillsSource,
Skill,
SkillFrontmatter,
SkillResource,
SkillScript,
SkillScriptArgumentParser,
SkillScriptRunner,
SkillsProvider,
SkillsSource,
SkillsSourceContext,
)
from ._telemetry import (
AGENT_FRAMEWORK_USER_AGENT,
APP_INFO,
@@ -214,128 +30,6 @@ from ._telemetry import (
USER_AGENT_TELEMETRY_DISABLED_ENV_VAR,
prepend_agent_framework_to_user_agent,
)
from ._tools import (
SKIP_PARSING,
FunctionInvocationConfiguration,
FunctionInvocationLayer,
FunctionTool,
ToolTypes,
normalize_function_invocation_configuration,
tool,
)
from ._types import (
AgentResponse,
AgentResponseUpdate,
AgentRunInputs,
Annotation,
ChatOptions,
ChatResponse,
ChatResponseUpdate,
Content,
ContinuationToken,
Embedding,
EmbeddingGenerationOptions,
EmbeddingInputT,
EmbeddingT,
FinalT,
FinishReason,
FinishReasonLiteral,
GeneratedEmbeddings,
Message,
OuterFinalT,
OuterUpdateT,
ResponseStream,
Role,
RoleLiteral,
TextSpanRegion,
ToolMode,
UpdateT,
UsageDetails,
add_usage_details,
detect_media_type_from_base64,
map_chat_to_agent_update,
merge_chat_options,
normalize_messages,
normalize_tools,
prepend_instructions_to_messages,
validate_chat_options,
validate_tool_mode,
validate_tools,
)
from ._workflows._agent import WorkflowAgent
from ._workflows._agent_executor import (
AgentExecutor,
AgentExecutorRequest,
AgentExecutorResponse,
)
from ._workflows._agent_utils import resolve_agent_id
from ._workflows._checkpoint import (
CheckpointID,
CheckpointStorage,
FileCheckpointStorage,
InMemoryCheckpointStorage,
WorkflowCheckpoint,
)
from ._workflows._const import (
DEFAULT_MAX_ITERATIONS,
)
from ._workflows._edge import (
Case,
Default,
Edge,
EdgeCondition,
FanInEdgeGroup,
FanOutEdgeGroup,
SingleEdgeGroup,
SwitchCaseEdgeGroup,
SwitchCaseEdgeGroupCase,
SwitchCaseEdgeGroupDefault,
)
from ._workflows._edge_runner import create_edge_runner
from ._workflows._events import (
WorkflowErrorDetails,
WorkflowEvent,
WorkflowEventSource,
WorkflowEventType,
WorkflowRunState,
)
from ._workflows._executor import (
Executor,
handler,
)
from ._workflows._function_executor import FunctionExecutor, executor
from ._workflows._functional import (
FunctionalWorkflow,
FunctionalWorkflowAgent,
RunContext,
StepWrapper,
get_run_context,
step,
workflow,
)
from ._workflows._request_info_mixin import response_handler
from ._workflows._runner_context import (
InProcRunnerContext,
RunnerContext,
WorkflowMessage,
)
from ._workflows._validation import (
EdgeDuplicationError,
GraphConnectivityError,
TypeCompatibilityError,
ValidationTypeEnum,
WorkflowValidationError,
validate_workflow_graph,
)
from ._workflows._viz import WorkflowViz
from ._workflows._workflow import Workflow, WorkflowRunResult
from ._workflows._workflow_builder import WorkflowBuilder
from ._workflows._workflow_context import WorkflowContext
from ._workflows._workflow_executor import (
SubWorkflowRequestMessage,
SubWorkflowResponseMessage,
WorkflowExecutor,
)
from .exceptions import (
AgentFrameworkException,
MiddlewareException,
@@ -346,6 +40,310 @@ from .exceptions import (
WorkflowRunnerException,
)
_LAZY_MODULE_EXPORTS: Final[Mapping[str, tuple[str, ...]]] = {
"._agents": ("Agent", "BaseAgent", "RawAgent", "SupportsAgentRun"),
"._clients": (
"BaseChatClient",
"BaseEmbeddingClient",
"SupportsChatGetResponse",
"SupportsCodeInterpreterTool",
"SupportsFileSearchTool",
"SupportsGetEmbeddings",
"SupportsImageGenerationTool",
"SupportsMCPTool",
"SupportsShellTool",
"SupportsWebSearchTool",
),
"._compaction": (
"COMPACTION_STATE_KEY",
"EXCLUDE_REASON_KEY",
"EXCLUDED_KEY",
"GROUP_ANNOTATION_KEY",
"GROUP_HAS_REASONING_KEY",
"GROUP_ID_KEY",
"GROUP_INDEX_KEY",
"GROUP_KIND_KEY",
"GROUP_TOKEN_COUNT_KEY",
"SUMMARIZED_BY_SUMMARY_ID_KEY",
"SUMMARY_OF_GROUP_IDS_KEY",
"SUMMARY_OF_MESSAGE_IDS_KEY",
"CharacterEstimatorTokenizer",
"CompactionProvider",
"CompactionStrategy",
"ContextWindowCompactionStrategy",
"SelectiveToolCallCompactionStrategy",
"SlidingWindowStrategy",
"SummarizationStrategy",
"TokenBudgetComposedStrategy",
"TokenizerProtocol",
"ToolResultCompactionStrategy",
"TruncationStrategy",
"annotate_message_groups",
"apply_compaction",
"included_messages",
"included_token_count",
),
"._evaluation": (
"AgentEvalConverter",
"CheckResult",
"ConversationSplit",
"ConversationSplitter",
"EvalItem",
"EvalItemResult",
"EvalNotPassedError",
"EvalResults",
"EvalScoreResult",
"Evaluator",
"ExpectedToolCall",
"LocalEvaluator",
"RubricScore",
"evaluate_agent",
"evaluate_workflow",
"evaluator",
"keyword_check",
"tool_call_args_match",
"tool_called_check",
"tool_calls_present",
),
"._feature_stage": ("ExperimentalFeature", "ReleaseCandidateFeature"),
"._harness._agent": ("DEFAULT_HARNESS_INSTRUCTIONS", "create_harness_agent"),
"._harness._background_agents": (
"DEFAULT_BACKGROUND_AGENTS_SOURCE_ID",
"BackgroundAgentsProvider",
"BackgroundTaskInfo",
"BackgroundTaskStatus",
),
"._harness._file_access": (
"DEFAULT_FILE_ACCESS_INSTRUCTIONS",
"DEFAULT_FILE_ACCESS_SOURCE_ID",
"AgentFileStore",
"FileAccessProvider",
"FileSearchMatch",
"FileSearchResult",
"FileStoreEntry",
"FileSystemAgentFileStore",
"InMemoryAgentFileStore",
),
"._harness._file_memory": (
"DEFAULT_FILE_MEMORY_INSTRUCTIONS",
"DEFAULT_FILE_MEMORY_SOURCE_ID",
"FileMemoryProvider",
),
"._harness._loop": (
"AgentLoopMiddleware",
"JudgeVerdict",
"background_tasks_running",
"background_tasks_running_message",
"todos_remaining",
"todos_remaining_message",
),
"._harness._memory": (
"DEFAULT_MEMORY_SOURCE_ID",
"MemoryContextProvider",
"MemoryFileStore",
"MemoryIndexEntry",
"MemoryStore",
"MemoryTopicRecord",
),
"._harness._mode": ("DEFAULT_MODE_SOURCE_ID", "AgentModeProvider", "get_agent_mode", "set_agent_mode"),
"._harness._todo": (
"DEFAULT_TODO_SOURCE_ID",
"TodoFileStore",
"TodoInput",
"TodoItem",
"TodoProvider",
"TodoSessionStore",
"TodoStore",
),
"._harness._tool_approval": (
"DEFAULT_TOOL_APPROVAL_SOURCE_ID",
"ToolApprovalMiddleware",
"ToolApprovalRule",
"ToolApprovalRuleCallback",
"ToolApprovalState",
"create_always_approve_tool_response",
"create_always_approve_tool_with_arguments_response",
),
"._mcp": (
"MCPStdioTool",
"MCPStreamableHTTPTool",
"MCPTaskOptions",
"MCPWebsocketTool",
"SamplingApprovalCallback",
),
"._middleware": (
"AgentContext",
"AgentMiddleware",
"AgentMiddlewareLayer",
"AgentMiddlewareTypes",
"ChatAndFunctionMiddlewareTypes",
"ChatContext",
"ChatMiddleware",
"ChatMiddlewareLayer",
"ChatMiddlewareTypes",
"FunctionInvocationContext",
"FunctionMiddleware",
"FunctionMiddlewareTypes",
"MiddlewareTermination",
"MiddlewareType",
"MiddlewareTypes",
"agent_middleware",
"chat_middleware",
"function_middleware",
),
"._sessions": (
"AgentSession",
"ContextProvider",
"FileHistoryProvider",
"HistoryProvider",
"InMemoryHistoryProvider",
"ServiceSessionId",
"SessionContext",
"register_state_type",
),
"._settings": ("SecretString", "load_settings"),
"._skills": (
"AggregatingSkillsSource",
"CachingSkillsSource",
"ClassSkill",
"DeduplicatingSkillsSource",
"DelegatingSkillsSource",
"FileSkill",
"FileSkillScript",
"FileSkillsSource",
"FilteringSkillsSource",
"InlineSkill",
"InlineSkillResource",
"InlineSkillScript",
"InMemorySkillsSource",
"MCPSkill",
"MCPSkillResource",
"MCPSkillsSource",
"Skill",
"SkillFrontmatter",
"SkillResource",
"SkillScript",
"SkillScriptArgumentParser",
"SkillScriptRunner",
"SkillsProvider",
"SkillsSource",
"SkillsSourceContext",
),
"._tools": (
"SKIP_PARSING",
"FunctionInvocationConfiguration",
"FunctionInvocationLayer",
"FunctionTool",
"ToolTypes",
"normalize_function_invocation_configuration",
"tool",
),
"._types": (
"AgentResponse",
"AgentResponseUpdate",
"AgentRunInputs",
"Annotation",
"ChatOptions",
"ChatResponse",
"ChatResponseUpdate",
"Content",
"ContinuationToken",
"Embedding",
"EmbeddingGenerationOptions",
"EmbeddingInputT",
"EmbeddingT",
"FinalT",
"FinishReason",
"FinishReasonLiteral",
"GeneratedEmbeddings",
"Message",
"OuterFinalT",
"OuterUpdateT",
"ResponseStream",
"Role",
"RoleLiteral",
"TextSpanRegion",
"ToolMode",
"UpdateT",
"UsageDetails",
"add_usage_details",
"detect_media_type_from_base64",
"map_chat_to_agent_update",
"merge_chat_options",
"normalize_messages",
"normalize_tools",
"prepend_instructions_to_messages",
"validate_chat_options",
"validate_tool_mode",
"validate_tools",
),
"._workflows._agent": ("WorkflowAgent",),
"._workflows._agent_executor": ("AgentExecutor", "AgentExecutorRequest", "AgentExecutorResponse"),
"._workflows._agent_utils": ("resolve_agent_id",),
"._workflows._checkpoint": (
"CheckpointID",
"CheckpointStorage",
"FileCheckpointStorage",
"InMemoryCheckpointStorage",
"WorkflowCheckpoint",
),
"._workflows._const": ("DEFAULT_MAX_ITERATIONS",),
"._workflows._edge": (
"Case",
"Default",
"Edge",
"EdgeCondition",
"FanInEdgeGroup",
"FanOutEdgeGroup",
"SingleEdgeGroup",
"SwitchCaseEdgeGroup",
"SwitchCaseEdgeGroupCase",
"SwitchCaseEdgeGroupDefault",
),
"._workflows._edge_runner": ("create_edge_runner",),
"._workflows._events": (
"WorkflowErrorDetails",
"WorkflowEvent",
"WorkflowEventSource",
"WorkflowEventType",
"WorkflowRunState",
),
"._workflows._executor": ("Executor", "handler"),
"._workflows._function_executor": ("FunctionExecutor", "executor"),
"._workflows._functional": (
"FunctionalWorkflow",
"FunctionalWorkflowAgent",
"RunContext",
"StepWrapper",
"get_run_context",
"step",
"workflow",
),
"._workflows._request_info_mixin": ("response_handler",),
"._workflows._runner": ("Runner",),
"._workflows._runner_context": ("InProcRunnerContext", "RunnerContext", "WorkflowMessage"),
"._workflows._validation": (
"EdgeDuplicationError",
"GraphConnectivityError",
"TypeCompatibilityError",
"ValidationTypeEnum",
"WorkflowValidationError",
"validate_workflow_graph",
),
"._workflows._viz": ("WorkflowViz",),
"._workflows._workflow": ("Workflow", "WorkflowRunResult"),
"._workflows._workflow_builder": ("WorkflowBuilder",),
"._workflows._workflow_context": ("WorkflowContext",),
"._workflows._workflow_executor": (
"SubWorkflowRequestMessage",
"SubWorkflowResponseMessage",
"WorkflowExecutor",
),
}
_LAZY_EXPORTS: Final[dict[str, str]] = {
name: module_name for module_name, names in _LAZY_MODULE_EXPORTS.items() for name in names
}
__all__ = [
"AGENT_FRAMEWORK_USER_AGENT",
"APP_INFO",
@@ -632,19 +630,17 @@ __all__ = [
"workflow",
]
if TYPE_CHECKING:
from ._workflows._runner import Runner
def __getattr__(name: str) -> Any:
"""Lazily resolve deprecated public names, emitting a ``DeprecationWarning``.
"""Lazily resolve public names exported from ``agent_framework``."""
if module_name := _LAZY_EXPORTS.get(name):
value = getattr(importlib.import_module(module_name, __name__), name)
globals()[name] = value
return value
``Runner`` remains importable from ``agent_framework`` for backward
compatibility but is deprecated and slated for removal from the public API.
"""
if name == "Runner":
from ._workflows._runner import Runner, warn_runner_deprecated
warn_runner_deprecated()
return Runner
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
def __dir__() -> list[str]:
"""Return public names for interactive discovery."""
return sorted(set(globals()) | set(__all__))
@@ -0,0 +1,598 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Final
__version__: Final[str]
from ._agents import Agent, BaseAgent, RawAgent, SupportsAgentRun
from ._clients import (
BaseChatClient,
BaseEmbeddingClient,
SupportsChatGetResponse,
SupportsCodeInterpreterTool,
SupportsFileSearchTool,
SupportsGetEmbeddings,
SupportsImageGenerationTool,
SupportsMCPTool,
SupportsShellTool,
SupportsWebSearchTool,
)
from ._compaction import (
COMPACTION_STATE_KEY,
EXCLUDE_REASON_KEY,
EXCLUDED_KEY,
GROUP_ANNOTATION_KEY,
GROUP_HAS_REASONING_KEY,
GROUP_ID_KEY,
GROUP_INDEX_KEY,
GROUP_KIND_KEY,
GROUP_TOKEN_COUNT_KEY,
SUMMARIZED_BY_SUMMARY_ID_KEY,
SUMMARY_OF_GROUP_IDS_KEY,
SUMMARY_OF_MESSAGE_IDS_KEY,
CharacterEstimatorTokenizer,
CompactionProvider,
CompactionStrategy,
ContextWindowCompactionStrategy,
SelectiveToolCallCompactionStrategy,
SlidingWindowStrategy,
SummarizationStrategy,
TokenBudgetComposedStrategy,
TokenizerProtocol,
ToolResultCompactionStrategy,
TruncationStrategy,
annotate_message_groups,
apply_compaction,
included_messages,
included_token_count,
)
from ._evaluation import (
AgentEvalConverter,
CheckResult,
ConversationSplit,
ConversationSplitter,
EvalItem,
EvalItemResult,
EvalNotPassedError,
EvalResults,
EvalScoreResult,
Evaluator,
ExpectedToolCall,
LocalEvaluator,
RubricScore,
evaluate_agent,
evaluate_workflow,
evaluator,
keyword_check,
tool_call_args_match,
tool_called_check,
tool_calls_present,
)
from ._feature_stage import ExperimentalFeature, ReleaseCandidateFeature
from ._harness._agent import DEFAULT_HARNESS_INSTRUCTIONS, create_harness_agent
from ._harness._background_agents import (
DEFAULT_BACKGROUND_AGENTS_SOURCE_ID,
BackgroundAgentsProvider,
BackgroundTaskInfo,
BackgroundTaskStatus,
)
from ._harness._file_access import (
DEFAULT_FILE_ACCESS_INSTRUCTIONS,
DEFAULT_FILE_ACCESS_SOURCE_ID,
AgentFileStore,
FileAccessProvider,
FileSearchMatch,
FileSearchResult,
FileStoreEntry,
FileSystemAgentFileStore,
InMemoryAgentFileStore,
)
from ._harness._file_memory import DEFAULT_FILE_MEMORY_INSTRUCTIONS, DEFAULT_FILE_MEMORY_SOURCE_ID, FileMemoryProvider
from ._harness._loop import (
AgentLoopMiddleware,
JudgeVerdict,
background_tasks_running,
background_tasks_running_message,
todos_remaining,
todos_remaining_message,
)
from ._harness._memory import (
DEFAULT_MEMORY_SOURCE_ID,
MemoryContextProvider,
MemoryFileStore,
MemoryIndexEntry,
MemoryStore,
MemoryTopicRecord,
)
from ._harness._mode import DEFAULT_MODE_SOURCE_ID, AgentModeProvider, get_agent_mode, set_agent_mode
from ._harness._todo import (
DEFAULT_TODO_SOURCE_ID,
TodoFileStore,
TodoInput,
TodoItem,
TodoProvider,
TodoSessionStore,
TodoStore,
)
from ._harness._tool_approval import (
DEFAULT_TOOL_APPROVAL_SOURCE_ID,
ToolApprovalMiddleware,
ToolApprovalRule,
ToolApprovalRuleCallback,
ToolApprovalState,
create_always_approve_tool_response,
create_always_approve_tool_with_arguments_response,
)
from ._mcp import (
MCPStdioTool,
MCPStreamableHTTPTool,
MCPTaskOptions,
MCPWebsocketTool,
SamplingApprovalCallback,
)
from ._middleware import (
AgentContext,
AgentMiddleware,
AgentMiddlewareLayer,
AgentMiddlewareTypes,
ChatAndFunctionMiddlewareTypes,
ChatContext,
ChatMiddleware,
ChatMiddlewareLayer,
ChatMiddlewareTypes,
FunctionInvocationContext,
FunctionMiddleware,
FunctionMiddlewareTypes,
MiddlewareTermination,
MiddlewareType,
MiddlewareTypes,
agent_middleware,
chat_middleware,
function_middleware,
)
from ._sessions import (
AgentSession,
ContextProvider,
FileHistoryProvider,
HistoryProvider,
InMemoryHistoryProvider,
ServiceSessionId,
SessionContext,
register_state_type,
)
from ._settings import SecretString, load_settings
from ._skills import (
AggregatingSkillsSource,
CachingSkillsSource,
ClassSkill,
DeduplicatingSkillsSource,
DelegatingSkillsSource,
FileSkill,
FileSkillScript,
FileSkillsSource,
FilteringSkillsSource,
InlineSkill,
InlineSkillResource,
InlineSkillScript,
InMemorySkillsSource,
MCPSkill,
MCPSkillResource,
MCPSkillsSource,
Skill,
SkillFrontmatter,
SkillResource,
SkillScript,
SkillScriptArgumentParser,
SkillScriptRunner,
SkillsProvider,
SkillsSource,
SkillsSourceContext,
)
from ._telemetry import (
AGENT_FRAMEWORK_USER_AGENT,
APP_INFO,
USER_AGENT_KEY,
USER_AGENT_TELEMETRY_DISABLED_ENV_VAR,
prepend_agent_framework_to_user_agent,
)
from ._tools import (
SKIP_PARSING,
FunctionInvocationConfiguration,
FunctionInvocationLayer,
FunctionTool,
ToolTypes,
normalize_function_invocation_configuration,
tool,
)
from ._types import (
AgentResponse,
AgentResponseUpdate,
AgentRunInputs,
Annotation,
ChatOptions,
ChatResponse,
ChatResponseUpdate,
Content,
ContinuationToken,
Embedding,
EmbeddingGenerationOptions,
EmbeddingInputT,
EmbeddingT,
FinalT,
FinishReason,
FinishReasonLiteral,
GeneratedEmbeddings,
Message,
OuterFinalT,
OuterUpdateT,
ResponseStream,
Role,
RoleLiteral,
TextSpanRegion,
ToolMode,
UpdateT,
UsageDetails,
add_usage_details,
detect_media_type_from_base64,
map_chat_to_agent_update,
merge_chat_options,
normalize_messages,
normalize_tools,
prepend_instructions_to_messages,
validate_chat_options,
validate_tool_mode,
validate_tools,
)
from ._workflows._agent import WorkflowAgent
from ._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from ._workflows._agent_utils import resolve_agent_id
from ._workflows._checkpoint import (
CheckpointID,
CheckpointStorage,
FileCheckpointStorage,
InMemoryCheckpointStorage,
WorkflowCheckpoint,
)
from ._workflows._const import DEFAULT_MAX_ITERATIONS
from ._workflows._edge import (
Case,
Default,
Edge,
EdgeCondition,
FanInEdgeGroup,
FanOutEdgeGroup,
SingleEdgeGroup,
SwitchCaseEdgeGroup,
SwitchCaseEdgeGroupCase,
SwitchCaseEdgeGroupDefault,
)
from ._workflows._edge_runner import create_edge_runner
from ._workflows._events import (
WorkflowErrorDetails,
WorkflowEvent,
WorkflowEventSource,
WorkflowEventType,
WorkflowRunState,
)
from ._workflows._executor import Executor, handler
from ._workflows._function_executor import FunctionExecutor, executor
from ._workflows._functional import (
FunctionalWorkflow,
FunctionalWorkflowAgent,
RunContext,
StepWrapper,
get_run_context,
step,
workflow,
)
from ._workflows._request_info_mixin import response_handler
from ._workflows._runner import Runner
from ._workflows._runner_context import InProcRunnerContext, RunnerContext, WorkflowMessage
from ._workflows._validation import (
EdgeDuplicationError,
GraphConnectivityError,
TypeCompatibilityError,
ValidationTypeEnum,
WorkflowValidationError,
validate_workflow_graph,
)
from ._workflows._viz import WorkflowViz
from ._workflows._workflow import Workflow, WorkflowRunResult
from ._workflows._workflow_builder import WorkflowBuilder
from ._workflows._workflow_context import WorkflowContext
from ._workflows._workflow_executor import SubWorkflowRequestMessage, SubWorkflowResponseMessage, WorkflowExecutor
from .exceptions import (
AgentFrameworkException,
MiddlewareException,
UserInputRequiredException,
WorkflowCheckpointException,
WorkflowConvergenceException,
WorkflowException,
WorkflowRunnerException,
)
__all__ = [
"AGENT_FRAMEWORK_USER_AGENT",
"APP_INFO",
"COMPACTION_STATE_KEY",
"DEFAULT_BACKGROUND_AGENTS_SOURCE_ID",
"DEFAULT_FILE_ACCESS_INSTRUCTIONS",
"DEFAULT_FILE_ACCESS_SOURCE_ID",
"DEFAULT_FILE_MEMORY_INSTRUCTIONS",
"DEFAULT_FILE_MEMORY_SOURCE_ID",
"DEFAULT_HARNESS_INSTRUCTIONS",
"DEFAULT_MAX_ITERATIONS",
"DEFAULT_MEMORY_SOURCE_ID",
"DEFAULT_MODE_SOURCE_ID",
"DEFAULT_TODO_SOURCE_ID",
"DEFAULT_TOOL_APPROVAL_SOURCE_ID",
"EXCLUDED_KEY",
"EXCLUDE_REASON_KEY",
"GROUP_ANNOTATION_KEY",
"GROUP_HAS_REASONING_KEY",
"GROUP_ID_KEY",
"GROUP_INDEX_KEY",
"GROUP_KIND_KEY",
"GROUP_TOKEN_COUNT_KEY",
"SKIP_PARSING",
"SUMMARIZED_BY_SUMMARY_ID_KEY",
"SUMMARY_OF_GROUP_IDS_KEY",
"SUMMARY_OF_MESSAGE_IDS_KEY",
"USER_AGENT_KEY",
"USER_AGENT_TELEMETRY_DISABLED_ENV_VAR",
"Agent",
"AgentContext",
"AgentEvalConverter",
"AgentExecutor",
"AgentExecutorRequest",
"AgentExecutorResponse",
"AgentFileStore",
"AgentFrameworkException",
"AgentLoopMiddleware",
"AgentMiddleware",
"AgentMiddlewareLayer",
"AgentMiddlewareTypes",
"AgentModeProvider",
"AgentResponse",
"AgentResponseUpdate",
"AgentRunInputs",
"AgentSession",
"AggregatingSkillsSource",
"Annotation",
"BackgroundAgentsProvider",
"BackgroundTaskInfo",
"BackgroundTaskStatus",
"BaseAgent",
"BaseChatClient",
"BaseEmbeddingClient",
"CachingSkillsSource",
"Case",
"CharacterEstimatorTokenizer",
"ChatAndFunctionMiddlewareTypes",
"ChatContext",
"ChatMiddleware",
"ChatMiddlewareLayer",
"ChatMiddlewareTypes",
"ChatOptions",
"ChatResponse",
"ChatResponseUpdate",
"CheckResult",
"CheckpointID",
"CheckpointStorage",
"ClassSkill",
"CompactionProvider",
"CompactionStrategy",
"Content",
"ContextProvider",
"ContextWindowCompactionStrategy",
"ContinuationToken",
"ConversationSplit",
"ConversationSplitter",
"DeduplicatingSkillsSource",
"Default",
"DelegatingSkillsSource",
"Edge",
"EdgeCondition",
"EdgeDuplicationError",
"Embedding",
"EmbeddingGenerationOptions",
"EmbeddingInputT",
"EmbeddingT",
"EvalItem",
"EvalItemResult",
"EvalNotPassedError",
"EvalResults",
"EvalScoreResult",
"Evaluator",
"Executor",
"ExpectedToolCall",
"ExperimentalFeature",
"FanInEdgeGroup",
"FanOutEdgeGroup",
"FileAccessProvider",
"FileCheckpointStorage",
"FileHistoryProvider",
"FileMemoryProvider",
"FileSearchMatch",
"FileSearchResult",
"FileSkill",
"FileSkillScript",
"FileSkillsSource",
"FileStoreEntry",
"FileSystemAgentFileStore",
"FilteringSkillsSource",
"FinalT",
"FinishReason",
"FinishReasonLiteral",
"FunctionExecutor",
"FunctionInvocationConfiguration",
"FunctionInvocationContext",
"FunctionInvocationLayer",
"FunctionMiddleware",
"FunctionMiddlewareTypes",
"FunctionTool",
"FunctionalWorkflow",
"FunctionalWorkflowAgent",
"GeneratedEmbeddings",
"GraphConnectivityError",
"HistoryProvider",
"InMemoryAgentFileStore",
"InMemoryCheckpointStorage",
"InMemoryHistoryProvider",
"InMemorySkillsSource",
"InProcRunnerContext",
"InlineSkill",
"InlineSkillResource",
"InlineSkillScript",
"JudgeVerdict",
"LocalEvaluator",
"MCPSkill",
"MCPSkillResource",
"MCPSkillsSource",
"MCPStdioTool",
"MCPStreamableHTTPTool",
"MCPTaskOptions",
"MCPWebsocketTool",
"MemoryContextProvider",
"MemoryFileStore",
"MemoryIndexEntry",
"MemoryStore",
"MemoryTopicRecord",
"Message",
"MiddlewareException",
"MiddlewareTermination",
"MiddlewareType",
"MiddlewareTypes",
"OuterFinalT",
"OuterUpdateT",
"RawAgent",
"ReleaseCandidateFeature",
"ResponseStream",
"Role",
"RoleLiteral",
"RubricScore",
"RunContext",
"Runner",
"RunnerContext",
"SamplingApprovalCallback",
"SecretString",
"SelectiveToolCallCompactionStrategy",
"ServiceSessionId",
"SessionContext",
"SingleEdgeGroup",
"Skill",
"SkillFrontmatter",
"SkillResource",
"SkillScript",
"SkillScriptArgumentParser",
"SkillScriptRunner",
"SkillsProvider",
"SkillsSource",
"SkillsSourceContext",
"SlidingWindowStrategy",
"StepWrapper",
"SubWorkflowRequestMessage",
"SubWorkflowResponseMessage",
"SummarizationStrategy",
"SupportsAgentRun",
"SupportsChatGetResponse",
"SupportsCodeInterpreterTool",
"SupportsFileSearchTool",
"SupportsGetEmbeddings",
"SupportsImageGenerationTool",
"SupportsMCPTool",
"SupportsShellTool",
"SupportsWebSearchTool",
"SwitchCaseEdgeGroup",
"SwitchCaseEdgeGroupCase",
"SwitchCaseEdgeGroupDefault",
"TextSpanRegion",
"TodoFileStore",
"TodoInput",
"TodoItem",
"TodoProvider",
"TodoSessionStore",
"TodoStore",
"TokenBudgetComposedStrategy",
"TokenizerProtocol",
"ToolApprovalMiddleware",
"ToolApprovalRule",
"ToolApprovalRuleCallback",
"ToolApprovalState",
"ToolMode",
"ToolResultCompactionStrategy",
"ToolTypes",
"TruncationStrategy",
"TypeCompatibilityError",
"UpdateT",
"UsageDetails",
"UserInputRequiredException",
"ValidationTypeEnum",
"Workflow",
"WorkflowAgent",
"WorkflowBuilder",
"WorkflowCheckpoint",
"WorkflowCheckpointException",
"WorkflowContext",
"WorkflowConvergenceException",
"WorkflowErrorDetails",
"WorkflowEvent",
"WorkflowEventSource",
"WorkflowEventType",
"WorkflowException",
"WorkflowExecutor",
"WorkflowMessage",
"WorkflowRunResult",
"WorkflowRunState",
"WorkflowRunnerException",
"WorkflowValidationError",
"WorkflowViz",
"__version__",
"add_usage_details",
"agent_middleware",
"annotate_message_groups",
"apply_compaction",
"background_tasks_running",
"background_tasks_running_message",
"chat_middleware",
"create_always_approve_tool_response",
"create_always_approve_tool_with_arguments_response",
"create_edge_runner",
"create_harness_agent",
"detect_media_type_from_base64",
"evaluate_agent",
"evaluate_workflow",
"evaluator",
"executor",
"function_middleware",
"get_agent_mode",
"get_run_context",
"handler",
"included_messages",
"included_token_count",
"keyword_check",
"load_settings",
"map_chat_to_agent_update",
"merge_chat_options",
"normalize_function_invocation_configuration",
"normalize_messages",
"normalize_tools",
"prepend_agent_framework_to_user_agent",
"prepend_instructions_to_messages",
"register_state_type",
"resolve_agent_id",
"response_handler",
"set_agent_mode",
"step",
"todos_remaining",
"todos_remaining_message",
"tool",
"tool_call_args_match",
"tool_called_check",
"tool_calls_present",
"validate_chat_options",
"validate_tool_mode",
"validate_tools",
"validate_workflow_graph",
"workflow",
]
+49 -18
View File
@@ -23,12 +23,8 @@ from typing import (
)
from uuid import uuid4
from pydantic import BaseModel
from . import _tools as _tool_utils # pyright: ignore[reportPrivateUsage]
from ._clients import BaseChatClient, SupportsChatGetResponse
from ._docstrings import apply_layered_docstring
from ._mcp import LOG_LEVEL_MAPPING, MCPTool
from ._middleware import AgentMiddlewareLayer, FunctionInvocationContext, MiddlewareTypes, categorize_middleware
from ._serialization import SerializationMixin
from ._sessions import (
@@ -41,7 +37,6 @@ from ._sessions import (
SessionContext,
is_local_history_conversation_id,
)
from ._tools import FunctionInvocationLayer, FunctionTool, ToolTypes, normalize_tools
from ._types import (
AgentResponse,
AgentResponseUpdate,
@@ -61,10 +56,6 @@ if sys.version_info >= (3, 13):
from typing import TypeVar # pragma: no cover
else:
from typing_extensions import TypeVar # pragma: no cover
if sys.version_info >= (3, 12):
pass
else:
pass # pragma: no cover
if sys.version_info >= (3, 11):
from typing import Self, TypedDict # pragma: no cover
else:
@@ -73,16 +64,19 @@ else:
if TYPE_CHECKING:
from mcp import types
from mcp.server.lowlevel import Server
from pydantic import BaseModel
from ._compaction import CompactionStrategy, TokenizerProtocol
from ._mcp import MCPTool
from ._tools import FunctionTool, ToolTypes
from ._types import ChatOptions
logger = logging.getLogger("agent_framework")
_append_unique_tools = _tool_utils._append_unique_tools # pyright: ignore[reportPrivateUsage]
_get_tool_name = _tool_utils._get_tool_name # pyright: ignore[reportPrivateUsage]
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
if TYPE_CHECKING:
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
else:
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=Any)
OptionsCoT = TypeVar(
"OptionsCoT",
bound=TypedDict, # type: ignore[valid-type]
@@ -91,6 +85,35 @@ OptionsCoT = TypeVar(
)
def _append_unique_tools(
existing_tools: list[ToolTypes],
new_tools: Sequence[ToolTypes],
*,
duplicate_error_message: str | None = None,
) -> list[ToolTypes]:
from ._tools import _append_unique_tools as append_unique_tools # pyright: ignore[reportPrivateUsage]
return append_unique_tools(
existing_tools,
new_tools,
duplicate_error_message=duplicate_error_message,
)
def _normalize_tools(
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
) -> list[ToolTypes]:
from ._tools import normalize_tools
return normalize_tools(tools)
def _get_tool_name(tool: Any) -> str | None: # pyright: ignore[reportUnusedFunction]
from ._tools import _get_tool_name as get_tool_name # pyright: ignore[reportPrivateUsage]
return get_tool_name(tool)
def _merge_options(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
"""Merge two options dicts, with override values taking precedence.
@@ -111,8 +134,8 @@ def _merge_options(base: dict[str, Any], override: dict[str, Any]) -> dict[str,
if value is None:
continue
if key == "tools" and (result.get("tools") or value):
base_tools = normalize_tools(result.get("tools"))
override_tools = normalize_tools(value)
base_tools = _normalize_tools(result.get("tools"))
override_tools = _normalize_tools(value)
result["tools"] = _append_unique_tools(
list(base_tools),
override_tools,
@@ -622,6 +645,8 @@ class BaseAgent(SerializationMixin):
# TODO(Copilot): update once #4331 merges
return final_response.text
from ._tools import FunctionTool
return FunctionTool(
name=tool_name,
description=tool_description,
@@ -771,6 +796,9 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
"""
opts = dict(default_options) if default_options else {}
from ._mcp import MCPTool
from ._tools import FunctionInvocationLayer
if not isinstance(client, FunctionInvocationLayer) and isinstance(client, BaseChatClient):
logger.warning(
"The provided chat client does not support function invoking, this might limit agent capabilities."
@@ -797,7 +825,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
# We ignore the MCP Servers here and store them separately,
# we add their functions to the tools list at runtime
normalized_tools = normalize_tools(tools_)
normalized_tools = _normalize_tools(tools_)
self.mcp_tools: list[MCPTool] = [tool for tool in normalized_tools if isinstance(tool, MCPTool)]
agent_tools = [tool for tool in normalized_tools if not isinstance(tool, MCPTool)]
@@ -1310,11 +1338,13 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
}
agent_name = self._get_agent_name()
base_tools = normalize_tools(chat_options.pop("tools", None))
from ._mcp import MCPTool
base_tools = _normalize_tools(chat_options.pop("tools", None))
mcp_duplicate_message = "Tool names must be unique. Consider setting `tool_name_prefix` on the MCPTool."
# Normalize tools
normalized_tools = normalize_tools(tools_)
normalized_tools = _normalize_tools(tools_)
# Resolve final tool list (configured tools + runtime provided tools + local MCP server tools)
final_tools = list(base_tools)
@@ -1549,6 +1579,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
raise ModuleNotFoundError(
"`mcp` is required to use `Agent.as_mcp_server()`. Please install `mcp`."
) from exc
from ._mcp import LOG_LEVEL_MAPPING
server_args: dict[str, Any] = {
"name": server_name,
@@ -25,11 +25,8 @@ from typing import (
runtime_checkable,
)
from pydantic import BaseModel
from ._docstrings import apply_layered_docstring
from ._serialization import SerializationMixin
from ._tools import ToolTypes
from ._types import (
ChatResponse,
ChatResponseUpdate,
@@ -49,11 +46,14 @@ else:
if TYPE_CHECKING:
from pydantic import BaseModel
from ._agents import Agent
from ._compaction import CompactionStrategy, TokenizerProtocol
from ._middleware import (
MiddlewareTypes,
)
from ._tools import ToolTypes
from ._types import ChatOptions
@@ -75,7 +75,10 @@ OptionsContraT = TypeVar(
)
# Used for the overloads that capture the response model type from options
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
if TYPE_CHECKING:
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
else:
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=Any)
@runtime_checkable
@@ -977,7 +980,13 @@ class BaseEmbeddingClient(SerializationMixin, ABC, Generic[EmbeddingInputT, Embe
def _apply_get_response_docstrings() -> None:
"""Align layered chat-client docstrings with the lowest public implementation."""
from ._middleware import ChatMiddlewareLayer
try:
from ._middleware import ChatMiddlewareLayer
except ImportError as exc:
if exc.name == "agent_framework._middleware" and "partially initialized module" in str(exc):
return
raise
from ._tools import FunctionInvocationLayer
from .observability import ChatTelemetryLayer
@@ -11,9 +11,10 @@ context providers (todo, mode, memory, skills).
from __future__ import annotations
import logging
import sys
from collections.abc import Callable, Sequence
from pathlib import Path
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, TypedDict
from .._agents import Agent, SupportsAgentRun
from .._clients import SupportsShellTool, SupportsWebSearchTool
@@ -21,6 +22,7 @@ from .._compaction import CompactionProvider, ContextWindowCompactionStrategy, T
from .._feature_stage import ExperimentalFeature, experimental
from .._sessions import ContextProvider, HistoryProvider, InMemoryHistoryProvider
from .._skills import SkillsProvider
from .._types import ChatOptions
from ._background_agents import BackgroundAgentsProvider
from ._file_access import AgentFileStore, FileAccessProvider, FileSystemAgentFileStore
from ._file_memory import FileMemoryProvider
@@ -29,6 +31,11 @@ from ._mode import AgentModeProvider
from ._todo import TodoProvider
from ._tool_approval import ToolApprovalMiddleware
if sys.version_info >= (3, 13):
from typing import TypeVar # pragma: no cover
else:
from typing_extensions import TypeVar # pragma: no cover
if TYPE_CHECKING:
from collections.abc import Mapping
@@ -246,10 +253,16 @@ def _assemble_shell(
HARNESS_AGENT_PROVIDER_NAME = "microsoft.agent_framework.harness"
OptionsCoT = TypeVar(
"OptionsCoT",
bound=TypedDict, # type: ignore[valid-type]
default="ChatOptions[None]",
)
@experimental(feature_id=ExperimentalFeature.HARNESS)
def create_harness_agent(
client: SupportsChatGetResponse[Any],
client: SupportsChatGetResponse[OptionsCoT],
*,
id: str | None = None,
name: str | None = None,
@@ -291,7 +304,7 @@ def create_harness_agent(
context_providers: Sequence[ContextProvider] | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
default_options: Mapping[str, Any] | None = None,
) -> Agent[Any]:
) -> Agent[OptionsCoT]:
"""Create a pre-configured agent with batteries included.
Assembles an :class:`~agent_framework.Agent` from a chat client, automatically wiring:
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft. All rights reserved.
from collections.abc import Callable, Mapping, Sequence
from pathlib import Path
from typing import Any, Protocol
from typing_extensions import TypedDict, TypeVar
from .._agents import Agent, SupportsAgentRun
from .._clients import SupportsChatGetResponse
from .._compaction import CompactionStrategy, TokenizerProtocol
from .._middleware import MiddlewareTypes
from .._sessions import ContextProvider, HistoryProvider
from .._skills import SkillsProvider
from .._tools import ToolTypes
from .._types import ChatOptions
from ._file_access import AgentFileStore
from ._loop import DEFAULT_MAX_ITERATIONS, NextMessageCallable, ShouldContinueCallable
from ._mode import AgentModeProvider
from ._todo import TodoProvider
from ._tool_approval import ToolApprovalRuleCallback
DEFAULT_HARNESS_INSTRUCTIONS: str
HARNESS_AGENT_PROVIDER_NAME: str
OptionsCoT = TypeVar(
"OptionsCoT",
bound=TypedDict, # type: ignore[valid-type]
default=ChatOptions[None],
)
class _ShellExecutorLike(Protocol):
def as_function(self, *args: Any, **kwargs: Any) -> Any: ...
class _ShellEnvironmentProviderOptionsLike(Protocol):
@property
def probe_tools(self) -> Sequence[str]: ...
@property
def override_family(self) -> Any | None: ...
@property
def probe_timeout(self) -> float: ...
@property
def instructions_formatter(self) -> Callable[[Any], str] | None: ...
def _assemble_instructions(
harness_instructions: str | None,
agent_instructions: str | None,
) -> str | None: ...
def create_harness_agent(
client: SupportsChatGetResponse[OptionsCoT],
*,
id: str | None = None,
name: str | None = None,
description: str | None = None,
harness_instructions: str | None = None,
agent_instructions: str | None = None,
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
max_context_window_tokens: int | None = None,
max_output_tokens: int | None = None,
history_provider: HistoryProvider | None = None,
disable_compaction: bool = False,
before_compaction_strategy: CompactionStrategy | None = None,
after_compaction_strategy: CompactionStrategy | None = None,
tokenizer: TokenizerProtocol | None = None,
disable_todo: bool = False,
todo_provider: TodoProvider | None = None,
disable_mode: bool = False,
mode_provider: AgentModeProvider | None = None,
disable_file_memory: bool = False,
file_memory_store: AgentFileStore | None = None,
disable_file_access: bool = False,
file_access_store: AgentFileStore | None = None,
file_access_disable_write_tools: bool = False,
file_access_disable_readonly_tool_approval: bool = False,
file_access_disable_write_tool_approval: bool = False,
skills_provider: SkillsProvider | None = None,
skills_paths: str | Path | Sequence[str | Path] | None = None,
background_agents: Sequence[SupportsAgentRun] | None = None,
background_agents_instructions: str | None = None,
shell_executor: _ShellExecutorLike | None = None,
shell_environment_provider_options: _ShellEnvironmentProviderOptionsLike | None = None,
disable_web_search: bool = False,
disable_tool_auto_approval: bool = False,
auto_approval_rules: Sequence[ToolApprovalRuleCallback] | None = None,
loop_should_continue: ShouldContinueCallable | None = None,
loop_next_message: NextMessageCallable | None = None,
loop_max_iterations: int | None = DEFAULT_MAX_ITERATIONS,
otel_provider_name: str | None = None,
context_providers: Sequence[ContextProvider] | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
default_options: Mapping[str, Any] | None = None,
) -> Agent[OptionsCoT]: ...
+20 -8
View File
@@ -25,12 +25,9 @@ from datetime import datetime
from inspect import isawaitable
from typing import TYPE_CHECKING, Any, ClassVar, Final, Generic, Literal, NewType, cast, overload
from pydantic import BaseModel
from typing_extensions import TypedDict
from ._serialization import SerializationMixin
from ._tools import ToolTypes
from ._tools import normalize_tools as _normalize_tools
from .exceptions import AdditionItemMismatch, ContentError
if sys.version_info >= (3, 13):
@@ -40,6 +37,11 @@ else:
logger = logging.getLogger("agent_framework")
if TYPE_CHECKING:
from pydantic import BaseModel
from ._tools import ToolTypes
# region Content Parsing Utilities
@@ -298,9 +300,14 @@ EmbeddingInputT = TypeVar("EmbeddingInputT", default="str")
ChatResponseT = TypeVar("ChatResponseT", bound="ChatResponse")
ToolModeT = TypeVar("ToolModeT", bound="ToolMode")
AgentResponseT = TypeVar("AgentResponseT", bound="AgentResponse")
ResponseModelT = TypeVar("ResponseModelT", bound=BaseModel | None, default=None, covariant=True)
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
StructuredResponseFormat = type[BaseModel] | Mapping[str, Any] | None
if TYPE_CHECKING:
ResponseModelT = TypeVar("ResponseModelT", bound=BaseModel | None, default=None, covariant=True)
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
StructuredResponseFormat = type[BaseModel] | Mapping[str, Any] | None
else:
ResponseModelT = TypeVar("ResponseModelT", bound=Any, default=None, covariant=True)
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=Any)
StructuredResponseFormat = type[Any] | Mapping[str, Any] | None
CreatedAtT = str # Use a datetimeoffset type? Or a more specific type like datetime.datetime?
@@ -2110,8 +2117,11 @@ def _parse_structured_response_value(text: str, response_format: Any | None) ->
return None
if not text:
return None
if isinstance(response_format, type) and issubclass(response_format, BaseModel):
return response_format.model_validate_json(text)
if isinstance(response_format, type):
from pydantic import BaseModel
if issubclass(response_format, BaseModel):
return response_format.model_validate_json(text)
if isinstance(response_format, Mapping):
try:
return json.loads(text)
@@ -3568,6 +3578,8 @@ def normalize_tools(
# List of tools
tools = normalize_tools([my_tool, another_tool])
"""
from ._tools import normalize_tools as _normalize_tools
return _normalize_tools(tools)
@@ -6,7 +6,7 @@ import logging
import warnings
from collections import defaultdict
from collections.abc import AsyncGenerator, Sequence
from typing import Any
from typing import TYPE_CHECKING, Any
from ..exceptions import (
WorkflowCheckpointException,
@@ -42,7 +42,7 @@ def warn_runner_deprecated() -> None:
)
class Runner:
class RunnerImpl:
"""A class to run a workflow in Pregel supersteps."""
def __init__(
@@ -419,3 +419,15 @@ class Runner:
existing_states[executor_id] = state
self._state.set(EXECUTOR_STATE_KEY, existing_states)
if TYPE_CHECKING:
Runner = RunnerImpl
def __getattr__(name: str) -> Any:
"""Lazily expose deprecated module-level public names."""
if name == "Runner":
warn_runner_deprecated()
return RunnerImpl
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -34,7 +34,7 @@ from ._events import (
)
from ._executor import Executor
from ._model_utils import DictConvertible
from ._runner import Runner
from ._runner import RunnerImpl
from ._runner_context import RunnerContext
from ._state import State
from ._typing_utils import is_instance_of, try_coerce_to_type
@@ -348,7 +348,7 @@ class Workflow(DictConvertible):
# Store non-serializable runtime objects as private attributes
self._runner_context = runner_context
self._runner_context.set_yield_output_classifier(self._output_designation.classify)
self._runner: Runner = Runner(
self._runner: RunnerImpl = RunnerImpl(
self.edge_groups,
self.executors,
State(),
@@ -28,7 +28,6 @@ from time import perf_counter, time_ns
from typing import TYPE_CHECKING, Any, ClassVar, Final, Generic, Literal, TypedDict, cast, overload
from dotenv import load_dotenv
from opentelemetry import context as otel_context
from opentelemetry import metrics, trace
from . import __version__ as version_info
@@ -2201,6 +2200,8 @@ def _activate_span(span: trace.Span) -> Generator[None]:
(and therefore the same async task / contextvars context), there is no risk
of "Failed to detach context" warnings from cross-context cleanup.
"""
from opentelemetry import context as otel_context
token = otel_context.attach(trace.set_span_in_context(span))
try:
yield
@@ -0,0 +1,44 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import ast
from pathlib import Path
import agent_framework
def _stub_all() -> set[str]:
stub_path = Path(agent_framework.__file__).with_suffix(".pyi")
module = ast.parse(stub_path.read_text(encoding="utf-8"))
for node in module.body:
if isinstance(node, ast.Assign):
for target in node.targets:
if isinstance(target, ast.Name) and target.id == "__all__":
return set(ast.literal_eval(node.value))
raise AssertionError("__all__ not found in agent_framework root stub")
def test_root_all_matches_stub_all() -> None:
assert set(agent_framework.__all__) == _stub_all()
def test_root_star_import_loads_representative_symbols() -> None:
namespace: dict[str, object] = {}
exec("from agent_framework import *", namespace)
assert namespace["Agent"] is agent_framework.Agent
assert namespace["Message"] is agent_framework.Message
assert namespace["tool"] is agent_framework.tool
assert namespace["FileStoreEntry"] is agent_framework.FileStoreEntry
assert namespace["SkillsSourceContext"] is agent_framework.SkillsSourceContext
def test_root_from_import_representative_symbols() -> None:
from agent_framework import Agent, FileStoreEntry, Message, SkillsSourceContext, tool
assert Agent is agent_framework.Agent
assert Message is agent_framework.Message
assert tool is agent_framework.tool
assert FileStoreEntry is agent_framework.FileStoreEntry
assert SkillsSourceContext is agent_framework.SkillsSourceContext