mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-21 19:05:13 +00:00
Moving the copilot-sdk cookbook content in here
This commit is contained in:
92
cookbook/copilot-sdk/python/recipe/README.md
Normal file
92
cookbook/copilot-sdk/python/recipe/README.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Runnable Recipe Examples
|
||||
|
||||
This folder contains standalone, executable Python examples for each cookbook recipe. Each file can be run directly as a Python script.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.8 or later
|
||||
- Install dependencies (this installs the local SDK in editable mode):
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Running Examples
|
||||
|
||||
Each `.py` file is a complete, runnable program with executable permissions:
|
||||
|
||||
```bash
|
||||
python <filename>.py
|
||||
# or on Unix-like systems:
|
||||
./<filename>.py
|
||||
```
|
||||
|
||||
### Available Recipes
|
||||
|
||||
| Recipe | Command | Description |
|
||||
| -------------------- | -------------------------------- | ------------------------------------------ |
|
||||
| Error Handling | `python error_handling.py` | Demonstrates error handling patterns |
|
||||
| Multiple Sessions | `python multiple_sessions.py` | Manages multiple independent conversations |
|
||||
| Managing Local Files | `python managing_local_files.py` | Organizes files using AI grouping |
|
||||
| PR Visualization | `python pr_visualization.py` | Generates PR age charts |
|
||||
| Persisting Sessions | `python persisting_sessions.py` | Save and resume sessions across restarts |
|
||||
|
||||
### Examples with Arguments
|
||||
|
||||
**PR Visualization with specific repo:**
|
||||
|
||||
```bash
|
||||
python pr_visualization.py --repo github/copilot-sdk
|
||||
```
|
||||
|
||||
**Managing Local Files (edit the file to change target folder):**
|
||||
|
||||
```bash
|
||||
# Edit the target_folder variable in managing_local_files.py first
|
||||
python managing_local_files.py
|
||||
```
|
||||
|
||||
## Local SDK Development
|
||||
|
||||
The `requirements.txt` installs the local Copilot SDK using `-e ../..` (editable install). This means:
|
||||
|
||||
- Changes to the SDK source are immediately available
|
||||
- No need to publish or install from PyPI
|
||||
- Perfect for testing and development
|
||||
|
||||
If you modify the SDK source, Python will automatically use the updated code (no rebuild needed).
|
||||
|
||||
## Python Best Practices
|
||||
|
||||
These examples follow Python conventions:
|
||||
|
||||
- PEP 8 naming (snake_case for functions and variables)
|
||||
- Shebang line for direct execution
|
||||
- Proper exception handling
|
||||
- Type hints where appropriate
|
||||
- Standard library usage
|
||||
|
||||
## Virtual Environment (Recommended)
|
||||
|
||||
For isolated development:
|
||||
|
||||
```bash
|
||||
# Create virtual environment
|
||||
python -m venv venv
|
||||
|
||||
# Activate it
|
||||
# Windows:
|
||||
venv\Scripts\activate
|
||||
# Unix/macOS:
|
||||
source venv/bin/activate
|
||||
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Learning Resources
|
||||
|
||||
- [Python Documentation](https://docs.python.org/3/)
|
||||
- [PEP 8 Style Guide](https://pep8.org/)
|
||||
- [GitHub Copilot SDK for Python](https://github.com/github/copilot-sdk/blob/main/python/README.md)
|
||||
- [Parent Cookbook](../README.md)
|
||||
28
cookbook/copilot-sdk/python/recipe/error_handling.py
Normal file
28
cookbook/copilot-sdk/python/recipe/error_handling.py
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from copilot import CopilotClient
|
||||
|
||||
client = CopilotClient()
|
||||
|
||||
try:
|
||||
client.start()
|
||||
session = client.create_session(model="gpt-5")
|
||||
|
||||
response = None
|
||||
def handle_message(event):
|
||||
nonlocal response
|
||||
if event["type"] == "assistant.message":
|
||||
response = event["data"]["content"]
|
||||
|
||||
session.on(handle_message)
|
||||
session.send(prompt="Hello!")
|
||||
session.wait_for_idle()
|
||||
|
||||
if response:
|
||||
print(response)
|
||||
|
||||
session.destroy()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
finally:
|
||||
client.stop()
|
||||
42
cookbook/copilot-sdk/python/recipe/managing_local_files.py
Normal file
42
cookbook/copilot-sdk/python/recipe/managing_local_files.py
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from copilot import CopilotClient
|
||||
import os
|
||||
|
||||
# Create and start client
|
||||
client = CopilotClient()
|
||||
client.start()
|
||||
|
||||
# Create session
|
||||
session = client.create_session(model="gpt-5")
|
||||
|
||||
# Event handler
|
||||
def handle_event(event):
|
||||
if event["type"] == "assistant.message":
|
||||
print(f"\nCopilot: {event['data']['content']}")
|
||||
elif event["type"] == "tool.execution_start":
|
||||
print(f" → Running: {event['data']['toolName']}")
|
||||
elif event["type"] == "tool.execution_complete":
|
||||
print(f" ✓ Completed: {event['data']['toolCallId']}")
|
||||
|
||||
session.on(handle_event)
|
||||
|
||||
# Ask Copilot to organize files
|
||||
# Change this to your target folder
|
||||
target_folder = os.path.expanduser("~/Downloads")
|
||||
|
||||
session.send(prompt=f"""
|
||||
Analyze the files in "{target_folder}" and organize them into subfolders.
|
||||
|
||||
1. First, list all files and their metadata
|
||||
2. Preview grouping by file extension
|
||||
3. Create appropriate subfolders (e.g., "images", "documents", "videos")
|
||||
4. Move each file to its appropriate subfolder
|
||||
|
||||
Please confirm before moving any files.
|
||||
""")
|
||||
|
||||
session.wait_for_idle()
|
||||
|
||||
session.destroy()
|
||||
client.stop()
|
||||
35
cookbook/copilot-sdk/python/recipe/multiple_sessions.py
Normal file
35
cookbook/copilot-sdk/python/recipe/multiple_sessions.py
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from copilot import CopilotClient
|
||||
|
||||
client = CopilotClient()
|
||||
client.start()
|
||||
|
||||
# Create multiple independent sessions
|
||||
session1 = client.create_session(model="gpt-5")
|
||||
session2 = client.create_session(model="gpt-5")
|
||||
session3 = client.create_session(model="claude-sonnet-4.5")
|
||||
|
||||
print("Created 3 independent sessions")
|
||||
|
||||
# Each session maintains its own conversation history
|
||||
session1.send(prompt="You are helping with a Python project")
|
||||
session2.send(prompt="You are helping with a TypeScript project")
|
||||
session3.send(prompt="You are helping with a Go project")
|
||||
|
||||
print("Sent initial context to all sessions")
|
||||
|
||||
# Follow-up messages stay in their respective contexts
|
||||
session1.send(prompt="How do I create a virtual environment?")
|
||||
session2.send(prompt="How do I set up tsconfig?")
|
||||
session3.send(prompt="How do I initialize a module?")
|
||||
|
||||
print("Sent follow-up questions to each session")
|
||||
|
||||
# Clean up all sessions
|
||||
session1.destroy()
|
||||
session2.destroy()
|
||||
session3.destroy()
|
||||
client.stop()
|
||||
|
||||
print("All sessions destroyed successfully")
|
||||
36
cookbook/copilot-sdk/python/recipe/persisting_sessions.py
Normal file
36
cookbook/copilot-sdk/python/recipe/persisting_sessions.py
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from copilot import CopilotClient
|
||||
|
||||
client = CopilotClient()
|
||||
client.start()
|
||||
|
||||
# Create session with a memorable ID
|
||||
session = client.create_session(
|
||||
session_id="user-123-conversation",
|
||||
model="gpt-5",
|
||||
)
|
||||
|
||||
session.send(prompt="Let's discuss TypeScript generics")
|
||||
print(f"Session created: {session.session_id}")
|
||||
|
||||
# Destroy session but keep data on disk
|
||||
session.destroy()
|
||||
print("Session destroyed (state persisted)")
|
||||
|
||||
# Resume the previous session
|
||||
resumed = client.resume_session("user-123-conversation")
|
||||
print(f"Resumed: {resumed.session_id}")
|
||||
|
||||
resumed.send(prompt="What were we discussing?")
|
||||
|
||||
# List sessions
|
||||
sessions = client.list_sessions()
|
||||
print("Sessions:", [s["sessionId"] for s in sessions])
|
||||
|
||||
# Delete session permanently
|
||||
client.delete_session("user-123-conversation")
|
||||
print("Session deleted")
|
||||
|
||||
resumed.destroy()
|
||||
client.stop()
|
||||
161
cookbook/copilot-sdk/python/recipe/pr_visualization.py
Normal file
161
cookbook/copilot-sdk/python/recipe/pr_visualization.py
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from copilot import CopilotClient
|
||||
|
||||
# ============================================================================
|
||||
# Git & GitHub Detection
|
||||
# ============================================================================
|
||||
|
||||
def is_git_repo():
|
||||
try:
|
||||
subprocess.run(
|
||||
["git", "rev-parse", "--git-dir"],
|
||||
check=True,
|
||||
capture_output=True
|
||||
)
|
||||
return True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
return False
|
||||
|
||||
def get_github_remote():
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "remote", "get-url", "origin"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
remote_url = result.stdout.strip()
|
||||
|
||||
# Handle SSH: git@github.com:owner/repo.git
|
||||
ssh_match = re.search(r"git@github\.com:(.+/.+?)(?:\.git)?$", remote_url)
|
||||
if ssh_match:
|
||||
return ssh_match.group(1)
|
||||
|
||||
# Handle HTTPS: https://github.com/owner/repo.git
|
||||
https_match = re.search(r"https://github\.com/(.+/.+?)(?:\.git)?$", remote_url)
|
||||
if https_match:
|
||||
return https_match.group(1)
|
||||
|
||||
return None
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
return None
|
||||
|
||||
def parse_args():
|
||||
args = sys.argv[1:]
|
||||
if "--repo" in args:
|
||||
idx = args.index("--repo")
|
||||
if idx + 1 < len(args):
|
||||
return {"repo": args[idx + 1]}
|
||||
return {}
|
||||
|
||||
def prompt_for_repo():
|
||||
return input("Enter GitHub repo (owner/repo): ").strip()
|
||||
|
||||
# ============================================================================
|
||||
# Main Application
|
||||
# ============================================================================
|
||||
|
||||
def main():
|
||||
print("🔍 PR Age Chart Generator\n")
|
||||
|
||||
# Determine the repository
|
||||
args = parse_args()
|
||||
repo = None
|
||||
|
||||
if "repo" in args:
|
||||
repo = args["repo"]
|
||||
print(f"📦 Using specified repo: {repo}")
|
||||
elif is_git_repo():
|
||||
detected = get_github_remote()
|
||||
if detected:
|
||||
repo = detected
|
||||
print(f"📦 Detected GitHub repo: {repo}")
|
||||
else:
|
||||
print("⚠️ Git repo found but no GitHub remote detected.")
|
||||
repo = prompt_for_repo()
|
||||
else:
|
||||
print("📁 Not in a git repository.")
|
||||
repo = prompt_for_repo()
|
||||
|
||||
if not repo or "/" not in repo:
|
||||
print("❌ Invalid repo format. Expected: owner/repo")
|
||||
sys.exit(1)
|
||||
|
||||
owner, repo_name = repo.split("/", 1)
|
||||
|
||||
# Create Copilot client - no custom tools needed!
|
||||
client = CopilotClient(log_level="error")
|
||||
client.start()
|
||||
|
||||
session = client.create_session(
|
||||
model="gpt-5",
|
||||
system_message={
|
||||
"content": f"""
|
||||
<context>
|
||||
You are analyzing pull requests for the GitHub repository: {owner}/{repo_name}
|
||||
The current working directory is: {os.getcwd()}
|
||||
</context>
|
||||
|
||||
<instructions>
|
||||
- Use the GitHub MCP Server tools to fetch PR data
|
||||
- Use your file and code execution tools to generate charts
|
||||
- Save any generated images to the current working directory
|
||||
- Be concise in your responses
|
||||
</instructions>
|
||||
"""
|
||||
}
|
||||
)
|
||||
|
||||
# Set up event handling
|
||||
def handle_event(event):
|
||||
if event["type"] == "assistant.message":
|
||||
print(f"\n🤖 {event['data']['content']}\n")
|
||||
elif event["type"] == "tool.execution_start":
|
||||
print(f" ⚙️ {event['data']['toolName']}")
|
||||
|
||||
session.on(handle_event)
|
||||
|
||||
# Initial prompt - let Copilot figure out the details
|
||||
print("\n📊 Starting analysis...\n")
|
||||
|
||||
session.send(prompt=f"""
|
||||
Fetch the open pull requests for {owner}/{repo_name} from the last week.
|
||||
Calculate the age of each PR in days.
|
||||
Then generate a bar chart image showing the distribution of PR ages
|
||||
(group them into sensible buckets like <1 day, 1-3 days, etc.).
|
||||
Save the chart as "pr-age-chart.png" in the current directory.
|
||||
Finally, summarize the PR health - average age, oldest PR, and how many might be considered stale.
|
||||
""")
|
||||
|
||||
session.wait_for_idle()
|
||||
|
||||
# Interactive loop
|
||||
print("\n💡 Ask follow-up questions or type \"exit\" to quit.\n")
|
||||
print("Examples:")
|
||||
print(" - \"Expand to the last month\"")
|
||||
print(" - \"Show me the 5 oldest PRs\"")
|
||||
print(" - \"Generate a pie chart instead\"")
|
||||
print(" - \"Group by author instead of age\"")
|
||||
print()
|
||||
|
||||
while True:
|
||||
user_input = input("You: ").strip()
|
||||
|
||||
if user_input.lower() in ["exit", "quit"]:
|
||||
print("👋 Goodbye!")
|
||||
break
|
||||
|
||||
if user_input:
|
||||
session.send(prompt=user_input)
|
||||
session.wait_for_idle()
|
||||
|
||||
session.destroy()
|
||||
client.stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
2
cookbook/copilot-sdk/python/recipe/requirements.txt
Normal file
2
cookbook/copilot-sdk/python/recipe/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# Install the local Copilot SDK package in editable mode
|
||||
github-copilot-sdk
|
||||
Reference in New Issue
Block a user