-
Notifications
You must be signed in to change notification settings - Fork 916
Add minimal chat samples for all SDK languages #492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
ee9df36
3d57c5c
9b6fbd8
0cdf409
f7c7c93
f766aba
8d06915
57535b4
393ef10
beb427c
2b5cd6c
bff6d90
e0e11a1
8b11a6c
3e74ff4
dccd8a7
66628ea
79e22d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| using GitHub.Copilot.SDK; | ||
|
|
||
| await using var client = new CopilotClient(); | ||
| await using var session = await client.CreateSessionAsync(); | ||
|
|
||
| using var _ = session.On(evt => | ||
| { | ||
| Console.ForegroundColor = ConsoleColor.Blue; | ||
| switch (evt) | ||
| { | ||
| case AssistantReasoningEvent reasoning: | ||
| Console.WriteLine($"[reasoning: {reasoning.Data.Content}]"); | ||
| break; | ||
| case ToolExecutionStartEvent tool: | ||
| Console.WriteLine($"[tool: {tool.Data.ToolName}]"); | ||
| break; | ||
| } | ||
| Console.ResetColor(); | ||
| }); | ||
|
|
||
| Console.WriteLine("Chat with Copilot (Ctrl+C to exit)\n"); | ||
|
|
||
| while (true) | ||
| { | ||
| Console.Write("You: "); | ||
| var input = Console.ReadLine()?.Trim(); | ||
| if (string.IsNullOrEmpty(input)) continue; | ||
| Console.WriteLine(); | ||
|
|
||
| var reply = await session.SendAndWaitAsync(new MessageOptions { Prompt = input }); | ||
| Console.WriteLine($"\nAssistant: {reply?.Data.Content}\n"); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <ProjectReference Include="..\src\GitHub.Copilot.SDK.csproj" /> | ||
| </ItemGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "bufio" | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
|
|
||
| "github.com/github/copilot-sdk/go" | ||
| ) | ||
|
|
||
| const blue = "\033[34m" | ||
| const reset = "\033[0m" | ||
|
|
||
| func main() { | ||
| ctx := context.Background() | ||
| client := copilot.NewClient(nil) | ||
| if err := client.Start(ctx); err != nil { | ||
| panic(err) | ||
| } | ||
| defer client.Stop() | ||
|
|
||
| session, err := client.CreateSession(ctx, nil) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
| defer session.Destroy() | ||
|
|
||
| session.On(func(event copilot.SessionEvent) { | ||
| var output string | ||
| switch event.Type { | ||
| case copilot.AssistantReasoning: | ||
| if event.Data.Content != nil { | ||
| output = fmt.Sprintf("[reasoning: %s]", *event.Data.Content) | ||
| } | ||
| case copilot.ToolExecutionStart: | ||
| if event.Data.ToolName != nil { | ||
| args, _ := json.Marshal(event.Data.Arguments) | ||
| output = fmt.Sprintf("[tool: %s %s]", *event.Data.ToolName, args) | ||
| } | ||
| } | ||
| if output != "" { | ||
| fmt.Printf("%s%s%s\n", blue, output, reset) | ||
| } | ||
| }) | ||
|
|
||
| fmt.Println("Chat with Copilot (Ctrl+C to exit)\n") | ||
| scanner := bufio.NewScanner(os.Stdin) | ||
|
|
||
| for { | ||
| fmt.Print("You: ") | ||
| if !scanner.Scan() { | ||
| break | ||
| } | ||
| input := strings.TrimSpace(scanner.Text()) | ||
| if input == "" { | ||
| continue | ||
| } | ||
| fmt.Println() | ||
|
|
||
| reply, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: input}) | ||
| content := "" | ||
| if reply != nil && reply.Data.Content != nil { | ||
| content = *reply.Data.Content | ||
| } | ||
| fmt.Printf("\nAssistant: %s\n\n", content) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| module github.com/github/copilot-sdk/go/samples | ||
|
|
||
| go 1.24 | ||
|
|
||
| require github.com/github/copilot-sdk/go v0.0.0 | ||
|
|
||
| require github.com/google/jsonschema-go v0.4.2 // indirect | ||
|
|
||
| replace github.com/github/copilot-sdk/go => ../ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= | ||
| github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= | ||
| github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= | ||
| github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,6 +10,16 @@ TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC. | |||||||||||||
| npm install @github/copilot-sdk | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
| ## Run the Sample | ||||||||||||||
|
|
||||||||||||||
| Try the interactive chat sample (from the repo root): | ||||||||||||||
|
|
||||||||||||||
| ```bash | ||||||||||||||
| cd nodejs/samples | ||||||||||||||
|
||||||||||||||
| cd nodejs/samples | |
| cd nodejs | |
| npm ci | |
| npm run build | |
| cd samples |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import * as readline from "node:readline"; | ||
| import { CopilotClient, type SessionEvent } from "@github/copilot-sdk"; | ||
|
|
||
| async function main() { | ||
| const client = new CopilotClient(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cross-SDK Inconsistency - Missing Cleanup: The Node.js sample doesn't close/cleanup the client, which may leave the CLI subprocess running. For consistency with other SDKs and proper resource management, consider adding cleanup. While Node.js doesn't have a built-in disposal pattern like .NET's
process.on('SIGINT', async () => {
await session.destroy();
await client.stop();
process.exit();
});
Note: Go uses explicit
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cross-SDK Consistency Issue: The Node.js sample doesn't call any start method on the client, while Python calls For consistency, if Node.js clients don't require an explicit start call (auto-start on first use), this should be documented. Alternatively, if Node.js supports a
|
||
| const session = await client.createSession(); | ||
|
|
||
| session.on((event: SessionEvent) => { | ||
| let output: string | null = null; | ||
| if (event.type === "assistant.reasoning") { | ||
| output = `[reasoning: ${event.data.content}]`; | ||
| } else if (event.type === "tool.execution_start") { | ||
| output = `[tool: ${event.data.toolName} ${JSON.stringify(event.data.arguments)}]`; | ||
| } | ||
| if (output) console.log(`\x1b[34m${output}\x1b[0m`); | ||
| }); | ||
|
|
||
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | ||
| const prompt = (q: string) => new Promise<string>((r) => rl.question(q, r)); | ||
|
|
||
| console.log("Chat with Copilot (Ctrl+C to exit)\n"); | ||
|
|
||
| while (true) { | ||
| const input = await prompt("You: "); | ||
| if (!input.trim()) continue; | ||
| console.log(); | ||
|
|
||
| const reply = await session.sendAndWait({ prompt: input }); | ||
| console.log(`\nAssistant: ${reply?.data.content}\n`); | ||
| } | ||
| } | ||
|
|
||
| main().catch(console.error); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cross-SDK Consistency Issue: The Node.js sample lacks resource cleanup, while:
Consider adding cleanup in a try-finally block or using signal handlers for graceful shutdown to match the cleanup patterns in other SDKs.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| "name": "copilot-sdk-sample", | ||
| "type": "module", | ||
| "scripts": { | ||
| "start": "npx tsx chat.ts" | ||
| }, | ||
| "dependencies": { | ||
| "@github/copilot-sdk": "file:.." | ||
| }, | ||
|
Comment on lines
+7
to
+9
|
||
| "devDependencies": { | ||
| "tsx": "^4.20.6", | ||
| "@types/node": "^22.0.0" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import asyncio | ||
| import json | ||
| from copilot import CopilotClient | ||
|
|
||
| BLUE = "\033[34m" | ||
| RESET = "\033[0m" | ||
|
|
||
|
|
||
| async def main(): | ||
| async with CopilotClient() as client: | ||
|
||
| session = await client.create_session() | ||
|
|
||
| def on_event(event): | ||
| output = None | ||
| if event.type == "assistant.reasoning": | ||
| output = f"[reasoning: {event.data.content}]" | ||
| elif event.type == "tool.execution_start": | ||
| output = f"[tool: {event.data.tool_name} {json.dumps(event.data.arguments)}]" | ||
| if output: | ||
| print(f"{BLUE}{output}{RESET}") | ||
|
|
||
| session.on(on_event) | ||
|
|
||
| print("Chat with Copilot (Ctrl+C to exit)\n") | ||
|
|
||
| while True: | ||
| user_input = input("You: ").strip() | ||
| if not user_input: | ||
| continue | ||
| print() | ||
|
|
||
| reply = await session.send_and_wait({"prompt": user_input}) | ||
| print(f"\nAssistant: {reply.data.content if reply else None}\n") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| try: | ||
| asyncio.run(main()) | ||
| except KeyboardInterrupt: | ||
| print("\nBye!") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cross-SDK Consistency Issue: The Python sample lacks resource cleanup. According to the memory, Python CopilotClient must be started/stopped explicitly. For consistency with Go (which uses async def main():
client = CopilotClient()
try:
await client.start()
session = await client.create_session()
# ... rest of code ...
finally:
await client.stop()This ensures proper cleanup when the user presses Ctrl+C.
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor inconsistency: Missing tool arguments in output
The .NET sample only logs the tool name, while the Node.js, Python, and Go samples all include the tool arguments in their output.
For consistency across all SDK samples, consider adding the arguments:
This would match the pattern in:
`[tool: ${event.data.toolName} ${JSON.stringify(event.data.arguments)}]`f"[tool: {event.data.tool_name} {json.dumps(event.data.arguments)}]"fmt.Sprintf("[tool: %s %s]", *event.Data.ToolName, args)