44d0bdc032
Adds internal/provider/subprocess — a provider.Provider that spawns CLI agents (claude, gemini, vibe) as subprocesses and streams their output. - FormatParser interface + three parsers for claude-stream-json, gemini-stream-json, and vibe-streaming formats; fixtures captured from real binaries - subprocessStream: pull-based stream.Stream over subprocess stdout with bounded stderr capture (8KB) and guarded reap() to prevent double-Wait - DiscoverCLIAgents: parallel PATH scan with 10s timeout, stable ordering - Provider: only the last user message is passed as --prompt; all other request fields (history, tools, system prompt) are intentionally ignored (see package doc) - main.go: discover and register CLI arms at startup; TODO(P0c) for tier-based routing to enforce preference order explicitly
80 lines
1.8 KiB
Go
80 lines
1.8 KiB
Go
package subprocess
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"somegit.dev/Owlibou/gnoma/internal/provider"
|
|
)
|
|
|
|
func TestProvider_NameAndDefaultModel(t *testing.T) {
|
|
agent := DiscoveredAgent{
|
|
CLIAgent: CLIAgent{
|
|
Name: "testcli",
|
|
DisplayName: "Test CLI",
|
|
Format: FormatVibeStreaming,
|
|
Capabilities: provider.Capabilities{ContextWindow: 32000},
|
|
},
|
|
Path: "/usr/bin/testcli",
|
|
Version: "1.0.0",
|
|
}
|
|
p := New(agent)
|
|
|
|
if p.Name() != "subprocess" {
|
|
t.Errorf("Name() = %q, want %q", p.Name(), "subprocess")
|
|
}
|
|
if p.DefaultModel() != "testcli" {
|
|
t.Errorf("DefaultModel() = %q, want %q", p.DefaultModel(), "testcli")
|
|
}
|
|
}
|
|
|
|
func TestProvider_Models(t *testing.T) {
|
|
agent := DiscoveredAgent{
|
|
CLIAgent: CLIAgent{
|
|
Name: "claude",
|
|
DisplayName: "Claude Code",
|
|
Format: FormatClaudeStreamJSON,
|
|
Capabilities: provider.Capabilities{
|
|
ContextWindow: 200000,
|
|
},
|
|
},
|
|
Path: "/usr/bin/claude",
|
|
Version: "2.1.0",
|
|
}
|
|
p := New(agent)
|
|
|
|
models, err := p.Models(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(models) != 1 {
|
|
t.Fatalf("Models() returned %d models, want 1", len(models))
|
|
}
|
|
m := models[0]
|
|
if m.Provider != "subprocess" {
|
|
t.Errorf("model.Provider = %q, want %q", m.Provider, "subprocess")
|
|
}
|
|
if m.Capabilities.ContextWindow != 200000 {
|
|
t.Errorf("ContextWindow = %d, want 200000", m.Capabilities.ContextWindow)
|
|
}
|
|
}
|
|
|
|
func TestProvider_Stream_MissingBinary(t *testing.T) {
|
|
agent := DiscoveredAgent{
|
|
CLIAgent: CLIAgent{
|
|
Name: "nonexistentcli",
|
|
DisplayName: "Nonexistent",
|
|
Format: FormatVibeStreaming,
|
|
PromptArgs: func(p string) []string { return []string{p} },
|
|
},
|
|
Path: "/nonexistent/cli",
|
|
}
|
|
p := New(agent)
|
|
|
|
req := provider.Request{}
|
|
_, err := p.Stream(context.Background(), req)
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent binary, got nil")
|
|
}
|
|
}
|