@@ -3,7 +3,6 @@ package server
33import (
44 "context"
55 "encoding/json"
6- "fmt"
76 "io"
87 "log"
98 "net/http"
@@ -14,23 +13,32 @@ import (
1413 "github.com/lazypower/continuity/internal/engine"
1514)
1615
16+ // jsonError writes a JSON error response with proper Content-Type and encoding.
17+ // Prefer this over http.Error for consistent JSON responses.
18+ func jsonError (w http.ResponseWriter , msg string , code int ) {
19+ w .Header ().Set ("Content-Type" , "application/json" )
20+ w .WriteHeader (code )
21+ json .NewEncoder (w ).Encode (map [string ]string {"error" : msg })
22+ }
23+
1724func (s * Server ) handleSessionInit (w http.ResponseWriter , r * http.Request ) {
1825 var req struct {
1926 SessionID string `json:"session_id"`
2027 Project string `json:"project"`
2128 }
2229 if err := json .NewDecoder (r .Body ).Decode (& req ); err != nil {
23- http . Error (w , `{"error":" invalid json"}` , http .StatusBadRequest )
30+ jsonError (w , " invalid json" , http .StatusBadRequest )
2431 return
2532 }
2633 if req .SessionID == "" {
27- http . Error (w , `{"error":" session_id required"}` , http .StatusBadRequest )
34+ jsonError (w , " session_id required" , http .StatusBadRequest )
2835 return
2936 }
3037
3138 sess , err := s .db .InitSession (req .SessionID , req .Project )
3239 if err != nil {
33- http .Error (w , `{"error":"` + err .Error ()+ `"}` , http .StatusInternalServerError )
40+ log .Printf ("init session: %v" , err )
41+ jsonError (w , "internal error" , http .StatusInternalServerError )
3442 return
3543 }
3644
@@ -52,16 +60,17 @@ func (s *Server) handleAddObservation(w http.ResponseWriter, r *http.Request) {
5260 }
5361 body , err := io .ReadAll (r .Body )
5462 if err != nil {
55- http . Error (w , `{"error":" read body failed"}` , http .StatusBadRequest )
63+ jsonError (w , " read body failed" , http .StatusBadRequest )
5664 return
5765 }
5866 if err := json .Unmarshal (body , & req ); err != nil {
59- http . Error (w , `{"error":" invalid json"}` , http .StatusBadRequest )
67+ jsonError (w , " invalid json" , http .StatusBadRequest )
6068 return
6169 }
6270
6371 if err := s .db .AddObservation (sessionID , req .ToolName , req .ToolInput , req .ToolResponse ); err != nil {
64- http .Error (w , `{"error":"` + err .Error ()+ `"}` , http .StatusInternalServerError )
72+ log .Printf ("add observation: %v" , err )
73+ jsonError (w , "internal error" , http .StatusInternalServerError )
6574 return
6675 }
6776
@@ -79,8 +88,9 @@ func (s *Server) handleCompleteSession(w http.ResponseWriter, r *http.Request) {
7988 if err := s .db .CompleteSession (sessionID ); err != nil {
8089 // Not finding an active session is not a server error — the session
8190 // may have already been completed or never existed. Log but return OK.
91+ log .Printf ("complete session: %v" , err )
8292 w .Header ().Set ("Content-Type" , "application/json" )
83- json .NewEncoder (w ).Encode (map [string ]string {"status" : "ok" , "note" : err . Error () })
93+ json .NewEncoder (w ).Encode (map [string ]string {"status" : "ok" })
8494 return
8595 }
8696
@@ -92,7 +102,8 @@ func (s *Server) handleEndSession(w http.ResponseWriter, r *http.Request) {
92102 sessionID := chi .URLParam (r , "sessionID" )
93103
94104 if err := s .db .EndSession (sessionID ); err != nil {
95- http .Error (w , `{"error":"` + err .Error ()+ `"}` , http .StatusInternalServerError )
105+ log .Printf ("end session: %v" , err )
106+ jsonError (w , "internal error" , http .StatusInternalServerError )
96107 return
97108 }
98109
@@ -108,7 +119,7 @@ func (s *Server) handleExtractSession(w http.ResponseWriter, r *http.Request) {
108119 Force bool `json:"force"`
109120 }
110121 if err := json .NewDecoder (r .Body ).Decode (& req ); err != nil {
111- http . Error (w , `{"error":" invalid json"}` , http .StatusBadRequest )
122+ jsonError (w , " invalid json" , http .StatusBadRequest )
112123 return
113124 }
114125
@@ -144,11 +155,11 @@ func (s *Server) handleSignal(w http.ResponseWriter, r *http.Request) {
144155 Prompt string `json:"prompt"`
145156 }
146157 if err := json .NewDecoder (r .Body ).Decode (& req ); err != nil {
147- http . Error (w , `{"error":" invalid json"}` , http .StatusBadRequest )
158+ jsonError (w , " invalid json" , http .StatusBadRequest )
148159 return
149160 }
150161 if req .Prompt == "" {
151- http . Error (w , `{"error":" prompt required"}` , http .StatusBadRequest )
162+ jsonError (w , " prompt required" , http .StatusBadRequest )
152163 return
153164 }
154165
@@ -180,9 +191,8 @@ func (s *Server) handleSignal(w http.ResponseWriter, r *http.Request) {
180191func (s * Server ) handleUnmarkEmptyExtractions (w http.ResponseWriter , r * http.Request ) {
181192 n , err := s .db .UnmarkEmptyExtractions ()
182193 if err != nil {
183- w .Header ().Set ("Content-Type" , "application/json" )
184- w .WriteHeader (http .StatusInternalServerError )
185- json .NewEncoder (w ).Encode (map [string ]string {"error" : err .Error ()})
194+ log .Printf ("unmark empty extractions: %v" , err )
195+ jsonError (w , "internal error" , http .StatusInternalServerError )
186196 return
187197 }
188198
@@ -204,15 +214,12 @@ func (s *Server) handleGetMemory(w http.ResponseWriter, r *http.Request) {
204214
205215 node , err := s .db .GetNodeByURI (uri )
206216 if err != nil {
207- w .Header ().Set ("Content-Type" , "application/json" )
208- w .WriteHeader (http .StatusInternalServerError )
209- json .NewEncoder (w ).Encode (map [string ]string {"error" : err .Error ()})
217+ log .Printf ("get memory: %v" , err )
218+ jsonError (w , "internal error" , http .StatusInternalServerError )
210219 return
211220 }
212221 if node == nil {
213- w .Header ().Set ("Content-Type" , "application/json" )
214- w .WriteHeader (http .StatusNotFound )
215- json .NewEncoder (w ).Encode (map [string ]string {"error" : "memory not found: " + uri })
222+ jsonError (w , "memory not found" , http .StatusNotFound )
216223 return
217224 }
218225
@@ -241,11 +248,11 @@ func (s *Server) handleRemember(w http.ResponseWriter, r *http.Request) {
241248 SessionID string `json:"session_id"`
242249 }
243250 if err := json .NewDecoder (r .Body ).Decode (& req ); err != nil {
244- http . Error (w , `{"error":" invalid json"}` , http .StatusBadRequest )
251+ jsonError (w , " invalid json" , http .StatusBadRequest )
245252 return
246253 }
247254 if req .Category == "" || req .Name == "" || req .Summary == "" || req .Body == "" {
248- http . Error (w , `{"error":" category, name, summary, and body are required"}` , http .StatusBadRequest )
255+ jsonError (w , " category, name, summary, and body are required" , http .StatusBadRequest )
249256 return
250257 }
251258
@@ -268,9 +275,8 @@ func (s *Server) handleRemember(w http.ResponseWriter, r *http.Request) {
268275 SessionID : req .SessionID ,
269276 })
270277 if err != nil {
271- w .Header ().Set ("Content-Type" , "application/json" )
272- w .WriteHeader (http .StatusBadRequest )
273- json .NewEncoder (w ).Encode (map [string ]string {"error" : err .Error ()})
278+ log .Printf ("remember: %v" , err )
279+ jsonError (w , "failed to store memory" , http .StatusBadRequest )
274280 return
275281 }
276282
@@ -289,7 +295,7 @@ func (s *Server) handleRemember(w http.ResponseWriter, r *http.Request) {
289295func (s * Server ) handleSearch (w http.ResponseWriter , r * http.Request ) {
290296 query := r .URL .Query ().Get ("q" )
291297 if query == "" {
292- http . Error (w , `{"error":" q parameter required"}` , http .StatusBadRequest )
298+ jsonError (w , " q parameter required" , http .StatusBadRequest )
293299 return
294300 }
295301
@@ -304,6 +310,9 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
304310 limit = n
305311 }
306312 }
313+ if limit > 100 {
314+ limit = 100
315+ }
307316
308317 category := r .URL .Query ().Get ("category" )
309318
@@ -333,7 +342,8 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
333342 }
334343
335344 if err != nil {
336- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
345+ log .Printf ("search: %v" , err )
346+ jsonError (w , "internal error" , http .StatusInternalServerError )
337347 return
338348 }
339349
@@ -384,7 +394,8 @@ func (s *Server) handleTimeline(w http.ResponseWriter, r *http.Request) {
384394
385395 sessions , err := s .db .GetSessionsSince (sinceMs )
386396 if err != nil {
387- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
397+ log .Printf ("timeline: %v" , err )
398+ jsonError (w , "internal error" , http .StatusInternalServerError )
388399 return
389400 }
390401
@@ -415,7 +426,8 @@ func (s *Server) handleTimeline(w http.ResponseWriter, r *http.Request) {
415426func (s * Server ) handleProfile (w http.ResponseWriter , r * http.Request ) {
416427 relProfile , err := s .db .GetNodeByURI ("mem://user/profile/communication" )
417428 if err != nil {
418- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
429+ log .Printf ("profile: %v" , err )
430+ jsonError (w , "internal error" , http .StatusInternalServerError )
419431 return
420432 }
421433
@@ -476,7 +488,8 @@ func (s *Server) handleTree(w http.ResponseWriter, r *http.Request) {
476488 // List roots
477489 roots , err := s .db .ListRoots ()
478490 if err != nil {
479- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
491+ log .Printf ("tree roots: %v" , err )
492+ jsonError (w , "internal error" , http .StatusInternalServerError )
480493 return
481494 }
482495 for _ , r := range roots {
@@ -492,7 +505,8 @@ func (s *Server) handleTree(w http.ResponseWriter, r *http.Request) {
492505 // List children
493506 children , err := s .db .GetChildren (uri )
494507 if err != nil {
495- http .Error (w , fmt .Sprintf (`{"error":"%s"}` , err .Error ()), http .StatusInternalServerError )
508+ log .Printf ("tree children: %v" , err )
509+ jsonError (w , "internal error" , http .StatusInternalServerError )
496510 return
497511 }
498512 for _ , c := range children {
0 commit comments