Skip to content

Commit

Permalink
Integrated external workflow loading into langchain agent
Browse files Browse the repository at this point in the history
  • Loading branch information
codingbandit committed Dec 19, 2024
1 parent cd4778b commit 56c74aa
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 54 deletions.
3 changes: 2 additions & 1 deletion src/python/PythonSDK/PythonSDK.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
<Compile Include="foundationallm\exceptions\__init__.py" />
<Compile Include="foundationallm\langchain\agents\langchain_knowledge_management_agent.py" />
<Compile Include="foundationallm\langchain\common\foundationallm_tool_base.py" />
<Compile Include="foundationallm\langchain\common\foundationallm_workflow_base.py" />
<Compile Include="foundationallm\langchain\common\__init__.py" />
<Compile Include="foundationallm\langchain\workflows\workflow_factory.py" />
<Compile Include="foundationallm\langchain\workflows\external_workflow_factory.py" />
<Compile Include="foundationallm\langchain\workflows\__init__.py" />
<Compile Include="foundationallm\models\agents\agent_tool.py" />
<Compile Include="foundationallm\models\agents\agent_workflows\agent_workflow_ai_model.py" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from foundationallm.langchain.agents import LangChainAgentBase
from foundationallm.langchain.exceptions import LangChainException
from foundationallm.langchain.retrievers import RetrieverFactory, ContentArtifactRetrievalBase
from foundationallm.models.agents import AzureOpenAIAssistantsAgentWorkflow, LangGraphReactAgentWorkflow
from foundationallm.langchain.workflows import ExternalWorkflowFactory
from foundationallm.models.agents import AzureOpenAIAssistantsAgentWorkflow, ExternalAgentWorkflow, LangGraphReactAgentWorkflow
from foundationallm.models.constants import (
AgentCapabilityCategories,
ResourceObjectIdPropertyNames,
Expand Down Expand Up @@ -499,6 +500,42 @@ async def invoke_async(self, request: KnowledgeManagementCompletionRequest) -> C
)
# End LangGraph ReAct Agent workflow implementation

# Start External Agent workflow implementation
if (agent.workflow is not None and isinstance(agent.workflow, ExternalAgentWorkflow)):
# prepare tools
tool_factory = ToolFactory(self.plugin_manager)
tools = []

parsed_user_prompt = request.user_prompt

explicit_tool = next((tool for tool in agent.tools if parsed_user_prompt.startswith(f'[{tool.name}]:')), None)
if explicit_tool is not None:
tools.append(tool_factory.get_tool(explicit_tool, request.objects, self.user_identity, self.config))
parsed_user_prompt = parsed_user_prompt.split(':', 1)[1].strip()
else:
# Populate tools list from agent configuration
for tool in agent.tools:
tools.append(tool_factory.get_tool(tool, request.objects, self.user_identity, self.config))

# create the workflow
workflow_factory = ExternalWorkflowFactory(self.plugin_manager)
workflow = workflow_factory.create_workflow(
agent.workflow,
request.objects,
tools,
self.user_identity,
self.config)

# Get message history
messages = self._build_conversation_history_message_list(request.message_history, agent.conversation_history_settings.max_history)

response = await workflow.invoke_async(
user_prompt=parsed_user_prompt,
message_history=messages
)
return response
# End External Agent workflow implementation

# Start LangChain Expression Language (LCEL) implementation

