Skip to content

Commit 9ef0dac

Browse files
authored
Go codegen: per-event-type data structs (#1037)
* Go codegen: per-event-type data structs (fixes #1031) Replace the flat quicktype-generated Data union struct with per-event-type data structs, matching the C# codegen approach. Adding a new session event type can no longer change the struct shape of existing event types. - Replace generateSessionEvents() in scripts/codegen/go.ts with custom codegen that produces 74 per-event data structs, a SessionEventData interface, and custom UnmarshalJSON/MarshalJSON on SessionEvent - Update go/session.go to use idiomatic Go type switches for event dispatch - Update samples, tests, and doc examples for the new API - Add type/const aliases for PermissionRequest, Attachment, and related types to ease migration - Add .gitattributes eol=lf for generated files to prevent cross-platform line ending diffs - Re-enable the codegen-check CI workflow (remove go/generated_session_events.go revert workaround) - Add ui, uri, mime to Go initialisms for correct field naming * Go codegen: use idiomatic Go doc comments on generated types Prefix all generated type comments with the type name per Go convention (e.g., '// SessionStartData session initialization metadata.'). * Revert "Go codegen: use idiomatic Go doc comments on generated types" This reverts commit 8e5423b. * Fix Go code examples in docs, scenarios, and lint warning Update all Go code examples in docs/, test/scenarios/, and one E2E test to use per-event type assertions instead of the old flat event.Data.FieldName pattern. Fix staticcheck SA5011 lint warning in tools_test.go (nil check must precede type assertion).
1 parent 8569d92 commit 9ef0dac

File tree

59 files changed

+3158
-2008
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+3158
-2008
lines changed

.gitattributes

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
.github/workflows/*.lock.yml linguist-generated=true merge=ours
1+
.github/workflows/*.lock.yml linguist-generated=true merge=ours
2+
3+
# Generated files — keep LF line endings so codegen output is deterministic across platforms.
4+
nodejs/src/generated/* eol=lf linguist-generated=true
5+
dotnet/src/Generated/* eol=lf linguist-generated=true
6+
python/copilot/generated/* eol=lf linguist-generated=true
7+
go/generated_session_events.go eol=lf linguist-generated=true
8+
go/rpc/generated_rpc.go eol=lf linguist-generated=true

.github/workflows/codegen-check.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ jobs:
4747

4848
- name: Check for uncommitted changes
4949
run: |
50-
# TODO: Remove this when https://github.com/github/copilot-sdk/issues/1031 is fixed
51-
# Exclude go/generated_session_events.go from the check — it was intentionally
52-
# reverted to avoid a breaking DataContent change (see #1031) and will be
53-
# regenerated once that issue is resolved.
54-
git checkout -- go/generated_session_events.go 2>/dev/null || true
5550
if [ -n "$(git status --porcelain)" ]; then
5651
echo "::error::Generated files are out of date. Run 'cd scripts/codegen && npm run generate' and commit the changes."
5752
git diff --stat

docs/auth/byok.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ func main() {
130130
panic(err)
131131
}
132132

133-
fmt.Println(*response.Data.Content)
133+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
134+
fmt.Println(d.Content)
135+
}
134136
}
135137
```
136138

docs/features/custom-agents.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -506,17 +506,17 @@ func main() {
506506
})
507507

508508
session.On(func(event copilot.SessionEvent) {
509-
switch event.Type {
510-
case "subagent.started":
511-
fmt.Printf("▶ Sub-agent started: %s\n", *event.Data.AgentDisplayName)
512-
fmt.Printf(" Description: %s\n", *event.Data.AgentDescription)
513-
fmt.Printf(" Tool call ID: %s\n", *event.Data.ToolCallID)
514-
case "subagent.completed":
515-
fmt.Printf("✅ Sub-agent completed: %s\n", *event.Data.AgentDisplayName)
516-
case "subagent.failed":
517-
fmt.Printf("❌ Sub-agent failed: %s%v\n", *event.Data.AgentDisplayName, event.Data.Error)
518-
case "subagent.selected":
519-
fmt.Printf("🎯 Agent selected: %s\n", *event.Data.AgentDisplayName)
509+
switch d := event.Data.(type) {
510+
case *copilot.SubagentStartedData:
511+
fmt.Printf("▶ Sub-agent started: %s\n", d.AgentDisplayName)
512+
fmt.Printf(" Description: %s\n", d.AgentDescription)
513+
fmt.Printf(" Tool call ID: %s\n", d.ToolCallID)
514+
case *copilot.SubagentCompletedData:
515+
fmt.Printf("✅ Sub-agent completed: %s\n", d.AgentDisplayName)
516+
case *copilot.SubagentFailedData:
517+
fmt.Printf("❌ Sub-agent failed: %s%v\n", d.AgentDisplayName, d.Error)
518+
case *copilot.SubagentSelectedData:
519+
fmt.Printf("🎯 Agent selected: %s\n", d.AgentDisplayName)
520520
}
521521
})
522522

@@ -530,17 +530,17 @@ func main() {
530530

531531
```go
532532
session.On(func(event copilot.SessionEvent) {
533-
switch event.Type {
534-
case "subagent.started":
535-
fmt.Printf("▶ Sub-agent started: %s\n", *event.Data.AgentDisplayName)
536-
fmt.Printf(" Description: %s\n", *event.Data.AgentDescription)
537-
fmt.Printf(" Tool call ID: %s\n", *event.Data.ToolCallID)
538-
case "subagent.completed":
539-
fmt.Printf("✅ Sub-agent completed: %s\n", *event.Data.AgentDisplayName)
540-
case "subagent.failed":
541-
fmt.Printf("❌ Sub-agent failed: %s%v\n", *event.Data.AgentDisplayName, event.Data.Error)
542-
case "subagent.selected":
543-
fmt.Printf("🎯 Agent selected: %s\n", *event.Data.AgentDisplayName)
533+
switch d := event.Data.(type) {
534+
case *copilot.SubagentStartedData:
535+
fmt.Printf("▶ Sub-agent started: %s\n", d.AgentDisplayName)
536+
fmt.Printf(" Description: %s\n", d.AgentDescription)
537+
fmt.Printf(" Tool call ID: %s\n", d.ToolCallID)
538+
case *copilot.SubagentCompletedData:
539+
fmt.Printf("✅ Sub-agent completed: %s\n", d.AgentDisplayName)
540+
case *copilot.SubagentFailedData:
541+
fmt.Printf("❌ Sub-agent failed: %s%v\n", d.AgentDisplayName, d.Error)
542+
case *copilot.SubagentSelectedData:
543+
fmt.Printf("🎯 Agent selected: %s\n", d.AgentDisplayName)
544544
}
545545
})
546546

docs/features/streaming-events.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ func main() {
137137
})
138138

139139
session.On(func(event copilot.SessionEvent) {
140-
if event.Type == "assistant.message_delta" {
141-
fmt.Print(*event.Data.DeltaContent)
140+
if d, ok := event.Data.(*copilot.AssistantMessageDeltaData); ok {
141+
fmt.Print(d.DeltaContent)
142142
}
143143
})
144144
_ = session
@@ -148,8 +148,8 @@ func main() {
148148

149149
```go
150150
session.On(func(event copilot.SessionEvent) {
151-
if event.Type == "assistant.message_delta" {
152-
fmt.Print(*event.Data.DeltaContent)
151+
if d, ok := event.Data.(*copilot.AssistantMessageDeltaData); ok {
152+
fmt.Print(d.DeltaContent)
153153
}
154154
})
155155
```

docs/getting-started.md

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ func main() {
211211
log.Fatal(err)
212212
}
213213

214-
fmt.Println(*response.Data.Content)
214+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
215+
fmt.Println(d.Content)
216+
}
215217
os.Exit(0)
216218
}
217219
```
@@ -406,10 +408,11 @@ func main() {
406408

407409
// Listen for response chunks
408410
session.On(func(event copilot.SessionEvent) {
409-
if event.Type == "assistant.message_delta" {
410-
fmt.Print(*event.Data.DeltaContent)
411-
}
412-
if event.Type == "session.idle" {
411+
switch d := event.Data.(type) {
412+
case *copilot.AssistantMessageDeltaData:
413+
fmt.Print(d.DeltaContent)
414+
case *copilot.SessionIdleData:
415+
_ = d
413416
fmt.Println()
414417
}
415418
})
@@ -604,10 +607,12 @@ func main() {
604607

605608
// Filter by event type in your handler
606609
session.On(func(event copilot.SessionEvent) {
607-
if event.Type == "session.idle" {
610+
switch d := event.Data.(type) {
611+
case *copilot.SessionIdleData:
612+
_ = d
608613
fmt.Println("Session is idle")
609-
} else if event.Type == "assistant.message" {
610-
fmt.Println("Message:", *event.Data.Content)
614+
case *copilot.AssistantMessageData:
615+
fmt.Println("Message:", d.Content)
611616
}
612617
})
613618

@@ -625,10 +630,12 @@ unsubscribe := session.On(func(event copilot.SessionEvent) {
625630

626631
// Filter by event type in your handler
627632
session.On(func(event copilot.SessionEvent) {
628-
if event.Type == "session.idle" {
633+
switch d := event.Data.(type) {
634+
case *copilot.SessionIdleData:
635+
_ = d
629636
fmt.Println("Session is idle")
630-
} else if event.Type == "assistant.message" {
631-
fmt.Println("Message:", *event.Data.Content)
637+
case *copilot.AssistantMessageData:
638+
fmt.Println("Message:", d.Content)
632639
}
633640
})
634641

@@ -897,10 +904,11 @@ func main() {
897904
}
898905

899906
session.On(func(event copilot.SessionEvent) {
900-
if event.Type == "assistant.message_delta" {
901-
fmt.Print(*event.Data.DeltaContent)
902-
}
903-
if event.Type == "session.idle" {
907+
switch d := event.Data.(type) {
908+
case *copilot.AssistantMessageDeltaData:
909+
fmt.Print(d.DeltaContent)
910+
case *copilot.SessionIdleData:
911+
_ = d
904912
fmt.Println()
905913
}
906914
})
@@ -1251,12 +1259,11 @@ func main() {
12511259
}
12521260

12531261
session.On(func(event copilot.SessionEvent) {
1254-
if event.Type == "assistant.message_delta" {
1255-
if event.Data.DeltaContent != nil {
1256-
fmt.Print(*event.Data.DeltaContent)
1257-
}
1258-
}
1259-
if event.Type == "session.idle" {
1262+
switch d := event.Data.(type) {
1263+
case *copilot.AssistantMessageDeltaData:
1264+
fmt.Print(d.DeltaContent)
1265+
case *copilot.SessionIdleData:
1266+
_ = d
12601267
fmt.Println()
12611268
}
12621269
})

docs/setup/bundled-cli.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ func main() {
130130

131131
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
132132
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
133-
fmt.Println(*response.Data.Content)
133+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
134+
fmt.Println(d.Content)
135+
}
134136
}
135137
```
136138
<!-- /docs-validate: hidden -->
@@ -146,7 +148,9 @@ defer client.Stop()
146148

147149
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
148150
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
149-
fmt.Println(*response.Data.Content)
151+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
152+
fmt.Println(d.Content)
153+
}
150154
```
151155

152156
</details>

docs/setup/local-cli.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ func main() {
9191

9292
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
9393
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
94-
fmt.Println(*response.Data.Content)
94+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
95+
fmt.Println(d.Content)
96+
}
9597
}
9698
```
9799
<!-- /docs-validate: hidden -->
@@ -105,7 +107,9 @@ defer client.Stop()
105107

106108
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
107109
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
108-
fmt.Println(*response.Data.Content)
110+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
111+
fmt.Println(d.Content)
112+
}
109113
```
110114

111115
</details>

go/README.md

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,10 @@ func main() {
5757
// Set up event handler
5858
done := make(chan bool)
5959
session.On(func(event copilot.SessionEvent) {
60-
if event.Type == "assistant.message" {
61-
if event.Data.Content != nil && event.Data.Content.String != nil {
62-
fmt.Println(*event.Data.Content.String)
63-
}
64-
}
65-
if event.Type == "session.idle" {
60+
switch d := event.Data.(type) {
61+
case *copilot.AssistantMessageData:
62+
fmt.Println(d.Content)
63+
case *copilot.SessionIdleData:
6664
close(done)
6765
}
6866
})
@@ -404,30 +402,22 @@ func main() {
404402
done := make(chan bool)
405403

406404
session.On(func(event copilot.SessionEvent) {
407-
if event.Type == "assistant.message_delta" {
405+
switch d := event.Data.(type) {
406+
case *copilot.AssistantMessageDeltaData:
408407
// Streaming message chunk - print incrementally
409-
if event.Data.DeltaContent != nil {
410-
fmt.Print(*event.Data.DeltaContent)
411-
}
412-
} else if event.Type == "assistant.reasoning_delta" {
408+
fmt.Print(d.DeltaContent)
409+
case *copilot.AssistantReasoningDeltaData:
413410
// Streaming reasoning chunk (if model supports reasoning)
414-
if event.Data.DeltaContent != nil {
415-
fmt.Print(*event.Data.DeltaContent)
416-
}
417-
} else if event.Type == "assistant.message" {
411+
fmt.Print(d.DeltaContent)
412+
case *copilot.AssistantMessageData:
418413
// Final message - complete content
419414
fmt.Println("\n--- Final message ---")
420-
if event.Data.Content != nil && event.Data.Content.String != nil {
421-
fmt.Println(*event.Data.Content.String)
422-
}
423-
} else if event.Type == "assistant.reasoning" {
415+
fmt.Println(d.Content)
416+
case *copilot.AssistantReasoningData:
424417
// Final reasoning content (if model supports reasoning)
425418
fmt.Println("--- Reasoning ---")
426-
if event.Data.Content != nil && event.Data.Content.String != nil {
427-
fmt.Println(*event.Data.Content.String)
428-
}
429-
}
430-
if event.Type == "session.idle" {
419+
fmt.Println(d.Content)
420+
case *copilot.SessionIdleData:
431421
close(done)
432422
}
433423
})

go/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
// }
2121
//
2222
// session.On(func(event copilot.SessionEvent) {
23-
// if event.Type == "assistant.message" {
24-
// fmt.Println(event.Data.Content)
23+
// if d, ok := event.Data.(*copilot.AssistantMessageData); ok {
24+
// fmt.Println(d.Content)
2525
// }
2626
// })
2727
//

0 commit comments

Comments
 (0)