Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* This sample demonstrates how to create an agent that uses a toolbox with a guardrail (RAI policy).
* The toolbox is configured with a web_search tool and an RAI policy that filters responses.
*
* @summary Create an agent with a toolbox that has a guardrail (RAI policy) applied.
*
* @azsdk-weight 100
*/

import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient, type MCPTool } from "@azure/ai-projects";
import "dotenv/config";

const projectEndpoint = process.env["FOUNDRY_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["FOUNDRY_MODEL_NAME"] || "<model deployment name>";
const raiPolicyName =
process.env["RAI_POLICY_NAME"] ||
"/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<account-name>/raiPolicies/<policy-name>";

export async function main(): Promise<void> {
const credential = new DefaultAzureCredential();
const project = new AIProjectClient(projectEndpoint, credential);
const openAIClient = project.getOpenAIClient();

console.log("Creating toolbox with guardrail (RAI policy)...");
const toolboxVersion = await project.beta.toolboxes.createVersion(
"my-toolbox",
[{ type: "web_search" }],
{
description: "Toolbox with guardrail",
policies: {
rai_config: {
rai_policy_name: raiPolicyName,
},
},
},
);
console.log(`Toolbox version created: ${toolboxVersion.version}`);

console.log("\nCreating agent with deferred MCP tool and tool_search...");
const token = (await credential.getToken("https://ai.azure.com/.default")).token;
const toolboxMcpUrl = `${projectEndpoint}/toolboxes/my-toolbox/versions/${toolboxVersion.version}/mcp?api-version=v1`;

const agent = await project.agents.createVersion("MyGuardrailAgent", {
kind: "prompt",
model: deploymentName,
instructions: "You are a helpful assistant. Use web search when needed to answer questions.",
tools: [
{
type: "mcp",
server_label: "my-toolbox",
server_url: toolboxMcpUrl,
authorization: token,
headers: { "Foundry-Features": "Toolboxes=V1Preview" },
require_approval: "never",
} as MCPTool,
],
});
console.log(`Agent created (id: ${agent.id}, name: ${agent.name}, version: ${agent.version})`);

console.log("\nSending request to the agent...");
try {
const response = await openAIClient.responses.create(
{
input: "What are the latest developments in responsible AI?",
},
{
body: {
agent_reference: { name: agent.name, type: "agent_reference" },
},
},
);
console.log(`\nResponse output: ${response.output_text}`);
} catch (e: any) {
if (e.status === 400 && e.message?.includes("blocked by policy: RAI")) {
console.log("\nThe RAI guardrail blocked the tool call as expected.");
console.log(`Details: ${e.message}`);
} else {
throw e;
}
}

console.log("\nCleaning up resources...");
await project.agents.deleteVersion(agent.name, agent.version);
await project.beta.toolboxes.deleteVersion("my-toolbox", toolboxVersion.version);
console.log("Agent and toolbox deleted");
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});
155 changes: 155 additions & 0 deletions sdk/ai/ai-projects/samples-dev/skills/skillWithToolbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* This sample demonstrates how to expose a Skill to a Prompt Agent via a
* Toolbox, using the AIProjectClient and the OpenAI-compatible client.
*
* It creates a Skill with inline content describing how to compute shipping
* cost, then creates a Toolbox version that references the skill. A Prompt
* Agent is created with an `MCPTool` pointed at the toolbox's versioned
* `/mcp` endpoint. The skill's instructions are injected into the agent's
* context, so when asked a shipping-cost question the agent answers directly
* using the skill's formula.
*
* Skills and Toolboxes are currently preview features. In the JS SDK, you
* access these operations via `project.beta.skills` and
* `project.beta.toolboxes`.
*
* @summary Demonstrates adding a skill to a toolbox and invoking it via a Prompt Agent.
*
* @azsdk-weight 100
*/

import type { MCPTool, ToolboxSkillReference } from "@azure/ai-projects";
import { AIProjectClient, RestError } from "@azure/ai-projects";
import { DefaultAzureCredential } from "@azure/identity";
import "dotenv/config";

const projectEndpoint = process.env["FOUNDRY_PROJECT_ENDPOINT"] || "<project endpoint>";
const deploymentName = process.env["FOUNDRY_MODEL_NAME"] || "<model deployment name>";

