mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-11-14 00:07:10 +01:00
Delete the Eino model adapters, callbacks, middleware, orchestration, summarization and single-agent runner together with their dependencies. Chat, batch tasks, workflow Agent nodes and sub-agents now share the Pi runtime, and dispatch is a single code path instead of an engine switch. Configuration migrates eino_middleware/eino_skills to runtime/skills and drops the retired callback settings while old files still load. Settings, i18n and docs describe Pi only. Also carry the Pi follow-up fixes: empty required lists are omitted from tool schemas, historical tool results stay with their call batch, model proxies work over HTTP/1.1, single-query retrieval skips query expansion, and finalization docs match Pi lifecycle events.
162 lines
4.9 KiB
Go
162 lines
4.9 KiB
Go
package openai
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"cyberstrike-ai/internal/config"
|
|
)
|
|
|
|
func TestApplyCustomHeadersOverridesBuiltinAndSkipsEmpty(t *testing.T) {
|
|
req, err := http.NewRequest(http.MethodPost, "http://example.com/v1/chat/completions", nil)
|
|
if err != nil {
|
|
t.Fatalf("new request: %v", err)
|
|
}
|
|
req.Header.Set("Authorization", "Bearer builtin")
|
|
applyCustomHeaders(req, &config.OpenAIConfig{Headers: map[string]string{
|
|
"Authorization": "Bearer custom",
|
|
"X-Api-Key": "secret",
|
|
"User-Agent": "cyberstrike-ai/1.0",
|
|
"X-Empty": "",
|
|
" ": "dropped",
|
|
}})
|
|
if got := req.Header.Get("Authorization"); got != "Bearer custom" {
|
|
t.Fatalf("Authorization = %q, want custom override", got)
|
|
}
|
|
if got := req.Header.Get("X-Api-Key"); got != "secret" {
|
|
t.Fatalf("X-Api-Key = %q", got)
|
|
}
|
|
if got := req.Header.Get("User-Agent"); got != "cyberstrike-ai/1.0" {
|
|
t.Fatalf("User-Agent = %q", got)
|
|
}
|
|
if got := req.Header.Get("X-Empty"); got != "" {
|
|
t.Fatalf("empty header value must be skipped, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestApplyCustomHeadersNilConfigIsNoop(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodGet, "http://example.com/", nil)
|
|
applyCustomHeaders(req, nil)
|
|
if got := req.Header.Get("Authorization"); got != "" {
|
|
t.Fatalf("unexpected Authorization %q", got)
|
|
}
|
|
}
|
|
|
|
func TestNativeClientInjectsHeaders(t *testing.T) {
|
|
var auth, provider string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
auth = r.Header.Get("Authorization")
|
|
provider = r.Header.Get("X-Provider")
|
|
w.Write([]byte(`{}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
cfg := &config.OpenAIConfig{BaseURL: srv.URL, APIKey: "fixture-key", Headers: map[string]string{
|
|
"Authorization": "Bearer from-headers",
|
|
"X-Provider": "opencode",
|
|
}}
|
|
var out interface{}
|
|
err := NewClient(cfg, srv.Client(), nil).ChatCompletion(context.Background(), map[string]string{}, &out)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if auth != "Bearer from-headers" {
|
|
t.Fatalf("Authorization = %q", auth)
|
|
}
|
|
if provider != "opencode" {
|
|
t.Fatalf("X-Provider = %q", provider)
|
|
}
|
|
}
|
|
|
|
func TestExpandHeaderMapEnv(t *testing.T) {
|
|
t.Setenv("TEST_CS_HEADER_TOKEN", "tok-123")
|
|
got := config.ExpandHeaderMap(map[string]string{
|
|
"X-Api-Key": "${TEST_CS_HEADER_TOKEN}",
|
|
"X-Default": "${TEST_CS_MISSING_VAR:-fallback}",
|
|
})
|
|
if got["X-Api-Key"] != "tok-123" {
|
|
t.Fatalf("X-Api-Key = %q", got["X-Api-Key"])
|
|
}
|
|
if got["X-Default"] != "fallback" {
|
|
t.Fatalf("X-Default = %q", got["X-Default"])
|
|
}
|
|
if config.ExpandHeaderMap(nil) != nil {
|
|
t.Fatalf("nil headers should stay nil")
|
|
}
|
|
}
|
|
|
|
func TestSessionHeaderPlaceholderRendering(t *testing.T) {
|
|
cfg := &config.OpenAIConfig{Headers: map[string]string{
|
|
"x-opencode-session": "%session_id%",
|
|
"X-Prefixed": "pfx-%session_id%",
|
|
"X-Fixed": "static",
|
|
}}
|
|
|
|
ctx := WithSessionID(context.Background(), "conv-abc-123")
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://example.com/v1/chat/completions", nil)
|
|
if err != nil {
|
|
t.Fatalf("new request: %v", err)
|
|
}
|
|
applyCustomHeaders(req, cfg)
|
|
if got := req.Header.Get("x-opencode-session"); got != "conv-abc-123" {
|
|
t.Fatalf("session header = %q, want conv-abc-123", got)
|
|
}
|
|
if got := req.Header.Get("X-Prefixed"); got != "pfx-conv-abc-123" {
|
|
t.Fatalf("prefixed header = %q", got)
|
|
}
|
|
if got := req.Header.Get("X-Fixed"); got != "static" {
|
|
t.Fatalf("fixed header = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSessionHeaderSkippedWithoutSession(t *testing.T) {
|
|
cfg := &config.OpenAIConfig{Headers: map[string]string{
|
|
"x-opencode-session": "%session_id%",
|
|
"X-Fixed": "static",
|
|
}}
|
|
req, _ := http.NewRequest(http.MethodPost, "http://example.com/v1/chat/completions", nil)
|
|
applyCustomHeaders(req, cfg)
|
|
if got := req.Header.Get("x-opencode-session"); got != "" {
|
|
t.Fatalf("placeholder must be skipped without session, got %q", got)
|
|
}
|
|
if got := req.Header.Get("X-Fixed"); got != "static" {
|
|
t.Fatalf("fixed header must still be sent, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSessionIDContextRoundTrip(t *testing.T) {
|
|
if got := SessionIDFromContext(context.Background()); got != "" {
|
|
t.Fatalf("empty context should yield empty id, got %q", got)
|
|
}
|
|
if got := SessionIDFromContext(WithSessionID(context.Background(), " ")); got != "" {
|
|
t.Fatalf("blank id must be ignored, got %q", got)
|
|
}
|
|
ctx := WithSessionID(context.Background(), " conv-1 ")
|
|
if got := SessionIDFromContext(ctx); got != "conv-1" {
|
|
t.Fatalf("id = %q, want conv-1", got)
|
|
}
|
|
}
|
|
|
|
func TestRenderHeaderValueCases(t *testing.T) {
|
|
cases := []struct {
|
|
value string
|
|
sid string
|
|
want string
|
|
ok bool
|
|
}{
|
|
{"static", "s1", "static", true},
|
|
{"%session_id%", "s1", "s1", true},
|
|
{"a-%session_id%-b", "s1", "a-s1-b", true},
|
|
{"%session_id%", "", "", false},
|
|
}
|
|
for _, c := range cases {
|
|
got, ok := renderHeaderValue(c.value, c.sid)
|
|
if ok != c.ok || got != c.want {
|
|
t.Fatalf("renderHeaderValue(%q,%q) = (%q,%v), want (%q,%v)", c.value, c.sid, got, ok, c.want, c.ok)
|
|
}
|
|
}
|
|
}
|