mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Fix tool normalization and provider sample consolidation (#3953)
* Fix tool normalization and provider samples - restore callable/single-tool normalization paths and unset tool-choice behavior\n- consolidate and expand chat/provider samples (OpenAI/Azure/Anthropic/Ollama/Bedrock)\n- migrate Bedrock lazy import surface to agent_framework.amazon and move provider samples Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * small fix in sample * Finalize provider, samples, and core cleanup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CopilotTool passthrough in agent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix link --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
ed113f941c
commit
aab621f5eb
@@ -720,6 +720,8 @@ class AnthropicClient(
|
||||
if options.get("tool_choice") is None:
|
||||
return result or None
|
||||
tool_mode = validate_tool_mode(options.get("tool_choice"))
|
||||
if tool_mode is None:
|
||||
return result or None
|
||||
allow_multiple = options.get("allow_multiple_tool_calls")
|
||||
match tool_mode.get("mode"):
|
||||
case "auto":
|
||||
|
||||
@@ -16,6 +16,7 @@ from agent_framework import (
|
||||
)
|
||||
from agent_framework._mcp import MCPTool
|
||||
from agent_framework._settings import load_settings
|
||||
from agent_framework._tools import ToolTypes
|
||||
from agent_framework.exceptions import ServiceInitializationError
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
from azure.ai.agents.models import Agent as AzureAgent
|
||||
@@ -169,11 +170,7 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
model: str | None = None,
|
||||
instructions: str | None = None,
|
||||
description: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -242,7 +239,12 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
normalized_tools = normalize_tools(tools)
|
||||
if normalized_tools:
|
||||
# Only convert non-MCP tools to Azure AI format
|
||||
non_mcp_tools = [t for t in normalized_tools if not isinstance(t, MCPTool)]
|
||||
non_mcp_tools: list[FunctionTool | MutableMapping[str, Any]] = []
|
||||
for normalized_tool in normalized_tools:
|
||||
if isinstance(normalized_tool, MCPTool):
|
||||
continue
|
||||
if isinstance(normalized_tool, (FunctionTool, MutableMapping)):
|
||||
non_mcp_tools.append(normalized_tool)
|
||||
if non_mcp_tools:
|
||||
# Pass run_options to capture tool_resources (e.g., for file search vector stores)
|
||||
run_options: dict[str, Any] = {}
|
||||
@@ -266,11 +268,7 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
self,
|
||||
id: str,
|
||||
*,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -322,11 +320,7 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
def as_agent(
|
||||
self,
|
||||
agent: AzureAgent,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -379,7 +373,7 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
def _to_chat_agent_from_agent(
|
||||
self,
|
||||
agent: AzureAgent,
|
||||
provided_tools: Sequence[FunctionTool | MutableMapping[str, Any]] | None = None,
|
||||
provided_tools: Sequence[ToolTypes] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -422,8 +416,8 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
def _merge_tools(
|
||||
self,
|
||||
agent_tools: Sequence[Any] | None,
|
||||
provided_tools: Sequence[FunctionTool | MutableMapping[str, Any]] | None,
|
||||
) -> list[FunctionTool | dict[str, Any]]:
|
||||
provided_tools: Sequence[ToolTypes] | None,
|
||||
) -> list[ToolTypes]:
|
||||
"""Merge hosted tools from agent with user-provided function tools.
|
||||
|
||||
Args:
|
||||
@@ -433,7 +427,7 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
Returns:
|
||||
Combined list of tools for the Agent.
|
||||
"""
|
||||
merged: list[FunctionTool | dict[str, Any]] = []
|
||||
merged: list[ToolTypes] = []
|
||||
|
||||
# Convert hosted tools from agent definition
|
||||
hosted_tools = from_azure_ai_agent_tools(agent_tools)
|
||||
@@ -459,7 +453,7 @@ class AzureAIAgentsProvider(Generic[OptionsCoT]):
|
||||
def _validate_function_tools(
|
||||
self,
|
||||
agent_tools: Sequence[Any] | None,
|
||||
provided_tools: Sequence[FunctionTool | MutableMapping[str, Any]] | None,
|
||||
provided_tools: Sequence[ToolTypes] | None,
|
||||
) -> None:
|
||||
"""Validate that required function tools are provided.
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ from agent_framework import (
|
||||
UsageDetails,
|
||||
)
|
||||
from agent_framework._settings import load_settings
|
||||
from agent_framework._tools import ToolTypes
|
||||
from agent_framework.exceptions import ServiceInitializationError, ServiceInvalidRequestError, ServiceResponseException
|
||||
from agent_framework.observability import ChatTelemetryLayer
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
@@ -1428,11 +1429,7 @@ class AzureAIAgentClient(
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
instructions: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: AzureAIAgentOptionsT | Mapping[str, Any] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from collections.abc import Callable, Mapping, MutableMapping, Sequence
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from contextlib import suppress
|
||||
from typing import Any, ClassVar, Generic, Literal, TypedDict, TypeVar, cast
|
||||
|
||||
@@ -22,6 +22,7 @@ from agent_framework import (
|
||||
MiddlewareTypes,
|
||||
)
|
||||
from agent_framework._settings import load_settings
|
||||
from agent_framework._tools import ToolTypes
|
||||
from agent_framework.exceptions import ServiceInitializationError
|
||||
from agent_framework.observability import ChatTelemetryLayer
|
||||
from agent_framework.openai import OpenAIResponsesOptions
|
||||
@@ -880,11 +881,7 @@ class RawAzureAIClient(RawOpenAIResponsesClient[AzureAIClientOptionsT], Generic[
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
instructions: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: AzureAIClientOptionsT | Mapping[str, Any] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
|
||||
@@ -17,6 +17,7 @@ from agent_framework import (
|
||||
)
|
||||
from agent_framework._mcp import MCPTool
|
||||
from agent_framework._settings import load_settings
|
||||
from agent_framework._tools import ToolTypes
|
||||
from agent_framework.exceptions import ServiceInitializationError
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.ai.projects.models import (
|
||||
@@ -161,11 +162,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
model: str | None = None,
|
||||
instructions: str | None = None,
|
||||
description: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -226,7 +223,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
for tool in normalized_tools:
|
||||
if isinstance(tool, MCPTool):
|
||||
mcp_tools.append(tool)
|
||||
else:
|
||||
elif isinstance(tool, (FunctionTool, MutableMapping)):
|
||||
non_mcp_tools.append(tool)
|
||||
|
||||
# Connect MCP tools and discover their functions BEFORE creating the agent
|
||||
@@ -263,11 +260,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
*,
|
||||
name: str | None = None,
|
||||
reference: AgentReference | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -323,11 +316,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
def as_agent(
|
||||
self,
|
||||
details: AgentVersionDetails,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -367,7 +356,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
def _to_chat_agent_from_details(
|
||||
self,
|
||||
details: AgentVersionDetails,
|
||||
provided_tools: Sequence[FunctionTool | MutableMapping[str, Any]] | None = None,
|
||||
provided_tools: Sequence[ToolTypes] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
@@ -415,8 +404,8 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
def _merge_tools(
|
||||
self,
|
||||
definition_tools: Sequence[Any] | None,
|
||||
provided_tools: Sequence[FunctionTool | MutableMapping[str, Any]] | None,
|
||||
) -> list[FunctionTool | dict[str, Any]]:
|
||||
provided_tools: Sequence[ToolTypes] | None,
|
||||
) -> list[ToolTypes]:
|
||||
"""Merge hosted tools from definition with user-provided function tools.
|
||||
|
||||
Args:
|
||||
@@ -426,7 +415,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
Returns:
|
||||
Combined list of tools for the Agent.
|
||||
"""
|
||||
merged: list[FunctionTool | dict[str, Any]] = []
|
||||
merged: list[ToolTypes] = []
|
||||
|
||||
# Convert hosted tools from definition (MCP, code interpreter, file search, web search)
|
||||
# Function tools from the definition are skipped - we use user-provided implementations instead
|
||||
@@ -450,11 +439,7 @@ class AzureAIProjectAgentProvider(Generic[OptionsCoT]):
|
||||
def _validate_function_tools(
|
||||
self,
|
||||
agent_tools: Sequence[Any] | None,
|
||||
provided_tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None,
|
||||
provided_tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> None:
|
||||
"""Validate that required function tools are provided."""
|
||||
# Normalize and validate function tools
|
||||
|
||||
@@ -12,7 +12,7 @@ Integration with AWS Bedrock for LLM inference.
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from agent_framework_bedrock import BedrockChatClient
|
||||
from agent_framework.amazon import BedrockChatClient
|
||||
|
||||
client = BedrockChatClient(model_id="anthropic.claude-3-sonnet-20240229-v1:0")
|
||||
response = await client.get_response("Hello")
|
||||
@@ -21,5 +21,5 @@ response = await client.get_response("Hello")
|
||||
## Import Path
|
||||
|
||||
```python
|
||||
from agent_framework_bedrock import BedrockChatClient
|
||||
from agent_framework.amazon import BedrockChatClient
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ The Bedrock integration enables Microsoft Agent Framework applications to call A
|
||||
|
||||
### Basic Usage Example
|
||||
|
||||
See the [Bedrock sample script](samples/bedrock_sample.py) for a runnable end-to-end script that:
|
||||
See the [Bedrock sample](../../samples/02-agents/providers/amazon/bedrock_chat_client.py) for a runnable end-to-end script that:
|
||||
|
||||
- Loads credentials from the `BEDROCK_*` environment variables
|
||||
- Instantiates `BedrockChatClient`
|
||||
|
||||
@@ -260,7 +260,7 @@ class BedrockChatClient(
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
from agent_framework.bedrock import BedrockChatClient
|
||||
from agent_framework.amazon import BedrockChatClient
|
||||
|
||||
# Basic usage with default credentials
|
||||
client = BedrockChatClient(model_id="<model name>")
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from agent_framework import Agent, tool
|
||||
|
||||
from agent_framework_bedrock import BedrockChatClient
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(city: str) -> dict[str, str]:
|
||||
"""Return a mock forecast for the requested city."""
|
||||
normalized = city.strip() or "New York"
|
||||
return {"city": normalized, "forecast": "72F and sunny"}
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run the Bedrock sample agent, invoke the weather tool, and log the response."""
|
||||
agent = Agent(
|
||||
client=BedrockChatClient(),
|
||||
instructions="You are a concise travel assistant.",
|
||||
name="BedrockWeatherAgent",
|
||||
tool_choice="auto",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
response = await agent.run("Use the weather tool to check the forecast for new york.")
|
||||
logging.info("\nAssistant reply:", response.text or "<no text returned>")
|
||||
logging.info("\nConversation transcript:")
|
||||
for message in response.messages:
|
||||
for idx, content in enumerate(message.contents, start=1):
|
||||
match content.type:
|
||||
case "text":
|
||||
logging.info(f" {idx}. text -> {content.text}")
|
||||
case "function_call":
|
||||
logging.info(f" {idx}. function_call ({content.name}) -> {content.arguments}")
|
||||
case "function_result":
|
||||
logging.info(f" {idx}. function_result ({content.call_id}) -> {content.result}")
|
||||
case _:
|
||||
logging.info(f" {idx}. {content.type}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -23,6 +23,7 @@ from agent_framework import (
|
||||
normalize_messages,
|
||||
)
|
||||
from agent_framework._settings import load_settings
|
||||
from agent_framework._tools import ToolTypes
|
||||
from agent_framework._types import AgentRunInputs, normalize_tools
|
||||
from agent_framework.exceptions import ServiceException
|
||||
from claude_agent_sdk import (
|
||||
@@ -217,12 +218,7 @@ class ClaudeAgent(BaseAgent, Generic[OptionsT]):
|
||||
description: str | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
middleware: Sequence[AgentMiddlewareTypes] | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| str
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, 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,
|
||||
@@ -289,7 +285,7 @@ class ClaudeAgent(BaseAgent, Generic[OptionsT]):
|
||||
|
||||
# Separate built-in tools (strings) from custom tools (callables/FunctionTool)
|
||||
self._builtin_tools: list[str] = []
|
||||
self._custom_tools: list[FunctionTool | MutableMapping[str, Any]] = []
|
||||
self._custom_tools: list[ToolTypes] = []
|
||||
self._normalize_tools(tools)
|
||||
|
||||
self._default_options = opts
|
||||
@@ -298,12 +294,7 @@ class ClaudeAgent(BaseAgent, Generic[OptionsT]):
|
||||
|
||||
def _normalize_tools(
|
||||
self,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| str
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | str]
|
||||
| None,
|
||||
tools: ToolTypes | Callable[..., Any] | str | Sequence[ToolTypes | Callable[..., Any] | str] | None,
|
||||
) -> None:
|
||||
"""Separate built-in tools (strings) from custom tools.
|
||||
|
||||
@@ -316,10 +307,10 @@ class ClaudeAgent(BaseAgent, Generic[OptionsT]):
|
||||
# Normalize to sequence
|
||||
if isinstance(tools, str):
|
||||
tools_list: Sequence[Any] = [tools]
|
||||
elif isinstance(tools, (FunctionTool, MutableMapping)) or callable(tools):
|
||||
tools_list = [tools]
|
||||
else:
|
||||
elif isinstance(tools, Sequence):
|
||||
tools_list = list(tools)
|
||||
else:
|
||||
tools_list = [tools]
|
||||
|
||||
for tool in tools_list:
|
||||
if isinstance(tool, str):
|
||||
@@ -457,7 +448,7 @@ class ClaudeAgent(BaseAgent, Generic[OptionsT]):
|
||||
|
||||
def _prepare_tools(
|
||||
self,
|
||||
tools: list[FunctionTool | MutableMapping[str, Any]],
|
||||
tools: Sequence[ToolTypes],
|
||||
) -> tuple[Any, list[str]]:
|
||||
"""Convert Agent Framework tools to SDK MCP server.
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""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.
|
||||
"""
|
||||
|
||||
import importlib.metadata
|
||||
from typing import Final
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ from ._sessions import AgentSession, BaseContextProvider, BaseHistoryProvider, I
|
||||
from ._tools import (
|
||||
FunctionInvocationLayer,
|
||||
FunctionTool,
|
||||
ToolTypes,
|
||||
normalize_tools,
|
||||
)
|
||||
from ._types import (
|
||||
AgentResponse,
|
||||
@@ -614,12 +616,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
id: str | None = None,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
**kwargs: Any,
|
||||
@@ -665,24 +662,14 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
|
||||
# Get tools from options or named parameter (named param takes precedence)
|
||||
tools_ = tools if tools is not None else opts.pop("tools", None)
|
||||
tools_ = cast(
|
||||
FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None,
|
||||
tools_,
|
||||
)
|
||||
|
||||
# Handle instructions - named parameter takes precedence over options
|
||||
instructions_ = instructions if instructions is not None else opts.pop("instructions", None)
|
||||
|
||||
# We ignore the MCP Servers here and store them separately,
|
||||
# we add their functions to the tools list at runtime
|
||||
normalized_tools: list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]] = ( # type:ignore[reportUnknownVariableType]
|
||||
[] if tools_ is None else tools_ if isinstance(tools_, list) else [tools_] # type: ignore[list-item]
|
||||
)
|
||||
self.mcp_tools: list[MCPTool] = [tool for tool in normalized_tools if isinstance(tool, MCPTool)] # type: ignore[misc]
|
||||
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)]
|
||||
|
||||
# Build chat options dict
|
||||
@@ -765,12 +752,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
*,
|
||||
stream: Literal[False] = ...,
|
||||
session: AgentSession | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
options: ChatOptions[ResponseModelBoundT],
|
||||
**kwargs: Any,
|
||||
) -> Awaitable[AgentResponse[ResponseModelBoundT]]: ...
|
||||
@@ -782,12 +764,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
*,
|
||||
stream: Literal[False] = ...,
|
||||
session: AgentSession | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
options: OptionsCoT | ChatOptions[None] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Awaitable[AgentResponse[Any]]: ...
|
||||
@@ -799,12 +776,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
*,
|
||||
stream: Literal[True],
|
||||
session: AgentSession | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
options: OptionsCoT | ChatOptions[Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> ResponseStream[AgentResponseUpdate, AgentResponse[Any]]: ...
|
||||
@@ -815,12 +787,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
*,
|
||||
stream: bool = False,
|
||||
session: AgentSession | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
options: OptionsCoT | ChatOptions[Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Awaitable[AgentResponse[Any]] | ResponseStream[AgentResponseUpdate, AgentResponse[Any]]:
|
||||
@@ -1000,12 +967,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
*,
|
||||
messages: AgentRunInputs | None,
|
||||
session: AgentSession | None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
options: Mapping[str, Any] | None,
|
||||
kwargs: dict[str, Any],
|
||||
) -> _RunContext:
|
||||
@@ -1035,9 +997,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
)
|
||||
|
||||
# Normalize tools
|
||||
normalized_tools: list[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any] = (
|
||||
[] if tools_ is None else tools_ if isinstance(tools_, list) else [tools_]
|
||||
)
|
||||
normalized_tools = normalize_tools(tools_)
|
||||
agent_name = self._get_agent_name()
|
||||
|
||||
# Resolve final tool list (runtime provided tools + local MCP server tools)
|
||||
@@ -1343,12 +1303,7 @@ class Agent(
|
||||
id: str | None = None,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Any
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any] | Any]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
|
||||
@@ -10,7 +10,6 @@ from collections.abc import (
|
||||
Awaitable,
|
||||
Callable,
|
||||
Mapping,
|
||||
MutableMapping,
|
||||
Sequence,
|
||||
)
|
||||
from typing import (
|
||||
@@ -31,7 +30,7 @@ from pydantic import BaseModel
|
||||
from ._serialization import SerializationMixin
|
||||
from ._tools import (
|
||||
FunctionInvocationConfiguration,
|
||||
FunctionTool,
|
||||
ToolTypes,
|
||||
)
|
||||
from ._types import (
|
||||
ChatResponse,
|
||||
@@ -436,11 +435,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
instructions: str | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsCoT | Mapping[str, Any] | None = None,
|
||||
context_providers: Sequence[Any] | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
|
||||
@@ -12,7 +12,6 @@ from collections.abc import (
|
||||
Awaitable,
|
||||
Callable,
|
||||
Mapping,
|
||||
MutableMapping,
|
||||
Sequence,
|
||||
)
|
||||
from functools import partial, wraps
|
||||
@@ -25,6 +24,7 @@ from typing import (
|
||||
Final,
|
||||
Generic,
|
||||
Literal,
|
||||
TypeAlias,
|
||||
TypedDict,
|
||||
Union,
|
||||
get_args,
|
||||
@@ -58,6 +58,7 @@ else:
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._clients import SupportsChatGetResponse
|
||||
from ._mcp import MCPTool
|
||||
from ._middleware import FunctionMiddlewarePipeline, FunctionMiddlewareTypes
|
||||
from ._types import (
|
||||
ChatOptions,
|
||||
@@ -69,6 +70,8 @@ if TYPE_CHECKING:
|
||||
)
|
||||
|
||||
ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel)
|
||||
else:
|
||||
MCPTool = Any # type: ignore[assignment,misc]
|
||||
|
||||
|
||||
logger = logging.getLogger("agent_framework")
|
||||
@@ -506,9 +509,7 @@ class FunctionTool(SerializationMixin):
|
||||
if OBSERVABILITY_SETTINGS.SENSITIVE_DATA_ENABLED: # type: ignore[name-defined]
|
||||
attributes.update({
|
||||
OtelAttr.TOOL_ARGUMENTS: (
|
||||
json.dumps(serializable_kwargs, default=str, ensure_ascii=False)
|
||||
if serializable_kwargs
|
||||
else "None"
|
||||
json.dumps(serializable_kwargs, default=str, ensure_ascii=False) if serializable_kwargs else "None"
|
||||
)
|
||||
})
|
||||
with get_function_span(attributes=attributes) as span:
|
||||
@@ -623,14 +624,46 @@ class FunctionTool(SerializationMixin):
|
||||
return as_dict
|
||||
|
||||
|
||||
ToolTypes: TypeAlias = FunctionTool | MCPTool | Mapping[str, Any] | Any
|
||||
|
||||
|
||||
def normalize_tools(
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> list[ToolTypes]:
|
||||
"""Normalize tool inputs while preserving non-callable tool objects.
|
||||
|
||||
Args:
|
||||
tools: A single tool or sequence of tools.
|
||||
|
||||
Returns:
|
||||
A normalized list where callable inputs are converted to ``FunctionTool``
|
||||
using :func:`tool`, and existing tool objects are passed through unchanged.
|
||||
"""
|
||||
if not tools:
|
||||
return []
|
||||
|
||||
tool_items = (
|
||||
list(tools)
|
||||
if isinstance(tools, Sequence) and not isinstance(tools, (str, bytes, bytearray, Mapping))
|
||||
else [tools]
|
||||
)
|
||||
from ._mcp import MCPTool
|
||||
|
||||
normalized: list[ToolTypes] = []
|
||||
for tool_item in tool_items:
|
||||
# check known types, these are also callable, so we need to do that first
|
||||
if isinstance(tool_item, (FunctionTool, Mapping, MCPTool)):
|
||||
normalized.append(tool_item)
|
||||
continue
|
||||
if callable(tool_item):
|
||||
normalized.append(tool(tool_item))
|
||||
continue
|
||||
normalized.append(tool_item)
|
||||
return normalized
|
||||
|
||||
|
||||
def _tools_to_dict(
|
||||
tools: (
|
||||
FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None
|
||||
),
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> list[str | dict[str, Any]] | None:
|
||||
"""Parse the tools to a dict.
|
||||
|
||||
@@ -640,32 +673,20 @@ def _tools_to_dict(
|
||||
Returns:
|
||||
A list of tool specifications as dictionaries, or None if no tools provided.
|
||||
"""
|
||||
if not tools:
|
||||
return None
|
||||
if not isinstance(tools, list):
|
||||
if isinstance(tools, FunctionTool):
|
||||
return [tools.to_json_schema_spec()]
|
||||
if isinstance(tools, SerializationMixin):
|
||||
return [tools.to_dict()]
|
||||
if isinstance(tools, dict):
|
||||
return [tools]
|
||||
if callable(tools):
|
||||
return [tool(tools).to_json_schema_spec()]
|
||||
logger.warning("Can't parse tool.")
|
||||
normalized_tools = normalize_tools(tools)
|
||||
if not normalized_tools:
|
||||
return None
|
||||
|
||||
results: list[str | dict[str, Any]] = []
|
||||
for tool_item in tools:
|
||||
for tool_item in normalized_tools:
|
||||
if isinstance(tool_item, FunctionTool):
|
||||
results.append(tool_item.to_json_schema_spec())
|
||||
continue
|
||||
if isinstance(tool_item, SerializationMixin):
|
||||
results.append(tool_item.to_dict())
|
||||
continue
|
||||
if isinstance(tool_item, dict):
|
||||
results.append(tool_item)
|
||||
continue
|
||||
if callable(tool_item):
|
||||
results.append(tool(tool_item).to_json_schema_spec())
|
||||
if isinstance(tool_item, Mapping):
|
||||
results.append(dict(tool_item))
|
||||
continue
|
||||
logger.warning("Can't parse tool.")
|
||||
return results
|
||||
@@ -1430,20 +1451,12 @@ async def _auto_invoke_function(
|
||||
|
||||
|
||||
def _get_tool_map(
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]],
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]],
|
||||
) -> dict[str, FunctionTool]:
|
||||
tool_list: dict[str, FunctionTool] = {}
|
||||
for tool_item in tools if isinstance(tools, list) else [tools]:
|
||||
for tool_item in normalize_tools(tools):
|
||||
if isinstance(tool_item, FunctionTool):
|
||||
tool_list[tool_item.name] = tool_item
|
||||
continue
|
||||
if callable(tool_item):
|
||||
# Convert to AITool if it's a function or callable
|
||||
ai_tool = tool(tool_item)
|
||||
tool_list[ai_tool.name] = ai_tool
|
||||
return tool_list
|
||||
|
||||
|
||||
@@ -1451,10 +1464,7 @@ async def _try_execute_function_calls(
|
||||
custom_args: dict[str, Any],
|
||||
attempt_idx: int,
|
||||
function_calls: Sequence[Content],
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]],
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]],
|
||||
config: FunctionInvocationConfiguration,
|
||||
middleware_pipeline: Any = None, # Optional MiddlewarePipeline to avoid circular imports
|
||||
) -> tuple[Sequence[Content], bool]:
|
||||
@@ -1633,15 +1643,16 @@ async def _ensure_response_stream(
|
||||
return stream
|
||||
|
||||
|
||||
def _extract_tools(options: dict[str, Any] | None) -> Any:
|
||||
def _extract_tools(
|
||||
options: dict[str, Any] | None,
|
||||
) -> ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None:
|
||||
"""Extract tools from options dict.
|
||||
|
||||
Args:
|
||||
options: The options dict containing chat options.
|
||||
|
||||
Returns:
|
||||
FunctionTool | Callable[..., Any] | MutableMapping[str, Any] |
|
||||
Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]] | None
|
||||
ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None
|
||||
"""
|
||||
if options and isinstance(options, dict):
|
||||
return options.get("tools")
|
||||
@@ -1996,6 +2007,11 @@ class FunctionInvocationLayer(Generic[OptionsCoT]):
|
||||
# Remove additional_function_arguments from options passed to underlying chat client
|
||||
# It's for tool invocation only and not recognized by chat service APIs
|
||||
mutable_options.pop("additional_function_arguments", None)
|
||||
# Support tools passed via kwargs in direct client.get_response(...) calls.
|
||||
if "tools" in filtered_kwargs:
|
||||
if mutable_options.get("tools") is None:
|
||||
mutable_options["tools"] = filtered_kwargs["tools"]
|
||||
filtered_kwargs.pop("tools", None)
|
||||
|
||||
if not stream:
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ from typing import TYPE_CHECKING, Any, ClassVar, Final, Generic, Literal, NewTyp
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ._serialization import SerializationMixin
|
||||
from ._tools import FunctionTool, tool
|
||||
from ._tools import ToolTypes
|
||||
from ._tools import normalize_tools as _normalize_tools
|
||||
from .exceptions import AdditionItemMismatch, ContentError
|
||||
|
||||
if sys.version_info >= (3, 13):
|
||||
@@ -2871,10 +2872,9 @@ class _ChatOptionsBase(TypedDict, total=False):
|
||||
|
||||
# Tool configuration (forward reference to avoid circular import)
|
||||
tools: (
|
||||
FunctionTool
|
||||
ToolTypes
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| Sequence[ToolTypes | Callable[..., Any]]
|
||||
| None
|
||||
)
|
||||
tool_choice: ToolMode | Literal["auto", "required", "none"]
|
||||
@@ -2963,18 +2963,11 @@ async def validate_chat_options(options: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
|
||||
def normalize_tools(
|
||||
tools: (
|
||||
FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None
|
||||
),
|
||||
) -> list[FunctionTool | MutableMapping[str, Any]]:
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> list[ToolTypes]:
|
||||
"""Normalize tools into a list.
|
||||
|
||||
Converts callables to FunctionTool objects and ensures all tools are either
|
||||
FunctionTool instances or MutableMappings.
|
||||
Converts callables to FunctionTool objects and preserves existing tool objects.
|
||||
|
||||
Args:
|
||||
tools: Tools to normalize - can be a single tool, callable, or sequence.
|
||||
@@ -2999,37 +2992,16 @@ def normalize_tools(
|
||||
# List of tools
|
||||
tools = normalize_tools([my_tool, another_tool])
|
||||
"""
|
||||
final_tools: list[FunctionTool | MutableMapping[str, Any]] = []
|
||||
if not tools:
|
||||
return final_tools
|
||||
if not isinstance(tools, Sequence) or isinstance(tools, (str, MutableMapping)):
|
||||
# Single tool (not a sequence, or is a mapping which shouldn't be treated as sequence)
|
||||
if not isinstance(tools, (FunctionTool, MutableMapping)):
|
||||
return [tool(tools)]
|
||||
return [tools]
|
||||
for tool_item in tools:
|
||||
if isinstance(tool_item, (FunctionTool, MutableMapping)):
|
||||
final_tools.append(tool_item)
|
||||
else:
|
||||
# Convert callable to FunctionTool
|
||||
final_tools.append(tool(tool_item))
|
||||
return final_tools
|
||||
return _normalize_tools(tools)
|
||||
|
||||
|
||||
async def validate_tools(
|
||||
tools: (
|
||||
FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None
|
||||
),
|
||||
) -> list[FunctionTool | MutableMapping[str, Any]]:
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> list[ToolTypes]:
|
||||
"""Validate and normalize tools into a list.
|
||||
|
||||
Converts callables to FunctionTool objects, expands MCP tools to their constituent
|
||||
functions (connecting them if needed), and ensures all tools are either FunctionTool
|
||||
instances or MutableMappings.
|
||||
functions (connecting them if needed), while preserving non-callable tool objects.
|
||||
|
||||
Args:
|
||||
tools: Tools to validate - can be a single tool, callable, or sequence.
|
||||
@@ -3058,7 +3030,7 @@ async def validate_tools(
|
||||
normalized = normalize_tools(tools)
|
||||
|
||||
# Handle MCP tool expansion (async-only)
|
||||
final_tools: list[FunctionTool | MutableMapping[str, Any]] = []
|
||||
final_tools: list[ToolTypes] = []
|
||||
for tool_ in normalized:
|
||||
# Import MCPTool here to avoid circular imports
|
||||
from ._mcp import MCPTool
|
||||
@@ -3076,20 +3048,21 @@ async def validate_tools(
|
||||
|
||||
def validate_tool_mode(
|
||||
tool_choice: ToolMode | Literal["auto", "required", "none"] | None,
|
||||
) -> ToolMode:
|
||||
) -> ToolMode | None:
|
||||
"""Validate and normalize tool_choice to a ToolMode dict.
|
||||
|
||||
Args:
|
||||
tool_choice: The tool choice value to validate.
|
||||
|
||||
Returns:
|
||||
A ToolMode dict (contains keys: "mode", and optionally "required_function_name").
|
||||
A ToolMode dict (contains keys: "mode", and optionally
|
||||
"required_function_name"), or ``None`` when not provided.
|
||||
|
||||
Raises:
|
||||
ContentError: If the tool_choice string is invalid.
|
||||
"""
|
||||
if not tool_choice:
|
||||
return {"mode": "none"}
|
||||
if tool_choice is None:
|
||||
return None
|
||||
if isinstance(tool_choice, str):
|
||||
if tool_choice not in ("auto", "required", "none"):
|
||||
raise ContentError(f"Invalid tool choice: {tool_choice}")
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Workflow namespace for built-in Agent Framework orchestration primitives.
|
||||
|
||||
This module re-exports objects from workflow implementation modules under
|
||||
``agent_framework._workflows``.
|
||||
|
||||
Supported classes include:
|
||||
- Workflow
|
||||
- WorkflowBuilder
|
||||
- AgentExecutor
|
||||
- Runner
|
||||
- WorkflowExecutor
|
||||
"""
|
||||
|
||||
from ._agent import WorkflowAgent
|
||||
from ._agent_executor import (
|
||||
AgentExecutor,
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""A2A integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-a2a``
|
||||
|
||||
Supported classes:
|
||||
- A2AAgent
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_a2a"
|
||||
PACKAGE_NAME = "agent-framework-a2a"
|
||||
_IMPORTS = ["__version__", "A2AAgent"]
|
||||
_IMPORTS = ["A2AAgent"]
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
from agent_framework_a2a import (
|
||||
A2AAgent,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"A2AAgent",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""AG-UI integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-ag-ui``
|
||||
|
||||
Supported classes and functions:
|
||||
- AgentFrameworkAgent
|
||||
- AGUIChatClient
|
||||
- AGUIEventConverter
|
||||
- AGUIHttpService
|
||||
- add_agent_framework_fastapi_endpoint
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_ag_ui"
|
||||
PACKAGE_NAME = "agent-framework-ag-ui"
|
||||
_IMPORTS = [
|
||||
"__version__",
|
||||
"AgentFrameworkAgent",
|
||||
"add_agent_framework_fastapi_endpoint",
|
||||
"AGUIChatClient",
|
||||
|
||||
@@ -5,7 +5,6 @@ from agent_framework_ag_ui import (
|
||||
AGUIChatClient,
|
||||
AGUIEventConverter,
|
||||
AGUIHttpService,
|
||||
__version__,
|
||||
add_agent_framework_fastapi_endpoint,
|
||||
)
|
||||
|
||||
@@ -14,6 +13,5 @@ __all__ = [
|
||||
"AGUIEventConverter",
|
||||
"AGUIHttpService",
|
||||
"AgentFrameworkAgent",
|
||||
"__version__",
|
||||
"add_agent_framework_fastapi_endpoint",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Amazon Bedrock integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-bedrock``
|
||||
|
||||
Supported classes:
|
||||
- BedrockChatClient
|
||||
- BedrockChatOptions
|
||||
- BedrockGuardrailConfig
|
||||
- BedrockSettings
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_bedrock"
|
||||
PACKAGE_NAME = "agent-framework-bedrock"
|
||||
_IMPORTS = ["BedrockChatClient", "BedrockChatOptions", "BedrockGuardrailConfig", "BedrockSettings"]
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
if name in _IMPORTS:
|
||||
try:
|
||||
return getattr(importlib.import_module(IMPORT_PATH), name)
|
||||
except ModuleNotFoundError as exc:
|
||||
raise ModuleNotFoundError(
|
||||
f"The '{PACKAGE_NAME}' package is not installed, please do `pip install {PACKAGE_NAME}`"
|
||||
) from exc
|
||||
raise AttributeError(f"Module {IMPORT_PATH} has no attribute {name}.")
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return _IMPORTS
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from agent_framework_bedrock import (
|
||||
BedrockChatClient,
|
||||
BedrockChatOptions,
|
||||
BedrockGuardrailConfig,
|
||||
BedrockSettings,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"BedrockChatClient",
|
||||
"BedrockChatOptions",
|
||||
"BedrockGuardrailConfig",
|
||||
"BedrockSettings",
|
||||
]
|
||||
@@ -1,23 +1,40 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Anthropic integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-anthropic``
|
||||
- ``agent-framework-claude``
|
||||
|
||||
Supported classes:
|
||||
- AnthropicClient
|
||||
- AnthropicChatOptions
|
||||
- ClaudeAgent
|
||||
- ClaudeAgentOptions
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_anthropic"
|
||||
PACKAGE_NAME = "agent-framework-anthropic"
|
||||
_IMPORTS = ["__version__", "AnthropicClient", "AnthropicChatOptions"]
|
||||
_IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"AnthropicClient": ("agent_framework_anthropic", "agent-framework-anthropic"),
|
||||
"AnthropicChatOptions": ("agent_framework_anthropic", "agent-framework-anthropic"),
|
||||
"ClaudeAgent": ("agent_framework_claude", "agent-framework-claude"),
|
||||
"ClaudeAgentOptions": ("agent_framework_claude", "agent-framework-claude"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
if name in _IMPORTS:
|
||||
import_path, package_name = _IMPORTS[name]
|
||||
try:
|
||||
return getattr(importlib.import_module(IMPORT_PATH), name)
|
||||
return getattr(importlib.import_module(import_path), name)
|
||||
except ModuleNotFoundError as exc:
|
||||
raise ModuleNotFoundError(
|
||||
f"The '{PACKAGE_NAME}' package is not installed, please do `pip install {PACKAGE_NAME}`"
|
||||
f"The '{package_name}' package is not installed, please do `pip install {package_name}`"
|
||||
) from exc
|
||||
raise AttributeError(f"Module {IMPORT_PATH} has no attribute {name}.")
|
||||
raise AttributeError(f"Module `anthropic` has no attribute {name}.")
|
||||
|
||||
|
||||
def __dir__() -> list[str]:
|
||||
return _IMPORTS
|
||||
return list(_IMPORTS.keys())
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
from agent_framework_anthropic import (
|
||||
AnthropicChatOptions,
|
||||
AnthropicClient,
|
||||
__version__,
|
||||
)
|
||||
from agent_framework_claude import ClaudeAgent, ClaudeAgentOptions
|
||||
|
||||
__all__ = [
|
||||
"AnthropicChatOptions",
|
||||
"AnthropicClient",
|
||||
"__version__",
|
||||
"ClaudeAgent",
|
||||
"ClaudeAgentOptions",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Azure integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from optional Azure connector packages and
|
||||
built-in core Azure OpenAI modules.
|
||||
|
||||
Supported classes include:
|
||||
- AzureAIClient
|
||||
- AzureAIAgentClient
|
||||
- AzureOpenAIChatClient
|
||||
- AzureOpenAIResponsesClient
|
||||
- AzureAISearchContextProvider
|
||||
- DurableAIAgent
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""ChatKit integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-chatkit``
|
||||
|
||||
Supported classes and functions:
|
||||
- ThreadItemConverter
|
||||
- simple_to_agent_input
|
||||
- stream_agent_response
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_chatkit"
|
||||
PACKAGE_NAME = "agent-framework-chatkit"
|
||||
_IMPORTS = ["__version__", "ThreadItemConverter", "simple_to_agent_input", "stream_agent_response"]
|
||||
_IMPORTS = ["ThreadItemConverter", "simple_to_agent_input", "stream_agent_response"]
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
from agent_framework_chatkit import (
|
||||
ThreadItemConverter,
|
||||
__version__,
|
||||
simple_to_agent_input,
|
||||
stream_agent_response,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"ThreadItemConverter",
|
||||
"__version__",
|
||||
"simple_to_agent_input",
|
||||
"stream_agent_response",
|
||||
]
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Declarative integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-declarative``
|
||||
|
||||
Supported classes include:
|
||||
- AgentFactory
|
||||
- WorkflowFactory
|
||||
- ExternalInputRequest
|
||||
- ExternalInputResponse
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_declarative"
|
||||
PACKAGE_NAME = "agent-framework-declarative"
|
||||
_IMPORTS = [
|
||||
"__version__",
|
||||
"AgentFactory",
|
||||
"AgentExternalInputRequest",
|
||||
"AgentExternalInputResponse",
|
||||
|
||||
@@ -13,7 +13,6 @@ from agent_framework_declarative import (
|
||||
ProviderTypeMapping,
|
||||
WorkflowFactory,
|
||||
WorkflowState,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
@@ -29,5 +28,4 @@ __all__ = [
|
||||
"ProviderTypeMapping",
|
||||
"WorkflowFactory",
|
||||
"WorkflowState",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""DevUI integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-devui``
|
||||
|
||||
Supported classes and functions include:
|
||||
- DevServer
|
||||
- AgentFrameworkRequest
|
||||
- DiscoveryResponse
|
||||
- ResponseStreamEvent
|
||||
- serve
|
||||
- main
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
@@ -16,7 +30,6 @@ _IMPORTS = [
|
||||
"main",
|
||||
"register_cleanup",
|
||||
"serve",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ from agent_framework_devui import (
|
||||
OpenAIError,
|
||||
OpenAIResponse,
|
||||
ResponseStreamEvent,
|
||||
__version__,
|
||||
main,
|
||||
register_cleanup,
|
||||
serve,
|
||||
@@ -22,7 +21,6 @@ __all__ = [
|
||||
"OpenAIError",
|
||||
"OpenAIResponse",
|
||||
"ResponseStreamEvent",
|
||||
"__version__",
|
||||
"main",
|
||||
"register_cleanup",
|
||||
"serve",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Exception hierarchy used across Agent Framework core and connectors."""
|
||||
|
||||
import logging
|
||||
from typing import Any, Literal
|
||||
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""GitHub integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-github-copilot``
|
||||
|
||||
Supported classes:
|
||||
- GitHubCopilotAgent
|
||||
- GitHubCopilotOptions
|
||||
- GitHubCopilotSettings
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
@@ -7,7 +18,6 @@ _IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"GitHubCopilotAgent": ("agent_framework_github_copilot", "agent-framework-github-copilot"),
|
||||
"GitHubCopilotOptions": ("agent_framework_github_copilot", "agent-framework-github-copilot"),
|
||||
"GitHubCopilotSettings": ("agent_framework_github_copilot", "agent-framework-github-copilot"),
|
||||
"__version__": ("agent_framework_github_copilot", "agent-framework-github-copilot"),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,10 @@ from agent_framework_github_copilot import (
|
||||
GitHubCopilotAgent,
|
||||
GitHubCopilotOptions,
|
||||
GitHubCopilotSettings,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"GitHubCopilotAgent",
|
||||
"GitHubCopilotOptions",
|
||||
"GitHubCopilotSettings",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Lab namespace package for experimental Agent Framework integrations.
|
||||
|
||||
This module extends the package path so experimental lab integrations can be
|
||||
distributed in separate packages under the ``agent_framework.lab`` namespace.
|
||||
"""
|
||||
|
||||
# This makes agent_framework.lab a namespace package
|
||||
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Mem0 integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-mem0``
|
||||
|
||||
Supported classes:
|
||||
- Mem0ContextProvider
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_mem0"
|
||||
PACKAGE_NAME = "agent-framework-mem0"
|
||||
_IMPORTS = ["__version__", "Mem0ContextProvider"]
|
||||
_IMPORTS = ["Mem0ContextProvider"]
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
from agent_framework_mem0 import (
|
||||
Mem0ContextProvider,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Mem0ContextProvider",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Microsoft integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-copilotstudio``
|
||||
- ``agent-framework-purview``
|
||||
- ``agent-framework-foundry-local``
|
||||
|
||||
Supported classes:
|
||||
- CopilotStudioAgent
|
||||
- PurviewPolicyMiddleware
|
||||
- PurviewChatPolicyMiddleware
|
||||
- PurviewSettings
|
||||
- PurviewAppLocation
|
||||
- PurviewLocationType
|
||||
- PurviewAuthenticationError
|
||||
- PurviewPaymentRequiredError
|
||||
- PurviewRateLimitError
|
||||
- PurviewRequestError
|
||||
- PurviewServiceError
|
||||
- CacheProvider
|
||||
- FoundryLocalChatOptions
|
||||
- FoundryLocalClient
|
||||
- FoundryLocalSettings
|
||||
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
_IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"CopilotStudioAgent": ("agent_framework_copilotstudio", "agent-framework-copilotstudio"),
|
||||
"__version__": ("agent_framework_copilotstudio", "agent-framework-copilotstudio"),
|
||||
"acquire_token": ("agent_framework_copilotstudio", "agent-framework-copilotstudio"),
|
||||
"PurviewPolicyMiddleware": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"PurviewChatPolicyMiddleware": ("agent_framework_purview", "agent-framework-purview"),
|
||||
@@ -18,6 +43,9 @@ _IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"PurviewRequestError": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"PurviewServiceError": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"CacheProvider": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"FoundryLocalChatOptions": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
"FoundryLocalClient": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
"FoundryLocalSettings": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
|
||||
from agent_framework_copilotstudio import (
|
||||
CopilotStudioAgent,
|
||||
__version__,
|
||||
acquire_token,
|
||||
)
|
||||
from agent_framework_foundry_local import (
|
||||
FoundryLocalChatOptions,
|
||||
FoundryLocalClient,
|
||||
FoundryLocalSettings,
|
||||
)
|
||||
from agent_framework_purview import (
|
||||
CacheProvider,
|
||||
PurviewAppLocation,
|
||||
@@ -22,6 +26,9 @@ from agent_framework_purview import (
|
||||
__all__ = [
|
||||
"CacheProvider",
|
||||
"CopilotStudioAgent",
|
||||
"FoundryLocalChatOptions",
|
||||
"FoundryLocalClient",
|
||||
"FoundryLocalSettings",
|
||||
"PurviewAppLocation",
|
||||
"PurviewAuthenticationError",
|
||||
"PurviewChatPolicyMiddleware",
|
||||
@@ -32,6 +39,5 @@ __all__ = [
|
||||
"PurviewRequestError",
|
||||
"PurviewServiceError",
|
||||
"PurviewSettings",
|
||||
"__version__",
|
||||
"acquire_token",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Observability and OpenTelemetry helpers for Agent Framework.
|
||||
|
||||
Commonly used exports:
|
||||
- enable_instrumentation
|
||||
- configure_otel_providers
|
||||
- AgentTelemetryLayer
|
||||
- ChatTelemetryLayer
|
||||
- get_tracer
|
||||
- get_meter
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
@@ -1128,11 +1139,8 @@ class ChatTelemetryLayer(Generic[OptionsCoT]):
|
||||
opts: dict[str, Any] = options or {} # type: ignore[assignment]
|
||||
provider_name = str(self.otel_provider_name)
|
||||
model_id = kwargs.get("model_id") or opts.get("model_id") or getattr(self, "model_id", None) or "unknown"
|
||||
service_url = str(
|
||||
service_url_func()
|
||||
if (service_url_func := getattr(self, "service_url", None)) and callable(service_url_func)
|
||||
else "unknown"
|
||||
)
|
||||
service_url_func = getattr(self, "service_url", None)
|
||||
service_url = str(service_url_func() if callable(service_url_func) else "unknown")
|
||||
attributes = _get_span_attributes(
|
||||
operation_name=OtelAttr.CHAT_COMPLETION_OPERATION,
|
||||
provider_name=provider_name,
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Ollama integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-ollama``
|
||||
|
||||
Supported classes:
|
||||
- OllamaChatClient
|
||||
- OllamaSettings
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_ollama"
|
||||
PACKAGE_NAME = "agent-framework-ollama"
|
||||
_IMPORTS = ["__version__", "OllamaChatClient", "OllamaSettings"]
|
||||
_IMPORTS = ["OllamaChatClient", "OllamaSettings"]
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
from agent_framework_ollama import (
|
||||
OllamaChatClient,
|
||||
OllamaSettings,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"OllamaChatClient",
|
||||
"OllamaSettings",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""OpenAI namespace for built-in Agent Framework clients.
|
||||
|
||||
This module re-exports objects from the core OpenAI implementation modules in
|
||||
``agent_framework.openai``.
|
||||
|
||||
Supported classes include:
|
||||
- OpenAIChatClient
|
||||
- OpenAIResponsesClient
|
||||
- OpenAIAssistantsClient
|
||||
- OpenAIAssistantProvider
|
||||
"""
|
||||
|
||||
from ._assistant_provider import OpenAIAssistantProvider
|
||||
from ._assistants_client import (
|
||||
AssistantToolResources,
|
||||
|
||||
@@ -15,8 +15,7 @@ from agent_framework._settings import SecretString, load_settings
|
||||
from .._agents import Agent
|
||||
from .._middleware import MiddlewareTypes
|
||||
from .._sessions import BaseContextProvider
|
||||
from .._tools import FunctionTool
|
||||
from .._types import normalize_tools
|
||||
from .._tools import FunctionTool, ToolTypes, normalize_tools
|
||||
from ..exceptions import ServiceInitializationError
|
||||
from ._assistants_client import OpenAIAssistantsClient
|
||||
from ._shared import OpenAISettings, from_assistant_tools, to_assistant_tools
|
||||
@@ -43,13 +42,6 @@ OptionsCoT = TypeVar(
|
||||
covariant=True,
|
||||
)
|
||||
|
||||
_ToolsType = (
|
||||
FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
)
|
||||
|
||||
|
||||
class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
"""Provider for creating Agent instances from OpenAI Assistants API.
|
||||
@@ -203,7 +195,7 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
model: str,
|
||||
instructions: str | None = None,
|
||||
description: str | None = None,
|
||||
tools: _ToolsType | None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
metadata: dict[str, str] | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
@@ -259,7 +251,8 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
"""
|
||||
# Normalize tools
|
||||
normalized_tools = normalize_tools(tools)
|
||||
api_tools = to_assistant_tools(normalized_tools) if normalized_tools else []
|
||||
assistant_tools = [tool for tool in normalized_tools if isinstance(tool, (FunctionTool, MutableMapping))]
|
||||
api_tools = to_assistant_tools(assistant_tools) if assistant_tools else []
|
||||
|
||||
# Extract response_format from default_options if present
|
||||
opts = dict(default_options) if default_options else {}
|
||||
@@ -311,7 +304,7 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
self,
|
||||
assistant_id: str,
|
||||
*,
|
||||
tools: _ToolsType | None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
instructions: str | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
@@ -377,7 +370,7 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
self,
|
||||
assistant: Assistant,
|
||||
*,
|
||||
tools: _ToolsType | None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
instructions: str | None = None,
|
||||
default_options: OptionsCoT | None = None,
|
||||
middleware: Sequence[MiddlewareTypes] | None = None,
|
||||
@@ -442,7 +435,7 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
def _validate_function_tools(
|
||||
self,
|
||||
assistant_tools: list[Any],
|
||||
provided_tools: _ToolsType | None,
|
||||
provided_tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> None:
|
||||
"""Validate that required function tools are provided.
|
||||
|
||||
@@ -493,8 +486,8 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
def _merge_tools(
|
||||
self,
|
||||
assistant_tools: list[Any],
|
||||
user_tools: _ToolsType | None,
|
||||
) -> list[FunctionTool | MutableMapping[str, Any]]:
|
||||
user_tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> list[FunctionTool | MutableMapping[str, Any] | Any]:
|
||||
"""Merge hosted tools from assistant with user-provided function tools.
|
||||
|
||||
Args:
|
||||
@@ -504,7 +497,7 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
Returns:
|
||||
A list of all tools (hosted tools + user function implementations).
|
||||
"""
|
||||
merged: list[FunctionTool | MutableMapping[str, Any]] = []
|
||||
merged: list[FunctionTool | MutableMapping[str, Any] | Any] = []
|
||||
|
||||
# Add hosted tools from assistant using shared conversion
|
||||
hosted_tools = from_assistant_tools(assistant_tools)
|
||||
@@ -520,7 +513,7 @@ class OpenAIAssistantProvider(Generic[OptionsCoT]):
|
||||
def _create_chat_agent_from_assistant(
|
||||
self,
|
||||
assistant: Assistant,
|
||||
tools: list[FunctionTool | MutableMapping[str, Any]] | None,
|
||||
tools: list[FunctionTool | MutableMapping[str, Any] | Any] | None,
|
||||
instructions: str | None,
|
||||
middleware: Sequence[MiddlewareTypes] | None,
|
||||
context_providers: Sequence[BaseContextProvider] | None,
|
||||
|
||||
@@ -36,6 +36,7 @@ from .._tools import (
|
||||
FunctionInvocationConfiguration,
|
||||
FunctionInvocationLayer,
|
||||
FunctionTool,
|
||||
normalize_tools,
|
||||
)
|
||||
from .._types import (
|
||||
ChatOptions,
|
||||
@@ -686,26 +687,26 @@ class OpenAIAssistantsClient( # type: ignore[misc]
|
||||
tool_definitions: list[MutableMapping[str, Any]] = []
|
||||
# Always include tools if provided, regardless of tool_choice
|
||||
# tool_choice="none" means the model won't call tools, but tools should still be available
|
||||
if tools is not None:
|
||||
for tool in tools:
|
||||
if isinstance(tool, FunctionTool):
|
||||
tool_definitions.append(tool.to_json_schema_spec()) # type: ignore[reportUnknownArgumentType]
|
||||
elif isinstance(tool, MutableMapping):
|
||||
# Pass through dict-based tools directly (from static factory methods)
|
||||
tool_definitions.append(tool)
|
||||
for tool in normalize_tools(tools):
|
||||
if isinstance(tool, FunctionTool):
|
||||
tool_definitions.append(tool.to_json_schema_spec()) # type: ignore[reportUnknownArgumentType]
|
||||
elif isinstance(tool, MutableMapping):
|
||||
# Pass through dict-based tools directly (from static factory methods)
|
||||
tool_definitions.append(tool)
|
||||
|
||||
if len(tool_definitions) > 0:
|
||||
run_options["tools"] = tool_definitions
|
||||
|
||||
if (mode := tool_mode["mode"]) == "required" and (
|
||||
func_name := tool_mode.get("required_function_name")
|
||||
) is not None:
|
||||
run_options["tool_choice"] = {
|
||||
"type": "function",
|
||||
"function": {"name": func_name},
|
||||
}
|
||||
else:
|
||||
run_options["tool_choice"] = mode
|
||||
if tool_mode is not None:
|
||||
if (mode := tool_mode["mode"]) == "required" and (
|
||||
func_name := tool_mode.get("required_function_name")
|
||||
) is not None:
|
||||
run_options["tool_choice"] = {
|
||||
"type": "function",
|
||||
"function": {"name": func_name},
|
||||
}
|
||||
else:
|
||||
run_options["tool_choice"] = mode
|
||||
|
||||
if response_format is not None:
|
||||
if isinstance(response_format, dict):
|
||||
|
||||
@@ -27,6 +27,8 @@ from .._tools import (
|
||||
FunctionInvocationConfiguration,
|
||||
FunctionInvocationLayer,
|
||||
FunctionTool,
|
||||
ToolTypes,
|
||||
normalize_tools,
|
||||
)
|
||||
from .._types import (
|
||||
ChatOptions,
|
||||
@@ -271,21 +273,24 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
# region content creation
|
||||
|
||||
def _prepare_tools_for_openai(self, tools: Sequence[Any]) -> dict[str, Any]:
|
||||
def _prepare_tools_for_openai(
|
||||
self,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None,
|
||||
) -> dict[str, Any]:
|
||||
"""Prepare tools for the OpenAI Chat Completions API.
|
||||
|
||||
Converts FunctionTool to JSON schema format. Web search tools are routed
|
||||
to web_search_options parameter. All other tools pass through unchanged.
|
||||
|
||||
Args:
|
||||
tools: Sequence of tools to prepare.
|
||||
tools: Tool(s) to prepare.
|
||||
|
||||
Returns:
|
||||
Dict containing tools and optionally web_search_options.
|
||||
"""
|
||||
chat_tools: list[Any] = []
|
||||
web_search_options: dict[str, Any] | None = None
|
||||
for tool in tools:
|
||||
for tool in normalize_tools(tools):
|
||||
if isinstance(tool, FunctionTool):
|
||||
chat_tools.append(tool.to_json_schema_spec())
|
||||
elif isinstance(tool, MutableMapping) and tool.get("type") == "web_search":
|
||||
@@ -338,15 +343,16 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
run_options.pop("tool_choice", None)
|
||||
elif tool_choice := run_options.pop("tool_choice", None):
|
||||
tool_mode = validate_tool_mode(tool_choice)
|
||||
if (mode := tool_mode.get("mode")) == "required" and (
|
||||
func_name := tool_mode.get("required_function_name")
|
||||
) is not None:
|
||||
run_options["tool_choice"] = {
|
||||
"type": "function",
|
||||
"function": {"name": func_name},
|
||||
}
|
||||
else:
|
||||
run_options["tool_choice"] = mode
|
||||
if tool_mode is not None:
|
||||
if (mode := tool_mode.get("mode")) == "required" and (
|
||||
func_name := tool_mode.get("required_function_name")
|
||||
) is not None:
|
||||
run_options["tool_choice"] = {
|
||||
"type": "function",
|
||||
"function": {"name": func_name},
|
||||
}
|
||||
else:
|
||||
run_options["tool_choice"] = mode
|
||||
|
||||
# response format
|
||||
if response_format := options.get("response_format"):
|
||||
|
||||
@@ -822,15 +822,16 @@ class RawOpenAIResponsesClient( # type: ignore[misc]
|
||||
# tool_choice: convert ToolMode to appropriate format
|
||||
if tool_choice := options.get("tool_choice"):
|
||||
tool_mode = validate_tool_mode(tool_choice)
|
||||
if (mode := tool_mode.get("mode")) == "required" and (
|
||||
func_name := tool_mode.get("required_function_name")
|
||||
) is not None:
|
||||
run_options["tool_choice"] = {
|
||||
"type": "function",
|
||||
"name": func_name,
|
||||
}
|
||||
else:
|
||||
run_options["tool_choice"] = mode
|
||||
if tool_mode is not None:
|
||||
if (mode := tool_mode.get("mode")) == "required" and (
|
||||
func_name := tool_mode.get("required_function_name")
|
||||
) is not None:
|
||||
run_options["tool_choice"] = {
|
||||
"type": "function",
|
||||
"name": func_name,
|
||||
}
|
||||
else:
|
||||
run_options["tool_choice"] = mode
|
||||
else:
|
||||
run_options.pop("parallel_tool_calls", None)
|
||||
run_options.pop("tool_choice", None)
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Orchestrations integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-orchestrations``
|
||||
|
||||
Supported classes include:
|
||||
- SequentialBuilder
|
||||
- ConcurrentBuilder
|
||||
- GroupChatBuilder
|
||||
- MagenticBuilder
|
||||
- HandoffBuilder
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_orchestrations"
|
||||
PACKAGE_NAME = "agent-framework-orchestrations"
|
||||
_IMPORTS = [
|
||||
"__version__",
|
||||
# Sequential
|
||||
"SequentialBuilder",
|
||||
# Concurrent
|
||||
|
||||
@@ -35,7 +35,6 @@ from agent_framework_orchestrations import (
|
||||
MagenticResetSignal,
|
||||
SequentialBuilder,
|
||||
StandardMagenticManager,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
@@ -73,5 +72,4 @@ __all__ = [
|
||||
"MagenticResetSignal",
|
||||
"SequentialBuilder",
|
||||
"StandardMagenticManager",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Redis integration namespace for optional Agent Framework connectors.
|
||||
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-redis``
|
||||
|
||||
Supported classes:
|
||||
- RedisContextProvider
|
||||
- RedisHistoryProvider
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
IMPORT_PATH = "agent_framework_redis"
|
||||
PACKAGE_NAME = "agent-framework-redis"
|
||||
_IMPORTS = ["__version__", "RedisContextProvider", "RedisHistoryProvider"]
|
||||
_IMPORTS = ["RedisContextProvider", "RedisHistoryProvider"]
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
from agent_framework_redis import (
|
||||
RedisContextProvider,
|
||||
RedisHistoryProvider,
|
||||
__version__,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"RedisContextProvider",
|
||||
"RedisHistoryProvider",
|
||||
"__version__",
|
||||
]
|
||||
|
||||
@@ -45,13 +45,16 @@ all = [
|
||||
"agent-framework-ag-ui",
|
||||
"agent-framework-azure-ai-search",
|
||||
"agent-framework-anthropic",
|
||||
"agent-framework-claude",
|
||||
"agent-framework-azure-ai",
|
||||
"agent-framework-azurefunctions",
|
||||
"agent-framework-bedrock",
|
||||
"agent-framework-chatkit",
|
||||
"agent-framework-copilotstudio",
|
||||
"agent-framework-declarative",
|
||||
"agent-framework-devui",
|
||||
"agent-framework-durabletask",
|
||||
"agent-framework-foundry-local",
|
||||
"agent-framework-github-copilot",
|
||||
"agent-framework-lab",
|
||||
"agent-framework-mem0",
|
||||
|
||||
@@ -56,6 +56,36 @@ async def test_base_client_with_function_calling(chat_client_base: SupportsChatG
|
||||
assert response.messages[2].text == "done"
|
||||
|
||||
|
||||
async def test_base_client_with_function_calling_tools_in_kwargs(chat_client_base: SupportsChatGetResponse):
|
||||
exec_counter = 0
|
||||
|
||||
@tool(name="test_function", approval_mode="never_require")
|
||||
def ai_func(arg1: str) -> str:
|
||||
nonlocal exec_counter
|
||||
exec_counter += 1
|
||||
return f"Processed {arg1}"
|
||||
|
||||
chat_client_base.run_responses = [
|
||||
ChatResponse(
|
||||
messages=Message(
|
||||
role="assistant",
|
||||
contents=[
|
||||
Content.from_function_call(call_id="1", name="test_function", arguments='{"arg1": "value1"}')
|
||||
],
|
||||
)
|
||||
),
|
||||
ChatResponse(messages=Message(role="assistant", text="done")),
|
||||
]
|
||||
|
||||
response = await chat_client_base.get_response("hello", tools=[ai_func])
|
||||
|
||||
assert exec_counter == 1
|
||||
assert len(response.messages) == 3
|
||||
assert response.messages[1].role == "tool"
|
||||
assert response.messages[1].contents[0].type == "function_result"
|
||||
assert response.messages[1].contents[0].result == "Processed value1"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("max_iterations", [3])
|
||||
async def test_base_client_with_function_calling_resets(chat_client_base: SupportsChatGetResponse):
|
||||
exec_counter = 0
|
||||
|
||||
@@ -921,8 +921,8 @@ def test_chat_options_tool_choice_validation():
|
||||
}
|
||||
assert validate_tool_mode({"mode": "none"}) == {"mode": "none"}
|
||||
|
||||
# None should return mode==none
|
||||
assert validate_tool_mode(None) == {"mode": "none"}
|
||||
# None should remain unset
|
||||
assert validate_tool_mode(None) is None
|
||||
|
||||
with raises(ContentError):
|
||||
validate_tool_mode("invalid_mode")
|
||||
|
||||
@@ -701,6 +701,7 @@ def test_prepare_options_basic(mock_async_openai: MagicMock) -> None:
|
||||
assert run_options["model"] == "gpt-4"
|
||||
assert run_options["temperature"] == 0.7
|
||||
assert run_options["top_p"] == 0.9
|
||||
assert "tool_choice" not in run_options
|
||||
assert tool_results is None
|
||||
|
||||
|
||||
@@ -733,6 +734,52 @@ def test_prepare_options_with_tool_tool(mock_async_openai: MagicMock) -> None:
|
||||
assert run_options["tool_choice"] == "auto"
|
||||
|
||||
|
||||
def test_prepare_options_with_tools_without_tool_choice(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options keeps tool_choice unset when not provided."""
|
||||
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def test_function(query: str) -> str:
|
||||
"""A test function."""
|
||||
return f"Result for {query}"
|
||||
|
||||
options = {
|
||||
"tools": [test_function],
|
||||
}
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
run_options, _ = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
assert "tools" in run_options
|
||||
assert "tool_choice" not in run_options
|
||||
|
||||
|
||||
def test_prepare_options_with_single_tool_tool(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with a single FunctionTool (non-sequence)."""
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def test_function(query: str) -> str:
|
||||
"""A test function."""
|
||||
return f"Result for {query}"
|
||||
|
||||
options = {
|
||||
"tools": test_function,
|
||||
"tool_choice": "auto",
|
||||
}
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
assert "tools" in run_options
|
||||
assert len(run_options["tools"]) == 1
|
||||
assert run_options["tools"][0]["type"] == "function"
|
||||
assert "function" in run_options["tools"][0]
|
||||
assert run_options["tool_choice"] == "auto"
|
||||
assert tool_results is None
|
||||
|
||||
|
||||
def test_prepare_options_with_code_interpreter(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with code interpreter tool."""
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
@@ -190,6 +190,21 @@ def test_unsupported_tool_handling(openai_unit_test_env: dict[str, str]) -> None
|
||||
assert result["tools"] == [dict_tool]
|
||||
|
||||
|
||||
def test_prepare_tools_with_single_function_tool(openai_unit_test_env: dict[str, str]) -> None:
|
||||
"""Test that a single FunctionTool is accepted for tool preparation."""
|
||||
client = OpenAIChatClient()
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def test_function(query: str) -> str:
|
||||
"""A test function."""
|
||||
return f"Result for {query}"
|
||||
|
||||
result = client._prepare_tools_for_openai(test_function)
|
||||
assert "tools" in result
|
||||
assert len(result["tools"]) == 1
|
||||
assert result["tools"][0]["type"] == "function"
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def get_story_text() -> str:
|
||||
"""Returns a story about Emily and David."""
|
||||
|
||||
@@ -7,3 +7,7 @@ pip install agent-framework-foundry-local --pre
|
||||
```
|
||||
|
||||
and see the [README](https://github.com/microsoft/agent-framework/tree/main/python/README.md) for more information.
|
||||
|
||||
## Foundry Local Sample
|
||||
|
||||
See the [Foundry Local provider sample](../../samples/02-agents/providers/foundry_local/foundry_local_agent.py) for a runnable example.
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
# ruff: noqa
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from random import randint
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
from agent_framework_foundry_local import FoundryLocalClient
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agent_framework import Agent
|
||||
|
||||
"""
|
||||
This sample demonstrates basic usage of the FoundryLocalClient.
|
||||
Shows both streaming and non-streaming responses with function tools.
|
||||
|
||||
Running this sample the first time will be slow, as the model needs to be
|
||||
downloaded and initialized.
|
||||
|
||||
Also, not every model supports function calling, so be sure to check the
|
||||
model capabilities in the Foundry catalog, or pick one from the list printed
|
||||
when running this sample.
|
||||
"""
|
||||
|
||||
|
||||
def get_weather(
|
||||
location: Annotated[str, "The location to get the weather for."],
|
||||
) -> str:
|
||||
"""Get the weather for a given location."""
|
||||
conditions = ["sunny", "cloudy", "rainy", "stormy"]
|
||||
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
|
||||
|
||||
|
||||
async def non_streaming_example(agent: Agent) -> None:
|
||||
"""Example of non-streaming response (get the complete result at once)."""
|
||||
print("=== Non-streaming Response Example ===")
|
||||
|
||||
query = "What's the weather like in Seattle?"
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
|
||||
async def streaming_example(agent: Agent) -> None:
|
||||
"""Example of streaming response (get results as they are generated)."""
|
||||
print("=== Streaming Response Example ===")
|
||||
|
||||
query = "What's the weather like in Amsterdam?"
|
||||
print(f"User: {query}")
|
||||
print("Agent: ", end="", flush=True)
|
||||
async for chunk in agent.run(query, stream=True):
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
print("\n")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=== Basic Foundry Local Client Agent Example ===")
|
||||
|
||||
client = FoundryLocalClient(model_id="phi-4-mini")
|
||||
print(f"Client Model ID: {client.model_id}\n")
|
||||
print("Other available models (tool calling supported only):")
|
||||
for model in client.manager.list_catalog_models():
|
||||
if model.supports_tool_calling:
|
||||
print(
|
||||
f"- {model.alias} for {model.task} - id={model.id} - {(model.file_size_mb / 1000):.2f} GB - {model.license}"
|
||||
)
|
||||
agent = client.as_agent(
|
||||
name="LocalAgent",
|
||||
instructions="You are a helpful agent.",
|
||||
tools=get_weather,
|
||||
)
|
||||
await non_streaming_example(agent)
|
||||
await streaming_example(agent)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -22,7 +22,7 @@ from agent_framework import (
|
||||
normalize_messages,
|
||||
)
|
||||
from agent_framework._settings import load_settings
|
||||
from agent_framework._tools import FunctionTool
|
||||
from agent_framework._tools import FunctionTool, ToolTypes
|
||||
from agent_framework._types import AgentRunInputs, normalize_tools
|
||||
from agent_framework.exceptions import ServiceException
|
||||
from copilot import CopilotClient, CopilotSession
|
||||
@@ -151,11 +151,7 @@ class GitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
||||
description: str | None = None,
|
||||
context_providers: Sequence[BaseContextProvider] | None = None,
|
||||
middleware: Sequence[AgentMiddlewareTypes] | None = None,
|
||||
tools: FunctionTool
|
||||
| Callable[..., Any]
|
||||
| MutableMapping[str, Any]
|
||||
| Sequence[FunctionTool | Callable[..., Any] | MutableMapping[str, Any]]
|
||||
| None = None,
|
||||
tools: ToolTypes | Callable[..., Any] | Sequence[ToolTypes | Callable[..., Any]] | None = None,
|
||||
default_options: OptionsT | None = None,
|
||||
env_file_path: str | None = None,
|
||||
env_file_encoding: str | None = None,
|
||||
@@ -478,7 +474,7 @@ class GitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
||||
|
||||
def _prepare_tools(
|
||||
self,
|
||||
tools: list[FunctionTool | MutableMapping[str, Any]],
|
||||
tools: Sequence[ToolTypes | CopilotTool],
|
||||
) -> list[CopilotTool]:
|
||||
"""Convert Agent Framework tools to Copilot SDK tools.
|
||||
|
||||
@@ -491,10 +487,12 @@ class GitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
||||
copilot_tools: list[CopilotTool] = []
|
||||
|
||||
for tool in tools:
|
||||
if isinstance(tool, FunctionTool):
|
||||
copilot_tools.append(self._tool_to_copilot_tool(tool)) # type: ignore
|
||||
elif isinstance(tool, CopilotTool):
|
||||
if isinstance(tool, CopilotTool):
|
||||
copilot_tools.append(tool)
|
||||
elif isinstance(tool, FunctionTool):
|
||||
copilot_tools.append(self._tool_to_copilot_tool(tool)) # type: ignore
|
||||
elif isinstance(tool, MutableMapping):
|
||||
copilot_tools.append(tool) # type: ignore[arg-type]
|
||||
# Note: Other tool types (e.g., dict-based hosted tools) are skipped
|
||||
|
||||
return copilot_tools
|
||||
|
||||
Reference in New Issue
Block a user