const SKILL_NAME = "shipping-cost-skill";
const TOOLBOX_NAME = "toolbox_with_skill";
const AGENT_NAME = "SkillToolboxAgent";

export async function main(): Promise<void> {
const credential = new DefaultAzureCredential();
const project = new AIProjectClient(projectEndpoint, credential);
const openAIClient = project.getOpenAIClient();

// --- Clean up any prior runs ---
try {
await project.beta.toolboxes.delete(TOOLBOX_NAME);
} catch (e) {
if (!(e instanceof RestError && e.statusCode === 404)) throw e;
}
try {
await project.beta.skills.delete(SKILL_NAME);
} catch (e) {
if (!(e instanceof RestError && e.statusCode === 404)) throw e;
}

// --- 1. Create a skill ---
const skill = await project.beta.skills.create(SKILL_NAME, {
inlineContent: {
description: "Compute shipping cost for a package given weight and destination.",
instructions:
"You are a shipping cost calculator. When asked to compute " +
"shipping cost, use this formula: cost (USD) = 5 + 2 * weight_kg " +
"for domestic destinations, and cost (USD) = 15 + 4 * weight_kg " +
"for international destinations. Always state the formula you used.",
metadata: { revision: "1" },
},
});
console.log(`Created skill: ${skill.name} version=${skill.version}`);

// --- 2. Create a toolbox version with toolbox_search_preview and the skill ---
const skillRef: ToolboxSkillReference = {
type: "skill_reference",
name: skill.name,
version: skill.version,
};

const toolboxVersion = await project.beta.toolboxes.createVersion(
TOOLBOX_NAME,
[{ type: "toolbox_search_preview" }],
{
description: "Toolbox exposing a shipping-cost skill.",
skills: [skillRef],
},
);
console.log(`Created toolbox: ${toolboxVersion.name} version=${toolboxVersion.version}`);

// --- 3. Build the MCP tool reference to the toolbox endpoint ---
const toolboxMcpUrl = `${projectEndpoint}/toolboxes/${TOOLBOX_NAME}/versions/${toolboxVersion.version}/mcp?api-version=v1`;
const token = (await credential.getToken("https://ai.azure.com/.default"))!.token;

const toolboxMcpTool: MCPTool = {
type: "mcp",
server_label: "skill-toolbox",
server_url: toolboxMcpUrl,
authorization: token,
headers: { "Foundry-Features": "Toolboxes=V1Preview" },
require_approval: "never",
};

// --- 4. Create a prompt agent with the toolbox MCP tool ---
const agent = await project.agents.createVersion(AGENT_NAME, {
kind: "prompt",
model: deploymentName,
instructions:
"Answer the user using the `shipping-cost-skill` instructions " +
"available in your context. Do not call `tool_search`; the " +
"skill rules are already part of your knowledge. Apply the " +
"skill's formula exactly as given and state the formula in " +
"your answer.",
temperature: 0,
tools: [toolboxMcpTool],
});
console.log(`Agent created (id=${agent.id}, name=${agent.name}, version=${agent.version})`);

// --- 5. Send a query ---
const userInput = "Compute the shipping cost for a 3 kg package shipped domestically.";
console.log(`User: ${userInput}`);

const response = await openAIClient.responses.create(
{ input: userInput },
{
body: {
agent_reference: { name: agent.name, type: "agent_reference" },
},
},
);

for (const item of response.output) {
if (item.type === "mcp_list_tools") {
console.log(
`mcp_list_tools server_label=${item.server_label} tools=${(item.tools || []).map((t: any) => t.name)}`,
);
} else if (item.type === "mcp_call") {
console.log(
`mcp_call server_label=${item.server_label} name=${item.name} error=${item.error}`,
);
if ("output" in item && item.output) {
console.log(` output: ${item.output}`);
}
} else if (item.type === "mcp_approval_request") {
console.log(`mcp_approval_request server_label=${item.server_label} name=${item.name}`);
} else {
console.log(`output item type=${item.type}`);
}
}

console.log(`Response: ${response.output_text}`);

// --- 6. Clean up ---
await project.beta.toolboxes.delete(TOOLBOX_NAME);
console.log("Toolbox deleted");
await project.beta.skills.delete(SKILL_NAME);
console.log("Skill deleted");
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Loading