6
6
"fmt"
7
7
"log/slog"
8
8
"net/http"
9
+ "net/url"
10
+ "strings"
9
11
"sync"
10
12
"time"
11
13
@@ -33,6 +35,7 @@ type Server struct {
33
35
agentio * termexec.Process
34
36
agentType mf.AgentType
35
37
emitter * EventEmitter
38
+ chatBasePath string
36
39
}
37
40
38
41
func (s * Server ) GetOpenAPI () string {
@@ -95,14 +98,20 @@ func NewServer(ctx context.Context, agentType mf.AgentType, process *termexec.Pr
95
98
agentio : process ,
96
99
agentType : agentType ,
97
100
emitter : emitter ,
101
+ chatBasePath : strings .TrimSuffix (chatBasePath , "/" ),
98
102
}
99
103
100
104
// Register API routes
101
- s .registerRoutes (chatBasePath )
105
+ s .registerRoutes ()
102
106
103
107
return s
104
108
}
105
109
110
+ // Handler returns the underlying chi.Router for testing purposes.
111
+ func (s * Server ) Handler () http.Handler {
112
+ return s .router
113
+ }
114
+
106
115
func (s * Server ) StartSnapshotLoop (ctx context.Context ) {
107
116
s .conversation .StartSnapshotLoop (ctx )
108
117
go func () {
@@ -116,7 +125,7 @@ func (s *Server) StartSnapshotLoop(ctx context.Context) {
116
125
}
117
126
118
127
// registerRoutes sets up all API endpoints
119
- func (s * Server ) registerRoutes (chatBasePath string ) {
128
+ func (s * Server ) registerRoutes () {
120
129
// GET /status endpoint
121
130
huma .Get (s .api , "/status" , s .getStatus , func (o * huma.Operation ) {
122
131
o .Description = "Returns the current status of the agent."
@@ -158,7 +167,7 @@ func (s *Server) registerRoutes(chatBasePath string) {
158
167
s .router .Handle ("/" , http .HandlerFunc (s .redirectToChat ))
159
168
160
169
// Serve static files for the chat interface under /chat
161
- s .registerStaticFileRoutes (chatBasePath )
170
+ s .registerStaticFileRoutes ()
162
171
}
163
172
164
173
// getStatus handles GET /status
@@ -305,14 +314,20 @@ func (s *Server) Stop(ctx context.Context) error {
305
314
}
306
315
307
316
// registerStaticFileRoutes sets up routes for serving static files
308
- func (s * Server ) registerStaticFileRoutes (chatBasePath string ) {
309
- chatHandler := FileServerWithIndexFallback (chatBasePath )
317
+ func (s * Server ) registerStaticFileRoutes () {
318
+ chatHandler := FileServerWithIndexFallback (s . chatBasePath )
310
319
311
320
// Mount the file server at /chat
312
321
s .router .Handle ("/chat" , http .StripPrefix ("/chat" , chatHandler ))
313
322
s .router .Handle ("/chat/*" , http .StripPrefix ("/chat" , chatHandler ))
314
323
}
315
324
316
325
func (s * Server ) redirectToChat (w http.ResponseWriter , r * http.Request ) {
317
- http .Redirect (w , r , "/chat/embed" , http .StatusTemporaryRedirect )
326
+ rdir , err := url .JoinPath (s .chatBasePath , "embed" )
327
+ if err != nil {
328
+ s .logger .Error ("Failed to construct redirect URL" , "error" , err )
329
+ http .Error (w , "Failed to redirect" , http .StatusInternalServerError )
330
+ return
331
+ }
332
+ http .Redirect (w , r , rdir , http .StatusTemporaryRedirect )
318
333
}
0 commit comments