update-1.6.2
ci / test (services/knowledge) (push) Successful in 47s
ci / test (services/agent) (push) Successful in 55s
ci / test (platform/neuroforge) (push) Successful in 56s
ci / docker-build (push) Failing after 1m10s
ci / test (services/control) (push) Successful in 1m26s
release-tag / release-image (push) Successful in 6m43s

This commit is contained in:
2026-09-09 12:55:35 +02:00
parent e0bf42bf32
commit d18405ed2e
48 changed files with 8062 additions and 1111 deletions
+9
View File
@@ -234,6 +234,7 @@ func run() (retErr error) {
changed := false
for name, dst := range map[string]*string{
"OPENAI_API_KEY": &sec.OpenAIAPIKey,
"NEUROFORGE_OLLAMA_API_KEY": &sec.OllamaAPIKey,
"NEUROFORGE_ADMIN_TOKEN": &sec.AdminToken,
"NEUROFORGE_APP_API_KEY": &sec.AppAPIKey,
"NEUROFORGE_INTEGRATION_TOKEN": &sec.IntegrationToken,
@@ -247,6 +248,14 @@ func run() (retErr error) {
changed = true
}
}
// OLLAMA_API_KEY is a convenient shared alias. The NeuroForge-specific
// variable wins when both are set.
if strings.TrimSpace(os.Getenv("NEUROFORGE_OLLAMA_API_KEY")) == "" {
if v := strings.TrimSpace(os.Getenv("OLLAMA_API_KEY")); v != "" {
sec.OllamaAPIKey = v
changed = true
}
}
if changed {
if err := s.UpdateSecrets(sec); err != nil {
return err
+8 -3
View File
@@ -86,6 +86,7 @@ type workerConfig struct {
MaxConcurrency int
Hostname string
OllamaURL string
OllamaAPIKey string
OllamaChatModel string
OllamaEmbedModel string
OllamaNumCtx int
@@ -145,6 +146,7 @@ func main() {
Heartbeat: heartbeat, ResourceClass: resource, Capabilities: caps,
MaxConcurrency: maxConcurrency, Hostname: hostname(),
OllamaURL: strings.TrimRight(firstNonEmpty(os.Getenv("NEUROFORGE_WORKER_OLLAMA_URL"), os.Getenv("OLLAMA_BASE_URL"), os.Getenv("OLLAMA_URL")), "/"),
OllamaAPIKey: firstNonEmpty(os.Getenv("NEUROFORGE_WORKER_OLLAMA_API_KEY"), os.Getenv("OLLAMA_API_KEY")),
OllamaChatModel: firstNonEmpty(os.Getenv("NEUROFORGE_WORKER_OLLAMA_CHAT_MODEL"), os.Getenv("OLLAMA_MODEL")),
OllamaEmbedModel: firstNonEmpty(os.Getenv("NEUROFORGE_WORKER_OLLAMA_EMBEDDING_MODEL"), os.Getenv("OLLAMA_EMBEDDING_MODEL")),
OllamaNumCtx: envInt("NEUROFORGE_WORKER_OLLAMA_NUM_CTX", 8192),
@@ -342,7 +344,7 @@ func ollamaEmbed(ctx context.Context, c *http.Client, cfg workerConfig, p modelE
Embeddings [][]float32 `json:"embeddings"`
PromptEvalCount int64 `json:"prompt_eval_count"`
}
if err := postOllama(ctx, c, cfg.OllamaURL+"/api/embed", body, &resp); err != nil {
if err := postOllama(ctx, c, cfg.OllamaURL+"/api/embed", cfg.OllamaAPIKey, body, &resp); err != nil {
return modelResult{}, err
}
if len(resp.Embeddings) == 0 || len(resp.Embeddings[0]) == 0 {
@@ -385,19 +387,22 @@ func ollamaChat(ctx context.Context, c *http.Client, cfg workerConfig, p modelCh
PromptEvalCount int64 `json:"prompt_eval_count"`
EvalCount int64 `json:"eval_count"`
}
if err := postOllama(ctx, c, cfg.OllamaURL+"/api/chat", body, &resp); err != nil {
if err := postOllama(ctx, c, cfg.OllamaURL+"/api/chat", cfg.OllamaAPIKey, body, &resp); err != nil {
return modelResult{}, err
}
return modelResult{Text: strings.TrimSpace(resp.Message.Content), Usage: modelUsage{InputTokens: resp.PromptEvalCount, OutputTokens: resp.EvalCount}, Provider: "ollama", Model: model, NodeID: cfg.ID}, nil
}
func postOllama(ctx context.Context, c *http.Client, url string, body any, out any) error {
func postOllama(ctx context.Context, c *http.Client, url, apiKey string, body any, out any) error {
raw, _ := json.Marshal(body)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(raw))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
if token := strings.TrimSpace(apiKey); token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
resp, err := c.Do(req)
if err != nil {
return err
@@ -0,0 +1,26 @@
package main
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
func TestPostOllamaSendsBearerToken(t *testing.T) {
const token = "ollama-secret"
var auth string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
auth = r.Header.Get("Authorization")
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
}))
defer srv.Close()
var out map[string]any
if err := postOllama(context.Background(), srv.Client(), srv.URL, token, map[string]any{"x": 1}, &out); err != nil {
t.Fatal(err)
}
if auth != "Bearer "+token {
t.Fatalf("authorization=%q", auth)
}
}