Skip to content

Commit

Permalink
Merge pull request #2042 from solliancenet/gg-resource-properties
Browse files Browse the repository at this point in the history
Extend agent tool configuration
  • Loading branch information
ciprianjichici authored Dec 9, 2024
2 parents 302eac0 + 6406bcc commit 794da32
Show file tree
Hide file tree
Showing 26 changed files with 649 additions and 239 deletions.
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"module": "uvicorn",
"cwd" : "${workspaceFolder}/src/python/LangChainAPI/app",
"env": {
"PYTHONPATH": "d:/repos/solliance-foundationallm/src/python/LangChainAPI;d:/repos/solliance-foundationallm/src/python/PythonSDK;d:/repos/fllm/foundationallm/src/python/PythonSDK;"
"PYTHONPATH": "${workspaceFolder}/src/python/LangChainAPI;${workspaceFolder}/src/python/PythonSDK;d:/repos/fllm/foundationallm/src/python/PythonSDK;",
"FOUNDATIONALLM_CONTEXT": "DEBUG"
},
"args": ["main:app","--reload", "--port", "8765"],
"python": "${workspaceFolder}/src/python/LangChainAPI/env/Scripts/python.exe"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace FoundationaLLM.Common.Constants.ResourceProviders
{
/// <summary>
/// Contains constants of the resource property names.
/// </summary>
public static class ResourceObjectIdPropertyNames
{
/// <summary>
/// Object role.
/// </summary>
public const string ObjectRole = "object_role";

/// <summary>
/// Model parameters.
/// </summary>
public const string ModelParameters = "model_parameters";

/// <summary>
/// Text embedding model name.
/// </summary>
public const string TextEmbeddingModelName = "text_embedding_model_name";

/// <summary>
/// Text embedding model parameters.
/// </summary>
public const string TextEmbeddingModelParameters = "text_embedding_model_parameters";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace FoundationaLLM.Common.Constants.ResourceProviders
{
/// <summary>
/// Contains constants of the resource property values.
/// </summary>
public static class ResourceObjectIdPropertyValues
{
/// <summary>
/// Main model.
/// </summary>
public const string MainModel = "main_model";

/// <summary>
/// Main prompt.
/// </summary>
public const string MainPrompt = "main_prompt";

/// <summary>
/// Main indexing profile.
/// </summary>
public const string MainIndexingProfile = "main_indexing_profile";
}
}
30 changes: 3 additions & 27 deletions src/dotnet/Common/Models/ResourceProviders/Agent/AgentTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,10 @@ public class AgentTool
public required string PackageName { get; set; }

/// <summary>
/// Gets or sets a dictionary of AI model object identifiers.
/// Gets or sets a dictionary of resource objects.
/// </summary>
/// <remarks>
/// The key is a value that is well-known to the tool, and the value is the AI model object identifier.
/// </remarks>
[JsonPropertyName("ai_model_object_ids")]
public Dictionary<string, string> AIModelObjectIds { get; set; } = [];

/// <summary>
/// Gets of sets a dictionary of API endpoint configuration object identifiers.
/// </summary>
/// <remarks>
/// The key is a value that is well-known to the tool, and the value is the API endpoint configuration object identifier.
/// </remarks>
[JsonPropertyName("api_endpoint_configuration_object_ids")]
public Dictionary<string, string> APIEndpointConfigurationObjectIds { get; set; } = [];

/// <summary>
/// Gets or sets a dictionary of indexing profile object identifiers.
/// </summary>
[JsonPropertyName("indexing_profile_object_ids")]
public Dictionary<string, string> IndexingProfileObjectIds { get; set; } = [];

/// <summary>
/// Gets or sets a dictionary of text embedding model names.
/// </summary>
[JsonPropertyName("text_embedding_model_names")]
public Dictionary<string, string> TextEmbeddingModelNames { get; set; } = [];
[JsonPropertyName("resource_object_ids")]
public Dictionary<string, ResourceObjectIdProperties> ResourceObjectIds { get; set; } = [];

/// <summary>
/// Gets or sets a dictionary of properties that are specific to the tool.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using FoundationaLLM.Common.Constants.ResourceProviders;
using System.Text.Json.Serialization;

namespace FoundationaLLM.Common.Models.ResourceProviders.Agent.AgentWorkflows
{
Expand All @@ -18,29 +19,34 @@ public class AgentWorkflowBase
public virtual string? Type { get; set; }

/// <summary>
/// The workflow resource associated with the agent.
/// The name of the workflow.
/// </summary>
[JsonPropertyName("workflow_object_id")]
public required string WorkflowObjectId { get; set; }
/// <remarks>
/// This value is always derived from the <see cref="ResourceObjectIds"/> property.
/// </remarks>
[JsonPropertyName("workflow_name")]
public string? WorkflowName { get; set; }

/// <summary>
/// The name of the workflow resource associated with the agent.
/// The host of the workflow environment.
/// </summary>
[JsonPropertyName("workflow_name")]
public required string WorkflowName { get; set; }
[JsonPropertyName("workflow_host")]
public string? WorkflowHost { get; set; }

/// <summary>
/// The collection of AI models available to the workflow.
/// The well-known key "main-model" is used to specify the model for the main workflow.
/// Gets or sets a dictionary of resource objects.
/// </summary>
[JsonPropertyName("agent_workflow_ai_models")]
public Dictionary<string, AgentWorkflowAIModel> AgentWorkflowAIModels { get; set; } = [];
[JsonPropertyName("resource_object_ids")]
public Dictionary<string, ResourceObjectIdProperties> ResourceObjectIds { get; set; } = [];

/// <summary>
/// The collection of prompt resources available to the workflow.
/// The well-known key "main-prompt" is used to specify the prompt for the main workflow.
/// Gets the main AI model object identifier.
/// </summary>
[JsonPropertyName("prompt_object_ids")]
public Dictionary<string, string> PromptObjectIds { get; set; } = [];
[JsonIgnore]
public string? MainAIModelObjectId =>
ResourceObjectIds.Values
.FirstOrDefault(
roid => roid.HasObjectRole(ResourceObjectIdPropertyValues.MainModel))
?.ObjectId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using FoundationaLLM.Common.Constants.ResourceProviders;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace FoundationaLLM.Common.Models.ResourceProviders
{
/// <summary>
/// Defines the properties of a resource.
/// </summary>
public class ResourceObjectIdProperties
{
/// <summary>
/// The unique identifier of the resource.
/// </summary>
[JsonPropertyName("object_id")]
public required string ObjectId { get; set; }

/// <summary>
/// Gets or sets a dictionary of properties.
/// </summary>
[JsonPropertyName("properties")]
public Dictionary<string, object> Properties { get; set; } = [];

/// <summary>
/// Indicates whether the resource has the specified object role.
/// </summary>
/// <param name="role">The object role being searched.</param>
/// <returns><see langword="true"/> if the object role is present, <see langword="false"/> otherwise.</returns>
public bool HasObjectRole(string role) =>
Properties.TryGetValue(ResourceObjectIdPropertyNames.ObjectRole, out var objectRole)
&& ((JsonElement)objectRole).GetString() == role;
}
}
49 changes: 49 additions & 0 deletions src/dotnet/Common/Models/ResourceProviders/ResourcePath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,55 @@ public bool MatchesResourceTypes(ResourcePath other)
return true;
}

/// <summary>
/// Parses a resource path.
/// </summary>
/// <param name="resourcePath">The resource path to be parsed.</param>
/// <returns>A <see cref="ResourcePath"/> object containing the parsed resource path.</returns>
public static ResourcePath GetResourcePath(string resourcePath)
{
TryParseResourceProvider(resourcePath, out var resourceProvider);

var allowedResourceProviders = ImmutableList<string>.Empty;
var allowedResourceTypes = new Dictionary<string, ResourceTypeDescriptor>();

if (resourceProvider != null)
{
allowedResourceProviders = allowedResourceProviders.Add(resourceProvider);
allowedResourceTypes = GetAllowedResourceTypes(resourceProvider);
}

if (!TryParse(
resourcePath,
allowedResourceProviders,
allowedResourceTypes,
false,
out ResourcePath? parsedResourcePath))
throw new AuthorizationException($"The resource path [{resourcePath}] is invalid.");

return parsedResourcePath!;
}

/// <summary>
/// Retrieves the allowed resource types for a specified resource provider.
/// </summary>
/// <param name="resourceProvider">The name of the resource provider.</param>
public static Dictionary<string, ResourceTypeDescriptor> GetAllowedResourceTypes(string resourceProvider) =>
resourceProvider switch
{
ResourceProviderNames.FoundationaLLM_Agent => AgentResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_DataSource => DataSourceResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Prompt => PromptResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Vectorization => VectorizationResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Configuration => ConfigurationResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Attachment => AttachmentResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Authorization => AuthorizationResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_AIModel => AIModelResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_AzureOpenAI => AzureOpenAIResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Conversation => ConversationResourceProviderMetadata.AllowedResourceTypes,
_ => []
};

private void ParseResourcePath(
string resourcePath,
ImmutableList<string> allowedResourceProviders,
Expand Down
42 changes: 1 addition & 41 deletions src/dotnet/Common/Utils/ResourcePathUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,52 +83,12 @@ private static ResourcePath ParseInternal(
|| !allowedInstanceIds.Contains(instanceId!))
throw new AuthorizationException("The resource path does not contain a valid FoundationaLLM instance identifier.");

var parsedResourcePath = GetResourcePath(resourcePath);
var parsedResourcePath = ResourcePath.GetResourcePath(resourcePath);

if (!allowRootPath && parsedResourcePath.IsRootPath)
throw new AuthorizationException("A root resource path is not allowed in this context.");

return parsedResourcePath;
}

private static ResourcePath GetResourcePath(string resourcePath)
{
ResourcePath.TryParseResourceProvider(resourcePath, out var resourceProvider);

var allowedResourceProviders = ImmutableList<string>.Empty;
var allowedResourceTypes = new Dictionary<string, ResourceTypeDescriptor>();

if (resourceProvider != null)
{
allowedResourceProviders = allowedResourceProviders.Add(resourceProvider);
allowedResourceTypes = GetAllowedResourceTypes(resourceProvider);
}

if (!ResourcePath.TryParse(
resourcePath,
allowedResourceProviders,
allowedResourceTypes,
false,
out ResourcePath? parsedResourcePath))
throw new AuthorizationException($"The resource path [{resourcePath}] is invalid.");

return parsedResourcePath!;
}

private static Dictionary<string, ResourceTypeDescriptor> GetAllowedResourceTypes(string resourceProvider) =>
resourceProvider switch
{
ResourceProviderNames.FoundationaLLM_Agent => AgentResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_DataSource => DataSourceResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Prompt => PromptResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Vectorization => VectorizationResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Configuration => ConfigurationResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Attachment => AttachmentResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Authorization => AuthorizationResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_AIModel => AIModelResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_AzureOpenAI => AzureOpenAIResourceProviderMetadata.AllowedResourceTypes,
ResourceProviderNames.FoundationaLLM_Conversation => ConversationResourceProviderMetadata.AllowedResourceTypes,
_ => []
};
}
}
66 changes: 66 additions & 0 deletions src/dotnet/Orchestration/Orchestration/ExplodedObjectsManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using ZstdSharp.Unsafe;

