@@ -56,7 +56,16 @@ defmodule SentinelCpWeb.ServicesLive.Edit do
5656 ( service . graphql != % { } && service . graphql != nil ) ,
5757 show_grpc:
5858 service . service_type == "grpc" ||
59- ( service . grpc != % { } && service . grpc != nil )
59+ ( service . grpc != % { } && service . grpc != nil ) ,
60+ show_websocket:
61+ service . service_type == "websocket" ||
62+ ( service . websocket != % { } && service . websocket != nil ) ,
63+ show_streaming:
64+ service . service_type == "streaming" ||
65+ ( service . streaming != % { } && service . streaming != nil ) ,
66+ show_inference:
67+ service . service_type == "inference" ||
68+ ( service . inference != % { } && service . inference != nil )
6069 ) }
6170 else
6271 _ ->
@@ -75,7 +84,10 @@ defmodule SentinelCpWeb.ServicesLive.Edit do
7584 assign ( socket ,
7685 service_type: type ,
7786 show_graphql: type == "graphql" ,
78- show_grpc: type == "grpc"
87+ show_grpc: type == "grpc" ,
88+ show_websocket: type == "websocket" ,
89+ show_streaming: type == "streaming" ,
90+ show_inference: type == "inference"
7991 ) }
8092 end
8193
@@ -153,6 +165,9 @@ defmodule SentinelCpWeb.ServicesLive.Edit do
153165
154166 attrs = maybe_put_map ( attrs , :graphql , params , "graphql" )
155167 attrs = maybe_put_map ( attrs , :grpc , params , "grpc" )
168+ attrs = maybe_put_map ( attrs , :websocket , params , "websocket" )
169+ attrs = maybe_put_map ( attrs , :streaming , params , "streaming" )
170+ attrs = maybe_put_map ( attrs , :inference , params , "inference" )
156171 attrs = maybe_put_map ( attrs , :retry , params , "retry" )
157172 attrs = maybe_put_map ( attrs , :cache , params , "cache" )
158173 attrs = maybe_put_map ( attrs , :rate_limit , params , "rate_limit" )
@@ -358,7 +373,10 @@ defmodule SentinelCpWeb.ServicesLive.Edit do
358373 </ div >
359374
360375 <%!-- Protocol Configuration --%>
361- < div :if = { @ service_type in ~w( graphql grpc) } class = "divider text-xs text-base-content/50 " >
376+ < div
377+ :if = { @ service_type in ~w( graphql grpc websocket streaming inference) }
378+ class = "divider text-xs text-base-content/50 "
379+ >
362380 Protocol Configuration
363381 </ div >
364382
@@ -501,6 +519,215 @@ defmodule SentinelCpWeb.ServicesLive.Edit do
501519 </ div >
502520 </ div >
503521
522+ < div
523+ :if = { @ service_type == "websocket" or @ show_websocket }
524+ data-testid = "websocket-config "
525+ >
526+ < button
527+ type = "button "
528+ phx-click = "toggle_section "
529+ phx-value-section = "websocket "
530+ class = "btn btn-ghost btn-xs "
531+ >
532+ { if @ show_websocket , do: "▼" , else: "▶" } WebSocket Settings
533+ </ button >
534+ < div :if = { @ show_websocket } class = "ml-4 mt-2 space-y-2 " >
535+ < div class = "form-control " >
536+ < label class = "label " >
537+ < span class = "label-text text-xs " > Ping Interval (seconds)</ span >
538+ </ label >
539+ < input
540+ type = "number "
541+ name = "websocket[ping_interval] "
542+ class = "input input-bordered input-xs w-24 "
543+ placeholder = "30 "
544+ min = "1 "
545+ value = { @ service . websocket [ "ping_interval" ] }
546+ />
547+ </ div >
548+ < div class = "form-control " >
549+ < label class = "label " >
550+ < span class = "label-text text-xs " > Max Message Size (bytes)</ span >
551+ </ label >
552+ < input
553+ type = "number "
554+ name = "websocket[max_message_size] "
555+ class = "input input-bordered input-xs w-32 "
556+ placeholder = "65536 "
557+ min = "1 "
558+ value = { @ service . websocket [ "max_message_size" ] }
559+ />
560+ </ div >
561+ < div class = "form-control " >
562+ < label class = "label " >
563+ < span class = "label-text text-xs " > Max Connections</ span >
564+ </ label >
565+ < input
566+ type = "number "
567+ name = "websocket[max_connections] "
568+ class = "input input-bordered input-xs w-28 "
569+ placeholder = "10000 "
570+ min = "1 "
571+ value = { @ service . websocket [ "max_connections" ] }
572+ />
573+ </ div >
574+ </ div >
575+ </ div >
576+
577+ < div
578+ :if = { @ service_type == "streaming" or @ show_streaming }
579+ data-testid = "streaming-config "
580+ >
581+ < button
582+ type = "button "
583+ phx-click = "toggle_section "
584+ phx-value-section = "streaming "
585+ class = "btn btn-ghost btn-xs "
586+ >
587+ { if @ show_streaming , do: "▼" , else: "▶" } Streaming Settings
588+ </ button >
589+ < div :if = { @ show_streaming } class = "ml-4 mt-2 space-y-2 " >
590+ < div class = "form-control " >
591+ < label class = "label " > < span class = "label-text text-xs " > Format</ span > </ label >
592+ < select name = "streaming[format] " class = "select select-bordered select-xs w-40 " >
593+ < option value = "" > —</ option >
594+ < option value = "sse " selected = { @ service . streaming [ "format" ] == "sse" } > SSE</ option >
595+ < option value = "ndjson " selected = { @ service . streaming [ "format" ] == "ndjson" } >
596+ NDJSON
597+ </ option >
598+ < option value = "chunked " selected = { @ service . streaming [ "format" ] == "chunked" } >
599+ Chunked
600+ </ option >
601+ </ select >
602+ </ div >
603+ < div class = "form-control " >
604+ < label class = "label " >
605+ < span class = "label-text text-xs " > Keepalive Interval (seconds)</ span >
606+ </ label >
607+ < input
608+ type = "number "
609+ name = "streaming[keepalive_interval] "
610+ class = "input input-bordered input-xs w-24 "
611+ placeholder = "15 "
612+ min = "1 "
613+ value = { @ service . streaming [ "keepalive_interval" ] }
614+ />
615+ </ div >
616+ < div class = "form-control " >
617+ < label class = "label " >
618+ < span class = "label-text text-xs " > Max Connection Duration (seconds)</ span >
619+ </ label >
620+ < input
621+ type = "number "
622+ name = "streaming[max_connection_duration] "
623+ class = "input input-bordered input-xs w-28 "
624+ placeholder = "3600 "
625+ min = "1 "
626+ value = { @ service . streaming [ "max_connection_duration" ] }
627+ />
628+ </ div >
629+ < div class = "form-control " >
630+ < label class = "label " >
631+ < span class = "label-text text-xs " > Buffer Size (bytes)</ span >
632+ </ label >
633+ < input
634+ type = "number "
635+ name = "streaming[buffer_size] "
636+ class = "input input-bordered input-xs w-28 "
637+ placeholder = "1024 "
638+ min = "1 "
639+ value = { @ service . streaming [ "buffer_size" ] }
640+ />
641+ </ div >
642+ </ div >
643+ </ div >
644+
645+ < div
646+ :if = { @ service_type == "inference" or @ show_inference }
647+ data-testid = "inference-config "
648+ >
649+ < button
650+ type = "button "
651+ phx-click = "toggle_section "
652+ phx-value-section = "inference "
653+ class = "btn btn-ghost btn-xs "
654+ >
655+ { if @ show_inference , do: "▼" , else: "▶" } Inference Settings
656+ </ button >
657+ < div :if = { @ show_inference } class = "ml-4 mt-2 space-y-2 " >
658+ < div class = "form-control " >
659+ < label class = "label " > < span class = "label-text text-xs " > Provider</ span > </ label >
660+ < select name = "inference[provider] " class = "select select-bordered select-xs w-40 " >
661+ < option value = "" > —</ option >
662+ < option value = "openai " selected = { @ service . inference [ "provider" ] == "openai" } >
663+ OpenAI
664+ </ option >
665+ < option
666+ value = "anthropic "
667+ selected = { @ service . inference [ "provider" ] == "anthropic" }
668+ >
669+ Anthropic
670+ </ option >
671+ < option value = "generic " selected = { @ service . inference [ "provider" ] == "generic" } >
672+ Generic
673+ </ option >
674+ </ select >
675+ </ div >
676+ < div class = "form-control " >
677+ < label class = "label " >
678+ < span class = "label-text text-xs " > Tokens per Minute</ span >
679+ </ label >
680+ < input
681+ type = "number "
682+ name = "inference[tokens_per_minute] "
683+ class = "input input-bordered input-xs w-32 "
684+ placeholder = "100000 "
685+ min = "1 "
686+ value = { @ service . inference [ "tokens_per_minute" ] }
687+ />
688+ </ div >
689+ < div class = "form-control " >
690+ < label class = "label " >
691+ < span class = "label-text text-xs " > Monthly Token Budget</ span >
692+ </ label >
693+ < input
694+ type = "number "
695+ name = "inference[monthly_token_budget] "
696+ class = "input input-bordered input-xs w-32 "
697+ placeholder = "10000000 "
698+ min = "1 "
699+ value = { @ service . inference [ "monthly_token_budget" ] }
700+ />
701+ </ div >
702+ < div class = "form-control " >
703+ < label class = "label " >
704+ < span class = "label-text text-xs " > Budget Alert Threshold (%)</ span >
705+ </ label >
706+ < input
707+ type = "number "
708+ name = "inference[budget_alert_threshold] "
709+ class = "input input-bordered input-xs w-24 "
710+ placeholder = "80 "
711+ min = "1 "
712+ max = "100 "
713+ value = { @ service . inference [ "budget_alert_threshold" ] }
714+ />
715+ </ div >
716+ < div class = "form-control " >
717+ < label class = "label cursor-pointer gap-2 justify-start " >
718+ < input
719+ type = "checkbox "
720+ name = "inference[streaming_enabled] "
721+ value = "true "
722+ checked = { @ service . inference [ "streaming_enabled" ] in [ "true" , true ] }
723+ class = "checkbox checkbox-xs "
724+ />
725+ < span class = "label-text text-xs " > Enable Streaming</ span >
726+ </ label >
727+ </ div >
728+ </ div >
729+ </ div >
730+
504731 <%!-- Advanced Sections --%>
505732 < div class = "divider text-xs text-base-content/50 " > Advanced Settings</ div >
506733
0 commit comments