Moving the copilot-sdk cookbook content in here

This commit is contained in:
Aaron Powell
2026-01-29 14:29:36 +11:00
parent ccdfd66cc2
commit f59e0b4080
53 changed files with 5385 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
# GitHub Copilot SDK Cookbook — Python
This folder hosts short, practical recipes for using the GitHub Copilot SDK with Python. Each recipe is concise, copypasteable, and points to fuller examples and tests.
## Recipes
- [Error Handling](error-handling.md): Handle errors gracefully including connection failures, timeouts, and cleanup.
- [Multiple Sessions](multiple-sessions.md): Manage multiple independent conversations simultaneously.
- [Managing Local Files](managing-local-files.md): Organize files by metadata using AI-powered grouping strategies.
- [PR Visualization](pr-visualization.md): Generate interactive PR age charts using GitHub MCP Server.
- [Persisting Sessions](persisting-sessions.md): Save and resume sessions across restarts.
## Contributing
Add a new recipe by creating a markdown file in this folder and linking it above. Follow repository guidance in [CONTRIBUTING.md](../../CONTRIBUTING.md).
## Status
This README is a scaffold; recipe files are placeholders until populated.

View File

@@ -0,0 +1,150 @@
# Error Handling Patterns
Handle errors gracefully in your Copilot SDK applications.
> **Runnable example:** [recipe/error_handling.py](recipe/error_handling.py)
>
> ```bash
> cd recipe && pip install -r requirements.txt
> python error_handling.py
> ```
## Example scenario
You need to handle various error conditions like connection failures, timeouts, and invalid responses.
## Basic try-except
```python
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()
```
## Handling specific error types
```python
import subprocess
try:
client.start()
except FileNotFoundError:
print("Copilot CLI not found. Please install it first.")
except ConnectionError:
print("Could not connect to Copilot CLI server.")
except Exception as e:
print(f"Unexpected error: {e}")
```
## Timeout handling
```python
import signal
from contextlib import contextmanager
@contextmanager
def timeout(seconds):
def timeout_handler(signum, frame):
raise TimeoutError("Request timed out")
old_handler = signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, old_handler)
session = client.create_session(model="gpt-5")
try:
session.send(prompt="Complex question...")
# Wait with timeout (30 seconds)
with timeout(30):
session.wait_for_idle()
print("Response received")
except TimeoutError:
print("Request timed out")
```
## Aborting a request
```python
import threading
session = client.create_session(model="gpt-5")
# Start a request
session.send(prompt="Write a very long story...")
# Abort it after some condition
def abort_later():
import time
time.sleep(5)
session.abort()
print("Request aborted")
threading.Thread(target=abort_later).start()
```
## Graceful shutdown
```python
import signal
import sys
def signal_handler(sig, frame):
print("\nShutting down...")
errors = client.stop()
if errors:
print(f"Cleanup errors: {errors}")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
```
## Context manager for automatic cleanup
```python
from copilot import CopilotClient
with CopilotClient() as client:
client.start()
session = client.create_session(model="gpt-5")
# ... do work ...
# client.stop() is automatically called when exiting context
```
## Best practices
1. **Always clean up**: Use try-finally or context managers to ensure `stop()` is called
2. **Handle connection errors**: The CLI might not be installed or running
3. **Set appropriate timeouts**: Long-running requests should have timeouts
4. **Log errors**: Capture error details for debugging

View File

@@ -0,0 +1,119 @@
# Grouping Files by Metadata
Use Copilot to intelligently organize files in a folder based on their metadata.
> **Runnable example:** [recipe/managing_local_files.py](recipe/managing_local_files.py)
>
> ```bash
> cd recipe && pip install -r requirements.txt
> python managing_local_files.py
> ```
## Example scenario
You have a folder with many files and want to organize them into subfolders based on metadata like file type, creation date, size, or other attributes. Copilot can analyze the files and suggest or execute a grouping strategy.
## Example code
```python
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
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()
client.stop()
```
## Grouping strategies
### By file extension
```python
# Groups files like:
# images/ -> .jpg, .png, .gif
# documents/ -> .pdf, .docx, .txt
# videos/ -> .mp4, .avi, .mov
```
### By creation date
```python
# Groups files like:
# 2024-01/ -> files created in January 2024
# 2024-02/ -> files created in February 2024
```
### By file size
```python
# Groups files like:
# tiny-under-1kb/
# small-under-1mb/
# medium-under-100mb/
# large-over-100mb/
```
## Dry-run mode
For safety, you can ask Copilot to only preview changes:
```python
session.send(prompt=f"""
Analyze files in "{target_folder}" and show me how you would organize them
by file type. DO NOT move any files - just show me the plan.
""")
```
## Custom grouping with AI analysis
Let Copilot determine the best grouping based on file content:
```python
session.send(prompt=f"""
Look at the files in "{target_folder}" and suggest a logical organization.
Consider:
- File names and what they might contain
- File types and their typical uses
- Date patterns that might indicate projects or events
Propose folder names that are descriptive and useful.
""")
```
## Safety considerations
1. **Confirm before moving**: Ask Copilot to confirm before executing moves
2. **Handle duplicates**: Consider what happens if a file with the same name exists
3. **Preserve originals**: Consider copying instead of moving for important files

