From 717c8b52f4605070cf46ced0a82dd9de8af8c25e Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Thu, 12 Sep 2024 16:50:37 +0100
Subject: [PATCH 01/10] fix issue with tabel storage identity
---
.../annotation/assistant/AssistantPost.java | 25 ++++++++---
.../annotation/assistant/AssistantQuery.java | 29 ++++++++++---
.../assistant/csharp-ooproc/AssistantApis.cs | 11 +++--
samples/chat/csharp-ooproc/ChatBot.cs | 11 +++--
samples/chat/javascript/src/app.js | 15 +++++--
.../powershell/GetChatState/function.json | 4 +-
.../powershell/PostUserResponse/function.json | 4 +-
samples/chat/typescript/src/functions/app.ts | 14 +++++--
src/Directory.Build.props | 2 +-
.../Assistants/AssistantPostInputAttribute.cs | 10 +++++
.../AssistantQueryInputAttribute.cs | 10 +++++
.../Assistants/AssistantBindingConverter.cs | 8 +---
.../Assistants/AssistantPostAttribute.cs | 10 +++++
.../Assistants/AssistantQueryAttribute.cs | 10 +++++
.../Assistants/AssistantService.cs | 41 +++++++++++++------
15 files changed, 154 insertions(+), 50 deletions(-)
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
index 768b127f..57b456d4 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
@@ -13,7 +13,6 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-
/**
*
* Assistant post input attribute which is used to update the assistant.
@@ -30,14 +29,14 @@
* The variable name used in function.json.
*
* @return The variable name used in function.json.
- */
+ */
String name();
-
+
/**
* The ID of the Assistant to query.
*
* @return The ID of the Assistant to query.
- */
+ */
String id();
/**
@@ -48,12 +47,26 @@
*/
String model();
-
/**
* The user message that user has entered for assistant to respond to.
*
* @return The user message that user has entered for assistant to respond to.
- */
+ */
String userMessage();
+ /**
+ * The configuration section name for the table settings for assistant chat
+ * storage.
+ *
+ * @return The configuration section name for the table settings for assistant
+ * chat storage.
+ */
+ String chatStorageConnectionSetting();
+
+ /**
+ * The table collection name for assistant chat storage.
+ *
+ * @return the table collection name for assistant chat storage..
+ */
+ String collectionName();
}
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
index cb4831dc..07a41799 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
@@ -12,10 +12,11 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-
+
/**
*
- * Assistant query input attribute which is used query the Assistant to get current state.
+ * Assistant query input attribute which is used query the Assistant to get
+ * current state.
*
*
* @since 1.0.0
@@ -31,7 +32,7 @@
* @return The variable name used in function.json.
*/
String name();
-
+
/**
* The ID of the Assistant to query.
*
@@ -41,10 +42,26 @@
/**
* The timestamp of the earliest message in the chat history to fetch.
- * The timestamp should be in ISO 8601 format - for example, 2023-08-01T00:00:00Z.
+ * The timestamp should be in ISO 8601 format - for example,
+ * 2023-08-01T00:00:00Z.
*
* @return The timestamp of the earliest message in the chat history to fetch.
*/
String timestampUtc();
-
- }
+
+ /**
+ * The configuration section name for the table settings for assistant chat
+ * storage.
+ *
+ * @return The configuration section name for the table settings for assistant
+ * chat storage.
+ */
+ String chatStorageConnectionSetting();
+
+ /**
+ * The table collection name for assistant chat storage.
+ *
+ * @return the table collection name for assistant chat storage..
+ */
+ String collectionName();
+}
diff --git a/samples/assistant/csharp-ooproc/AssistantApis.cs b/samples/assistant/csharp-ooproc/AssistantApis.cs
index 60cdd9ac..99b3c500 100644
--- a/samples/assistant/csharp-ooproc/AssistantApis.cs
+++ b/samples/assistant/csharp-ooproc/AssistantApis.cs
@@ -13,6 +13,9 @@ namespace AssistantSample;
///
static class AssistantApis
{
+ const string CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
+ const string COLLECTION_NAME = "SampleChatState";
+
///
/// HTTP PUT function that creates a new assistant chat bot with the specified ID.
///
@@ -37,8 +40,8 @@ public static async Task CreateAssistant(
HttpResponse = new ObjectResult(new { assistantId }) { StatusCode = 202 },
ChatBotCreateRequest = new AssistantCreateRequest(assistantId, instructions)
{
- ChatStorageConnectionSetting = "AzureWebJobsStorage",
- CollectionName = "SampleChatState",
+ ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING,
+ CollectionName = COLLECTION_NAME,
},
};
}
@@ -59,7 +62,7 @@ public class CreateChatBotOutput
public static async Task PostUserQuery(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "assistants/{assistantId}")] HttpRequestData req,
string assistantId,
- [AssistantPostInput("{assistantId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%")] AssistantState state)
+ [AssistantPostInput("{assistantId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state)
{
return new OkObjectResult(state.RecentMessages.LastOrDefault()?.Content ?? "No response returned.");
}
@@ -71,7 +74,7 @@ public static async Task PostUserQuery(
public static async Task GetChatState(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "assistants/{assistantId}")] HttpRequestData req,
string assistantId,
- [AssistantQueryInput("{assistantId}", TimestampUtc = "{Query.timestampUTC}")] AssistantState state)
+ [AssistantQueryInput("{assistantId}", TimestampUtc = "{Query.timestampUTC}", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state)
{
return new OkObjectResult(state);
}
diff --git a/samples/chat/csharp-ooproc/ChatBot.cs b/samples/chat/csharp-ooproc/ChatBot.cs
index 73025983..cd0db61d 100644
--- a/samples/chat/csharp-ooproc/ChatBot.cs
+++ b/samples/chat/csharp-ooproc/ChatBot.cs
@@ -12,6 +12,9 @@ namespace ChatBot;
///
public static class ChatBot
{
+ const string CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
+ const string COLLECTION_NAME = "SampleChatState";
+
public class CreateRequest
{
[JsonPropertyName("instructions")]
@@ -44,8 +47,8 @@ public static async Task CreateChatBot(
HttpResponse = new ObjectResult(responseJson) { StatusCode = 201 },
ChatBotCreateRequest = new AssistantCreateRequest(chatId, createRequestBody?.Instructions)
{
- ChatStorageConnectionSetting = "AzureWebJobsStorage",
- CollectionName = "SampleChatState"
+ ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING,
+ CollectionName = COLLECTION_NAME
},
};
}
@@ -63,7 +66,7 @@ public class CreateChatBotOutput
public static async Task PostUserResponse(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "chats/{chatId}")] HttpRequestData req,
string chatId,
- [AssistantPostInput("{chatId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%")] AssistantState state)
+ [AssistantPostInput("{chatId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state)
{
return new OkObjectResult(state.RecentMessages.LastOrDefault()?.Content ?? "No response returned.");
}
@@ -72,7 +75,7 @@ public static async Task PostUserResponse(
public static async Task GetChatState(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "chats/{chatId}")] HttpRequestData req,
string chatId,
- [AssistantQueryInput("{chatId}", TimestampUtc = "{Query.timestampUTC}")] AssistantState state,
+ [AssistantQueryInput("{chatId}", TimestampUtc = "{Query.timestampUTC}", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state,
FunctionContext context)
{
return new OkObjectResult(state);
diff --git a/samples/chat/javascript/src/app.js b/samples/chat/javascript/src/app.js
index 6c82941c..ae799f71 100644
--- a/samples/chat/javascript/src/app.js
+++ b/samples/chat/javascript/src/app.js
@@ -3,6 +3,9 @@
const { app, input, output } = require("@azure/functions");
+const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
+const COLLECTION_NAME = "SampleChatState";
+
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
})
@@ -18,8 +21,8 @@ app.http('CreateChatBot', {
const createRequest = {
id: chatID,
instructions: inputJson.instructions,
- chatStorageConnectionSetting: "AzureWebJobsStorage",
- collectionName: "SampleChatState"
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
}
context.extraOutputs.set(chatBotCreateOutput, createRequest)
return { status: 202, jsonBody: { chatId: chatID } }
@@ -30,7 +33,9 @@ app.http('CreateChatBot', {
const assistantQueryInput = input.generic({
type: 'assistantQuery',
id: '{chatId}',
- timestampUtc: '{Query.timestampUTC}'
+ timestampUtc: '{Query.timestampUTC}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('GetChatState', {
methods: ['GET'],
@@ -48,7 +53,9 @@ const assistantPostInput = input.generic({
type: 'assistantPost',
id: '{chatID}',
model: '%CHAT_MODEL_DEPLOYMENT_NAME%',
- userMessage: '{Query.message}'
+ userMessage: '{Query.message}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('PostUserResponse', {
methods: ['POST'],
diff --git a/samples/chat/powershell/GetChatState/function.json b/samples/chat/powershell/GetChatState/function.json
index 8a51d7da..52da792d 100644
--- a/samples/chat/powershell/GetChatState/function.json
+++ b/samples/chat/powershell/GetChatState/function.json
@@ -20,7 +20,9 @@
"direction": "in",
"name": "ChatBotState",
"id": "{chatId}",
- "timeStampUtc": "{Query.timestampUTC}"
+ "timeStampUtc": "{Query.timestampUTC}",
+ "chatStorageConnectionSetting": "AzureWebJobsStorage",
+ "collectionName": "SampleChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/chat/powershell/PostUserResponse/function.json b/samples/chat/powershell/PostUserResponse/function.json
index f560e806..3a9c871c 100644
--- a/samples/chat/powershell/PostUserResponse/function.json
+++ b/samples/chat/powershell/PostUserResponse/function.json
@@ -21,7 +21,9 @@
"name": "ChatBotState",
"id": "{chatId}",
"model": "%CHAT_MODEL_DEPLOYMENT_NAME%",
- "userMessage": "{Query.message}"
+ "userMessage": "{Query.message}",
+ "chatStorageConnectionSetting": "AzureWebJobsStorage",
+ "collectionName": "SampleChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/chat/typescript/src/functions/app.ts b/samples/chat/typescript/src/functions/app.ts
index 78fad462..62c495aa 100644
--- a/samples/chat/typescript/src/functions/app.ts
+++ b/samples/chat/typescript/src/functions/app.ts
@@ -3,6 +3,8 @@
import { HttpRequest, InvocationContext, app, input, output } from "@azure/functions";
+const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
+const COLLECTION_NAME = "SampleChatState";
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
@@ -19,8 +21,8 @@ app.http('CreateChatBot', {
const createRequest = {
id: chatID,
instructions: inputJson.instructions,
- chatStorageConnectionSetting: "AzureWebJobsStorage",
- collectionName: "SampleChatState"
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
}
context.extraOutputs.set(chatBotCreateOutput, createRequest)
return { status: 202, jsonBody: { chatId: chatID } }
@@ -31,7 +33,9 @@ app.http('CreateChatBot', {
const assistantQueryInput = input.generic({
type: 'assistantQuery',
id: '{chatId}',
- timestampUtc: '{Query.timestampUTC}'
+ timestampUtc: '{Query.timestampUTC}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('GetChatState', {
methods: ['GET'],
@@ -49,7 +53,9 @@ const assistantPostInput = input.generic({
type: 'assistantPost',
id: '{chatID}',
model: '%CHAT_MODEL_DEPLOYMENT_NAME%',
- userMessage: '{Query.message}'
+ userMessage: '{Query.message}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('PostUserResponse', {
methods: ['POST'],
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 9fbbeeb4..ae985155 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -23,7 +23,7 @@
0
- 17
+ 18
0
$(MajorVersion).$(MinorVersion).$(PatchVersion)
alpha
diff --git a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs
index 3753ddb4..8104c8d6 100644
--- a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs
+++ b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs
@@ -33,4 +33,14 @@ public AssistantPostInputAttribute(string id, string UserMessage)
/// Gets user message that user has entered for assistant to respond to.
///
public string UserMessage { get; }
+
+ ///
+ /// Configuration section name for the table settings for chat storage.
+ ///
+ public string? ChatStorageConnectionSetting { get; set; }
+
+ ///
+ /// Table collection name for chat storage.
+ ///
+ public string CollectionName { get; set; } = "SampleChatState";
}
diff --git a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
index 74128d6e..b3711431 100644
--- a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
+++ b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
@@ -25,4 +25,14 @@ public AssistantQueryInputAttribute(string id)
/// The timestamp should be in ISO 8601 format - for example, 2023-08-01T00:00:00Z.
///
public string TimestampUtc { get; set; } = string.Empty;
+
+ ///
+ /// Configuration section name for the table settings for chat storage.
+ ///
+ public string? ChatStorageConnectionSetting { get; set; }
+
+ ///
+ /// Table collection name for chat storage.
+ ///
+ public string CollectionName { get; set; } = "SampleChatState";
}
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantBindingConverter.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantBindingConverter.cs
index 05f634a5..8ec12b63 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantBindingConverter.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantBindingConverter.cs
@@ -33,13 +33,7 @@ public Task ConvertAsync(
AssistantQueryAttribute input,
CancellationToken cancellationToken)
{
- string timestampString = Uri.UnescapeDataString(input.TimestampUtc);
- if (!DateTime.TryParse(timestampString, out DateTime timestamp))
- {
- throw new ArgumentException($"Invalid timestamp '{timestampString}'");
- }
-
- return this.assistantService.GetStateAsync(input.Id, timestamp, cancellationToken);
+ return this.assistantService.GetStateAsync(input, cancellationToken);
}
async Task IAsyncConverter.ConvertAsync(
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
index 6acc8e41..db6d3cd6 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
@@ -35,4 +35,14 @@ public AssistantPostAttribute(string id, string userMessage)
///
[AutoResolve]
public string UserMessage { get; }
+
+ ///
+ /// Configuration section name for the table settings for chat storage.
+ ///
+ public string? ChatStorageConnectionSetting { get; set; }
+
+ ///
+ /// Table collection name for chat storage.
+ ///
+ public string CollectionName { get; set; } = "SampleChatState";
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
index 28c0d3ff..ede24c9b 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
@@ -26,4 +26,14 @@ public AssistantQueryAttribute(string id)
///
[AutoResolve]
public string TimestampUtc { get; set; } = string.Empty;
+
+ ///
+ /// Configuration section name for the table settings for chat storage.
+ ///
+ public string? ChatStorageConnectionSetting { get; set; }
+
+ ///
+ /// Table collection name for chat storage.
+ ///
+ public string CollectionName { get; set; } = "SampleChatState";
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
index 3c783459..6071f157 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
@@ -14,7 +14,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenAI.Assistants;
public interface IAssistantService
{
Task CreateAssistantAsync(AssistantCreateRequest request, CancellationToken cancellationToken);
- Task GetStateAsync(string id, DateTime since, CancellationToken cancellationToken);
+ Task GetStateAsync(AssistantQueryAttribute assistantQuery, CancellationToken cancellationToken);
Task PostMessageAsync(AssistantPostAttribute attribute, CancellationToken cancellationToken);
}
@@ -63,7 +63,7 @@ public async Task CreateAssistantAsync(AssistantCreateRequest request, Cancellat
request.Id,
request.Instructions ?? "(none)");
- this.CreateTableClient(request);
+ this.CreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
if (this.tableClient is null)
{
@@ -136,14 +136,26 @@ async Task DeleteBatch()
await this.tableClient.SubmitTransactionAsync(batch);
}
- public async Task GetStateAsync(string id, DateTime after, CancellationToken cancellationToken)
+ public async Task GetStateAsync(AssistantQueryAttribute assistantQuery, CancellationToken cancellationToken)
{
- DateTime afterUtc = after.ToUniversalTime();
+ string id = assistantQuery.Id;
+ string timestampString = Uri.UnescapeDataString(assistantQuery.TimestampUtc);
+ if (!DateTime.TryParse(timestampString, out DateTime timestamp))
+ {
+ throw new ArgumentException($"Invalid timestamp '{timestampString}'");
+ }
+
+ DateTime afterUtc = timestamp.ToUniversalTime();
this.logger.LogInformation(
"Reading state for assistant entity '{Id}' and getting chat messages after {Timestamp}",
id,
afterUtc.ToString("o"));
+ if (this.tableClient is null)
+ {
+ this.CreateTableClient(assistantQuery.ChatStorageConnectionSetting, assistantQuery.CollectionName);
+ }
+
InternalChatState? chatState = await this.LoadChatStateAsync(id, cancellationToken);
if (chatState is null)
{
@@ -176,7 +188,7 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
DateTime timeFilter = DateTime.UtcNow;
if (string.IsNullOrEmpty(attribute.Id))
{
- throw new ArgumentException("The assistant ID must be specified.", nameof(attribute));
+ throw new ArgumentException("The assistant Id must be specified.", nameof(attribute));
}
if (string.IsNullOrEmpty(attribute.UserMessage))
@@ -186,7 +198,12 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
if (this.tableClient is null)
{
- throw new ArgumentException("The assistant must be initialized first using CreateAssistantAsync", nameof(this.tableClient));
+ this.CreateTableClient(attribute.ChatStorageConnectionSetting, attribute.CollectionName);
+ }
+
+ if (this.tableClient is null)
+ {
+ throw new ArgumentNullException(nameof(this.tableClient));
}
this.logger.LogInformation("Posting message to assistant entity '{Id}'", attribute.Id);
@@ -389,7 +406,7 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
{
if (this.tableClient is null)
{
- throw new ArgumentException("The assistant must be initialized first using CreateAssistantAsync", nameof(this.tableClient));
+ throw new ArgumentNullException(nameof(this.tableClient));
}
// Check to see if any entity exists with partition id
@@ -451,9 +468,9 @@ static IEnumerable ToOpenAIChatRequestMessages(IEnumerable(connectionStringName);
@@ -489,7 +506,7 @@ void CreateTableClient(AssistantCreateRequest request)
this.tableServiceClient = new TableServiceClient(connectionString);
}
- this.logger.LogInformation("Using {CollectionName} for table storage collection name", request.CollectionName);
- this.tableClient = this.tableServiceClient.GetTableClient(request.CollectionName);
+ this.logger.LogInformation("Using {CollectionName} for table storage collection name", collectionName);
+ this.tableClient = this.tableServiceClient.GetTableClient(collectionName);
}
}
\ No newline at end of file
From dcf4e45721b4f584c57d178c50edb169119654a2 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 23 Sep 2024 11:22:32 +0100
Subject: [PATCH 02/10] update java library for table client post and query
---
java-library/pom.xml | 2 +-
.../annotation/assistant/AssistantPost.java | 25 ++++++++++++++++---
.../annotation/assistant/AssistantQuery.java | 25 ++++++++++++++++---
.../embeddings/EmbeddingsContext.java | 2 +-
.../Assistants/AssistantService.cs | 13 ++++++----
5 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/java-library/pom.xml b/java-library/pom.xml
index e1a8d766..c8951db5 100644
--- a/java-library/pom.xml
+++ b/java-library/pom.xml
@@ -90,7 +90,7 @@
com.azure
azure-ai-openai
- 1.0.0-beta.10
+ 1.0.0-beta.11
compile
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
index 57b456d4..4850bccc 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
@@ -25,6 +25,22 @@
@CustomBinding(direction = "in", name = "", type = "assistantPost")
public @interface AssistantPost {
+ /**
+ * The default storage account setting for the table storage account.
+ * This constant is used to specify the connection string for the table storage
+ * account
+ * where chat data will be stored.
+ */
+ String DEFAULT_CHATSTORAGE = "AzureWebJobsStorage";
+
+ /**
+ * The default collection name for the table storage account.
+ * This constant is used to specify the collection name for the table storage
+ * account
+ * where chat data will be stored.
+ */
+ String DEFAULT_COLLECTION = "SampleChatState";
+
/**
* The variable name used in function.json.
*
@@ -59,14 +75,15 @@
* storage.
*
* @return The configuration section name for the table settings for assistant
- * chat storage.
+ * chat storage. By default, it returns {@code DEFAULT_CHATSTORAGE}.
*/
- String chatStorageConnectionSetting();
+ String chatStorageConnectionSetting() default DEFAULT_CHATSTORAGE;
/**
* The table collection name for assistant chat storage.
*
- * @return the table collection name for assistant chat storage..
+ * @return the table collection name for assistant chat storage.By default, it
+ * returns {@code DEFAULT_COLLECTION}.
*/
- String collectionName();
+ String collectionName() default DEFAULT_COLLECTION;
}
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
index 07a41799..76cf262a 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
@@ -26,6 +26,22 @@
@CustomBinding(direction = "in", name = "", type = "assistantQuery")
public @interface AssistantQuery {
+ /**
+ * The default storage account setting for the table storage account.
+ * This constant is used to specify the connection string for the table storage
+ * account
+ * where chat data will be stored.
+ */
+ String DEFAULT_CHATSTORAGE = "AzureWebJobsStorage";
+
+ /**
+ * The default collection name for the table storage account.
+ * This constant is used to specify the collection name for the table storage
+ * account
+ * where chat data will be stored.
+ */
+ String DEFAULT_COLLECTION = "SampleChatState";
+
/**
* The variable name used in function.json.
*
@@ -54,14 +70,15 @@
* storage.
*
* @return The configuration section name for the table settings for assistant
- * chat storage.
+ * chat storage. By default, it returns {@code DEFAULT_CHATSTORAGE}.
*/
- String chatStorageConnectionSetting();
+ String chatStorageConnectionSetting() default DEFAULT_CHATSTORAGE;
/**
* The table collection name for assistant chat storage.
*
- * @return the table collection name for assistant chat storage..
+ * @return the table collection name for assistant chat storage.By default, it
+ * returns {@code DEFAULT_COLLECTION}.
*/
- String collectionName();
+ String collectionName() default DEFAULT_COLLECTION;
}
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/embeddings/EmbeddingsContext.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/embeddings/EmbeddingsContext.java
index 8908b33b..1627b380 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/embeddings/EmbeddingsContext.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/embeddings/EmbeddingsContext.java
@@ -13,7 +13,7 @@ public class EmbeddingsContext {
private EmbeddingsOptions request;
private Embeddings response;
- private int count;
+ private int count = 0;
public EmbeddingsOptions getRequest() {
return request;
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
index 6071f157..503b2078 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
@@ -63,11 +63,14 @@ public async Task CreateAssistantAsync(AssistantCreateRequest request, Cancellat
request.Id,
request.Instructions ?? "(none)");
- this.CreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
+ if (this.tableClient is null)
+ {
+ this.CreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
+ }
if (this.tableClient is null)
{
- throw new ArgumentNullException(nameof(this.tableClient));
+ throw new InvalidOperationException($"{nameof(this.tableClient)} is null.");
}
// Create the table if it doesn't exist
@@ -142,7 +145,7 @@ public async Task GetStateAsync(AssistantQueryAttribute assistan
string timestampString = Uri.UnescapeDataString(assistantQuery.TimestampUtc);
if (!DateTime.TryParse(timestampString, out DateTime timestamp))
{
- throw new ArgumentException($"Invalid timestamp '{timestampString}'");
+ throw new ArgumentException($"Invalid timestamp '{assistantQuery.TimestampUtc}'");
}
DateTime afterUtc = timestamp.ToUniversalTime();
@@ -203,7 +206,7 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
if (this.tableClient is null)
{
- throw new ArgumentNullException(nameof(this.tableClient));
+ throw new InvalidOperationException($"{nameof(this.tableClient)} is null.");
}
this.logger.LogInformation("Posting message to assistant entity '{Id}'", attribute.Id);
@@ -406,7 +409,7 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
{
if (this.tableClient is null)
{
- throw new ArgumentNullException(nameof(this.tableClient));
+ throw new InvalidOperationException($"{nameof(this.tableClient)} is null.");
}
// Check to see if any entity exists with partition id
From 7c6730fba5038fbcb850fa794f004a214c5e7861 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 23 Sep 2024 11:23:14 +0100
Subject: [PATCH 03/10] add null checks
---
samples/assistant/csharp-ooproc/TodoManager.cs | 13 +++----------
.../Embeddings/EmbeddingsStoreConverter.cs | 5 +++--
.../Search/SearchableDocumentJsonConverter.cs | 6 +++---
3 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/samples/assistant/csharp-ooproc/TodoManager.cs b/samples/assistant/csharp-ooproc/TodoManager.cs
index c267925b..53d572e2 100644
--- a/samples/assistant/csharp-ooproc/TodoManager.cs
+++ b/samples/assistant/csharp-ooproc/TodoManager.cs
@@ -67,22 +67,15 @@ class CosmosDbTodoManager : ITodoManager
public CosmosDbTodoManager(ILoggerFactory loggerFactory, CosmosClient cosmosClient)
{
- if (loggerFactory is null)
- {
- throw new ArgumentNullException(nameof(loggerFactory));
- }
-
- if (cosmosClient is null)
- {
- throw new ArgumentNullException(nameof(cosmosClient));
- }
+ ArgumentNullException.ThrowIfNull(loggerFactory, nameof(loggerFactory));
+ ArgumentNullException.ThrowIfNull(cosmosClient, nameof(cosmosClient));
string? CosmosDatabaseName = Environment.GetEnvironmentVariable("CosmosDatabaseName");
string? CosmosContainerName = Environment.GetEnvironmentVariable("CosmosContainerName");
if (string.IsNullOrEmpty(CosmosDatabaseName) || string.IsNullOrEmpty(CosmosContainerName))
{
- throw new ArgumentNullException("CosmosDatabaseName and CosmosContainerName must be set as environment variables or in local.settings.json");
+ throw new InvalidOperationException("CosmosDatabaseName and CosmosContainerName must be set as environment variables or in local.settings.json");
}
this.logger = loggerFactory.CreateLogger();
diff --git a/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs b/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
index ee76230a..22fcafb7 100644
--- a/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
+++ b/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
@@ -49,8 +49,9 @@ public Task> ConvertAsync(EmbeddingsStoreAtt
internal SearchableDocument ToSearchableDocument(string? json)
{
this.logger.LogDebug("Creating searchable document from JSON string: {Text}", json);
- SearchableDocument document = JsonSerializer.Deserialize(json, options);
- return document ?? throw new ArgumentException("Invalid search request.");
+ SearchableDocument document = JsonSerializer.Deserialize(json ?? throw new ArgumentNullException(nameof(json)), options)
+ ?? throw new ArgumentException("Invalid search request.");
+ return document;
}
sealed class SemanticDocumentCollector : IAsyncCollector
diff --git a/src/WebJobs.Extensions.OpenAI/Search/SearchableDocumentJsonConverter.cs b/src/WebJobs.Extensions.OpenAI/Search/SearchableDocumentJsonConverter.cs
index 2526a6c0..0bbf9b55 100644
--- a/src/WebJobs.Extensions.OpenAI/Search/SearchableDocumentJsonConverter.cs
+++ b/src/WebJobs.Extensions.OpenAI/Search/SearchableDocumentJsonConverter.cs
@@ -49,18 +49,18 @@ public override SearchableDocument Read(ref Utf8JsonReader reader, Type typeToCo
{
if (connectionInfoItem.NameEquals("connectionName"u8))
{
- connectionName = connectionInfoItem.Value.GetString();
+ connectionName = connectionInfoItem.Value.GetString() ?? string.Empty;
}
if (connectionInfoItem.NameEquals("collectionName"u8))
{
- collectionName = connectionInfoItem.Value.GetString();
+ collectionName = connectionInfoItem.Value.GetString() ?? string.Empty;
}
}
}
if (item.NameEquals("title"u8))
{
- title = item.Value.GetString();
+ title = item.Value.GetString() ?? string.Empty;
}
}
SearchableDocument searchableDocument = new SearchableDocument(title)
From 1de690448a3ac749a8d5e1bec31523dbfc4bd596 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 23 Sep 2024 11:27:02 +0100
Subject: [PATCH 04/10] add null checks for IngestEmail
---
.../rag-aisearch/csharp-ooproc/FilePrompt.cs | 19 ++++++++++++++-----
.../rag-cosmosdb/csharp-ooproc/FilePrompt.cs | 19 ++++++++++++++-----
.../csharp-ooproc/EmailPromptDemo.cs | 19 ++++++++++++++-----
3 files changed, 42 insertions(+), 15 deletions(-)
diff --git a/samples/rag-aisearch/csharp-ooproc/FilePrompt.cs b/samples/rag-aisearch/csharp-ooproc/FilePrompt.cs
index 56fcabde..7cda09af 100644
--- a/samples/rag-aisearch/csharp-ooproc/FilePrompt.cs
+++ b/samples/rag-aisearch/csharp-ooproc/FilePrompt.cs
@@ -30,24 +30,33 @@ public class SemanticSearchRequest
public static async Task IngestFile(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
+ ArgumentNullException.ThrowIfNull(req);
+
using StreamReader reader = new(req.Body);
string request = await reader.ReadToEndAsync();
+ if (string.IsNullOrWhiteSpace(request))
+ {
+ throw new ArgumentException("Request body is empty.");
+ }
+
EmbeddingsRequest? requestBody = JsonSerializer.Deserialize(request);
- if (requestBody == null || requestBody.Url == null)
+ if (string.IsNullOrWhiteSpace(requestBody?.Url))
{
throw new ArgumentException("Invalid request body. Make sure that you pass in {\"Url\": value } as the request body.");
}
- Uri uri = new(requestBody.Url);
- string filename = Path.GetFileName(uri.AbsolutePath);
+ if (!Uri.TryCreate(requestBody.Url, UriKind.Absolute, out Uri? uri))
+ {
+ throw new ArgumentException("Invalid Url format.");
+ }
- IActionResult result = new OkObjectResult(new { status = HttpStatusCode.OK });
+ string filename = Path.GetFileName(uri.AbsolutePath);
return new EmbeddingsStoreOutputResponse
{
- HttpResponse = result,
+ HttpResponse = new OkObjectResult(new { status = HttpStatusCode.OK }),
SearchableDocument = new SearchableDocument(filename)
};
}
diff --git a/samples/rag-cosmosdb/csharp-ooproc/FilePrompt.cs b/samples/rag-cosmosdb/csharp-ooproc/FilePrompt.cs
index ed0ba589..87587626 100644
--- a/samples/rag-cosmosdb/csharp-ooproc/FilePrompt.cs
+++ b/samples/rag-cosmosdb/csharp-ooproc/FilePrompt.cs
@@ -30,24 +30,33 @@ public class SemanticSearchRequest
public static async Task IngestFile(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
+ ArgumentNullException.ThrowIfNull(req);
+
using StreamReader reader = new(req.Body);
string request = await reader.ReadToEndAsync();
+ if (string.IsNullOrWhiteSpace(request))
+ {
+ throw new ArgumentException("Request body is empty.");
+ }
+
EmbeddingsRequest? requestBody = JsonSerializer.Deserialize(request);
- if (requestBody == null || requestBody.Url == null)
+ if (string.IsNullOrWhiteSpace(requestBody?.Url))
{
throw new ArgumentException("Invalid request body. Make sure that you pass in {\"Url\": value } as the request body.");
}
- Uri uri = new(requestBody.Url);
- string filename = Path.GetFileName(uri.AbsolutePath);
+ if (!Uri.TryCreate(requestBody.Url, UriKind.Absolute, out Uri? uri))
+ {
+ throw new ArgumentException("Invalid Url format.");
+ }
- IActionResult result = new OkObjectResult(new { status = HttpStatusCode.OK });
+ string filename = Path.GetFileName(uri.AbsolutePath);
return new EmbeddingsStoreOutputResponse
{
- HttpResponse = result,
+ HttpResponse = new OkObjectResult(new { status = HttpStatusCode.OK }),
SearchableDocument = new SearchableDocument(filename)
};
}
diff --git a/samples/rag-kusto/csharp-ooproc/EmailPromptDemo.cs b/samples/rag-kusto/csharp-ooproc/EmailPromptDemo.cs
index b9f1ec6a..972ad200 100644
--- a/samples/rag-kusto/csharp-ooproc/EmailPromptDemo.cs
+++ b/samples/rag-kusto/csharp-ooproc/EmailPromptDemo.cs
@@ -30,24 +30,33 @@ public class SemanticSearchRequest
public async Task IngestEmail(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
+ ArgumentNullException.ThrowIfNull(req);
+
using StreamReader reader = new(req.Body);
string request = await reader.ReadToEndAsync();
+ if (string.IsNullOrWhiteSpace(request))
+ {
+ throw new ArgumentException("Request body is empty.");
+ }
+
EmbeddingsRequest? requestBody = JsonSerializer.Deserialize(request);
- if (requestBody == null || requestBody.Url == null)
+ if (string.IsNullOrWhiteSpace(requestBody?.Url))
{
throw new ArgumentException("Invalid request body. Make sure that you pass in {\"Url\": value } as the request body.");
}
- Uri uri = new(requestBody.Url);
- string filename = Path.GetFileName(uri.AbsolutePath);
+ if (!Uri.TryCreate(requestBody.Url, UriKind.Absolute, out Uri? uri))
+ {
+ throw new ArgumentException("Invalid Url format.");
+ }
- IActionResult result = new OkObjectResult(new { status = HttpStatusCode.OK });
+ string filename = Path.GetFileName(uri.AbsolutePath);
return new EmbeddingsStoreOutputResponse
{
- HttpResponse = result,
+ HttpResponse = new OkObjectResult(new { status = HttpStatusCode.OK }),
SearchableDocument = new SearchableDocument(filename)
};
}
From af06e5d47c906a22a2103631800d9c3c282abc5b Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 23 Sep 2024 11:28:51 +0100
Subject: [PATCH 05/10] update packages
---
.../WebJobs.Extensions.OpenAI.csproj | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/WebJobs.Extensions.OpenAI/WebJobs.Extensions.OpenAI.csproj b/src/WebJobs.Extensions.OpenAI/WebJobs.Extensions.OpenAI.csproj
index 522080b3..65ecfa87 100644
--- a/src/WebJobs.Extensions.OpenAI/WebJobs.Extensions.OpenAI.csproj
+++ b/src/WebJobs.Extensions.OpenAI/WebJobs.Extensions.OpenAI.csproj
@@ -6,12 +6,12 @@
-
-
+
+
-
+
-
+
From aa411823ba297c2bf024c175d37d7d532435f934 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 23 Sep 2024 16:00:01 +0100
Subject: [PATCH 06/10] update worker core package
---
.../Functions.Worker.Extensions.OpenAI.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Functions.Worker.Extensions.OpenAI/Functions.Worker.Extensions.OpenAI.csproj b/src/Functions.Worker.Extensions.OpenAI/Functions.Worker.Extensions.OpenAI.csproj
index eb465162..ee76b15d 100644
--- a/src/Functions.Worker.Extensions.OpenAI/Functions.Worker.Extensions.OpenAI.csproj
+++ b/src/Functions.Worker.Extensions.OpenAI/Functions.Worker.Extensions.OpenAI.csproj
@@ -8,7 +8,7 @@
-
+
From 7863d9a6401f514dcce9b6b99c864b6e3aaf078a Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 23 Sep 2024 16:57:11 +0100
Subject: [PATCH 07/10] update assistant samples for js,ts and ps
---
.../javascript/src/functions/assistantApis.js | 15 +++++++++++----
.../assistant/powershell/CreateAssistant/run.ps1 | 4 ++--
.../powershell/GetChatState/function.json | 4 +++-
.../powershell/PostUserQuery/function.json | 4 +++-
.../typescript/src/functions/assistantApis.ts | 14 ++++++++++----
samples/chat/powershell/CreateChatBot/run.ps1 | 4 ++--
6 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/samples/assistant/javascript/src/functions/assistantApis.js b/samples/assistant/javascript/src/functions/assistantApis.js
index 469cae21..b64289e3 100644
--- a/samples/assistant/javascript/src/functions/assistantApis.js
+++ b/samples/assistant/javascript/src/functions/assistantApis.js
@@ -3,6 +3,9 @@
const { app, input, output } = require("@azure/functions");
+const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
+const COLLECTION_NAME = "SampleChatState";
+
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
})
@@ -21,8 +24,8 @@ app.http('CreateAssistant', {
const createRequest = {
id: assistantId,
instructions: instructions,
- chatStorageConnectionSetting: "AzureWebJobsStorage",
- collectionName: "SampleChatState"
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
}
context.extraOutputs.set(chatBotCreateOutput, createRequest)
return { status: 202, jsonBody: { assistantId: assistantId } }
@@ -34,7 +37,9 @@ const assistantPostInput = input.generic({
type: 'assistantPost',
id: '{assistantId}',
model: '%CHAT_MODEL_DEPLOYMENT_NAME%',
- userMessage: '{Query.message}'
+ userMessage: '{Query.message}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('PostUserResponse', {
methods: ['POST'],
@@ -58,7 +63,9 @@ app.http('PostUserResponse', {
const chatBotQueryInput = input.generic({
type: 'assistantQuery',
id: '{assistantId}',
- timestampUtc: '{Query.timestampUTC}'
+ timestampUtc: '{Query.timestampUTC}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('GetChatState', {
methods: ['GET'],
diff --git a/samples/assistant/powershell/CreateAssistant/run.ps1 b/samples/assistant/powershell/CreateAssistant/run.ps1
index d61679a9..08fdb14d 100644
--- a/samples/assistant/powershell/CreateAssistant/run.ps1
+++ b/samples/assistant/powershell/CreateAssistant/run.ps1
@@ -9,8 +9,8 @@ $instructions += "\nAsk for clarification if a user request is ambiguous."
$create_request = @{
"id" = $assistantId
- "instructions" = $instructions,
- "chatStorageConnectionSetting" = "AzureWebJobsStorage",
+ "instructions" = $instructions
+ "chatStorageConnectionSetting" = "AzureWebJobsStorage"
"collectionName" = "SampleChatState"
}
diff --git a/samples/assistant/powershell/GetChatState/function.json b/samples/assistant/powershell/GetChatState/function.json
index 56e22792..dc5a00a4 100644
--- a/samples/assistant/powershell/GetChatState/function.json
+++ b/samples/assistant/powershell/GetChatState/function.json
@@ -21,7 +21,9 @@
"direction": "in",
"dataType": "string",
"id": "{assistantId}",
- "timestampUtc": "{Query.timestampUTC}"
+ "timestampUtc": "{Query.timestampUTC}",
+ "chatStorageConnectionSetting": "AzureWebJobsStorage",
+ "collectionName": "SampleChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/assistant/powershell/PostUserQuery/function.json b/samples/assistant/powershell/PostUserQuery/function.json
index c6958834..1be27abf 100644
--- a/samples/assistant/powershell/PostUserQuery/function.json
+++ b/samples/assistant/powershell/PostUserQuery/function.json
@@ -22,7 +22,9 @@
"dataType": "string",
"id": "{assistantId}",
"userMessage": "{Query.message}",
- "model": "%CHAT_MODEL_DEPLOYMENT_NAME%"
+ "model": "%CHAT_MODEL_DEPLOYMENT_NAME%",
+ "chatStorageConnectionSetting": "AzureWebJobsStorage",
+ "collectionName": "SampleChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/assistant/typescript/src/functions/assistantApis.ts b/samples/assistant/typescript/src/functions/assistantApis.ts
index 27d2963c..81f27d4e 100644
--- a/samples/assistant/typescript/src/functions/assistantApis.ts
+++ b/samples/assistant/typescript/src/functions/assistantApis.ts
@@ -3,6 +3,8 @@
import { HttpRequest, InvocationContext, app, input, output } from "@azure/functions"
+const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
+const COLLECTION_NAME = "SampleChatState";
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
@@ -22,8 +24,8 @@ app.http('CreateAssistant', {
const createRequest = {
id: assistantId,
instructions: instructions,
- chatStorageConnectionSetting: "AzureWebJobsStorage",
- collectionName: "SampleChatState"
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
}
context.extraOutputs.set(chatBotCreateOutput, createRequest)
return { status: 202, jsonBody: { assistantId: assistantId } }
@@ -35,7 +37,9 @@ const assistantPostInput = input.generic({
type: 'assistantPost',
id: '{assistantId}',
model: '%CHAT_MODEL_DEPLOYMENT_NAME%',
- userMessage: '{Query.message}'
+ userMessage: '{Query.message}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('PostUserResponse', {
methods: ['POST'],
@@ -59,7 +63,9 @@ app.http('PostUserResponse', {
const chatBotQueryInput = input.generic({
type: 'assistantQuery',
id: '{assistantId}',
- timestampUtc: '{Query.timestampUTC}'
+ timestampUtc: '{Query.timestampUTC}',
+ chatStorageConnectionSetting: CHAT_STORAGE_CONNECTION_SETTING,
+ collectionName: COLLECTION_NAME
})
app.http('GetChatState', {
methods: ['GET'],
diff --git a/samples/chat/powershell/CreateChatBot/run.ps1 b/samples/chat/powershell/CreateChatBot/run.ps1
index e669a730..6406004d 100644
--- a/samples/chat/powershell/CreateChatBot/run.ps1
+++ b/samples/chat/powershell/CreateChatBot/run.ps1
@@ -8,8 +8,8 @@ Write-Host "Creating chat $chatID from input parameters $($inputJson)"
$createRequest = @{
id = $chatID
- instructions = $inputJson.Instructions,
- chatStorageConnectionSetting = "AzureWebJobsStorage",
+ instructions = $inputJson.Instructions
+ chatStorageConnectionSetting = "AzureWebJobsStorage"
collectionName = "SampleChatState"
}
From 826f5efe7760ac7cd3ecf4c2443ec16ceb150668 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Thu, 26 Sep 2024 15:33:13 +0100
Subject: [PATCH 08/10] resolve Chris' comments
---
.../assistant/AssistantCreateRequest.java | 2 +-
.../annotation/assistant/AssistantPost.java | 2 +-
.../annotation/assistant/AssistantQuery.java | 2 +-
samples/assistant/README.md | 49 +++++++----------
.../assistant/csharp-ooproc/AssistantApis.cs | 12 ++---
.../javascript/src/functions/assistantApis.js | 2 +-
.../powershell/CreateAssistant/run.ps1 | 2 +-
.../powershell/GetChatState/function.json | 2 +-
.../powershell/PostUserQuery/function.json | 2 +-
samples/assistant/python/assistant_apis.py | 2 +-
.../typescript/src/functions/assistantApis.ts | 2 +-
samples/chat/csharp-ooproc/ChatBot.cs | 12 ++---
samples/chat/javascript/src/app.js | 2 +-
samples/chat/powershell/CreateChatBot/run.ps1 | 2 +-
.../powershell/GetChatState/function.json | 2 +-
.../powershell/PostUserResponse/function.json | 2 +-
samples/chat/python/function_app.py | 2 +-
samples/chat/typescript/src/functions/app.ts | 2 +-
.../Assistants/AssistantCreateRequest.cs | 2 +-
.../Assistants/AssistantPostInputAttribute.cs | 2 +-
.../AssistantQueryInputAttribute.cs | 2 +-
.../Assistants/AssistantCreateAttribute.cs | 2 +-
.../Assistants/AssistantPostAttribute.cs | 2 +-
.../Assistants/AssistantQueryAttribute.cs | 2 +-
.../Assistants/AssistantService.cs | 52 ++++++-------------
.../Embeddings/EmbeddingsStoreConverter.cs | 6 ++-
26 files changed, 72 insertions(+), 101 deletions(-)
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantCreateRequest.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantCreateRequest.java
index 7e621f63..f9f0c6ef 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantCreateRequest.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantCreateRequest.java
@@ -14,7 +14,7 @@ public class AssistantCreateRequest {
private String id;
private String instructions = "You are a helpful assistant.";
private String chatStorageConnectionSetting;
- private String collectionName = "SampleChatState";
+ private String collectionName = "ChatState";
public AssistantCreateRequest(String id) {
this.id = id;
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
index 4850bccc..67a3cc3f 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantPost.java
@@ -39,7 +39,7 @@
* account
* where chat data will be stored.
*/
- String DEFAULT_COLLECTION = "SampleChatState";
+ String DEFAULT_COLLECTION = "ChatState";
/**
* The variable name used in function.json.
diff --git a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
index 76cf262a..caf7c2a6 100644
--- a/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
+++ b/java-library/src/main/java/com/microsoft/azure/functions/openai/annotation/assistant/AssistantQuery.java
@@ -40,7 +40,7 @@
* account
* where chat data will be stored.
*/
- String DEFAULT_COLLECTION = "SampleChatState";
+ String DEFAULT_COLLECTION = "ChatState";
/**
* The variable name used in function.json.
diff --git a/samples/assistant/README.md b/samples/assistant/README.md
index eda3965b..b4d0e541 100644
--- a/samples/assistant/README.md
+++ b/samples/assistant/README.md
@@ -26,27 +26,6 @@ This OpenAI extension internally uses the [function calling](https://platform.op
* 0301 is the default and oldest model version for gpt-3.5 but it doesn't support this feature.
* Model version 1106 has known issue with duplicate function calls in the OpenAI extension, check the repo issues for progress as the extension team works on it.
-### Chat Storage Configuration
-
-If you are using a different table storage than `AzureWebJobsStorage` for chat storage, follow these steps:
-
-1. **Managed Identity - Assign Permissions**:
- * Assign the user or function app's managed identity the role of `Storage Table Data Contributor`.
-
-1. **Configure Table Service URI**:
- * Set the `tableServiceUri` in the configuration as follows:
-
- ```json
- "__tableServiceUri": "tableServiceUri"
- ```
-
- * Replace `CONNECTION_NAME_PREFIX` with the appropriate prefix.
-
-1. **Update Function Code**:
- * Supply the `ConnectionNamePrefix` to `ChatStorageConnectionSetting` in the function code. This will replace the default value of `AzureWebJobsStorage`.
-
-For additional details on using identity-based connections, refer to the [Azure Functions reference documentation](https://learn.microsoft.com/azure/azure-functions/functions-reference?#common-properties-for-identity-based-connections).
-
## Defining skills
You can define a skill by creating a function that uses the `AssistantSkillTrigger` binding. The following example shows a skill that adds a todo item to a database:
@@ -205,18 +184,26 @@ Additionally, if you want to run the sample with Cosmos DB, then you must also d
* Install the [Azure Cosmos DB Emulator](https://docs.microsoft.com/azure/cosmos-db/local-emulator), or get a connection string to a real Azure Cosmos DB resource.
* Update the `CosmosDbConnectionString` setting in the `local.settings.json` file and configure it with the connection string to your Cosmos DB resource (local or Azure).
-Also note that the storage of chat history is done via table storage. You may configure the `host.json` file within the project to be as follows:
+### Chat Storage Configuration
-```json
-"extensions": {
- "openai": {
- "storageConnectionName": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
- }
-}
-```
+If you are using a different table storage than `AzureWebJobsStorage` for chat storage, follow these steps:
+
+1. **Managed Identity - Assign Permissions**:
+ * Assign the user or function app's managed identity the role of `Storage Table Data Contributor`.
+
+1. **Configure Table Service URI**:
+ * Set the `tableServiceUri` in the configuration as follows:
-`StorageConnectionName` is the name of connection string of a storage account and `CollectionName` is the name of the table that would hold the chat state and messages.
+ ```json
+ "__tableServiceUri": "tableServiceUri"
+ ```
+
+ * Replace `CONNECTION_NAME_PREFIX` with the appropriate prefix.
+
+1. **Update Function Code**:
+ * Supply the `ConnectionNamePrefix` to `ChatStorageConnectionSetting` in the function code. This will replace the default value of `AzureWebJobsStorage`.
+
+For additional details on using identity-based connections, refer to the [Azure Functions reference documentation](https://learn.microsoft.com/azure/azure-functions/functions-reference?#common-properties-for-identity-based-connections).
## Running the sample
diff --git a/samples/assistant/csharp-ooproc/AssistantApis.cs b/samples/assistant/csharp-ooproc/AssistantApis.cs
index 99b3c500..c1f4c16d 100644
--- a/samples/assistant/csharp-ooproc/AssistantApis.cs
+++ b/samples/assistant/csharp-ooproc/AssistantApis.cs
@@ -13,8 +13,8 @@ namespace AssistantSample;
///
static class AssistantApis
{
- const string CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
- const string COLLECTION_NAME = "SampleChatState";
+ const string DefaultChatStorageConnectionSetting = "AzureWebJobsStorage";
+ const string DefaultCollectionName = "ChatState";
///
/// HTTP PUT function that creates a new assistant chat bot with the specified ID.
@@ -40,8 +40,8 @@ public static async Task CreateAssistant(
HttpResponse = new ObjectResult(new { assistantId }) { StatusCode = 202 },
ChatBotCreateRequest = new AssistantCreateRequest(assistantId, instructions)
{
- ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING,
- CollectionName = COLLECTION_NAME,
+ ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting,
+ CollectionName = DefaultCollectionName,
},
};
}
@@ -62,7 +62,7 @@ public class CreateChatBotOutput
public static async Task PostUserQuery(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "assistants/{assistantId}")] HttpRequestData req,
string assistantId,
- [AssistantPostInput("{assistantId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state)
+ [AssistantPostInput("{assistantId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting, CollectionName = CollectionName)] AssistantState state)
{
return new OkObjectResult(state.RecentMessages.LastOrDefault()?.Content ?? "No response returned.");
}
@@ -74,7 +74,7 @@ public static async Task PostUserQuery(
public static async Task GetChatState(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "assistants/{assistantId}")] HttpRequestData req,
string assistantId,
- [AssistantQueryInput("{assistantId}", TimestampUtc = "{Query.timestampUTC}", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state)
+ [AssistantQueryInput("{assistantId}", TimestampUtc = "{Query.timestampUTC}", ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] AssistantState state)
{
return new OkObjectResult(state);
}
diff --git a/samples/assistant/javascript/src/functions/assistantApis.js b/samples/assistant/javascript/src/functions/assistantApis.js
index b64289e3..a8eaced4 100644
--- a/samples/assistant/javascript/src/functions/assistantApis.js
+++ b/samples/assistant/javascript/src/functions/assistantApis.js
@@ -4,7 +4,7 @@
const { app, input, output } = require("@azure/functions");
const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
-const COLLECTION_NAME = "SampleChatState";
+const COLLECTION_NAME = "ChatState";
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
diff --git a/samples/assistant/powershell/CreateAssistant/run.ps1 b/samples/assistant/powershell/CreateAssistant/run.ps1
index 08fdb14d..c18d0d0c 100644
--- a/samples/assistant/powershell/CreateAssistant/run.ps1
+++ b/samples/assistant/powershell/CreateAssistant/run.ps1
@@ -11,7 +11,7 @@ $create_request = @{
"id" = $assistantId
"instructions" = $instructions
"chatStorageConnectionSetting" = "AzureWebJobsStorage"
- "collectionName" = "SampleChatState"
+ "collectionName" = "ChatState"
}
Push-OutputBinding -Name Requests -Value (ConvertTo-Json $create_request)
diff --git a/samples/assistant/powershell/GetChatState/function.json b/samples/assistant/powershell/GetChatState/function.json
index dc5a00a4..0aae0b70 100644
--- a/samples/assistant/powershell/GetChatState/function.json
+++ b/samples/assistant/powershell/GetChatState/function.json
@@ -23,7 +23,7 @@
"id": "{assistantId}",
"timestampUtc": "{Query.timestampUTC}",
"chatStorageConnectionSetting": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
+ "collectionName": "ChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/assistant/powershell/PostUserQuery/function.json b/samples/assistant/powershell/PostUserQuery/function.json
index 1be27abf..024cd24f 100644
--- a/samples/assistant/powershell/PostUserQuery/function.json
+++ b/samples/assistant/powershell/PostUserQuery/function.json
@@ -24,7 +24,7 @@
"userMessage": "{Query.message}",
"model": "%CHAT_MODEL_DEPLOYMENT_NAME%",
"chatStorageConnectionSetting": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
+ "collectionName": "ChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/assistant/python/assistant_apis.py b/samples/assistant/python/assistant_apis.py
index 86b28335..9202c690 100644
--- a/samples/assistant/python/assistant_apis.py
+++ b/samples/assistant/python/assistant_apis.py
@@ -17,7 +17,7 @@ def create_assistant(req: func.HttpRequest, requests: func.Out[str]) -> func.Htt
"id": assistantId,
"instructions": instructions,
"chatStorageConnectionSection": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
+ "collectionName": "ChatState"
}
requests.set(json.dumps(create_request))
response_json = {"assistantId": assistantId}
diff --git a/samples/assistant/typescript/src/functions/assistantApis.ts b/samples/assistant/typescript/src/functions/assistantApis.ts
index 81f27d4e..35bdd59c 100644
--- a/samples/assistant/typescript/src/functions/assistantApis.ts
+++ b/samples/assistant/typescript/src/functions/assistantApis.ts
@@ -4,7 +4,7 @@
import { HttpRequest, InvocationContext, app, input, output } from "@azure/functions"
const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
-const COLLECTION_NAME = "SampleChatState";
+const COLLECTION_NAME = "ChatState";
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
diff --git a/samples/chat/csharp-ooproc/ChatBot.cs b/samples/chat/csharp-ooproc/ChatBot.cs
index cd0db61d..88dd3975 100644
--- a/samples/chat/csharp-ooproc/ChatBot.cs
+++ b/samples/chat/csharp-ooproc/ChatBot.cs
@@ -12,8 +12,8 @@ namespace ChatBot;
///
public static class ChatBot
{
- const string CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
- const string COLLECTION_NAME = "SampleChatState";
+ const string DefaultChatStorageConnectionSetting = "AzureWebJobsStorage";
+ const string DefaultCollectionName = "ChatState";
public class CreateRequest
{
@@ -47,8 +47,8 @@ public static async Task CreateChatBot(
HttpResponse = new ObjectResult(responseJson) { StatusCode = 201 },
ChatBotCreateRequest = new AssistantCreateRequest(chatId, createRequestBody?.Instructions)
{
- ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING,
- CollectionName = COLLECTION_NAME
+ ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting,
+ CollectionName = DefaultChatStorageConnectionSetting
},
};
}
@@ -66,7 +66,7 @@ public class CreateChatBotOutput
public static async Task PostUserResponse(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "chats/{chatId}")] HttpRequestData req,
string chatId,
- [AssistantPostInput("{chatId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state)
+ [AssistantPostInput("{chatId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] AssistantState state)
{
return new OkObjectResult(state.RecentMessages.LastOrDefault()?.Content ?? "No response returned.");
}
@@ -75,7 +75,7 @@ public static async Task PostUserResponse(
public static async Task GetChatState(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "chats/{chatId}")] HttpRequestData req,
string chatId,
- [AssistantQueryInput("{chatId}", TimestampUtc = "{Query.timestampUTC}", ChatStorageConnectionSetting = CHAT_STORAGE_CONNECTION_SETTING, CollectionName = COLLECTION_NAME)] AssistantState state,
+ [AssistantQueryInput("{chatId}", TimestampUtc = "{Query.timestampUTC}", ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] AssistantState state,
FunctionContext context)
{
return new OkObjectResult(state);
diff --git a/samples/chat/javascript/src/app.js b/samples/chat/javascript/src/app.js
index ae799f71..f0a86ddd 100644
--- a/samples/chat/javascript/src/app.js
+++ b/samples/chat/javascript/src/app.js
@@ -4,7 +4,7 @@
const { app, input, output } = require("@azure/functions");
const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
-const COLLECTION_NAME = "SampleChatState";
+const COLLECTION_NAME = "ChatState";
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
diff --git a/samples/chat/powershell/CreateChatBot/run.ps1 b/samples/chat/powershell/CreateChatBot/run.ps1
index 6406004d..eacd061c 100644
--- a/samples/chat/powershell/CreateChatBot/run.ps1
+++ b/samples/chat/powershell/CreateChatBot/run.ps1
@@ -10,7 +10,7 @@ $createRequest = @{
id = $chatID
instructions = $inputJson.Instructions
chatStorageConnectionSetting = "AzureWebJobsStorage"
- collectionName = "SampleChatState"
+ collectionName = "ChatState"
}
Push-OutputBinding -Name ChatBotCreate -Value $createRequest
diff --git a/samples/chat/powershell/GetChatState/function.json b/samples/chat/powershell/GetChatState/function.json
index 52da792d..d919a1b9 100644
--- a/samples/chat/powershell/GetChatState/function.json
+++ b/samples/chat/powershell/GetChatState/function.json
@@ -22,7 +22,7 @@
"id": "{chatId}",
"timeStampUtc": "{Query.timestampUTC}",
"chatStorageConnectionSetting": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
+ "collectionName": "ChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/chat/powershell/PostUserResponse/function.json b/samples/chat/powershell/PostUserResponse/function.json
index 3a9c871c..16142e20 100644
--- a/samples/chat/powershell/PostUserResponse/function.json
+++ b/samples/chat/powershell/PostUserResponse/function.json
@@ -23,7 +23,7 @@
"model": "%CHAT_MODEL_DEPLOYMENT_NAME%",
"userMessage": "{Query.message}",
"chatStorageConnectionSetting": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
+ "collectionName": "ChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/chat/python/function_app.py b/samples/chat/python/function_app.py
index a366e1b6..eb23ab2a 100644
--- a/samples/chat/python/function_app.py
+++ b/samples/chat/python/function_app.py
@@ -17,7 +17,7 @@ def create_chat_bot(req: func.HttpRequest, requests: func.Out[str]) -> func.Http
"id": chatId,
"instructions": input_json.get("instructions"),
"chatStorageConnectionSection": "AzureWebJobsStorage",
- "collectionName": "SampleChatState"
+ "collectionName": "ChatState"
}
requests.set(json.dumps(create_request))
response_json = {"chatId": chatId}
diff --git a/samples/chat/typescript/src/functions/app.ts b/samples/chat/typescript/src/functions/app.ts
index 62c495aa..84a12075 100644
--- a/samples/chat/typescript/src/functions/app.ts
+++ b/samples/chat/typescript/src/functions/app.ts
@@ -4,7 +4,7 @@
import { HttpRequest, InvocationContext, app, input, output } from "@azure/functions";
const CHAT_STORAGE_CONNECTION_SETTING = "AzureWebJobsStorage";
-const COLLECTION_NAME = "SampleChatState";
+const COLLECTION_NAME = "ChatState";
const chatBotCreateOutput = output.generic({
type: 'assistantCreate'
diff --git a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantCreateRequest.cs b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantCreateRequest.cs
index fdb5991a..243d8bfd 100644
--- a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantCreateRequest.cs
+++ b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantCreateRequest.cs
@@ -47,5 +47,5 @@ public AssistantCreateRequest(string id, string? instructions)
///
/// Table collection name for chat storage.
///
- public string CollectionName { get; set; } = "SampleChatState";
+ public string CollectionName { get; set; } = "ChatState";
}
diff --git a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs
index 8104c8d6..fda594e7 100644
--- a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs
+++ b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantPostInputAttribute.cs
@@ -42,5 +42,5 @@ public AssistantPostInputAttribute(string id, string UserMessage)
///
/// Table collection name for chat storage.
///
- public string CollectionName { get; set; } = "SampleChatState";
+ public string CollectionName { get; set; } = "ChatState";
}
diff --git a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
index b3711431..029baf14 100644
--- a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
+++ b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
@@ -34,5 +34,5 @@ public AssistantQueryInputAttribute(string id)
///
/// Table collection name for chat storage.
///
- public string CollectionName { get; set; } = "SampleChatState";
+ public string CollectionName { get; set; } = "ChatState";
}
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantCreateAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantCreateAttribute.cs
index fdcbffb1..2a9dcc5e 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantCreateAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantCreateAttribute.cs
@@ -68,5 +68,5 @@ public AssistantCreateRequest(string id, string? instructions)
///
/// Table collection name for chat storage.
///
- public string CollectionName { get; set; } = "SampleChatState";
+ public string CollectionName { get; set; } = "ChatState";
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
index db6d3cd6..e024e7be 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
@@ -44,5 +44,5 @@ public AssistantPostAttribute(string id, string userMessage)
///
/// Table collection name for chat storage.
///
- public string CollectionName { get; set; } = "SampleChatState";
+ public string CollectionName { get; set; } = "ChatState";
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
index ede24c9b..466eb97c 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
@@ -35,5 +35,5 @@ public AssistantQueryAttribute(string id)
///
/// Table collection name for chat storage.
///
- public string CollectionName { get; set; } = "SampleChatState";
+ public string CollectionName { get; set; } = "ChatState";
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
index 503b2078..ba50dff4 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
@@ -63,15 +63,7 @@ public async Task CreateAssistantAsync(AssistantCreateRequest request, Cancellat
request.Id,
request.Instructions ?? "(none)");
- if (this.tableClient is null)
- {
- this.CreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
- }
-
- if (this.tableClient is null)
- {
- throw new InvalidOperationException($"{nameof(this.tableClient)} is null.");
- }
+ this.tableClient = this.GetOrCreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
// Create the table if it doesn't exist
await this.tableClient.CreateIfNotExistsAsync();
@@ -154,12 +146,9 @@ public async Task GetStateAsync(AssistantQueryAttribute assistan
id,
afterUtc.ToString("o"));
- if (this.tableClient is null)
- {
- this.CreateTableClient(assistantQuery.ChatStorageConnectionSetting, assistantQuery.CollectionName);
- }
+ this.tableClient = this.GetOrCreateTableClient(assistantQuery.ChatStorageConnectionSetting, assistantQuery.CollectionName);
- InternalChatState? chatState = await this.LoadChatStateAsync(id, cancellationToken);
+ InternalChatState? chatState = await this.LoadChatStateAsync(id, this.tableClient, cancellationToken);
if (chatState is null)
{
this.logger.LogWarning("No assistant exists with ID = '{Id}'", id);
@@ -191,7 +180,7 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
DateTime timeFilter = DateTime.UtcNow;
if (string.IsNullOrEmpty(attribute.Id))
{
- throw new ArgumentException("The assistant Id must be specified.", nameof(attribute));
+ throw new ArgumentException("The assistant ID must be specified.", nameof(attribute));
}
if (string.IsNullOrEmpty(attribute.UserMessage))
@@ -199,19 +188,11 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
throw new ArgumentException("The assistant must have a user message", nameof(attribute));
}
- if (this.tableClient is null)
- {
- this.CreateTableClient(attribute.ChatStorageConnectionSetting, attribute.CollectionName);
- }
-
- if (this.tableClient is null)
- {
- throw new InvalidOperationException($"{nameof(this.tableClient)} is null.");
- }
-
this.logger.LogInformation("Posting message to assistant entity '{Id}'", attribute.Id);
- InternalChatState? chatState = await this.LoadChatStateAsync(attribute.Id, cancellationToken);
+ this.tableClient = this.GetOrCreateTableClient(attribute.ChatStorageConnectionSetting, attribute.CollectionName);
+
+ InternalChatState? chatState = await this.LoadChatStateAsync(attribute.Id, this.tableClient, cancellationToken);
// Check if assistant has been deactivated
if (chatState is null || !chatState.Metadata.Exists)
@@ -405,15 +386,10 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
return state;
}
- async Task LoadChatStateAsync(string id, CancellationToken cancellationToken)
+ async Task LoadChatStateAsync(string id, TableClient tableClient, CancellationToken cancellationToken)
{
- if (this.tableClient is null)
- {
- throw new InvalidOperationException($"{nameof(this.tableClient)} is null.");
- }
-
// Check to see if any entity exists with partition id
- AsyncPageable itemsWithPartitionKey = this.tableClient.QueryAsync(
+ AsyncPageable itemsWithPartitionKey = tableClient.QueryAsync(
filter: $"PartitionKey eq '{id}'",
cancellationToken: cancellationToken);
@@ -471,8 +447,13 @@ static IEnumerable ToOpenAIChatRequestMessages(IEnumerable(connectionStringName);
this.logger.LogInformation("using connection string for table service client");
@@ -510,6 +490,6 @@ void CreateTableClient(string? chatStorageConnectionSetting, string? collectionN
}
this.logger.LogInformation("Using {CollectionName} for table storage collection name", collectionName);
- this.tableClient = this.tableServiceClient.GetTableClient(collectionName);
+ return this.tableServiceClient.GetTableClient(collectionName);
}
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs b/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
index 22fcafb7..f51285d5 100644
--- a/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
+++ b/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
@@ -48,8 +48,12 @@ public Task> ConvertAsync(EmbeddingsStoreAtt
// Called by the host when processing binding requests from out-of-process workers.
internal SearchableDocument ToSearchableDocument(string? json)
{
+ if (json is null)
+ {
+ throw new ArgumentNullException(nameof(json));
+ }
this.logger.LogDebug("Creating searchable document from JSON string: {Text}", json);
- SearchableDocument document = JsonSerializer.Deserialize(json ?? throw new ArgumentNullException(nameof(json)), options)
+ SearchableDocument document = JsonSerializer.Deserialize(json, options)
?? throw new ArgumentException("Invalid search request.");
return document;
}
From e365273580ff06818601c99928a4237e3568bd05 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Fri, 27 Sep 2024 15:46:40 +0100
Subject: [PATCH 09/10] resolve Aishwarya's comments
---
samples/assistant/csharp-ooproc/AssistantApis.cs | 2 +-
samples/chat/csharp-ooproc/ChatBot.cs | 2 +-
.../Assistants/AssistantPostAttribute.cs | 1 +
.../Assistants/AssistantQueryAttribute.cs | 1 +
4 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/samples/assistant/csharp-ooproc/AssistantApis.cs b/samples/assistant/csharp-ooproc/AssistantApis.cs
index c1f4c16d..a55df046 100644
--- a/samples/assistant/csharp-ooproc/AssistantApis.cs
+++ b/samples/assistant/csharp-ooproc/AssistantApis.cs
@@ -62,7 +62,7 @@ public class CreateChatBotOutput
public static async Task PostUserQuery(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "assistants/{assistantId}")] HttpRequestData req,
string assistantId,
- [AssistantPostInput("{assistantId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting, CollectionName = CollectionName)] AssistantState state)
+ [AssistantPostInput("{assistantId}", "{Query.message}", Model = "%CHAT_MODEL_DEPLOYMENT_NAME%", ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] AssistantState state)
{
return new OkObjectResult(state.RecentMessages.LastOrDefault()?.Content ?? "No response returned.");
}
diff --git a/samples/chat/csharp-ooproc/ChatBot.cs b/samples/chat/csharp-ooproc/ChatBot.cs
index 88dd3975..2a94b4b4 100644
--- a/samples/chat/csharp-ooproc/ChatBot.cs
+++ b/samples/chat/csharp-ooproc/ChatBot.cs
@@ -48,7 +48,7 @@ public static async Task CreateChatBot(
ChatBotCreateRequest = new AssistantCreateRequest(chatId, createRequestBody?.Instructions)
{
ChatStorageConnectionSetting = DefaultChatStorageConnectionSetting,
- CollectionName = DefaultChatStorageConnectionSetting
+ CollectionName = DefaultCollectionName
},
};
}
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
index e024e7be..56ed35fa 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
@@ -44,5 +44,6 @@ public AssistantPostAttribute(string id, string userMessage)
///
/// Table collection name for chat storage.
///
+ [AutoResolve]
public string CollectionName { get; set; } = "ChatState";
}
\ No newline at end of file
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
index 466eb97c..9d3a8e31 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
@@ -35,5 +35,6 @@ public AssistantQueryAttribute(string id)
///
/// Table collection name for chat storage.
///
+ [AutoResolve]
public string CollectionName { get; set; } = "ChatState";
}
\ No newline at end of file
From 346568d0821fd477ab1298d8493f47f65891dca0 Mon Sep 17 00:00:00 2001
From: manvkaur <67894494+manvkaur@users.noreply.github.com>
Date: Mon, 30 Sep 2024 12:41:12 +0100
Subject: [PATCH 10/10] resolve Chris's review comments
---
.../Assistants/AssistantService.cs | 24 ++++++++++---------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
index ba50dff4..e31e8a3b 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantService.cs
@@ -63,13 +63,13 @@ public async Task CreateAssistantAsync(AssistantCreateRequest request, Cancellat
request.Id,
request.Instructions ?? "(none)");
- this.tableClient = this.GetOrCreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
+ TableClient tableClient = this.GetOrCreateTableClient(request.ChatStorageConnectionSetting, request.CollectionName);
// Create the table if it doesn't exist
- await this.tableClient.CreateIfNotExistsAsync();
+ await tableClient.CreateIfNotExistsAsync();
// Check to see if the assistant has already been initialized
- AsyncPageable queryResultsFilter = this.tableClient.QueryAsync(
+ AsyncPageable queryResultsFilter = tableClient.QueryAsync(
filter: $"PartitionKey eq '{request.Id}'",
cancellationToken: cancellationToken);
@@ -85,7 +85,7 @@ async Task DeleteBatch()
"Deleting {Count} record(s) for assistant '{Id}'.",
deleteBatch.Count,
request.Id);
- await this.tableClient.SubmitTransactionAsync(deleteBatch);
+ await tableClient.SubmitTransactionAsync(deleteBatch);
deleteBatch.Clear();
}
}
@@ -128,7 +128,7 @@ async Task DeleteBatch()
batch.Add(new TableTransactionAction(TableTransactionActionType.Add, assistantStateEntity));
// Add the batch of table transaction actions to the table
- await this.tableClient.SubmitTransactionAsync(batch);
+ await tableClient.SubmitTransactionAsync(batch);
}
public async Task GetStateAsync(AssistantQueryAttribute assistantQuery, CancellationToken cancellationToken)
@@ -146,9 +146,9 @@ public async Task GetStateAsync(AssistantQueryAttribute assistan
id,
afterUtc.ToString("o"));
- this.tableClient = this.GetOrCreateTableClient(assistantQuery.ChatStorageConnectionSetting, assistantQuery.CollectionName);
+ TableClient tableClient = this.GetOrCreateTableClient(assistantQuery.ChatStorageConnectionSetting, assistantQuery.CollectionName);
- InternalChatState? chatState = await this.LoadChatStateAsync(id, this.tableClient, cancellationToken);
+ InternalChatState? chatState = await this.LoadChatStateAsync(id, tableClient, cancellationToken);
if (chatState is null)
{
this.logger.LogWarning("No assistant exists with ID = '{Id}'", id);
@@ -190,9 +190,9 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
this.logger.LogInformation("Posting message to assistant entity '{Id}'", attribute.Id);
- this.tableClient = this.GetOrCreateTableClient(attribute.ChatStorageConnectionSetting, attribute.CollectionName);
+ TableClient tableClient = this.GetOrCreateTableClient(attribute.ChatStorageConnectionSetting, attribute.CollectionName);
- InternalChatState? chatState = await this.LoadChatStateAsync(attribute.Id, this.tableClient, cancellationToken);
+ InternalChatState? chatState = await this.LoadChatStateAsync(attribute.Id, tableClient, cancellationToken);
// Check if assistant has been deactivated
if (chatState is null || !chatState.Metadata.Exists)
@@ -361,7 +361,7 @@ public async Task PostMessageAsync(AssistantPostAttribute attrib
batch.Add(new TableTransactionAction(TableTransactionActionType.UpdateMerge, chatState.Metadata));
// Add the batch of table transaction actions to the table
- await this.tableClient.SubmitTransactionAsync(batch, cancellationToken);
+ await tableClient.SubmitTransactionAsync(batch, cancellationToken);
// return the latest assistant message in the chat state
List filteredChatMessages = chatState.Messages
@@ -490,6 +490,8 @@ TableClient GetOrCreateTableClient(string? chatStorageConnectionSetting, string?
}
this.logger.LogInformation("Using {CollectionName} for table storage collection name", collectionName);
- return this.tableServiceClient.GetTableClient(collectionName);
+ this.tableClient = this.tableServiceClient.GetTableClient(collectionName);
+
+ return this.tableClient;
}
}
\ No newline at end of file