diff --git a/core/p2p/federated.go b/core/p2p/federated.go index 800d38b81..8dcb491a2 100644 --- a/core/p2p/federated.go +++ b/core/p2p/federated.go @@ -130,7 +130,7 @@ func servesModel(nd schema.NodeData, model string) bool { // cheapest source first: an explicit query value, then the JSON body "model" // field. Returns "" when it cannot be determined (for example a multipart or // websocket request), in which case the caller routes by load/affinity only. -func extractModel(path, queryModel string, body []byte) string { +func extractModel(queryModel string, body []byte) string { if strings.TrimSpace(queryModel) != "" { return queryModel } diff --git a/core/p2p/federated_server.go b/core/p2p/federated_server.go index 1d8b7c930..aaaa8245a 100644 --- a/core/p2p/federated_server.go +++ b/core/p2p/federated_server.go @@ -145,7 +145,7 @@ func (fs *FederatedServer) proxy(ctx context.Context, node *node.Node) error { // Websocket: no readable model; route by load only. workerID, _ = fs.selectPeer("", nil, now) default: - model = extractModel(req.URL.Path, req.URL.Query().Get("model"), body) + model = extractModel(req.URL.Query().Get("model"), body) workerID, chain = fs.selectPeer(model, body, now) } diff --git a/core/p2p/federated_test.go b/core/p2p/federated_test.go index f5c8ed5c3..817a79564 100644 --- a/core/p2p/federated_test.go +++ b/core/p2p/federated_test.go @@ -102,20 +102,20 @@ var _ = Describe("model-aware candidate building", func() { var _ = Describe("extractModel", func() { It("reads the JSON body model field", func() { body := []byte(`{"model":"llama-3","messages":[]}`) - Expect(extractModel("/v1/chat/completions", "", body)).To(Equal("llama-3")) + Expect(extractModel("", body)).To(Equal("llama-3")) }) It("prefers a path/query model over the body", func() { body := []byte(`{"model":"frombody"}`) - Expect(extractModel("/x", "fromquery", body)).To(Equal("fromquery")) + Expect(extractModel("fromquery", body)).To(Equal("fromquery")) }) It("returns empty when no model is present", func() { - Expect(extractModel("/x", "", []byte(`{"messages":[]}`))).To(Equal("")) + Expect(extractModel("", []byte(`{"messages":[]}`))).To(Equal("")) }) It("returns empty on non-JSON / unparseable body without panicking", func() { - Expect(extractModel("/x", "", []byte("--multipart-boundary--"))).To(Equal("")) + Expect(extractModel("", []byte("--multipart-boundary--"))).To(Equal("")) }) }) diff --git a/core/p2p/p2p.go b/core/p2p/p2p.go index ff13e8b09..f7a0e0a26 100644 --- a/core/p2p/p2p.go +++ b/core/p2p/p2p.go @@ -152,6 +152,7 @@ func proxyHTTPToPeer(ctx context.Context, n *node.Node, serviceID string, conn n // io.Copy(conn, stream) blocks forever, leaking the goroutine, conn, and // stream. Websocket upgrades keep keep-alive: their duplex copy owns the // lifetime. + req.Header.Del("Connection") req.Close = !duplex if err := req.Write(stream); err != nil { zlog.Error("Could not write request to peer", "error", err)