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
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ hello.txt
hello.go
memories/
cancellation_demo.txt
developer_instructions
extended_thinking
/developer_instructions
/extended_thinking
graceful_shutdown_demo.txt
personality
service_tier
/personality
/service_tier
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test:

## test-integration: run integration tests
test-integration:
go test -race -tags=integration -timeout=240s -v ./integration/...
go test -race -tags=integration -timeout=600s -v ./integration/...

## clean: remove build artifacts
clean:
Expand Down
75 changes: 75 additions & 0 deletions examples/developer_instructions/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"context"
"fmt"
"log/slog"
"os"
"time"

codexsdk "github.com/ethpandaops/codex-agent-sdk-go"
)

// This example demonstrates WithDeveloperInstructions, which provides
// additional instructions to the agent separately from WithSystemPrompt.
// DeveloperInstructions maps to the "developerInstructions" field in the
// Codex CLI protocol and takes precedence over the systemPrompt mapping.
func main() {
fmt.Println("Developer Instructions Example")
fmt.Println()

logger := slog.New(slog.NewTextHandler(os.Stderr, nil))

client := codexsdk.NewClient()

ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

defer func() {
if err := client.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close client: %v\n", err)
}
}()

if err := client.Start(ctx,
codexsdk.WithLogger(logger),
codexsdk.WithDeveloperInstructions(
"Always respond in exactly three bullet points. "+
"Each bullet point must be a single sentence.",
),
); err != nil {
fmt.Printf("Failed to connect: %v\n", err)

return
}

prompt := "Explain why Go is a good language for backend development."
fmt.Printf("Prompt: %s\n\n", prompt)

if err := client.Query(ctx, codexsdk.Text(prompt)); err != nil {
fmt.Printf("Failed to send query: %v\n", err)

return
}

