diff --git a/docs/docs/SUMMARY.md b/docs/docs/SUMMARY.md index bd1b9d9d..8cb3e5cf 100644 --- a/docs/docs/SUMMARY.md +++ b/docs/docs/SUMMARY.md @@ -33,7 +33,24 @@ search: - [TextInput](api/fastagency/TextInput.md) - [TextMessage](api/fastagency/TextMessage.md) - [UI](api/fastagency/UI.md) - - [Workflows](api/fastagency/Workflows.md) + - [WorkflowsProtocol](api/fastagency/WorkflowsProtocol.md) + - adapters + - fastapi + - [FastAPIAdapter](api/fastagency/adapters/fastapi/FastAPIAdapter.md) + - [FastAPIProvider](api/fastagency/adapters/fastapi/FastAPIProvider.md) + - base + - [FastAPIAdapter](api/fastagency/adapters/fastapi/base/FastAPIAdapter.md) + - [FastAPIProvider](api/fastagency/adapters/fastapi/base/FastAPIProvider.md) + - nats + - [InitiateModel](api/fastagency/adapters/nats/InitiateModel.md) + - [InputResponseModel](api/fastagency/adapters/nats/InputResponseModel.md) + - [NatsAdapter](api/fastagency/adapters/nats/NatsAdapter.md) + - [NatsProvider](api/fastagency/adapters/nats/NatsProvider.md) + - base + - [InitiateModel](api/fastagency/adapters/nats/base/InitiateModel.md) + - [InputResponseModel](api/fastagency/adapters/nats/base/InputResponseModel.md) + - [NatsAdapter](api/fastagency/adapters/nats/base/NatsAdapter.md) + - [NatsProvider](api/fastagency/adapters/nats/base/NatsProvider.md) - api - openapi - [OpenAPI](api/fastagency/api/openapi/OpenAPI.md) @@ -56,22 +73,24 @@ search: - app - [FastAgency](api/fastagency/app/FastAgency.md) - base - - [ASGI](api/fastagency/base/ASGI.md) + - [ASGIProtocol](api/fastagency/base/ASGIProtocol.md) + - [AdapterProtocol](api/fastagency/base/AdapterProtocol.md) - [AskingMessage](api/fastagency/base/AskingMessage.md) - [Error](api/fastagency/base/Error.md) - [FunctionCallExecution](api/fastagency/base/FunctionCallExecution.md) - [IOMessage](api/fastagency/base/IOMessage.md) - [IOMessageVisitor](api/fastagency/base/IOMessageVisitor.md) - [MultipleChoice](api/fastagency/base/MultipleChoice.md) + - [ProviderProtocol](api/fastagency/base/ProviderProtocol.md) - [Runnable](api/fastagency/base/Runnable.md) - [SuggestedFunctionCall](api/fastagency/base/SuggestedFunctionCall.md) - [SystemMessage](api/fastagency/base/SystemMessage.md) - [TextInput](api/fastagency/base/TextInput.md) - [TextMessage](api/fastagency/base/TextMessage.md) - [UI](api/fastagency/base/UI.md) - - [WSGI](api/fastagency/base/WSGI.md) + - [WSGIProtocol](api/fastagency/base/WSGIProtocol.md) - [WorkflowCompleted](api/fastagency/base/WorkflowCompleted.md) - - [Workflows](api/fastagency/base/Workflows.md) + - [WorkflowsProtocol](api/fastagency/base/WorkflowsProtocol.md) - [run_workflow](api/fastagency/base/run_workflow.md) - cli - cli @@ -103,14 +122,6 @@ search: - [optional_temp_path](api/fastagency/helpers/optional_temp_path.md) - logging - [get_logger](api/fastagency/logging/get_logger.md) - - new - - base - - [ClientProtocol](api/fastagency/new/base/ClientProtocol.md) - - [Conversation](api/fastagency/new/base/Conversation.md) - - [FastAPIConversationClient](api/fastagency/new/base/FastAPIConversationClient.md) - - [NatsProvider](api/fastagency/new/base/NatsProvider.md) - - [ProviderProtocol](api/fastagency/new/base/ProviderProtocol.md) - - [WorkflowInfo](api/fastagency/new/base/WorkflowInfo.md) - runtime - autogen - [AutoGenWorkflows](api/fastagency/runtime/autogen/AutoGenWorkflows.md) @@ -133,12 +144,6 @@ search: - [ConsoleUI](api/fastagency/ui/console/ConsoleUI.md) - base - [ConsoleUI](api/fastagency/ui/console/base/ConsoleUI.md) - - fastapi - - [FastAPIProvider](api/fastagency/ui/fastapi/FastAPIProvider.md) - - [FastAPIWorkflows](api/fastagency/ui/fastapi/FastAPIWorkflows.md) - - base - - [FastAPIProvider](api/fastagency/ui/fastapi/base/FastAPIProvider.md) - - [FastAPIWorkflows](api/fastagency/ui/fastapi/base/FastAPIWorkflows.md) - mesop - [MesopUI](api/fastagency/ui/mesop/MesopUI.md) - base @@ -173,16 +178,6 @@ search: - [MesopMultipleChoiceInnerStyles](api/fastagency/ui/mesop/styles/MesopMultipleChoiceInnerStyles.md) - [MesopSingleChoiceInnerStyles](api/fastagency/ui/mesop/styles/MesopSingleChoiceInnerStyles.md) - [MesopTextInputInnerStyles](api/fastagency/ui/mesop/styles/MesopTextInputInnerStyles.md) - - nats - - [InitiateModel](api/fastagency/ui/nats/InitiateModel.md) - - [InputResponseModel](api/fastagency/ui/nats/InputResponseModel.md) - - [NatsProvider](api/fastagency/ui/nats/NatsProvider.md) - - [NatsWorkflows](api/fastagency/ui/nats/NatsWorkflows.md) - - base - - [InitiateModel](api/fastagency/ui/nats/base/InitiateModel.md) - - [InputResponseModel](api/fastagency/ui/nats/base/InputResponseModel.md) - - [NatsProvider](api/fastagency/ui/nats/base/NatsProvider.md) - - [NatsWorkflows](api/fastagency/ui/nats/base/NatsWorkflows.md) - [CLI](cli/cli.md) - [Contributing](contributing/index.md) - [Development](contributing/CONTRIBUTING.md) diff --git a/docs/docs/en/api/fastagency/Workflows.md b/docs/docs/en/api/fastagency/WorkflowsProtocol.md similarity index 76% rename from docs/docs/en/api/fastagency/Workflows.md rename to docs/docs/en/api/fastagency/WorkflowsProtocol.md index 7ae0ecc8..9e05a5d0 100644 --- a/docs/docs/en/api/fastagency/Workflows.md +++ b/docs/docs/en/api/fastagency/WorkflowsProtocol.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.Workflows +::: fastagency.WorkflowsProtocol diff --git a/docs/docs/en/api/fastagency/adapters/fastapi/FastAPIAdapter.md b/docs/docs/en/api/fastagency/adapters/fastapi/FastAPIAdapter.md new file mode 100644 index 00000000..c77828a7 --- /dev/null +++ b/docs/docs/en/api/fastagency/adapters/fastapi/FastAPIAdapter.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.adapters.fastapi.FastAPIAdapter diff --git a/docs/docs/en/api/fastagency/ui/fastapi/FastAPIProvider.md b/docs/docs/en/api/fastagency/adapters/fastapi/FastAPIProvider.md similarity index 69% rename from docs/docs/en/api/fastagency/ui/fastapi/FastAPIProvider.md rename to docs/docs/en/api/fastagency/adapters/fastapi/FastAPIProvider.md index b8b1fee2..e002a2c1 100644 --- a/docs/docs/en/api/fastagency/ui/fastapi/FastAPIProvider.md +++ b/docs/docs/en/api/fastagency/adapters/fastapi/FastAPIProvider.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.fastapi.FastAPIProvider +::: fastagency.adapters.fastapi.FastAPIProvider diff --git a/docs/docs/en/api/fastagency/adapters/fastapi/base/FastAPIAdapter.md b/docs/docs/en/api/fastagency/adapters/fastapi/base/FastAPIAdapter.md new file mode 100644 index 00000000..b0db33fb --- /dev/null +++ b/docs/docs/en/api/fastagency/adapters/fastapi/base/FastAPIAdapter.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.adapters.fastapi.base.FastAPIAdapter diff --git a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIProvider.md b/docs/docs/en/api/fastagency/adapters/fastapi/base/FastAPIProvider.md similarity index 67% rename from docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIProvider.md rename to docs/docs/en/api/fastagency/adapters/fastapi/base/FastAPIProvider.md index cf91cc6e..3b064634 100644 --- a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIProvider.md +++ b/docs/docs/en/api/fastagency/adapters/fastapi/base/FastAPIProvider.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.fastapi.base.FastAPIProvider +::: fastagency.adapters.fastapi.base.FastAPIProvider diff --git a/docs/docs/en/api/fastagency/ui/nats/InitiateModel.md b/docs/docs/en/api/fastagency/adapters/nats/InitiateModel.md similarity index 71% rename from docs/docs/en/api/fastagency/ui/nats/InitiateModel.md rename to docs/docs/en/api/fastagency/adapters/nats/InitiateModel.md index 20e89286..e99a3258 100644 --- a/docs/docs/en/api/fastagency/ui/nats/InitiateModel.md +++ b/docs/docs/en/api/fastagency/adapters/nats/InitiateModel.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.nats.InitiateModel +::: fastagency.adapters.nats.InitiateModel diff --git a/docs/docs/en/api/fastagency/ui/nats/InputResponseModel.md b/docs/docs/en/api/fastagency/adapters/nats/InputResponseModel.md similarity index 69% rename from docs/docs/en/api/fastagency/ui/nats/InputResponseModel.md rename to docs/docs/en/api/fastagency/adapters/nats/InputResponseModel.md index bf452b7d..3f2faba7 100644 --- a/docs/docs/en/api/fastagency/ui/nats/InputResponseModel.md +++ b/docs/docs/en/api/fastagency/adapters/nats/InputResponseModel.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.nats.InputResponseModel +::: fastagency.adapters.nats.InputResponseModel diff --git a/docs/docs/en/api/fastagency/adapters/nats/NatsAdapter.md b/docs/docs/en/api/fastagency/adapters/nats/NatsAdapter.md new file mode 100644 index 00000000..a7de7125 --- /dev/null +++ b/docs/docs/en/api/fastagency/adapters/nats/NatsAdapter.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.adapters.nats.NatsAdapter diff --git a/docs/docs/en/api/fastagency/new/base/NatsProvider.md b/docs/docs/en/api/fastagency/adapters/nats/NatsProvider.md similarity index 72% rename from docs/docs/en/api/fastagency/new/base/NatsProvider.md rename to docs/docs/en/api/fastagency/adapters/nats/NatsProvider.md index b0b17d9e..11e92f3a 100644 --- a/docs/docs/en/api/fastagency/new/base/NatsProvider.md +++ b/docs/docs/en/api/fastagency/adapters/nats/NatsProvider.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.new.base.NatsProvider +::: fastagency.adapters.nats.NatsProvider diff --git a/docs/docs/en/api/fastagency/ui/nats/base/InitiateModel.md b/docs/docs/en/api/fastagency/adapters/nats/base/InitiateModel.md similarity index 69% rename from docs/docs/en/api/fastagency/ui/nats/base/InitiateModel.md rename to docs/docs/en/api/fastagency/adapters/nats/base/InitiateModel.md index 8c200f44..3f49c002 100644 --- a/docs/docs/en/api/fastagency/ui/nats/base/InitiateModel.md +++ b/docs/docs/en/api/fastagency/adapters/nats/base/InitiateModel.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.nats.base.InitiateModel +::: fastagency.adapters.nats.base.InitiateModel diff --git a/docs/docs/en/api/fastagency/ui/nats/base/InputResponseModel.md b/docs/docs/en/api/fastagency/adapters/nats/base/InputResponseModel.md similarity index 67% rename from docs/docs/en/api/fastagency/ui/nats/base/InputResponseModel.md rename to docs/docs/en/api/fastagency/adapters/nats/base/InputResponseModel.md index 8962b356..f05f3b82 100644 --- a/docs/docs/en/api/fastagency/ui/nats/base/InputResponseModel.md +++ b/docs/docs/en/api/fastagency/adapters/nats/base/InputResponseModel.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.nats.base.InputResponseModel +::: fastagency.adapters.nats.base.InputResponseModel diff --git a/docs/docs/en/api/fastagency/adapters/nats/base/NatsAdapter.md b/docs/docs/en/api/fastagency/adapters/nats/base/NatsAdapter.md new file mode 100644 index 00000000..330ab27d --- /dev/null +++ b/docs/docs/en/api/fastagency/adapters/nats/base/NatsAdapter.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.adapters.nats.base.NatsAdapter diff --git a/docs/docs/en/api/fastagency/ui/nats/NatsProvider.md b/docs/docs/en/api/fastagency/adapters/nats/base/NatsProvider.md similarity index 70% rename from docs/docs/en/api/fastagency/ui/nats/NatsProvider.md rename to docs/docs/en/api/fastagency/adapters/nats/base/NatsProvider.md index 03b325f3..e162cfb8 100644 --- a/docs/docs/en/api/fastagency/ui/nats/NatsProvider.md +++ b/docs/docs/en/api/fastagency/adapters/nats/base/NatsProvider.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.nats.NatsProvider +::: fastagency.adapters.nats.base.NatsProvider diff --git a/docs/docs/en/api/fastagency/base/ASGI.md b/docs/docs/en/api/fastagency/base/ASGIProtocol.md similarity index 76% rename from docs/docs/en/api/fastagency/base/ASGI.md rename to docs/docs/en/api/fastagency/base/ASGIProtocol.md index 6ae20cae..c699a383 100644 --- a/docs/docs/en/api/fastagency/base/ASGI.md +++ b/docs/docs/en/api/fastagency/base/ASGIProtocol.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.base.ASGI +::: fastagency.base.ASGIProtocol diff --git a/docs/docs/en/api/fastagency/base/Workflows.md b/docs/docs/en/api/fastagency/base/AdapterProtocol.md similarity index 75% rename from docs/docs/en/api/fastagency/base/Workflows.md rename to docs/docs/en/api/fastagency/base/AdapterProtocol.md index 5ba7c0f1..0bb7d6bc 100644 --- a/docs/docs/en/api/fastagency/base/Workflows.md +++ b/docs/docs/en/api/fastagency/base/AdapterProtocol.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.base.Workflows +::: fastagency.base.AdapterProtocol diff --git a/docs/docs/en/api/fastagency/base/ProviderProtocol.md b/docs/docs/en/api/fastagency/base/ProviderProtocol.md new file mode 100644 index 00000000..5abac1df --- /dev/null +++ b/docs/docs/en/api/fastagency/base/ProviderProtocol.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.base.ProviderProtocol diff --git a/docs/docs/en/api/fastagency/base/WSGI.md b/docs/docs/en/api/fastagency/base/WSGIProtocol.md similarity index 76% rename from docs/docs/en/api/fastagency/base/WSGI.md rename to docs/docs/en/api/fastagency/base/WSGIProtocol.md index 6dea07ed..107c23df 100644 --- a/docs/docs/en/api/fastagency/base/WSGI.md +++ b/docs/docs/en/api/fastagency/base/WSGIProtocol.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.base.WSGI +::: fastagency.base.WSGIProtocol diff --git a/docs/docs/en/api/fastagency/base/WorkflowsProtocol.md b/docs/docs/en/api/fastagency/base/WorkflowsProtocol.md new file mode 100644 index 00000000..6c9a4d56 --- /dev/null +++ b/docs/docs/en/api/fastagency/base/WorkflowsProtocol.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.base.WorkflowsProtocol diff --git a/docs/docs/en/api/fastagency/new/base/ClientProtocol.md b/docs/docs/en/api/fastagency/new/base/ClientProtocol.md deleted file mode 100644 index 36e3c313..00000000 --- a/docs/docs/en/api/fastagency/new/base/ClientProtocol.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.new.base.ClientProtocol diff --git a/docs/docs/en/api/fastagency/new/base/Conversation.md b/docs/docs/en/api/fastagency/new/base/Conversation.md deleted file mode 100644 index 675781d3..00000000 --- a/docs/docs/en/api/fastagency/new/base/Conversation.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.new.base.Conversation diff --git a/docs/docs/en/api/fastagency/new/base/FastAPIConversationClient.md b/docs/docs/en/api/fastagency/new/base/FastAPIConversationClient.md deleted file mode 100644 index a606b8cf..00000000 --- a/docs/docs/en/api/fastagency/new/base/FastAPIConversationClient.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.new.base.FastAPIConversationClient diff --git a/docs/docs/en/api/fastagency/new/base/ProviderProtocol.md b/docs/docs/en/api/fastagency/new/base/ProviderProtocol.md deleted file mode 100644 index 8e8113f0..00000000 --- a/docs/docs/en/api/fastagency/new/base/ProviderProtocol.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.new.base.ProviderProtocol diff --git a/docs/docs/en/api/fastagency/new/base/WorkflowInfo.md b/docs/docs/en/api/fastagency/new/base/WorkflowInfo.md deleted file mode 100644 index 69a6deff..00000000 --- a/docs/docs/en/api/fastagency/new/base/WorkflowInfo.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.new.base.WorkflowInfo diff --git a/docs/docs/en/api/fastagency/ui/fastapi/FastAPIWorkflows.md b/docs/docs/en/api/fastagency/ui/fastapi/FastAPIWorkflows.md deleted file mode 100644 index c937d7df..00000000 --- a/docs/docs/en/api/fastagency/ui/fastapi/FastAPIWorkflows.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.ui.fastapi.FastAPIWorkflows diff --git a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIWorkflows.md b/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIWorkflows.md deleted file mode 100644 index 0ed6b0de..00000000 --- a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIWorkflows.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.ui.fastapi.base.FastAPIWorkflows diff --git a/docs/docs/en/api/fastagency/ui/nats/NatsWorkflows.md b/docs/docs/en/api/fastagency/ui/nats/NatsWorkflows.md deleted file mode 100644 index 5935a875..00000000 --- a/docs/docs/en/api/fastagency/ui/nats/NatsWorkflows.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.ui.nats.NatsWorkflows diff --git a/docs/docs/en/api/fastagency/ui/nats/base/NatsProvider.md b/docs/docs/en/api/fastagency/ui/nats/base/NatsProvider.md deleted file mode 100644 index 0d6b7582..00000000 --- a/docs/docs/en/api/fastagency/ui/nats/base/NatsProvider.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.ui.nats.base.NatsProvider diff --git a/docs/docs/en/api/fastagency/ui/nats/base/NatsWorkflows.md b/docs/docs/en/api/fastagency/ui/nats/base/NatsWorkflows.md deleted file mode 100644 index 6bf34652..00000000 --- a/docs/docs/en/api/fastagency/ui/nats/base/NatsWorkflows.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -# 0.5 - API -# 2 - Release -# 3 - Contributing -# 5 - Template Page -# 10 - Default -search: - boost: 0.5 ---- - -::: fastagency.ui.nats.base.NatsWorkflows diff --git a/docs/docs_src/getting_started/main_console.py b/docs/docs_src/getting_started/main_console.py index d76c947c..ce3223a8 100644 --- a/docs/docs_src/getting_started/main_console.py +++ b/docs/docs_src/getting_started/main_console.py @@ -2,7 +2,7 @@ from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.runtime.autogen import AutoGenWorkflows from fastagency.ui.console import ConsoleUI @@ -21,7 +21,7 @@ @wf.register(name="simple_learning", description="Student and teacher learning chat") def simple_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: student_agent = ConversableAgent( name="Student_Agent", @@ -44,4 +44,4 @@ def simple_workflow( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI(), title="Learning Chat") +app = FastAgency(provider=wf, ui=ConsoleUI(), title="Learning Chat") diff --git a/docs/docs_src/getting_started/main_mesop.py b/docs/docs_src/getting_started/main_mesop.py index 7b7f05b5..e22a1cb0 100644 --- a/docs/docs_src/getting_started/main_mesop.py +++ b/docs/docs_src/getting_started/main_mesop.py @@ -2,7 +2,7 @@ from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.runtime.autogen import AutoGenWorkflows from fastagency.ui.mesop import MesopUI @@ -21,7 +21,7 @@ @wf.register(name="simple_learning", description="Student and teacher learning chat") def simple_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: student_agent = ConversableAgent( name="Student_Agent", @@ -44,4 +44,4 @@ def simple_workflow( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=MesopUI(), title="Learning Chat") +app = FastAgency(provider=wf, ui=MesopUI(), title="Learning Chat") diff --git a/docs/docs_src/tutorial/giphy/main.py b/docs/docs_src/tutorial/giphy/main.py index da803dba..61ee7216 100644 --- a/docs/docs_src/tutorial/giphy/main.py +++ b/docs/docs_src/tutorial/giphy/main.py @@ -4,7 +4,7 @@ from autogen import register_function from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.api.openapi.client import OpenAPI from fastagency.api.openapi.security import APIKeyQuery from fastagency.base import TextInput @@ -58,7 +58,7 @@ @wf.register(name="giphy_and_websurfer", description="Giphy and Websurfer chat") def giphy_workflow_with_security( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: def is_termination_msg(msg: dict[str, Any]) -> bool: return msg["content"] is not None and "TERMINATE" in msg["content"] @@ -119,4 +119,4 @@ def present_completed_task_or_ask_question( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=MesopUI(), title="Giphy and Websurfer chat") +app = FastAgency(provider=wf, ui=MesopUI(), title="Giphy and Websurfer chat") diff --git a/docs/docs_src/tutorial/giphy/simple_main.py b/docs/docs_src/tutorial/giphy/simple_main.py index aacc48dd..79e081a4 100644 --- a/docs/docs_src/tutorial/giphy/simple_main.py +++ b/docs/docs_src/tutorial/giphy/simple_main.py @@ -3,7 +3,7 @@ from autogen import ConversableAgent, UserProxyAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.api.openapi.client import OpenAPI from fastagency.api.openapi.security import APIKeyQuery from fastagency.runtime.autogen.base import AutoGenWorkflows @@ -30,7 +30,7 @@ @wf.register(name="giphy_chat", description="Giphy chat") def giphy_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: def is_termination_msg(msg: dict[str, Any]) -> bool: return msg["content"] is not None and "TERMINATE" in msg["content"] @@ -70,4 +70,4 @@ def is_termination_msg(msg: dict[str, Any]) -> bool: return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=MesopUI(), title="Giphy chat") +app = FastAgency(provider=wf, ui=MesopUI(), title="Giphy chat") diff --git a/docs/docs_src/user_guide/custom_user_interactions/main.py b/docs/docs_src/user_guide/custom_user_interactions/main.py index b4358490..f293e542 100644 --- a/docs/docs_src/user_guide/custom_user_interactions/main.py +++ b/docs/docs_src/user_guide/custom_user_interactions/main.py @@ -4,7 +4,7 @@ from autogen import register_function from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.base import MultipleChoice, SystemMessage, TextInput from fastagency.runtime.autogen.base import AutoGenWorkflows from fastagency.ui.console import ConsoleUI @@ -23,7 +23,7 @@ @wf.register(name="exam_practice", description="Student and teacher chat") -def exam_learning(wf: Workflows, ui: UI, initial_message: str, session_id: str) -> str: +def exam_learning(wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str) -> str: def is_termination_msg(msg: dict[str, Any]) -> bool: return msg["content"] is not None and "TERMINATE" in msg["content"] @@ -130,4 +130,4 @@ def get_final_grade( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/docs/docs_src/user_guide/external_rest_apis/main.py b/docs/docs_src/user_guide/external_rest_apis/main.py index 821a705b..91bb5a30 100644 --- a/docs/docs_src/user_guide/external_rest_apis/main.py +++ b/docs/docs_src/user_guide/external_rest_apis/main.py @@ -3,7 +3,7 @@ from autogen import UserProxyAgent from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.api.openapi import OpenAPI from fastagency.runtime.autogen.base import AutoGenWorkflows from fastagency.ui.console import ConsoleUI @@ -26,7 +26,7 @@ @wf.register(name="simple_weather", description="Weather chat") def weather_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: user_agent = UserProxyAgent( name="User_Agent", @@ -57,4 +57,4 @@ def weather_workflow( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/docs/docs_src/user_guide/external_rest_apis/security.py b/docs/docs_src/user_guide/external_rest_apis/security.py index 99c6d8ad..f123b415 100644 --- a/docs/docs_src/user_guide/external_rest_apis/security.py +++ b/docs/docs_src/user_guide/external_rest_apis/security.py @@ -3,7 +3,7 @@ from autogen import UserProxyAgent from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.api.openapi.client import OpenAPI from fastagency.api.openapi.security import APIKeyHeader from fastagency.runtime.autogen.base import AutoGenWorkflows @@ -38,7 +38,7 @@ name="simple_weather_with_security", description="Weather chat with security" ) def weather_workflow_with_security( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: user_agent = UserProxyAgent( name="User_Agent", @@ -69,4 +69,4 @@ def weather_workflow_with_security( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/docs/docs_src/user_guide/runtime/autogen/main.py b/docs/docs_src/user_guide/runtime/autogen/main.py index 8e60c5ae..1a9e2c54 100644 --- a/docs/docs_src/user_guide/runtime/autogen/main.py +++ b/docs/docs_src/user_guide/runtime/autogen/main.py @@ -67,4 +67,4 @@ def weather_workflow( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/docs/docs_src/user_guide/runtime/autogen/websurfer.py b/docs/docs_src/user_guide/runtime/autogen/websurfer.py index 808cce9f..087dfdcc 100644 --- a/docs/docs_src/user_guide/runtime/autogen/websurfer.py +++ b/docs/docs_src/user_guide/runtime/autogen/websurfer.py @@ -47,4 +47,4 @@ def websurfer_workflow( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/docs/docs_src/user_guide/runtime/autogen/websurfer_tool.py b/docs/docs_src/user_guide/runtime/autogen/websurfer_tool.py index 1f66b63b..ec7046f4 100644 --- a/docs/docs_src/user_guide/runtime/autogen/websurfer_tool.py +++ b/docs/docs_src/user_guide/runtime/autogen/websurfer_tool.py @@ -59,4 +59,4 @@ def websurfer_workflow( return chat_result.summary # type: ignore[no-any-return] -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/docs/docs_src/user_guide/ui/mesop/main_mesop.py b/docs/docs_src/user_guide/ui/mesop/main_mesop.py index 4b21dcea..b76d1abf 100644 --- a/docs/docs_src/user_guide/ui/mesop/main_mesop.py +++ b/docs/docs_src/user_guide/ui/mesop/main_mesop.py @@ -4,7 +4,7 @@ from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.runtime.autogen import AutoGenWorkflows from fastagency.ui.mesop import MesopUI from fastagency.ui.mesop.styles import ( @@ -28,7 +28,7 @@ @wf.register(name="simple_learning", description="Student and teacher learning chat") def simple_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: student_agent = ConversableAgent( name="Student_Agent", @@ -80,4 +80,4 @@ def simple_workflow( ui = MesopUI(security_policy=security_policy, styles=styles) -app = FastAgency(wf=wf, ui=MesopUI(), title="Learning Chat") +app = FastAgency(provider=wf, ui=MesopUI(), title="Learning Chat") diff --git a/examples/cli/main_console.py b/examples/cli/main_console.py index c4a19210..877e86be 100644 --- a/examples/cli/main_console.py +++ b/examples/cli/main_console.py @@ -45,4 +45,4 @@ def simple_workflow( return chat_result.summary -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/examples/cli/main_mesop.py b/examples/cli/main_mesop.py index fed1dd4c..fa26cc6d 100644 --- a/examples/cli/main_mesop.py +++ b/examples/cli/main_mesop.py @@ -2,7 +2,7 @@ from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.runtime.autogen.base import AutoGenWorkflows from fastagency.ui.mesop import MesopUI @@ -22,7 +22,7 @@ @wf.register(name="simple_learning", description="Student and teacher learning chat") def simple_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: student_agent = ConversableAgent( name="Student_Agent", @@ -45,4 +45,4 @@ def simple_workflow( return chat_result.summary -app = FastAgency(wf=wf, ui=MesopUI()) +app = FastAgency(provider=wf, ui=MesopUI()) diff --git a/examples/cli/main_user_proxy.py b/examples/cli/main_user_proxy.py index 66cc1985..e1630d36 100644 --- a/examples/cli/main_user_proxy.py +++ b/examples/cli/main_user_proxy.py @@ -61,4 +61,4 @@ def simple_workflow( return chat_result.summary -app = FastAgency(wf=wf, ui=ConsoleUI()) +app = FastAgency(provider=wf, ui=ConsoleUI()) diff --git a/examples/cli/nats-n-fastapi/1_main_natsprovider.py b/examples/cli/nats-n-fastapi/1_main_natsprovider.py index 973b9a4e..ab7fd34c 100644 --- a/examples/cli/nats-n-fastapi/1_main_natsprovider.py +++ b/examples/cli/nats-n-fastapi/1_main_natsprovider.py @@ -5,9 +5,9 @@ from fastapi import FastAPI from fastagency import UI +from fastagency.adapters.nats import NatsAdapter from fastagency.logging import get_logger from fastagency.runtime.autogen.base import AutoGenWorkflows -from fastagency.ui.nats import NatsProvider llm_config = { "config_list": [ @@ -60,9 +60,15 @@ def simple_workflow( user: str = "faststream" password: str = environ.get("FASTSTREAM_NATS_PASSWORD") # type: ignore[assignment] -provider = NatsProvider(wf=wf, nats_url=nats_url, user=user, password=password) +adapter = NatsAdapter(provider=wf, nats_url=nats_url, user=user, password=password) -app = FastAPI(lifespan=provider.lifespan) +app = FastAPI(lifespan=adapter.lifespan) + + +# this is optional, but we would like to see the list of workflows +@app.get("/") +def list_workflows(): + return {"Workflows": {name: wf.get_description(name) for name in wf.names}} # start the provider with either command diff --git a/examples/cli/nats-n-fastapi/2_main_fastapiprovider.py b/examples/cli/nats-n-fastapi/2_main_fastapiprovider.py index e32f8d8e..71f088e1 100644 --- a/examples/cli/nats-n-fastapi/2_main_fastapiprovider.py +++ b/examples/cli/nats-n-fastapi/2_main_fastapiprovider.py @@ -2,8 +2,8 @@ from fastapi import FastAPI -from fastagency.ui.fastapi import FastAPIProvider -from fastagency.ui.nats import NatsProvider +from fastagency.adapters.fastapi import FastAPIAdapter +from fastagency.adapters.nats import NatsAdapter nats_url = environ.get("NATS_URL", None) # type: ignore[assignment] @@ -13,23 +13,28 @@ nats_user: str = "faststream" nats_password: str = environ.get("FASTSTREAM_NATS_PASSWORD") # type: ignore[assignment] -wf = NatsProvider.Workflows( +provider = NatsAdapter.create_provider( nats_url=environ.get("NATS_URL", None), user=nats_user, password=nats_password ) -provider = FastAPIProvider( - wf=wf, +adapter = FastAPIAdapter( + provider=provider, user=fastapi_user, password=fastapi_password, ) # app = FastAPI(lifespan=provider.lifespan) app = FastAPI() -app.include_router(provider.router) +app.include_router(adapter.router) + + +# this is optional, but we would like to see the list of available workflows +@app.get("/") +def read_root(): + return { + "Workflows": {name: provider.get_description(name) for name in provider.names} + } -# todo (both here and in nats provider) -# - route for initiating a chat - DONE -# - route for listing workflows with their descriptions - DONE # start the provider with the following command # uvicorn 2_main_fastapiprovider:app --host 0.0.0.0 --port 8008 --reload diff --git a/examples/cli/nats-n-fastapi/3_main_mesop.py b/examples/cli/nats-n-fastapi/3_main_mesop.py index c471e7a0..03bd0c4e 100644 --- a/examples/cli/nats-n-fastapi/3_main_mesop.py +++ b/examples/cli/nats-n-fastapi/3_main_mesop.py @@ -1,7 +1,7 @@ from os import environ +from fastagency.adapters.fastapi import FastAPIAdapter from fastagency.app import FastAgency -from fastagency.ui.fastapi import FastAPIProvider from fastagency.ui.mesop import MesopUI nats_url = environ.get("NATS_URL", None) # type: ignore[assignment] @@ -15,7 +15,7 @@ fastapi_user: str = "fastapi" fastapi_password: str = environ.get("FASTAPI_PASSWORD") # type: ignore[assignment] -wf = FastAPIProvider.Workflows( +provider = FastAPIAdapter.create_provider( fastapi_url=fastapi_url, fastapi_user=fastapi_user, fastapi_password=fastapi_password, @@ -26,7 +26,7 @@ ui = MesopUI() -app = FastAgency(wf=wf, ui=ui) +app = FastAgency(provider=provider, ui=ui) # write their own routes here ... diff --git a/examples/cli/nats/main_mesop.py b/examples/cli/nats/main_mesop.py deleted file mode 100644 index bbb3d721..00000000 --- a/examples/cli/nats/main_mesop.py +++ /dev/null @@ -1,21 +0,0 @@ -from os import environ - -from fastagency.app import FastAgency -from fastagency.ui.mesop import MesopUI -from fastagency.ui.nats import NatsProvider - -nats_url = environ.get("NATS_URL", None) # type: ignore[assignment] - -user: str = "faststream" -password: str = environ.get("FASTSTREAM_NATS_PASSWORD") # type: ignore[assignment] - -wf = NatsProvider.Workflows( - nats_url=environ.get("NATS_URL", None), user="faststream", password=password -) - -ui = MesopUI() - -app = FastAgency(wf=wf, ui=ui) - -# start the provider with the following command -# gunicorn main_mesop:app --reload diff --git a/examples/cli/nats/main_natsprovider.py b/examples/cli/nats/main_natsprovider.py deleted file mode 100644 index fa313617..00000000 --- a/examples/cli/nats/main_natsprovider.py +++ /dev/null @@ -1,77 +0,0 @@ -import os -from os import environ - -from autogen.agentchat import ConversableAgent -from fastapi import FastAPI - -from fastagency import UI -from fastagency.logging import get_logger -from fastagency.runtime.autogen.base import AutoGenWorkflows -from fastagency.ui.nats import NatsProvider - -llm_config = { - "config_list": [ - { - "model": "gpt-4o-mini", - "api_key": os.getenv("OPENAI_API_KEY"), - } - ], - "temperature": 0.0, -} - -logger = get_logger(__name__) - -wf = AutoGenWorkflows() - - -@wf.register(name="simple_learning", description="Student and teacher learning chat") -def simple_workflow( - wf: AutoGenWorkflows, ui: UI, initial_message: str, session_id: str -) -> str: - student_agent = ConversableAgent( - name="Student_Agent", - system_message="You are a student willing to learn.", - llm_config=llm_config, - # human_input_mode="ALWAYS", - ) - teacher_agent = ConversableAgent( - name="Teacher_Agent", - system_message="You are a math teacher.", - llm_config=llm_config, - # human_input_mode="ALWAYS", - ) - - logger.info("Above initiate_chat in simple_workflow") - logger.info(llm_config) - chat_result = student_agent.initiate_chat( - teacher_agent, - message=initial_message, - summary_method="reflection_with_llm", - max_turns=5, - ) - logger.info("Below initiate_chat in simple_workflow") - logger.info(chat_result) - - return chat_result.summary - - -nats_url = environ.get("NATS_URL", None) # type: ignore[assignment] - -user: str = "faststream" -password: str = environ.get("FASTSTREAM_NATS_PASSWORD") # type: ignore[assignment] - -provider = NatsProvider(wf=wf, nats_url=nats_url, user=user, password=password) - -app = FastAPI(lifespan=provider.lifespan) - - -# todo: we need a way to list of workflows (names and descrioptions) -@app.get("/discover") -def start_workflow(): - # todo: you need to produce a message on NATS to actually start it - - return {"msg": "Workflow started."} - - -# start the provider with either command -# uvicorn main_natsprovider:app --reload diff --git a/examples/cli/nats/nats_client_faststream.py b/examples/cli/nats/nats_client_faststream.py deleted file mode 100644 index 55644648..00000000 --- a/examples/cli/nats/nats_client_faststream.py +++ /dev/null @@ -1,71 +0,0 @@ -import asyncio -import uuid -from os import environ - -from faststream import FastStream, Logger -from faststream.nats import NatsBroker -from nats.js import api - -from fastagency.base import AskingMessage, IOMessage -from fastagency.logging import get_logger -from fastagency.ui.nats import JETSTREAM, InitiateModel, InputResponseModel - -logger = get_logger(__name__) - -title = "Nats FastStream Client" - -nats_url = environ.get("NATS_URL", None) # type: ignore[assignment] -user: str = "faststream" -password: str = environ.get("FASTSTREAM_NATS_PASSWORD") # type: ignore[assignment] -broker = NatsBroker(nats_url, user=user, password=password) - -app = FastStream(broker=broker, title=title) - -user_id = str(uuid.uuid4()) -thread_id = str(uuid.uuid4()) - -i = 0 - - -@broker.subscriber( - f"chat.client.messages.{user_id}.{thread_id}", - stream=JETSTREAM, - deliver_policy=api.DeliverPolicy("all"), -) -async def consume_msg_from_autogen(msg: dict, logger: Logger) -> None: - global i - logger.info( - f"Received message from topic chat.client.messages.{user_id}.{thread_id}: {msg}" - ) - iomessage = IOMessage.create(**msg) - if isinstance(iomessage, AskingMessage) and i == 0: - response = InputResponseModel( - msg="Start a new conversation", question_id=iomessage.uuid - ) - await broker.publish(response, f"chat.server.messages.{user_id}.{thread_id}") - logger.info( - f"Sent response to topic chat.server.messages.{user_id}.{thread_id}: {response.model_dump_json()}" - ) - i = i + 1 - elif i != 0 and isinstance(iomessage, AskingMessage): - logger.info("i is not 0") - # response = InputResponseModel( - # msg="", question_id=iomessage.uuid - # ) - # await broker.publish(response, f"chat.server.messages.{user_id}.{thread_id}") - - -@app.after_startup -async def send_initiate_chat_msg() -> None: - async def _send_initiate_chat_msg(): - init_message = InitiateModel( - user_id=user_id, - conversation_id=thread_id, - msg="Hello, How are you chatbot?", - ) - await broker.publish(init_message, "chat.server.initiate_chat") - logger.info( - f"Message sent to topic chat.server.initiate_chat: {init_message.model_dump_json()}" - ) - - asyncio.create_task(_send_initiate_chat_msg()) # noqa: RUF006 diff --git a/fastagency/__init__.py b/fastagency/__init__.py index e9118bda..50ea13a4 100644 --- a/fastagency/__init__.py +++ b/fastagency/__init__.py @@ -12,7 +12,7 @@ TextInput, TextMessage, Workflow, - Workflows, + WorkflowsProtocol, ) __all__ = [ @@ -25,7 +25,7 @@ "SuggestedFunctionCall", "TextInput", "TextMessage", - "Workflows", + "WorkflowsProtocol", "Workflow", "__version__", ] diff --git a/fastagency/new/__init__.py b/fastagency/adapters/__init__.py similarity index 100% rename from fastagency/new/__init__.py rename to fastagency/adapters/__init__.py diff --git a/fastagency/adapters/fastapi/__init__.py b/fastagency/adapters/fastapi/__init__.py new file mode 100644 index 00000000..81497f15 --- /dev/null +++ b/fastagency/adapters/fastapi/__init__.py @@ -0,0 +1,3 @@ +from .base import FastAPIAdapter, FastAPIProvider + +__all__ = ["FastAPIAdapter", "FastAPIProvider"] diff --git a/fastagency/ui/fastapi/base.py b/fastagency/adapters/fastapi/base.py similarity index 94% rename from fastagency/ui/fastapi/base.py rename to fastagency/adapters/fastapi/base.py index 9cf203b9..5a3e3cae 100644 --- a/fastagency/ui/fastapi/base.py +++ b/fastagency/adapters/fastapi/base.py @@ -22,31 +22,31 @@ IOMessage, IOMessageVisitor, Workflow, - Workflows, + WorkflowsProtocol, ) -from ..nats import InitiateModel, InputResponseModel, NatsWorkflows +from ..nats import InitiateModel, InputResponseModel, NatsProvider logger = get_logger(__name__) -class FastAPIProvider(IOMessageVisitor): +class FastAPIAdapter(IOMessageVisitor): def __init__( self, - wf: NatsWorkflows, + provider: NatsProvider, *, user: Optional[str] = None, password: Optional[str] = None, - super_conversation: Optional["FastAPIProvider"] = None, + super_conversation: Optional["FastAPIAdapter"] = None, ) -> None: """Provider for NATS. Args: - wf (Workflows): The workflow object. + provider (NatsProvider): The provider. user (Optional[str], optional): The user. Defaults to None. password (Optional[str], optional): The password. Defaults to None. super_conversation (Optional["FastAPIProvider"], optional): The super conversation. Defaults to None. """ - self.wf = wf + self.wf = provider self.user = user self.password = password @@ -111,11 +111,11 @@ def process_message(self, message: IOMessage) -> Optional[str]: logger.error(f"Error in process_message: {e}", stack_info=True) raise - def create_subconversation(self) -> "FastAPIProvider": + def create_subconversation(self) -> "FastAPIAdapter": return self @classmethod - def Workflows( # noqa: N802 + def create_provider( cls, fastapi_url: str, fastapi_user: Optional[str] = None, @@ -123,8 +123,8 @@ def Workflows( # noqa: N802 nats_url: Optional[str] = None, nats_user: Optional[str] = None, nats_password: Optional[str] = None, - ) -> Workflows: - return FastAPIWorkflows( + ) -> WorkflowsProtocol: + return FastAPIProvider( fastapi_url=fastapi_url, fastapi_user=fastapi_user, fastapi_password=fastapi_password, @@ -134,7 +134,7 @@ def Workflows( # noqa: N802 ) -class FastAPIWorkflows(Workflows): +class FastAPIProvider(WorkflowsProtocol): def __init__( self, fastapi_url: str, @@ -146,7 +146,7 @@ def __init__( ) -> None: """Initialize the fastapi workflows.""" self._workflows: dict[ - str, tuple[Callable[[Workflows, UI, str, str], str], str] + str, tuple[Callable[[WorkflowsProtocol, UI, str, str], str], str] ] = {} self.fastapi_url = ( diff --git a/fastagency/ui/nats/__init__.py b/fastagency/adapters/nats/__init__.py similarity index 83% rename from fastagency/ui/nats/__init__.py rename to fastagency/adapters/nats/__init__.py index 2cbf4e64..87bbada0 100644 --- a/fastagency/ui/nats/__init__.py +++ b/fastagency/adapters/nats/__init__.py @@ -2,14 +2,14 @@ JETSTREAM, InitiateModel, InputResponseModel, + NatsAdapter, NatsProvider, - NatsWorkflows, ) __all__ = [ - "NatsProvider", + "NatsAdapter", "InitiateModel", "InputResponseModel", "JETSTREAM", - "NatsWorkflows", + "NatsProvider", ] diff --git a/fastagency/ui/nats/base.py b/fastagency/adapters/nats/base.py similarity index 84% rename from fastagency/ui/nats/base.py rename to fastagency/adapters/nats/base.py index 63549b3e..c9afa99b 100644 --- a/fastagency/ui/nats/base.py +++ b/fastagency/adapters/nats/base.py @@ -3,10 +3,10 @@ import asyncio import os import traceback -from collections.abc import AsyncIterator, Iterable, Mapping +from collections.abc import AsyncIterator from contextlib import asynccontextmanager from queue import Queue -from typing import TYPE_CHECKING, Any, Callable, Optional, Union +from typing import TYPE_CHECKING, Any, Optional from uuid import UUID, uuid4 from asyncer import asyncify, syncify @@ -15,21 +15,18 @@ from nats.js import api from pydantic import BaseModel -from fastagency.logging import get_logger - from ...base import ( UI, - Agent, AskingMessage, IOMessage, IOMessageVisitor, MultipleChoice, + ProviderProtocol, TextInput, TextMessage, - Workflow, - Workflows, run_workflow, ) +from ...logging import get_logger if TYPE_CHECKING: from faststream.nats.subscriber.asyncapi import AsyncAPISubscriber @@ -64,26 +61,26 @@ class InitiateModel(BaseModel): ) -class NatsProvider(IOMessageVisitor): +class NatsAdapter(IOMessageVisitor): def __init__( self, - wf: Workflows, + provider: ProviderProtocol, *, nats_url: Optional[str] = None, user: Optional[str] = None, password: Optional[str] = None, - super_conversation: Optional["NatsProvider"] = None, + super_conversation: Optional["NatsAdapter"] = None, ) -> None: """Provider for NATS. Args: - wf (Workflows): The workflow object. + provider (ProviderProtocol): The provider. nats_url (Optional[str], optional): The NATS URL. Defaults to None in which case 'nats://localhost:4222' is used. user (Optional[str], optional): The user. Defaults to None. password (Optional[str], optional): The password. Defaults to None. super_conversation (Optional["NatsProvider"], optional): The super conversation. Defaults to None. """ - self.wf = wf + self.provider = provider self.nats_url = nats_url or "nats://localhost:4222" self.user = user self.password = password @@ -95,12 +92,12 @@ def __init__( self._input_request_subject: str self._input_receive_subject: str - self.super_conversation: Optional[NatsProvider] = super_conversation - self.sub_conversations: list[NatsProvider] = [] + self.super_conversation: Optional[NatsAdapter] = super_conversation + self.sub_conversations: list[NatsAdapter] = [] - self.create_initiate_subscriber() + self._create_initiate_subscriber() - async def handle_input( + async def _handle_input( self, body: InputResponseModel, msg: NatsMessage, logger: Logger ) -> None: """Handle input from the client by consuming messages from chat.server.messages.*.*. @@ -116,7 +113,7 @@ async def handle_input( await msg.ack() self.queue.put(msg) - async def send_error_msg(self, e: Exception, logger: Logger) -> None: + async def _send_error_msg(self, e: Exception, logger: Logger) -> None: """Send an error message. Args: @@ -129,7 +126,7 @@ async def send_error_msg(self, e: Exception, logger: Logger) -> None: error_msg = InputResponseModel(msg=str(e), error=True, question_id=None) await self.broker.publish(error_msg, self._input_request_subject) - def create_initiate_subscriber(self) -> None: + def _create_initiate_subscriber(self) -> None: @self.broker.subscriber( "chat.server.initiate_chat", stream=JETSTREAM, @@ -167,7 +164,7 @@ async def initiate_handler( stream=JETSTREAM, deliver_policy=api.DeliverPolicy("all"), ) - subscriber(self.handle_input) + subscriber(self._handle_input) self.broker.setup_subscriber(subscriber) await subscriber.start() @@ -176,15 +173,15 @@ async def initiate_handler( async def start_chat() -> None: # type: ignore [return] try: await asyncify(run_workflow)( - wf=self.wf, + provider=self.provider, ui=self, # type: ignore[arg-type] - name=self.wf.names[0], + name=self.provider.names[0], initial_message=body.msg, single_run=True, ) except Exception as e: - await self.send_error_msg(e, logger) + await self._send_error_msg(e, logger) background_tasks = set() task = asyncio.create_task(start_chat()) # type: ignore @@ -201,7 +198,7 @@ def callback(t: asyncio.Task[Any]) -> None: task.add_done_callback(callback) except Exception as e: - await self.send_error_msg(e, logger) + await self._send_error_msg(e, logger) # todo: make it a router @asynccontextmanager @@ -223,7 +220,7 @@ def visit_text_message(self, message: TextMessage) -> None: logger.debug(f"visit_text_message(): {content=}") syncify(self.broker.publish)(content, self._input_request_subject) - async def wait_for_question_response( + async def _wait_for_question_response_with_timeout( self, question_id: str, *, timeout: int = 180 ) -> InputResponseModel: """Wait for the question response. @@ -280,9 +277,9 @@ def visit_text_input(self, message: TextInput) -> str: logger.info(f"visit_text_input(): {content=}") syncify(self.broker.publish)(content, self._input_request_subject) - input_response: InputResponseModel = syncify(self.wait_for_question_response)( - question_id=question_id - ) + input_response: InputResponseModel = syncify( + self._wait_for_question_response_with_timeout + )(question_id=question_id) logger.info(input_response) return input_response.msg @@ -292,9 +289,9 @@ def visit_multiple_choice(self, message: MultipleChoice) -> str: logger.info(f"visit_multiple_choice(): {content=}") syncify(self.broker.publish)(content, self._input_request_subject) - input_response: InputResponseModel = syncify(self.wait_for_question_response)( - question_id=question_id - ) + input_response: InputResponseModel = syncify( + self._wait_for_question_response_with_timeout + )(question_id=question_id) logger.info(input_response) return input_response.msg @@ -303,32 +300,41 @@ def process_message(self, message: IOMessage) -> Optional[str]: return self.visit(message) except Exception as e: logger.error(f"Error in process_message: {e}", stack_info=True) - raise + # do not reraise, we must go on + if isinstance(message, AskingMessage): + return "Error: Something went wrong. Please check logs for details." + return None - def create_subconversation(self) -> "NatsProvider": + def create_subconversation(self) -> "NatsAdapter": return self @classmethod - def Workflows( # noqa: N802 + def create_provider( cls, nats_url: Optional[str] = None, user: Optional[str] = None, password: Optional[str] = None, - ) -> Workflows: - return NatsWorkflows(nats_url=nats_url, user=user, password=password) + ) -> ProviderProtocol: + return NatsProvider(nats_url=nats_url, user=user, password=password) -class NatsWorkflows(Workflows): +class NatsProvider: def __init__( self, nats_url: Optional[str] = None, user: Optional[str] = None, password: Optional[str] = None, ) -> None: - """Initialize the nats workflows.""" - self._workflows: dict[ - str, tuple[Callable[[Workflows, UI, str, str], str], str] - ] = {} + """Initialize the nats workflows. + + Args: + nats_url (Optional[str], optional): The NATS URL. Defaults to None. + user (Optional[str], optional): The user. Defaults to None. + password (Optional[str], optional): The password. Defaults to None. + """ + # self._workflows: dict[ + # str, tuple[Callable[[WorkflowsProtocol, UI, str, str], str], str] + # ] = {} self.nats_url = nats_url or "nats://localhost:4222" self.user = user @@ -341,12 +347,7 @@ def __init__( self.is_broker_running: bool = False - def register( - self, name: str, description: str, *, fail_on_redefintion: bool = False - ) -> Callable[[Workflow], Workflow]: - raise NotImplementedError("Just ignore this for now; @register") - - async def setup_subscriber( + async def _setup_subscriber( self, ui: UI, from_server_subject: str, to_server_subject: str ) -> None: logger.info( @@ -409,7 +410,7 @@ async def lifespan() -> AsyncIterator[None]: async def _setup_and_run() -> None: await send_initiate_chat_msg() - await self.setup_subscriber(ui, _from_server_subject, _to_server_subject) + await self._setup_subscriber(ui, _from_server_subject, _to_server_subject) while True: # noqa: ASYNC110 await asyncio.sleep(0.1) @@ -437,16 +438,3 @@ def names(self) -> list[str]: def get_description(self, name: str) -> str: return "Student and teacher learning chat" - - def register_api( - self, - api: Any, - callers: Union[Agent, Iterable[Agent]], - executors: Union[Agent, Iterable[Agent]], - functions: Optional[ - Union[str, Iterable[Union[str, Mapping[str, Mapping[str, str]]]]] - ] = None, - ) -> None: - raise NotImplementedError( - "Just ignore this for now, will be removed from this protocol; @register_api" - ) diff --git a/fastagency/app.py b/fastagency/app.py index 5719c26e..47f07602 100644 --- a/fastagency/app.py +++ b/fastagency/app.py @@ -4,7 +4,13 @@ from contextlib import contextmanager from typing import Any, Callable, Optional, Union -from .base import ASGI, UI, WSGI, Workflows +from .base import ( + UI, + ASGIProtocol, + ProviderProtocol, + Runnable, + WSGIProtocol, +) from .exceptions import ( FastAgencyASGINotImplementedError, FastAgencyWSGINotImplementedError, @@ -17,7 +23,7 @@ class FastAgency: # Runnable def __init__( self, - wf: Workflows, + provider: ProviderProtocol, ui: UI, *, title: Optional[str] = None, @@ -26,25 +32,28 @@ def __init__( """Initialize the FastAgency object. Args: - wf (Workflows): The workflows object to use + provider (ProviderProtocol): The provider object to use ui (UI): The UI object to use title (Optional[str], optional): The title of the FastAgency. If None, the default string will be used. Defaults to None. description (Optional[str], optional): The description of the FastAgency. If None, the default string will be used. Defaults to None. """ + _self: Runnable = self self._title = title or "FastAgency application" default_description = "FastAgency application" - if len(wf.names) == 0: - logger.warning(f"No workflows found in {wf}") + if len(provider.names) == 0: + logger.warning(f"No workflows found in {provider}") default_description += " - No workflows found" else: default_description += " - Workflows:" - for name in wf.names: - default_description += f" - {name}: {wf.get_description(name)}" + for name in provider.names: + default_description += f" - {name}: {provider.get_description(name)}" self._description = description or default_description - logger.info(f"Initializing FastAgency {self} with workflows: {wf} and UI: {ui}") - self._wf = wf + logger.info( + f"Initializing FastAgency {self} with workflows: {provider} and UI: {ui}" + ) + self._provider = provider self._ui = ui logger.info(f"Initialized FastAgency: {self}") @@ -63,9 +72,9 @@ def __str__(self) -> str: return f"" @property - def wf(self) -> Workflows: - """Return the workflows object.""" - return self._wf + def provider(self) -> ProviderProtocol: + """Return the provider object.""" + return self._provider @property def ui(self) -> UI: @@ -115,7 +124,7 @@ def __call__(self, *args: Any) -> Union[Awaitable[None], list[bytes]]: def handle_wsgi( self, environ: dict[str, Any], start_response: Callable[..., Any] ) -> list[bytes]: - if isinstance(self.ui, WSGI): + if isinstance(self.ui, WSGIProtocol): return self.ui.handle_wsgi(self, environ, start_response) else: raise FastAgencyWSGINotImplementedError( @@ -128,7 +137,7 @@ async def handle_asgi( receive: Callable[[dict[str, Any]], Awaitable[None]], send: Callable[[dict[str, Any]], Awaitable[None]], ) -> None: - if isinstance(self.ui, ASGI): + if isinstance(self.ui, ASGIProtocol): return await self.ui.handle_asgi(self, scope, receive, send) else: raise FastAgencyASGINotImplementedError( diff --git a/fastagency/base.py b/fastagency/base.py index 359e4c6b..3e52a5ba 100644 --- a/fastagency/base.py +++ b/fastagency/base.py @@ -34,7 +34,7 @@ "TextMessage", "Workflow", "WorkflowCompleted", - "Workflows", + "WorkflowsProtocol", "run_workflow", ] @@ -239,7 +239,7 @@ def create_subconversation(self) -> "UI": ... @runtime_checkable -class WSGI(Protocol): +class WSGIProtocol(Protocol): def handle_wsgi( self, app: "Runnable", @@ -249,7 +249,7 @@ def handle_wsgi( @runtime_checkable -class ASGI(Protocol): +class ASGIProtocol(Protocol): async def handle_asgi( self, app: "Runnable", @@ -259,18 +259,14 @@ async def handle_asgi( ) -> None: ... -Workflow = TypeVar("Workflow", bound=Callable[["Workflows", UI, str, str], str]) +Workflow = TypeVar("Workflow", bound=Callable[["WorkflowsProtocol", UI, str, str], str]) Agent = TypeVar("Agent") @runtime_checkable -class Workflows(Protocol): - def register( - self, name: str, description: str - ) -> Callable[[Workflow], Workflow]: ... - +class ProviderProtocol(Protocol): def run(self, name: str, session_id: str, ui: UI, initial_message: str) -> str: ... @property @@ -278,6 +274,13 @@ def names(self) -> list[str]: ... def get_description(self, name: str) -> str: ... + +@runtime_checkable +class WorkflowsProtocol(ProviderProtocol, Protocol): + def register( + self, name: str, description: str + ) -> Callable[[Workflow], Workflow]: ... + def register_api( self, api: "OpenAPI", @@ -289,6 +292,12 @@ def register_api( ) -> None: ... +@runtime_checkable +class AdapterProtocol(Protocol): + @classmethod + def create_provider(*args: Any, **kwargs: Any) -> ProviderProtocol: ... + + @runtime_checkable class Runnable(Protocol): @contextmanager @@ -304,7 +313,7 @@ def start( ) -> None: ... @property - def wf(self) -> Workflows: ... + def provider(self) -> ProviderProtocol: ... @property def ui(self) -> UI: ... @@ -318,7 +327,7 @@ def description(self) -> str: ... def run_workflow( *, - wf: Workflows, + provider: ProviderProtocol, ui: UI, name: Optional[str], initial_message: Optional[str] = None, @@ -327,15 +336,15 @@ def run_workflow( """Run a workflow. Args: - wf (Workflows): The workflows object to use. + provider (ProviderProtocol): The provider to use. ui (UI): The UI object to use. name (Optional[str]): The name of the workflow to run. If not provided, the default workflow will be run. initial_message (Optional[str], optional): The initial message to send to the workflow. If not provided, a default message will be sent. Defaults to None. single_run (bool, optional): If True, the workflow will only be run once. Defaults to False. """ while True: - name = wf.names[0] if name is None else name - description = wf.get_description(name) + name = provider.names[0] if name is None else name + description = provider.get_description(name) if initial_message is None: initial_message = ui.process_message( @@ -367,7 +376,7 @@ def run_workflow( ) ) - result = wf.run( + result = provider.run( name=name, session_id="session_id", ui=ui.create_subconversation(), diff --git a/fastagency/new/base.py b/fastagency/new/base.py deleted file mode 100644 index 9230c76e..00000000 --- a/fastagency/new/base.py +++ /dev/null @@ -1,211 +0,0 @@ -from collections.abc import AsyncGenerator, AsyncIterator, Awaitable -from contextlib import asynccontextmanager -from dataclasses import dataclass -from typing import Any, Callable, Optional, Protocol -from uuid import UUID - -from pydantic import UUID4 - -from fastagency.base import IOMessage - - -class Conversation: - def __init__( - self, - *, - provider: "ProviderProtocol", - id: Optional[UUID] = None, - name: Optional[str] = None, - parent: Optional["Conversation"] = None, - ) -> None: - """Initialize the conversation with the provider. - - Args: - provider: The provider that is handling the conversation. - id: The ID of the conversation. If not provided (default), a new UUID4 will be generated. - name: The name of the conversation. - parent: The parent conversation - """ - self._provider = provider - self._id = id if id else UUID4() - self._name = name - self._parent = parent - self._subconversations: list["Conversation"] = [] - - @property - def name(self) -> "ProviderProtocol": - return self._provider - - @name.setter - def name(self, name: Optional[str]) -> None: - self._name = name - - @property - def parent(self) -> Optional["Conversation"]: - return self._parent - - @property - def id(self) -> UUID: - return self._id - - @property - def subconversations(self) -> list["Conversation"]: - return self._subconversations - - @property - def all_subconversations(self) -> list["Conversation"]: - # recursive function to get all subconversations - all_subs = [s.all_subconversations for s in self._subconversations] - - # flatten the list - all_subs_flat = [item for sublist in all_subs for item in sublist] - - return self._subconversations + all_subs_flat - - async def create_subconversation( - self, - *, - id: Optional[UUID] = None, - name: Optional[str] = None, - ) -> "Conversation": - """Create a new subconversation. - - Args: - id: The ID of the conversation. If not provided (default), a new UUID4 will be generated. - name: The name of the conversation. - """ - subconversation = Conversation( - provider=self._provider, id=id, name=name, parent=self - ) - await self._provider.create_subconversation(subconversation) - self._subconversations.append(subconversation) - - return subconversation - - async def get_message(self, response: Optional[str]) -> IOMessage: - return await self._provider.get_message(self, response) - - -class ClientProtocol(Protocol): - async def start( - self, lifespan: Callable[[], Awaitable[Any]] - ) -> AsyncGenerator[None]: ... - - async def process_message(self, message: IOMessage) -> Optional[str]: ... - - -class FastAPIConversationClient: # Client - def __init__( - self, - provider: "ProviderProtocol", - *args: Any, - port: Optional[int] = None, - **kwargs: Any, - ) -> None: - """Initialize the conversation with the provider.""" - self._provider = provider - self._port = port - self._args = args - self._kwargs = kwargs - - @classmethod - async def create(cls, provider: "ProviderProtocol") -> ClientProtocol: - raise NotImplementedError - - @asynccontextmanager - async def start( - self, lifespan: Callable[[], Awaitable[Any]] - ) -> AsyncIterator[None]: - raise NotImplementedError - yield - - async def process_message(self, message: IOMessage) -> Optional[str]: - raise NotImplementedError - - class Provider: - """Provider for the FastAPIConversationClient.""" - - def __init__(self: "ProviderProtocol", url: str) -> None: - """Initialize the provider with the URL. - - Args: - url: The URL of the provider. - - """ - self._url = url - - @asynccontextmanager - async def start( - self, lifespan: Callable[[], Awaitable[Any]] - ) -> AsyncIterator[None]: - raise NotImplementedError - yield - - async def get_workflows(self) -> "list[WorkflowInfo]": - raise NotImplementedError - - async def start_conversation( - self, workflow_name: Optional[str], message: Optional[str] - ) -> Conversation: - raise NotImplementedError - - async def create_subconversation( - self, superconversation: Conversation - ) -> Conversation: - raise NotImplementedError - - async def get_conversation(self, conversation_id: UUID) -> Conversation: - raise NotImplementedError - - async def get_message( - self, conversation: Conversation, response: Optional[str] - ) -> IOMessage: - raise NotImplementedError - - -@dataclass -class WorkflowInfo: - name: str - description: str - - -class ProviderProtocol(Protocol): - async def start( - self, lifespan: Callable[[], Awaitable[Any]] - ) -> AsyncGenerator[None]: ... - - async def get_workflows(self) -> list[WorkflowInfo]: ... - - async def start_conversation( - self, workflow_name: Optional[str], message: Optional[str] - ) -> Conversation: ... - - async def create_subconversation( - self, superconversation: Conversation - ) -> Conversation: ... - - async def get_conversation(self, conversation_id: UUID) -> Conversation: ... - - async def get_message( - self, conversation: Conversation, response: Optional[str] - ) -> IOMessage: ... - - -class NatsProvider: # implements WorkflowProviderProtocol - @asynccontextmanager - async def start( - self, lifespan: Callable[[], Awaitable[Any]] - ) -> AsyncIterator[None]: - raise NotImplementedError - yield - - async def get_workflows(self) -> list[WorkflowInfo]: - raise NotImplementedError - - async def start_conversation( - self, workflow_name: Optional[str], message: Optional[str] - ) -> Conversation: - raise NotImplementedError - - async def get_conversation(self, conversation_id: UUID) -> Conversation: - raise NotImplementedError diff --git a/fastagency/runtime/autogen/base.py b/fastagency/runtime/autogen/base.py index bf4ab8cb..b7ea9af0 100644 --- a/fastagency/runtime/autogen/base.py +++ b/fastagency/runtime/autogen/base.py @@ -23,7 +23,7 @@ MultipleChoice, TextInput, Workflow, - Workflows, + WorkflowsProtocol, ) from ...logging import get_logger @@ -268,11 +268,11 @@ def input(self, prompt: str = "", *, password: bool = False) -> str: return retval -class AutoGenWorkflows(Workflows): +class AutoGenWorkflows(WorkflowsProtocol): def __init__(self) -> None: """Initialize the workflows.""" self._workflows: dict[ - str, tuple[Callable[[Workflows, UI, str, str], str], str] + str, tuple[Callable[[WorkflowsProtocol, UI, str, str], str], str] ] = {} def register( diff --git a/fastagency/ui/console/base.py b/fastagency/ui/console/base.py index c5f93dc0..a4b39d45 100644 --- a/fastagency/ui/console/base.py +++ b/fastagency/ui/console/base.py @@ -56,7 +56,7 @@ def start( single_run: bool = False, ) -> None: run_workflow( - wf=app.wf, + provider=app.provider, ui=self, name=name, initial_message=initial_message, diff --git a/fastagency/ui/fastapi/__init__.py b/fastagency/ui/fastapi/__init__.py deleted file mode 100644 index c1247ea8..00000000 --- a/fastagency/ui/fastapi/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .base import FastAPIProvider, FastAPIWorkflows - -__all__ = ["FastAPIProvider", "FastAPIWorkflows"] diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index fc36ac48..cc236cc7 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -17,11 +17,11 @@ IOMessage, IOMessageVisitor, MultipleChoice, + ProviderProtocol, Runnable, TextInput, TextMessage, WorkflowCompleted, - Workflows, ) from ...logging import get_logger from .styles import MesopHomePageStyles @@ -253,7 +253,9 @@ def handle_wsgi( return MesopUI._me(environ, start_response) # type: ignore[no-any-return] -def run_workflow(wf: Workflows, name: str, initial_message: str) -> MesopUI: +def run_workflow( + provider: ProviderProtocol, name: str, initial_message: str +) -> MesopUI: def conversation_worker(ui: MesopUI, subconversation: MesopUI) -> None: ui.process_message( IOMessage.create( @@ -268,7 +270,7 @@ def conversation_worker(ui: MesopUI, subconversation: MesopUI) -> None: ) try: - result = wf.run( + result = provider.run( name=name, session_id="session_id", ui=subconversation, # type: ignore[arg-type] diff --git a/fastagency/ui/mesop/main.py b/fastagency/ui/mesop/main.py index 342f4912..11e4bf99 100644 --- a/fastagency/ui/mesop/main.py +++ b/fastagency/ui/mesop/main.py @@ -168,9 +168,9 @@ def conversation_starter_box(self) -> None: def send_prompt(self, prompt: str) -> Iterator[None]: ui = self._ui - wf = ui.app.wf + provider = ui.app.provider - name = wf.names[0] + name = provider.names[0] state = me.state(State) # me.navigate("/conversation") @@ -180,7 +180,7 @@ def send_prompt(self, prompt: str) -> Iterator[None]: state.conversation = conversation state.in_conversation = True yield - responses = send_prompt_to_autogen(prompt=prompt, wf=wf, name=name) + responses = send_prompt_to_autogen(prompt=prompt, provider=provider, name=name) yield from consume_responses(responses) def conversation_box(self) -> None: diff --git a/fastagency/ui/mesop/send_prompt.py b/fastagency/ui/mesop/send_prompt.py index be22f02e..121a6561 100644 --- a/fastagency/ui/mesop/send_prompt.py +++ b/fastagency/ui/mesop/send_prompt.py @@ -2,15 +2,15 @@ import mesop as me -from ...base import Workflows +from ...base import ProviderProtocol from .base import MesopMessage, MesopUI, run_workflow from .data_model import State def send_prompt_to_autogen( - prompt: str, wf: Workflows, name: str + prompt: str, provider: ProviderProtocol, name: str ) -> Iterable[MesopMessage]: - mesop_io = run_workflow(wf, name=name, initial_message=prompt) + mesop_io = run_workflow(provider, name=name, initial_message=prompt) state = me.state(State) state.conversation.fastagency = mesop_io.id return mesop_io.get_message_stream() diff --git a/tests/cli/test_discover.py b/tests/cli/test_discover.py index 2bd5c743..8fe9118e 100644 --- a/tests/cli/test_discover.py +++ b/tests/cli/test_discover.py @@ -33,12 +33,12 @@ def _import_fixture( from unittest.mock import MagicMock from fastagency.ui.console import ConsoleUI from fastagency.runtime.autogen.base import AutoGenWorkflows -{'frim fastagency import FastAgency' if syntax_error else 'from fastagency import FastAgency'} +{'frim' if syntax_error else 'from'} fastagency import FastAgency wf = AutoGenWorkflows() -app = {'FastAgency(wf=wf, ui=ConsoleUI())' if not mock_app else 'MagicMock()'} +app = {'FastAgency(provider=wf, ui=ConsoleUI())' if not mock_app else 'MagicMock()'} """ diff --git a/tests/cli/test_mesop.py b/tests/cli/test_mesop.py index 08b8720d..f83faf54 100644 --- a/tests/cli/test_mesop.py +++ b/tests/cli/test_mesop.py @@ -13,7 +13,7 @@ from autogen.agentchat import ConversableAgent -from fastagency import UI, FastAgency, Workflows +from fastagency import UI, FastAgency, WorkflowsProtocol from fastagency.runtime.autogen.base import AutoGenWorkflows from fastagency.ui.mesop import MesopUI @@ -31,7 +31,7 @@ @wf.register(name="simple_learning", description="Student and teacher learning chat") def simple_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: student_agent = ConversableAgent( name="Student_Agent", @@ -53,7 +53,7 @@ def simple_workflow( return chat_result.summary -app = FastAgency(wf=wf, ui=MesopUI()) +app = FastAgency(provider=wf, ui=MesopUI()) """ diff --git a/tests/test_autogen.py b/tests/runtime/autogen/test_autogen.py similarity index 97% rename from tests/test_autogen.py rename to tests/runtime/autogen/test_autogen.py index 72ceb63a..837687b9 100644 --- a/tests/test_autogen.py +++ b/tests/runtime/autogen/test_autogen.py @@ -7,7 +7,7 @@ from fastagency import UI, IOMessage from fastagency.api.openapi import OpenAPI -from fastagency.base import Workflows +from fastagency.base import WorkflowsProtocol from fastagency.runtime.autogen import AutoGenWorkflows from fastagency.runtime.autogen.base import _findall, _match from fastagency.ui.console import ConsoleUI @@ -142,7 +142,7 @@ def test_simple(openai_gpt4o_mini_llm_config: dict[str, Any]) -> None: name="simple_learning", description="Student and teacher learning chat" ) def simple_workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: student_agent = ConversableAgent( name="Student_Agent", @@ -244,7 +244,7 @@ def wf(self, openai_gpt4o_mini_llm_config: dict[str, Any]) -> AutoGenWorkflows: description="Test of user proxy with human input mode set to always", ) def workflow( - wf: Workflows, ui: UI, initial_message: str, session_id: str + wf: WorkflowsProtocol, ui: UI, initial_message: str, session_id: str ) -> str: user_proxy = UserProxyAgent( name="User_Proxy", diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 00000000..bb87db99 --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,67 @@ +import importlib +import pkgutil +import sys # Import the pkgutil module to work with the import system + +import pytest + +from fastagency.exceptions import ( + FastAgencyCLIPythonVersionError, # Import the importlib module to dynamically import modules +) + + +def list_submodules(module_name: str) -> list[str]: + """List all submodules of a given module. + + Args: + module_name (str): The name of the module to list submodules for. + + Returns: + list: A list of submodule names. + """ + # Import the module dynamically using its name + try: + module = importlib.import_module(module_name) + except Exception: + return [] + + # Get the path of the module. This is necessary to find its submodules. + module_path = module.__path__ + + # Initialize an empty list to store the names of submodules + submodules = [] + + # Iterate over the submodules in the module's path + for _, name, ispkg in pkgutil.iter_modules(module_path, prefix=f"{module_name}."): + # Add the name of each submodule to the list + submodules.append(name) + + if ispkg: + submodules.extend(list_submodules(name)) + + # Return the list of submodule names + return submodules + + +def test_list_submodules() -> None: + # Specify the name of the module you want to inspect + module_name = "fastagency" + + # Get the list of submodules for the specified module + submodules = list_submodules(module_name) + + assert "fastagency.ui" in submodules + assert "fastagency.ui.mesop" in submodules + assert "fastagency.ui.console.base" in submodules + + +@pytest.mark.parametrize("module", list_submodules("fastagency")) +def test_submodules(module: str) -> None: + if module.startswith("fastagency.ui.mesop") and sys.version_info < (3, 10): + with pytest.raises( + FastAgencyCLIPythonVersionError, + match="Mesop requires Python 3.10 or higher", + ): + importlib.import_module(module) + return + + importlib.import_module(module) diff --git a/tests/ui/console/test_base.py b/tests/ui/console/test_base.py index 94ea7e71..62db65be 100644 --- a/tests/ui/console/test_base.py +++ b/tests/ui/console/test_base.py @@ -17,7 +17,7 @@ def import_string() -> str: def app(import_string: str) -> Iterator[FastAgency]: wf = AutoGenWorkflows() console = ConsoleUI() - app = FastAgency(wf=wf, ui=console) + app = FastAgency(provider=wf, ui=console) @wf.register(name="noop", description="No operation") def noop(*args: Any, **kwargs: Any) -> str: diff --git a/tests/ui/mesop/test_base.py b/tests/ui/mesop/test_base.py index 6ccd665a..7ecb21a0 100644 --- a/tests/ui/mesop/test_base.py +++ b/tests/ui/mesop/test_base.py @@ -22,7 +22,7 @@ def test_create(self) -> None: MesopUI.get_created_instance() wf = AutoGenWorkflows() - app = FastAgency(wf=wf, ui=mesop_ui) + app = FastAgency(provider=wf, ui=mesop_ui) with mesop_ui.create(app, "import_string"): assert MesopUI.get_created_instance() == mesop_ui