From 732d9f6cd766568c71be4db71d11a508665d6269 Mon Sep 17 00:00:00 2001 From: Evan Mattson <35585003+moonbox3@users.noreply.github.com> Date: Tue, 16 Sep 2025 21:04:07 +0900 Subject: [PATCH] Python: [BREAKING] Move workflow to main package (#767) * Move workflow to main package * Remove workflow specific unit test config * Remove workflow-specific version info * Revert unintended telemetry changes * Removed the obsolete packages/workflow/tests target * Rename dir workflow to _workflow * Fix test imports --- .github/workflows/python-tests.yml | 22 --- python/README.md | 1 + .../packages/main/agent_framework/__init__.py | 1 + .../main/agent_framework/_workflow/README.md | 15 ++ .../agent_framework/_workflow}/__init__.py | 43 ++-- .../agent_framework/_workflow/__init__.pyi | 186 ++++++++++++++++++ .../agent_framework/_workflow}/_agent.py | 50 +++-- .../agent_framework/_workflow}/_checkpoint.py | 0 .../agent_framework/_workflow}/_concurrent.py | 2 +- .../agent_framework/_workflow}/_const.py | 0 .../agent_framework/_workflow}/_edge.py | 5 +- .../_workflow}/_edge_runner.py | 0 .../agent_framework/_workflow}/_events.py | 0 .../agent_framework/_workflow}/_executor.py | 3 +- .../_workflow}/_function_executor.py | 0 .../agent_framework/_workflow}/_magentic.py | 3 +- .../agent_framework/_workflow}/_runner.py | 0 .../_workflow}/_runner_context.py | 0 .../agent_framework/_workflow}/_sequential.py | 2 +- .../_workflow}/_shared_state.py | 0 .../agent_framework/_workflow}/_telemetry.py | 3 +- .../_workflow}/_typing_utils.py | 0 .../agent_framework/_workflow}/_validation.py | 0 .../agent_framework/_workflow}/_viz.py | 2 +- .../agent_framework/_workflow}/_workflow.py | 40 ++-- .../_workflow}/_workflow_context.py | 0 .../main/agent_framework/workflow/__init__.py | 82 -------- .../agent_framework/workflow/__init__.pyi | 111 ----------- python/packages/main/pyproject.toml | 8 +- .../tests/workflow}/test_checkpoint.py | 2 +- .../tests/workflow}/test_concurrent.py | 6 +- .../tests/workflow}/test_edge.py | 29 +-- .../tests/workflow}/test_executor.py | 3 +- .../tests/workflow}/test_full_conversation.py | 12 +- .../tests/workflow}/test_function_executor.py | 3 +- .../tests/workflow}/test_magentic.py | 20 +- .../tests/workflow}/test_runner.py | 10 +- .../tests/workflow}/test_sequential.py | 8 +- .../tests/workflow}/test_serialization.py | 10 +- .../workflow}/test_simple_sub_workflow.py | 4 +- .../tests/workflow}/test_sub_workflow.py | 2 +- .../tests/workflow}/test_tracing.py | 18 +- .../tests/workflow}/test_validation.py | 6 +- .../tests => main/tests/workflow}/test_viz.py | 3 +- .../tests/workflow}/test_workflow.py | 16 +- .../tests/workflow}/test_workflow_agent.py | 11 +- .../tests/workflow}/test_workflow_builder.py | 16 +- .../tests/workflow}/test_workflow_states.py | 10 +- python/packages/runtime/tests/test_sample.py | 6 + python/packages/workflow/LICENSE | 21 -- python/packages/workflow/README.md | 9 - python/packages/workflow/pyproject.toml | 91 --------- python/pyproject.toml | 4 +- .../getting_started/telemetry/04-workflow.py | 4 +- .../getting_started/workflow/README.md | 8 +- .../_start-here/step1_executors_and_edges.py | 2 +- .../_start-here/step2_agents_in_a_workflow.py | 2 +- .../workflow/_start-here/step3_streaming.py | 7 +- .../agents/azure_chat_agents_streaming.py | 2 +- .../workflow/agents/custom_agent_executors.py | 11 +- .../agents/foundry_chat_agents_streaming.py | 4 +- .../workflow_as_agent_human_in_the_loop.py | 2 +- .../workflow_as_agent_reflection_pattern.py | 2 +- .../checkpoint/checkpoint_with_resume.py | 7 +- .../composition/sub_workflow_basics.py | 2 +- .../sub_workflow_parallel_requests.py | 6 +- .../sub_workflow_request_interception.py | 2 +- .../workflow/control-flow/edge_condition.py | 7 +- .../multi_selection_edge_group.py | 7 +- .../control-flow/sequential_executors.py | 2 +- .../control-flow/sequential_streaming.py | 2 +- .../workflow/control-flow/simple_loop.py | 7 +- .../control-flow/switch_case_edge_group.py | 7 +- .../guessing_game_with_human_input.py | 15 +- .../workflow/observability/tracing_basics.py | 2 +- .../orchestration/concurrent_agents.py | 3 +- .../concurrent_custom_agent_executors.py | 7 +- .../concurrent_custom_aggregator.py | 3 +- .../workflow/orchestration/magentic.py | 7 +- .../magentic_human_plan_update.py | 7 +- .../orchestration/sequential_agents.py | 3 +- .../sequential_custom_executors.py | 11 +- .../parallelism/fan_out_fan_in_edges.py | 7 +- .../map_reduce_and_visualization.py | 4 +- .../shared_states_with_agents.py | 7 +- .../concurrent_with_visualization.py | 11 +- python/uv.lock | 40 ++-- 87 files changed, 524 insertions(+), 595 deletions(-) create mode 100644 python/packages/main/agent_framework/_workflow/README.md rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/__init__.py (84%) create mode 100644 python/packages/main/agent_framework/_workflow/__init__.pyi rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_agent.py (93%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_checkpoint.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_concurrent.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_const.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_edge.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_edge_runner.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_events.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_executor.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_function_executor.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_magentic.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_runner.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_runner_context.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_sequential.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_shared_state.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_telemetry.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_typing_utils.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_validation.py (100%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_viz.py (99%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_workflow.py (97%) rename python/packages/{workflow/agent_framework_workflow => main/agent_framework/_workflow}/_workflow_context.py (100%) delete mode 100644 python/packages/main/agent_framework/workflow/__init__.py delete mode 100644 python/packages/main/agent_framework/workflow/__init__.pyi rename python/packages/{workflow/tests => main/tests/workflow}/test_checkpoint.py (99%) rename python/packages/{workflow/tests => main/tests/workflow}/test_concurrent.py (97%) rename python/packages/{workflow/tests => main/tests/workflow}/test_edge.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_executor.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_full_conversation.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_function_executor.py (99%) rename python/packages/{workflow/tests => main/tests/workflow}/test_magentic.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_runner.py (92%) rename python/packages/{workflow/tests => main/tests/workflow}/test_sequential.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_serialization.py (99%) rename python/packages/{workflow/tests => main/tests/workflow}/test_simple_sub_workflow.py (96%) rename python/packages/{workflow/tests => main/tests/workflow}/test_sub_workflow.py (99%) rename python/packages/{workflow/tests => main/tests/workflow}/test_tracing.py (97%) rename python/packages/{workflow/tests => main/tests/workflow}/test_validation.py (99%) rename python/packages/{workflow/tests => main/tests/workflow}/test_viz.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_workflow.py (98%) rename python/packages/{workflow/tests => main/tests/workflow}/test_workflow_agent.py (99%) rename python/packages/{workflow/tests => main/tests/workflow}/test_workflow_builder.py (93%) rename python/packages/{workflow/tests => main/tests/workflow}/test_workflow_states.py (95%) create mode 100644 python/packages/runtime/tests/test_sample.py delete mode 100644 python/packages/workflow/LICENSE delete mode 100644 python/packages/workflow/README.md delete mode 100644 python/packages/workflow/pyproject.toml diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 9de09f319c..ef31032840 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -102,28 +102,6 @@ jobs: name: coverage-${{ matrix.OS }}-${{ matrix.python-version }}-${{ env.PACKAGE_NAME }} path: ./python/coverage_${{ matrix.OS }}_${{ matrix.python-version }}_${{ env.PACKAGE_NAME }}.xml - # Workflow package tests - - name: Set environment variables - workflow - win - if: ${{ matrix.os == 'windows-latest' }} - run: | - echo "PACKAGE_NAME=workflow" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Set environment variables - workflow - if: ${{ matrix.os != 'windows-latest' }} - run: | - echo "PACKAGE_NAME=workflow" >> $GITHUB_ENV - - name: Test with pytest - workflow - run: uv run poe --directory ./packages/${{ env.PACKAGE_NAME }} test -n logical --dist loadfile --dist worksteal --junitxml=coverage.xml - working-directory: ./python - - name: Move coverage file - workflow - run: | - mv ./packages/${{ env.PACKAGE_NAME }}/coverage.xml coverage_${{ matrix.OS }}_${{ matrix.python-version }}_${{ env.PACKAGE_NAME }}.xml - working-directory: ./python - - name: Upload coverage artifact - workflow - uses: actions/upload-artifact@v4 - with: - name: coverage-${{ matrix.OS }}-${{ matrix.python-version }}-${{ env.PACKAGE_NAME }} - path: ./python/coverage_${{ matrix.OS }}_${{ matrix.python-version }}_${{ env.PACKAGE_NAME }}.xml - # Surface failing tests - name: Surface failing tests if: always() diff --git a/python/README.md b/python/README.md index 2098eda85d..c5f3b61a97 100644 --- a/python/README.md +++ b/python/README.md @@ -3,6 +3,7 @@ ## Quick Install ```bash +# Base package including workflow support pip install agent-framework # Optional: Add Azure integration pip install agent-framework[azure] diff --git a/python/packages/main/agent_framework/__init__.py b/python/packages/main/agent_framework/__init__.py index ca82fa412d..dc6c9511e1 100644 --- a/python/packages/main/agent_framework/__init__.py +++ b/python/packages/main/agent_framework/__init__.py @@ -16,3 +16,4 @@ from ._memory import * # noqa: F403 from ._threads import * # noqa: F403 from ._tools import * # noqa: F403 from ._types import * # noqa: F403 +from ._workflow import * # noqa: F403 diff --git a/python/packages/main/agent_framework/_workflow/README.md b/python/packages/main/agent_framework/_workflow/README.md new file mode 100644 index 0000000000..90e9eb8991 --- /dev/null +++ b/python/packages/main/agent_framework/_workflow/README.md @@ -0,0 +1,15 @@ +# Get Started with Microsoft Agent Framework Workflow + +Workflow capabilities now ship with the core `agent-framework` package. + +```bash +pip install agent-framework +``` + +Optional visualization support is still available via the `viz` extra: + +```bash +pip install agent-framework[viz] +``` + +See the [project README](https://github.com/microsoft/agent-framework/tree/main/python/README.md) for more information. diff --git a/python/packages/workflow/agent_framework_workflow/__init__.py b/python/packages/main/agent_framework/_workflow/__init__.py similarity index 84% rename from python/packages/workflow/agent_framework_workflow/__init__.py rename to python/packages/main/agent_framework/_workflow/__init__.py index 61094b9eb6..f8c3955c9d 100644 --- a/python/packages/workflow/agent_framework_workflow/__init__.py +++ b/python/packages/main/agent_framework/_workflow/__init__.py @@ -1,6 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. -import importlib.metadata +import contextlib from ._agent import WorkflowAgent from ._checkpoint import ( @@ -13,7 +13,18 @@ from ._concurrent import ConcurrentBuilder from ._const import ( DEFAULT_MAX_ITERATIONS, ) -from ._edge import Case, Default +from ._edge import ( + Case, + Default, + Edge, + FanInEdgeGroup, + FanOutEdgeGroup, + SingleEdgeGroup, + SwitchCaseEdgeGroup, + SwitchCaseEdgeGroupCase, + SwitchCaseEdgeGroupDefault, +) +from ._edge_runner import create_edge_runner from ._events import ( AgentRunEvent, AgentRunUpdateEvent, @@ -67,15 +78,19 @@ from ._magentic import ( MagenticStartMessage, StandardMagenticManager, ) +from ._runner import Runner from ._runner_context import ( InProcRunnerContext, Message, RunnerContext, ) from ._sequential import SequentialBuilder +from ._shared_state import SharedState +from ._telemetry import EdgeGroupDeliveryStatus, WorkflowTracer, workflow_tracer from ._validation import ( EdgeDuplicationError, GraphConnectivityError, + HandlerOutputAnnotationError, TypeCompatibilityError, ValidationTypeEnum, WorkflowValidationError, @@ -85,12 +100,6 @@ from ._viz import WorkflowViz from ._workflow import Workflow, WorkflowBuilder, WorkflowRunResult from ._workflow_context import WorkflowContext -try: - __version__ = importlib.metadata.version(__name__) -except importlib.metadata.PackageNotFoundError: - __version__ = "0.0.0" # Fallback for development mode - - __all__ = [ "DEFAULT_MAX_ITERATIONS", "AgentExecutor", @@ -102,15 +111,20 @@ __all__ = [ "CheckpointStorage", "ConcurrentBuilder", "Default", + "Edge", "EdgeDuplicationError", + "EdgeGroupDeliveryStatus", "Executor", "ExecutorCompletedEvent", "ExecutorEvent", "ExecutorFailedEvent", "ExecutorInvokeEvent", + "FanInEdgeGroup", + "FanOutEdgeGroup", "FileCheckpointStorage", "FunctionExecutor", "GraphConnectivityError", + "HandlerOutputAnnotationError", "InMemoryCheckpointStorage", "InProcRunnerContext", "MagenticAgentDeltaEvent", @@ -137,11 +151,17 @@ __all__ = [ "RequestInfoExecutor", "RequestInfoMessage", "RequestResponse", + "Runner", "RunnerContext", "SequentialBuilder", + "SharedState", + "SingleEdgeGroup", "StandardMagenticManager", "SubWorkflowRequestInfo", "SubWorkflowResponse", + "SwitchCaseEdgeGroup", + "SwitchCaseEdgeGroupCase", + "SwitchCaseEdgeGroupDefault", "TypeCompatibilityError", "ValidationTypeEnum", "Workflow", @@ -158,19 +178,18 @@ __all__ = [ "WorkflowRunState", "WorkflowStartedEvent", "WorkflowStatusEvent", + "WorkflowTracer", "WorkflowValidationError", "WorkflowViz", - "__version__", + "create_edge_runner", "executor", "handler", "intercepts_request", "validate_workflow_graph", + "workflow_tracer", ] - # Rebuild models to resolve forward references after all imports are complete -import contextlib - with contextlib.suppress(AttributeError, TypeError, ValueError): # Rebuild WorkflowExecutor to resolve Workflow forward reference WorkflowExecutor.model_rebuild() diff --git a/python/packages/main/agent_framework/_workflow/__init__.pyi b/python/packages/main/agent_framework/_workflow/__init__.pyi new file mode 100644 index 0000000000..506cac18e3 --- /dev/null +++ b/python/packages/main/agent_framework/_workflow/__init__.pyi @@ -0,0 +1,186 @@ +# Copyright (c) Microsoft. All rights reserved. + +from ._agent import WorkflowAgent +from ._checkpoint import ( + CheckpointStorage, + FileCheckpointStorage, + InMemoryCheckpointStorage, + WorkflowCheckpoint, +) +from ._concurrent import ConcurrentBuilder +from ._const import DEFAULT_MAX_ITERATIONS +from ._edge import ( + Case, + Default, + Edge, + FanInEdgeGroup, + FanOutEdgeGroup, + SingleEdgeGroup, + SwitchCaseEdgeGroup, + SwitchCaseEdgeGroupCase, + SwitchCaseEdgeGroupDefault, +) +from ._edge_runner import create_edge_runner +from ._events import ( + AgentRunEvent, + AgentRunUpdateEvent, + ExecutorCompletedEvent, + ExecutorEvent, + ExecutorFailedEvent, + ExecutorInvokeEvent, + RequestInfoEvent, + WorkflowCompletedEvent, + WorkflowErrorDetails, + WorkflowEvent, + WorkflowFailedEvent, + WorkflowRunState, + WorkflowStartedEvent, + WorkflowStatusEvent, +) +from ._executor import ( + AgentExecutor, + AgentExecutorRequest, + AgentExecutorResponse, + Executor, + RequestInfoExecutor, + RequestInfoMessage, + RequestResponse, + SubWorkflowRequestInfo, + SubWorkflowResponse, + WorkflowExecutor, + handler, + intercepts_request, +) +from ._function_executor import FunctionExecutor, executor +from ._magentic import ( + MagenticAgentDeltaEvent, + MagenticAgentExecutor, + MagenticAgentMessageEvent, + MagenticBuilder, + MagenticCallbackEvent, + MagenticCallbackMode, + MagenticContext, + MagenticFinalResultEvent, + MagenticManagerBase, + MagenticOrchestratorExecutor, + MagenticOrchestratorMessageEvent, + MagenticPlanReviewDecision, + MagenticPlanReviewReply, + MagenticPlanReviewRequest, + MagenticProgressLedger, + MagenticProgressLedgerItem, + MagenticRequestMessage, + MagenticResponseMessage, + MagenticStartMessage, + StandardMagenticManager, +) +from ._runner import Runner +from ._runner_context import ( + InProcRunnerContext, + Message, + RunnerContext, +) +from ._sequential import SequentialBuilder +from ._shared_state import SharedState +from ._telemetry import EdgeGroupDeliveryStatus, WorkflowTracer, workflow_tracer +from ._validation import ( + EdgeDuplicationError, + GraphConnectivityError, + HandlerOutputAnnotationError, + TypeCompatibilityError, + ValidationTypeEnum, + WorkflowValidationError, + validate_workflow_graph, +) +from ._viz import WorkflowViz +from ._workflow import Workflow, WorkflowBuilder, WorkflowRunResult +from ._workflow_context import WorkflowContext + +__all__ = [ + "DEFAULT_MAX_ITERATIONS", + "AgentExecutor", + "AgentExecutorRequest", + "AgentExecutorResponse", + "AgentRunEvent", + "AgentRunUpdateEvent", + "Case", + "CheckpointStorage", + "ConcurrentBuilder", + "Default", + "Edge", + "EdgeDuplicationError", + "EdgeGroupDeliveryStatus", + "Executor", + "ExecutorCompletedEvent", + "ExecutorEvent", + "ExecutorFailedEvent", + "ExecutorInvokeEvent", + "FanInEdgeGroup", + "FanOutEdgeGroup", + "FileCheckpointStorage", + "FunctionExecutor", + "GraphConnectivityError", + "HandlerOutputAnnotationError", + "InMemoryCheckpointStorage", + "InProcRunnerContext", + "MagenticAgentDeltaEvent", + "MagenticAgentExecutor", + "MagenticAgentMessageEvent", + "MagenticBuilder", + "MagenticCallbackEvent", + "MagenticCallbackMode", + "MagenticContext", + "MagenticFinalResultEvent", + "MagenticManagerBase", + "MagenticOrchestratorExecutor", + "MagenticOrchestratorMessageEvent", + "MagenticPlanReviewDecision", + "MagenticPlanReviewReply", + "MagenticPlanReviewRequest", + "MagenticProgressLedger", + "MagenticProgressLedgerItem", + "MagenticRequestMessage", + "MagenticResponseMessage", + "MagenticStartMessage", + "Message", + "RequestInfoEvent", + "RequestInfoExecutor", + "RequestInfoMessage", + "RequestResponse", + "Runner", + "RunnerContext", + "SequentialBuilder", + "SharedState", + "SingleEdgeGroup", + "StandardMagenticManager", + "SubWorkflowRequestInfo", + "SubWorkflowResponse", + "SwitchCaseEdgeGroup", + "SwitchCaseEdgeGroupCase", + "SwitchCaseEdgeGroupDefault", + "TypeCompatibilityError", + "ValidationTypeEnum", + "Workflow", + "WorkflowAgent", + "WorkflowBuilder", + "WorkflowCheckpoint", + "WorkflowCompletedEvent", + "WorkflowContext", + "WorkflowErrorDetails", + "WorkflowEvent", + "WorkflowExecutor", + "WorkflowFailedEvent", + "WorkflowRunResult", + "WorkflowRunState", + "WorkflowStartedEvent", + "WorkflowStatusEvent", + "WorkflowTracer", + "WorkflowValidationError", + "WorkflowViz", + "create_edge_runner", + "executor", + "handler", + "intercepts_request", + "validate_workflow_graph", + "workflow_tracer", +] diff --git a/python/packages/workflow/agent_framework_workflow/_agent.py b/python/packages/main/agent_framework/_workflow/_agent.py similarity index 93% rename from python/packages/workflow/agent_framework_workflow/_agent.py rename to python/packages/main/agent_framework/_workflow/_agent.py index 94e1d6555e..29d4251bc2 100644 --- a/python/packages/workflow/agent_framework_workflow/_agent.py +++ b/python/packages/main/agent_framework/_workflow/_agent.py @@ -6,6 +6,8 @@ from collections.abc import AsyncIterable, Sequence from datetime import datetime from typing import TYPE_CHECKING, Any, ClassVar, TypedDict, cast +from pydantic import Field + from agent_framework import ( AgentRunResponse, AgentRunResponseUpdate, @@ -20,7 +22,6 @@ from agent_framework import ( ) from agent_framework._pydantic import AFBaseModel from agent_framework.exceptions import AgentExecutionException -from pydantic import Field from ._events import ( AgentRunUpdateEvent, @@ -73,9 +74,10 @@ class WorkflowAgent(BaseAgent): kwargs["workflow"] = workflow # Validate the workflow's start executor can handle agent-facing message inputs - start_executor = workflow.get_start_executor() - if start_executor is None: - raise ValueError("Workflow's start executor is not defined.") + try: + start_executor = workflow.get_start_executor() + except KeyError as exc: # Defensive: workflow lacks a configured entry point + raise ValueError("Workflow's start executor is not defined.") from exc if not start_executor.can_handle_type(list[ChatMessage]): raise ValueError("Workflow's start executor cannot handle list[ChatMessage]") @@ -256,6 +258,9 @@ class WorkflowAgent(BaseAgent): message_id=str(uuid.uuid4()), created_at=datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ"), ) + case _: + # Ignore non-agent workflow events + pass # We only care about the above two events and discard the rest. return None @@ -349,16 +354,17 @@ class WorkflowAgent(BaseAgent): if current is None: return incoming raw_list: list[object] = [] + + def _add_raw(value: object) -> None: + if isinstance(value, list): + raw_list.extend(cast(list[object], value)) + else: + raw_list.append(value) + if current.raw_representation is not None: - if isinstance(current.raw_representation, list): - raw_list.extend(current.raw_representation) - else: - raw_list.append(current.raw_representation) + _add_raw(current.raw_representation) if incoming.raw_representation is not None: - if isinstance(incoming.raw_representation, list): - raw_list.extend(incoming.raw_representation) - else: - raw_list.append(incoming.raw_representation) + _add_raw(incoming.raw_representation) return AgentRunResponse( messages=(current.messages or []) + (incoming.messages or []), response_id=current.response_id or incoming.response_id, @@ -407,11 +413,13 @@ class WorkflowAgent(BaseAgent): if merged_additional_properties is None: merged_additional_properties = {} merged_additional_properties.update(aggregated.additional_properties) - if aggregated.raw_representation: - if isinstance(aggregated.raw_representation, list): - raw_representations.extend(aggregated.raw_representation) + raw_value = aggregated.raw_representation + if raw_value: + cast_value = cast(object | list[object], raw_value) + if isinstance(cast_value, list): + raw_representations.extend(cast(list[object], cast_value)) else: - raw_representations.append(aggregated.raw_representation) + raw_representations.append(cast_value) # PHASE 3: HANDLE GLOBAL DANGLING UPDATES (NO RESPONSE_ID) if global_dangling: @@ -427,11 +435,13 @@ class WorkflowAgent(BaseAgent): if merged_additional_properties is None: merged_additional_properties = {} merged_additional_properties.update(flattened.additional_properties) - if flattened.raw_representation: - if isinstance(flattened.raw_representation, list): - raw_representations.extend(flattened.raw_representation) + flat_raw = flattened.raw_representation + if flat_raw: + cast_flat = cast(object | list[object], flat_raw) + if isinstance(cast_flat, list): + raw_representations.extend(cast(list[object], cast_flat)) else: - raw_representations.append(flattened.raw_representation) + raw_representations.append(cast_flat) # PHASE 4: CONSTRUCT FINAL RESPONSE WITH INPUT RESPONSE_ID return AgentRunResponse( diff --git a/python/packages/workflow/agent_framework_workflow/_checkpoint.py b/python/packages/main/agent_framework/_workflow/_checkpoint.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_checkpoint.py rename to python/packages/main/agent_framework/_workflow/_checkpoint.py diff --git a/python/packages/workflow/agent_framework_workflow/_concurrent.py b/python/packages/main/agent_framework/_workflow/_concurrent.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_concurrent.py rename to python/packages/main/agent_framework/_workflow/_concurrent.py index 14feb6bc8e..670a555f50 100644 --- a/python/packages/workflow/agent_framework_workflow/_concurrent.py +++ b/python/packages/main/agent_framework/_workflow/_concurrent.py @@ -177,7 +177,7 @@ class ConcurrentBuilder: Usage: ```python - from agent_framework.workflow import ConcurrentBuilder + from agent_framework import ConcurrentBuilder # Minimal: use default aggregator (returns list[ChatMessage]) workflow = ConcurrentBuilder().participants([agent1, agent2, agent3]).build() diff --git a/python/packages/workflow/agent_framework_workflow/_const.py b/python/packages/main/agent_framework/_workflow/_const.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_const.py rename to python/packages/main/agent_framework/_workflow/_const.py diff --git a/python/packages/workflow/agent_framework_workflow/_edge.py b/python/packages/main/agent_framework/_workflow/_edge.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_edge.py rename to python/packages/main/agent_framework/_workflow/_edge.py index 76a0cb9a3a..7e175a5054 100644 --- a/python/packages/workflow/agent_framework_workflow/_edge.py +++ b/python/packages/main/agent_framework/_workflow/_edge.py @@ -6,10 +6,11 @@ from collections.abc import Callable, Sequence from dataclasses import dataclass from typing import Any, ClassVar -from agent_framework._pydantic import AFBaseModel from pydantic import Field -from agent_framework_workflow._executor import Executor +from agent_framework._pydantic import AFBaseModel + +from ._executor import Executor logger = logging.getLogger(__name__) diff --git a/python/packages/workflow/agent_framework_workflow/_edge_runner.py b/python/packages/main/agent_framework/_workflow/_edge_runner.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_edge_runner.py rename to python/packages/main/agent_framework/_workflow/_edge_runner.py diff --git a/python/packages/workflow/agent_framework_workflow/_events.py b/python/packages/main/agent_framework/_workflow/_events.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_events.py rename to python/packages/main/agent_framework/_workflow/_events.py diff --git a/python/packages/workflow/agent_framework_workflow/_executor.py b/python/packages/main/agent_framework/_workflow/_executor.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_executor.py rename to python/packages/main/agent_framework/_workflow/_executor.py index b4005cd152..83763bc02a 100644 --- a/python/packages/workflow/agent_framework_workflow/_executor.py +++ b/python/packages/main/agent_framework/_workflow/_executor.py @@ -12,9 +12,10 @@ from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union, get_args, get_or if TYPE_CHECKING: from ._workflow import Workflow +from pydantic import Field + from agent_framework import AgentProtocol, AgentRunResponse, AgentRunResponseUpdate, AgentThread, ChatMessage from agent_framework._pydantic import AFBaseModel -from pydantic import Field from ._events import ( AgentRunEvent, diff --git a/python/packages/workflow/agent_framework_workflow/_function_executor.py b/python/packages/main/agent_framework/_workflow/_function_executor.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_function_executor.py rename to python/packages/main/agent_framework/_workflow/_function_executor.py diff --git a/python/packages/workflow/agent_framework_workflow/_magentic.py b/python/packages/main/agent_framework/_workflow/_magentic.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_magentic.py rename to python/packages/main/agent_framework/_workflow/_magentic.py index 7e3e75949f..204565c320 100644 --- a/python/packages/workflow/agent_framework_workflow/_magentic.py +++ b/python/packages/main/agent_framework/_workflow/_magentic.py @@ -13,6 +13,8 @@ from enum import Enum from typing import Annotated, Any, Literal, Protocol, TypeVar, Union, cast from uuid import uuid4 +from pydantic import BaseModel, ConfigDict, Field + from agent_framework import ( AgentProtocol, AgentRunResponse, @@ -25,7 +27,6 @@ from agent_framework import ( ) from agent_framework._agents import BaseAgent from agent_framework._pydantic import AFBaseModel -from pydantic import BaseModel, ConfigDict, Field from ._events import WorkflowCompletedEvent, WorkflowEvent from ._executor import Executor, RequestInfoMessage, RequestResponse, handler diff --git a/python/packages/workflow/agent_framework_workflow/_runner.py b/python/packages/main/agent_framework/_workflow/_runner.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_runner.py rename to python/packages/main/agent_framework/_workflow/_runner.py diff --git a/python/packages/workflow/agent_framework_workflow/_runner_context.py b/python/packages/main/agent_framework/_workflow/_runner_context.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_runner_context.py rename to python/packages/main/agent_framework/_workflow/_runner_context.py diff --git a/python/packages/workflow/agent_framework_workflow/_sequential.py b/python/packages/main/agent_framework/_workflow/_sequential.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_sequential.py rename to python/packages/main/agent_framework/_workflow/_sequential.py index 4271d3f7d7..cc091601c4 100644 --- a/python/packages/workflow/agent_framework_workflow/_sequential.py +++ b/python/packages/main/agent_framework/_workflow/_sequential.py @@ -103,7 +103,7 @@ class SequentialBuilder: Usage: ```python - from agent_framework.workflow import SequentialBuilder + from agent_framework import SequentialBuilder workflow = SequentialBuilder().participants([agent1, agent2, summarizer_exec]).build() ``` diff --git a/python/packages/workflow/agent_framework_workflow/_shared_state.py b/python/packages/main/agent_framework/_workflow/_shared_state.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_shared_state.py rename to python/packages/main/agent_framework/_workflow/_shared_state.py diff --git a/python/packages/workflow/agent_framework_workflow/_telemetry.py b/python/packages/main/agent_framework/_workflow/_telemetry.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_telemetry.py rename to python/packages/main/agent_framework/_workflow/_telemetry.py index 682a90b040..dc1a483e93 100644 --- a/python/packages/workflow/agent_framework_workflow/_telemetry.py +++ b/python/packages/main/agent_framework/_workflow/_telemetry.py @@ -3,11 +3,12 @@ from enum import Enum from typing import TYPE_CHECKING, Any, ClassVar -from agent_framework._pydantic import AFBaseSettings from opentelemetry.trace import Link, NoOpTracer, SpanKind, StatusCode, get_current_span, get_tracer from opentelemetry.trace.span import SpanContext from opentelemetry.util.types import Attributes +from agent_framework._pydantic import AFBaseSettings + if TYPE_CHECKING: from ._workflow import Workflow diff --git a/python/packages/workflow/agent_framework_workflow/_typing_utils.py b/python/packages/main/agent_framework/_workflow/_typing_utils.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_typing_utils.py rename to python/packages/main/agent_framework/_workflow/_typing_utils.py diff --git a/python/packages/workflow/agent_framework_workflow/_validation.py b/python/packages/main/agent_framework/_workflow/_validation.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_validation.py rename to python/packages/main/agent_framework/_workflow/_validation.py diff --git a/python/packages/workflow/agent_framework_workflow/_viz.py b/python/packages/main/agent_framework/_workflow/_viz.py similarity index 99% rename from python/packages/workflow/agent_framework_workflow/_viz.py rename to python/packages/main/agent_framework/_workflow/_viz.py index 916d980993..34ecd7e2be 100644 --- a/python/packages/workflow/agent_framework_workflow/_viz.py +++ b/python/packages/main/agent_framework/_workflow/_viz.py @@ -80,7 +80,7 @@ class WorkflowViz: import graphviz # type: ignore except ImportError as e: raise ImportError( - "viz extra is required for export. Install it with: pip install agent-framework-workflow[viz]. " + "viz extra is required for export. Install it with: pip install agent-framework[viz]. " "You also need to install graphviz separately. E.g., sudo apt-get install graphviz on Debian/Ubuntu " "or brew install graphviz on macOS. See https://graphviz.org/download/ for details." ) from e diff --git a/python/packages/workflow/agent_framework_workflow/_workflow.py b/python/packages/main/agent_framework/_workflow/_workflow.py similarity index 97% rename from python/packages/workflow/agent_framework_workflow/_workflow.py rename to python/packages/main/agent_framework/_workflow/_workflow.py index 25aad51e14..d4915fb8bd 100644 --- a/python/packages/workflow/agent_framework_workflow/_workflow.py +++ b/python/packages/main/agent_framework/_workflow/_workflow.py @@ -5,11 +5,12 @@ import logging import sys import uuid from collections.abc import AsyncIterable, Awaitable, Callable, Sequence -from typing import Any +from typing import Any, cast + +from pydantic import Field from agent_framework import AgentProtocol from agent_framework._pydantic import AFBaseModel -from pydantic import Field from ._agent import WorkflowAgent from ._checkpoint import CheckpointStorage @@ -51,6 +52,14 @@ else: logger = logging.getLogger(__name__) +def _default_edge_groups() -> list[EdgeGroup]: + return [] + + +def _default_executors() -> dict[str, Executor]: + return {} + + class WorkflowRunResult(list[WorkflowEvent]): """A list of events generated during the workflow execution in non-streaming mode. @@ -116,10 +125,10 @@ class Workflow(AFBaseModel): """ edge_groups: list[EdgeGroup] = Field( - default_factory=list, description="List of edge groups that define the workflow edges" + default_factory=_default_edge_groups, description="List of edge groups that define the workflow edges" ) executors: dict[str, Executor] = Field( - default_factory=dict, description="Dictionary mapping executor IDs to Executor instances" + default_factory=_default_executors, description="Dictionary mapping executor IDs to Executor instances" ) start_executor_id: str = Field(min_length=1, description="The ID of the starting executor for the workflow") max_iterations: int = Field( @@ -181,21 +190,20 @@ class Workflow(AFBaseModel): # Ensure WorkflowExecutor instances have their workflow field serialized if "executors" in data: - executors_data = data["executors"] + executors_data = cast(dict[str, Any], data["executors"]) + executor_map: dict[str, Executor] = self.executors for executor_id, executor_data in executors_data.items(): # Check if this is a WorkflowExecutor that might be missing its workflow field - if ( - isinstance(executor_data, dict) - and executor_data.get("type") == "WorkflowExecutor" - and "workflow" not in executor_data - ): - # Get the original executor object and serialize its workflow - original_executor = self.executors.get(executor_id) - if original_executor and hasattr(original_executor, "workflow"): - from ._executor import WorkflowExecutor + if isinstance(executor_data, dict): + executor_dict = cast(dict[str, Any], executor_data) + if executor_dict.get("type") == "WorkflowExecutor" and "workflow" not in executor_dict: + # Get the original executor object and serialize its workflow + original_executor = executor_map.get(executor_id) + if original_executor is not None and hasattr(original_executor, "workflow"): + from ._executor import WorkflowExecutor - if isinstance(original_executor, WorkflowExecutor): - executor_data["workflow"] = original_executor.workflow.model_dump(**kwargs) + if isinstance(original_executor, WorkflowExecutor): + executor_dict["workflow"] = original_executor.workflow.model_dump(**kwargs) return data diff --git a/python/packages/workflow/agent_framework_workflow/_workflow_context.py b/python/packages/main/agent_framework/_workflow/_workflow_context.py similarity index 100% rename from python/packages/workflow/agent_framework_workflow/_workflow_context.py rename to python/packages/main/agent_framework/_workflow/_workflow_context.py diff --git a/python/packages/main/agent_framework/workflow/__init__.py b/python/packages/main/agent_framework/workflow/__init__.py deleted file mode 100644 index 70f9bf49ea..0000000000 --- a/python/packages/main/agent_framework/workflow/__init__.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) Microsoft. All rights reserved. - -import importlib -from typing import Any - -PACKAGE_NAME = "agent_framework_workflow" -PACKAGE_EXTRA = "workflow" -_IMPORTS = [ - "Executor", - "FunctionExecutor", - "executor", - "WorkflowContext", - "__version__", - "events", - "WorkflowBuilder", - "ExecutorCompletedEvent", - "ExecutorEvent", - "ExecutorInvokeEvent", - "RequestInfoEvent", - "WorkflowCompletedEvent", - "WorkflowEvent", - "WorkflowStartedEvent", - "AgentRunEvent", - "AgentRunUpdateEvent", - "handler", - "AgentExecutor", - "MagenticAgentDeltaEvent", - "MagenticCallbackEvent", - "MagenticCallbackMode", - "MagenticAgentMessageEvent", - "MagenticFinalResultEvent", - "MagenticManagerBase", - "MagenticOrchestratorMessageEvent", - "AgentExecutorRequest", - "AgentExecutorResponse", - "RequestInfoExecutor", - "RequestInfoMessage", - "WorkflowRunResult", - "Workflow", - "WorkflowAgent", - "WorkflowViz", - "FileCheckpointStorage", - "ExecutorFailedEvent", - "InMemoryCheckpointStorage", - "CheckpointStorage", - "WorkflowCheckpoint", - "Case", - "Default", - "RequestResponse", - "SubWorkflowRequestInfo", - "SubWorkflowResponse", - "WorkflowExecutor", - "intercepts_request", - "MagenticBuilder", - "PlanReviewDecision", - "PlanReviewReply", - "PlanReviewRequest", - "RequestInfoEvent", - "StandardMagenticManager", - "WorkflowStatusEvent", - "WorkflowRunState", - "WorkflowErrorDetails", - "WorkflowFailedEvent", - "ConcurrentBuilder", - "SequentialBuilder", -] - - -def __getattr__(name: str) -> Any: - if name in _IMPORTS: - try: - return getattr(importlib.import_module(PACKAGE_NAME), name) - except ModuleNotFoundError as exc: - raise ModuleNotFoundError( - f"The '{PACKAGE_EXTRA}' extra is not installed, " - f"please do `pip install agent-framework[{PACKAGE_EXTRA}]`" - ) from exc - raise AttributeError(f"Module {PACKAGE_NAME} has no attribute {name}.") - - -def __dir__() -> list[str]: - return _IMPORTS diff --git a/python/packages/main/agent_framework/workflow/__init__.pyi b/python/packages/main/agent_framework/workflow/__init__.pyi deleted file mode 100644 index b50c2007a2..0000000000 --- a/python/packages/main/agent_framework/workflow/__init__.pyi +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (c) Microsoft. All rights reserved. - -from agent_framework_workflow import ( - AgentExecutor, - AgentExecutorRequest, - AgentExecutorResponse, - AgentRunEvent, - AgentRunUpdateEvent, - Case, - CheckpointStorage, - ConcurrentBuilder, - Default, - Executor, - ExecutorCompletedEvent, - ExecutorEvent, - ExecutorFailedEvent, - ExecutorInvokeEvent, - FileCheckpointStorage, - FunctionExecutor, - InMemoryCheckpointStorage, - MagenticBuilder, - MagenticCallbackEvent, - MagenticCallbackMode, - MagenticPlanReviewDecision, - MagenticPlanReviewReply, - MagenticPlanReviewRequest, - MagenticProgressLedger, - MagenticProgressLedgerItem, - RequestInfoEvent, - RequestInfoExecutor, - RequestInfoMessage, - RequestResponse, - SequentialBuilder, - StandardMagenticManager, - SubWorkflowRequestInfo, - SubWorkflowResponse, - Workflow, - WorkflowAgent, - WorkflowBuilder, - WorkflowCheckpoint, - WorkflowCompletedEvent, - WorkflowContext, - WorkflowErrorDetails, - WorkflowEvent, - WorkflowExecutor, - WorkflowFailedEvent, - WorkflowRunResult, - WorkflowRunState, - WorkflowStartedEvent, - WorkflowStatusEvent, - WorkflowViz, - __version__, - executor, - handler, - intercepts_request, -) - -__all__ = [ - "AgentExecutor", - "AgentExecutorRequest", - "AgentExecutorResponse", - "AgentRunEvent", - "AgentRunUpdateEvent", - "Case", - "CheckpointStorage", - "ConcurrentBuilder", - "Default", - "Executor", - "ExecutorCompletedEvent", - "ExecutorEvent", - "ExecutorFailedEvent", - "ExecutorInvokeEvent", - "FileCheckpointStorage", - "FunctionExecutor", - "InMemoryCheckpointStorage", - "MagenticBuilder", - "MagenticCallbackEvent", - "MagenticCallbackMode", - "MagenticPlanReviewDecision", - "MagenticPlanReviewReply", - "MagenticPlanReviewRequest", - "MagenticProgressLedger", - "MagenticProgressLedgerItem", - "RequestInfoEvent", - "RequestInfoExecutor", - "RequestInfoMessage", - "RequestResponse", - "SequentialBuilder", - "StandardMagenticManager", - "SubWorkflowRequestInfo", - "SubWorkflowResponse", - "Workflow", - "WorkflowAgent", - "WorkflowBuilder", - "WorkflowCheckpoint", - "WorkflowCompletedEvent", - "WorkflowContext", - "WorkflowErrorDetails", - "WorkflowEvent", - "WorkflowExecutor", - "WorkflowFailedEvent", - "WorkflowRunResult", - "WorkflowRunState", - "WorkflowStartedEvent", - "WorkflowStatusEvent", - "WorkflowViz", - "__version__", - "executor", - "handler", - "intercepts_request", -] diff --git a/python/packages/main/pyproject.toml b/python/packages/main/pyproject.toml index ef24985546..24eec9eee5 100644 --- a/python/packages/main/pyproject.toml +++ b/python/packages/main/pyproject.toml @@ -33,7 +33,8 @@ dependencies = [ "azure-monitor-opentelemetry>=1.7.0", "azure-monitor-opentelemetry-exporter>=1.0.0b41", "opentelemetry-exporter-otlp-proto-grpc>=1.36.0", - "opentelemetry-semantic-conventions-ai>=0.4.13" + "opentelemetry-semantic-conventions-ai>=0.4.13", + "aiofiles>=24.1.0" ] [project.optional-dependencies] @@ -43,8 +44,8 @@ azure = [ foundry = [ "agent-framework-foundry" ] -workflow = [ - "agent-framework-workflow" +viz = [ + "graphviz>=0.20.0", ] runtime = [ "agent-framework-runtime" @@ -55,7 +56,6 @@ mem0 = [ all = [ "agent-framework-azure", "agent-framework-foundry", - "agent-framework-workflow", "agent-framework-runtime", "agent-framework-mem0" ] diff --git a/python/packages/workflow/tests/test_checkpoint.py b/python/packages/main/tests/workflow/test_checkpoint.py similarity index 99% rename from python/packages/workflow/tests/test_checkpoint.py rename to python/packages/main/tests/workflow/test_checkpoint.py index 4ae5304672..0515a7ca35 100644 --- a/python/packages/workflow/tests/test_checkpoint.py +++ b/python/packages/main/tests/workflow/test_checkpoint.py @@ -5,7 +5,7 @@ import tempfile from datetime import datetime, timezone from pathlib import Path -from agent_framework_workflow._checkpoint import ( +from agent_framework import ( FileCheckpointStorage, InMemoryCheckpointStorage, WorkflowCheckpoint, diff --git a/python/packages/workflow/tests/test_concurrent.py b/python/packages/main/tests/workflow/test_concurrent.py similarity index 97% rename from python/packages/workflow/tests/test_concurrent.py rename to python/packages/main/tests/workflow/test_concurrent.py index 25becca7cd..1974b0b2e9 100644 --- a/python/packages/workflow/tests/test_concurrent.py +++ b/python/packages/main/tests/workflow/test_concurrent.py @@ -3,13 +3,15 @@ from typing import Any, cast import pytest -from agent_framework import AgentRunResponse, ChatMessage, Role -from agent_framework_workflow import ( +from agent_framework import ( AgentExecutorRequest, AgentExecutorResponse, + AgentRunResponse, + ChatMessage, ConcurrentBuilder, Executor, + Role, WorkflowCompletedEvent, WorkflowContext, handler, diff --git a/python/packages/workflow/tests/test_edge.py b/python/packages/main/tests/workflow/test_edge.py similarity index 98% rename from python/packages/workflow/tests/test_edge.py rename to python/packages/main/tests/workflow/test_edge.py index 98ecee5138..8c6692a56f 100644 --- a/python/packages/workflow/tests/test_edge.py +++ b/python/packages/main/tests/workflow/test_edge.py @@ -5,12 +5,19 @@ from typing import Any from unittest.mock import patch import pytest -from agent_framework.workflow import Executor, WorkflowContext, handler from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter -from agent_framework_workflow._edge import ( +from agent_framework import ( + Executor, + InProcRunnerContext, + Message, + SharedState, + WorkflowContext, + handler, +) +from agent_framework._workflow._edge import ( Edge, FanInEdgeGroup, FanOutEdgeGroup, @@ -19,10 +26,8 @@ from agent_framework_workflow._edge import ( SwitchCaseEdgeGroupCase, SwitchCaseEdgeGroupDefault, ) -from agent_framework_workflow._edge_runner import create_edge_runner -from agent_framework_workflow._runner_context import InProcRunnerContext, Message -from agent_framework_workflow._shared_state import SharedState -from agent_framework_workflow._telemetry import EdgeGroupDeliveryStatus, workflow_tracer +from agent_framework._workflow._edge_runner import create_edge_runner +from agent_framework._workflow._telemetry import EdgeGroupDeliveryStatus, workflow_tracer @pytest.fixture @@ -34,7 +39,7 @@ def tracing_enabled(): os.environ["AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL_DIAGNOSTICS"] = "true" # Force reload the settings to pick up the environment variable - from agent_framework_workflow._telemetry import WorkflowDiagnosticSettings + from agent_framework._workflow._telemetry import WorkflowDiagnosticSettings workflow_tracer.settings = WorkflowDiagnosticSettings() @@ -635,7 +640,7 @@ async def test_source_edge_group_with_selection_func_send_message() -> None: data = MockMessage(data="test") message = Message(data=data, source_id=source.id) - with patch("agent_framework_workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: + with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: success = await edge_runner.send_message(message, shared_state, ctx) assert success is True @@ -688,7 +693,7 @@ async def test_source_edge_group_with_selection_func_send_message_with_target() data = MockMessage(data="test") message = Message(data=data, source_id=source.id, target_id=target1.id) - with patch("agent_framework_workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: + with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: success = await edge_runner.send_message(message, shared_state, ctx) assert success is True @@ -921,7 +926,7 @@ async def test_target_edge_group_send_message_buffer() -> None: data = MockMessage(data="test") - with patch("agent_framework_workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: + with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: success = await edge_runner.send_message( Message(data=data, source_id=source1.id), shared_state, @@ -1203,7 +1208,7 @@ async def test_switch_case_edge_group_send_message() -> None: data = MockMessage(data=-1) message = Message(data=data, source_id=source.id) - with patch("agent_framework_workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: + with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: success = await edge_runner.send_message(message, shared_state, ctx) assert success is True @@ -1212,7 +1217,7 @@ async def test_switch_case_edge_group_send_message() -> None: # Default condition should data = MockMessage(data=1) message = Message(data=data, source_id=source.id) - with patch("agent_framework_workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: + with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send: success = await edge_runner.send_message(message, shared_state, ctx) assert success is True diff --git a/python/packages/workflow/tests/test_executor.py b/python/packages/main/tests/workflow/test_executor.py similarity index 98% rename from python/packages/workflow/tests/test_executor.py rename to python/packages/main/tests/workflow/test_executor.py index 21da2d9db7..c448212357 100644 --- a/python/packages/workflow/tests/test_executor.py +++ b/python/packages/main/tests/workflow/test_executor.py @@ -1,7 +1,8 @@ # Copyright (c) Microsoft. All rights reserved. import pytest -from agent_framework.workflow import Executor, WorkflowContext, handler + +from agent_framework import Executor, WorkflowContext, handler def test_executor_without_handlers(): diff --git a/python/packages/workflow/tests/test_full_conversation.py b/python/packages/main/tests/workflow/test_full_conversation.py similarity index 98% rename from python/packages/workflow/tests/test_full_conversation.py rename to python/packages/main/tests/workflow/test_full_conversation.py index f1bad2a477..a56d05a7b1 100644 --- a/python/packages/workflow/tests/test_full_conversation.py +++ b/python/packages/main/tests/workflow/test_full_conversation.py @@ -3,26 +3,24 @@ from collections.abc import AsyncIterable from typing import Any +from pydantic import PrivateAttr + from agent_framework import ( + AgentExecutor, AgentRunResponse, AgentRunResponseUpdate, AgentThread, BaseAgent, ChatMessage, Role, - TextContent, -) -from pydantic import PrivateAttr - -from agent_framework_workflow import ( - AgentExecutor, SequentialBuilder, + TextContent, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, handler, ) -from agent_framework_workflow._executor import AgentExecutorResponse, Executor +from agent_framework._workflow._executor import AgentExecutorResponse, Executor class _SimpleAgent(BaseAgent): diff --git a/python/packages/workflow/tests/test_function_executor.py b/python/packages/main/tests/workflow/test_function_executor.py similarity index 99% rename from python/packages/workflow/tests/test_function_executor.py rename to python/packages/main/tests/workflow/test_function_executor.py index ebe6ebd7b5..1ca16e9c66 100644 --- a/python/packages/workflow/tests/test_function_executor.py +++ b/python/packages/main/tests/workflow/test_function_executor.py @@ -3,7 +3,8 @@ from typing import Any import pytest -from agent_framework.workflow import ( + +from agent_framework import ( FunctionExecutor, WorkflowBuilder, WorkflowCompletedEvent, diff --git a/python/packages/workflow/tests/test_magentic.py b/python/packages/main/tests/workflow/test_magentic.py similarity index 98% rename from python/packages/workflow/tests/test_magentic.py rename to python/packages/main/tests/workflow/test_magentic.py index 5b4a96edf0..13e170cdc3 100644 --- a/python/packages/workflow/tests/test_magentic.py +++ b/python/packages/main/tests/workflow/test_magentic.py @@ -5,19 +5,13 @@ from dataclasses import dataclass from typing import Any import pytest + from agent_framework import ( AgentRunResponse, AgentRunResponseUpdate, ChatMessage, ChatResponse, ChatResponseUpdate, - Role, - TextContent, -) -from agent_framework._agents import BaseAgent -from agent_framework._clients import ChatClientProtocol as AFChatClient - -from agent_framework_workflow import ( Executor, MagenticBuilder, MagenticManagerBase, @@ -27,12 +21,16 @@ from agent_framework_workflow import ( MagenticProgressLedger, MagenticProgressLedgerItem, RequestInfoEvent, + Role, + TextContent, WorkflowCompletedEvent, WorkflowContext, WorkflowEvent, # type: ignore # noqa: E402 handler, ) -from agent_framework_workflow._magentic import ( +from agent_framework._agents import BaseAgent +from agent_framework._clients import ChatClientProtocol as AFChatClient +from agent_framework._workflow._magentic import ( MagenticContext, MagenticStartMessage, ) @@ -239,7 +237,7 @@ async def test_magentic_orchestrator_round_limit_produces_partial_result(): manager.satisfied_after_signoff = False wf = MagenticBuilder().participants(agentA=_DummyExec("agentA")).with_standard_manager(manager).build() - from agent_framework_workflow import WorkflowEvent # type: ignore + from agent_framework import WorkflowEvent # type: ignore events: list[WorkflowEvent] = [] async for ev in wf.run_stream("round limit test"): @@ -263,7 +261,7 @@ class _DummyExec(Executor): pass -from agent_framework_workflow import StandardMagenticManager # noqa: E402 +from agent_framework import StandardMagenticManager # noqa: E402 class _StubChatClient(AFChatClient): @@ -415,7 +413,7 @@ async def _collect_agent_responses_setup(participant_obj: object): captured: list[ChatMessage] = [] async def sink(event) -> None: # type: ignore[no-untyped-def] - from agent_framework_workflow._magentic import MagenticAgentMessageEvent + from agent_framework._workflow._magentic import MagenticAgentMessageEvent if isinstance(event, MagenticAgentMessageEvent) and event.message is not None: captured.append(event.message) diff --git a/python/packages/workflow/tests/test_runner.py b/python/packages/main/tests/workflow/test_runner.py similarity index 92% rename from python/packages/workflow/tests/test_runner.py rename to python/packages/main/tests/workflow/test_runner.py index 0666f1b66c..cfd01f1f08 100644 --- a/python/packages/workflow/tests/test_runner.py +++ b/python/packages/main/tests/workflow/test_runner.py @@ -4,12 +4,12 @@ import asyncio from dataclasses import dataclass import pytest -from agent_framework.workflow import Executor, WorkflowCompletedEvent, WorkflowContext, WorkflowEvent, handler -from agent_framework_workflow._edge import SingleEdgeGroup -from agent_framework_workflow._runner import Runner -from agent_framework_workflow._runner_context import InProcRunnerContext, RunnerContext -from agent_framework_workflow._shared_state import SharedState +from agent_framework import Executor, WorkflowCompletedEvent, WorkflowContext, WorkflowEvent, handler +from agent_framework._workflow._edge import SingleEdgeGroup +from agent_framework._workflow._runner import Runner +from agent_framework._workflow._runner_context import InProcRunnerContext, RunnerContext +from agent_framework._workflow._shared_state import SharedState @dataclass diff --git a/python/packages/workflow/tests/test_sequential.py b/python/packages/main/tests/workflow/test_sequential.py similarity index 98% rename from python/packages/workflow/tests/test_sequential.py rename to python/packages/main/tests/workflow/test_sequential.py index 25ccabab75..930ec4db76 100644 --- a/python/packages/workflow/tests/test_sequential.py +++ b/python/packages/main/tests/workflow/test_sequential.py @@ -4,19 +4,17 @@ from collections.abc import AsyncIterable from typing import Any import pytest + from agent_framework import ( AgentRunResponse, AgentRunResponseUpdate, AgentThread, BaseAgent, ChatMessage, - Role, - TextContent, -) - -from agent_framework_workflow import ( Executor, + Role, SequentialBuilder, + TextContent, WorkflowCompletedEvent, WorkflowContext, handler, diff --git a/python/packages/workflow/tests/test_serialization.py b/python/packages/main/tests/workflow/test_serialization.py similarity index 99% rename from python/packages/workflow/tests/test_serialization.py rename to python/packages/main/tests/workflow/test_serialization.py index e3b0177c57..2a515b2c57 100644 --- a/python/packages/workflow/tests/test_serialization.py +++ b/python/packages/main/tests/workflow/test_serialization.py @@ -4,9 +4,11 @@ import json from typing import Any import pytest -from agent_framework.workflow import Executor, WorkflowBuilder, WorkflowContext, handler -from agent_framework_workflow._edge import ( +from agent_framework import Executor, WorkflowBuilder, WorkflowContext, handler +from agent_framework._workflow._edge import ( + Case, + Default, Edge, FanInEdgeGroup, FanOutEdgeGroup, @@ -15,7 +17,7 @@ from agent_framework_workflow._edge import ( SwitchCaseEdgeGroupCase, SwitchCaseEdgeGroupDefault, ) -from agent_framework_workflow._executor import ( +from agent_framework._workflow._executor import ( WorkflowExecutor, ) @@ -629,8 +631,6 @@ class TestSerializationWorkflowClasses: def test_comprehensive_edge_groups_workflow_serialization() -> None: """Test serialization of a workflow that uses all edge group types: SwitchCase, FanOut, and FanIn.""" - from agent_framework_workflow._edge import Case, Default - # Create executors for a comprehensive workflow router = SampleExecutor(id="router") processor_a = SampleExecutor(id="proc_a") diff --git a/python/packages/workflow/tests/test_simple_sub_workflow.py b/python/packages/main/tests/workflow/test_simple_sub_workflow.py similarity index 96% rename from python/packages/workflow/tests/test_simple_sub_workflow.py rename to python/packages/main/tests/workflow/test_simple_sub_workflow.py index 07bbcd6afc..41309db05d 100644 --- a/python/packages/workflow/tests/test_simple_sub_workflow.py +++ b/python/packages/main/tests/workflow/test_simple_sub_workflow.py @@ -5,7 +5,7 @@ from dataclasses import dataclass import pytest -from agent_framework_workflow import ( +from agent_framework import ( Executor, WorkflowBuilder, WorkflowContext, @@ -37,7 +37,7 @@ class SimpleSubExecutor(Executor): @handler async def process(self, request: SimpleRequest, ctx: WorkflowContext[None]) -> None: """Process a simple request.""" - from agent_framework_workflow import WorkflowCompletedEvent + from agent_framework import WorkflowCompletedEvent # Just echo back with prefix and complete response = SimpleResponse(result=f"processed: {request.text}") diff --git a/python/packages/workflow/tests/test_sub_workflow.py b/python/packages/main/tests/workflow/test_sub_workflow.py similarity index 99% rename from python/packages/workflow/tests/test_sub_workflow.py rename to python/packages/main/tests/workflow/test_sub_workflow.py index 8687f3f47e..7bcb72e54b 100644 --- a/python/packages/workflow/tests/test_sub_workflow.py +++ b/python/packages/main/tests/workflow/test_sub_workflow.py @@ -7,7 +7,7 @@ from typing import Any import pytest from pydantic import Field -from agent_framework_workflow import ( +from agent_framework import ( Executor, RequestInfoExecutor, RequestInfoMessage, diff --git a/python/packages/workflow/tests/test_tracing.py b/python/packages/main/tests/workflow/test_tracing.py similarity index 97% rename from python/packages/workflow/tests/test_tracing.py rename to python/packages/main/tests/workflow/test_tracing.py index d42132402a..5b280727c4 100644 --- a/python/packages/workflow/tests/test_tracing.py +++ b/python/packages/main/tests/workflow/test_tracing.py @@ -10,13 +10,13 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter -from agent_framework_workflow import WorkflowBuilder -from agent_framework_workflow._executor import Executor, handler -from agent_framework_workflow._runner_context import InProcRunnerContext, Message -from agent_framework_workflow._shared_state import SharedState -from agent_framework_workflow._telemetry import WorkflowTracer, workflow_tracer -from agent_framework_workflow._workflow import Workflow -from agent_framework_workflow._workflow_context import WorkflowContext +from agent_framework import WorkflowBuilder +from agent_framework._workflow._executor import Executor, handler +from agent_framework._workflow._runner_context import InProcRunnerContext, Message +from agent_framework._workflow._shared_state import SharedState +from agent_framework._workflow._telemetry import WorkflowTracer, workflow_tracer +from agent_framework._workflow._workflow import Workflow +from agent_framework._workflow._workflow_context import WorkflowContext @pytest.fixture @@ -26,7 +26,7 @@ def tracing_enabled() -> Generator[None, None, None]: os.environ["AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL"] = "true" # Force reload the settings to pick up the environment variable - from agent_framework_workflow._telemetry import WorkflowDiagnosticSettings + from agent_framework._workflow._telemetry import WorkflowDiagnosticSettings workflow_tracer.settings = WorkflowDiagnosticSettings() @@ -153,7 +153,7 @@ async def test_workflow_tracer_configuration() -> None: os.environ["AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL"] = "true" # Force reload the settings to pick up the environment variable - from agent_framework_workflow._telemetry import WorkflowDiagnosticSettings + from agent_framework._workflow._telemetry import WorkflowDiagnosticSettings tracer.settings = WorkflowDiagnosticSettings() diff --git a/python/packages/workflow/tests/test_validation.py b/python/packages/main/tests/workflow/test_validation.py similarity index 99% rename from python/packages/workflow/tests/test_validation.py rename to python/packages/main/tests/workflow/test_validation.py index 213a9f0e53..6057f4486a 100644 --- a/python/packages/workflow/tests/test_validation.py +++ b/python/packages/main/tests/workflow/test_validation.py @@ -5,7 +5,7 @@ from typing import Any import pytest -from agent_framework_workflow import ( +from agent_framework import ( EdgeDuplicationError, Executor, GraphConnectivityError, @@ -17,8 +17,8 @@ from agent_framework_workflow import ( handler, validate_workflow_graph, ) -from agent_framework_workflow._edge import SingleEdgeGroup -from agent_framework_workflow._validation import HandlerOutputAnnotationError +from agent_framework._workflow._edge import SingleEdgeGroup +from agent_framework._workflow._validation import HandlerOutputAnnotationError class StringExecutor(Executor): diff --git a/python/packages/workflow/tests/test_viz.py b/python/packages/main/tests/workflow/test_viz.py similarity index 98% rename from python/packages/workflow/tests/test_viz.py rename to python/packages/main/tests/workflow/test_viz.py index 474cd1ade2..d445343590 100644 --- a/python/packages/workflow/tests/test_viz.py +++ b/python/packages/main/tests/workflow/test_viz.py @@ -3,9 +3,8 @@ """Tests for the workflow visualization module.""" import pytest -from agent_framework.workflow import Executor, WorkflowBuilder, WorkflowContext, WorkflowViz, handler -from agent_framework_workflow import WorkflowExecutor +from agent_framework import Executor, WorkflowBuilder, WorkflowContext, WorkflowExecutor, WorkflowViz, handler class MockExecutor(Executor): diff --git a/python/packages/workflow/tests/test_workflow.py b/python/packages/main/tests/workflow/test_workflow.py similarity index 98% rename from python/packages/workflow/tests/test_workflow.py rename to python/packages/main/tests/workflow/test_workflow.py index bdca48afbc..e1b5956c3c 100644 --- a/python/packages/workflow/tests/test_workflow.py +++ b/python/packages/main/tests/workflow/test_workflow.py @@ -5,9 +5,11 @@ from dataclasses import dataclass from typing import Any import pytest -from agent_framework.workflow import ( + +from agent_framework import ( Executor, FileCheckpointStorage, + Message, RequestInfoEvent, RequestInfoExecutor, RequestInfoMessage, @@ -19,8 +21,6 @@ from agent_framework.workflow import ( handler, ) -from agent_framework_workflow import Message - @dataclass class NumberMessage: @@ -381,7 +381,7 @@ async def test_workflow_run_stream_from_checkpoint_with_external_storage(simple_ storage = FileCheckpointStorage(temp_dir) # Create a test checkpoint manually in storage - from agent_framework_workflow._checkpoint import WorkflowCheckpoint + from agent_framework import WorkflowCheckpoint test_checkpoint = WorkflowCheckpoint( workflow_id="test-workflow", @@ -418,7 +418,7 @@ async def test_workflow_run_from_checkpoint_non_streaming(simple_executor: Execu storage = FileCheckpointStorage(temp_dir) # Create a test checkpoint manually in storage - from agent_framework_workflow._checkpoint import WorkflowCheckpoint + from agent_framework import WorkflowCheckpoint test_checkpoint = WorkflowCheckpoint( workflow_id="test-workflow", @@ -451,7 +451,7 @@ async def test_workflow_run_stream_from_checkpoint_with_responses(simple_executo storage = FileCheckpointStorage(temp_dir) # Create a test checkpoint manually in storage - from agent_framework_workflow._checkpoint import WorkflowCheckpoint + from agent_framework import WorkflowCheckpoint test_checkpoint = WorkflowCheckpoint( workflow_id="test-workflow", @@ -561,7 +561,7 @@ async def test_workflow_multiple_runs_no_state_collision(): async def test_comprehensive_edge_groups_workflow(): """Test a workflow that uses SwitchCaseEdgeGroup, FanOutEdgeGroup, and FanInEdgeGroup.""" - from agent_framework_workflow._edge import Case, Default + from agent_framework import Case, Default # Create 6 executors for different roles with different increment values router = IncrementExecutor(id="router", limit=1000, increment=1) # Increment by 1 @@ -668,7 +668,7 @@ async def test_workflow_with_simple_cycle_and_exit_condition(): # Verify cycling occurred (should have events from both executors) # Check for ExecutorInvokeEvent and ExecutorCompletedEvent types that have executor_id - from agent_framework_workflow._events import ExecutorCompletedEvent, ExecutorInvokeEvent + from agent_framework import ExecutorCompletedEvent, ExecutorInvokeEvent executor_events = [e for e in events if isinstance(e, (ExecutorInvokeEvent, ExecutorCompletedEvent))] executor_ids = {e.executor_id for e in executor_events} diff --git a/python/packages/workflow/tests/test_workflow_agent.py b/python/packages/main/tests/workflow/test_workflow_agent.py similarity index 99% rename from python/packages/workflow/tests/test_workflow_agent.py rename to python/packages/main/tests/workflow/test_workflow_agent.py index 8a8377843e..a194940d27 100644 --- a/python/packages/workflow/tests/test_workflow_agent.py +++ b/python/packages/main/tests/workflow/test_workflow_agent.py @@ -4,21 +4,20 @@ import uuid from typing import Any import pytest + from agent_framework import ( AgentRunResponse, AgentRunResponseUpdate, + AgentRunUpdateEvent, ChatMessage, + Executor, FunctionResultContent, + RequestInfoExecutor, + RequestInfoMessage, Role, TextContent, UsageContent, UsageDetails, -) -from agent_framework.workflow import ( - AgentRunUpdateEvent, - Executor, - RequestInfoExecutor, - RequestInfoMessage, WorkflowAgent, WorkflowBuilder, WorkflowContext, diff --git a/python/packages/workflow/tests/test_workflow_builder.py b/python/packages/main/tests/workflow/test_workflow_builder.py similarity index 93% rename from python/packages/workflow/tests/test_workflow_builder.py rename to python/packages/main/tests/workflow/test_workflow_builder.py index ebd3d2c9d0..bcac9c7669 100644 --- a/python/packages/workflow/tests/test_workflow_builder.py +++ b/python/packages/main/tests/workflow/test_workflow_builder.py @@ -4,8 +4,20 @@ from dataclasses import dataclass from typing import Any import pytest -from agent_framework import AgentRunResponse, AgentRunResponseUpdate, AgentThread, BaseAgent, ChatMessage, Role -from agent_framework.workflow import AgentExecutor, Executor, WorkflowBuilder, WorkflowContext, handler + +from agent_framework import ( + AgentExecutor, + AgentRunResponse, + AgentRunResponseUpdate, + AgentThread, + BaseAgent, + ChatMessage, + Executor, + Role, + WorkflowBuilder, + WorkflowContext, + handler, +) class DummyAgent(BaseAgent): diff --git a/python/packages/workflow/tests/test_workflow_states.py b/python/packages/main/tests/workflow/test_workflow_states.py similarity index 95% rename from python/packages/workflow/tests/test_workflow_states.py rename to python/packages/main/tests/workflow/test_workflow_states.py index 0070afda46..51e16d5afb 100644 --- a/python/packages/workflow/tests/test_workflow_states.py +++ b/python/packages/main/tests/workflow/test_workflow_states.py @@ -1,12 +1,15 @@ # Copyright (c) Microsoft. All rights reserved. import pytest -from agent_framework.workflow import ( + +from agent_framework import ( Executor, ExecutorFailedEvent, + InProcRunnerContext, RequestInfoEvent, RequestInfoExecutor, RequestInfoMessage, + SharedState, Workflow, WorkflowBuilder, WorkflowCompletedEvent, @@ -17,10 +20,7 @@ from agent_framework.workflow import ( WorkflowStatusEvent, handler, ) - -from agent_framework_workflow import InProcRunnerContext -from agent_framework_workflow._shared_state import SharedState -from agent_framework_workflow._workflow_context import WorkflowContext as WFContext +from agent_framework import WorkflowContext as WFContext class FailingExecutor(Executor): diff --git a/python/packages/runtime/tests/test_sample.py b/python/packages/runtime/tests/test_sample.py new file mode 100644 index 0000000000..73e3423a41 --- /dev/null +++ b/python/packages/runtime/tests/test_sample.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft. All rights reserved. + + +def test_sample(): + """Sample test so test task doesn't stop due to no tests.""" + assert True diff --git a/python/packages/workflow/LICENSE b/python/packages/workflow/LICENSE deleted file mode 100644 index 9e841e7a26..0000000000 --- a/python/packages/workflow/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - MIT License - - Copyright (c) Microsoft Corporation. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE diff --git a/python/packages/workflow/README.md b/python/packages/workflow/README.md deleted file mode 100644 index 1133074818..0000000000 --- a/python/packages/workflow/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Get Started with Microsoft Agent Framework Workflow - -Please install this package as the extra for `agent-framework`: - -```bash -pip install agent-framework[workflow] -``` - -and see the [README](https://github.com/microsoft/agent-framework/tree/main/python/README.md) for more information. diff --git a/python/packages/workflow/pyproject.toml b/python/packages/workflow/pyproject.toml deleted file mode 100644 index cccb4da09c..0000000000 --- a/python/packages/workflow/pyproject.toml +++ /dev/null @@ -1,91 +0,0 @@ -[project] -name = "agent-framework-workflow" -description = "Workflow integration for Microsoft Agent Framework." -authors = [{ name = "Microsoft", email = "SK-Support@microsoft.com"}] -readme = "README.md" -requires-python = ">=3.10" -version = "0.1.0b1" -license-files = ["LICENSE"] -urls.homepage = "https://learn.microsoft.com/en-us/semantic-kernel/overview/" -urls.source = "https://github.com/microsoft/agent-framework/tree/main/python" -urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true" -urls.issues = "https://github.com/microsoft/agent-framework/issues" -classifiers = [ - "License :: OSI Approved :: MIT License", - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Framework :: Pydantic :: 2", - "Typing :: Typed", -] -dependencies = [ - "agent-framework", -] - -[project.optional-dependencies] -viz = [ - "graphviz>=0.20.0", -] - -[tool.uv] -prerelease = "if-necessary-or-explicit" -environments = [ - "sys_platform == 'darwin'", - "sys_platform == 'linux'", - "sys_platform == 'win32'" -] - -[tool.uv-dynamic-versioning] -fallback-version = "0.0.0" -[tool.pytest.ini_options] -testpaths = 'tests' -addopts = "-ra -q -r fEX" -asyncio_mode = "auto" -asyncio_default_fixture_loop_scope = "function" -filterwarnings = [] -timeout = 120 - -[tool.ruff] -extend = "../../pyproject.toml" - -[tool.coverage.run] -omit = [ - "**/__init__.py" -] - -[tool.pyright] -extend = "../../pyproject.toml" -exclude = ['tests'] - -[tool.mypy] -plugins = ['pydantic.mypy'] -strict = true -python_version = "3.10" -ignore_missing_imports = true -disallow_untyped_defs = true -no_implicit_optional = true -check_untyped_defs = true -warn_return_any = true -show_error_codes = true -warn_unused_ignores = false -disallow_incomplete_defs = true -disallow_untyped_decorators = true - -[tool.bandit] -targets = ["agent_framework_workflow"] -exclude_dirs = ["tests"] - -[tool.poe] -executor.type = "uv" -include = "../../shared_tasks.toml" -[tool.poe.tasks] -mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_workflow" -test = "pytest --cov=agent_framework_workflow --cov-report=term-missing:skip-covered tests" - -[build-system] -requires = ["flit-core >= 3.9,<4.0"] -build-backend = "flit_core.buildapi" diff --git a/python/pyproject.toml b/python/pyproject.toml index d5b777f686..d35badb111 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -9,7 +9,6 @@ dependencies = [ "agent-framework-copilotstudio", "agent-framework-foundry", "agent-framework-mem0", - "agent-framework-workflow", ] [dependency-groups] @@ -57,7 +56,6 @@ agent-framework-copilotstudio = { workspace = true } agent-framework-foundry = { workspace = true } agent-framework-mem0 = { workspace = true } agent-framework-runtime = { workspace = true } -agent-framework-workflow = { workspace = true } [tool.ruff] line-length = 120 @@ -182,7 +180,7 @@ build = "python run_tasks_in_packages_if_exists.py build" # combined checks check = ["fmt", "lint", "pyright", "mypy", "test", "markdown-code-lint", "samples-code-check"] pre-commit-check = ["fmt", "lint", "pyright", "markdown-code-lint", "samples-code-check"] -all-tests = "pytest --import-mode=importlib --cov=agent_framework --cov=agent_framework_azure --cov=agent_framework_copilotstudio --cov=agent_framework_foundry --cov=agent_framework_mem0 --cov=agent_framework_workflow --cov-report=term-missing:skip-covered packages/azure/tests packages/copilotstudio/tests packages/foundry/tests packages/main/tests packages/mem0/tests packages/workflow/tests" +all-tests = "pytest --import-mode=importlib --cov=agent_framework --cov=agent_framework_azure --cov=agent_framework_copilotstudio --cov=agent_framework_foundry --cov=agent_framework_mem0 --cov-report=term-missing:skip-covered packages/azure/tests packages/copilotstudio/tests packages/foundry/tests packages/main/tests packages/mem0/tests" [tool.poe.tasks.venv] cmd = "uv venv --clear --python $python" diff --git a/python/samples/getting_started/telemetry/04-workflow.py b/python/samples/getting_started/telemetry/04-workflow.py index e07df885e2..88bd8b7187 100644 --- a/python/samples/getting_started/telemetry/04-workflow.py +++ b/python/samples/getting_started/telemetry/04-workflow.py @@ -3,14 +3,14 @@ import asyncio from typing import Any -from agent_framework.telemetry import setup_telemetry -from agent_framework.workflow import ( +from agent_framework import ( Executor, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, handler, ) +from agent_framework.telemetry import setup_telemetry from opentelemetry import trace from opentelemetry.trace import SpanKind from opentelemetry.trace.span import format_trace_id diff --git a/python/samples/getting_started/workflow/README.md b/python/samples/getting_started/workflow/README.md index 1a52dfe738..4b879e10dd 100644 --- a/python/samples/getting_started/workflow/README.md +++ b/python/samples/getting_started/workflow/README.md @@ -2,16 +2,12 @@ ## Installation -To install the base `agent_framework.workflow` package, run: - -```bash -pip install agent-framework-workflow -``` +Workflow support ships with the core `agent-framework` package, so no extra installation step is required. To install with visualization support: ```bash -pip install agent-framework-workflow[viz] +pip install agent-framework[viz] ``` To export visualization images you also need to [install GraphViz](https://graphviz.org/download/). diff --git a/python/samples/getting_started/workflow/_start-here/step1_executors_and_edges.py b/python/samples/getting_started/workflow/_start-here/step1_executors_and_edges.py index 14c5348575..173c578a51 100644 --- a/python/samples/getting_started/workflow/_start-here/step1_executors_and_edges.py +++ b/python/samples/getting_started/workflow/_start-here/step1_executors_and_edges.py @@ -2,7 +2,7 @@ import asyncio -from agent_framework.workflow import ( +from agent_framework import ( Executor, WorkflowBuilder, WorkflowCompletedEvent, diff --git a/python/samples/getting_started/workflow/_start-here/step2_agents_in_a_workflow.py b/python/samples/getting_started/workflow/_start-here/step2_agents_in_a_workflow.py index 3d42723a38..1c0a113965 100644 --- a/python/samples/getting_started/workflow/_start-here/step2_agents_in_a_workflow.py +++ b/python/samples/getting_started/workflow/_start-here/step2_agents_in_a_workflow.py @@ -2,8 +2,8 @@ import asyncio +from agent_framework import AgentRunEvent, WorkflowBuilder from agent_framework.azure import AzureChatClient -from agent_framework.workflow import AgentRunEvent, WorkflowBuilder from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/_start-here/step3_streaming.py b/python/samples/getting_started/workflow/_start-here/step3_streaming.py index 0619bd4c8e..423fcd53da 100644 --- a/python/samples/getting_started/workflow/_start-here/step3_streaming.py +++ b/python/samples/getting_started/workflow/_start-here/step3_streaming.py @@ -2,9 +2,9 @@ import asyncio -from agent_framework import ChatAgent, ChatMessage -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( + ChatAgent, + ChatMessage, Executor, ExecutorFailedEvent, WorkflowBuilder, @@ -15,6 +15,7 @@ from agent_framework.workflow import ( WorkflowStatusEvent, handler, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/agents/azure_chat_agents_streaming.py b/python/samples/getting_started/workflow/agents/azure_chat_agents_streaming.py index 4f39385a92..175ee30214 100644 --- a/python/samples/getting_started/workflow/agents/azure_chat_agents_streaming.py +++ b/python/samples/getting_started/workflow/agents/azure_chat_agents_streaming.py @@ -2,8 +2,8 @@ import asyncio +from agent_framework import AgentRunUpdateEvent, WorkflowBuilder, WorkflowCompletedEvent from agent_framework.azure import AzureChatClient -from agent_framework.workflow import AgentRunUpdateEvent, WorkflowBuilder, WorkflowCompletedEvent from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/agents/custom_agent_executors.py b/python/samples/getting_started/workflow/agents/custom_agent_executors.py index 6d416eb1b1..eb9497ae77 100644 --- a/python/samples/getting_started/workflow/agents/custom_agent_executors.py +++ b/python/samples/getting_started/workflow/agents/custom_agent_executors.py @@ -2,9 +2,16 @@ import asyncio -from agent_framework import ChatAgent, ChatMessage +from agent_framework import ( + ChatAgent, + ChatMessage, + Executor, + WorkflowBuilder, + WorkflowCompletedEvent, + WorkflowContext, + handler, +) from agent_framework.azure import AzureChatClient -from agent_framework.workflow import Executor, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, handler from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/agents/foundry_chat_agents_streaming.py b/python/samples/getting_started/workflow/agents/foundry_chat_agents_streaming.py index da7cba755a..20f04c2a00 100644 --- a/python/samples/getting_started/workflow/agents/foundry_chat_agents_streaming.py +++ b/python/samples/getting_started/workflow/agents/foundry_chat_agents_streaming.py @@ -3,7 +3,7 @@ # import asyncio # from agent_framework.foundry import FoundryChatClient -# from agent_framework.workflow import AgentRunUpdateEvent, WorkflowBuilder, WorkflowCompletedEvent +# from agent_framework import AgentRunUpdateEvent, WorkflowBuilder, WorkflowCompletedEvent # from azure.identity.aio import AzureCliCredential # """ @@ -100,7 +100,7 @@ from typing import Any from collections.abc import Awaitable, Callable from agent_framework.foundry import FoundryChatClient -from agent_framework.workflow import AgentRunUpdateEvent, WorkflowBuilder, WorkflowCompletedEvent +from agent_framework import AgentRunUpdateEvent, WorkflowBuilder, WorkflowCompletedEvent from azure.identity.aio import AzureCliCredential diff --git a/python/samples/getting_started/workflow/agents/workflow_as_agent_human_in_the_loop.py b/python/samples/getting_started/workflow/agents/workflow_as_agent_human_in_the_loop.py index 54940837c0..c1af5d63cc 100644 --- a/python/samples/getting_started/workflow/agents/workflow_as_agent_human_in_the_loop.py +++ b/python/samples/getting_started/workflow/agents/workflow_as_agent_human_in_the_loop.py @@ -10,7 +10,7 @@ from agent_framework import ( Role, ) from agent_framework.openai import OpenAIChatClient -from agent_framework.workflow import ( +from agent_framework import ( Executor, RequestInfoExecutor, RequestInfoMessage, diff --git a/python/samples/getting_started/workflow/agents/workflow_as_agent_reflection_pattern.py b/python/samples/getting_started/workflow/agents/workflow_as_agent_reflection_pattern.py index 8fa8835176..1dd66da437 100644 --- a/python/samples/getting_started/workflow/agents/workflow_as_agent_reflection_pattern.py +++ b/python/samples/getting_started/workflow/agents/workflow_as_agent_reflection_pattern.py @@ -6,7 +6,7 @@ from uuid import uuid4 from agent_framework import AgentRunResponseUpdate, ChatClientProtocol, ChatMessage, Contents, Role from agent_framework.openai import OpenAIChatClient -from agent_framework.workflow import AgentRunUpdateEvent, Executor, WorkflowBuilder, WorkflowContext, handler +from agent_framework import AgentRunUpdateEvent, Executor, WorkflowBuilder, WorkflowContext, handler from pydantic import BaseModel """ diff --git a/python/samples/getting_started/workflow/checkpoint/checkpoint_with_resume.py b/python/samples/getting_started/workflow/checkpoint/checkpoint_with_resume.py index db70db6ec5..839b3ad12c 100644 --- a/python/samples/getting_started/workflow/checkpoint/checkpoint_with_resume.py +++ b/python/samples/getting_started/workflow/checkpoint/checkpoint_with_resume.py @@ -5,19 +5,20 @@ import os from pathlib import Path from typing import Any -from agent_framework import ChatMessage, Role -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutor, AgentExecutorRequest, AgentExecutorResponse, + ChatMessage, Executor, FileCheckpointStorage, + Role, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, handler, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/composition/sub_workflow_basics.py b/python/samples/getting_started/workflow/composition/sub_workflow_basics.py index ed023be224..1c8013bacf 100644 --- a/python/samples/getting_started/workflow/composition/sub_workflow_basics.py +++ b/python/samples/getting_started/workflow/composition/sub_workflow_basics.py @@ -4,7 +4,7 @@ import asyncio from dataclasses import dataclass from typing import Any -from agent_framework.workflow import ( +from agent_framework import ( Executor, WorkflowBuilder, WorkflowCompletedEvent, diff --git a/python/samples/getting_started/workflow/composition/sub_workflow_parallel_requests.py b/python/samples/getting_started/workflow/composition/sub_workflow_parallel_requests.py index 7ab7737a8e..a5a5ef45bd 100644 --- a/python/samples/getting_started/workflow/composition/sub_workflow_parallel_requests.py +++ b/python/samples/getting_started/workflow/composition/sub_workflow_parallel_requests.py @@ -4,7 +4,7 @@ import asyncio from dataclasses import dataclass from typing import Any -from agent_framework.workflow import ( +from agent_framework import ( Executor, RequestInfoExecutor, WorkflowBuilder, @@ -15,7 +15,7 @@ from agent_framework.workflow import ( # Import the new sub-workflow types directly from the implementation package try: - from agent_framework_workflow import ( + from agent_framework import ( RequestInfoMessage, RequestResponse, WorkflowExecutor, @@ -26,7 +26,7 @@ except ImportError: import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "packages", "workflow")) - from agent_framework_workflow import ( + from agent_framework import ( RequestInfoMessage, RequestResponse, WorkflowExecutor, diff --git a/python/samples/getting_started/workflow/composition/sub_workflow_request_interception.py b/python/samples/getting_started/workflow/composition/sub_workflow_request_interception.py index eae530334b..2cc2be9a01 100644 --- a/python/samples/getting_started/workflow/composition/sub_workflow_request_interception.py +++ b/python/samples/getting_started/workflow/composition/sub_workflow_request_interception.py @@ -4,7 +4,7 @@ import asyncio from dataclasses import dataclass from typing import Any -from agent_framework_workflow import ( +from agent_framework import ( Executor, RequestInfoExecutor, RequestInfoMessage, diff --git a/python/samples/getting_started/workflow/control-flow/edge_condition.py b/python/samples/getting_started/workflow/control-flow/edge_condition.py index 63d2977ca4..405b237fe5 100644 --- a/python/samples/getting_started/workflow/control-flow/edge_condition.py +++ b/python/samples/getting_started/workflow/control-flow/edge_condition.py @@ -4,17 +4,18 @@ import asyncio import os from typing import Any -from agent_framework import ChatMessage, Role # Core chat primitives used to build requests -from agent_framework.azure import AzureChatClient # Thin client wrapper for Azure OpenAI chat models -from agent_framework.workflow import ( +from agent_framework import ( # Core chat primitives used to build requests AgentExecutor, # Wraps an LLM agent that can be invoked inside a workflow AgentExecutorRequest, # Input message bundle for an AgentExecutor AgentExecutorResponse, # Output from an AgentExecutor + ChatMessage, + Role, WorkflowBuilder, # Fluent builder for wiring executors and edges WorkflowCompletedEvent, # Event we emit at the end to signal completion WorkflowContext, # Per-run context and event bus executor, # Decorator to declare a Python function as a workflow executor ) +from agent_framework.azure import AzureChatClient # Thin client wrapper for Azure OpenAI chat models from azure.identity import AzureCliCredential # Uses your az CLI login for credentials from pydantic import BaseModel # Structured outputs for safer parsing diff --git a/python/samples/getting_started/workflow/control-flow/multi_selection_edge_group.py b/python/samples/getting_started/workflow/control-flow/multi_selection_edge_group.py index d14a1ab539..547f0ed740 100644 --- a/python/samples/getting_started/workflow/control-flow/multi_selection_edge_group.py +++ b/python/samples/getting_started/workflow/control-flow/multi_selection_edge_group.py @@ -8,18 +8,19 @@ from dataclasses import dataclass from typing import Literal from uuid import uuid4 -from agent_framework import ChatMessage, Role -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutor, AgentExecutorRequest, AgentExecutorResponse, + ChatMessage, + Role, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, WorkflowEvent, executor, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential from pydantic import BaseModel diff --git a/python/samples/getting_started/workflow/control-flow/sequential_executors.py b/python/samples/getting_started/workflow/control-flow/sequential_executors.py index 9da46054f3..d4921e99fa 100644 --- a/python/samples/getting_started/workflow/control-flow/sequential_executors.py +++ b/python/samples/getting_started/workflow/control-flow/sequential_executors.py @@ -3,7 +3,7 @@ import asyncio from typing import Any -from agent_framework.workflow import ( +from agent_framework import ( Executor, WorkflowBuilder, WorkflowCompletedEvent, diff --git a/python/samples/getting_started/workflow/control-flow/sequential_streaming.py b/python/samples/getting_started/workflow/control-flow/sequential_streaming.py index 9333611824..bf194ba901 100644 --- a/python/samples/getting_started/workflow/control-flow/sequential_streaming.py +++ b/python/samples/getting_started/workflow/control-flow/sequential_streaming.py @@ -2,7 +2,7 @@ import asyncio -from agent_framework.workflow import WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, executor +from agent_framework import WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, executor """ Sample: Foundational sequential workflow with streaming using function-style executors. diff --git a/python/samples/getting_started/workflow/control-flow/simple_loop.py b/python/samples/getting_started/workflow/control-flow/simple_loop.py index b2ed84e42a..d38c314b02 100644 --- a/python/samples/getting_started/workflow/control-flow/simple_loop.py +++ b/python/samples/getting_started/workflow/control-flow/simple_loop.py @@ -3,19 +3,20 @@ import asyncio from enum import Enum -from agent_framework import ChatMessage, Role -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutor, AgentExecutorRequest, AgentExecutorResponse, + ChatMessage, Executor, ExecutorCompletedEvent, + Role, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, handler, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/control-flow/switch_case_edge_group.py b/python/samples/getting_started/workflow/control-flow/switch_case_edge_group.py index b23ffafb08..0833ff5b12 100644 --- a/python/samples/getting_started/workflow/control-flow/switch_case_edge_group.py +++ b/python/samples/getting_started/workflow/control-flow/switch_case_edge_group.py @@ -6,19 +6,20 @@ from dataclasses import dataclass from typing import Any, Literal from uuid import uuid4 -from agent_framework import ChatMessage, Role # Core chat primitives used to form LLM requests -from agent_framework.azure import AzureChatClient # Thin client for Azure OpenAI chat models -from agent_framework.workflow import ( +from agent_framework import ( # Core chat primitives used to form LLM requests AgentExecutor, # Wraps an agent so it can run inside a workflow AgentExecutorRequest, # Message bundle sent to an AgentExecutor AgentExecutorResponse, # Result returned by an AgentExecutor Case, # Case entry for a switch-case edge group + ChatMessage, Default, # Default branch when no cases match + Role, WorkflowBuilder, # Fluent builder for assembling the graph WorkflowCompletedEvent, # Terminal event for successful completion WorkflowContext, # Per-run context and event bus executor, # Decorator to turn a function into a workflow executor ) +from agent_framework.azure import AzureChatClient # Thin client for Azure OpenAI chat models from azure.identity import AzureCliCredential # Uses your az CLI login for credentials from pydantic import BaseModel # Structured outputs with validation diff --git a/python/samples/getting_started/workflow/human-in-the-loop/guessing_game_with_human_input.py b/python/samples/getting_started/workflow/human-in-the-loop/guessing_game_with_human_input.py index ca5c5ec884..1be8abf83b 100644 --- a/python/samples/getting_started/workflow/human-in-the-loop/guessing_game_with_human_input.py +++ b/python/samples/getting_started/workflow/human-in-the-loop/guessing_game_with_human_input.py @@ -3,17 +3,17 @@ import asyncio from dataclasses import dataclass -from agent_framework import ChatMessage, Role -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutor, # Executor that runs the agent AgentExecutorRequest, # Message bundle sent to an AgentExecutor AgentExecutorResponse, # Result returned by an AgentExecutor - Executor, + ChatMessage, # Chat message structure + Executor, # Base class for workflow executors RequestInfoEvent, # Event emitted when human input is requested RequestInfoExecutor, # Special executor that collects human input out of band RequestInfoMessage, # Base class for request payloads sent to RequestInfoExecutor RequestResponse, # Correlates a human response with the original request + Role, # Enum of chat roles (user, assistant, system) WorkflowBuilder, # Fluent builder for assembling the graph WorkflowCompletedEvent, # Terminal event used to finish the workflow WorkflowContext, # Per run context and event bus @@ -21,6 +21,7 @@ from agent_framework.workflow import ( WorkflowStatusEvent, # Event emitted on run state changes handler, # Decorator to expose an Executor method as a step ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential from pydantic import BaseModel @@ -230,13 +231,11 @@ async def main() -> None: # Detect run state transitions for a better developer experience. pending_status = any( - isinstance(e, WorkflowStatusEvent) - and e.state == WorkflowRunState.IN_PROGRESS_PENDING_REQUESTS + isinstance(e, WorkflowStatusEvent) and e.state == WorkflowRunState.IN_PROGRESS_PENDING_REQUESTS for e in events ) idle_with_requests = any( - isinstance(e, WorkflowStatusEvent) - and e.state == WorkflowRunState.IDLE_WITH_PENDING_REQUESTS + isinstance(e, WorkflowStatusEvent) and e.state == WorkflowRunState.IDLE_WITH_PENDING_REQUESTS for e in events ) if pending_status: diff --git a/python/samples/getting_started/workflow/observability/tracing_basics.py b/python/samples/getting_started/workflow/observability/tracing_basics.py index 0fbccd9e47..3e34aefbcf 100644 --- a/python/samples/getting_started/workflow/observability/tracing_basics.py +++ b/python/samples/getting_started/workflow/observability/tracing_basics.py @@ -4,7 +4,7 @@ import asyncio import os from typing import Any -from agent_framework_workflow import Executor, WorkflowBuilder, WorkflowContext, handler +from agent_framework import Executor, WorkflowBuilder, WorkflowContext, handler """Basic tracing workflow sample. diff --git a/python/samples/getting_started/workflow/orchestration/concurrent_agents.py b/python/samples/getting_started/workflow/orchestration/concurrent_agents.py index b8e165c5b4..df3d212b4c 100644 --- a/python/samples/getting_started/workflow/orchestration/concurrent_agents.py +++ b/python/samples/getting_started/workflow/orchestration/concurrent_agents.py @@ -3,9 +3,8 @@ import asyncio from typing import Any -from agent_framework import ChatMessage +from agent_framework import ChatMessage, ConcurrentBuilder, WorkflowCompletedEvent from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ConcurrentBuilder, WorkflowCompletedEvent from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/orchestration/concurrent_custom_agent_executors.py b/python/samples/getting_started/workflow/orchestration/concurrent_custom_agent_executors.py index 067489dee2..e4883e6789 100644 --- a/python/samples/getting_started/workflow/orchestration/concurrent_custom_agent_executors.py +++ b/python/samples/getting_started/workflow/orchestration/concurrent_custom_agent_executors.py @@ -3,17 +3,18 @@ import asyncio from typing import Any -from agent_framework import ChatAgent, ChatMessage -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutorRequest, AgentExecutorResponse, + ChatAgent, + ChatMessage, ConcurrentBuilder, Executor, WorkflowCompletedEvent, WorkflowContext, handler, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/orchestration/concurrent_custom_aggregator.py b/python/samples/getting_started/workflow/orchestration/concurrent_custom_aggregator.py index 73f95388c6..02fa8c892a 100644 --- a/python/samples/getting_started/workflow/orchestration/concurrent_custom_aggregator.py +++ b/python/samples/getting_started/workflow/orchestration/concurrent_custom_aggregator.py @@ -3,9 +3,8 @@ import asyncio from typing import Any -from agent_framework import ChatMessage, Role +from agent_framework import ChatMessage, ConcurrentBuilder, Role, WorkflowCompletedEvent from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ConcurrentBuilder, WorkflowCompletedEvent from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/orchestration/magentic.py b/python/samples/getting_started/workflow/orchestration/magentic.py index e5fd8d4ba6..52be43a418 100644 --- a/python/samples/getting_started/workflow/orchestration/magentic.py +++ b/python/samples/getting_started/workflow/orchestration/magentic.py @@ -3,9 +3,9 @@ import asyncio import logging -from agent_framework import ChatAgent, HostedCodeInterpreterTool -from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient -from agent_framework_workflow import ( +from agent_framework import ( + ChatAgent, + HostedCodeInterpreterTool, MagenticAgentDeltaEvent, MagenticAgentMessageEvent, MagenticBuilder, @@ -15,6 +15,7 @@ from agent_framework_workflow import ( MagenticOrchestratorMessageEvent, WorkflowCompletedEvent, ) +from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) diff --git a/python/samples/getting_started/workflow/orchestration/magentic_human_plan_update.py b/python/samples/getting_started/workflow/orchestration/magentic_human_plan_update.py index 9e946c2d23..aec0aaa334 100644 --- a/python/samples/getting_started/workflow/orchestration/magentic_human_plan_update.py +++ b/python/samples/getting_started/workflow/orchestration/magentic_human_plan_update.py @@ -4,9 +4,9 @@ import asyncio import logging from typing import cast -from agent_framework import ChatAgent, HostedCodeInterpreterTool -from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient -from agent_framework_workflow import ( +from agent_framework import ( + ChatAgent, + HostedCodeInterpreterTool, MagenticAgentDeltaEvent, MagenticAgentMessageEvent, MagenticBuilder, @@ -20,6 +20,7 @@ from agent_framework_workflow import ( RequestInfoEvent, WorkflowCompletedEvent, ) +from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) diff --git a/python/samples/getting_started/workflow/orchestration/sequential_agents.py b/python/samples/getting_started/workflow/orchestration/sequential_agents.py index 88aa5ba37a..dfc7f154a5 100644 --- a/python/samples/getting_started/workflow/orchestration/sequential_agents.py +++ b/python/samples/getting_started/workflow/orchestration/sequential_agents.py @@ -3,9 +3,8 @@ import asyncio from typing import Any -from agent_framework import ChatMessage, Role +from agent_framework import ChatMessage, Role, SequentialBuilder, WorkflowCompletedEvent from agent_framework.azure import AzureChatClient -from agent_framework.workflow import SequentialBuilder, WorkflowCompletedEvent from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/orchestration/sequential_custom_executors.py b/python/samples/getting_started/workflow/orchestration/sequential_custom_executors.py index b78ea96626..889833f634 100644 --- a/python/samples/getting_started/workflow/orchestration/sequential_custom_executors.py +++ b/python/samples/getting_started/workflow/orchestration/sequential_custom_executors.py @@ -3,9 +3,16 @@ import asyncio from typing import Any -from agent_framework import ChatMessage, Role +from agent_framework import ( + ChatMessage, + Executor, + Role, + SequentialBuilder, + WorkflowCompletedEvent, + WorkflowContext, + handler, +) from agent_framework.azure import AzureChatClient -from agent_framework.workflow import Executor, SequentialBuilder, WorkflowCompletedEvent, WorkflowContext, handler from azure.identity import AzureCliCredential """ diff --git a/python/samples/getting_started/workflow/parallelism/fan_out_fan_in_edges.py b/python/samples/getting_started/workflow/parallelism/fan_out_fan_in_edges.py index ca96bb78d6..d28a2ca6a0 100644 --- a/python/samples/getting_started/workflow/parallelism/fan_out_fan_in_edges.py +++ b/python/samples/getting_started/workflow/parallelism/fan_out_fan_in_edges.py @@ -4,19 +4,20 @@ import asyncio from dataclasses import dataclass from typing import Any -from agent_framework import ChatMessage, Role # Core chat primitives to build LLM requests -from agent_framework.azure import AzureChatClient # Client wrapper for Azure OpenAI chat models -from agent_framework.workflow import ( +from agent_framework import ( # Core chat primitives to build LLM requests AgentExecutor, # Wraps an LLM agent for use inside a workflow AgentExecutorRequest, # The message bundle sent to an AgentExecutor AgentExecutorResponse, # The structured result returned by an AgentExecutor AgentRunEvent, # Tracing event for agent execution steps + ChatMessage, # Chat message structure Executor, # Base class for custom Python executors + Role, # Enum of chat roles (user, assistant, system) WorkflowBuilder, # Fluent builder for wiring the workflow graph WorkflowCompletedEvent, # Terminal event carrying the final result WorkflowContext, # Per run context and event bus handler, # Decorator to mark an Executor method as invokable ) +from agent_framework.azure import AzureChatClient # Client wrapper for Azure OpenAI chat models from azure.identity import AzureCliCredential # Uses your az CLI login for credentials """ diff --git a/python/samples/getting_started/workflow/parallelism/map_reduce_and_visualization.py b/python/samples/getting_started/workflow/parallelism/map_reduce_and_visualization.py index e551c44136..160b62ec6b 100644 --- a/python/samples/getting_started/workflow/parallelism/map_reduce_and_visualization.py +++ b/python/samples/getting_started/workflow/parallelism/map_reduce_and_visualization.py @@ -8,7 +8,7 @@ from dataclasses import dataclass from typing import Any import aiofiles -from agent_framework.workflow import ( +from agent_framework import ( Executor, # Base class for custom workflow steps WorkflowBuilder, # Fluent graph builder for executors and edges WorkflowCompletedEvent, # Terminal event that carries final output @@ -296,7 +296,7 @@ async def main(): svg_file = viz.export(format="svg") print(f"SVG file saved to: {svg_file}") except ImportError: - print("Tip: Install 'viz' extra to export workflow visualization: pip install agent-framework-workflow[viz]") + print("Tip: Install 'viz' extra to export workflow visualization: pip install agent-framework[viz]") # Step 3: Open the text file and read its content. async with aiofiles.open(os.path.join(DIR, "resources", "long_text.txt"), "r") as f: diff --git a/python/samples/getting_started/workflow/state-management/shared_states_with_agents.py b/python/samples/getting_started/workflow/state-management/shared_states_with_agents.py index 45c71b516c..c5584bc0fc 100644 --- a/python/samples/getting_started/workflow/state-management/shared_states_with_agents.py +++ b/python/samples/getting_started/workflow/state-management/shared_states_with_agents.py @@ -6,16 +6,17 @@ from dataclasses import dataclass from typing import Any from uuid import uuid4 -from agent_framework import ChatMessage, Role -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutorRequest, AgentExecutorResponse, + ChatMessage, + Role, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, executor, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential from pydantic import BaseModel diff --git a/python/samples/getting_started/workflow/visualization/concurrent_with_visualization.py b/python/samples/getting_started/workflow/visualization/concurrent_with_visualization.py index 28cdae27f4..dfc4c3b0fd 100644 --- a/python/samples/getting_started/workflow/visualization/concurrent_with_visualization.py +++ b/python/samples/getting_started/workflow/visualization/concurrent_with_visualization.py @@ -4,20 +4,21 @@ import asyncio from dataclasses import dataclass from typing import Any -from agent_framework import ChatMessage, Role -from agent_framework.azure import AzureChatClient -from agent_framework.workflow import ( +from agent_framework import ( AgentExecutor, AgentExecutorRequest, AgentExecutorResponse, AgentRunEvent, + ChatMessage, Executor, + Role, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, WorkflowViz, handler, ) +from agent_framework.azure import AzureChatClient from azure.identity import AzureCliCredential """ @@ -31,7 +32,7 @@ What it does: Prerequisites: - Azure AI/ Azure OpenAI for `AzureChatClient` agents. - Authentication via `azure-identity` — uses `AzureCliCredential()` (run `az login`). -- For visualization export: `pip install agent-framework-workflow[viz]` and install GraphViz binaries. +- For visualization export: `pip install agent-framework[viz]` and install GraphViz binaries. """ @@ -161,7 +162,7 @@ async def main() -> None: svg_file = viz.export(format="svg") print(f"SVG file saved to: {svg_file}") except ImportError: - print("Tip: Install 'viz' extra to export workflow visualization: pip install agent-framework-workflow[viz]") + print("Tip: Install 'viz' extra to export workflow visualization: pip install agent-framework[viz]") # 3) Run with a single prompt completion: WorkflowCompletedEvent | None = None diff --git a/python/uv.lock b/python/uv.lock index f7b264d5b2..06a3ee6a41 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -30,7 +30,6 @@ members = [ "agent-framework-mem0", "agent-framework-project", "agent-framework-runtime", - "agent-framework-workflow", ] [[package]] @@ -38,6 +37,7 @@ name = "agent-framework" version = "0.1.0b1" source = { editable = "packages/main" } dependencies = [ + { name = "aiofiles", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "azure-monitor-opentelemetry", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "azure-monitor-opentelemetry-exporter", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "mcp", extra = ["ws"], marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -57,7 +57,6 @@ all = [ { name = "agent-framework-foundry", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "agent-framework-mem0", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "agent-framework-runtime", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, - { name = "agent-framework-workflow", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] azure = [ { name = "agent-framework-azure", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -71,8 +70,8 @@ mem0 = [ runtime = [ { name = "agent-framework-runtime", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] -workflow = [ - { name = "agent-framework-workflow", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +viz = [ + { name = "graphviz", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] [package.metadata] @@ -85,10 +84,10 @@ requires-dist = [ { name = "agent-framework-mem0", marker = "extra == 'mem0'", editable = "packages/mem0" }, { name = "agent-framework-runtime", marker = "extra == 'all'", editable = "packages/runtime" }, { name = "agent-framework-runtime", marker = "extra == 'runtime'", editable = "packages/runtime" }, - { name = "agent-framework-workflow", marker = "extra == 'all'", editable = "packages/workflow" }, - { name = "agent-framework-workflow", marker = "extra == 'workflow'", editable = "packages/workflow" }, + { name = "aiofiles", specifier = ">=24.1.0" }, { name = "azure-monitor-opentelemetry", specifier = ">=1.7.0" }, { name = "azure-monitor-opentelemetry-exporter", specifier = ">=1.0.0b41" }, + { name = "graphviz", marker = "extra == 'viz'", specifier = ">=0.20.0" }, { name = "mcp", extras = ["ws"], specifier = ">=1.13" }, { name = "openai", specifier = ">=1.99.0" }, { name = "opentelemetry-api", specifier = "~=1.24" }, @@ -99,7 +98,7 @@ requires-dist = [ { name = "pydantic-settings", specifier = ">=2.10.1" }, { name = "typing-extensions", specifier = ">=4.14.0" }, ] -provides-extras = ["azure", "foundry", "workflow", "runtime", "mem0", "all"] +provides-extras = ["azure", "foundry", "viz", "runtime", "mem0", "all"] [[package]] name = "agent-framework-azure" @@ -175,7 +174,6 @@ dependencies = [ { name = "agent-framework-copilotstudio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "agent-framework-foundry", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "agent-framework-mem0", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, - { name = "agent-framework-workflow", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] [package.dev-dependencies] @@ -208,7 +206,6 @@ requires-dist = [ { name = "agent-framework-copilotstudio", editable = "packages/copilotstudio" }, { name = "agent-framework-foundry", editable = "packages/foundry" }, { name = "agent-framework-mem0", editable = "packages/mem0" }, - { name = "agent-framework-workflow", editable = "packages/workflow" }, ] [package.metadata.requires-dev] @@ -246,25 +243,14 @@ dependencies = [ requires-dist = [{ name = "agent-framework", editable = "packages/main" }] [[package]] -name = "agent-framework-workflow" -version = "0.1.0b1" -source = { editable = "packages/workflow" } -dependencies = [ - { name = "agent-framework", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +name = "aiofiles" +version = "24.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" }, ] -[package.optional-dependencies] -viz = [ - { name = "graphviz", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, -] - -[package.metadata] -requires-dist = [ - { name = "agent-framework", editable = "packages/main" }, - { name = "graphviz", marker = "extra == 'viz'", specifier = ">=0.20.0" }, -] -provides-extras = ["viz"] - [[package]] name = "aiohappyeyeballs" version = "2.6.1" @@ -971,7 +957,7 @@ name = "exceptiongroup" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "(python_full_version < '3.13' and sys_platform == 'darwin') or (python_full_version < '3.13' and sys_platform == 'linux') or (python_full_version < '3.13' and sys_platform == 'win32')" }, + { name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } wheels = [