diff --git a/java-library/pom.xml b/java-library/pom.xml
index 85a1e7a0..400f666e 100644
--- a/java-library/pom.xml
+++ b/java-library/pom.xml
@@ -84,7 +84,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/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 768b127f..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
@@ -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.
@@ -26,18 +25,34 @@
@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 = "ChatState";
+
/**
* 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 +63,27 @@
*/
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. By default, it returns {@code DEFAULT_CHATSTORAGE}.
+ */
+ String chatStorageConnectionSetting() default DEFAULT_CHATSTORAGE;
+
+ /**
+ * 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() 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 cb4831dc..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
@@ -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
@@ -25,13 +26,29 @@
@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 = "ChatState";
+
/**
* The variable name used in function.json.
*
* @return The variable name used in function.json.
*/
String name();
-
+
/**
* The ID of the Assistant to query.
*
@@ -41,10 +58,27 @@
/**
* 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. By default, it returns {@code DEFAULT_CHATSTORAGE}.
+ */
+ String chatStorageConnectionSetting() default DEFAULT_CHATSTORAGE;
+
+ /**
+ * 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() 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/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 60cdd9ac..a55df046 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 DefaultChatStorageConnectionSetting = "AzureWebJobsStorage";
+ const string DefaultCollectionName = "ChatState";
+
///
/// 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 = DefaultChatStorageConnectionSetting,
+ CollectionName = DefaultCollectionName,
},
};
}
@@ -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 = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] 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 = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] AssistantState state)
{
return new OkObjectResult(state);
}
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/samples/assistant/javascript/src/functions/assistantApis.js b/samples/assistant/javascript/src/functions/assistantApis.js
index 469cae21..a8eaced4 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 = "ChatState";
+
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..c18d0d0c 100644
--- a/samples/assistant/powershell/CreateAssistant/run.ps1
+++ b/samples/assistant/powershell/CreateAssistant/run.ps1
@@ -9,9 +9,9 @@ $instructions += "\nAsk for clarification if a user request is ambiguous."
$create_request = @{
"id" = $assistantId
- "instructions" = $instructions,
- "chatStorageConnectionSetting" = "AzureWebJobsStorage",
- "collectionName" = "SampleChatState"
+ "instructions" = $instructions
+ "chatStorageConnectionSetting" = "AzureWebJobsStorage"
+ "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 56e22792..0aae0b70 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": "ChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/assistant/powershell/PostUserQuery/function.json b/samples/assistant/powershell/PostUserQuery/function.json
index c6958834..024cd24f 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": "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 27d2963c..35bdd59c 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 = "ChatState";
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/csharp-ooproc/ChatBot.cs b/samples/chat/csharp-ooproc/ChatBot.cs
index 73025983..2a94b4b4 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 DefaultChatStorageConnectionSetting = "AzureWebJobsStorage";
+ const string DefaultCollectionName = "ChatState";
+
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 = DefaultChatStorageConnectionSetting,
+ CollectionName = DefaultCollectionName
},
};
}
@@ -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 = DefaultChatStorageConnectionSetting, CollectionName = DefaultCollectionName)] 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 = 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 6c82941c..f0a86ddd 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 = "ChatState";
+
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/CreateChatBot/run.ps1 b/samples/chat/powershell/CreateChatBot/run.ps1
index e669a730..eacd061c 100644
--- a/samples/chat/powershell/CreateChatBot/run.ps1
+++ b/samples/chat/powershell/CreateChatBot/run.ps1
@@ -8,9 +8,9 @@ Write-Host "Creating chat $chatID from input parameters $($inputJson)"
$createRequest = @{
id = $chatID
- instructions = $inputJson.Instructions,
- chatStorageConnectionSetting = "AzureWebJobsStorage",
- collectionName = "SampleChatState"
+ instructions = $inputJson.Instructions
+ chatStorageConnectionSetting = "AzureWebJobsStorage"
+ 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 8a51d7da..d919a1b9 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": "ChatState"
}
]
}
\ No newline at end of file
diff --git a/samples/chat/powershell/PostUserResponse/function.json b/samples/chat/powershell/PostUserResponse/function.json
index f560e806..16142e20 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": "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 78fad462..84a12075 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 = "ChatState";
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/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)
};
}
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/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 3753ddb4..fda594e7 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; } = "ChatState";
}
diff --git a/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs b/src/Functions.Worker.Extensions.OpenAI/Assistants/AssistantQueryInputAttribute.cs
index 74128d6e..029baf14 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; } = "ChatState";
}
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 @@
-
+
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/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 6acc8e41..56ed35fa 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantPostAttribute.cs
@@ -35,4 +35,15 @@ 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.
+ ///
+ [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 28c0d3ff..9d3a8e31 100644
--- a/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
+++ b/src/WebJobs.Extensions.OpenAI/Assistants/AssistantQueryAttribute.cs
@@ -26,4 +26,15 @@ 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.
+ ///
+ [AutoResolve]
+ 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 3c783459..e31e8a3b 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,18 +63,13 @@ public async Task CreateAssistantAsync(AssistantCreateRequest request, Cancellat
request.Id,
request.Instructions ?? "(none)");
- this.CreateTableClient(request);
-
- if (this.tableClient is null)
- {
- throw new ArgumentNullException(nameof(this.tableClient));
- }
+ 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);
@@ -90,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();
}
}
@@ -133,18 +128,27 @@ 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(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 '{assistantQuery.TimestampUtc}'");
+ }
+
+ DateTime afterUtc = timestamp.ToUniversalTime();
this.logger.LogInformation(
"Reading state for assistant entity '{Id}' and getting chat messages after {Timestamp}",
id,
afterUtc.ToString("o"));
- InternalChatState? chatState = await this.LoadChatStateAsync(id, cancellationToken);
+ TableClient tableClient = this.GetOrCreateTableClient(assistantQuery.ChatStorageConnectionSetting, assistantQuery.CollectionName);
+
+ InternalChatState? chatState = await this.LoadChatStateAsync(id, tableClient, cancellationToken);
if (chatState is null)
{
this.logger.LogWarning("No assistant exists with ID = '{Id}'", id);
@@ -184,14 +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)
- {
- throw new ArgumentException("The assistant must be initialized first using CreateAssistantAsync", nameof(this.tableClient));
- }
-
this.logger.LogInformation("Posting message to assistant entity '{Id}'", attribute.Id);
- InternalChatState? chatState = await this.LoadChatStateAsync(attribute.Id, cancellationToken);
+ TableClient tableClient = this.GetOrCreateTableClient(attribute.ChatStorageConnectionSetting, attribute.CollectionName);
+
+ InternalChatState? chatState = await this.LoadChatStateAsync(attribute.Id, tableClient, cancellationToken);
// Check if assistant has been deactivated
if (chatState is null || !chatState.Metadata.Exists)
@@ -360,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
@@ -385,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 ArgumentException("The assistant must be initialized first using CreateAssistantAsync", nameof(this.tableClient));
- }
-
// 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);
@@ -451,9 +447,14 @@ static IEnumerable ToOpenAIChatRequestMessages(IEnumerable(connectionStringName);
this.logger.LogInformation("using connection string for table service client");
@@ -489,7 +489,9 @@ 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);
+
+ return this.tableClient;
}
}
\ 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 ee76230a..f51285d5 100644
--- a/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
+++ b/src/WebJobs.Extensions.OpenAI/Embeddings/EmbeddingsStoreConverter.cs
@@ -48,9 +48,14 @@ 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, options);
- return document ?? throw new ArgumentException("Invalid search request.");
+ SearchableDocument document = JsonSerializer.Deserialize(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)
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 @@
-
-
+
+
-
+
-
+