-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[Projects] v2 update LRO poller for memory ops #36703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
83c256b
a224866
e781cd4
400df57
cae1fc3
d1b2cc5
53e4c06
722799d
30b7cf6
fc9a6ba
daca2d2
2a6b473
feaf248
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1841,7 +1841,7 @@ export interface MemoryStoresOperations { | |
| list: (options?: MemoryStoresListMemoryStoresOptionalParams) => PagedAsyncIterableIterator<MemoryStore>; | ||
| searchMemories: (name: string, scope: string, options?: MemoryStoresSearchMemoriesOptionalParams) => Promise<MemoryStoreSearchResponse>; | ||
| update: (name: string, options?: MemoryStoresUpdateMemoryStoreOptionalParams) => Promise<MemoryStore>; | ||
| updateMemories: (name: string, scope: string, options?: MemoryStoresUpdateMemoriesOptionalParams) => PollerLike<OperationState_2<MemoryStoreUpdateResult>, MemoryStoreUpdateResult>; | ||
| updateMemories: (name: string, scope: string, options?: MemoryStoresUpdateMemoriesOptionalParams) => MemoryStoreUpdatePoller; | ||
| } | ||
|
|
||
| // @public | ||
|
|
@@ -1867,6 +1867,20 @@ export interface MemoryStoresUpdateMemoryStoreOptionalParams extends OperationOp | |
| metadata?: Record<string, string>; | ||
| } | ||
|
|
||
| // @public (undocumented) | ||
| export type MemoryStoreUpdateOperationState = OperationState_2<MemoryStoreUpdateResult> & { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we override existing status property instead of defining a new updateStatus? (Surprised by OperationState_2 name)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updateId and status are both required, if that is consistent with OperationState_2 design.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The reason for the OperationState name collision is that another "OperationState" is apparently being emitted from our TypeSpec, and that local OperationState roughly corresponds to the OperationStatus enum in core-lro/poller.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Are the responses from the service constrained to the OperationStatus strings? I'm seeing "queued" and "superseded" as possible return statuses, but those don't exist in the OperationStatus enums here |
||
| updateId?: string; | ||
| updateStatus?: MemoryStoreUpdateStatus; | ||
| supersededBy?: string; | ||
| }; | ||
|
|
||
| // @public (undocumented) | ||
| export type MemoryStoreUpdatePoller = PollerLike<MemoryStoreUpdateOperationState, MemoryStoreUpdateResult> & { | ||
| readonly updateId?: string; | ||
| readonly updateStatus?: MemoryStoreUpdateStatus; | ||
| readonly supersededBy?: string; | ||
| }; | ||
|
||
|
|
||
| // @public | ||
| export interface MemoryStoreUpdateResponse { | ||
| error?: ApiError; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| /** | ||
| * This sample demonstrates how to add conversational memory to an agent by using the | ||
| * Memory Search tool. The agent stores memories in a memory store and can recall them | ||
| * in later conversations. | ||
| * | ||
| * @summary Create an agent with Memory Search, capture memories from a conversation, | ||
| * and retrieve them in a new conversation. | ||
| * | ||
| * @azsdk-weight 100 | ||
| */ | ||
|
|
||
| import { DefaultAzureCredential } from "@azure/identity"; | ||
| import { | ||
| AIProjectClient, | ||
| MemoryStoreDefaultDefinition, | ||
| MemoryStoreDefaultOptions, | ||
| MemorySearchTool, | ||
| } from "@azure/ai-projects"; | ||
| import "dotenv/config"; | ||
|
|
||
| const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>"; | ||
| const agentModelDeployment = | ||
| process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<agent model deployment name>"; | ||
| const chatModelDeployment = | ||
| process.env["AZURE_AI_CHAT_MODEL_DEPLOYMENT_NAME"] || "<memory chat model deployment name>"; | ||
| const embeddingModelDeployment = | ||
| process.env["AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME"] || | ||
| "<memory embedding model deployment name>"; | ||
|
|
||
| const memoryStoreName = "my_memory_store_123"; | ||
| const scope = "user_123"; | ||
|
|
||
| function delay(ms: number): Promise<void> { | ||
| return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| } | ||
|
|
||
| export async function main(): Promise<void> { | ||
| const project = new AIProjectClient(projectEndpoint, new DefaultAzureCredential()); | ||
| const openAIClient = await project.getOpenAIClient(); | ||
|
|
||
| let conversationId: string | undefined; | ||
| let followUpConversationId: string | undefined; | ||
| let agentVersion: | ||
| | { | ||
| name: string; | ||
| version: string; | ||
| } | ||
| | undefined; | ||
|
|
||
| try { | ||
| // Clean up an existing memory store if it already exists | ||
| try { | ||
| await project.memoryStores.delete(memoryStoreName); | ||
| console.log(`Memory store '${memoryStoreName}' deleted`); | ||
| } catch (error: any) { | ||
| if (error?.statusCode !== 404) { | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| // Create a memory store with chat and embedding models | ||
| const memoryStore = await project.memoryStores.create( | ||
| memoryStoreName, | ||
| { | ||
| kind: "default", | ||
| chat_model: chatModelDeployment, | ||
| embedding_model: embeddingModelDeployment, | ||
| options: { | ||
| user_profile_enabled: true, | ||
| chat_summary_enabled: true, | ||
| } satisfies MemoryStoreDefaultOptions, | ||
| } satisfies MemoryStoreDefaultDefinition, | ||
| { | ||
| description: "Memory store for agent conversations", | ||
| }, | ||
| ); | ||
| const chatModelUsed = | ||
| "chat_model" in memoryStore.definition | ||
| ? memoryStore.definition.chat_model | ||
| : chatModelDeployment; | ||
| console.log( | ||
| `Created memory store: ${memoryStore.name} (${memoryStore.id}) using chat model '${chatModelUsed}'`, | ||
| ); | ||
|
|
||
| // Configure Memory Search tool to attach to the agent | ||
| const memorySearchTool: MemorySearchTool = { | ||
| type: "memory_search", | ||
| memory_store_name: memoryStore.name, | ||
| scope, | ||
| update_delay: 5, // wait briefly after conversation inactivity before updating memories | ||
| }; | ||
|
|
||
| // Create an agent that will use the Memory Search tool | ||
| const agent = await project.agents.createVersion("MemorySearchAgent", { | ||
| kind: "prompt", | ||
| model: agentModelDeployment, | ||
| instructions: | ||
| "You are a helpful assistant that remembers user preferences using the memory search tool.", | ||
| tools: [memorySearchTool], | ||
| }); | ||
| agentVersion = { | ||
| name: agent.name, | ||
| version: agent.version, | ||
| }; | ||
| console.log(`Agent created (id: ${agent.id}, name: ${agent.name}, version: ${agent.version})`); | ||
|
|
||
| // Start a conversation and provide details the agent should remember | ||
| const conversation = await openAIClient.conversations.create(); | ||
| conversationId = conversation.id; | ||
| console.log(`Conversation started (${conversation.id}). Sending a message to seed memories...`); | ||
|
|
||
| const firstResponse = await openAIClient.responses.create( | ||
| { | ||
| input: "I prefer dark roast coffee and usually drink it in the morning.", | ||
| conversation: conversation.id, | ||
| }, | ||
| { | ||
| body: { agent: { name: agent.name, type: "agent_reference" } }, | ||
| }, | ||
| ); | ||
| console.log(`Initial response: ${firstResponse.output_text}`); | ||
|
|
||
| // Allow time for the memory store to update from this conversation | ||
| console.log("Waiting for the memory store to capture the new memory..."); | ||
| await delay(10000); | ||
|
|
||
| // Create a follow-up conversation and ask the agent to recall the stored memory | ||
| const followUpConversation = await openAIClient.conversations.create(); | ||
| followUpConversationId = followUpConversation.id; | ||
| console.log(`Follow-up conversation started (${followUpConversation.id}).`); | ||
|
|
||
| const followUpResponse = await openAIClient.responses.create( | ||
| { | ||
| input: "Can you remind me of my usual coffee order?", | ||
| conversation: followUpConversation.id, | ||
| }, | ||
| { | ||
| body: { agent: { name: agent.name, type: "agent_reference" } }, | ||
| }, | ||
| ); | ||
| console.log(`Follow-up response: ${followUpResponse.output_text}`); | ||
| } finally { | ||
| console.log("\nCleaning up resources..."); | ||
| if (conversationId) { | ||
| await openAIClient.conversations.delete(conversationId); | ||
| console.log(`Conversation ${conversationId} deleted`); | ||
| } | ||
| if (followUpConversationId) { | ||
| await openAIClient.conversations.delete(followUpConversationId); | ||
| console.log(`Conversation ${followUpConversationId} deleted`); | ||
| } | ||
| if (agentVersion) { | ||
| await project.agents.deleteVersion(agentVersion.name, agentVersion.version); | ||
| console.log("Agent deleted"); | ||
| } | ||
| try { | ||
| await project.memoryStores.delete(memoryStoreName); | ||
| console.log("Memory store deleted"); | ||
| } catch (error: any) { | ||
| if (error?.statusCode !== 404) { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| console.log("\nMemory Search agent sample completed!"); | ||
| } | ||
|
|
||
| main().catch((err) => { | ||
| console.error("The sample encountered an error:", err); | ||
| }); |
Uh oh!
There was an error while loading. Please reload this page.