Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion sdk/ai/ai-projects/review/ai-projects-node.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -1867,6 +1867,20 @@ export interface MemoryStoresUpdateMemoryStoreOptionalParams extends OperationOp
metadata?: Record<string, string>;
}

// @public (undocumented)
export type MemoryStoreUpdateOperationState = OperationState_2<MemoryStoreUpdateResult> & {
Copy link
Member

Choose a reason for hiding this comment

The 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)

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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)

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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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)

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;
};
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new public API types MemoryStoreUpdateOperationState and MemoryStoreUpdatePoller are marked as (undocumented) in the API extractor output. According to Azure SDK guidelines, all public APIs must be documented. These types need JSDoc comments in the source code (memoryStoreUpdatePoller.ts) to appear properly documented in the API surface.

Copilot uses AI. Check for mistakes.

// @public
export interface MemoryStoreUpdateResponse {
error?: ApiError;
Expand Down
3 changes: 2 additions & 1 deletion sdk/ai/ai-projects/sample.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
AZURE_AI_PROJECT_ENDPOINT="<project connection string from Microsoft Foundry>"
AZURE_AI_CHAT_MODEL_DEPLOYMENT_NAME="<memory chat model deployment name>"
AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME="<memory embedding model deployment name>"
MODEL_DEPLOYMENT_NAME="<model deployment name>"
MODEL_API_KEY="<model api key>"
MODEL_ENDPOINT="<model endpoint url>"
Expand All @@ -22,4 +24,3 @@ IMAGE_GENERATION_MODEL_DEPLOYMENT_NAME="<image generation model deployment name>

MCP_PROJECT_CONNECTION_ID="<mcp project connection id>"
TRIPADVISOR_PROJECT_CONNECTION_ID="<tripadvisor project connection id>"

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as readline from "readline";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const a2aProjectConnectionId =
process.env["A2A_PROJECT_CONNECTION_ID"] || "<a2a project connection id>";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as readline from "readline";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const aiSearchConnectionId =
process.env["AZURE_AI_SEARCH_CONNECTION_ID"] || "<ai search project connection id>";
const aiSearchIndexName = process.env["AI_SEARCH_INDEX_NAME"] || "<ai search index name>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as readline from "readline";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const bingCustomSearchProjectConnectionId =
process.env["BING_CUSTOM_SEARCH_PROJECT_CONNECTION_ID"] ||
"<bing custom search project connection id>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { AIProjectClient } from "@azure/ai-projects";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const bingProjectConnectionId =
process.env["BING_PROJECT_CONNECTION_ID"] || "<bing project connection id>";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { AIProjectClient } from "@azure/ai-projects";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const browserAutomationProjectConnectionId =
process.env["BROWSER_AUTOMATION_PROJECT_CONNECTION_ID"] ||
"<browser automation project connection id>";
Expand Down
174 changes: 174 additions & 0 deletions sdk/ai/ai-projects/samples-dev/agents/tools/agentMemorySearch.ts
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["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);
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import * as path from "path";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const weatherSpecPath = path.resolve(__dirname, "../assets", "weather_openapi.json");

function loadOpenApiSpec(specPath: string): unknown {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import * as path from "path";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const tripAdvisorProjectConnectionId =
process.env["TRIPADVISOR_PROJECT_CONNECTION_ID"] || "<tripadvisor project connection id>";
const tripAdvisorSpecPath = path.resolve(__dirname, "../assets", "tripadvisor_openapi.json");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { AIProjectClient } from "@azure/ai-projects";
import "dotenv/config";

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const sharepointProjectConnectionId =
process.env["SHAREPOINT_PROJECT_CONNECTION_ID"] || "<sharepoint project connection id>";

Expand Down
4 changes: 3 additions & 1 deletion sdk/ai/ai-projects/samples/v2-beta/javascript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ These sample programs show how to use the JavaScript client libraries for Azure
| [agents/tools/agentImageGeneration.js][agents_tools_agentimagegeneration] | This sample demonstrates how to create an agent with ImageGenTool configured for image generation, make requests to generate images from text prompts, extract base64-encoded image data from the response, decode and save the generated image to a local file, and clean up created resources. |
| [agents/tools/agentMcp.js][agents_tools_agentmcp] | This sample demonstrates how to create an agent with MCP tool capabilities, send requests that trigger MCP approval workflows, handle approval requests, and clean up resources. |
| [agents/tools/agentMcpConnectionAuth.js][agents_tools_agentmcpconnectionauth] | This sample demonstrates how to create an agent with MCP tool capabilities using project connection authentication, send requests that trigger MCP approval workflows, handle approval requests, and clean up resources. |
| [agents/tools/agentMemorySearch.js][agents_tools_agentmemorysearch] | Create an agent with Memory Search, capture memories from a conversation, and retrieve them in a new conversation. |
| [agents/tools/agentOpenApi.js][agents_tools_agentopenapi] | This sample demonstrates how to create an agent with OpenAPI tool capabilities, load OpenAPI specifications from local assets, and process streaming responses that may include tool outputs. |
| [agents/tools/agentOpenApiConnectionAuth.js][agents_tools_agentopenapiconnectionauth] | Demonstrates how to create an OpenAPI-enabled agent that uses a project connection for authentication and stream responses that include tool invocation details. |
| [agents/tools/agentOpenApiConnectionAuth.js][agents_tools_agentopenapiconnectionauth] | Demonstrates how to create an OpenAPI-enabled agent that uses a project connection for authentication and stream responses that include tool invocation details. |
| [agents/tools/agentSharepoint.js][agents_tools_agentsharepoint] | This sample demonstrates how to create an agent with SharePoint tool capabilities, search SharePoint content, and process streaming responses with citations. |
| [agents/tools/agentWebSearch.js][agents_tools_agentwebsearch] | This sample demonstrates how to create an agent with web search capabilities, send a query to search the web, and clean up resources. |
| [responses/responseBasic.js][responses_responsebasic] | This sample demonstrates how to create responses with and without conversation context. |
Expand Down Expand Up @@ -98,6 +99,7 @@ Take a look at our [API Documentation][apiref] for more information about the AP
[agents_tools_agentimagegeneration]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentImageGeneration.js
[agents_tools_agentmcp]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentMcp.js
[agents_tools_agentmcpconnectionauth]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentMcpConnectionAuth.js
[agents_tools_agentmemorysearch]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentMemorySearch.js
[agents_tools_agentopenapi]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentOpenApi.js
[agents_tools_agentopenapiconnectionauth]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentOpenApiConnectionAuth.js
[agents_tools_agentsharepoint]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentSharepoint.js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const readline = require("readline");
require("dotenv/config");

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const a2aProjectConnectionId =
process.env["A2A_PROJECT_CONNECTION_ID"] || "<a2a project connection id>";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const readline = require("readline");
require("dotenv/config");

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const aiSearchConnectionId =
process.env["AZURE_AI_SEARCH_CONNECTION_ID"] || "<ai search project connection id>";
const aiSearchIndexName = process.env["AI_SEARCH_INDEX_NAME"] || "<ai search index name>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const readline = require("readline");
require("dotenv/config");

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const bingCustomSearchProjectConnectionId =
process.env["BING_CUSTOM_SEARCH_PROJECT_CONNECTION_ID"] ||
"<bing custom search project connection id>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/**
* This sample demonstrates how to create an AI agent with Bing grounding capabilities
* using the `bing_grounding` tool type and synchronous Azure AI Projects client. The agent can search
* using the "bing_grounding" tool type and synchronous Azure AI Projects client. The agent can search
* the web for current information and provide grounded responses with URL citations.
*
* @summary This sample demonstrates how to create an agent with Bing grounding tool capabilities,
Expand All @@ -15,7 +15,7 @@ const { AIProjectClient } = require("@azure/ai-projects");
require("dotenv/config");

const projectEndpoint = process.env["AZURE_AI_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["AZURE_AI_MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const deploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "<model deployment name>";
const bingProjectConnectionId =
process.env["BING_PROJECT_CONNECTION_ID"] || "<bing project connection id>";

Expand Down
Loading
Loading