Python: replace pre-commit with prek, add PEP 723 script deps, clean up dev dependencies (#3748)

* python: replace pre-commit with prek, add PEP 723 script deps, clean up dev dependencies

- Replace pre-commit with prek (Rust-native, faster pre-commit alternative)
- Move supported hooks to repo: builtin for zero-clone speed
- Add new builtin hooks: trailing-whitespace, check-merge-conflict, detect-private-key, check-added-large-files
- Update all hook versions to latest (pre-commit-hooks v6, pyupgrade v3.21.2, bandit 1.9.3, uv-pre-commit 0.10.0)
- Add PEP 723 inline script metadata to 34 samples with external deps
- Remove autogen-agentchat/autogen-ext from dev deps (now declared per-sample)
- Remove unused dev deps: pytest-env, tomli-w
- Add agent-framework-core>=1.0.0b260130 lower bound to all 21 packages
- Update CI workflow to use j178/prek-action
- Update docs: DEV_SETUP.md, AGENTS.md, CODING_STANDARD.md, SAMPLE_GUIDELINES.md

* updated lock

* python: fix prek config paths for local execution and CI workflow

Remove global 'files: ^python/' filter and strip python/ prefix from all path patterns in .pre-commit-config.yaml so prek finds files when run from the python/ directory. Update CI workflow to use --cd python instead of --config path. Include trailing whitespace fixes and dev dependency cleanup.

* python: move helper scripts to scripts/ folder and exclude from checks

* python: exclude AGENTS.md from prek markdown code lint

* python: exclude AGENTS.md and azure_ai_search sample from markdown lint

* fix m365 sample

* python: ignore CPY rule for samples with PEP 723 headers

* fix in dev_setup

* python: replace aiofiles with regular open in samples

* python: suppress reportUnusedImport in markdown code block checker

* python: use samples pyright config for markdown code block checker

Write a temp pyrightconfig.json matching pyrightconfig.samples.json rules (typeCheckingMode=off, only reportMissingImports and reportAttributeAccessIssue). Filter output to only fail on these rules since syntax-level errors (top-level await, undefined vars) are expected in README documentation snippets.

* python: use markdown-code-lint with fixed globs instead of prek file list

The prek-markdown-code-lint task received all changed files including non-README markdown and files with pre-existing broken imports. Replace with the standard markdown-code-lint task which uses the correct glob patterns (README.md, packages/**/README.md, samples/**/*.md).

* python: exclude READMEs with pre-existing broken imports from markdown lint

* python: fix broken README code snippets instead of excluding them

- ag-ui: replace TextContent (removed) with content.type == 'text'
- durabletask: fix import path to durabletask.worker.TaskHubGrpcWorker
- orchestrations: use constructor params instead of .participants() method
- observability: mark deprecated code blocks as plain text, filter
  reportMissingImports to agent_framework modules only
- remove README excludes from markdown-code-lint task

* add revision to gaia download

* feat(python): parallelize checks across packages

Run (package × task) cross-product in parallel using ThreadPoolExecutor
and subprocesses. Key changes:

- Add scripts/task_runner.py with shared parallel execution engine
- Update run_tasks_in_packages_if_exists.py to accept multiple tasks
- Update run_tasks_in_changed_packages.py with --files flag and parallel support
- Add check-packages poe task (fmt+lint+pyright+mypy in parallel)
- Add prek-markdown-code-lint and prek-samples-check with change detection
- Split CI code quality workflow into parallel prek and mypy jobs
- Update DEV_SETUP.md to document new parallel behavior

Core package changes still trigger checks on all packages.

* feat(ci): split code quality into 4 parallel jobs

Split the single prek job into parallel jobs:
- pre-commit-hooks: lightweight hooks (SKIP=poe-check)
- package-checks: fmt/lint/pyright/mypy via check-packages
- samples-markdown: samples-lint, samples-syntax, markdown-code-lint
- mypy: change-detected mypy checks

All 4 jobs run concurrently (×2 Python versions = 8 runners).

* feat(ci): use only Python 3.10 for code quality checks

* refactor(python): add future annotations and remove quoted types

Add `from __future__ import annotations` to 93 package files that
used quoted string annotations, then run pyupgrade --py310-plus to
remove the now-unnecessary quotes.

Fixes https://github.com/microsoft/agent-framework/issues/3578
This commit is contained in:
Eduard van Valkenburg
2026-02-09 18:51:01 +01:00
committed by GitHub
Unverified
parent ad0dac3c86
commit 977c3adfb2
177 changed files with 1373 additions and 1010 deletions
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import base64
import json
import re
@@ -169,7 +171,7 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
msg = f"Invalid timeout type: {type(timeout)}. Expected float, httpx.Timeout, or None."
raise TypeError(msg)
async def __aenter__(self) -> "A2AAgent":
async def __aenter__(self) -> A2AAgent:
"""Async context manager entry."""
return self
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"a2a-sdk>=0.3.5",
]
+1 -2
View File
@@ -40,7 +40,6 @@ add_agent_framework_fastapi_endpoint(app, agent, "/")
```python
import asyncio
from agent_framework import TextContent
from agent_framework.ag_ui import AGUIChatClient
async def main():
@@ -48,7 +47,7 @@ async def main():
# Stream responses
async for update in client.get_response("Hello!", stream=True):
for content in update.contents:
if isinstance(content, TextContent):
if content.type == "text" and content.text:
print(content.text, end="", flush=True)
print()
@@ -2,6 +2,8 @@
"""AG-UI Chat Client implementation."""
from __future__ import annotations
import json
import logging
import sys
@@ -216,7 +218,7 @@ class AGUIChatClient(
http_client: httpx.AsyncClient | None = None,
timeout: float = 60.0,
additional_properties: dict[str, Any] | None = None,
middleware: Sequence["ChatAndFunctionMiddlewareTypes"] | None = None,
middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
**kwargs: Any,
) -> None:
@@ -2,6 +2,8 @@
"""FastAPI endpoint creation for AG-UI agents."""
from __future__ import annotations
import copy
import logging
from collections.abc import AsyncGenerator, Sequence
@@ -77,7 +79,7 @@ def add_agent_framework_fastapi_endpoint(
)
logger.info(f"Received request at {path}: {input_data.get('run_id', 'no-run-id')}")
async def event_generator() -> AsyncGenerator[str, None]:
async def event_generator() -> AsyncGenerator[str]:
encoder = EventEncoder()
event_count = 0
async for event in wrapped_agent.run_agent(input_data):
@@ -2,6 +2,8 @@
"""Event converter for AG-UI protocol events to Agent Framework types."""
from __future__ import annotations
from typing import Any
from agent_framework import (
@@ -2,6 +2,8 @@
"""HTTP service for AG-UI protocol communication."""
from __future__ import annotations
import json
import logging
from collections.abc import AsyncIterable
@@ -148,7 +150,7 @@ class AGUIHttpService:
if self._owns_client and self.http_client:
await self.http_client.aclose()
async def __aenter__(self) -> "AGUIHttpService":
async def __aenter__(self) -> AGUIHttpService:
"""Enter async context manager."""
return self
@@ -2,6 +2,8 @@
"""Message format conversion between AG-UI and Agent Framework."""
from __future__ import annotations
import json
import logging
from typing import Any, cast
@@ -6,6 +6,8 @@ Most orchestration helpers have been moved inline to _run.py.
This module retains utilities that may be useful for testing or extensions.
"""
from __future__ import annotations
import json
import logging
from typing import Any
@@ -2,6 +2,8 @@
"""Predictive state handling utilities."""
from __future__ import annotations
import json
import logging
import re
@@ -2,6 +2,8 @@
"""Tool handling helpers."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Any
@@ -29,7 +31,7 @@ def _collect_mcp_tool_functions(mcp_tools: list[Any]) -> list[Any]:
return functions
def collect_server_tools(agent: "SupportsAgentRun") -> list[Any]:
def collect_server_tools(agent: SupportsAgentRun) -> list[Any]:
"""Collect server tools from an agent.
This includes both regular tools from default_options and MCP tools.
@@ -64,7 +66,7 @@ def collect_server_tools(agent: "SupportsAgentRun") -> list[Any]:
return server_tools
def register_additional_client_tools(agent: "SupportsAgentRun", client_tools: list[Any] | None) -> None:
def register_additional_client_tools(agent: SupportsAgentRun, client_tools: list[Any] | None) -> None:
"""Register client tools as additional declaration-only tools to avoid server execution.
Args:
@@ -2,6 +2,8 @@
"""Simplified AG-UI orchestration - single linear flow."""
from __future__ import annotations
import json
import logging
import uuid
@@ -742,8 +744,8 @@ def _build_messages_snapshot(
async def run_agent_stream(
input_data: dict[str, Any],
agent: SupportsAgentRun,
config: "AgentConfig",
) -> "AsyncGenerator[BaseEvent, None]":
config: AgentConfig,
) -> AsyncGenerator[BaseEvent]:
"""Run agent and yield AG-UI events.
This is the single entry point for all AG-UI agent runs. It follows a simple
@@ -2,6 +2,8 @@
"""Utility functions for AG-UI integration."""
from __future__ import annotations
import copy
import json
import uuid
@@ -2,6 +2,8 @@
"""Example agent demonstrating predictive state updates with document writing."""
from __future__ import annotations
from agent_framework import ChatAgent, ChatClientProtocol, tool
from agent_framework.ag_ui import AgentFrameworkAgent
@@ -2,6 +2,8 @@
"""Recipe agent example demonstrating shared state management (Feature 3)."""
from __future__ import annotations
from enum import Enum
from typing import Any
@@ -2,6 +2,8 @@
"""Task steps agent demonstrating agentic generative UI (Feature 6)."""
from __future__ import annotations
import asyncio
from collections.abc import AsyncGenerator
from enum import Enum
@@ -128,7 +130,7 @@ class TaskStepsAgentWithExecution:
"""Delegate all other attribute access to base agent."""
return getattr(self._base_agent, name)
async def run_agent(self, input_data: dict[str, Any]) -> AsyncGenerator[Any, None]:
async def run_agent(self, input_data: dict[str, Any]) -> AsyncGenerator[Any]:
"""Run the agent and then simulate step execution."""
import logging
import uuid
@@ -2,6 +2,8 @@
"""Example agent demonstrating Tool-based Generative UI (Feature 5)."""
from __future__ import annotations
import sys
from typing import TYPE_CHECKING, Any, TypedDict
@@ -2,6 +2,8 @@
"""Weather agent example demonstrating backend tool rendering."""
from __future__ import annotations
from typing import Any
from agent_framework import ChatAgent, ChatClientProtocol, tool
@@ -2,6 +2,8 @@
"""Example FastAPI server with AG-UI endpoints."""
from __future__ import annotations
import logging
import os
from typing import cast
@@ -292,7 +292,6 @@ Create a file named `client.py`:
import asyncio
import os
from agent_framework import TextContent
from agent_framework.ag_ui import AGUIChatClient
@@ -333,7 +332,7 @@ async def main():
# Stream text content as it arrives
for content in update.contents:
if isinstance(content, TextContent) and content.text:
if content.type == "text" and content.text:
print(content.text, end="", flush=True)
print() # New line after response
@@ -9,6 +9,8 @@ This example demonstrates advanced AGUIChatClient features including:
- Error handling
"""
from __future__ import annotations
import asyncio
import os
from typing import cast
@@ -18,6 +18,8 @@ This demonstrates the HYBRID pattern matching .NET AGUIClient implementation:
This matches .NET pattern: thread maintains state, tools execute on appropriate side.
"""
from __future__ import annotations
import asyncio
import logging
import os
@@ -2,6 +2,8 @@
"""AG-UI server example with server-side tools."""
from __future__ import annotations
import logging
import os
+1 -1
View File
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"ag-ui-protocol>=0.1.9",
"fastapi>=0.115.0",
"uvicorn>=0.30.0"
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import AsyncIterable, Awaitable, Mapping, MutableMapping, Sequence
from typing import Any, ClassVar, Final, Generic, Literal, TypedDict
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"anthropic>=0.70.0,<1",
]
@@ -1,6 +1,8 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Awaitable, Callable, MutableSequence
from typing import TYPE_CHECKING, Any, ClassVar, Literal
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"azure-search-documents==11.7.0b2",
]
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Callable, MutableMapping, Sequence
from typing import TYPE_CHECKING, Any, Generic, cast
@@ -141,7 +143,7 @@ class AzureAIAgentsProvider(Generic[TOptions_co]):
)
self._should_close_client = True
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Async context manager entry."""
return self
@@ -177,7 +179,7 @@ class AzureAIAgentsProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a new agent on the Azure AI service and return a ChatAgent.
This method creates a persistent agent on the Azure AI service with the specified
@@ -274,7 +276,7 @@ class AzureAIAgentsProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Retrieve an existing agent from the service and return a ChatAgent.
This method fetches an agent by ID from the Azure AI service
@@ -330,7 +332,7 @@ class AzureAIAgentsProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Wrap an existing Agent SDK object as a ChatAgent without making HTTP calls.
Use this method when you already have an Agent object from a previous
@@ -383,7 +385,7 @@ class AzureAIAgentsProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a ChatAgent from an Agent SDK object.
Args:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import ast
import json
import os
@@ -346,7 +348,7 @@ class AzureAIAgentClient(
self._should_close_client = should_close_client # Track whether we should close client connection
self._agent_definition: Agent | None = None # Cached definition for existing agent
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Async context manager entry."""
return self
@@ -1047,9 +1049,7 @@ class AzureAIAgentClient(
return tool_definitions
def _prepare_mcp_resources(
self, tools: Sequence["ToolProtocol | MutableMapping[str, Any]"]
) -> list[dict[str, Any]]:
def _prepare_mcp_resources(self, tools: Sequence[ToolProtocol | MutableMapping[str, Any]]) -> list[dict[str, Any]]:
"""Prepare MCP tool resources for approval mode configuration."""
mcp_tools = [tool for tool in tools if isinstance(tool, HostedMCPTool)]
if not mcp_tools:
@@ -1142,7 +1142,7 @@ class AzureAIAgentClient(
return additional_messages, instructions, required_action_results
async def _prepare_tools_for_azure_ai(
self, tools: Sequence["ToolProtocol | MutableMapping[str, Any]"], run_options: dict[str, Any] | None = None
self, tools: Sequence[ToolProtocol | MutableMapping[str, Any]], run_options: dict[str, Any] | None = None
) -> list[ToolDefinition | dict[str, Any]]:
"""Prepare tool definitions for the Azure AI Agents API."""
tool_definitions: list[ToolDefinition | dict[str, Any]] = []
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Callable, Mapping, MutableMapping, Sequence
from typing import Any, ClassVar, Generic, TypedDict, TypeVar, cast
@@ -295,7 +297,7 @@ class RawAzureAIClient(RawOpenAIResponsesClient[TAzureAIClientOptions], Generic[
# Complete setup with core observability
enable_instrumentation(enable_sensitive_data=enable_sensitive_data)
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Async context manager entry."""
return self
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Callable, MutableMapping, Sequence
from typing import Any, Generic
@@ -168,7 +170,7 @@ class AzureAIProjectAgentProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a new agent on the Azure AI service and return a local ChatAgent wrapper.
Args:
@@ -270,7 +272,7 @@ class AzureAIProjectAgentProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Retrieve an existing agent from the Azure AI service and return a local ChatAgent wrapper.
You must provide either name or reference. Use `as_agent()` if you already have
@@ -330,7 +332,7 @@ class AzureAIProjectAgentProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Wrap an SDK agent version object into a ChatAgent without making HTTP calls.
Use this when you already have an AgentVersionDetails from a previous API call.
@@ -370,7 +372,7 @@ class AzureAIProjectAgentProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a ChatAgent from an AgentVersionDetails.
Args:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import os
from collections.abc import Mapping, MutableMapping, Sequence
from typing import Any, ClassVar, Literal, cast
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"azure-ai-projects >= 2.0.0b3",
"azure-ai-agents == 1.2.0b5",
"aiohttp",
@@ -6,6 +6,8 @@ This module provides the AgentFunctionApp class that integrates Microsoft Agent
with Azure Durable Entities, enabling stateful and durable AI agent execution.
"""
from __future__ import annotations
import json
import re
import uuid
@@ -7,6 +7,8 @@ Using entities instead of orchestrations provides better state management and
allows for long-running agent conversations.
"""
from __future__ import annotations
import asyncio
from collections.abc import Callable
from typing import Any, cast
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"agent-framework-durabletask",
"azure-functions",
"azure-functions-durable",
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import asyncio
import json
import sys
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"boto3>=1.35.0,<2.0.0",
"botocore>=1.35.0,<2.0.0",
]
@@ -2,6 +2,8 @@
"""Converter utilities for converting ChatKit thread items to Agent Framework messages."""
from __future__ import annotations
import logging
import sys
from collections.abc import Awaitable, Callable, Sequence
+1 -1
View File
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"openai-chatkit>=1.4.0,<2.0.0",
]
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import contextlib
import sys
from collections.abc import AsyncIterable, Awaitable, Callable, MutableMapping, Sequence
@@ -100,13 +102,13 @@ class ClaudeAgentOptions(TypedDict, total=False):
disallowed_tools: list[str]
"""Blocklist of tools. Claude cannot use these tools."""
mcp_servers: dict[str, "McpServerConfig"]
mcp_servers: dict[str, McpServerConfig]
"""MCP server configurations for external tools."""
permission_mode: "PermissionMode"
permission_mode: PermissionMode
"""Permission handling mode ("default", "acceptEdits", "plan", "bypassPermissions")."""
can_use_tool: "CanUseTool"
can_use_tool: CanUseTool
"""Permission callback for tool use."""
max_turns: int
@@ -115,16 +117,16 @@ class ClaudeAgentOptions(TypedDict, total=False):
max_budget_usd: float
"""Budget limit in USD."""
hooks: dict[str, list["HookMatcher"]]
hooks: dict[str, list[HookMatcher]]
"""Pre/post tool hooks."""
add_dirs: list[str | Path]
"""Additional directories to add to context."""
sandbox: "SandboxSettings"
sandbox: SandboxSettings
"""Sandbox configuration for bash isolation."""
agents: dict[str, "AgentDefinition"]
agents: dict[str, AgentDefinition]
"""Custom agent definitions."""
output_format: dict[str, Any]
@@ -133,7 +135,7 @@ class ClaudeAgentOptions(TypedDict, total=False):
enable_file_checkpointing: bool
"""Enable file checkpointing for rewind."""
betas: list["SdkBeta"]
betas: list[SdkBeta]
"""Beta features to enable."""
@@ -328,7 +330,7 @@ class ClaudeAgent(BaseAgent, Generic[TOptions]):
normalized = normalize_tools(tool)
self._custom_tools.extend(normalized)
async def __aenter__(self) -> "ClaudeAgent[TOptions]":
async def __aenter__(self) -> ClaudeAgent[TOptions]:
"""Start the agent when entering async context."""
await self.start()
return self
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"claude-agent-sdk>=0.1.25",
]
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from collections.abc import AsyncIterable, Awaitable, Sequence
from typing import Any, ClassVar, Literal, overload
@@ -213,7 +215,7 @@ class CopilotStudioAgent(BaseAgent):
stream: Literal[False] = False,
thread: AgentThread | None = None,
**kwargs: Any,
) -> "Awaitable[AgentResponse]": ...
) -> Awaitable[AgentResponse]: ...
@overload
def run(
@@ -232,7 +234,7 @@ class CopilotStudioAgent(BaseAgent):
stream: bool = False,
thread: AgentThread | None = None,
**kwargs: Any,
) -> "Awaitable[AgentResponse] | ResponseStream[AgentResponseUpdate, AgentResponse]":
) -> Awaitable[AgentResponse] | ResponseStream[AgentResponseUpdate, AgentResponse]:
"""Get a response from the agent.
This method returns the final result of the agent's execution
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"microsoft-agents-copilotstudio-client>=0.3.1",
]
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import inspect
import re
import sys
@@ -729,7 +731,7 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
self._async_exit_stack = AsyncExitStack()
self._update_agent_name_and_description()
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Enter the async context manager.
If any of the chat_client or local_mcp_tools are context managers,
@@ -787,7 +789,7 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
| MutableMapping[str, Any]
| list[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
options: "ChatOptions[TResponseModelT]",
options: ChatOptions[TResponseModelT],
**kwargs: Any,
) -> Awaitable[AgentResponse[TResponseModelT]]: ...
@@ -803,7 +805,7 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
| MutableMapping[str, Any]
| list[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
options: "TOptions_co | ChatOptions[None] | None" = None,
options: TOptions_co | ChatOptions[None] | None = None,
**kwargs: Any,
) -> Awaitable[AgentResponse[Any]]: ...
@@ -819,7 +821,7 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
| MutableMapping[str, Any]
| list[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
options: "TOptions_co | ChatOptions[Any] | None" = None,
options: TOptions_co | ChatOptions[Any] | None = None,
**kwargs: Any,
) -> ResponseStream[AgentResponseUpdate, AgentResponse[Any]]: ...
@@ -834,7 +836,7 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
| MutableMapping[str, Any]
| list[ToolProtocol | Callable[..., Any] | MutableMapping[str, Any]]
| None = None,
options: "TOptions_co | ChatOptions[Any] | None" = None,
options: TOptions_co | ChatOptions[Any] | None = None,
**kwargs: Any,
) -> Awaitable[AgentResponse[Any]] | ResponseStream[AgentResponseUpdate, AgentResponse[Any]]:
"""Run the agent with the given messages and options.
@@ -1149,9 +1151,9 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
server_name: str = "Agent",
version: str | None = None,
instructions: str | None = None,
lifespan: Callable[["Server[Any]"], AbstractAsyncContextManager[Any]] | None = None,
lifespan: Callable[[Server[Any]], AbstractAsyncContextManager[Any]] | None = None,
**kwargs: Any,
) -> "Server[Any]":
) -> Server[Any]:
"""Create an MCP server from an agent instance.
This function automatically creates a MCP server from an agent instance, it uses the provided arguments to
@@ -1177,7 +1179,7 @@ class RawChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
if kwargs:
server_args.update(kwargs)
server: "Server[Any]" = Server(**server_args) # type: ignore[call-arg]
server: Server[Any] = Server(**server_args) # type: ignore[call-arg]
agent_tool = self.as_tool(name=self._get_agent_name())
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from abc import ABC, abstractmethod
from collections.abc import (
@@ -137,7 +139,7 @@ class ChatClientProtocol(Protocol[TOptions_contra]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: Literal[False] = ...,
options: "ChatOptions[TResponseModelT]",
options: ChatOptions[TResponseModelT],
**kwargs: Any,
) -> Awaitable[ChatResponse[TResponseModelT]]: ...
@@ -147,7 +149,7 @@ class ChatClientProtocol(Protocol[TOptions_contra]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: Literal[False] = ...,
options: "TOptions_contra | ChatOptions[None] | None" = None,
options: TOptions_contra | ChatOptions[None] | None = None,
**kwargs: Any,
) -> Awaitable[ChatResponse[Any]]: ...
@@ -157,7 +159,7 @@ class ChatClientProtocol(Protocol[TOptions_contra]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: Literal[True],
options: "TOptions_contra | ChatOptions[Any] | None" = None,
options: TOptions_contra | ChatOptions[Any] | None = None,
**kwargs: Any,
) -> ResponseStream[ChatResponseUpdate, ChatResponse[Any]]: ...
@@ -166,7 +168,7 @@ class ChatClientProtocol(Protocol[TOptions_contra]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: bool = False,
options: "TOptions_contra | ChatOptions[Any] | None" = None,
options: TOptions_contra | ChatOptions[Any] | None = None,
**kwargs: Any,
) -> Awaitable[ChatResponse[Any]] | ResponseStream[ChatResponseUpdate, ChatResponse[Any]]:
"""Send input and return the response.
@@ -366,7 +368,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[TOptions_co]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: Literal[False] = ...,
options: "ChatOptions[TResponseModelT]",
options: ChatOptions[TResponseModelT],
**kwargs: Any,
) -> Awaitable[ChatResponse[TResponseModelT]]: ...
@@ -376,7 +378,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[TOptions_co]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: Literal[False] = ...,
options: "TOptions_co | ChatOptions[None] | None" = None,
options: TOptions_co | ChatOptions[None] | None = None,
**kwargs: Any,
) -> Awaitable[ChatResponse[Any]]: ...
@@ -386,7 +388,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[TOptions_co]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: Literal[True],
options: "TOptions_co | ChatOptions[Any] | None" = None,
options: TOptions_co | ChatOptions[Any] | None = None,
**kwargs: Any,
) -> ResponseStream[ChatResponseUpdate, ChatResponse[Any]]: ...
@@ -395,7 +397,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[TOptions_co]):
messages: str | ChatMessage | Sequence[str | ChatMessage],
*,
stream: bool = False,
options: "TOptions_co | ChatOptions[Any] | None" = None,
options: TOptions_co | ChatOptions[Any] | None = None,
**kwargs: Any,
) -> Awaitable[ChatResponse[Any]] | ResponseStream[ChatResponseUpdate, ChatResponse[Any]]:
"""Get a response from a chat client.
@@ -443,10 +445,10 @@ class BaseChatClient(SerializationMixin, ABC, Generic[TOptions_co]):
default_options: TOptions_co | Mapping[str, Any] | None = None,
chat_message_store_factory: Callable[[], ChatMessageStoreProtocol] | None = None,
context_provider: ContextProvider | None = None,
middleware: Sequence["MiddlewareTypes"] | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
**kwargs: Any,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a ChatAgent with this client.
This is a convenience method that creates a ChatAgent instance with this
+6 -4
View File
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import asyncio
import base64
import logging
@@ -333,7 +335,7 @@ class MCPTool:
parse_prompt_results: Literal[True] | Callable[[types.GetPromptResult], Any] | None = True,
session: ClientSession | None = None,
request_timeout: int | None = None,
chat_client: "ChatClientProtocol | None" = None,
chat_client: ChatClientProtocol | None = None,
additional_properties: dict[str, Any] | None = None,
) -> None:
"""Initialize the MCP Tool base.
@@ -940,7 +942,7 @@ class MCPStdioTool(MCPTool):
args: list[str] | None = None,
env: dict[str, str] | None = None,
encoding: str | None = None,
chat_client: "ChatClientProtocol | None" = None,
chat_client: ChatClientProtocol | None = None,
additional_properties: dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
@@ -1059,7 +1061,7 @@ class MCPStreamableHTTPTool(MCPTool):
approval_mode: (Literal["always_require", "never_require"] | HostedMCPSpecificApproval | None) = None,
allowed_tools: Collection[str] | None = None,
terminate_on_close: bool | None = None,
chat_client: "ChatClientProtocol | None" = None,
chat_client: ChatClientProtocol | None = None,
additional_properties: dict[str, Any] | None = None,
http_client: httpx.AsyncClient | None = None,
**kwargs: Any,
@@ -1173,7 +1175,7 @@ class MCPWebsocketTool(MCPTool):
description: str | None = None,
approval_mode: (Literal["always_require", "never_require"] | HostedMCPSpecificApproval | None) = None,
allowed_tools: Collection[str] | None = None,
chat_client: "ChatClientProtocol | None" = None,
chat_client: ChatClientProtocol | None = None,
additional_properties: dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from abc import ABC, abstractmethod
from collections.abc import MutableSequence, Sequence
@@ -50,7 +52,7 @@ class Context:
self,
instructions: str | None = None,
messages: Sequence[ChatMessage] | None = None,
tools: Sequence["ToolProtocol"] | None = None,
tools: Sequence[ToolProtocol] | None = None,
):
"""Create a new Context object.
@@ -61,7 +63,7 @@ class Context:
"""
self.instructions = instructions
self.messages: Sequence[ChatMessage] = messages or []
self.tools: Sequence["ToolProtocol"] = tools or []
self.tools: Sequence[ToolProtocol] = tools or []
# region ContextProvider
@@ -151,7 +153,7 @@ class ContextProvider(ABC):
"""
pass
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Enter the async context manager.
Override this method to perform any setup operations when the context provider is entered.
@@ -1,6 +1,8 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from typing import Annotated, Any, ClassVar, TypeVar
from pydantic import Field, UrlConstraints
@@ -48,7 +50,7 @@ class AFBaseSettings(BaseSettings):
kwargs = {k: v for k, v in kwargs.items() if v is not None}
super().__init__(**kwargs)
def __new__(cls: type["TSettings"], *args: Any, **kwargs: Any) -> "TSettings":
def __new__(cls: type[TSettings], *args: Any, **kwargs: Any) -> TSettings:
"""Override the __new__ method to set the env_prefix."""
# for both, if supplied but None, set to default
if "env_file_encoding" in kwargs and kwargs["env_file_encoding"] is not None:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import json
import re
from collections.abc import Mapping, MutableMapping
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import os
from typing import Any, Final
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from collections.abc import MutableMapping, Sequence
from typing import Any, Protocol, TypeVar
@@ -74,7 +76,7 @@ class ChatMessageStoreProtocol(Protocol):
@classmethod
async def deserialize(
cls, serialized_store_state: MutableMapping[str, Any], **kwargs: Any
) -> "ChatMessageStoreProtocol":
) -> ChatMessageStoreProtocol:
"""Creates a new instance of the store from previously serialized state.
This method, together with ``serialize()`` can be used to save and load messages from a persistent store
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import contextlib
import importlib
import logging
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any, ClassVar, Generic
@@ -63,7 +65,7 @@ class AzureOpenAIAssistantsClient(
ad_token: str | None = None,
ad_token_provider: AsyncAzureADTokenProvider | None = None,
token_endpoint: str | None = None,
credential: "TokenCredential | None" = None,
credential: TokenCredential | None = None,
default_headers: Mapping[str, str] | None = None,
async_client: AsyncAzureOpenAI | None = None,
env_file_path: str | None = None,
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import json
import logging
import sys
@@ -175,7 +177,7 @@ class AzureOpenAIChatClient( # type: ignore[misc]
env_file_path: str | None = None,
env_file_encoding: str | None = None,
instruction_role: str | None = None,
middleware: Sequence["MiddlewareTypes"] | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
**kwargs: Any,
) -> None:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Any
@@ -15,7 +17,7 @@ logger: logging.Logger = logging.getLogger(__name__)
def get_entra_auth_token(
credential: "TokenCredential",
credential: TokenCredential,
token_endpoint: str,
**kwargs: Any,
) -> str | None:
@@ -49,7 +51,7 @@ def get_entra_auth_token(
async def get_entra_auth_token_async(
credential: "AsyncTokenCredential", token_endpoint: str, **kwargs: Any
credential: AsyncTokenCredential, token_endpoint: str, **kwargs: Any
) -> str | None:
"""Retrieve a async Microsoft Entra Auth Token for a given token endpoint.
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Mapping, Sequence
from typing import TYPE_CHECKING, Any, Generic
@@ -74,7 +76,7 @@ class AzureOpenAIResponsesClient( # type: ignore[misc]
env_file_path: str | None = None,
env_file_encoding: str | None = None,
instruction_role: str | None = None,
middleware: Sequence["MiddlewareTypes"] | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
**kwargs: Any,
) -> None:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import logging
import sys
from collections.abc import Awaitable, Callable, Mapping
@@ -110,7 +112,7 @@ class AzureOpenAISettings(AFBaseSettings):
default_token_endpoint: str = DEFAULT_AZURE_TOKEN_ENDPOINT
def get_azure_auth_token(
self, credential: "TokenCredential", token_endpoint: str | None = None, **kwargs: Any
self, credential: TokenCredential, token_endpoint: str | None = None, **kwargs: Any
) -> str | None:
"""Retrieve a Microsoft Entra Auth Token for a given token endpoint for the use with Azure OpenAI.
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Awaitable, Callable, MutableMapping, Sequence
from typing import TYPE_CHECKING, Any, Generic, cast
@@ -177,7 +179,7 @@ class OpenAIAssistantProvider(Generic[TOptions_co]):
self._client = AsyncOpenAI(**client_args)
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Async context manager entry."""
return self
@@ -206,7 +208,7 @@ class OpenAIAssistantProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a new assistant on OpenAI and return a ChatAgent.
This method creates a new assistant on the OpenAI service and wraps it
@@ -314,7 +316,7 @@ class OpenAIAssistantProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Retrieve an existing assistant by ID and return a ChatAgent.
This method fetches an existing assistant from OpenAI by its ID
@@ -380,7 +382,7 @@ class OpenAIAssistantProvider(Generic[TOptions_co]):
default_options: TOptions_co | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
context_provider: ContextProvider | None = None,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Wrap an existing SDK Assistant object as a ChatAgent.
This method does NOT make any HTTP calls. It simply wraps an already-
@@ -524,7 +526,7 @@ class OpenAIAssistantProvider(Generic[TOptions_co]):
context_provider: ContextProvider | None,
default_options: TOptions_co | None = None,
**kwargs: Any,
) -> "ChatAgent[TOptions_co]":
) -> ChatAgent[TOptions_co]:
"""Create a ChatAgent from an Assistant.
Args:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import json
import sys
from collections.abc import (
@@ -227,7 +229,7 @@ class OpenAIAssistantsClient( # type: ignore[misc]
async_client: AsyncOpenAI | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
middleware: Sequence["MiddlewareTypes"] | None = None,
middleware: Sequence[MiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
**kwargs: Any,
) -> None:
@@ -325,7 +327,7 @@ class OpenAIAssistantsClient( # type: ignore[misc]
self.thread_id: str | None = thread_id
self._should_delete_assistant: bool = False
async def __aenter__(self) -> "Self":
async def __aenter__(self) -> Self:
"""Async context manager entry."""
return self
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import json
import sys
from collections.abc import AsyncIterable, Awaitable, Callable, Mapping, MutableMapping, Sequence
@@ -305,7 +307,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
run_options["response_format"] = type_to_response_format_param(response_format)
return run_options
def _parse_response_from_openai(self, response: ChatCompletion, options: Mapping[str, Any]) -> "ChatResponse":
def _parse_response_from_openai(self, response: ChatCompletion, options: Mapping[str, Any]) -> ChatResponse:
"""Parse a response from OpenAI into a ChatResponse."""
response_metadata = self._get_metadata_from_chat_response(response)
messages: list[ChatMessage] = []
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from typing import Any
@@ -29,7 +31,7 @@ class ContentFilterResult:
severity: ContentFilterResultSeverity = ContentFilterResultSeverity.SAFE
@classmethod
def from_inner_error_result(cls, inner_error_results: dict[str, Any]) -> "ContentFilterResult":
def from_inner_error_result(cls, inner_error_results: dict[str, Any]) -> ContentFilterResult:
"""Creates a ContentFilterResult from the inner error results.
Args:
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import (
AsyncIterable,
@@ -815,7 +817,7 @@ class RawOpenAIResponsesClient( # type: ignore[misc]
self,
response: OpenAIResponse | ParsedResponse[BaseModel],
options: dict[str, Any],
) -> "ChatResponse":
) -> ChatResponse:
"""Parse an OpenAI Responses API response into a ChatResponse."""
structured_response: BaseModel | None = response.output_parsed if isinstance(response, ParsedResponse) else None # type: ignore[reportUnknownMemberType]
@@ -945,7 +947,7 @@ class RawOpenAIResponsesClient( # type: ignore[misc]
)
case "code_interpreter_call": # ResponseOutputCodeInterpreterCall
call_id = getattr(item, "call_id", None) or getattr(item, "id", None)
outputs: list["Content"] = []
outputs: list[Content] = []
if item_outputs := getattr(item, "outputs", None):
for code_output in item_outputs:
if getattr(code_output, "type", None) == "logs":
@@ -1456,7 +1458,7 @@ class OpenAIResponsesClient( # type: ignore[misc]
env_file_path: str | None = None,
env_file_encoding: str | None = None,
middleware: (
Sequence["ChatMiddleware | ChatMiddlewareCallable | FunctionMiddleware | FunctionMiddlewareCallable"] | None
Sequence[ChatMiddleware | ChatMiddlewareCallable | FunctionMiddleware | FunctionMiddlewareCallable] | None
) = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
**kwargs: Any,
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import logging
from collections.abc import Awaitable, Callable, Mapping, MutableMapping, Sequence
from copy import copy
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import sys
from collections.abc import Callable, Mapping
from pathlib import Path
@@ -1,4 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import os
from collections.abc import MutableMapping
from contextvars import ContextVar
@@ -101,7 +103,7 @@ class Property(SerializationMixin):
@classmethod
def from_dict(
cls, value: MutableMapping[str, Any], /, *, dependencies: MutableMapping[str, Any] | None = None
) -> "Property":
) -> Property:
"""Create a Property instance from a dictionary, dispatching to the appropriate subclass."""
# Only dispatch if we're being called on the base Property class
if cls is not Property:
@@ -211,7 +213,7 @@ class PropertySchema(SerializationMixin):
@classmethod
def from_dict(
cls, value: MutableMapping[str, Any], /, *, dependencies: MutableMapping[str, Any] | None = None
) -> "PropertySchema":
) -> PropertySchema:
"""Create a PropertySchema instance from a dictionary, filtering out 'kind' field."""
# Filter out 'kind', 'type', 'name', and 'description' fields that may appear in YAML
# but aren't PropertySchema params
@@ -491,7 +493,7 @@ class AgentDefinition(SerializationMixin):
@classmethod
def from_dict(
cls, value: MutableMapping[str, Any], /, *, dependencies: MutableMapping[str, Any] | None = None
) -> "AgentDefinition":
) -> AgentDefinition:
"""Create an AgentDefinition instance from a dictionary, dispatching to the appropriate subclass."""
# Only dispatch if we're being called on the base AgentDefinition class
if cls is not AgentDefinition:
@@ -537,7 +539,7 @@ class Tool(SerializationMixin):
@classmethod
def from_dict(
cls: type[TTool], value: MutableMapping[str, Any], /, *, dependencies: MutableMapping[str, Any] | None = None
) -> "TTool":
) -> TTool:
"""Create a Tool instance from a dictionary, dispatching to the appropriate subclass."""
# Only dispatch if we're being called on the base Tool class
if cls is not Tool:
@@ -867,7 +869,7 @@ class Resource(SerializationMixin):
@classmethod
def from_dict(
cls, value: MutableMapping[str, Any], /, *, dependencies: MutableMapping[str, Any] | None = None
) -> "Resource":
) -> Resource:
"""Create a Resource instance from a dictionary, dispatching to the appropriate subclass."""
# Only dispatch if we're being called on the base Resource class
if cls is not Resource:
@@ -7,6 +7,8 @@ This module implements handlers for:
- InvokePromptAgent: Invoke a local prompt-based agent
"""
from __future__ import annotations
import json
from collections.abc import AsyncGenerator
from typing import Any, cast
@@ -185,7 +187,7 @@ def _build_messages_from_state(ctx: ActionContext) -> list[ChatMessage]:
@action_handler("InvokeAzureAgent")
async def handle_invoke_azure_agent(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]:
async def handle_invoke_azure_agent(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]:
"""Invoke a hosted Azure AI agent.
Supports both Python-style and .NET-style YAML schemas:
@@ -523,7 +525,7 @@ def _normalize_variable_path(variable: str) -> str:
@action_handler("InvokePromptAgent")
async def handle_invoke_prompt_agent(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]:
async def handle_invoke_prompt_agent(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]:
"""Invoke a local prompt-based agent (similar to InvokeAzureAgent but for local agents).
Action schema:
@@ -16,6 +16,8 @@ network calls. The `return; yield` pattern makes a function an async generator w
actually yielding any events.
"""
from __future__ import annotations
from collections.abc import AsyncGenerator
from typing import TYPE_CHECKING, Any, cast
@@ -37,7 +39,7 @@ logger = get_logger("agent_framework.declarative.workflows.actions")
@action_handler("SetValue")
async def handle_set_value(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_set_value(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Set a value in the workflow state.
Action schema:
@@ -63,7 +65,7 @@ async def handle_set_value(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent,
@action_handler("SetVariable")
async def handle_set_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_set_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Set a variable in the workflow state (.NET workflow format).
This is an alias for SetValue with 'variable' instead of 'path'.
@@ -113,7 +115,7 @@ def _normalize_variable_path(variable: str) -> str:
@action_handler("AppendValue")
async def handle_append_value(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_append_value(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Append a value to a list in the workflow state.
Action schema:
@@ -139,7 +141,7 @@ async def handle_append_value(ctx: ActionContext) -> AsyncGenerator[WorkflowEven
@action_handler("SendActivity")
async def handle_send_activity(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_send_activity(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Send text or attachments to the user.
Action schema (object form):
@@ -189,7 +191,7 @@ async def handle_send_activity(ctx: ActionContext) -> AsyncGenerator[WorkflowEve
@action_handler("EmitEvent")
async def handle_emit_event(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_emit_event(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Emit a custom workflow event.
Action schema:
@@ -213,7 +215,7 @@ async def handle_emit_event(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent,
yield CustomEvent(name=name, data=evaluated_data)
def _evaluate_dict_values(d: dict[str, Any], state: "WorkflowState") -> dict[str, Any]:
def _evaluate_dict_values(d: dict[str, Any], state: WorkflowState) -> dict[str, Any]:
"""Recursively evaluate PowerFx expressions in a dictionary.
Args:
@@ -245,7 +247,7 @@ def _evaluate_dict_values(d: dict[str, Any], state: "WorkflowState") -> dict[str
@action_handler("SetTextVariable")
async def handle_set_text_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_set_text_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Set a text variable with string interpolation support.
This is similar to SetVariable but supports multi-line text with
@@ -281,7 +283,7 @@ async def handle_set_text_variable(ctx: ActionContext) -> AsyncGenerator[Workflo
@action_handler("SetMultipleVariables")
async def handle_set_multiple_variables(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_set_multiple_variables(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Set multiple variables at once.
Action schema:
@@ -313,7 +315,7 @@ async def handle_set_multiple_variables(ctx: ActionContext) -> AsyncGenerator[Wo
@action_handler("ResetVariable")
async def handle_reset_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_reset_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Reset a variable to its default/blank state.
Action schema:
@@ -336,7 +338,7 @@ async def handle_reset_variable(ctx: ActionContext) -> AsyncGenerator[WorkflowEv
@action_handler("ClearAllVariables")
async def handle_clear_all_variables(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_clear_all_variables(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Clear all turn-scoped variables.
Action schema:
@@ -350,7 +352,7 @@ async def handle_clear_all_variables(ctx: ActionContext) -> AsyncGenerator[Workf
@action_handler("CreateConversation")
async def handle_create_conversation(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_create_conversation(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Create a new conversation context.
Action schema (.NET style):
@@ -399,7 +401,7 @@ async def handle_create_conversation(ctx: ActionContext) -> AsyncGenerator[Workf
@action_handler("AddConversationMessage")
async def handle_add_conversation_message(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_add_conversation_message(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Add a message to a conversation.
Action schema:
@@ -451,7 +453,7 @@ async def handle_add_conversation_message(ctx: ActionContext) -> AsyncGenerator[
@action_handler("CopyConversationMessages")
async def handle_copy_conversation_messages(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_copy_conversation_messages(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Copy messages from one conversation to another.
Action schema:
@@ -506,7 +508,7 @@ async def handle_copy_conversation_messages(ctx: ActionContext) -> AsyncGenerato
@action_handler("RetrieveConversationMessages")
async def handle_retrieve_conversation_messages(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_retrieve_conversation_messages(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Retrieve messages from a conversation and store in a variable.
Action schema:
@@ -547,7 +549,7 @@ async def handle_retrieve_conversation_messages(ctx: ActionContext) -> AsyncGene
yield # Make it a generator
def _interpolate_string(text: str, state: "WorkflowState") -> str:
def _interpolate_string(text: str, state: WorkflowState) -> str:
"""Interpolate {Variable.Path} references in a string.
Args:
@@ -7,6 +7,8 @@ This module implements handlers for:
- TryCatch: Try-catch-finally error handling
"""
from __future__ import annotations
from collections.abc import AsyncGenerator
from dataclasses import dataclass
@@ -44,7 +46,7 @@ class ErrorEvent(WorkflowEvent):
@action_handler("ThrowException")
async def handle_throw_exception(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_throw_exception(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Raise an exception that can be caught by TryCatch.
Action schema:
@@ -67,7 +69,7 @@ async def handle_throw_exception(ctx: ActionContext) -> AsyncGenerator[WorkflowE
@action_handler("TryCatch")
async def handle_try_catch(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]:
async def handle_try_catch(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]:
"""Try-catch-finally error handling.
Action schema:
@@ -23,6 +23,8 @@ the full RecalcEngine API. We work around this by:
See: dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/PowerFx/
"""
from __future__ import annotations
import logging
import sys
from collections.abc import Mapping
@@ -148,7 +150,7 @@ class DeclarativeWorkflowState:
"""
self._state = state
def initialize(self, inputs: "Mapping[str, Any] | None" = None) -> None:
def initialize(self, inputs: Mapping[str, Any] | None = None) -> None:
"""Initialize the declarative state with inputs.
Args:
@@ -814,7 +816,7 @@ class DeclarativeActionExecutor(Executor):
async def _ensure_state_initialized(
self,
ctx: "WorkflowContext[Any, Any]",
ctx: WorkflowContext[Any, Any],
trigger: Any,
) -> DeclarativeWorkflowState:
"""Ensure declarative state is initialized.
@@ -11,6 +11,8 @@ action definitions and creates a proper workflow graph with:
- Loop edges for foreach
"""
from __future__ import annotations
from typing import Any
from agent_framework._workflows import (
@@ -10,6 +10,8 @@ Each YAML action becomes a real Executor node in the workflow graph,
enabling checkpointing, visualization, and pause/resume capabilities.
"""
from __future__ import annotations
from collections.abc import Mapping
from pathlib import Path
from typing import Any, cast
@@ -506,7 +508,7 @@ class WorkflowFactory:
f"Invalid agent definition. Expected 'file', 'kind', or 'connection': {agent_def}"
)
def register_agent(self, name: str, agent: SupportsAgentRun | AgentExecutor) -> "WorkflowFactory":
def register_agent(self, name: str, agent: SupportsAgentRun | AgentExecutor) -> WorkflowFactory:
"""Register an agent instance with the factory for use in workflows.
Registered agents are available to InvokeAzureAgent actions by name.
@@ -552,7 +554,7 @@ class WorkflowFactory:
self._agents[name] = agent
return self
def register_binding(self, name: str, func: Any) -> "WorkflowFactory":
def register_binding(self, name: str, func: Any) -> WorkflowFactory:
"""Register a function binding with the factory for use in workflow actions.
Bindings allow workflow actions to invoke Python functions by name.
@@ -7,6 +7,8 @@ workflow actions defined in YAML. Each action type (InvokeAzureAgent, Foreach, e
has a corresponding handler registered via the @action_handler decorator.
"""
from __future__ import annotations
from collections.abc import AsyncGenerator, Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
@@ -27,13 +29,13 @@ class ActionContext:
for executing nested actions (for control flow constructs like Foreach).
"""
state: "WorkflowState"
state: WorkflowState
"""The current workflow state with variables and agent results."""
action: dict[str, Any]
"""The action definition from the YAML."""
execute_actions: "ExecuteActionsFn"
execute_actions: ExecuteActionsFn
"""Function to execute a list of nested actions (for Foreach, If, etc.)."""
agents: dict[str, Any]
@@ -150,7 +152,7 @@ class ActionHandler(Protocol):
def __call__(
self,
ctx: ActionContext,
) -> AsyncGenerator[WorkflowEvent, None]:
) -> AsyncGenerator[WorkflowEvent]:
"""Execute the action and yield events.
Args:
@@ -8,6 +8,8 @@ This module implements handlers for human input patterns:
- ExternalLoop processing: Loop while waiting for external input
"""
from __future__ import annotations
from collections.abc import AsyncGenerator
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, cast
@@ -75,7 +77,7 @@ class ExternalLoopEvent(WorkflowEvent):
@action_handler("Question")
async def handle_question(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_question(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Handle Question action - request human input with optional validation.
Action schema:
@@ -140,7 +142,7 @@ async def handle_question(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, N
@action_handler("RequestExternalInput")
async def handle_request_external_input(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_request_external_input(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Handle RequestExternalInput action - request input from external system.
Action schema:
@@ -197,7 +199,7 @@ async def handle_request_external_input(ctx: ActionContext) -> AsyncGenerator[Wo
@action_handler("WaitForInput")
async def handle_wait_for_input(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent, None]: # noqa: RUF029
async def handle_wait_for_input(ctx: ActionContext) -> AsyncGenerator[WorkflowEvent]: # noqa: RUF029
"""Handle WaitForInput action - pause and wait for external input.
Action schema:
@@ -231,7 +233,7 @@ async def handle_wait_for_input(ctx: ActionContext) -> AsyncGenerator[WorkflowEv
def process_external_loop(
input_config: dict[str, Any],
state: "WorkflowState",
state: WorkflowState,
) -> tuple[bool, str | None]:
"""Process the externalLoop.when pattern from action input.
@@ -10,6 +10,8 @@ These functions can be used as fallbacks when PowerFx is not available,
or registered with the PowerFx engine when it is available.
"""
from __future__ import annotations
from typing import Any, cast
@@ -9,6 +9,8 @@ This module provides state management for declarative workflows, handling:
- Agent results and context
"""
from __future__ import annotations
from collections.abc import Mapping
from typing import Any, cast
@@ -624,7 +626,7 @@ class WorkflowState:
"""Reset the agent result for a new agent invocation."""
self._agent.clear()
def clone(self) -> "WorkflowState":
def clone(self) -> WorkflowState:
"""Create a shallow copy of the state.
Returns:
+1 -1
View File
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"powerfx>=0.0.31; python_version < '3.14'",
"pyyaml>=6.0,<7.0",
]
@@ -6,6 +6,8 @@ This module provides a clean abstraction layer for managing conversations
while wrapping AgentFramework's AgentThread underneath.
"""
from __future__ import annotations
import time
import uuid
from abc import ABC, abstractmethod
@@ -2,6 +2,8 @@
"""Agent Framework entity discovery implementation."""
from __future__ import annotations
import ast
import importlib
import importlib.util
@@ -2,6 +2,8 @@
"""Agent Framework executor implementation."""
from __future__ import annotations
import json
import logging
from collections.abc import AsyncGenerator
@@ -184,7 +186,7 @@ class AgentFrameworkExecutor:
raise EntityNotFoundError(f"Entity '{entity_id}' not found")
return entity_info
async def execute_streaming(self, request: AgentFrameworkRequest) -> AsyncGenerator[Any, None]:
async def execute_streaming(self, request: AgentFrameworkRequest) -> AsyncGenerator[Any]:
"""Execute request and stream results in OpenAI format.
Args:
@@ -229,7 +231,7 @@ class AgentFrameworkExecutor:
# Aggregate into final response
return await self.message_mapper.aggregate_to_response(events, request)
async def execute_entity(self, entity_id: str, request: AgentFrameworkRequest) -> AsyncGenerator[Any, None]:
async def execute_entity(self, entity_id: str, request: AgentFrameworkRequest) -> AsyncGenerator[Any]:
"""Execute the entity and yield raw Agent Framework events plus trace events.
Args:
@@ -286,7 +288,7 @@ class AgentFrameworkExecutor:
async def _execute_agent(
self, agent: SupportsAgentRun, request: AgentFrameworkRequest, trace_collector: Any
) -> AsyncGenerator[Any, None]:
) -> AsyncGenerator[Any]:
"""Execute Agent Framework agent with trace collection and optional thread support.
Args:
@@ -361,7 +363,7 @@ class AgentFrameworkExecutor:
async def _execute_workflow(
self, workflow: Workflow, request: AgentFrameworkRequest, trace_collector: Any
) -> AsyncGenerator[Any, None]:
) -> AsyncGenerator[Any]:
"""Execute Agent Framework workflow with checkpoint support via conversation items.
Args:
@@ -2,6 +2,8 @@
"""Agent Framework message mapper implementation."""
from __future__ import annotations
import json
import logging
import time
@@ -6,6 +6,8 @@ This executor mirrors the AgentFrameworkExecutor interface but routes
requests to OpenAI's API instead of executing local entities.
"""
from __future__ import annotations
import logging
import os
from collections.abc import AsyncGenerator
@@ -76,7 +78,7 @@ class OpenAIExecutor:
return self._client
async def execute_streaming(self, request: AgentFrameworkRequest) -> AsyncGenerator[Any, None]:
async def execute_streaming(self, request: AgentFrameworkRequest) -> AsyncGenerator[Any]:
"""Execute request via OpenAI and stream results in OpenAI format.
This mirrors AgentFrameworkExecutor.execute_streaming() interface.
@@ -2,6 +2,8 @@
"""FastAPI server implementation."""
from __future__ import annotations
import asyncio
import importlib.metadata
import inspect
@@ -287,7 +289,7 @@ class DevServer:
"""Create the FastAPI application."""
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
# Startup
logger.info("Starting Agent Framework Server")
await self._ensure_executor()
@@ -623,7 +625,7 @@ class DevServer:
entity_path = Path(entity_path_str)
# Stream deployment events
async def event_generator() -> AsyncGenerator[str, None]:
async def event_generator() -> AsyncGenerator[str]:
async for event in self.deployment_manager.deploy(config, entity_path):
# Format as SSE
import json
@@ -1085,7 +1087,7 @@ class DevServer:
async def _stream_execution(
self, executor: AgentFrameworkExecutor, request: AgentFrameworkRequest
) -> AsyncGenerator[str, None]:
) -> AsyncGenerator[str]:
"""Stream execution directly through executor."""
try:
# Collect events for final response.completed event
@@ -1155,7 +1157,7 @@ class DevServer:
async def _stream_openai_execution(
self, executor: OpenAIExecutor, request: AgentFrameworkRequest
) -> AsyncGenerator[str, None]:
) -> AsyncGenerator[str]:
"""Stream execution through OpenAI executor.
OpenAI events are already in final format - no conversion or aggregation needed.
@@ -1212,7 +1214,7 @@ class DevServer:
async def _stream_with_cancellation(
self, executor: AgentFrameworkExecutor, request: AgentFrameworkRequest, response_id: str
) -> AsyncGenerator[str, None]:
) -> AsyncGenerator[str]:
"""Stream execution with automatic cancellation on client disconnect.
This wrapper adds cancellation support to the execution stream:
@@ -1231,7 +1233,7 @@ class DevServer:
"""
task = None
async def execution_wrapper() -> AsyncGenerator[str, None]:
async def execution_wrapper() -> AsyncGenerator[str]:
"""Inner wrapper to handle the actual execution."""
try:
logger.debug(f"[CANCELLATION] Starting execution for {response_id}")
@@ -2,6 +2,8 @@
"""Simplified tracing integration for Agent Framework Server."""
from __future__ import annotations
import logging
from collections.abc import Generator, Sequence
from contextlib import contextmanager
@@ -120,9 +122,7 @@ class SimpleTraceCollector(SpanExporter):
@contextmanager
def capture_traces(
response_id: str | None = None, entity_id: str | None = None
) -> Generator[SimpleTraceCollector, None, None]:
def capture_traces(response_id: str | None = None, entity_id: str | None = None) -> Generator[SimpleTraceCollector]:
"""Context manager to capture traces during execution.
Args:
@@ -559,7 +559,7 @@ export function AgentView({ selectedAgent, onDebugEvent }: AgentViewProps) {
// Backend successfully returned conversations list
setAvailableConversations(conversations);
if (conversations.length > 0) {
// Found conversations on backend - use most recent
const mostRecent = conversations[0];
@@ -614,7 +614,7 @@ export function AgentView({ selectedAgent, onDebugEvent }: AgentViewProps) {
// Check for incomplete stream and resume if needed
const state = loadStreamingState(mostRecent.id);
if (state && !state.completed) {
accumulatedTextRef.current = state.accumulatedText || "";
// Add assistant message with resumed text
@@ -565,7 +565,7 @@ export const WorkflowFlow = memo(function WorkflowFlow({
0% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: -10; }
}
/* Dark theme styles for React Flow controls */
.dark .react-flow__controls {
background-color: rgba(31, 41, 55, 0.9) !important;
@@ -13,7 +13,7 @@ export function LoadingSpinner({ size = "md", className }: LoadingSpinnerProps)
"animate-spin",
{
"h-4 w-4": size === "sm",
"h-6 w-6": size === "md",
"h-6 w-6": size === "md",
"h-8 w-8": size === "lg",
},
className
@@ -9,8 +9,8 @@ interface LoadingStateProps {
fullPage?: boolean
}
export function LoadingState({
message = "Loading...",
export function LoadingState({
message = "Loading...",
description,
size = "md",
className,
@@ -1,6 +1,6 @@
/**
* Streaming State Persistence
*
*
* Manages browser storage of streaming response state to enable:
* - Resume interrupted streams after page refresh
* - Replay cached events before fetching new ones
@@ -73,7 +73,7 @@ export function loadStreamingState(conversationId: string): StreamingState | nul
try {
const key = getStorageKey(conversationId);
const data = localStorage.getItem(key);
if (!data) {
return null;
}
@@ -111,9 +111,9 @@ export function updateStreamingState(
try {
const existing = loadStreamingState(conversationId);
const sequenceNumber = "sequence_number" in event ? event.sequence_number : undefined;
const newEvents = existing ? [...existing.events, event] : [event];
const state: StreamingState = {
conversationId,
responseId,
@@ -174,7 +174,7 @@ export function clearExpiredStreamingStates(): void {
if (data) {
const state: StreamingState = JSON.parse(data);
const age = now - state.timestamp;
if (age > STATE_EXPIRY_MS || state.completed) {
localStorage.removeItem(key);
}
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0",
"python-dotenv>=1.0.0",
+3 -3
View File
@@ -15,15 +15,15 @@ The durable task integration lets you host Microsoft Agent Framework agents usin
### Basic Usage Example
```python
from durabletask import TaskHubGrpcWorker
from durabletask.worker import TaskHubGrpcWorker
from agent_framework.azure import DurableAIAgentWorker
# Create the worker
with TaskHubGrpcWorker(...) as worker:
# Register the agent worker wrapper
agent_worker = DurableAIAgentWorker(worker)
# Register the agent
agent_worker.add_agent(my_agent)
```
+1 -1
View File
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"durabletask>=1.3.0",
"durabletask-azuremanaged>=1.3.0",
"python-dateutil>=2.8.0",
+1 -1
View File
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"foundry-local-sdk>=0.5.1,<1",
]
@@ -1,6 +1,8 @@
# Copyright (c) Microsoft. All rights reserved.
# ruff: noqa
from __future__ import annotations
import asyncio
from random import randint
from typing import TYPE_CHECKING, Annotated
@@ -31,7 +33,7 @@ def get_weather(
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: "ChatAgent") -> None:
async def non_streaming_example(agent: ChatAgent) -> None:
"""Example of non-streaming response (get the complete result at once)."""
print("=== Non-streaming Response Example ===")
@@ -41,7 +43,7 @@ async def non_streaming_example(agent: "ChatAgent") -> None:
print(f"Agent: {result}\n")
async def streaming_example(agent: "ChatAgent") -> None:
async def streaming_example(agent: ChatAgent) -> None:
"""Example of streaming response (get results as they are generated)."""
print("=== Streaming Response Example ===")
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import asyncio
import contextlib
import logging
@@ -223,7 +225,7 @@ class GitHubCopilotAgent(BaseAgent, Generic[TOptions]):
self._default_options = opts
self._started = False
async def __aenter__(self) -> "GitHubCopilotAgent[TOptions]":
async def __aenter__(self) -> GitHubCopilotAgent[TOptions]:
"""Start the agent when entering async context."""
await self.start()
return self
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
"github-copilot-sdk>=0.1.0",
]
@@ -371,6 +371,7 @@ class GAIA:
local_dir = snapshot_download( # type: ignore
repo_id="gaia-benchmark/GAIA",
repo_type="dataset",
revision="682dd723ee1e1697e00360edccf2366dc8418dd9",
token=token,
local_dir=str(self.data_dir),
force_download=False,
@@ -8,6 +8,8 @@ using an MCP calculator tool.
One GPU with 40GB of memory is sufficient for this sample.
"""
from __future__ import annotations
import argparse
import asyncio
import json
@@ -12,6 +12,8 @@ Builds on concepts from train_math_agent.py with additional complexity.
Requires one GPU of at least 80GB of memory.
"""
from __future__ import annotations
import argparse
import asyncio
import json

Some files were not shown because too many files have changed in this diff Show More