for msg, err := range client.ReceiveResponse(ctx) {
if err != nil {
fmt.Printf("Error: %v\n", err)

return
}

switch m := msg.(type) {
case *codexsdk.AssistantMessage:
for _, block := range m.Content {
if textBlock, ok := block.(*codexsdk.TextBlock); ok {
fmt.Printf("Codex: %s\n", textBlock.Text)
}
}
case *codexsdk.ResultMessage:
if m.Usage != nil {
fmt.Printf("\nTokens: %d in / %d out\n", m.Usage.InputTokens, m.Usage.OutputTokens)
}
}
}
}
27 changes: 22 additions & 5 deletions examples/extended_thinking/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,26 @@ func displayMessage(msg codexsdk.Message) {
fmt.Printf("Codex: %s\n", b.Text)
}
}
case *codexsdk.SystemMessage:
if (m.Subtype == "item/reasoning/summaryPartAdded" || m.Subtype == "item/reasoning/summaryTextDelta") && m.Data != nil {
if text, ok := m.Data["text"].(string); ok && text != "" {
fmt.Printf("[Reasoning Summary] %s\n", text)
}
case *codexsdk.StreamEvent:
event := m.Event

eventType, _ := event["type"].(string)
if eventType != "content_block_delta" {
return
}

delta, ok := event["delta"].(map[string]any)
if !ok {
return
}

switch delta["type"] {
case "thinking_delta":
thinking, _ := delta["thinking"].(string)
fmt.Print(thinking)
case "text_delta":
text, _ := delta["text"].(string)
fmt.Print(text)
}
case *codexsdk.ResultMessage:
if m.Result != nil && *m.Result != "" {
Expand Down Expand Up @@ -94,6 +109,7 @@ func runEffortExample(title string, effort codexsdk.Effort, prompt string, extra
func runStreamingEffortExample() {
fmt.Println("=== Streaming Reasoning Example ===")
fmt.Println("Streams response events while using high reasoning effort.")
fmt.Println("Thinking deltas appear as [thinking_delta] stream events.")
fmt.Println()

logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
Expand All @@ -110,6 +126,7 @@ func runStreamingEffortExample() {
if err := client.Start(ctx,
codexsdk.WithLogger(logger),
codexsdk.WithEffort(codexsdk.EffortHigh),
codexsdk.WithIncludePartialMessages(true),
); err != nil {
fmt.Printf("Failed to connect: %v\n", err)

Expand Down
6 changes: 5 additions & 1 deletion examples/include_partial_messages/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ func main() {
continue
}

if delta["type"] == "text_delta" {
switch delta["type"] {
case "text_delta":
text, _ := delta["text"].(string)
fmt.Print(text)
case "thinking_delta":
thinking, _ := delta["thinking"].(string)
fmt.Printf("[thinking] %s", thinking)
}

case *codexsdk.AssistantMessage:
Expand Down
101 changes: 101 additions & 0 deletions examples/personality/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package main

import (
"context"
"fmt"
"log/slog"
"os"
"strings"
"time"

codexsdk "github.com/ethpandaops/codex-agent-sdk-go"
)

// This example demonstrates WithPersonality, which controls the agent's
// response style. Valid values are "none", "friendly", and "pragmatic".
func runPersonalityExample(name, personality string) {
fmt.Printf("=== Personality: %s ===\n", name)

logger := slog.New(slog.NewTextHandler(os.Stderr, nil))

client := codexsdk.NewClient()

ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

defer func() {
if err := client.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close client: %v\n", err)
}
}()

if err := client.Start(ctx,
codexsdk.WithLogger(logger),
codexsdk.WithPersonality(personality),
); err != nil {
fmt.Printf("Failed to connect: %v\n", err)

return
}

prompt := "What is a goroutine?"

fmt.Printf("Prompt: %s\n", prompt)
fmt.Println(strings.Repeat("-", 50))

if err := client.Query(ctx, codexsdk.Text(prompt)); err != nil {
fmt.Printf("Failed to send query: %v\n", err)

return
}

for msg, err := range client.ReceiveResponse(ctx) {
if err != nil {
fmt.Printf("Error: %v\n", err)

return
}

switch m := msg.(type) {
case *codexsdk.AssistantMessage:
for _, block := range m.Content {
if textBlock, ok := block.(*codexsdk.TextBlock); ok {
fmt.Printf("Codex: %s\n", textBlock.Text)
}
}
case *codexsdk.ResultMessage:
if m.Usage != nil {
fmt.Printf("\nTokens: %d in / %d out\n", m.Usage.InputTokens, m.Usage.OutputTokens)
}
}
}

fmt.Println()
}

func main() {
fmt.Println("Personality Examples")
fmt.Println("Demonstrating WithPersonality options: none, friendly, pragmatic")
fmt.Println(strings.Repeat("=", 60))
fmt.Println()

personalities := []struct {
name string
value string
}{
{"None (neutral)", "none"},
{"Friendly", "friendly"},
{"Pragmatic", "pragmatic"},
}

example := "all"
if len(os.Args) > 1 {
example = os.Args[1]
}

for _, p := range personalities {
if example == "all" || example == p.value {
runPersonalityExample(p.name, p.value)
}
}
}
107 changes: 107 additions & 0 deletions examples/service_tier/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package main

import (
"context"
"fmt"
"log/slog"
"os"
"strings"
"time"

codexsdk "github.com/ethpandaops/codex-agent-sdk-go"
)

// This example demonstrates WithServiceTier, which controls the API service
// tier for requests. Valid values are "fast" (optimized for speed) and "flex"
// (optimized for cost/throughput).
//
// Note: "flex" tier availability is model-dependent and may not yet be
// supported by all API endpoints. This example demonstrates both tiers
// and shows how unsupported tiers surface errors through the SDK.
func runServiceTierExample(tier string) {
fmt.Printf("=== Service Tier: %s ===\n", tier)

logger := slog.New(slog.NewTextHandler(os.Stderr, nil))

client := codexsdk.NewClient()

ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

defer func() {
if err := client.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close client: %v\n", err)
}
}()

if err := client.Start(ctx,
codexsdk.WithLogger(logger),
codexsdk.WithServiceTier(tier),
); err != nil {
fmt.Printf("Failed to connect: %v\n", err)

return
}

prompt := "What is 2+2? Reply with just the number."
fmt.Printf("Prompt: %s\n", prompt)
fmt.Println(strings.Repeat("-", 50))

if err := client.Query(ctx, codexsdk.Text(prompt)); err != nil {
fmt.Printf("Failed to send query: %v\n", err)

return
}

for msg, err := range client.ReceiveResponse(ctx) {
if err != nil {
fmt.Printf("Error: %v\n", err)

return
}

switch m := msg.(type) {
case *codexsdk.AssistantMessage:
if m.Error != nil {
fmt.Printf("API Error (expected for unsupported tiers):\n")
}

for _, block := range m.Content {
if textBlock, ok := block.(*codexsdk.TextBlock); ok {
fmt.Printf("Codex: %s\n", textBlock.Text)
}
}
case *codexsdk.ResultMessage:
if m.Usage != nil {
fmt.Printf("\nTokens: %d in / %d out\n", m.Usage.InputTokens, m.Usage.OutputTokens)
}
}
}

fmt.Println()
}

func main() {
fmt.Println("Service Tier Examples")
fmt.Println("Demonstrating WithServiceTier options: fast, flex")
fmt.Println(strings.Repeat("=", 60))
fmt.Println()

example := "all"
if len(os.Args) > 1 {
example = os.Args[1]
}

switch example {
case "all":
runServiceTierExample("fast")
fmt.Println(strings.Repeat("-", 60))
fmt.Println()
runServiceTierExample("flex")
case "fast", "flex":
runServiceTierExample(example)
default:
fmt.Printf("Unknown tier %q. Valid values: fast, flex, all\n", example)
os.Exit(1)
}
}
Loading
Loading