# Get the vector document retriever, if it exists.
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .foundationallm_tool_base import FoundationaLLMToolBase
from .foundationallm_workflow_base import FoundationaLLMWorkflowBase
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""
Class: FoundationaLLMWorkflowBase
Description: FoundationaLLM base class for tools that uses the agent workflow model for its configuration.
"""
from abc import ABC, abstractmethod
from azure.identity import DefaultAzureCredential
from langchain_core.messages import BaseMessage
from pydantic import BaseModel
from typing import List
from foundationallm.config import Configuration, UserIdentity
from foundationallm.models.agents import AgentTool, ExternalAgentWorkflow
from foundationallm.models.orchestration import CompletionResponse
from foundationallm.telemetry import Telemetry

class FoundationaLLMWorkflowBase(BaseModel, ABC):
"""
FoundationaLLM base class for workflows that uses the agent workflow model for its configuration.
"""
def __init__(self,
workflow_config: ExternalAgentWorkflow,
objects: dict,
tools: List[AgentTool],
user_identity: UserIdentity,
config: Configuration):
"""
Initializes the FoundationaLLMWorkflowBase class with the workflow configuration.
Parameters
----------
workflow_config : ExternalAgentWorkflow
The workflow assigned to the agent.
objects : dict
The exploded objects assigned from the agent.
tools : List[AgentTool]
The tools assigned to the agent.
user_identity : UserIdentity
The user identity of the user initiating the request.
config : Configuration
The application configuration for FoundationaLLM.
"""
self.workflow_config = workflow_config
self.objects = objects
self.tools = tools if tools is not None else []
self.user_identity = user_identity
self.config = config
self.logger = Telemetry.get_logger(self.workflow_config.name)
self.tracer = Telemetry.get_tracer(self.workflow_config.name)
self.default_credential = DefaultAzureCredential(exclude_environment_credential=True)

@abstractmethod
async def invoke_async(self,
user_prompt:str,
message_history: List[BaseMessage])-> CompletionResponse:
"""
Invokes the workflow asynchronously.
Parameters
----------
user_prompt : str
The user prompt message.
message_history : List[BaseMessage]
The message history.
"""
pass

class Config:
""" Pydantic configuration for FoundationaLLMWorkflowBase. """
extra = "allow"
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .workflow_factory import WorkflowFactory
from .external_workflow_factory import ExternalWorkflowFactory
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""
Class: WorkflowFactory
Description: Factory class for creating an external workflow instance based on the Agent workflow configuration.
"""
from typing import List
from foundationallm.config import Configuration, UserIdentity
from foundationallm.langchain.common import FoundationaLLMWorkflowBase
from foundationallm.langchain.exceptions import LangChainException
from foundationallm.models.agents import AgentTool, ExternalAgentWorkflow
from foundationallm.plugins import PluginManager

class ExternalWorkflowFactory:
"""
Factory class for creating an external agent workflow instance based on the Agent workflow configuration.
"""
def __init__(self, plugin_manager: PluginManager):
"""
Initializes the workflow factory.
Parameters
----------
plugin_manager : PluginManager
The plugin manager object used to load external workflows.
"""
self.plugin_manager = plugin_manager

def get_workflow(
self,
workflow_config: ExternalAgentWorkflow,
objects: dict,
tools: List[AgentTool],
user_identity: UserIdentity,
config: Configuration
) -> FoundationaLLMWorkflowBase:
"""
Creates an instance of an external agent workflow based on the agent workflow configuration.
Parameters
----------
workflow_config : ExternalAgentWorkflow
The workflow assigned to the agent.
objects : dict
The exploded objects assigned from the agent.
tools : List[AgentTool]
The tools assigned to the agent.
user_identity : UserIdentity
The user identity of the user initiating the request.
config : Configuration
The application configuration for FoundationaLLM.
"""
workflow_plugin_manager = None
if workflow_config.package_name in self.plugin_manager.external_modules:
workflow_plugin_manager = self.plugin_manager.external_modules[workflow_config.package_name].plugin_manager
return workflow_plugin_manager.create_workflow(workflow_config, objects, tools, user_identity, config)
else:
raise LangChainException(f"Package {workflow_config.package_name} not found in the list of external modules loaded by the package manager.")

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
from abc import ABC, abstractmethod
from typing import List
from foundationallm.config import Configuration, UserIdentity
from foundationallm.langchain.common import FoundationaLLMToolBase
from foundationallm.models.agents import AgentWorkflowBase
from foundationallm.models.agents import AgentTool, ExternalAgentWorkflow

class WorkflowPluginManagerBase(ABC):
"""
The base class for all workflow plugin managers.
"""
def __init__(self):
pass

@abstractmethod
def create_workflow(self,
workflow_config: AgentWorkflowBase,
workflow_config: ExternalAgentWorkflow,
objects: dict,
tools: List[AgentTool],
user_identity: UserIdentity,
config: Configuration) -> FoundationaLLMToolBase:
"""
Create a workflow instance based on the given configuration and tools.
Parameters
----------
workflow_config : ExternalAgentWorkflow
The workflow assigned to the agent.
objects : dict
The exploded objects assigned from the agent.
tools : List[AgentTool]
The tools assigned to the agent.
user_identity : UserIdentity
The user identity of the user initiating the request.
config : Configuration
The application configuration for FoundationaLLM.
"""
pass

@abstractmethod
Expand Down

0 comments on commit 56c74aa

Please sign in to comment.