From ca202db99a52772507cc422ddf8e96cd2ef70f88 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:03:13 +0000 Subject: [PATCH 01/11] Initial plan From cf6b200978cf33a08610d53fbb170c41f31acc7e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:08:35 +0000 Subject: [PATCH 02/11] Add GitHub Copilot skill for Foundry Agent with examples Co-authored-by: adyada <118839465+adyada@users.noreply.github.com> --- .github/skills/foundry-agent/SKILL.md | 222 ++++++++++++++++++++++++++ .gitignore | 40 +++++ README.md | 77 ++++++++- examples/README.md | 97 +++++++++++ examples/package.json | 27 ++++ examples/python_example.py | 157 ++++++++++++++++++ examples/requirements.txt | 1 + examples/typescript_example.ts | 180 +++++++++++++++++++++ 8 files changed, 800 insertions(+), 1 deletion(-) create mode 100644 .github/skills/foundry-agent/SKILL.md create mode 100644 .gitignore create mode 100644 examples/README.md create mode 100644 examples/package.json create mode 100644 examples/python_example.py create mode 100644 examples/requirements.txt create mode 100644 examples/typescript_example.ts diff --git a/.github/skills/foundry-agent/SKILL.md b/.github/skills/foundry-agent/SKILL.md new file mode 100644 index 0000000..276733e --- /dev/null +++ b/.github/skills/foundry-agent/SKILL.md @@ -0,0 +1,222 @@ +--- +name: foundry-agent +description: > + Enables GitHub Copilot to send user prompts to a Microsoft Foundry Agent for advanced Q&A, + complex reasoning, or data processing tasks that require specialized AI capabilities. +--- + +# Foundry Agent Skill + +This skill allows GitHub Copilot to interact with a Microsoft Foundry Agent application for tasks that require: +- Complex reasoning and analysis +- Advanced natural language understanding +- Specialized domain knowledge +- Integration with external data sources +- Custom AI workflows and processing + +## When to Use + +Use this skill when: +- The user's request requires advanced AI capabilities beyond standard Copilot functionality +- Complex data analysis or processing is needed +- Integration with Microsoft Foundry's specialized models is beneficial +- The task involves multi-step reasoning or orchestration + +## Usage Instructions + +When Copilot detects that a user's intent matches this skill's capabilities, it will: +1. Extract the user's prompt or question +2. Send a request to the Foundry Agent endpoint +3. Process the response from the agent +4. Return the result to the user in the Copilot chat + +## Implementation Examples + +### Python Example + +```python +import requests +import os + +def ask_foundry_agent(prompt: str) -> dict: + """ + Send a prompt to the Microsoft Foundry Agent endpoint. + + Args: + prompt: The user's question or request + + Returns: + The agent's response as a dictionary + """ + # Get the Foundry Agent endpoint from environment variables + endpoint = os.getenv("FOUNDRY_AGENT_ENDPOINT", "https:///chat") + api_key = os.getenv("FOUNDRY_AGENT_API_KEY") + + headers = { + "Content-Type": "application/json", + } + + if api_key: + headers["Authorization"] = f"Bearer {api_key}" + + payload = { + "message": prompt, + "conversation_id": None # Optional: for maintaining conversation context + } + + try: + response = requests.post(endpoint, json=payload, headers=headers, timeout=30) + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + return {"error": f"Failed to call Foundry Agent: {str(e)}"} + +# Example usage +if __name__ == "__main__": + user_prompt = "Analyze the latest sales data trends" + result = ask_foundry_agent(user_prompt) + print(result) +``` + +### TypeScript/JavaScript Example + +```typescript +import axios from 'axios'; + +interface FoundryAgentRequest { + message: string; + conversation_id?: string; +} + +interface FoundryAgentResponse { + response: string; + conversation_id?: string; + metadata?: any; +} + +async function askFoundryAgent(prompt: string): Promise { + // Get the Foundry Agent endpoint from environment variables + const endpoint = process.env.FOUNDRY_AGENT_ENDPOINT || 'https:///chat'; + const apiKey = process.env.FOUNDRY_AGENT_API_KEY; + + const headers: Record = { + 'Content-Type': 'application/json', + }; + + if (apiKey) { + headers['Authorization'] = `Bearer ${apiKey}`; + } + + const payload: FoundryAgentRequest = { + message: prompt, + conversation_id: undefined, // Optional: for maintaining conversation context + }; + + try { + const response = await axios.post( + endpoint, + payload, + { headers, timeout: 30000 } + ); + return response.data; + } catch (error: any) { + return { error: `Failed to call Foundry Agent: ${error.message}` }; + } +} + +// Example usage +(async () => { + const userPrompt = 'Analyze the latest sales data trends'; + const result = await askFoundryAgent(userPrompt); + console.log(result); +})(); +``` + +### C#/.NET Example + +```csharp +using System; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +public class FoundryAgentClient +{ + private readonly HttpClient _httpClient; + private readonly string _endpoint; + private readonly string _apiKey; + + public FoundryAgentClient() + { + _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; + _endpoint = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_ENDPOINT") + ?? "https:///chat"; + _apiKey = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_API_KEY"); + } + + public async Task AskFoundryAgentAsync(string prompt) + { + var payload = new + { + message = prompt, + conversation_id = (string)null + }; + + var content = new StringContent( + JsonSerializer.Serialize(payload), + Encoding.UTF8, + "application/json" + ); + + if (!string.IsNullOrEmpty(_apiKey)) + { + _httpClient.DefaultRequestHeaders.Authorization = + new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiKey); + } + + try + { + var response = await _httpClient.PostAsync(_endpoint, content); + response.EnsureSuccessStatusCode(); + + var responseBody = await response.Content.ReadAsStringAsync(); + return JsonDocument.Parse(responseBody); + } + catch (Exception ex) + { + var errorJson = JsonSerializer.Serialize(new { error = $"Failed to call Foundry Agent: {ex.Message}" }); + return JsonDocument.Parse(errorJson); + } + } + + // Example usage + public static async Task Main(string[] args) + { + var client = new FoundryAgentClient(); + var result = await client.AskFoundryAgentAsync("Analyze the latest sales data trends"); + Console.WriteLine(result.RootElement.ToString()); + } +} +``` + +## Configuration + +To use this skill, you need to configure the following environment variables: + +- `FOUNDRY_AGENT_ENDPOINT`: The URL of your Microsoft Foundry Agent endpoint +- `FOUNDRY_AGENT_API_KEY`: (Optional) The API key for authentication + +## Testing + +You can test the Foundry Agent integration by: + +1. Setting up the environment variables with your Foundry Agent endpoint +2. Running any of the example scripts above +3. Verifying that the agent responds correctly to your prompts + +## Additional Resources + +- [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) +- [GitHub Copilot Agent Skills Documentation](https://code.visualstudio.com/docs/copilot/customization/agent-skills) +- [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24a33ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +.venv +pip-log.txt +pip-delete-this-directory.txt +.pytest_cache/ +*.egg-info/ +dist/ +build/ + +# Node +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +yarn.lock +*.tsbuildinfo + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Environment variables +.env +.env.local diff --git a/README.md b/README.md index 5a7236f..da6bb9c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,77 @@ # foundry-github-copilot-skill -Foundry Github copilot skill + +This repository contains a GitHub Copilot Agent Skill example that demonstrates how to call a Microsoft Foundry Agent application from within GitHub Copilot. + +## Overview + +The Foundry Agent Skill enables GitHub Copilot to interact with Microsoft Foundry Agent applications for advanced AI capabilities, including: + +- Complex reasoning and analysis +- Advanced natural language understanding +- Specialized domain knowledge integration +- Custom AI workflows and processing +- Multi-step task orchestration + +## Skill Structure + +The skill is defined in `.github/skills/foundry-agent/SKILL.md` following the GitHub Copilot Agent Skills specification. + +## Getting Started + +### Prerequisites + +1. GitHub Copilot with Agent Skills support enabled +2. A Microsoft Foundry Agent endpoint deployed and accessible +3. API credentials (if required by your Foundry Agent) + +### Installation + +1. Clone this repository +2. Enable Agent Skills in VS Code: + ``` + Set "chat.useAgentSkills": true in your VS Code settings + ``` +3. Configure environment variables: + - `FOUNDRY_AGENT_ENDPOINT`: Your Foundry Agent endpoint URL + - `FOUNDRY_AGENT_API_KEY`: Your API key (if authentication is required) + +### Usage + +Once installed and configured, GitHub Copilot will automatically detect when to use the Foundry Agent skill based on user prompts that require advanced AI capabilities. + +Example interactions: +- "Use the Foundry agent to analyze this data" +- "Ask the Foundry agent about complex business logic" +- "Query the Foundry agent for specialized domain knowledge" + +## Skill Implementation + +The skill provides implementation examples in multiple languages: + +- **Python**: Using the `requests` library +- **TypeScript/JavaScript**: Using `axios` +- **C#/.NET**: Using `HttpClient` + +See `.github/skills/foundry-agent/SKILL.md` for complete code examples and documentation. + +## How It Works + +1. User makes a request in GitHub Copilot +2. Copilot detects the request matches the Foundry Agent skill +3. The skill sends the prompt to the configured Foundry Agent endpoint +4. The Foundry Agent processes the request and returns a response +5. Copilot displays the response to the user + +## Contributing + +Contributions are welcome! Please feel free to submit issues or pull requests. + +## Resources + +- [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) +- [GitHub Copilot Agent Skills Documentation](https://code.visualstudio.com/docs/copilot/customization/agent-skills) +- [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp) + +## License + +See LICENSE file for details. diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..205ffe5 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,97 @@ +# Foundry Agent Examples + +This directory contains practical examples demonstrating how to call Microsoft Foundry Agent applications from different programming languages. + +## Available Examples + +### Python Example (`python_example.py`) + +A Python implementation using the `requests` library. + +**Prerequisites:** +```bash +pip install requests +``` + +**Usage:** +```bash +# Set environment variables +export FOUNDRY_AGENT_ENDPOINT="https://your-foundry-endpoint.azure.com/chat" +export FOUNDRY_AGENT_API_KEY="your-api-key" + +# Run with example prompts +python examples/python_example.py + +# Run with custom prompt +python examples/python_example.py "What are the latest AI trends?" +``` + +### TypeScript Example (`typescript_example.ts`) + +A TypeScript implementation using `axios`. + +**Prerequisites:** +```bash +npm install axios +npm install --save-dev @types/node typescript ts-node +``` + +**Usage:** +```bash +# Set environment variables +export FOUNDRY_AGENT_ENDPOINT="https://your-foundry-endpoint.azure.com/chat" +export FOUNDRY_AGENT_API_KEY="your-api-key" + +# Run with ts-node +npx ts-node examples/typescript_example.ts + +# Run with custom prompt +npx ts-node examples/typescript_example.ts "What are the latest AI trends?" +``` + +## Configuration + +Both examples support the following environment variables: + +- `FOUNDRY_AGENT_ENDPOINT`: The URL of your Microsoft Foundry Agent endpoint (required) +- `FOUNDRY_AGENT_API_KEY`: The API key for authentication (optional, depends on your setup) + +## Features + +All examples include: + +- ✅ Environment variable configuration +- ✅ Proper error handling +- ✅ Timeout management +- ✅ Authentication support +- ✅ Conversation context tracking (optional) +- ✅ Command-line interface +- ✅ Example prompts for testing + +## Error Handling + +The examples handle common error scenarios: + +- HTTP errors (4xx, 5xx) +- Connection errors +- Timeout errors +- Invalid JSON responses + +## Testing Without a Foundry Agent + +If you don't have a Foundry Agent endpoint set up yet, the examples will: +1. Use a placeholder endpoint +2. Show connection errors (expected behavior) +3. Demonstrate the structure of requests and responses + +This allows you to: +- Review the code structure +- Understand the API interface +- Prepare your integration before the endpoint is ready + +## Next Steps + +1. Deploy a Microsoft Foundry Agent (see [Azure AI Foundry documentation](https://learn.microsoft.com/azure/ai-foundry/)) +2. Configure your endpoint URL and API key +3. Run the examples to test your integration +4. Integrate the code into your GitHub Copilot skill workflow diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..53abbbc --- /dev/null +++ b/examples/package.json @@ -0,0 +1,27 @@ +{ + "name": "foundry-agent-examples", + "version": "1.0.0", + "description": "Examples for calling Microsoft Foundry Agent from TypeScript/JavaScript", + "main": "typescript_example.ts", + "scripts": { + "start": "ts-node typescript_example.ts", + "build": "tsc typescript_example.ts" + }, + "keywords": [ + "foundry", + "agent", + "copilot", + "microsoft", + "ai" + ], + "author": "", + "license": "MIT", + "dependencies": { + "axios": "^1.6.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.0.0", + "ts-node": "^10.9.0" + } +} diff --git a/examples/python_example.py b/examples/python_example.py new file mode 100644 index 0000000..370c83d --- /dev/null +++ b/examples/python_example.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +""" +Example script demonstrating how to call a Microsoft Foundry Agent from Python. +This is a practical implementation of the foundry-agent skill. +""" + +import os +import sys +import requests +from typing import Dict, Any, Optional + + +class FoundryAgentClient: + """Client for interacting with Microsoft Foundry Agent endpoints.""" + + def __init__( + self, + endpoint: Optional[str] = None, + api_key: Optional[str] = None + ): + """ + Initialize the Foundry Agent client. + + Args: + endpoint: The Foundry Agent endpoint URL. + If not provided, reads from FOUNDRY_AGENT_ENDPOINT env var. + api_key: The API key for authentication. + If not provided, reads from FOUNDRY_AGENT_API_KEY env var. + """ + self.endpoint = endpoint or os.getenv( + "FOUNDRY_AGENT_ENDPOINT", + "https://your-foundry-endpoint.azure.com/chat" + ) + self.api_key = api_key or os.getenv("FOUNDRY_AGENT_API_KEY") + self.session = requests.Session() + + # Set up default headers + self.session.headers.update({ + "Content-Type": "application/json", + }) + + if self.api_key: + self.session.headers.update({ + "Authorization": f"Bearer {self.api_key}" + }) + + def ask( + self, + prompt: str, + conversation_id: Optional[str] = None, + timeout: int = 30 + ) -> Dict[str, Any]: + """ + Send a prompt to the Foundry Agent. + + Args: + prompt: The user's question or request + conversation_id: Optional conversation ID for maintaining context + timeout: Request timeout in seconds + + Returns: + The agent's response as a dictionary + """ + payload = { + "message": prompt, + } + + if conversation_id: + payload["conversation_id"] = conversation_id + + try: + response = self.session.post( + self.endpoint, + json=payload, + timeout=timeout + ) + response.raise_for_status() + return response.json() + except requests.exceptions.HTTPError as e: + return { + "error": f"HTTP error: {e.response.status_code}", + "details": str(e) + } + except requests.exceptions.ConnectionError as e: + return { + "error": "Connection error", + "details": "Failed to connect to Foundry Agent endpoint" + } + except requests.exceptions.Timeout as e: + return { + "error": "Timeout error", + "details": f"Request timed out after {timeout} seconds" + } + except requests.exceptions.RequestException as e: + return { + "error": "Request failed", + "details": str(e) + } + except ValueError as e: + return { + "error": "Invalid JSON response", + "details": str(e) + } + + +def main(): + """Main function demonstrating the Foundry Agent client.""" + print("Foundry Agent Client Example") + print("=" * 50) + + # Initialize the client + client = FoundryAgentClient() + + print(f"Endpoint: {client.endpoint}") + print(f"API Key configured: {'Yes' if client.api_key else 'No'}") + print() + + # Example prompts + examples = [ + "What are the key trends in cloud computing?", + "Explain the benefits of AI in software development", + "Analyze the impact of automation on productivity" + ] + + # If command line arguments provided, use them as prompts + if len(sys.argv) > 1: + prompt = " ".join(sys.argv[1:]) + print(f"User Prompt: {prompt}") + print("-" * 50) + + result = client.ask(prompt) + + if "error" in result: + print(f"Error: {result['error']}") + if "details" in result: + print(f"Details: {result['details']}") + else: + print("Agent Response:") + print(result) + else: + # Run example prompts + print("Running example prompts:") + print() + + for i, prompt in enumerate(examples, 1): + print(f"{i}. Prompt: {prompt}") + result = client.ask(prompt) + + if "error" in result: + print(f" Error: {result['error']}") + else: + print(f" Response: {result.get('response', result)}") + print() + + +if __name__ == "__main__": + main() diff --git a/examples/requirements.txt b/examples/requirements.txt new file mode 100644 index 0000000..0eb8cae --- /dev/null +++ b/examples/requirements.txt @@ -0,0 +1 @@ +requests>=2.31.0 diff --git a/examples/typescript_example.ts b/examples/typescript_example.ts new file mode 100644 index 0000000..cf324af --- /dev/null +++ b/examples/typescript_example.ts @@ -0,0 +1,180 @@ +/** + * Example script demonstrating how to call a Microsoft Foundry Agent from TypeScript/JavaScript. + * This is a practical implementation of the foundry-agent skill. + */ + +import axios, { AxiosInstance, AxiosError } from 'axios'; + +interface FoundryAgentRequest { + message: string; + conversation_id?: string; +} + +interface FoundryAgentResponse { + response: string; + conversation_id?: string; + metadata?: any; +} + +interface ErrorResponse { + error: string; + details: string; +} + +/** + * Client for interacting with Microsoft Foundry Agent endpoints. + */ +class FoundryAgentClient { + private endpoint: string; + private apiKey?: string; + private client: AxiosInstance; + + /** + * Initialize the Foundry Agent client. + * + * @param endpoint - The Foundry Agent endpoint URL. + * If not provided, reads from FOUNDRY_AGENT_ENDPOINT env var. + * @param apiKey - The API key for authentication. + * If not provided, reads from FOUNDRY_AGENT_API_KEY env var. + */ + constructor(endpoint?: string, apiKey?: string) { + this.endpoint = endpoint || + process.env.FOUNDRY_AGENT_ENDPOINT || + 'https://your-foundry-endpoint.azure.com/chat'; + this.apiKey = apiKey || process.env.FOUNDRY_AGENT_API_KEY; + + const headers: Record = { + 'Content-Type': 'application/json', + }; + + if (this.apiKey) { + headers['Authorization'] = `Bearer ${this.apiKey}`; + } + + this.client = axios.create({ + baseURL: this.endpoint, + headers, + timeout: 30000, + }); + } + + /** + * Send a prompt to the Foundry Agent. + * + * @param prompt - The user's question or request + * @param conversationId - Optional conversation ID for maintaining context + * @returns The agent's response or an error object + */ + async ask( + prompt: string, + conversationId?: string + ): Promise { + const payload: FoundryAgentRequest = { + message: prompt, + }; + + if (conversationId) { + payload.conversation_id = conversationId; + } + + try { + const response = await this.client.post('', payload); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + const axiosError = error as AxiosError; + if (axiosError.response) { + return { + error: `HTTP error: ${axiosError.response.status}`, + details: axiosError.message, + }; + } else if (axiosError.request) { + return { + error: 'Connection error', + details: 'Failed to connect to Foundry Agent endpoint', + }; + } + } + return { + error: 'Request failed', + details: error instanceof Error ? error.message : String(error), + }; + } + } + + getEndpoint(): string { + return this.endpoint; + } + + hasApiKey(): boolean { + return !!this.apiKey; + } +} + +/** + * Main function demonstrating the Foundry Agent client. + */ +async function main() { + console.log('Foundry Agent Client Example'); + console.log('='.repeat(50)); + + // Initialize the client + const client = new FoundryAgentClient(); + + console.log(`Endpoint: ${client.getEndpoint()}`); + console.log(`API Key configured: ${client.hasApiKey() ? 'Yes' : 'No'}`); + console.log(); + + // Example prompts + const examples = [ + 'What are the key trends in cloud computing?', + 'Explain the benefits of AI in software development', + 'Analyze the impact of automation on productivity', + ]; + + // If command line arguments provided, use them as prompts + const args = process.argv.slice(2); + if (args.length > 0) { + const prompt = args.join(' '); + console.log(`User Prompt: ${prompt}`); + console.log('-'.repeat(50)); + + const result = await client.ask(prompt); + + if ('error' in result) { + console.log(`Error: ${result.error}`); + console.log(`Details: ${result.details}`); + } else { + console.log('Agent Response:'); + console.log(result); + } + } else { + // Run example prompts + console.log('Running example prompts:'); + console.log(); + + for (let i = 0; i < examples.length; i++) { + const prompt = examples[i]; + console.log(`${i + 1}. Prompt: ${prompt}`); + + const result = await client.ask(prompt); + + if ('error' in result) { + console.log(` Error: ${result.error}`); + } else { + console.log(` Response: ${result.response || JSON.stringify(result)}`); + } + console.log(); + } + } +} + +// Run main function if this is the entry point +if (require.main === module) { + main().catch((error) => { + console.error('Unhandled error:', error); + process.exit(1); + }); +} + +export { FoundryAgentClient, FoundryAgentRequest, FoundryAgentResponse, ErrorResponse }; From 327ad03e5c9af9a0412985b59bae9b0f6a60788d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:10:00 +0000 Subject: [PATCH 03/11] Add architecture documentation and make Python example executable Co-authored-by: adyada <118839465+adyada@users.noreply.github.com> --- ARCHITECTURE.md | 171 +++++++++++++++++++++++++++++++++++++ examples/python_example.py | 0 2 files changed, 171 insertions(+) create mode 100644 ARCHITECTURE.md mode change 100644 => 100755 examples/python_example.py diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..0156ba5 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,171 @@ +# Architecture Overview + +## How the Foundry Agent Skill Works + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ User in VS Code │ +│ │ +│ "Use the Foundry agent to analyze this data..." │ +└─────────────────────┬───────────────────────────────────────────┘ + │ + │ User prompt + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ GitHub Copilot │ +│ │ +│ • Detects intent matches Foundry Agent skill │ +│ • Loads .github/skills/foundry-agent/SKILL.md │ +│ • Determines appropriate action │ +└─────────────────────┬───────────────────────────────────────────┘ + │ + │ Invokes skill + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Foundry Agent Skill (SKILL.md) │ +│ │ +│ • Extracts user prompt │ +│ • Executes implementation code (Python/TS/C#) │ +│ • Formats request payload │ +└─────────────────────┬───────────────────────────────────────────┘ + │ + │ HTTP POST request + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Microsoft Foundry Agent Endpoint │ +│ (Azure AI Foundry Service) │ +│ │ +│ • Receives prompt: { "message": "...", "conversation_id": ... }│ +│ • Processes with specialized AI models │ +│ • Returns response with analysis/results │ +└─────────────────────┬───────────────────────────────────────────┘ + │ + │ JSON response + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Foundry Agent Skill (Response) │ +│ │ +│ • Receives agent response │ +│ • Parses and formats result │ +│ • Returns to Copilot │ +└─────────────────────┬───────────────────────────────────────────┘ + │ + │ Formatted response + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ GitHub Copilot │ +│ │ +│ • Displays result in chat │ +│ • Provides context for follow-up questions │ +└─────────────────────┬───────────────────────────────────────────┘ + │ + │ Display to user + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ User in VS Code │ +│ │ +│ "The analysis shows..." │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Components + +### 1. SKILL.md Definition +- Located at: `.github/skills/foundry-agent/SKILL.md` +- Contains: Skill metadata, description, usage instructions, implementation code +- Format: YAML frontmatter + Markdown content + +### 2. Example Implementations + +#### Python (`examples/python_example.py`) +- Uses: `requests` library +- Features: Error handling, authentication, conversation context +- Run: `python examples/python_example.py "your prompt"` + +#### TypeScript (`examples/typescript_example.ts`) +- Uses: `axios` library +- Features: Type safety, async/await, error handling +- Run: `npx ts-node examples/typescript_example.ts "your prompt"` + +### 3. Configuration +Environment variables: +- `FOUNDRY_AGENT_ENDPOINT`: The Foundry Agent URL +- `FOUNDRY_AGENT_API_KEY`: Optional API key for authentication + +## Request/Response Flow + +### Request Format +```json +{ + "message": "User's prompt or question", + "conversation_id": "optional-uuid-for-context" +} +``` + +### Response Format +```json +{ + "response": "Agent's generated response", + "conversation_id": "uuid-for-context", + "metadata": { + "model": "foundry-model-name", + "tokens": 150 + } +} +``` + +## Error Handling + +The skill handles: +- **Connection Errors**: Network issues, unreachable endpoint +- **HTTP Errors**: 4xx client errors, 5xx server errors +- **Timeout Errors**: Requests exceeding 30 seconds +- **Authentication Errors**: Invalid or missing API keys +- **Parse Errors**: Invalid JSON responses + +## Security Considerations + +1. **API Key Management**: Store keys in environment variables, never in code +2. **HTTPS Only**: All communication uses encrypted HTTPS +3. **Timeout Limits**: Prevents indefinite hanging requests +4. **Input Validation**: Sanitize user inputs before sending to agent +5. **Error Messages**: Don't expose sensitive information in error messages + +## Testing + +### Without Foundry Agent +Run examples with default endpoint to see error handling: +```bash +python examples/python_example.py +``` + +### With Foundry Agent +Configure environment and run: +```bash +export FOUNDRY_AGENT_ENDPOINT="https://your-endpoint.azure.com/chat" +export FOUNDRY_AGENT_API_KEY="your-key" +python examples/python_example.py "Test prompt" +``` + +## Integration with GitHub Copilot + +1. **Enable Skills**: Set `chat.useAgentSkills: true` in VS Code settings +2. **Skill Detection**: Copilot automatically loads skills from `.github/skills/` +3. **Intent Matching**: Copilot uses skill name and description to determine when to invoke +4. **Execution**: Copilot executes the appropriate implementation code +5. **Response**: Results are displayed in the Copilot chat interface + +## Extending the Skill + +To customize the skill: + +1. **Modify SKILL.md**: Update description, usage instructions, or implementation +2. **Add Languages**: Include additional implementation examples (Java, Go, etc.) +3. **Enhance Features**: Add streaming, file attachments, or multimodal support +4. **Custom Parameters**: Extend request payload with additional fields + +## Resources + +- [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) +- [GitHub Copilot Agent Skills](https://code.visualstudio.com/docs/copilot/customization/agent-skills) +- [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp) diff --git a/examples/python_example.py b/examples/python_example.py old mode 100644 new mode 100755 From 36b1623e5762fff48593aab71ce25d572948c153 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:11:48 +0000 Subject: [PATCH 04/11] Standardize placeholder format for endpoint URLs Co-authored-by: adyada <118839465+adyada@users.noreply.github.com> --- .github/skills/foundry-agent/SKILL.md | 6 +++--- examples/python_example.py | 2 +- examples/typescript_example.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/skills/foundry-agent/SKILL.md b/.github/skills/foundry-agent/SKILL.md index 276733e..ccdd86c 100644 --- a/.github/skills/foundry-agent/SKILL.md +++ b/.github/skills/foundry-agent/SKILL.md @@ -49,7 +49,7 @@ def ask_foundry_agent(prompt: str) -> dict: The agent's response as a dictionary """ # Get the Foundry Agent endpoint from environment variables - endpoint = os.getenv("FOUNDRY_AGENT_ENDPOINT", "https:///chat") + endpoint = os.getenv("FOUNDRY_AGENT_ENDPOINT", "https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat") api_key = os.getenv("FOUNDRY_AGENT_API_KEY") headers = { @@ -96,7 +96,7 @@ interface FoundryAgentResponse { async function askFoundryAgent(prompt: string): Promise { // Get the Foundry Agent endpoint from environment variables - const endpoint = process.env.FOUNDRY_AGENT_ENDPOINT || 'https:///chat'; + const endpoint = process.env.FOUNDRY_AGENT_ENDPOINT || 'https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat'; const apiKey = process.env.FOUNDRY_AGENT_API_KEY; const headers: Record = { @@ -151,7 +151,7 @@ public class FoundryAgentClient { _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; _endpoint = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_ENDPOINT") - ?? "https:///chat"; + ?? "https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat"; _apiKey = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_API_KEY"); } diff --git a/examples/python_example.py b/examples/python_example.py index 370c83d..ff9609d 100755 --- a/examples/python_example.py +++ b/examples/python_example.py @@ -29,7 +29,7 @@ def __init__( """ self.endpoint = endpoint or os.getenv( "FOUNDRY_AGENT_ENDPOINT", - "https://your-foundry-endpoint.azure.com/chat" + "https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat" ) self.api_key = api_key or os.getenv("FOUNDRY_AGENT_API_KEY") self.session = requests.Session() diff --git a/examples/typescript_example.ts b/examples/typescript_example.ts index cf324af..63189cc 100644 --- a/examples/typescript_example.ts +++ b/examples/typescript_example.ts @@ -40,7 +40,7 @@ class FoundryAgentClient { constructor(endpoint?: string, apiKey?: string) { this.endpoint = endpoint || process.env.FOUNDRY_AGENT_ENDPOINT || - 'https://your-foundry-endpoint.azure.com/chat'; + 'https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat'; this.apiKey = apiKey || process.env.FOUNDRY_AGENT_API_KEY; const headers: Record = { From eccdfdc152140867d9a8f7af6f514caa49f062d9 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Tue, 20 Jan 2026 21:07:35 -0500 Subject: [PATCH 05/11] working example. --- examples/python_example.py | 60 ++++++++++++++++++++++++++++---------- examples/requirements.txt | 1 + 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/examples/python_example.py b/examples/python_example.py index ff9609d..0e44ddd 100755 --- a/examples/python_example.py +++ b/examples/python_example.py @@ -8,15 +8,20 @@ import sys import requests from typing import Dict, Any, Optional +from azure.identity import DefaultAzureCredential class FoundryAgentClient: """Client for interacting with Microsoft Foundry Agent endpoints.""" + # Default scope for Azure AI services + DEFAULT_SCOPE = "https://ai.azure.com/.default" + def __init__( self, endpoint: Optional[str] = None, - api_key: Optional[str] = None + credential: Optional[DefaultAzureCredential] = None, + scope: Optional[str] = None ): """ Initialize the Foundry Agent client. @@ -24,25 +29,35 @@ def __init__( Args: endpoint: The Foundry Agent endpoint URL. If not provided, reads from FOUNDRY_AGENT_ENDPOINT env var. - api_key: The API key for authentication. - If not provided, reads from FOUNDRY_AGENT_API_KEY env var. + credential: Azure credential for authentication. + If not provided, uses DefaultAzureCredential. + scope: The token scope for authentication. + Defaults to Azure AI services scope. """ self.endpoint = endpoint or os.getenv( "FOUNDRY_AGENT_ENDPOINT", - "https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat" + "https://e2e-tests-westus2-account.services.ai.azure.com/api/projects/e2e-tests-westus2/applications/test-adyada/protocols/openai/responses?api-version=2025-11-15-preview" ) - self.api_key = api_key or os.getenv("FOUNDRY_AGENT_API_KEY") + self.credential = credential or DefaultAzureCredential() + self.scope = scope or self.DEFAULT_SCOPE self.session = requests.Session() # Set up default headers self.session.headers.update({ "Content-Type": "application/json", }) - - if self.api_key: - self.session.headers.update({ - "Authorization": f"Bearer {self.api_key}" - }) + + def _get_token(self) -> str: + """Get an access token using DefaultAzureCredential.""" + token = self.credential.get_token(self.scope) + return token.token + + def _update_auth_header(self): + """Update the authorization header with a fresh token.""" + token = self._get_token() + self.session.headers.update({ + "Authorization": f"Bearer {token}" + }) def ask( self, @@ -61,14 +76,18 @@ def ask( Returns: The agent's response as a dictionary """ + # Use OpenAI-compatible request format for Foundry Agent payload = { - "message": prompt, + "input": prompt, } if conversation_id: - payload["conversation_id"] = conversation_id + payload["previous_response_id"] = conversation_id try: + # Refresh the auth token before each request + self._update_auth_header() + response = self.session.post( self.endpoint, json=payload, @@ -77,9 +96,15 @@ def ask( response.raise_for_status() return response.json() except requests.exceptions.HTTPError as e: + error_body = "" + try: + error_body = e.response.text + except: + pass return { "error": f"HTTP error: {e.response.status_code}", - "details": str(e) + "details": str(e), + "response_body": error_body } except requests.exceptions.ConnectionError as e: return { @@ -112,7 +137,7 @@ def main(): client = FoundryAgentClient() print(f"Endpoint: {client.endpoint}") - print(f"API Key configured: {'Yes' if client.api_key else 'No'}") + print(f"Credential: DefaultAzureCredential") print() # Example prompts @@ -130,13 +155,16 @@ def main(): result = client.ask(prompt) - if "error" in result: + if result.get("error"): print(f"Error: {result['error']}") if "details" in result: print(f"Details: {result['details']}") + if "response_body" in result: + print(f"Response Body: {result['response_body']}") else: print("Agent Response:") - print(result) + import json + print(json.dumps(result, indent=2)) else: # Run example prompts print("Running example prompts:") diff --git a/examples/requirements.txt b/examples/requirements.txt index 0eb8cae..98cb3b9 100644 --- a/examples/requirements.txt +++ b/examples/requirements.txt @@ -1 +1,2 @@ requests>=2.31.0 +azure-identity>=1.15.0 From d7dce0ecc7732b6dcd20bc3d40e1cbe04ba23c95 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Wed, 21 Jan 2026 13:38:45 -0500 Subject: [PATCH 06/11] works with CLI. --- .github/skills/foundry-agent/SKILL.md | 262 ++++++++++---------------- ARCHITECTURE.md | 220 +++++++++++++++------ README.md | 74 ++++++-- examples/python_example.py | 4 +- requirements.txt | 2 + 5 files changed, 320 insertions(+), 242 deletions(-) create mode 100644 requirements.txt diff --git a/.github/skills/foundry-agent/SKILL.md b/.github/skills/foundry-agent/SKILL.md index ccdd86c..3dc5095 100644 --- a/.github/skills/foundry-agent/SKILL.md +++ b/.github/skills/foundry-agent/SKILL.md @@ -3,6 +3,23 @@ name: foundry-agent description: > Enables GitHub Copilot to send user prompts to a Microsoft Foundry Agent for advanced Q&A, complex reasoning, or data processing tasks that require specialized AI capabilities. +location: project +tools: + - name: query_foundry_agent + description: > + Sends a user prompt to the Microsoft Foundry Agent endpoint for advanced AI processing. + Use this when the user explicitly requests Foundry agent capabilities or when complex + reasoning beyond standard Copilot is needed. + parameters: + - name: prompt + description: The user's question or request to send to the Foundry Agent + type: string + required: true + - name: conversation_id + description: Optional conversation ID for maintaining context across multiple requests + type: string + required: false + implementation: python --- # Foundry Agent Skill @@ -17,206 +34,121 @@ This skill allows GitHub Copilot to interact with a Microsoft Foundry Agent appl ## When to Use Use this skill when: +- The user explicitly mentions "Foundry" or "Foundry agent" - The user's request requires advanced AI capabilities beyond standard Copilot functionality - Complex data analysis or processing is needed - Integration with Microsoft Foundry's specialized models is beneficial - The task involves multi-step reasoning or orchestration -## Usage Instructions +## Tool: query_foundry_agent -When Copilot detects that a user's intent matches this skill's capabilities, it will: -1. Extract the user's prompt or question -2. Send a request to the Foundry Agent endpoint -3. Process the response from the agent -4. Return the result to the user in the Copilot chat +Sends a prompt to the configured Microsoft Foundry Agent endpoint. -## Implementation Examples +### Parameters +- **prompt** (required): The user's question or request +- **conversation_id** (optional): Conversation ID for maintaining context -### Python Example +### Implementation ```python -import requests import os +import requests +from azure.identity import DefaultAzureCredential -def ask_foundry_agent(prompt: str) -> dict: - """ - Send a prompt to the Microsoft Foundry Agent endpoint. - - Args: - prompt: The user's question or request - - Returns: - The agent's response as a dictionary - """ - # Get the Foundry Agent endpoint from environment variables - endpoint = os.getenv("FOUNDRY_AGENT_ENDPOINT", "https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat") - api_key = os.getenv("FOUNDRY_AGENT_API_KEY") - - headers = { - "Content-Type": "application/json", - } - - if api_key: - headers["Authorization"] = f"Bearer {api_key}" - - payload = { - "message": prompt, - "conversation_id": None # Optional: for maintaining conversation context - } - - try: - response = requests.post(endpoint, json=payload, headers=headers, timeout=30) - response.raise_for_status() - return response.json() - except requests.exceptions.RequestException as e: - return {"error": f"Failed to call Foundry Agent: {str(e)}"} - -# Example usage -if __name__ == "__main__": - user_prompt = "Analyze the latest sales data trends" - result = ask_foundry_agent(user_prompt) - print(result) -``` +# Initialize Azure credential +credential = DefaultAzureCredential() -### TypeScript/JavaScript Example +# Get endpoint from environment or use default +endpoint = os.getenv( + "FOUNDRY_AGENT_ENDPOINT", + "https://bptest-eastus2-1.services.ai.azure.com/api/projects/test-project-1/applications/test-adyada-agent/protocols/openai/responses?api-version=2025-11-15-preview" +) -```typescript -import axios from 'axios'; +# Get access token +token = credential.get_token("https://ai.azure.com/.default") -interface FoundryAgentRequest { - message: string; - conversation_id?: string; +# Prepare request +headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {token.token}" } -interface FoundryAgentResponse { - response: string; - conversation_id?: string; - metadata?: any; +payload = { + "input": prompt, } -async function askFoundryAgent(prompt: string): Promise { - // Get the Foundry Agent endpoint from environment variables - const endpoint = process.env.FOUNDRY_AGENT_ENDPOINT || 'https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat'; - const apiKey = process.env.FOUNDRY_AGENT_API_KEY; - - const headers: Record = { - 'Content-Type': 'application/json', - }; - - if (apiKey) { - headers['Authorization'] = `Bearer ${apiKey}`; - } - - const payload: FoundryAgentRequest = { - message: prompt, - conversation_id: undefined, // Optional: for maintaining conversation context - }; - - try { - const response = await axios.post( - endpoint, - payload, - { headers, timeout: 30000 } - ); - return response.data; - } catch (error: any) { - return { error: `Failed to call Foundry Agent: ${error.message}` }; - } -} +if conversation_id: + payload["previous_response_id"] = conversation_id -// Example usage -(async () => { - const userPrompt = 'Analyze the latest sales data trends'; - const result = await askFoundryAgent(userPrompt); - console.log(result); -})(); +# Send request to Foundry Agent +try: + response = requests.post(endpoint, json=payload, headers=headers, timeout=120) + response.raise_for_status() + result = response.json() + + # Return the response + return result + +except requests.exceptions.RequestException as e: + return { + "error": f"Failed to call Foundry Agent: {str(e)}", + "endpoint": endpoint + } ``` -### C#/.NET Example +## Configuration -```csharp -using System; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; +To use this skill, you need to: -public class FoundryAgentClient -{ - private readonly HttpClient _httpClient; - private readonly string _endpoint; - private readonly string _apiKey; - - public FoundryAgentClient() - { - _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; - _endpoint = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_ENDPOINT") - ?? "https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat"; - _apiKey = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_API_KEY"); - } +1. **Set up Azure authentication**: The skill uses `DefaultAzureCredential` which supports multiple authentication methods: + - Azure CLI: `az login` + - Environment variables: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET` + - Managed Identity (when running in Azure) + - Visual Studio Code Azure account - public async Task AskFoundryAgentAsync(string prompt) - { - var payload = new - { - message = prompt, - conversation_id = (string)null - }; - - var content = new StringContent( - JsonSerializer.Serialize(payload), - Encoding.UTF8, - "application/json" - ); - - if (!string.IsNullOrEmpty(_apiKey)) - { - _httpClient.DefaultRequestHeaders.Authorization = - new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiKey); - } - - try - { - var response = await _httpClient.PostAsync(_endpoint, content); - response.EnsureSuccessStatusCode(); - - var responseBody = await response.Content.ReadAsStringAsync(); - return JsonDocument.Parse(responseBody); - } - catch (Exception ex) - { - var errorJson = JsonSerializer.Serialize(new { error = $"Failed to call Foundry Agent: {ex.Message}" }); - return JsonDocument.Parse(errorJson); - } - } +2. **Configure the Foundry Agent endpoint** (optional): + - Set `FOUNDRY_AGENT_ENDPOINT` environment variable to your Foundry Agent URL + - If not set, uses the default endpoint shown in the implementation - // Example usage - public static async Task Main(string[] args) - { - var client = new FoundryAgentClient(); - var result = await client.AskFoundryAgentAsync("Analyze the latest sales data trends"); - Console.WriteLine(result.RootElement.ToString()); - } -} -``` +3. **Install required Python packages**: + ```bash + pip install requests azure-identity + ``` -## Configuration +## Example Usage -To use this skill, you need to configure the following environment variables: +In GitHub Copilot, you can invoke this skill by asking: +- "Use the Foundry agent to analyze this code" +- "Ask the Foundry agent what's new in Foundry" +- "Query the Foundry agent about cloud computing trends" -- `FOUNDRY_AGENT_ENDPOINT`: The URL of your Microsoft Foundry Agent endpoint -- `FOUNDRY_AGENT_API_KEY`: (Optional) The API key for authentication +## Response Format -## Testing +The Foundry Agent returns responses in the following format: +```json +{ + "response": "Agent's response text", + "conversation_id": "optional-conversation-id", + "metadata": { + "model": "model-name", + "tokens": 150 + } +} +``` -You can test the Foundry Agent integration by: +## Error Handling -1. Setting up the environment variables with your Foundry Agent endpoint -2. Running any of the example scripts above -3. Verifying that the agent responds correctly to your prompts +If the request fails, the skill returns an error object: +```json +{ + "error": "Error description", + "endpoint": "The endpoint that was called" +} +``` ## Additional Resources - [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) - [GitHub Copilot Agent Skills Documentation](https://code.visualstudio.com/docs/copilot/customization/agent-skills) +- [Azure Identity Library](https://learn.microsoft.com/python/api/azure-identity/) - [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0156ba5..44de68a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -4,40 +4,41 @@ ``` ┌─────────────────────────────────────────────────────────────────┐ -│ User in VS Code │ +│ User in GitHub Copilot │ │ │ -│ "Use the Foundry agent to analyze this data..." │ +│ "Use the Foundry agent to analyze this code..." │ └─────────────────────┬───────────────────────────────────────────┘ │ - │ User prompt + │ User prompt with "Foundry" keyword ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ GitHub Copilot │ +│ GitHub Copilot CLI │ │ │ -│ • Detects intent matches Foundry Agent skill │ +│ • Detects "foundry-agent" skill intent │ │ • Loads .github/skills/foundry-agent/SKILL.md │ -│ • Determines appropriate action │ +│ • Invokes query_foundry_agent tool │ └─────────────────────┬───────────────────────────────────────────┘ │ - │ Invokes skill + │ Executes Python implementation ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ Foundry Agent Skill (SKILL.md) │ +│ Foundry Agent Skill (Python) │ │ │ -│ • Extracts user prompt │ -│ • Executes implementation code (Python/TS/C#) │ -│ • Formats request payload │ +│ • Authenticates with DefaultAzureCredential │ +│ • Gets access token for https://ai.azure.com │ +│ • Formats request: { "input": "prompt" } │ +│ • Sends POST to Foundry Agent endpoint │ └─────────────────────┬───────────────────────────────────────────┘ │ - │ HTTP POST request + │ HTTPS POST with Bearer token ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Microsoft Foundry Agent Endpoint │ │ (Azure AI Foundry Service) │ │ │ -│ • Receives prompt: { "message": "...", "conversation_id": ... }│ -│ • Processes with specialized AI models │ -│ • Returns response with analysis/results │ +│ • Validates authentication token │ +│ • Processes prompt with AI models │ +│ • Returns JSON response with results │ └─────────────────────┬───────────────────────────────────────────┘ │ │ JSON response @@ -46,25 +47,24 @@ │ Foundry Agent Skill (Response) │ │ │ │ • Receives agent response │ -│ • Parses and formats result │ -│ • Returns to Copilot │ +│ • Returns to Copilot CLI │ └─────────────────────┬───────────────────────────────────────────┘ │ │ Formatted response ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ GitHub Copilot │ +│ GitHub Copilot CLI │ │ │ │ • Displays result in chat │ -│ • Provides context for follow-up questions │ +│ • Ready for follow-up questions │ └─────────────────────┬───────────────────────────────────────────┘ │ │ Display to user ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ User in VS Code │ +│ User in GitHub Copilot │ │ │ -│ "The analysis shows..." │ +│ "The Foundry agent says..." │ └─────────────────────────────────────────────────────────────────┘ ``` @@ -72,37 +72,66 @@ ### 1. SKILL.md Definition - Located at: `.github/skills/foundry-agent/SKILL.md` -- Contains: Skill metadata, description, usage instructions, implementation code -- Format: YAML frontmatter + Markdown content +- Contains: + - YAML frontmatter with tool definition (`query_foundry_agent`) + - Python implementation using `requests` and `azure-identity` + - Configuration instructions + - Usage examples -### 2. Example Implementations +### 2. Tool: query_foundry_agent +- **Parameters**: + - `prompt` (required): User's question or request + - `conversation_id` (optional): For maintaining conversation context +- **Authentication**: Uses Azure `DefaultAzureCredential` +- **Endpoint**: Configurable via `FOUNDRY_AGENT_ENDPOINT` environment variable +- **Timeout**: 120 seconds + +### 3. Example Implementations #### Python (`examples/python_example.py`) -- Uses: `requests` library -- Features: Error handling, authentication, conversation context +- Full client implementation with `FoundryAgentClient` class +- Uses: `requests` library and `azure-identity` +- Features: Token refresh, error handling, conversation context - Run: `python examples/python_example.py "your prompt"` #### TypeScript (`examples/typescript_example.ts`) +- Full client implementation with `FoundryAgentClient` class - Uses: `axios` library - Features: Type safety, async/await, error handling - Run: `npx ts-node examples/typescript_example.ts "your prompt"` -### 3. Configuration +### 4. Configuration +Required Python packages (see `requirements.txt`): +- `requests>=2.31.0` - HTTP client +- `azure-identity>=1.15.0` - Azure authentication + Environment variables: -- `FOUNDRY_AGENT_ENDPOINT`: The Foundry Agent URL -- `FOUNDRY_AGENT_API_KEY`: Optional API key for authentication +- `FOUNDRY_AGENT_ENDPOINT`: Optional custom endpoint URL +- Azure authentication (one of): + - Azure CLI: `az login` + - Environment variables: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET` + - Managed Identity (when running in Azure) + - VS Code Azure account ## Request/Response Flow ### Request Format +The skill sends requests to the Foundry Agent endpoint in the following format: ```json { - "message": "User's prompt or question", - "conversation_id": "optional-uuid-for-context" + "input": "User's prompt or question", + "previous_response_id": "optional-conversation-id" } ``` +**Headers:** +``` +Content-Type: application/json +Authorization: Bearer +``` + ### Response Format +The Foundry Agent returns responses in this format: ```json { "response": "Agent's generated response", @@ -125,44 +154,123 @@ The skill handles: ## Security Considerations -1. **API Key Management**: Store keys in environment variables, never in code -2. **HTTPS Only**: All communication uses encrypted HTTPS -3. **Timeout Limits**: Prevents indefinite hanging requests -4. **Input Validation**: Sanitize user inputs before sending to agent -5. **Error Messages**: Don't expose sensitive information in error messages +1. **Azure Authentication**: Uses Azure `DefaultAzureCredential` for secure, passwordless authentication + - No API keys or secrets stored in code or environment variables + - Leverages Azure AD token-based authentication + - Supports managed identities for Azure-hosted applications -## Testing +2. **Token Management**: + - Access tokens are obtained fresh for each request + - Tokens have limited lifetime and are automatically refreshed + - Bearer token authentication via HTTPS only -### Without Foundry Agent -Run examples with default endpoint to see error handling: -```bash -python examples/python_example.py -``` +3. **HTTPS Only**: All communication uses encrypted HTTPS +4. **Timeout Limits**: 120-second timeout prevents indefinite hanging requests +5. **Input Validation**: User prompts are sent as-is to the Foundry Agent endpoint +6. **Error Messages**: Errors include endpoint information but no sensitive authentication details + +## Testing -### With Foundry Agent -Configure environment and run: +### Testing Without a Foundry Agent Endpoint +Run the example scripts without configuration to see error handling: ```bash -export FOUNDRY_AGENT_ENDPOINT="https://your-endpoint.azure.com/chat" -export FOUNDRY_AGENT_API_KEY="your-key" +# Test Python example python examples/python_example.py "Test prompt" + +# This will attempt to authenticate and call the default endpoint +# If authentication fails or endpoint is unreachable, you'll see appropriate error messages ``` +### Testing With Your Own Foundry Agent +1. **Set up Azure authentication**: + ```bash + az login + ``` + +2. **Configure your endpoint** (optional): + ```bash + export FOUNDRY_AGENT_ENDPOINT="https://your-endpoint.azure.com/api/..." + ``` + +3. **Test with Python example**: + ```bash + python examples/python_example.py "What are the latest AI trends?" + ``` + +4. **Test with TypeScript example**: + ```bash + npm install # from examples/ directory + npx ts-node typescript_example.ts "Explain quantum computing" + ``` + +### Testing the GitHub Copilot Skill +1. Ensure you're in a repository with the skill installed +2. Open GitHub Copilot chat +3. Try: "Use the Foundry agent to explain microservices architecture" +4. Copilot should invoke the skill and return the Foundry Agent's response + ## Integration with GitHub Copilot -1. **Enable Skills**: Set `chat.useAgentSkills: true` in VS Code settings -2. **Skill Detection**: Copilot automatically loads skills from `.github/skills/` -3. **Intent Matching**: Copilot uses skill name and description to determine when to invoke -4. **Execution**: Copilot executes the appropriate implementation code -5. **Response**: Results are displayed in the Copilot chat interface +### How Copilot Loads Skills +1. **Skill Detection**: Copilot automatically loads skills from `.github/skills/` directory +2. **Metadata Parsing**: Reads YAML frontmatter to understand skill capabilities +3. **Tool Registration**: Registers the `query_foundry_agent` tool +4. **Intent Matching**: Uses skill name and description to determine when to invoke + +### Skill Invocation Process +1. **User mentions "Foundry" or "Foundry agent"** in their prompt +2. **Copilot matches intent** to the `foundry-agent` skill +3. **Copilot calls `query_foundry_agent`** with the user's prompt +4. **Python code executes**: + - Authenticates with Azure + - Calls Foundry Agent endpoint + - Returns response +5. **Copilot displays result** in the chat interface + +### Requirements +- GitHub Copilot CLI or VS Code with Copilot +- Skill must be in `.github/skills/foundry-agent/SKILL.md` +- Python runtime available with required packages installed +- Azure authentication configured ## Extending the Skill -To customize the skill: +To customize or extend the skill: + +1. **Modify Request/Response Format**: + - Edit the Python implementation in SKILL.md + - Update payload structure in lines 76-81 + - Adjust response parsing as needed + +2. **Add New Parameters**: + - Add parameters to the tool definition in YAML frontmatter + - Update Python code to use the new parameters + - Document in the Configuration section + +3. **Enhance Error Handling**: + - Extend the try/except block (lines 84-96) + - Add specific error cases + - Improve error messages + +4. **Add TypeScript/Node.js Support**: + - Add `implementation: typescript` or `implementation: javascript` to tool definition + - Include TypeScript/JavaScript code instead of Python + - Update documentation accordingly + +5. **Support Multiple Endpoints**: + - Add endpoint selection logic + - Support different Foundry Agent types + - Route requests based on prompt analysis + +6. **Add Streaming Support**: + - Modify to use streaming API endpoints + - Yield partial responses + - Update response format -1. **Modify SKILL.md**: Update description, usage instructions, or implementation -2. **Add Languages**: Include additional implementation examples (Java, Go, etc.) -3. **Enhance Features**: Add streaming, file attachments, or multimodal support -4. **Custom Parameters**: Extend request payload with additional fields +7. **Add Conversation Memory**: + - Store conversation IDs persistently + - Track conversation history + - Enable multi-turn conversations ## Resources diff --git a/README.md b/README.md index da6bb9c..fa50660 100644 --- a/README.md +++ b/README.md @@ -20,39 +20,75 @@ The skill is defined in `.github/skills/foundry-agent/SKILL.md` following the Gi ### Prerequisites -1. GitHub Copilot with Agent Skills support enabled -2. A Microsoft Foundry Agent endpoint deployed and accessible -3. API credentials (if required by your Foundry Agent) +1. **GitHub Copilot** with Agent Skills support enabled +2. **Python 3.8+** installed +3. **Azure authentication** configured (Azure CLI, environment variables, or managed identity) +4. **Microsoft Foundry Agent** endpoint deployed and accessible (optional - uses default if not configured) ### Installation -1. Clone this repository -2. Enable Agent Skills in VS Code: +1. **Clone this repository**: + ```bash + git clone https://github.com/yourusername/foundry-github-copilot-skill.git + cd foundry-github-copilot-skill ``` - Set "chat.useAgentSkills": true in your VS Code settings + +2. **Install Python dependencies**: + ```bash + pip install -r requirements.txt + ``` + +3. **Set up Azure authentication** (choose one method): + - **Azure CLI** (recommended for development): + ```bash + az login + ``` + - **Environment variables**: + ```bash + export AZURE_CLIENT_ID="your-client-id" + export AZURE_TENANT_ID="your-tenant-id" + export AZURE_CLIENT_SECRET="your-client-secret" + ``` + - **VS Code**: Sign in with your Azure account + +4. **Configure Foundry Agent endpoint** (optional): + ```bash + export FOUNDRY_AGENT_ENDPOINT="https://your-endpoint.azure.com/api/..." ``` -3. Configure environment variables: - - `FOUNDRY_AGENT_ENDPOINT`: Your Foundry Agent endpoint URL - - `FOUNDRY_AGENT_API_KEY`: Your API key (if authentication is required) + If not set, the skill uses a default test endpoint. ### Usage -Once installed and configured, GitHub Copilot will automatically detect when to use the Foundry Agent skill based on user prompts that require advanced AI capabilities. +Once installed and configured, the Foundry Agent skill is automatically available in GitHub Copilot. + +#### Invoking the Skill + +You can invoke the skill by mentioning "Foundry" or "Foundry agent" in your Copilot prompts: + +- "Use the Foundry agent to analyze this code" +- "Ask the Foundry agent what's new in Microsoft Foundry" +- "Query the Foundry agent about cloud architecture best practices" +- "Call the Foundry agent to explain this algorithm" + +#### How It Works -Example interactions: -- "Use the Foundry agent to analyze this data" -- "Ask the Foundry agent about complex business logic" -- "Query the Foundry agent for specialized domain knowledge" +1. **You make a request** in GitHub Copilot mentioning the Foundry agent +2. **Copilot detects the intent** and loads the `foundry-agent` skill +3. **The skill authenticates** using Azure DefaultAzureCredential +4. **Sends your prompt** to the configured Foundry Agent endpoint +5. **Returns the response** from the Foundry Agent back to you in Copilot ## Skill Implementation -The skill provides implementation examples in multiple languages: +The skill is implemented as a GitHub Copilot Agent Skill located in `.github/skills/foundry-agent/SKILL.md`. -- **Python**: Using the `requests` library -- **TypeScript/JavaScript**: Using `axios` -- **C#/.NET**: Using `HttpClient` +### Key Features -See `.github/skills/foundry-agent/SKILL.md` for complete code examples and documentation. +- **Azure Authentication**: Uses `DefaultAzureCredential` for secure, passwordless authentication +- **Configurable Endpoint**: Support for custom Foundry Agent endpoints via environment variable +- **Error Handling**: Robust error handling with descriptive error messages +- **Conversation Context**: Optional conversation ID parameter for multi-turn conversations +- **Timeout Protection**: 120-second timeout to prevent hanging requests ## How It Works diff --git a/examples/python_example.py b/examples/python_example.py index 0e44ddd..5b8b43d 100755 --- a/examples/python_example.py +++ b/examples/python_example.py @@ -36,7 +36,7 @@ def __init__( """ self.endpoint = endpoint or os.getenv( "FOUNDRY_AGENT_ENDPOINT", - "https://e2e-tests-westus2-account.services.ai.azure.com/api/projects/e2e-tests-westus2/applications/test-adyada/protocols/openai/responses?api-version=2025-11-15-preview" + "https://bptest-eastus2-1.services.ai.azure.com/api/projects/test-project-1/applications/test-adyada-agent/protocols/openai/responses?api-version=2025-11-15-preview" ) self.credential = credential or DefaultAzureCredential() self.scope = scope or self.DEFAULT_SCOPE @@ -63,7 +63,7 @@ def ask( self, prompt: str, conversation_id: Optional[str] = None, - timeout: int = 30 + timeout: int = 120 ) -> Dict[str, Any]: """ Send a prompt to the Foundry Agent. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8e60dc6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests>=2.31.0 +azure-identity>=1.15.0 From 39507aa69b99a16e2a0bb8b3e65d1ad33ad8bb94 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Wed, 21 Jan 2026 15:14:46 -0500 Subject: [PATCH 07/11] added another tool file. --- .../foundry-agent/query_foundry_agent.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 .github/skills/foundry-agent/query_foundry_agent.py diff --git a/.github/skills/foundry-agent/query_foundry_agent.py b/.github/skills/foundry-agent/query_foundry_agent.py new file mode 100644 index 0000000..e05a0f0 --- /dev/null +++ b/.github/skills/foundry-agent/query_foundry_agent.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +""" +GitHub Copilot Agent Skill tool: query_foundry_agent +Sends a prompt to Microsoft Foundry Agent for advanced AI processing. +""" + +import os +import sys +import json +import requests +from azure.identity import DefaultAzureCredential + + +def query_foundry_agent(prompt: str, conversation_id: str = None): + """ + Query the Microsoft Foundry Agent with a user prompt. + + Args: + prompt: The user's question or request to send to the Foundry Agent + conversation_id: Optional conversation ID for maintaining context across multiple requests + + Returns: + dict: The Foundry Agent response or error information + """ + try: + # Initialize Azure credential + credential = DefaultAzureCredential() + + # Get endpoint from environment or use default + endpoint = os.getenv( + "FOUNDRY_AGENT_ENDPOINT", + "https://bptest-eastus2-1.services.ai.azure.com/api/projects/test-project-1/applications/test-adyada-agent/protocols/openai/responses?api-version=2025-11-15-preview" + ) + + # Get access token + token = credential.get_token("https://ai.azure.com/.default") + + # Prepare request + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {token.token}" + } + + payload = { + "input": prompt, + } + + if conversation_id: + payload["previous_response_id"] = conversation_id + + # Send request to Foundry Agent + response = requests.post(endpoint, json=payload, headers=headers, timeout=120) + response.raise_for_status() + result = response.json() + + # Return the response + return result + + except requests.exceptions.RequestException as e: + return { + "error": f"Failed to call Foundry Agent: {str(e)}", + "endpoint": endpoint + } + except Exception as e: + return { + "error": f"Unexpected error: {str(e)}", + "type": type(e).__name__ + } + + +def main(): + """Main entry point for the tool when called by GitHub Copilot.""" + try: + # Read input parameters from stdin (JSON format) + input_data = json.loads(sys.stdin.read()) + + prompt = input_data.get("prompt") + conversation_id = input_data.get("conversation_id") + + if not prompt: + print(json.dumps({"error": "Missing required parameter: prompt"})) + sys.exit(1) + + # Call the Foundry Agent + result = query_foundry_agent(prompt, conversation_id) + + # Output result as JSON + print(json.dumps(result)) + + except json.JSONDecodeError as e: + print(json.dumps({"error": f"Invalid JSON input: {str(e)}"})) + sys.exit(1) + except Exception as e: + print(json.dumps({"error": f"Tool execution failed: {str(e)}"})) + sys.exit(1) + + +if __name__ == "__main__": + main() From 346f7ee890d79a78950d8d5f4cdbbd49d0920562 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Fri, 23 Jan 2026 17:41:26 -0500 Subject: [PATCH 08/11] cleaned up sample --- .github/skills/foundry-agent/SKILL.md | 10 +- .../foundry-agent/query_foundry_agent.py | 14 +- ARCHITECTURE.md | 279 ------------------ README.md | 113 ------- examples/README.md | 97 ------ examples/package.json | 27 -- examples/python_example.py | 185 ------------ examples/requirements.txt | 2 - examples/typescript_example.ts | 180 ----------- 9 files changed, 12 insertions(+), 895 deletions(-) delete mode 100644 ARCHITECTURE.md delete mode 100644 README.md delete mode 100644 examples/README.md delete mode 100644 examples/package.json delete mode 100755 examples/python_example.py delete mode 100644 examples/requirements.txt delete mode 100644 examples/typescript_example.ts diff --git a/.github/skills/foundry-agent/SKILL.md b/.github/skills/foundry-agent/SKILL.md index 3dc5095..db14461 100644 --- a/.github/skills/foundry-agent/SKILL.md +++ b/.github/skills/foundry-agent/SKILL.md @@ -58,11 +58,11 @@ from azure.identity import DefaultAzureCredential # Initialize Azure credential credential = DefaultAzureCredential() -# Get endpoint from environment or use default -endpoint = os.getenv( - "FOUNDRY_AGENT_ENDPOINT", - "https://bptest-eastus2-1.services.ai.azure.com/api/projects/test-project-1/applications/test-adyada-agent/protocols/openai/responses?api-version=2025-11-15-preview" -) +# Get endpoint from environment (required) +# Example: "https://.services.ai.azure.com/api/projects//applications//protocols/openai/responses?api-version=2025-11-15-preview" +endpoint = os.getenv("FOUNDRY_AGENT_APPLICATION_ENDPOINT") +if not endpoint: + raise ValueError("FOUNDRY_AGENT_APPLICATION_ENDPOINT environment variable is required but not set") # Get access token token = credential.get_token("https://ai.azure.com/.default") diff --git a/.github/skills/foundry-agent/query_foundry_agent.py b/.github/skills/foundry-agent/query_foundry_agent.py index e05a0f0..b3e2e3b 100644 --- a/.github/skills/foundry-agent/query_foundry_agent.py +++ b/.github/skills/foundry-agent/query_foundry_agent.py @@ -25,13 +25,13 @@ def query_foundry_agent(prompt: str, conversation_id: str = None): try: # Initialize Azure credential credential = DefaultAzureCredential() - - # Get endpoint from environment or use default - endpoint = os.getenv( - "FOUNDRY_AGENT_ENDPOINT", - "https://bptest-eastus2-1.services.ai.azure.com/api/projects/test-project-1/applications/test-adyada-agent/protocols/openai/responses?api-version=2025-11-15-preview" - ) - + + # Get endpoint from environment (required) + # Example: "https://.services.ai.azure.com/api/projects//applications//protocols/openai/responses?api-version=2025-11-15-preview" + endpoint = os.getenv("FOUNDRY_AGENT_APPLICATION_ENDPOINT") + if not endpoint: + raise ValueError("FOUNDRY_AGENT_APPLICATION_ENDPOINT environment variable is required but not set") + # Get access token token = credential.get_token("https://ai.azure.com/.default") diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md deleted file mode 100644 index 44de68a..0000000 --- a/ARCHITECTURE.md +++ /dev/null @@ -1,279 +0,0 @@ -# Architecture Overview - -## How the Foundry Agent Skill Works - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ User in GitHub Copilot │ -│ │ -│ "Use the Foundry agent to analyze this code..." │ -└─────────────────────┬───────────────────────────────────────────┘ - │ - │ User prompt with "Foundry" keyword - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ GitHub Copilot CLI │ -│ │ -│ • Detects "foundry-agent" skill intent │ -│ • Loads .github/skills/foundry-agent/SKILL.md │ -│ • Invokes query_foundry_agent tool │ -└─────────────────────┬───────────────────────────────────────────┘ - │ - │ Executes Python implementation - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Foundry Agent Skill (Python) │ -│ │ -│ • Authenticates with DefaultAzureCredential │ -│ • Gets access token for https://ai.azure.com │ -│ • Formats request: { "input": "prompt" } │ -│ • Sends POST to Foundry Agent endpoint │ -└─────────────────────┬───────────────────────────────────────────┘ - │ - │ HTTPS POST with Bearer token - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Microsoft Foundry Agent Endpoint │ -│ (Azure AI Foundry Service) │ -│ │ -│ • Validates authentication token │ -│ • Processes prompt with AI models │ -│ • Returns JSON response with results │ -└─────────────────────┬───────────────────────────────────────────┘ - │ - │ JSON response - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Foundry Agent Skill (Response) │ -│ │ -│ • Receives agent response │ -│ • Returns to Copilot CLI │ -└─────────────────────┬───────────────────────────────────────────┘ - │ - │ Formatted response - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ GitHub Copilot CLI │ -│ │ -│ • Displays result in chat │ -│ • Ready for follow-up questions │ -└─────────────────────┬───────────────────────────────────────────┘ - │ - │ Display to user - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ User in GitHub Copilot │ -│ │ -│ "The Foundry agent says..." │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Components - -### 1. SKILL.md Definition -- Located at: `.github/skills/foundry-agent/SKILL.md` -- Contains: - - YAML frontmatter with tool definition (`query_foundry_agent`) - - Python implementation using `requests` and `azure-identity` - - Configuration instructions - - Usage examples - -### 2. Tool: query_foundry_agent -- **Parameters**: - - `prompt` (required): User's question or request - - `conversation_id` (optional): For maintaining conversation context -- **Authentication**: Uses Azure `DefaultAzureCredential` -- **Endpoint**: Configurable via `FOUNDRY_AGENT_ENDPOINT` environment variable -- **Timeout**: 120 seconds - -### 3. Example Implementations - -#### Python (`examples/python_example.py`) -- Full client implementation with `FoundryAgentClient` class -- Uses: `requests` library and `azure-identity` -- Features: Token refresh, error handling, conversation context -- Run: `python examples/python_example.py "your prompt"` - -#### TypeScript (`examples/typescript_example.ts`) -- Full client implementation with `FoundryAgentClient` class -- Uses: `axios` library -- Features: Type safety, async/await, error handling -- Run: `npx ts-node examples/typescript_example.ts "your prompt"` - -### 4. Configuration -Required Python packages (see `requirements.txt`): -- `requests>=2.31.0` - HTTP client -- `azure-identity>=1.15.0` - Azure authentication - -Environment variables: -- `FOUNDRY_AGENT_ENDPOINT`: Optional custom endpoint URL -- Azure authentication (one of): - - Azure CLI: `az login` - - Environment variables: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET` - - Managed Identity (when running in Azure) - - VS Code Azure account - -## Request/Response Flow - -### Request Format -The skill sends requests to the Foundry Agent endpoint in the following format: -```json -{ - "input": "User's prompt or question", - "previous_response_id": "optional-conversation-id" -} -``` - -**Headers:** -``` -Content-Type: application/json -Authorization: Bearer -``` - -### Response Format -The Foundry Agent returns responses in this format: -```json -{ - "response": "Agent's generated response", - "conversation_id": "uuid-for-context", - "metadata": { - "model": "foundry-model-name", - "tokens": 150 - } -} -``` - -## Error Handling - -The skill handles: -- **Connection Errors**: Network issues, unreachable endpoint -- **HTTP Errors**: 4xx client errors, 5xx server errors -- **Timeout Errors**: Requests exceeding 30 seconds -- **Authentication Errors**: Invalid or missing API keys -- **Parse Errors**: Invalid JSON responses - -## Security Considerations - -1. **Azure Authentication**: Uses Azure `DefaultAzureCredential` for secure, passwordless authentication - - No API keys or secrets stored in code or environment variables - - Leverages Azure AD token-based authentication - - Supports managed identities for Azure-hosted applications - -2. **Token Management**: - - Access tokens are obtained fresh for each request - - Tokens have limited lifetime and are automatically refreshed - - Bearer token authentication via HTTPS only - -3. **HTTPS Only**: All communication uses encrypted HTTPS -4. **Timeout Limits**: 120-second timeout prevents indefinite hanging requests -5. **Input Validation**: User prompts are sent as-is to the Foundry Agent endpoint -6. **Error Messages**: Errors include endpoint information but no sensitive authentication details - -## Testing - -### Testing Without a Foundry Agent Endpoint -Run the example scripts without configuration to see error handling: -```bash -# Test Python example -python examples/python_example.py "Test prompt" - -# This will attempt to authenticate and call the default endpoint -# If authentication fails or endpoint is unreachable, you'll see appropriate error messages -``` - -### Testing With Your Own Foundry Agent -1. **Set up Azure authentication**: - ```bash - az login - ``` - -2. **Configure your endpoint** (optional): - ```bash - export FOUNDRY_AGENT_ENDPOINT="https://your-endpoint.azure.com/api/..." - ``` - -3. **Test with Python example**: - ```bash - python examples/python_example.py "What are the latest AI trends?" - ``` - -4. **Test with TypeScript example**: - ```bash - npm install # from examples/ directory - npx ts-node typescript_example.ts "Explain quantum computing" - ``` - -### Testing the GitHub Copilot Skill -1. Ensure you're in a repository with the skill installed -2. Open GitHub Copilot chat -3. Try: "Use the Foundry agent to explain microservices architecture" -4. Copilot should invoke the skill and return the Foundry Agent's response - -## Integration with GitHub Copilot - -### How Copilot Loads Skills -1. **Skill Detection**: Copilot automatically loads skills from `.github/skills/` directory -2. **Metadata Parsing**: Reads YAML frontmatter to understand skill capabilities -3. **Tool Registration**: Registers the `query_foundry_agent` tool -4. **Intent Matching**: Uses skill name and description to determine when to invoke - -### Skill Invocation Process -1. **User mentions "Foundry" or "Foundry agent"** in their prompt -2. **Copilot matches intent** to the `foundry-agent` skill -3. **Copilot calls `query_foundry_agent`** with the user's prompt -4. **Python code executes**: - - Authenticates with Azure - - Calls Foundry Agent endpoint - - Returns response -5. **Copilot displays result** in the chat interface - -### Requirements -- GitHub Copilot CLI or VS Code with Copilot -- Skill must be in `.github/skills/foundry-agent/SKILL.md` -- Python runtime available with required packages installed -- Azure authentication configured - -## Extending the Skill - -To customize or extend the skill: - -1. **Modify Request/Response Format**: - - Edit the Python implementation in SKILL.md - - Update payload structure in lines 76-81 - - Adjust response parsing as needed - -2. **Add New Parameters**: - - Add parameters to the tool definition in YAML frontmatter - - Update Python code to use the new parameters - - Document in the Configuration section - -3. **Enhance Error Handling**: - - Extend the try/except block (lines 84-96) - - Add specific error cases - - Improve error messages - -4. **Add TypeScript/Node.js Support**: - - Add `implementation: typescript` or `implementation: javascript` to tool definition - - Include TypeScript/JavaScript code instead of Python - - Update documentation accordingly - -5. **Support Multiple Endpoints**: - - Add endpoint selection logic - - Support different Foundry Agent types - - Route requests based on prompt analysis - -6. **Add Streaming Support**: - - Modify to use streaming API endpoints - - Yield partial responses - - Update response format - -7. **Add Conversation Memory**: - - Store conversation IDs persistently - - Track conversation history - - Enable multi-turn conversations - -## Resources - -- [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) -- [GitHub Copilot Agent Skills](https://code.visualstudio.com/docs/copilot/customization/agent-skills) -- [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp) diff --git a/README.md b/README.md deleted file mode 100644 index fa50660..0000000 --- a/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# foundry-github-copilot-skill - -This repository contains a GitHub Copilot Agent Skill example that demonstrates how to call a Microsoft Foundry Agent application from within GitHub Copilot. - -## Overview - -The Foundry Agent Skill enables GitHub Copilot to interact with Microsoft Foundry Agent applications for advanced AI capabilities, including: - -- Complex reasoning and analysis -- Advanced natural language understanding -- Specialized domain knowledge integration -- Custom AI workflows and processing -- Multi-step task orchestration - -## Skill Structure - -The skill is defined in `.github/skills/foundry-agent/SKILL.md` following the GitHub Copilot Agent Skills specification. - -## Getting Started - -### Prerequisites - -1. **GitHub Copilot** with Agent Skills support enabled -2. **Python 3.8+** installed -3. **Azure authentication** configured (Azure CLI, environment variables, or managed identity) -4. **Microsoft Foundry Agent** endpoint deployed and accessible (optional - uses default if not configured) - -### Installation - -1. **Clone this repository**: - ```bash - git clone https://github.com/yourusername/foundry-github-copilot-skill.git - cd foundry-github-copilot-skill - ``` - -2. **Install Python dependencies**: - ```bash - pip install -r requirements.txt - ``` - -3. **Set up Azure authentication** (choose one method): - - **Azure CLI** (recommended for development): - ```bash - az login - ``` - - **Environment variables**: - ```bash - export AZURE_CLIENT_ID="your-client-id" - export AZURE_TENANT_ID="your-tenant-id" - export AZURE_CLIENT_SECRET="your-client-secret" - ``` - - **VS Code**: Sign in with your Azure account - -4. **Configure Foundry Agent endpoint** (optional): - ```bash - export FOUNDRY_AGENT_ENDPOINT="https://your-endpoint.azure.com/api/..." - ``` - If not set, the skill uses a default test endpoint. - -### Usage - -Once installed and configured, the Foundry Agent skill is automatically available in GitHub Copilot. - -#### Invoking the Skill - -You can invoke the skill by mentioning "Foundry" or "Foundry agent" in your Copilot prompts: - -- "Use the Foundry agent to analyze this code" -- "Ask the Foundry agent what's new in Microsoft Foundry" -- "Query the Foundry agent about cloud architecture best practices" -- "Call the Foundry agent to explain this algorithm" - -#### How It Works - -1. **You make a request** in GitHub Copilot mentioning the Foundry agent -2. **Copilot detects the intent** and loads the `foundry-agent` skill -3. **The skill authenticates** using Azure DefaultAzureCredential -4. **Sends your prompt** to the configured Foundry Agent endpoint -5. **Returns the response** from the Foundry Agent back to you in Copilot - -## Skill Implementation - -The skill is implemented as a GitHub Copilot Agent Skill located in `.github/skills/foundry-agent/SKILL.md`. - -### Key Features - -- **Azure Authentication**: Uses `DefaultAzureCredential` for secure, passwordless authentication -- **Configurable Endpoint**: Support for custom Foundry Agent endpoints via environment variable -- **Error Handling**: Robust error handling with descriptive error messages -- **Conversation Context**: Optional conversation ID parameter for multi-turn conversations -- **Timeout Protection**: 120-second timeout to prevent hanging requests - -## How It Works - -1. User makes a request in GitHub Copilot -2. Copilot detects the request matches the Foundry Agent skill -3. The skill sends the prompt to the configured Foundry Agent endpoint -4. The Foundry Agent processes the request and returns a response -5. Copilot displays the response to the user - -## Contributing - -Contributions are welcome! Please feel free to submit issues or pull requests. - -## Resources - -- [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) -- [GitHub Copilot Agent Skills Documentation](https://code.visualstudio.com/docs/copilot/customization/agent-skills) -- [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp) - -## License - -See LICENSE file for details. diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 205ffe5..0000000 --- a/examples/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Foundry Agent Examples - -This directory contains practical examples demonstrating how to call Microsoft Foundry Agent applications from different programming languages. - -## Available Examples - -### Python Example (`python_example.py`) - -A Python implementation using the `requests` library. - -**Prerequisites:** -```bash -pip install requests -``` - -**Usage:** -```bash -# Set environment variables -export FOUNDRY_AGENT_ENDPOINT="https://your-foundry-endpoint.azure.com/chat" -export FOUNDRY_AGENT_API_KEY="your-api-key" - -# Run with example prompts -python examples/python_example.py - -# Run with custom prompt -python examples/python_example.py "What are the latest AI trends?" -``` - -### TypeScript Example (`typescript_example.ts`) - -A TypeScript implementation using `axios`. - -**Prerequisites:** -```bash -npm install axios -npm install --save-dev @types/node typescript ts-node -``` - -**Usage:** -```bash -# Set environment variables -export FOUNDRY_AGENT_ENDPOINT="https://your-foundry-endpoint.azure.com/chat" -export FOUNDRY_AGENT_API_KEY="your-api-key" - -# Run with ts-node -npx ts-node examples/typescript_example.ts - -# Run with custom prompt -npx ts-node examples/typescript_example.ts "What are the latest AI trends?" -``` - -## Configuration - -Both examples support the following environment variables: - -- `FOUNDRY_AGENT_ENDPOINT`: The URL of your Microsoft Foundry Agent endpoint (required) -- `FOUNDRY_AGENT_API_KEY`: The API key for authentication (optional, depends on your setup) - -## Features - -All examples include: - -- ✅ Environment variable configuration -- ✅ Proper error handling -- ✅ Timeout management -- ✅ Authentication support -- ✅ Conversation context tracking (optional) -- ✅ Command-line interface -- ✅ Example prompts for testing - -## Error Handling - -The examples handle common error scenarios: - -- HTTP errors (4xx, 5xx) -- Connection errors -- Timeout errors -- Invalid JSON responses - -## Testing Without a Foundry Agent - -If you don't have a Foundry Agent endpoint set up yet, the examples will: -1. Use a placeholder endpoint -2. Show connection errors (expected behavior) -3. Demonstrate the structure of requests and responses - -This allows you to: -- Review the code structure -- Understand the API interface -- Prepare your integration before the endpoint is ready - -## Next Steps - -1. Deploy a Microsoft Foundry Agent (see [Azure AI Foundry documentation](https://learn.microsoft.com/azure/ai-foundry/)) -2. Configure your endpoint URL and API key -3. Run the examples to test your integration -4. Integrate the code into your GitHub Copilot skill workflow diff --git a/examples/package.json b/examples/package.json deleted file mode 100644 index 53abbbc..0000000 --- a/examples/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "foundry-agent-examples", - "version": "1.0.0", - "description": "Examples for calling Microsoft Foundry Agent from TypeScript/JavaScript", - "main": "typescript_example.ts", - "scripts": { - "start": "ts-node typescript_example.ts", - "build": "tsc typescript_example.ts" - }, - "keywords": [ - "foundry", - "agent", - "copilot", - "microsoft", - "ai" - ], - "author": "", - "license": "MIT", - "dependencies": { - "axios": "^1.6.0" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "typescript": "^5.0.0", - "ts-node": "^10.9.0" - } -} diff --git a/examples/python_example.py b/examples/python_example.py deleted file mode 100755 index 5b8b43d..0000000 --- a/examples/python_example.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -""" -Example script demonstrating how to call a Microsoft Foundry Agent from Python. -This is a practical implementation of the foundry-agent skill. -""" - -import os -import sys -import requests -from typing import Dict, Any, Optional -from azure.identity import DefaultAzureCredential - - -class FoundryAgentClient: - """Client for interacting with Microsoft Foundry Agent endpoints.""" - - # Default scope for Azure AI services - DEFAULT_SCOPE = "https://ai.azure.com/.default" - - def __init__( - self, - endpoint: Optional[str] = None, - credential: Optional[DefaultAzureCredential] = None, - scope: Optional[str] = None - ): - """ - Initialize the Foundry Agent client. - - Args: - endpoint: The Foundry Agent endpoint URL. - If not provided, reads from FOUNDRY_AGENT_ENDPOINT env var. - credential: Azure credential for authentication. - If not provided, uses DefaultAzureCredential. - scope: The token scope for authentication. - Defaults to Azure AI services scope. - """ - self.endpoint = endpoint or os.getenv( - "FOUNDRY_AGENT_ENDPOINT", - "https://bptest-eastus2-1.services.ai.azure.com/api/projects/test-project-1/applications/test-adyada-agent/protocols/openai/responses?api-version=2025-11-15-preview" - ) - self.credential = credential or DefaultAzureCredential() - self.scope = scope or self.DEFAULT_SCOPE - self.session = requests.Session() - - # Set up default headers - self.session.headers.update({ - "Content-Type": "application/json", - }) - - def _get_token(self) -> str: - """Get an access token using DefaultAzureCredential.""" - token = self.credential.get_token(self.scope) - return token.token - - def _update_auth_header(self): - """Update the authorization header with a fresh token.""" - token = self._get_token() - self.session.headers.update({ - "Authorization": f"Bearer {token}" - }) - - def ask( - self, - prompt: str, - conversation_id: Optional[str] = None, - timeout: int = 120 - ) -> Dict[str, Any]: - """ - Send a prompt to the Foundry Agent. - - Args: - prompt: The user's question or request - conversation_id: Optional conversation ID for maintaining context - timeout: Request timeout in seconds - - Returns: - The agent's response as a dictionary - """ - # Use OpenAI-compatible request format for Foundry Agent - payload = { - "input": prompt, - } - - if conversation_id: - payload["previous_response_id"] = conversation_id - - try: - # Refresh the auth token before each request - self._update_auth_header() - - response = self.session.post( - self.endpoint, - json=payload, - timeout=timeout - ) - response.raise_for_status() - return response.json() - except requests.exceptions.HTTPError as e: - error_body = "" - try: - error_body = e.response.text - except: - pass - return { - "error": f"HTTP error: {e.response.status_code}", - "details": str(e), - "response_body": error_body - } - except requests.exceptions.ConnectionError as e: - return { - "error": "Connection error", - "details": "Failed to connect to Foundry Agent endpoint" - } - except requests.exceptions.Timeout as e: - return { - "error": "Timeout error", - "details": f"Request timed out after {timeout} seconds" - } - except requests.exceptions.RequestException as e: - return { - "error": "Request failed", - "details": str(e) - } - except ValueError as e: - return { - "error": "Invalid JSON response", - "details": str(e) - } - - -def main(): - """Main function demonstrating the Foundry Agent client.""" - print("Foundry Agent Client Example") - print("=" * 50) - - # Initialize the client - client = FoundryAgentClient() - - print(f"Endpoint: {client.endpoint}") - print(f"Credential: DefaultAzureCredential") - print() - - # Example prompts - examples = [ - "What are the key trends in cloud computing?", - "Explain the benefits of AI in software development", - "Analyze the impact of automation on productivity" - ] - - # If command line arguments provided, use them as prompts - if len(sys.argv) > 1: - prompt = " ".join(sys.argv[1:]) - print(f"User Prompt: {prompt}") - print("-" * 50) - - result = client.ask(prompt) - - if result.get("error"): - print(f"Error: {result['error']}") - if "details" in result: - print(f"Details: {result['details']}") - if "response_body" in result: - print(f"Response Body: {result['response_body']}") - else: - print("Agent Response:") - import json - print(json.dumps(result, indent=2)) - else: - # Run example prompts - print("Running example prompts:") - print() - - for i, prompt in enumerate(examples, 1): - print(f"{i}. Prompt: {prompt}") - result = client.ask(prompt) - - if "error" in result: - print(f" Error: {result['error']}") - else: - print(f" Response: {result.get('response', result)}") - print() - - -if __name__ == "__main__": - main() diff --git a/examples/requirements.txt b/examples/requirements.txt deleted file mode 100644 index 98cb3b9..0000000 --- a/examples/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests>=2.31.0 -azure-identity>=1.15.0 diff --git a/examples/typescript_example.ts b/examples/typescript_example.ts deleted file mode 100644 index 63189cc..0000000 --- a/examples/typescript_example.ts +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Example script demonstrating how to call a Microsoft Foundry Agent from TypeScript/JavaScript. - * This is a practical implementation of the foundry-agent skill. - */ - -import axios, { AxiosInstance, AxiosError } from 'axios'; - -interface FoundryAgentRequest { - message: string; - conversation_id?: string; -} - -interface FoundryAgentResponse { - response: string; - conversation_id?: string; - metadata?: any; -} - -interface ErrorResponse { - error: string; - details: string; -} - -/** - * Client for interacting with Microsoft Foundry Agent endpoints. - */ -class FoundryAgentClient { - private endpoint: string; - private apiKey?: string; - private client: AxiosInstance; - - /** - * Initialize the Foundry Agent client. - * - * @param endpoint - The Foundry Agent endpoint URL. - * If not provided, reads from FOUNDRY_AGENT_ENDPOINT env var. - * @param apiKey - The API key for authentication. - * If not provided, reads from FOUNDRY_AGENT_API_KEY env var. - */ - constructor(endpoint?: string, apiKey?: string) { - this.endpoint = endpoint || - process.env.FOUNDRY_AGENT_ENDPOINT || - 'https://YOUR-FOUNDRY-ENDPOINT.azure.com/chat'; - this.apiKey = apiKey || process.env.FOUNDRY_AGENT_API_KEY; - - const headers: Record = { - 'Content-Type': 'application/json', - }; - - if (this.apiKey) { - headers['Authorization'] = `Bearer ${this.apiKey}`; - } - - this.client = axios.create({ - baseURL: this.endpoint, - headers, - timeout: 30000, - }); - } - - /** - * Send a prompt to the Foundry Agent. - * - * @param prompt - The user's question or request - * @param conversationId - Optional conversation ID for maintaining context - * @returns The agent's response or an error object - */ - async ask( - prompt: string, - conversationId?: string - ): Promise { - const payload: FoundryAgentRequest = { - message: prompt, - }; - - if (conversationId) { - payload.conversation_id = conversationId; - } - - try { - const response = await this.client.post('', payload); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - const axiosError = error as AxiosError; - if (axiosError.response) { - return { - error: `HTTP error: ${axiosError.response.status}`, - details: axiosError.message, - }; - } else if (axiosError.request) { - return { - error: 'Connection error', - details: 'Failed to connect to Foundry Agent endpoint', - }; - } - } - return { - error: 'Request failed', - details: error instanceof Error ? error.message : String(error), - }; - } - } - - getEndpoint(): string { - return this.endpoint; - } - - hasApiKey(): boolean { - return !!this.apiKey; - } -} - -/** - * Main function demonstrating the Foundry Agent client. - */ -async function main() { - console.log('Foundry Agent Client Example'); - console.log('='.repeat(50)); - - // Initialize the client - const client = new FoundryAgentClient(); - - console.log(`Endpoint: ${client.getEndpoint()}`); - console.log(`API Key configured: ${client.hasApiKey() ? 'Yes' : 'No'}`); - console.log(); - - // Example prompts - const examples = [ - 'What are the key trends in cloud computing?', - 'Explain the benefits of AI in software development', - 'Analyze the impact of automation on productivity', - ]; - - // If command line arguments provided, use them as prompts - const args = process.argv.slice(2); - if (args.length > 0) { - const prompt = args.join(' '); - console.log(`User Prompt: ${prompt}`); - console.log('-'.repeat(50)); - - const result = await client.ask(prompt); - - if ('error' in result) { - console.log(`Error: ${result.error}`); - console.log(`Details: ${result.details}`); - } else { - console.log('Agent Response:'); - console.log(result); - } - } else { - // Run example prompts - console.log('Running example prompts:'); - console.log(); - - for (let i = 0; i < examples.length; i++) { - const prompt = examples[i]; - console.log(`${i + 1}. Prompt: ${prompt}`); - - const result = await client.ask(prompt); - - if ('error' in result) { - console.log(` Error: ${result.error}`); - } else { - console.log(` Response: ${result.response || JSON.stringify(result)}`); - } - console.log(); - } - } -} - -// Run main function if this is the entry point -if (require.main === module) { - main().catch((error) => { - console.error('Unhandled error:', error); - process.exit(1); - }); -} - -export { FoundryAgentClient, FoundryAgentRequest, FoundryAgentResponse, ErrorResponse }; From 2738b66592626843f4798a341bc2f6ce65570883 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Fri, 23 Jan 2026 17:46:37 -0500 Subject: [PATCH 09/11] decreased timeout --- .github/skills/foundry-agent/SKILL.md | 2 +- .github/skills/foundry-agent/query_foundry_agent.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/skills/foundry-agent/SKILL.md b/.github/skills/foundry-agent/SKILL.md index db14461..3aae4d9 100644 --- a/.github/skills/foundry-agent/SKILL.md +++ b/.github/skills/foundry-agent/SKILL.md @@ -82,7 +82,7 @@ if conversation_id: # Send request to Foundry Agent try: - response = requests.post(endpoint, json=payload, headers=headers, timeout=120) + response = requests.post(endpoint, json=payload, headers=headers, timeout=30) response.raise_for_status() result = response.json() diff --git a/.github/skills/foundry-agent/query_foundry_agent.py b/.github/skills/foundry-agent/query_foundry_agent.py index b3e2e3b..b722245 100644 --- a/.github/skills/foundry-agent/query_foundry_agent.py +++ b/.github/skills/foundry-agent/query_foundry_agent.py @@ -49,7 +49,7 @@ def query_foundry_agent(prompt: str, conversation_id: str = None): payload["previous_response_id"] = conversation_id # Send request to Foundry Agent - response = requests.post(endpoint, json=payload, headers=headers, timeout=120) + response = requests.post(endpoint, json=payload, headers=headers, timeout=30) response.raise_for_status() result = response.json() From 311036afe3124c244691b4f2109f9eeea4b5fd1c Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Fri, 23 Jan 2026 17:54:35 -0500 Subject: [PATCH 10/11] fixed the script. --- .github/skills/foundry-agent/SKILL.md | 72 ------------------- .../foundry-agent/query_foundry_agent.py | 18 +++-- 2 files changed, 8 insertions(+), 82 deletions(-) diff --git a/.github/skills/foundry-agent/SKILL.md b/.github/skills/foundry-agent/SKILL.md index 3aae4d9..e848640 100644 --- a/.github/skills/foundry-agent/SKILL.md +++ b/.github/skills/foundry-agent/SKILL.md @@ -48,54 +48,6 @@ Sends a prompt to the configured Microsoft Foundry Agent endpoint. - **prompt** (required): The user's question or request - **conversation_id** (optional): Conversation ID for maintaining context -### Implementation - -```python -import os -import requests -from azure.identity import DefaultAzureCredential - -# Initialize Azure credential -credential = DefaultAzureCredential() - -# Get endpoint from environment (required) -# Example: "https://.services.ai.azure.com/api/projects//applications//protocols/openai/responses?api-version=2025-11-15-preview" -endpoint = os.getenv("FOUNDRY_AGENT_APPLICATION_ENDPOINT") -if not endpoint: - raise ValueError("FOUNDRY_AGENT_APPLICATION_ENDPOINT environment variable is required but not set") - -# Get access token -token = credential.get_token("https://ai.azure.com/.default") - -# Prepare request -headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {token.token}" -} - -payload = { - "input": prompt, -} - -if conversation_id: - payload["previous_response_id"] = conversation_id - -# Send request to Foundry Agent -try: - response = requests.post(endpoint, json=payload, headers=headers, timeout=30) - response.raise_for_status() - result = response.json() - - # Return the response - return result - -except requests.exceptions.RequestException as e: - return { - "error": f"Failed to call Foundry Agent: {str(e)}", - "endpoint": endpoint - } -``` - ## Configuration To use this skill, you need to: @@ -122,30 +74,6 @@ In GitHub Copilot, you can invoke this skill by asking: - "Ask the Foundry agent what's new in Foundry" - "Query the Foundry agent about cloud computing trends" -## Response Format - -The Foundry Agent returns responses in the following format: -```json -{ - "response": "Agent's response text", - "conversation_id": "optional-conversation-id", - "metadata": { - "model": "model-name", - "tokens": 150 - } -} -``` - -## Error Handling - -If the request fails, the skill returns an error object: -```json -{ - "error": "Error description", - "endpoint": "The endpoint that was called" -} -``` - ## Additional Resources - [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) diff --git a/.github/skills/foundry-agent/query_foundry_agent.py b/.github/skills/foundry-agent/query_foundry_agent.py index b722245..bedcb86 100644 --- a/.github/skills/foundry-agent/query_foundry_agent.py +++ b/.github/skills/foundry-agent/query_foundry_agent.py @@ -7,6 +7,7 @@ import os import sys import json +import argparse import requests from azure.identity import DefaultAzureCredential @@ -71,15 +72,15 @@ def query_foundry_agent(prompt: str, conversation_id: str = None): def main(): """Main entry point for the tool when called by GitHub Copilot.""" try: - # Read input parameters from stdin (JSON format) - input_data = json.loads(sys.stdin.read()) + # Parse command-line arguments + parser = argparse.ArgumentParser(description="Query Microsoft Foundry Agent") + parser.add_argument("prompt", help="The user's question or request to send to the Foundry Agent") + parser.add_argument("--conversation_id", "-c", help="Optional conversation ID for maintaining context", default=None) - prompt = input_data.get("prompt") - conversation_id = input_data.get("conversation_id") + args = parser.parse_args() - if not prompt: - print(json.dumps({"error": "Missing required parameter: prompt"})) - sys.exit(1) + prompt = args.prompt + conversation_id = args.conversation_id # Call the Foundry Agent result = query_foundry_agent(prompt, conversation_id) @@ -87,9 +88,6 @@ def main(): # Output result as JSON print(json.dumps(result)) - except json.JSONDecodeError as e: - print(json.dumps({"error": f"Invalid JSON input: {str(e)}"})) - sys.exit(1) except Exception as e: print(json.dumps({"error": f"Tool execution failed: {str(e)}"})) sys.exit(1) From f45e4813b1123c6b60b464f44dac61f664fe1e66 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Fri, 23 Jan 2026 20:03:44 -0500 Subject: [PATCH 11/11] took README changes. --- .gitignore | 40 -------------- README.md | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 40 deletions(-) delete mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 24a33ee..0000000 --- a/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -env/ -venv/ -ENV/ -.venv -pip-log.txt -pip-delete-this-directory.txt -.pytest_cache/ -*.egg-info/ -dist/ -build/ - -# Node -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* -package-lock.json -yarn.lock -*.tsbuildinfo - -# IDEs -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# OS -.DS_Store -Thumbs.db - -# Environment variables -.env -.env.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..666f980 --- /dev/null +++ b/README.md @@ -0,0 +1,153 @@ +# foundry-github-copilot-skill + +This repository contains a GitHub Copilot Agent Skill that enables GitHub Copilot to call a Microsoft Foundry Agent application for advanced AI capabilities. + +## Overview + +The Foundry Agent Skill enables GitHub Copilot to interact with Microsoft Foundry Agent applications for: + +- Complex reasoning and analysis +- Advanced natural language understanding +- Specialized domain knowledge integration +- Custom AI workflows and processing +- Multi-step task orchestration + +## Installation + +### Step 1: Copy the Skill to Your Repository + +Copy the `.github/skills/foundry-agent/` folder to your target repository. + +**macOS/Linux:** +```bash +# From your target repository +mkdir -p .github/skills +cp -r /path/to/foundry-github-copilot-skill/.github/skills/foundry-agent .github/skills/ +``` + +**Windows (PowerShell):** +```powershell +# From your target repository +New-Item -ItemType Directory -Force -Path .github\skills +Copy-Item -Recurse -Path C:\path\to\foundry-github-copilot-skill\.github\skills\foundry-agent -Destination .github\skills\ +``` + +Or manually copy these files to your repository: +``` +your-repo/ +└── .github/ + └── skills/ + └── foundry-agent/ + ├── SKILL.md + └── query_foundry_agent.py +``` + +### Step 2: Install Python Dependencies + +The skill requires Python 3.8+ and the following packages. + +**macOS:** +```bash +# Install Python if needed (using Homebrew) +brew install python + +# Install dependencies +pip3 install requests>=2.31.0 azure-identity>=1.15.0 +``` + +**Windows:** +```powershell +# Install Python from https://www.python.org/downloads/ or using winget +winget install Python.Python.3.11 + +# Install dependencies +pip install requests>=2.31.0 azure-identity>=1.15.0 +``` + +### Step 3: Install and Configure Azure CLI + +**macOS:** +```bash +# Install Azure CLI using Homebrew +brew install azure-cli + +# Sign in to Azure +az login +``` + +**Windows:** +```powershell +# Install Azure CLI using winget +winget install Microsoft.AzureCLI + +# Or download from: https://aka.ms/installazurecliwindows + +# Sign in to Azure +az login +``` + +### Step 4: Configure Azure Authentication + +The skill uses Azure `DefaultAzureCredential` for secure, passwordless authentication. + +```bash +az login +``` + + +### Step 5: Configure Your Foundry Agent Endpoint + +Set the `FOUNDRY_AGENT_APPLICATION_ENDPOINT` environment variable to point to your Foundry Agent. + +**macOS/Linux:** +```bash +export FOUNDRY_AGENT_APPLICATION_ENDPOINT="https://your-project.services.ai.azure.com/api/projects/your-project/applications/your-agent/protocols/openai/responses?api-version=2025-11-15-preview" +``` + +**Windows (PowerShell):** +```powershell +$env:FOUNDRY_AGENT_APPLICATION_ENDPOINT = "https://your-project.services.ai.azure.com/api/projects/your-project/applications/your-agent/protocols/openai/responses?api-version=2025-11-15-preview" +``` + +**Windows (Command Prompt):** +```cmd +set FOUNDRY_AGENT_APPLICATION_ENDPOINT=https://your-project.services.ai.azure.com/api/projects/your-project/applications/your-agent/protocols/openai/responses?api-version=2025-11-15-preview +``` + +## Skill Structure + +``` +.github/skills/foundry-agent/ +├── SKILL.md # Skill definition and metadata +└── query_foundry_agent.py # Python implementation +``` + +## Usage + +Once installed and configured, the Foundry Agent skill is automatically available in GitHub Copilot. + +### Invoking the Skill + +Invoke the skill by mentioning "Foundry" or "Foundry agent" in your Copilot prompts: + +``` +"Use the Foundry agent to analyze this code" +"Ask the Foundry agent what's new in Microsoft Foundry" +"Query the Foundry agent about cloud architecture best practices" +"Call the Foundry agent to explain this algorithm" +``` + +### How It Works + +1. **You make a request** in GitHub Copilot mentioning the Foundry agent +2. **Copilot detects the intent** and loads the `foundry-agent` skill +3. **The skill authenticates** using Azure DefaultAzureCredential +4. **Sends your prompt** to the configured Foundry Agent endpoint +5. **Returns the response** from the Foundry Agent back to you in Copilot + + +## Resources + +- [Microsoft Foundry Documentation](https://learn.microsoft.com/azure/ai-foundry/) +- [GitHub Copilot Agent Skills Documentation](https://code.visualstudio.com/docs/copilot/customization/agent-skills) +- [Foundry Agent Webapp Example](https://github.com/microsoft-foundry/foundry-agent-webapp)