Skip to content

Commit

Permalink
Merge pull request #2095 from solliancenet/cp_agent_workflow_plugin
Browse files Browse the repository at this point in the history
Adds dynamic loading of agent workflow modules
  • Loading branch information
ciprianjichici authored Dec 19, 2024
2 parents 697f033 + 2c4ea0f commit b5950ec
Show file tree
Hide file tree
Showing 31 changed files with 590 additions and 67 deletions.
47 changes: 47 additions & 0 deletions docs/release-notes/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,53 @@
> [!NOTE]
> This section is for changes that are not yet released but will affect future releases.
## Starting with 0.9.1-rc105

### Configuration changes

The following new App Configuration settings are required:

|Name | Default value | Description |
|--- | --- | --- |
|`FoundationaLLM:PythonSDK:Logging:LogLevel:Azure` | `Warning` | Provides the default level of logging for Azure modules in the Python SDK. |

### Agent workflow configuration changes

Agent resource configuration files that have a `workflow` property now requires a `name` and `package_name` property. This is to support loading external workflows via plugins. For internal workflows, the `package_name` should be set to `FoundationaLLM`. Example below truncated for brevity.

```json
{
"workflow": {
"type": "langgraph-react-agent-workflow",
"name": "LangGraphReactAgent",
"package_name": "FoundationaLLM",
"workflow_host": "LangChain",
"graph_recursion_limit": 10,
"resource_object_ids": {}
}
}
```

A new `Workflow` resource must be added to the `FoundationaLLM.Agent` resource provider:

```json
{
"type": "external-agent-workflow",
"name": "ExternalAgentWorkflow",
"object_id": "/instances/<instance_id>/providers/FoundationaLLM.Agent/workflows/ExternalAgentWorkflow",
"display_name": "ExternalAgentWorkflow",
"description": "External Agent workflow",
"cost_center": null,
"properties": null,
"created_on": "2024-11-13T18:12:07.0223039+00:00",
"updated_on": "0001-01-01T00:00:00+00:00",
"created_by": "[email protected]",
"updated_by": null,
"deleted": false,
"expiration_date": null
}
```

## Starting with 0.9.1-rc102

