Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 54 additions & 72 deletions cookbook/python/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,46 @@ You need to handle various error conditions like connection failures, timeouts,
## Basic try-except

```python
import asyncio
from copilot import CopilotClient

client = CopilotClient()

try:
client.start()
session = client.create_session(model="gpt-5")

async def main():
client = CopilotClient()
response = None

def handle_message(event):
nonlocal response
if event["type"] == "assistant.message":
response = event["data"]["content"]
if event.type == "assistant.message":
response = event.data.content

session.on(handle_message)
session.send(prompt="Hello!")
session.wait_for_idle()
try:
await client.start()
session = await client.create_session()
session.on(handle_message)

if response:
print(response)
await session.send_and_wait({"prompt": "Hello!"})

session.destroy()
except Exception as e:
print(f"Error: {e}")
finally:
client.stop()
if response:
print(response)

await session.destroy()

except Exception as e:
print(f"Error: {e}")

finally:
await client.stop()


asyncio.run(main())
```

## Handling specific error types

```python
import subprocess

try:
client.start()
await client.start()
except FileNotFoundError:
print("Copilot CLI not found. Please install it first.")
except ConnectionError:
Expand All @@ -61,90 +66,67 @@ except Exception as e:

## Timeout handling

```python
import signal
from contextlib import contextmanager
The SDK's `send_and_wait()` method accepts a timeout parameter:

@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)
```python
import asyncio

session = client.create_session(model="gpt-5")
session = await client.create_session()

try:
session.send(prompt="Complex question...")

# Wait with timeout (30 seconds)
with timeout(30):
session.wait_for_idle()

await session.send_and_wait({"prompt": "Complex question..."}, timeout=30.0)
print("Response received")
except TimeoutError:
except asyncio.TimeoutError:
print("Request timed out")
```

## Aborting a request

```python
import threading
import asyncio

session = client.create_session(model="gpt-5")
session = await client.create_session()

# 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()
async def abort_after_delay():
await asyncio.sleep(5)
await session.abort()
print("Request aborted")

threading.Thread(target=abort_later).start()

# Start the abort task
abort_task = asyncio.create_task(abort_after_delay())

# Send a long request
await session.send({"prompt": "Write a very long story..."})
```

## Graceful shutdown

```python
import asyncio
import signal
import sys

def signal_handler(sig, frame):
client = CopilotClient()


async def shutdown():
print("\nShutting down...")
errors = client.stop()
errors = await 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
# Handle Ctrl+C gracefully
loop = asyncio.get_event_loop()
loop.add_signal_handler(signal.SIGINT, lambda: asyncio.create_task(shutdown()))
```

## Best practices

1. **Always clean up**: Use try-finally or context managers to ensure `stop()` is called
1. **Always clean up**: Use try-finally to ensure `await client.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
3. **Use timeouts**: Pass timeout to `send_and_wait()` for long-running requests
4. **Log errors**: Capture error details for debugging
5. **Use async patterns**: The SDK is fully async - use `asyncio.run()` as entry point
61 changes: 36 additions & 25 deletions cookbook/python/managing-local-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,35 @@ You have a folder with many files and want to organize them into subfolders base
## Example code

```python
from copilot import CopilotClient
import asyncio
import os
from copilot import CopilotClient

# Create and start client
client = CopilotClient()
client.start()

# Create session
session = client.create_session(model="gpt-5")
async def main():
# Create and start client
client = CopilotClient()
await client.start()

# 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']}")
# Create session
session = await client.create_session()

session.on(handle_event)
# 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.tool_name}")
elif event.type == "tool.execution_complete":
print(f" ✓ Completed: {event.data.tool_call_id}")

# Ask Copilot to organize files
target_folder = os.path.expanduser("~/Downloads")
session.on(handle_event)

session.send(prompt=f"""
# Ask Copilot to organize files
target_folder = os.path.expanduser("~/Downloads")

await session.send_and_wait({
"prompt": f"""
Analyze the files in "{target_folder}" and organize them into subfolders.

1. First, list all files and their metadata
Expand All @@ -49,11 +53,14 @@ Analyze the files in "{target_folder}" and organize them into subfolders.
4. Move each file to its appropriate subfolder

Please confirm before moving any files.
""")
"""
})

await session.destroy()
await client.stop()

session.wait_for_idle()

client.stop()
asyncio.run(main())
```

## Grouping strategies
Expand Down Expand Up @@ -90,26 +97,30 @@ client.stop()
For safety, you can ask Copilot to only preview changes:

```python
session.send(prompt=f"""
await session.send_and_wait({
"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"""
await session.send_and_wait({
"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
Expand Down
69 changes: 38 additions & 31 deletions cookbook/python/multiple-sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,59 +16,66 @@ You need to run multiple conversations in parallel, each with its own context an
## Python

```python
import asyncio
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()

async def main():
client = CopilotClient()
await client.start()

# Create multiple independent sessions
session1 = await client.create_session()
session2 = await client.create_session()
session3 = await client.create_session({"model": "claude-sonnet-4"})

# Each session maintains its own conversation history
await session1.send({"prompt": "You are helping with a Python project"})
await session2.send({"prompt": "You are helping with a TypeScript project"})
await session3.send({"prompt": "You are helping with a Go project"})

# Follow-up messages stay in their respective contexts
await session1.send_and_wait({"prompt": "How do I create a virtual environment?"})
await session2.send_and_wait({"prompt": "How do I set up tsconfig?"})
await session3.send_and_wait({"prompt": "How do I initialize a module?"})

# Clean up all sessions
await session1.destroy()
await session2.destroy()
await session3.destroy()
await client.stop()


asyncio.run(main())
```

## Custom session IDs

Use custom IDs for easier tracking:

```python
session = client.create_session(
session_id="user-123-chat",
model="gpt-5"
)
session = await client.create_session({
"session_id": "user-123-chat",
})

print(session.session_id) # "user-123-chat"
```

## Listing sessions

```python
sessions = client.list_sessions()
# List all available sessions
sessions = await client.list_sessions()
for session_info in sessions:
print(f"Session: {session_info['sessionId']}")
print(f"Session: {session_info['session_id']}")
print(f" Modified: {session_info['modified_time']}")
```

## Deleting sessions

```python
# Delete a specific session
client.delete_session("user-123-chat")
# Delete a specific session permanently
await client.delete_session("user-123-chat")
```

## Use cases
Expand Down
Loading
Loading