mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
Add SDK features to all Ralph loop recipes
- Add WorkingDirectory/working_directory to pin sessions to project root - Add OnPermissionRequest/on_permission_request for unattended operation - Add tool execution event logging for visibility - Add See Also cross-links to error-handling and persisting-sessions - Add best practices for WorkingDirectory and permission auto-approval - Consistent across all 4 languages (Node.js, Python, .NET, Go)
This commit is contained in:
@@ -119,13 +119,24 @@ try
|
|||||||
|
|
||||||
// Fresh session — each task gets full context budget
|
// Fresh session — each task gets full context budget
|
||||||
var session = await client.CreateSessionAsync(
|
var session = await client.CreateSessionAsync(
|
||||||
new SessionConfig { Model = "claude-sonnet-4.5" });
|
new SessionConfig
|
||||||
|
{
|
||||||
|
Model = "claude-sonnet-4.5",
|
||||||
|
// Pin the agent to the project directory
|
||||||
|
WorkingDirectory = Environment.CurrentDirectory,
|
||||||
|
// Auto-approve tool calls for unattended operation
|
||||||
|
OnPermissionRequest = (_, _) => Task.FromResult(
|
||||||
|
new PermissionRequestResult { Kind = "approved" }),
|
||||||
|
});
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var done = new TaskCompletionSource<string>();
|
var done = new TaskCompletionSource<string>();
|
||||||
session.On(evt =>
|
session.On(evt =>
|
||||||
{
|
{
|
||||||
if (evt is AssistantMessageEvent msg)
|
// Log tool usage for visibility
|
||||||
|
if (evt is ToolExecutionStartEvent toolStart)
|
||||||
|
Console.WriteLine($" ⚙ {toolStart.Data.ToolName}");
|
||||||
|
else if (evt is AssistantMessageEvent msg)
|
||||||
done.TrySetResult(msg.Data.Content);
|
done.TrySetResult(msg.Data.Content);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -224,6 +235,8 @@ dotnet build
|
|||||||
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
||||||
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
||||||
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
||||||
|
9. **Set `WorkingDirectory`**: Pin the session to your project root so tool operations resolve paths correctly
|
||||||
|
10. **Auto-approve permissions**: Use `OnPermissionRequest` to allow tool calls without interrupting the loop
|
||||||
|
|
||||||
## When to Use a Ralph Loop
|
## When to Use a Ralph Loop
|
||||||
|
|
||||||
@@ -238,3 +251,8 @@ dotnet build
|
|||||||
- One-shot operations that don't benefit from iteration
|
- One-shot operations that don't benefit from iteration
|
||||||
- Vague requirements without testable acceptance criteria
|
- Vague requirements without testable acceptance criteria
|
||||||
- Exploratory prototyping where direction isn't clear
|
- Exploratory prototyping where direction isn't clear
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions
|
||||||
|
- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts
|
||||||
|
|||||||
@@ -43,14 +43,25 @@ try
|
|||||||
|
|
||||||
// Fresh session — each task gets full context budget
|
// Fresh session — each task gets full context budget
|
||||||
var session = await client.CreateSessionAsync(
|
var session = await client.CreateSessionAsync(
|
||||||
new SessionConfig { Model = "claude-sonnet-4.5" });
|
new SessionConfig
|
||||||
|
{
|
||||||
|
Model = "claude-sonnet-4.5",
|
||||||
|
// Pin the agent to the project directory
|
||||||
|
WorkingDirectory = Environment.CurrentDirectory,
|
||||||
|
// Auto-approve tool calls for unattended operation
|
||||||
|
OnPermissionRequest = (_, _) => Task.FromResult(
|
||||||
|
new PermissionRequestResult { Kind = "approved" }),
|
||||||
|
});
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var done = new TaskCompletionSource<string>();
|
var done = new TaskCompletionSource<string>();
|
||||||
session.On(evt =>
|
session.On(evt =>
|
||||||
{
|
{
|
||||||
if (evt is AssistantMessageEvent msg)
|
// Log tool usage for visibility
|
||||||
|
if (evt is ToolExecutionStartEvent toolStart)
|
||||||
|
Console.WriteLine($" ⚙ {toolStart.Data.ToolName}");
|
||||||
|
else if (evt is AssistantMessageEvent msg)
|
||||||
done.TrySetResult(msg.Data.Content);
|
done.TrySetResult(msg.Data.Content);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
copilot "github.com/github/copilot-sdk/go"
|
copilot "github.com/github/copilot-sdk/go"
|
||||||
)
|
)
|
||||||
@@ -127,6 +128,8 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error {
|
|||||||
}
|
}
|
||||||
defer client.Stop()
|
defer client.Stop()
|
||||||
|
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
fmt.Println(strings.Repeat("━", 40))
|
fmt.Println(strings.Repeat("━", 40))
|
||||||
fmt.Printf("Mode: %s\n", mode)
|
fmt.Printf("Mode: %s\n", mode)
|
||||||
fmt.Printf("Prompt: %s\n", promptFile)
|
fmt.Printf("Prompt: %s\n", promptFile)
|
||||||
@@ -141,14 +144,24 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error {
|
|||||||
for i := 1; i <= maxIterations; i++ {
|
for i := 1; i <= maxIterations; i++ {
|
||||||
fmt.Printf("\n=== Iteration %d/%d ===\n", i, maxIterations)
|
fmt.Printf("\n=== Iteration %d/%d ===\n", i, maxIterations)
|
||||||
|
|
||||||
// Fresh session — each task gets full context budget
|
|
||||||
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
|
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
|
||||||
Model: "claude-sonnet-4.5",
|
Model: "claude-sonnet-4.5",
|
||||||
|
WorkingDirectory: cwd,
|
||||||
|
OnPermissionRequest: func(_ copilot.PermissionRequest, _ map[string]string) copilot.PermissionRequestResult {
|
||||||
|
return copilot.PermissionRequestResult{Kind: "approved"}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log tool usage for visibility
|
||||||
|
session.On(func(event copilot.Event) {
|
||||||
|
if te, ok := event.(copilot.ToolExecutionStartEvent); ok {
|
||||||
|
fmt.Printf(" ⚙ %s\n", te.Data.ToolName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
_, err = session.SendAndWait(ctx, copilot.MessageOptions{
|
_, err = session.SendAndWait(ctx, copilot.MessageOptions{
|
||||||
Prompt: string(prompt),
|
Prompt: string(prompt),
|
||||||
})
|
})
|
||||||
@@ -258,6 +271,8 @@ go build ./...
|
|||||||
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
||||||
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
||||||
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
||||||
|
9. **Set `WorkingDirectory`**: Pin the session to your project root so tool operations resolve paths correctly
|
||||||
|
10. **Auto-approve permissions**: Use `OnPermissionRequest` to allow tool calls without interrupting the loop
|
||||||
|
|
||||||
## When to Use a Ralph Loop
|
## When to Use a Ralph Loop
|
||||||
|
|
||||||
@@ -272,3 +287,8 @@ go build ./...
|
|||||||
- One-shot operations that don't benefit from iteration
|
- One-shot operations that don't benefit from iteration
|
||||||
- Vague requirements without testable acceptance criteria
|
- Vague requirements without testable acceptance criteria
|
||||||
- Exploratory prototyping where direction isn't clear
|
- Exploratory prototyping where direction isn't clear
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions
|
||||||
|
- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error {
|
|||||||
}
|
}
|
||||||
defer client.Stop()
|
defer client.Stop()
|
||||||
|
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
fmt.Println(strings.Repeat("━", 40))
|
fmt.Println(strings.Repeat("━", 40))
|
||||||
fmt.Printf("Mode: %s\n", mode)
|
fmt.Printf("Mode: %s\n", mode)
|
||||||
fmt.Printf("Prompt: %s\n", promptFile)
|
fmt.Printf("Prompt: %s\n", promptFile)
|
||||||
@@ -53,14 +55,24 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error {
|
|||||||
for i := 1; i <= maxIterations; i++ {
|
for i := 1; i <= maxIterations; i++ {
|
||||||
fmt.Printf("\n=== Iteration %d/%d ===\n", i, maxIterations)
|
fmt.Printf("\n=== Iteration %d/%d ===\n", i, maxIterations)
|
||||||
|
|
||||||
// Fresh session — each task gets full context budget
|
|
||||||
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
|
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
|
||||||
Model: "claude-sonnet-4.5",
|
Model: "claude-sonnet-4.5",
|
||||||
|
WorkingDirectory: cwd,
|
||||||
|
OnPermissionRequest: func(_ copilot.PermissionRequest, _ map[string]string) copilot.PermissionRequestResult {
|
||||||
|
return copilot.PermissionRequestResult{Kind: "approved"}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create session: %w", err)
|
return fmt.Errorf("failed to create session: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log tool usage for visibility
|
||||||
|
session.On(func(event copilot.Event) {
|
||||||
|
if te, ok := event.(copilot.ToolExecutionStartEvent); ok {
|
||||||
|
fmt.Printf(" ⚙ %s\n", te.Data.ToolName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
_, err = session.SendAndWait(ctx, copilot.MessageOptions{
|
_, err = session.SendAndWait(ctx, copilot.MessageOptions{
|
||||||
Prompt: string(prompt),
|
Prompt: string(prompt),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -99,8 +99,21 @@ async function ralphLoop(mode: Mode, maxIterations: number = 50) {
|
|||||||
for (let i = 1; i <= maxIterations; i++) {
|
for (let i = 1; i <= maxIterations; i++) {
|
||||||
console.log(`\n=== Iteration ${i}/${maxIterations} ===`);
|
console.log(`\n=== Iteration ${i}/${maxIterations} ===`);
|
||||||
|
|
||||||
// Fresh session — each task gets full context budget
|
const session = await client.createSession({
|
||||||
const session = await client.createSession({ model: "claude-sonnet-4.5" });
|
model: "claude-sonnet-4.5",
|
||||||
|
// Pin the agent to the project directory
|
||||||
|
workingDirectory: process.cwd(),
|
||||||
|
// Auto-approve tool calls for unattended operation
|
||||||
|
onPermissionRequest: async () => ({ allow: true }),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log tool usage for visibility
|
||||||
|
session.on((event) => {
|
||||||
|
if (event.type === "tool.execution_start") {
|
||||||
|
console.log(` ⚙ ${event.data.toolName}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await session.sendAndWait({ prompt }, 600_000);
|
await session.sendAndWait({ prompt }, 600_000);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -200,6 +213,8 @@ npm run build
|
|||||||
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
||||||
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
||||||
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
||||||
|
9. **Set `workingDirectory`**: Pin the session to your project root so tool operations resolve paths correctly
|
||||||
|
10. **Auto-approve permissions**: Use `onPermissionRequest` to allow tool calls without interrupting the loop
|
||||||
|
|
||||||
## When to Use a Ralph Loop
|
## When to Use a Ralph Loop
|
||||||
|
|
||||||
@@ -214,3 +229,8 @@ npm run build
|
|||||||
- One-shot operations that don't benefit from iteration
|
- One-shot operations that don't benefit from iteration
|
||||||
- Vague requirements without testable acceptance criteria
|
- Vague requirements without testable acceptance criteria
|
||||||
- Exploratory prototyping where direction isn't clear
|
- Exploratory prototyping where direction isn't clear
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions
|
||||||
|
- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"name": "copilot-sdk-cookbook-recipes",
|
"name": "copilot-sdk-cookbook-recipes",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@github/copilot-sdk": "file:../../src"
|
"@github/copilot-sdk": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.19.7",
|
"@types/node": "^22.19.7",
|
||||||
|
|||||||
@@ -39,9 +39,19 @@ async function ralphLoop(mode: Mode, maxIterations: number) {
|
|||||||
for (let i = 1; i <= maxIterations; i++) {
|
for (let i = 1; i <= maxIterations; i++) {
|
||||||
console.log(`\n=== Iteration ${i}/${maxIterations} ===`);
|
console.log(`\n=== Iteration ${i}/${maxIterations} ===`);
|
||||||
|
|
||||||
// Fresh session — each task gets full context budget
|
|
||||||
const session = await client.createSession({
|
const session = await client.createSession({
|
||||||
model: "claude-sonnet-4.5",
|
model: "claude-sonnet-4.5",
|
||||||
|
// Pin the agent to the project directory
|
||||||
|
workingDirectory: process.cwd(),
|
||||||
|
// Auto-approve tool calls for unattended operation
|
||||||
|
onPermissionRequest: async () => ({ allow: true }),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log tool usage for visibility
|
||||||
|
session.on((event) => {
|
||||||
|
if (event.type === "tool.execution_start") {
|
||||||
|
console.log(` ⚙ ${event.data.toolName}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -108,10 +108,20 @@ async def ralph_loop(mode: str = "build", max_iterations: int = 50):
|
|||||||
for i in range(1, max_iterations + 1):
|
for i in range(1, max_iterations + 1):
|
||||||
print(f"\n=== Iteration {i}/{max_iterations} ===")
|
print(f"\n=== Iteration {i}/{max_iterations} ===")
|
||||||
|
|
||||||
# Fresh session — each task gets full context budget
|
session = await client.create_session(SessionConfig(
|
||||||
session = await client.create_session(
|
model="claude-sonnet-4.5",
|
||||||
SessionConfig(model="claude-sonnet-4.5")
|
# Pin the agent to the project directory
|
||||||
|
working_directory=str(Path.cwd()),
|
||||||
|
# Auto-approve tool calls for unattended operation
|
||||||
|
on_permission_request=lambda _req, _ctx: {"kind": "approved", "rules": []},
|
||||||
|
))
|
||||||
|
|
||||||
|
# Log tool usage for visibility
|
||||||
|
session.on(lambda event:
|
||||||
|
print(f" ⚙ {event.data.tool_name}")
|
||||||
|
if event.type.value == "tool.execution_start" else None
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await session.send_and_wait(
|
await session.send_and_wait(
|
||||||
MessageOptions(prompt=prompt), timeout=600
|
MessageOptions(prompt=prompt), timeout=600
|
||||||
@@ -210,6 +220,8 @@ python -m pytest
|
|||||||
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan
|
||||||
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes
|
||||||
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it
|
||||||
|
9. **Set `working_directory`**: Pin the session to your project root so tool operations resolve paths correctly
|
||||||
|
10. **Auto-approve permissions**: Use `on_permission_request` to allow tool calls without interrupting the loop
|
||||||
|
|
||||||
## When to Use a Ralph Loop
|
## When to Use a Ralph Loop
|
||||||
|
|
||||||
@@ -224,3 +236,8 @@ python -m pytest
|
|||||||
- One-shot operations that don't benefit from iteration
|
- One-shot operations that don't benefit from iteration
|
||||||
- Vague requirements without testable acceptance criteria
|
- Vague requirements without testable acceptance criteria
|
||||||
- Exploratory prototyping where direction isn't clear
|
- Exploratory prototyping where direction isn't clear
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions
|
||||||
|
- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts
|
||||||
|
|||||||
@@ -43,10 +43,23 @@ async def ralph_loop(mode: str = "build", max_iterations: int = 50):
|
|||||||
for i in range(1, max_iterations + 1):
|
for i in range(1, max_iterations + 1):
|
||||||
print(f"\n=== Iteration {i}/{max_iterations} ===")
|
print(f"\n=== Iteration {i}/{max_iterations} ===")
|
||||||
|
|
||||||
# Fresh session — each task gets full context budget
|
session = await client.create_session(SessionConfig(
|
||||||
session = await client.create_session(
|
model="claude-sonnet-4.5",
|
||||||
SessionConfig(model="claude-sonnet-4.5")
|
# Pin the agent to the project directory
|
||||||
|
working_directory=str(Path.cwd()),
|
||||||
|
# Auto-approve tool calls for unattended operation
|
||||||
|
on_permission_request=lambda _req, _ctx: {
|
||||||
|
"kind": "approved",
|
||||||
|
"rules": [],
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
# Log tool usage for visibility
|
||||||
|
session.on(lambda event:
|
||||||
|
print(f" ⚙ {event.data.tool_name}")
|
||||||
|
if event.type.value == "tool.execution_start" else None
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await session.send_and_wait(
|
await session.send_and_wait(
|
||||||
MessageOptions(prompt=prompt), timeout=600
|
MessageOptions(prompt=prompt), timeout=600
|
||||||
|
|||||||
Reference in New Issue
Block a user