Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create classes ad sample code for Azure Functions #47319

Merged
merged 23 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions sdk/ai/Azure.AI.Projects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Use the AI Projects client library to:
- [Retrieve messages](#retrieve-messages)
- [File search](#file-search)
- [Function call](#function-call)
- [Azure function call](#azure-function-call)
nick863 marked this conversation as resolved.
Show resolved Hide resolved
- [Troubleshooting](#troubleshooting)
- [Next steps](#next-steps)
- [Contributing](#contributing)
Expand Down Expand Up @@ -347,6 +348,83 @@ while (runResponse.Value.Status == RunStatus.Queued
|| runResponse.Value.Status == RunStatus.InProgress);
```

#### Azure function call
We also can use Azure Function from inside the agent. In the example below we are calling function "foo", which responds "Bar". In this example we create `AzureFunctionToolDefinition` object, with the function name, description, input and output queues, followed by function parameters.
```C# Snippet:AzureFunctionsDefineFunctionTools
AzureFunctionToolDefinition azureFnTool = new(
name: "foo",
description: "Get answers from the foo bot.",
inputBinding: new AzureFunctionBinding(
new AzureFunctionStorageQueue(
queueName: "azure-function-foo-input",
storageServiceEndpoint: storageQueueUri
)
),
outputBinding: new AzureFunctionBinding(
new AzureFunctionStorageQueue(
queueName: "azure-function-tool-output",
storageServiceEndpoint: storageQueueUri
)
),
parameters: BinaryData.FromObjectAsJson(
new
{
Type = "object",
Properties = new
{
query = new
{
Type = "string",
Description = "The question to ask.",
},
outputqueueuri = new
{
Type = "string",
Description = "The full output queue uri."
}
},
},
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }
)
);
```

Note that in this scenario we are asking agent to supply storage queue URI to the azure function whenever it is called.
```C# Snippet:AzureFunctionsCreateAgentWithFunctionTools
Response<Agent> agentResponse = await client.CreateAgentAsync(
model: "gpt-4",
name: "azure-function-agent-foo",
instructions: "You are a helpful support agent. Use the provided function any "
+ "time the prompt contains the string 'What would foo say?'. When you invoke "
+ "the function, ALWAYS specify the output queue uri parameter as "
+ $"'{storageQueueUri}/azure-function-tool-output'. Always responds with "
+ "\"Foo says\" and then the response from the tool.",
tools: new List<ToolDefinition> { azureFnTool }
);
Agent agent = agentResponse.Value;
```

After we have created a message with request to ask "What would foo say?", we need to wait while the run is in queued, in progress or requires action states.
```C# Snippet:AzureFunctionsHandlePollingWithRequiredAction
Response<ThreadMessage> messageResponse = await client.CreateMessageAsync(
thread.Id,
MessageRole.User,
"What is the most prevalent element in the universe? What would foo say?");
ThreadMessage message = messageResponse.Value;

Response<ThreadRun> runResponse = await client.CreateRunAsync(thread, agent);

do
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
runResponse = await client.GetRunAsync(thread.Id, runResponse.Value.Id);
}
while (runResponse.Value.Status == RunStatus.Queued
|| runResponse.Value.Status == RunStatus.InProgress
|| runResponse.Value.Status == RunStatus.RequiresAction);
```


nick863 marked this conversation as resolved.
Show resolved Hide resolved
## Troubleshooting

Any operation that fails will throw a [RequestFailedException][RequestFailedException]. The exception's `code` will hold the HTTP response status code. The exception's `message` contains a detailed message that may be helpful in diagnosing the issue:
Expand Down
162 changes: 154 additions & 8 deletions sdk/ai/Azure.AI.Projects/api/Azure.AI.Projects.net8.0.cs

Large diffs are not rendered by default.

162 changes: 154 additions & 8 deletions sdk/ai/Azure.AI.Projects/api/Azure.AI.Projects.netstandard2.0.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public static ThreadRun ThreadRun(string id = null, string threadId = null, stri
tools ??= new List<ToolDefinition>();
metadata ??= new Dictionary<string, string>();

return new ThreadRun(id, @object: null, threadId, agentId, status, requiredAction, lastError, model, instructions, tools.ToList(), createdAt, expiresAt, startedAt, completedAt, cancelledAt, failedAt, incompleteDetails, usage, temperature, topP, maxPromptTokens, maxCompletionTokens, truncationStrategy, toolChoice, responseFormat, metadata, toolResources, parallelToolCalls, serializedAdditionalRawData: null);
return new ThreadRun(id, @object: null, threadId, agentId, status, requiredAction, lastError, model, instructions, tools.ToList(), createdAt, expiresAt, startedAt, completedAt, cancelledAt, failedAt, incompleteDetails, usage, temperature, topP, maxPromptTokens, maxCompletionTokens, truncationStrategy, toolChoice, responseFormat, metadata, toolResources, parallelToolCalls ?? true, serializedAdditionalRawData: null);
}

/// <summary> Initializes a new instance of <see cref="Projects.AgentFile"/>. </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ public partial class AgentsClient
/// <param name="truncationStrategy"> The strategy to use for dropping messages as the context windows moves forward. </param>
/// <param name="toolChoice"> Controls whether or not and which tool is called by the model. </param>
/// <param name="responseFormat"> Specifies the format that the model must output. </param>
/// <param name="parallelToolCalls"> If `true` functions will run in parallel during tool use. </param>
/// <param name="metadata"> A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that object in a structured format. Keys may be up to 64 characters in length and values may be up to 512 characters in length. </param>
/// <param name="cancellationToken"> The cancellation token to use. </param>
/// <exception cref="ArgumentNullException"> <paramref name="threadId"/> or <paramref name="assistantId"/> is null. </exception>
/// <exception cref="ArgumentException"> <paramref name="threadId"/> is an empty string, and was expected to be non-empty. </exception>
#pragma warning disable AZC0015 // Unexpected client method return type.
public virtual AsyncCollectionResult<StreamingUpdate> CreateRunStreamingAsync(string threadId, string assistantId, string overrideModelName = null, string overrideInstructions = null, string additionalInstructions = null, IEnumerable<ThreadMessageOptions> additionalMessages = null, IEnumerable<ToolDefinition> overrideTools = null, float? temperature = null, float? topP = null, int? maxPromptTokens = null, int? maxCompletionTokens = null, TruncationObject truncationStrategy = null, BinaryData toolChoice = null, BinaryData responseFormat = null, IReadOnlyDictionary<string, string> metadata = null, CancellationToken cancellationToken = default)
public virtual AsyncCollectionResult<StreamingUpdate> CreateRunStreamingAsync(string threadId, string assistantId, string overrideModelName = null, string overrideInstructions = null, string additionalInstructions = null, IEnumerable<ThreadMessageOptions> additionalMessages = null, IEnumerable<ToolDefinition> overrideTools = null, float? temperature = null, float? topP = null, int? maxPromptTokens = null, int? maxCompletionTokens = null, TruncationObject truncationStrategy = null, BinaryData toolChoice = null, BinaryData responseFormat = null, bool? parallelToolCalls = null, IReadOnlyDictionary<string, string> metadata = null, CancellationToken cancellationToken = default)
#pragma warning restore AZC0015 // Unexpected client method return type.
{
Argument.AssertNotNullOrEmpty(threadId, nameof(threadId));
Expand All @@ -78,6 +79,7 @@ public virtual AsyncCollectionResult<StreamingUpdate> CreateRunStreamingAsync(st
truncationStrategy,
toolChoice,
responseFormat,
parallelToolCalls,
metadata ?? new ChangeTrackingDictionary<string, string>(),
null);
RequestContext context = FromCancellationToken(cancellationToken);
Expand Down Expand Up @@ -126,12 +128,13 @@ async Task<Response> sendRequestAsync() =>
/// <param name="truncationStrategy"> The strategy to use for dropping messages as the context windows moves forward. </param>
/// <param name="toolChoice"> Controls whether or not and which tool is called by the model. </param>
/// <param name="responseFormat"> Specifies the format that the model must output. </param>
/// <param name="parallelToolCalls"> If `true` functions will run in parallel during tool use. </param>
/// <param name="metadata"> A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that object in a structured format. Keys may be up to 64 characters in length and values may be up to 512 characters in length. </param>
/// <param name="cancellationToken"> The cancellation token to use. </param>
/// <exception cref="ArgumentNullException"> <paramref name="threadId"/> or <paramref name="assistantId"/> is null. </exception>
/// <exception cref="ArgumentException"> <paramref name="threadId"/> is an empty string, and was expected to be non-empty. </exception>
#pragma warning disable AZC0015 // Unexpected client method return type.
public virtual CollectionResult<StreamingUpdate> CreateRunStreaming(string threadId, string assistantId, string overrideModelName = null, string overrideInstructions = null, string additionalInstructions = null, IEnumerable<ThreadMessageOptions> additionalMessages = null, IEnumerable<ToolDefinition> overrideTools = null, float? temperature = null, float? topP = null, int? maxPromptTokens = null, int? maxCompletionTokens = null, TruncationObject truncationStrategy = null, BinaryData toolChoice = null, BinaryData responseFormat = null, IReadOnlyDictionary<string, string> metadata = null, CancellationToken cancellationToken = default)
public virtual CollectionResult<StreamingUpdate> CreateRunStreaming(string threadId, string assistantId, string overrideModelName = null, string overrideInstructions = null, string additionalInstructions = null, IEnumerable<ThreadMessageOptions> additionalMessages = null, IEnumerable<ToolDefinition> overrideTools = null, float? temperature = null, float? topP = null, int? maxPromptTokens = null, int? maxCompletionTokens = null, TruncationObject truncationStrategy = null, BinaryData toolChoice = null, BinaryData responseFormat = null, bool? parallelToolCalls = null, IReadOnlyDictionary<string, string> metadata = null, CancellationToken cancellationToken = default)
#pragma warning restore AZC0015 // Unexpected client method return type.
{
Argument.AssertNotNullOrEmpty(threadId, nameof(threadId));
Expand All @@ -152,6 +155,7 @@ public virtual CollectionResult<StreamingUpdate> CreateRunStreaming(string threa
truncationStrategy,
toolChoice,
responseFormat,
parallelToolCalls,
metadata ?? new ChangeTrackingDictionary<string, string>(),
null);
RequestContext context = FromCancellationToken(cancellationToken);
Expand Down
4 changes: 2 additions & 2 deletions sdk/ai/Azure.AI.Projects/src/Custom/Agent/AgentsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public AgentsClient(Uri endpoint, string subscriptionId, string resourceGroupNam
/// <param name="cancellationToken"> The cancellation token to use. </param>
/// <returns> A new <see cref="ThreadRun"/> instance. </returns>
public virtual Response<ThreadRun> CreateRun(AgentThread thread, Agent agent, CancellationToken cancellationToken = default)
=> CreateRun(thread.Id, agent.Id, null, null, null, null, null, null, null, null, null, null, null, null, null, null, cancellationToken);
=> CreateRun(thread.Id, agent.Id, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, cancellationToken);

/// <summary>
/// Creates a new run of the specified thread using a specified agent.
Expand All @@ -121,7 +121,7 @@ public virtual Response<ThreadRun> CreateRun(AgentThread thread, Agent agent, Ca
/// <param name="cancellationToken"> The cancellation token to use. </param>
/// <returns> A new <see cref="ThreadRun"/> instance. </returns>
public virtual Task<Response<ThreadRun>> CreateRunAsync(AgentThread thread, Agent agent, CancellationToken cancellationToken = default)
=> CreateRunAsync(thread.Id, agent.Id, null, null, null, null, null, null, null, null, null, null, null, null, null, null, cancellationToken);
=> CreateRunAsync(thread.Id, agent.Id, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, cancellationToken);

/// <summary> Returns a list of run steps associated an agent thread run. </summary>
/// <param name="run"> The <see cref="ThreadRun"/> instance from which run steps should be listed. </param>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// <auto-generated/>

nick863 marked this conversation as resolved.
Show resolved Hide resolved
#nullable disable

using System;
using Azure.Core;

namespace Azure.AI.Projects
{
[CodeGenSuppress("AzureFunctionToolDefinition", typeof(InternalAzureFunctionDefinition))]
public partial class AzureFunctionToolDefinition
ShivangiReja marked this conversation as resolved.
Show resolved Hide resolved
{
/// <inheritdoc cref="InternalFunctionDefinition.Name"/>
public string Name => InternalAzureFunction.Function.Name;

/// <inheritdoc cref="InternalFunctionDefinition.Description"/>
public string Description => InternalAzureFunction.Function.Description;

/// <inheritdoc cref="InternalFunctionDefinition.Parameters"/>
public BinaryData Parameters => InternalAzureFunction.Function.Parameters;

/// <summary> The definition of the function that the function tool should call. </summary>
internal InternalAzureFunctionDefinition InternalAzureFunction { get; set; }

/// <summary>
/// Initializes a new instance of AzureFunctionDefinition.
/// </summary>
/// <param name="name"> The name of the Azure function to be called. </param>
/// <param name="description"> A description of what the Azure function does, used by the model to choose when and how to call the function. </param>
/// <param name="inputBinding">Input storage queue.</param>
/// <param name="outputBinding">Output storage queue.</param>
/// <param name="parameters"> The parameters the Azure functions accepts, described as a JSON Schema object. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/>, <paramref name="description"/> or <paramref name="parameters"/> is null. </exception>
public AzureFunctionToolDefinition(string name, string description, AzureFunctionBinding inputBinding, AzureFunctionBinding outputBinding, BinaryData parameters)
: this(type: "azure_function", serializedAdditionalRawData: null, new InternalAzureFunctionDefinition(new InternalFunctionDefinition(name, description, parameters, serializedAdditionalRawData: null), inputBinding: inputBinding, outputBinding: outputBinding))
{
}

/// <inheritdoc/>
public override bool Equals(object obj)
=> (obj is AzureFunctionToolDefinition toolDefinition && Name == toolDefinition.Name);

/// <inheritdoc/>
public override int GetHashCode() => InternalAzureFunction.GetHashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public enum StreamingUpdateReason
/// Indicates that an update was generated as part of a <c>thread.created</c> event.
/// </summary>
/// <remarks> This reason is typically only associated with calls to
/// <see cref="AgentsClient.CreateThreadAndRun(string, AgentThreadCreationOptions, string, string, System.Collections.Generic.IEnumerable{ToolDefinition}, UpdateToolResourcesOptions, bool?, float?, float?, int?, int?, TruncationObject, System.BinaryData, System.BinaryData, System.Collections.Generic.IReadOnlyDictionary{string, string}, System.Threading.CancellationToken)"/>,
/// <see cref="AgentsClient.CreateThreadAndRun(string, AgentThreadCreationOptions, string, string, System.Collections.Generic.IEnumerable{ToolDefinition}, UpdateToolResourcesOptions, bool?, float?, float?, int?, int?, TruncationObject, System.BinaryData, System.BinaryData, bool?, System.Collections.Generic.IReadOnlyDictionary{string, string}, System.Threading.CancellationToken)"/>,
/// as other run-related methods operate on a thread that has previously been created.
/// </remarks>
ThreadCreated,
Expand Down
8 changes: 4 additions & 4 deletions sdk/ai/Azure.AI.Projects/src/Generated/AIProjectClient.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading