MCPcopy Create free account
hub / github.com/rilldata/rill / CompleteStreamingHandler

Method CompleteStreamingHandler

runtime/server/chat.go:456–547  ·  view source on GitHub ↗

CompleteStreamingHandler is a HTTP handler that wraps CompleteStreaming and maps it to SSE. This is required as vanguard doesn't currently map streaming RPCs to SSE, so we register this handler manually override the behavior

(w http.ResponseWriter, req *http.Request)

Source from the content-addressed store, hash-verified

454// CompleteStreamingHandler is a HTTP handler that wraps CompleteStreaming and maps it to SSE.
455// This is required as vanguard doesn't currently map streaming RPCs to SSE, so we register this handler manually override the behavior
456func (s *Server) CompleteStreamingHandler(w http.ResponseWriter, req *http.Request) {
457 // Observability
458 ctx := req.Context()
459 instanceID := req.PathValue("instance_id")
460 observability.AddRequestAttributes(ctx,
461 attribute.String("args.instance_id", instanceID),
462 )
463
464 // Access check
465 if !auth.GetClaims(ctx, instanceID).Can(runtime.UseAI) {
466 http.Error(w, "action not allowed", http.StatusUnauthorized)
467 return
468 }
469
470 // Apply configured timeout for AI chat
471 cfg, err := s.runtime.InstanceConfig(ctx, instanceID)
472 if err != nil {
473 http.Error(w, fmt.Sprintf("failed to load instance config: %v", err), http.StatusBadRequest)
474 return
475 }
476 ctx, cancel := context.WithTimeout(ctx, time.Duration(cfg.AICompletionTimeoutSeconds)*time.Second)
477 defer cancel()
478 req = req.WithContext(ctx)
479
480 // Build request. Note we try to support both GET and POST.
481 completeReq := &runtimev1.CompleteStreamingRequest{}
482 if req.Method == http.MethodGet {
483 // Parse from query parameters
484 completeReq.ConversationId = req.URL.Query().Get("conversationId")
485 completeReq.Prompt = req.URL.Query().Get("prompt")
486 } else {
487 // Parse from JSON body
488 body, err := io.ReadAll(req.Body)
489 if err != nil {
490 http.Error(w, "failed to read request body", http.StatusBadRequest)
491 return
492 }
493 if err := protojson.Unmarshal(body, completeReq); err != nil {
494 http.Error(w, "failed to parse request body", http.StatusBadRequest)
495 return
496 }
497 }
498 completeReq.InstanceId = instanceID // Set instance ID from path
499
500 // Start goroutine that calls CompleteStreaming and publishes responses to a channel
501 events := make(chan *sseEvent)
502 go func() {
503 // Handle panics (it's a separate goroutine so the middleware won't catch panics)
504 defer func() {
505 if r := recover(); r != nil {
506 s.logger.Error("panic in CompleteStreamingHandler subscription goroutine", zap.Any("recover", r), zap.Stack("stack"))
507 }
508 }()
509
510 // We must close the events channel when done to make sure the SSE handler returns
511 defer close(events)
512
513 // Create the shim that implements RuntimeService_CompleteStreamingServer

Callers

nothing calls this directly

Calls 13

CompleteStreamingMethod · 0.95
AddRequestAttributesFunction · 0.92
GetClaimsFunction · 0.92
recoverFunction · 0.85
serveSSEUntilCloseFunction · 0.85
CanMethod · 0.80
InstanceConfigMethod · 0.80
MessageMethod · 0.80
ContextMethod · 0.65
StringMethod · 0.65
GetMethod · 0.65
QueryMethod · 0.65

Tested by

no test coverage detected