### Configuration changes
Expand Down
8 changes: 8 additions & 0 deletions src/dotnet/Common/Constants/Data/AppConfiguration.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@
"content_type": "",
"first_version": "0.9.0"
},
{
"name": "Logging:LogLevel:Azure",
"description": "The default logging level used by the Python SDK.",
"secret": "",
"value": "Warning",
"content_type": "",
"first_version": "0.9.1"
},
{
"name": "Logging:EnableConsoleLogging",
"description": "The flag indicating whether the Python SDK sends logs to the console or not.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace FoundationaLLM.Common.Models.ResourceProviders.Agent.AgentWorkflows
[JsonDerivedType(typeof(AzureOpenAIAssistantsAgentWorkflow), AgentWorkflowTypes.AzureOpenAIAssistants)]
[JsonDerivedType(typeof(LangChainExpressionLanguageAgentWorkflow), AgentWorkflowTypes.LangChainExpressionLanguage)]
[JsonDerivedType(typeof(LangGraphReactAgentWorkflow), AgentWorkflowTypes.LangGraphReactAgent)]
[JsonDerivedType(typeof(ExternalAgentWorkflow), AgentWorkflowTypes.ExternalAgentWorkflow)]
public class AgentWorkflowBase
{
/// <summary>
Expand All @@ -20,12 +21,17 @@ public class AgentWorkflowBase

/// <summary>
/// The name of the workflow.
/// </summary>
[JsonPropertyName("name")]
public required string Name { get; set; }

/// <summary>
/// Gets or sets the package name of the workflow.
/// For internal workflows, this value will be FoundationaLLM
/// For external workflows, this value will be the name of the package.
/// </summary>
/// <remarks>
/// This value is always derived from the <see cref="ResourceObjectIds"/> property.
/// </remarks>
[JsonPropertyName("workflow_name")]
public string? WorkflowName { get; set; }
[JsonPropertyName("package_name")]
public required string PackageName { get; set; }

/// <summary>
/// The host of the workflow environment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ public static class AgentWorkflowTypes
/// The LangGraph ReAct agent workflow.
/// </summary>
public const string LangGraphReactAgent = "langgraph-react-agent-workflow";

/// <summary>
/// The External Agent workflow.
/// </summary>
public const string ExternalAgentWorkflow = "external-agent-workflow";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Text.Json.Serialization;

namespace FoundationaLLM.Common.Models.ResourceProviders.Agent.AgentWorkflows
{
/// <summary>
/// Provides an agent workflow configuration for an External Agent workflow loaded via an external module.
/// </summary>
public class ExternalAgentWorkflow : AgentWorkflowBase
{
/// <inheritdoc/>
[JsonIgnore]
public override string Type => AgentWorkflowTypes.ExternalAgentWorkflow;
}
}
7 changes: 7 additions & 0 deletions src/dotnet/Common/Templates/AppConfigurationKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ public static class AppConfigurationKeys
public const string FoundationaLLM_PythonSDK_Logging_LogLevel_Default =
"FoundationaLLM:PythonSDK:Logging:LogLevel:Default";

/// <summary>
/// The app configuration key for the FoundationaLLM:PythonSDK:Logging:LogLevel:Azure setting.
/// <para>Value description:<br/>The default logging level used by the Python SDK.</para>
/// </summary>
public const string FoundationaLLM_PythonSDK_Logging_LogLevel_Azure =
"FoundationaLLM:PythonSDK:Logging:LogLevel:Azure";

/// <summary>
/// The app configuration key for the FoundationaLLM:PythonSDK:Logging:EnableConsoleLogging setting.
/// <para>Value description:<br/>The flag indicating whether the Python SDK sends logs to the console or not.</para>
Expand Down
7 changes: 7 additions & 0 deletions src/dotnet/Common/Templates/appconfig.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@
"content_type": "",
"tags": {}
},
{
"key": "FoundationaLLM:PythonSDK:Logging:LogLevel:Azure",
"value": "Warning",
"label": null,
"content_type": "",
"tags": {}
},
{
"key": "FoundationaLLM:PythonSDK:Logging:EnableConsoleLogging",
"value": "false",
Expand Down
10 changes: 9 additions & 1 deletion src/dotnet/Orchestration/Orchestration/OrchestrationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,15 @@ await cosmosDBService.PatchOperationsItemPropertiesAsync<LongRunningOperationCon
}
break;
case AgentResourceTypeNames.Workflows:
agentWorkflow.WorkflowName = resourcePath.MainResourceId;

var retrievedWorkflow = await agentResourceProvider.GetResourceAsync<Workflow>(
resourceObjectId.ObjectId,
currentUserIdentity);

explodedObjectsManager.TryAdd(
retrievedWorkflow.ObjectId!,
retrievedWorkflow);

break;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .skunkworks_tool_plugin_manager import SkunkworksToolPluginManager
from .skunkworks_workflow_plugin_manager import SkunkworksWorkflowPluginManager
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class SkunkworksToolPluginManager(ToolPluginManagerBase):
FOUNDATIONALLM_CODE_INTERPRETER_TOOL_NAME = 'FoundationaLLMCodeInterpreterTool'

def __init__(self):
pass
super().__init__()

def create_tool(self,
tool_config: AgentTool,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import List

from foundationallm.config import Configuration, UserIdentity
from foundationallm.models.agents import AgentTool, ExternalAgentWorkflow
from foundationallm.langchain.common import FoundationaLLMWorkflowBase
from foundationallm.plugins import WorkflowPluginManagerBase

from skunkworks_foundationallm.workflows import (
FoundationaLLMRouterWorkflow
)

class SkunkworksWorkflowPluginManager(WorkflowPluginManagerBase):

FOUNDATIONALLM_ROUTER_WORKFLOW_NAME = 'FoundationaLLMRouterWorkflow'

def __init__(self):
super().__init__()

def create_workflow(
self,
workflow_config: ExternalAgentWorkflow,
objects: dict,
tools: List[AgentTool],
user_identity: UserIdentity,
config: Configuration) -> FoundationaLLMWorkflowBase:
"""
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.
"""
match workflow_config.name:
case SkunkworksWorkflowPluginManager.FOUNDATIONALLM_ROUTER_WORKFLOW_NAME:
return FoundationaLLMRouterWorkflow(workflow_config, objects, tools, user_identity, config)
case _:
raise ValueError(f"Unknown tool name: {workflow_config.name}")

def refresh_tools():
print('Refreshing tools...')
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .foundationallm_router_workflow import FoundationaLLMRouterWorkflow
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
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.langchain.common import FoundationaLLMWorkflowBase
from foundationallm.models.agents import AgentTool, ExternalAgentWorkflow
from foundationallm.models.constants import AgentCapabilityCategories
from foundationallm.models.orchestration import CompletionResponse, OpenAITextMessageContentItem
from foundationallm.telemetry import Telemetry

class FoundationaLLMRouterWorkflow(FoundationaLLMWorkflowBase):
"""
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.
"""
super().__init__(workflow_config, objects, tools, user_identity, config)

async def invoke_async(self,
operation_id: str,
user_prompt:str,
message_history: List[BaseMessage])-> CompletionResponse:
"""
Invokes the workflow asynchronously.
Parameters
----------
operation_id : str
The unique identifier of the FoundationaLLM operation.
user_prompt : str
The user prompt message.
message_history : List[BaseMessage]
The message history.
"""
response_content = OpenAITextMessageContentItem(
value = '42 is the answer to all questions',
agent_capability_category = AgentCapabilityCategories.FOUNDATIONALLM_KNOWLEDGE_MANAGEMENT
)


return CompletionResponse(
operation_id = operation_id,
content = [response_content],
content_artifacts = [],
user_prompt = user_prompt,
full_prompt = '',
completion_tokens = 0,
prompt_tokens = 0,
total_tokens = 0,
total_cost = 0
)
8 changes: 8 additions & 0 deletions src/python/PythonSDK/PythonSDK.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@
<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\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" />
<Compile Include="foundationallm\models\agents\agent_workflows\agent_workflow_base.py" />
<Compile Include="foundationallm\models\agents\agent_workflows\azure_openai_assistants_agent_workflow.py" />
<Compile Include="foundationallm\models\agents\agent_workflows\external_agent_workflow.py" />
<Compile Include="foundationallm\models\agents\agent_workflows\langchain_expression_language_agent_workflow.py" />
<Compile Include="foundationallm\models\agents\agent_workflows\langgraph_react_agent_workflow.py" />
<Compile Include="foundationallm\models\attachments\attachment_properties.py" />
Expand All @@ -56,7 +60,9 @@
<Compile Include="foundationallm\models\services\openai_assistants_response.py" />
<Compile Include="foundationallm\plugins\external_module.py" />
<Compile Include="foundationallm\plugins\plugin_manager.py" />
<Compile Include="foundationallm\plugins\plugin_manager_types.py" />
<Compile Include="foundationallm\plugins\tools\tool_plugin_manager_base.py" />
<Compile Include="foundationallm\plugins\workflows\workflow_plugin_manager_base.py" />
<Compile Include="foundationallm\plugins\__init__.py" />
<Compile Include="foundationallm\services\audio_analysis_service.py" />
<Compile Include="foundationallm\services\gateway_text_embedding\text_chunk.py" />
Expand Down Expand Up @@ -185,12 +191,14 @@
<Folder Include="foundationallm\langchain\language_models\" />
<Folder Include="foundationallm\langchain\language_models\openai\" />
<Folder Include="foundationallm\langchain\exceptions\" />
<Folder Include="foundationallm\langchain\workflows\" />
<Folder Include="foundationallm\models\agents\agent_workflows\" />
<Folder Include="foundationallm\models\attachments\" />
<Folder Include="foundationallm\models\constants\" />
<Folder Include="foundationallm\event_handlers\" />
<Folder Include="foundationallm\models\messages\" />
<Folder Include="foundationallm\plugins\" />
<Folder Include="foundationallm\plugins\workflows\" />
<Folder Include="foundationallm\plugins\tools\" />
<Folder Include="foundationallm\services\" />
<Folder Include="foundationallm\langchain\retrievers\" />
Expand Down
Loading

0 comments on commit b5950ec

Please sign in to comment.