Amazon Nova S2S on Bedrock
For teams already running infrastructure on AWS, Amazon Nova provides end-to-end voice conversations through AWS Bedrock without introducing a separate vendor. This avoids additional billing relationships, keeps audio data within your AWS account boundary, and leverages existing IAM policies for access control. This guide covers integrating the Amazon Nova S2S provider with Beluga AI for real-time streaming voice interactions.
Overview
Section titled “Overview”The Amazon Nova integration is the voice/s2s/providers/nova package. It registers itself as "nova" with the s2s registry and implements the standard s2s.S2S / s2s.Session interfaces, so the code you write against it is the same as for the OpenAI Realtime and Gemini Live providers.
The provider talks to Bedrock through the InvokeModelWithBidirectionalStream API using aws-sdk-go-v2, so requests are SigV4-signed with your AWS credentials: static keys from Extra["access_key_id"] / Extra["secret_access_key"] (and optional Extra["session_token"]), or the default AWS credential chain when those are absent.
Prerequisites
Section titled “Prerequisites”- Go 1.26 or later
- AWS account with Bedrock access
- Nova 2 Sonic model enabled in Bedrock console
- AWS credentials configured (IAM role or access keys)
Installation
Section titled “Installation”go get github.com/lookatitude/beluga-ai/v2Configure AWS credentials:
export AWS_ACCESS_KEY_ID="your-access-key"export AWS_SECRET_ACCESS_KEY="your-secret-key"export AWS_REGION="us-east-1"Enable the Nova 2 Sonic model in the AWS Bedrock console before proceeding.
Configuration
Section titled “Configuration”Create a Nova engine through the registry and start a session. Instructions and tools go on s2s.Config (or as s2s.Options to Start); the region goes in Extra:
package main
import ( "context" "fmt" "log" "os"
"github.com/lookatitude/beluga-ai/v2/voice/s2s" _ "github.com/lookatitude/beluga-ai/v2/voice/s2s/providers/nova")
func main() { ctx := context.Background()
engine, err := s2s.New("nova", s2s.Config{ Model: "amazon.nova-sonic-v1:0", Instructions: "You are a helpful assistant.", Extra: map[string]any{"region": os.Getenv("AWS_REGION")}, }) if err != nil { log.Fatalf("Failed to create Nova provider: %v", err) }
session, err := engine.Start(ctx) if err != nil { log.Fatalf("Failed to start session: %v", err) } defer session.Close()
fmt.Println("Nova session started")}Bidirectional Audio Streaming
Section titled “Bidirectional Audio Streaming”Send audio with SendAudio and consume s2s.SessionEvent values from Recv:
func handleNovaSession(ctx context.Context, session s2s.Session, audioIn <-chan []byte, play func([]byte)) error { go func() { for audio := range audioIn { if err := session.SendAudio(ctx, audio); err != nil { log.Printf("Send error: %v", err) return } } }()
for event, err := range session.Recv(ctx) { if err != nil { return err } switch event.Type { case s2s.EventAudioOutput: play(event.Audio) case s2s.EventTranscript, s2s.EventTextOutput: log.Printf("text: %s", event.Text) case s2s.EventError: return event.Error } } return nil}To use the engine inside a voice pipeline, wrap it with s2s.AsFrameProcessor(engine).
Observability
Section titled “Observability”Add OpenTelemetry tracing to monitor Nova sessions:
import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace")
tracer := otel.Tracer("beluga.voice.s2s.nova")ctx, span := tracer.Start(ctx, "nova.start", trace.WithAttributes( attribute.String("model", "amazon.nova-sonic-v1:0"), attribute.String("region", os.Getenv("AWS_REGION")), ),)defer span.End()Configuration Reference
Section titled “Configuration Reference”| Field | Description | Default | Required |
|---|---|---|---|
Extra["region"] | AWS region | us-east-1 | No |
Extra["base_url"] | Bedrock Runtime endpoint override (http(s) only) | SDK-resolved regional endpoint | No |
Extra["access_key_id"], Extra["secret_access_key"], Extra["session_token"] | Static AWS credentials | Default AWS credential chain | No |
Model | Nova model ID | amazon.nova-sonic-v1:0 | No |
Voice | Voice selection | matthew | No |
Instructions | System instructions | - | No |
Troubleshooting
Section titled “Troubleshooting”Model not enabled
Section titled “Model not enabled”Verify the Nova model is enabled in the AWS Bedrock console for your region. Navigate to Bedrock > Model access and confirm Nova 2 Sonic is available.
Access denied
Section titled “Access denied”Ensure your IAM role or user has the required Bedrock permissions. Add bedrock:InvokeModelWithResponseStream to your IAM policy.
Advanced Topics
Section titled “Advanced Topics”Production Deployment
Section titled “Production Deployment”- Use IAM roles instead of access keys for authentication in production
- Monitor Bedrock usage through AWS Cost Explorer and CloudWatch
- Choose an AWS region close to your users for lower latency
- Implement connection retry logic for transient Bedrock errors
- Set context timeouts to prevent indefinite streaming sessions