View File

@@ -0,0 +1,78 @@
# Working with Multiple Sessions
Manage multiple independent conversations simultaneously.
> **Runnable example:** [recipe/multiple_sessions.py](recipe/multiple_sessions.py)
>
> ```bash
> cd recipe && pip install -r requirements.txt
> python multiple_sessions.py
> ```
## Example scenario
You need to run multiple conversations in parallel, each with its own context and history.
## Python
```python
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")
# 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")
# 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?")
# Clean up all sessions
session1.destroy()
session2.destroy()
session3.destroy()
client.stop()
```
## Custom session IDs
Use custom IDs for easier tracking:
```python
session = client.create_session(
session_id="user-123-chat",
model="gpt-5"
)
print(session.session_id) # "user-123-chat"
```
## Listing sessions
```python
sessions = client.list_sessions()
for session_info in sessions:
print(f"Session: {session_info['sessionId']}")
```
## Deleting sessions
```python
# Delete a specific session
client.delete_session("user-123-chat")
```
## Use cases
- **Multi-user applications**: One session per user
- **Multi-task workflows**: Separate sessions for different tasks
- **A/B testing**: Compare responses from different models

View File

@@ -0,0 +1,83 @@
# Session Persistence and Resumption
Save and restore conversation sessions across application restarts.
## Example scenario
You want users to be able to continue a conversation even after closing and reopening your application.
> **Runnable example:** [recipe/persisting_sessions.py](recipe/persisting_sessions.py)
>
> ```bash
> cd recipe && pip install -r requirements.txt
> python persisting_sessions.py
> ```
### Creating a session with a custom ID
```python
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")
# Session ID is preserved
print(session.session_id) # "user-123-conversation"
# Destroy session but keep data on disk
session.destroy()
client.stop()
```
### Resuming a session
```python
client = CopilotClient()
client.start()
# Resume the previous session
session = client.resume_session("user-123-conversation")
# Previous context is restored
session.send(prompt="What were we discussing?")
session.destroy()
client.stop()
```
### Listing available sessions
```python
sessions = client.list_sessions()
for s in sessions:
print("Session:", s["sessionId"])
```
### Deleting a session permanently
```python
# Remove session and all its data from disk
client.delete_session("user-123-conversation")
```
### Getting session history
```python
messages = session.get_messages()
for msg in messages:
print(f"[{msg['type']}] {msg['data']}")
```
## Best practices
1. **Use meaningful session IDs**: Include user ID or context in the session ID
2. **Handle missing sessions**: Check if a session exists before resuming
3. **Clean up old sessions**: Periodically delete sessions that are no longer needed

View File

@@ -0,0 +1,218 @@
# Generating PR Age Charts
Build an interactive CLI tool that visualizes pull request age distribution for a GitHub repository using Copilot's built-in capabilities.
> **Runnable example:** [recipe/pr_visualization.py](recipe/pr_visualization.py)
>
> ```bash
> cd recipe && pip install -r requirements.txt
> # Auto-detect from current git repo
> python pr_visualization.py
>
> # Specify a repo explicitly
> python pr_visualization.py --repo github/copilot-sdk
> ```
## Example scenario
You want to understand how long PRs have been open in a repository. This tool detects the current Git repo or accepts a repo as input, then lets Copilot fetch PR data via the GitHub MCP Server and generate a chart image.
## Prerequisites
```bash
pip install copilot-sdk
```
## Usage
```bash
# Auto-detect from current git repo
python pr_breakdown.py
# Specify a repo explicitly
python pr_breakdown.py --repo github/copilot-sdk
```
## Full example: pr_breakdown.py
```python
#!/usr/bin/env python3
import subprocess
import sys
import os
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
import re
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()
client.stop()
if __name__ == "__main__":
main()
```
## How it works
1. **Repository detection**: Checks `--repo` flag → git remote → prompts user
2. **No custom tools**: Relies entirely on Copilot CLI's built-in capabilities:
- **GitHub MCP Server** - Fetches PR data from GitHub
- **File tools** - Saves generated chart images
- **Code execution** - Generates charts using Python/matplotlib or other methods
3. **Interactive session**: After initial analysis, user can ask for adjustments
## Why this approach?
| Aspect | Custom Tools | Built-in Copilot |
| --------------- | ----------------- | --------------------------------- |
| Code complexity | High | **Minimal** |
| Maintenance | You maintain | **Copilot maintains** |
| Flexibility | Fixed logic | **AI decides best approach** |
| Chart types | What you coded | **Any type Copilot can generate** |
| Data grouping | Hardcoded buckets | **Intelligent grouping** |

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

View 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()

View 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()

View 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")

View 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()

View 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()

View File

@@ -0,0 +1,2 @@
# Install the local Copilot SDK package in editable mode
github-copilot-sdk