Skip to content
Merged
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: 122 additions & 4 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,32 @@ unsubscribeIdle();
<details>
<summary><strong>Python</strong></summary>

<!-- docs-validate: skip -->
<!-- docs-validate: hidden -->
```python
from copilot import CopilotClient
from copilot.generated.session_events import SessionEvent, SessionEventType

client = CopilotClient()

session = client.create_session({"on_permission_request": lambda req, inv: {"kind": "approved"}})

# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))

# Filter by event type in your handler
def handle_event(event: SessionEvent) -> None:
if event.type == SessionEventType.SESSION_IDLE:
print("Session is idle")
elif event.type == SessionEventType.ASSISTANT_MESSAGE:
print(f"Message: {event.data.content}")

unsubscribe = session.on(handle_event)

# Later, to unsubscribe:
unsubscribe()
Comment on lines +431 to +451
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hidden “full compilable code” Python example calls client.create_session(...) without await, but CopilotClient.create_session is async in the SDK. To keep the hidden block accurate and actually runnable, wrap it in an async main() and use await client.start(), session = await client.create_session(...), and await client.stop() (similar to earlier Python samples in this doc).

Suggested change
from copilot import CopilotClient
from copilot.generated.session_events import SessionEvent, SessionEventType
client = CopilotClient()
session = client.create_session({"on_permission_request": lambda req, inv: {"kind": "approved"}})
# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))
# Filter by event type in your handler
def handle_event(event: SessionEvent) -> None:
if event.type == SessionEventType.SESSION_IDLE:
print("Session is idle")
elif event.type == SessionEventType.ASSISTANT_MESSAGE:
print(f"Message: {event.data.content}")
unsubscribe = session.on(handle_event)
# Later, to unsubscribe:
unsubscribe()
import asyncio
from copilot import CopilotClient
from copilot.generated.session_events import SessionEvent, SessionEventType
async def main() -> None:
client = CopilotClient()
await client.start()
session = await client.create_session(
{"on_permission_request": lambda req, inv: {"kind": "approved"}}
)
# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))
# Filter by event type in your handler
def handle_event(event: SessionEvent) -> None:
if event.type == SessionEventType.SESSION_IDLE:
print("Session is idle")
elif event.type == SessionEventType.ASSISTANT_MESSAGE:
print(f"Message: {event.data.content}")
unsubscribe = session.on(handle_event)
# Later, to unsubscribe:
unsubscribe()
await client.stop()
if __name__ == "__main__":
asyncio.run(main())

Copilot uses AI. Check for mistakes.
```
<!-- /docs-validate: hidden -->

```python
# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))
Expand All @@ -449,7 +474,39 @@ unsubscribe()
<details>
<summary><strong>Go</strong></summary>

<!-- docs-validate: skip -->
<!-- docs-validate: hidden -->
```go
package main

import (
"fmt"

copilot "github.com/github/copilot-sdk/go"
)