namespace FoundationaLLM.Orchestration.Core.Orchestration
{
/// <summary>
/// Manages the exploded objects dictionary ensuring consistency and integrity.
/// </summary>
public class ExplodedObjectsManager
{
private readonly Dictionary<string, object> _explodedObjects = [];

/// <summary>
/// Adds a new key value pair to the exploded objects dictionary.
/// </summary>
/// <param name="key">The key of the object to add to the dictionary.</param>
/// <param name="value">The object to add to the dictionary.</param>
/// <returns><see langword="true"/> if the value was added successfully, <see langword="false"/> otherwise.</returns>
/// <remarks>
/// The first attempt to add an object always wins.
/// This means that if the key already exists in the dictionary, the add operation will have no effect and it will not generate an exception either.
/// </remarks>
public bool TryAdd(string key, object value)
{
if (_explodedObjects.ContainsKey(key))
return false;

_explodedObjects.Add(key, value);
return true;
}

/// <summary>
/// Indicates whether the exploded objects dictionary contains the specified key.
/// </summary>
/// <param name="key">The key being searched for.</param>
/// <returns><see langword="true"/> if the key is present in the dictionary (even if the associated value is null), <see langword="false"/> otherwise.</returns>
public bool HasKey(string key) =>
_explodedObjects.ContainsKey(key);

/// <summary>
/// Tries to get the value associated with the specified key.
/// </summary>
/// <typeparam name="T">The type of the value associated with the key.</typeparam>
/// <param name="key">The key being searched for.</param>
/// <param name="value">The value being searched for.</param>
/// <returns>The typed object associated with the specified key.</returns>
public bool TryGet<T>(string key, out T? value) where T : class
{
value = default(T);

if (_explodedObjects.TryGetValue(key, out var obj))
{
value = obj as T;
return value != null;
}

return false;
}

/// <summary>
/// Gets the exploded objects dictionary.
/// </summary>
/// <returns>A shallow copy of the internal exploded objects dictionary. This only prevents unguarded changes to the key-value pairs but not to the values themselves.</returns>
public Dictionary<string, object> GetExplodedObjects() =>
new(_explodedObjects);
}
}
Loading

0 comments on commit 794da32

Please sign in to comment.