func main() {
session := &copilot.Session{}

// Subscribe to all events
unsubscribe := session.On(func(event copilot.SessionEvent) {
fmt.Println("Event:", event.Type)
})

// Filter by event type in your handler
session.On(func(event copilot.SessionEvent) {
if event.Type == "session.idle" {
fmt.Println("Session is idle")
} else if event.Type == "assistant.message" {
fmt.Println("Message:", *event.Data.Content)
}
})

// Later, to unsubscribe:
unsubscribe()
}
```
<!-- /docs-validate: hidden -->

```go
// Subscribe to all events
unsubscribe := session.On(func(event copilot.SessionEvent) {
Expand All @@ -474,7 +531,38 @@ unsubscribe()
<details>
<summary><strong>.NET</strong></summary>

<!-- docs-validate: skip -->
<!-- docs-validate: hidden -->
```csharp
using GitHub.Copilot.SDK;

public static class EventSubscriptionExample
{
public static void Example(CopilotSession session)
{
// Subscribe to all events
var unsubscribe = session.On(ev => Console.WriteLine($"Event: {ev.Type}"));

// Filter by event type using pattern matching
session.On(ev =>
{
switch (ev)
{
case SessionIdleEvent:
Console.WriteLine("Session is idle");
break;
case AssistantMessageEvent msg:
Console.WriteLine($"Message: {msg.Data.Content}");
break;
}
});

// Later, to unsubscribe:
unsubscribe.Dispose();
}
}
```
<!-- /docs-validate: hidden -->

```csharp
// Subscribe to all events
var unsubscribe = session.On(ev => Console.WriteLine($"Event: {ev.Type}"));
Expand Down Expand Up @@ -1227,7 +1315,37 @@ session = await client.create_session({"on_permission_request": PermissionHandle
<details>
<summary><strong>Go</strong></summary>

<!-- docs-validate: skip -->
<!-- docs-validate: hidden -->
```go
package main

import (
"context"
"log"

copilot "github.com/github/copilot-sdk/go"
)

func main() {
ctx := context.Background()

client := copilot.NewClient(&copilot.ClientOptions{
CLIUrl: "localhost:4321",
})

if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()

// Use the client normally
_, _ = client.CreateSession(ctx, &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
Comment on lines +1341 to +1344
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the hidden Go external-server example, the session creation result and error are discarded (_, _ = client.CreateSession(...)). For a “complete” example, it should at least check the error and (if it returns a session) destroy it, otherwise readers may copy/paste a pattern that silently ignores failures/leaks resources.

This issue also appears on line 487 of the same file.

Copilot uses AI. Check for mistakes.
}
```
<!-- /docs-validate: hidden -->

```go
import copilot "github.com/github/copilot-sdk/go"

Expand Down
27 changes: 26 additions & 1 deletion scripts/docs-validation/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface CodeBlock {
file: string;
line: number;
skip: boolean;
hidden: boolean;
wrapAsync: boolean;
}

Expand Down Expand Up @@ -58,6 +59,7 @@ function parseMarkdownCodeBlocks(
let blockStartLine = 0;
let skipNext = false;
let wrapAsync = false;
let inHiddenBlock = false;

for (let i = 0; i < lines.length; i++) {
const line = lines[i];
Expand All @@ -71,6 +73,16 @@ function parseMarkdownCodeBlocks(
wrapAsync = true;
continue;
}
if (line.includes("<!-- docs-validate: hidden -->")) {
inHiddenBlock = true;
continue;
}
if (line.includes("<!-- /docs-validate: hidden -->")) {
inHiddenBlock = false;
// Skip the next visible code block since the hidden one replaces it
skipNext = true;
continue;
}

// Start of code block
if (!inCodeBlock && line.startsWith("```")) {
Expand All @@ -92,12 +104,17 @@ function parseMarkdownCodeBlocks(
file: filePath,
line: blockStartLine,
skip: skipNext,
hidden: inHiddenBlock,
wrapAsync: wrapAsync,
});
inCodeBlock = false;
currentLang = "";
currentCode = [];
skipNext = false;
// Only reset skipNext when NOT in a hidden block — hidden blocks
// can contain multiple code fences that all get validated.
if (!inHiddenBlock) {
skipNext = false;
}
wrapAsync = false;
continue;
}
Expand Down Expand Up @@ -358,6 +375,7 @@ async function main() {
const langCounts = new Map<string, number>();
let totalBlocks = 0;
let skippedBlocks = 0;
let hiddenBlocks = 0;

for (const mdFile of mdFiles) {
const fullPath = path.join(DOCS_DIR, mdFile);
Expand All @@ -370,6 +388,10 @@ async function main() {
continue;
}

if (block.hidden) {
hiddenBlocks++;
}

// Skip empty or trivial blocks
if (block.code.trim().length < 10) {
continue;
Expand Down Expand Up @@ -426,6 +448,9 @@ async function main() {
if (skippedBlocks > 0) {
console.log(` Skipped ${skippedBlocks}`);
}
if (hiddenBlocks > 0) {
console.log(` Hidden ${hiddenBlocks}`);
}
console.log(`\nOutput: ${OUTPUT_DIR}`);
}

Expand Down
9 changes: 9 additions & 0 deletions scripts/docs-validation/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,15 @@ async function main() {
console.log(" 3. Re-run: npm run validate");
console.log("\nTo skip a code block, add before it:");
console.log(" <!-- docs-validate: skip -->");
console.log("\nTo validate a complete version while showing a snippet:");
console.log(" <!-- docs-validate: hidden -->");
console.log(" ```lang");
console.log(" // full compilable code");
console.log(" ```");
console.log(" <!-- /docs-validate: hidden -->");
console.log(" ```lang");
console.log(" // visible snippet (auto-skipped)");
console.log(" ```");
process.exit(1);
}

Expand Down