fix: post-split cleanup — remove test script, fix tests, update docs
- Delete test-mlx.go (standalone test script, not library code) - Fix TestSandboxing_Symlinks_Followed to match security behaviour (renamed to TestSandboxing_Symlinks_Blocked — asserts sandbox correctly blocks symlinks escaping the workspace root) - Fix TestNewTCPTransport_Warning by adding missing security warning to NewTCPTransport when binding to 0.0.0.0 (all interfaces) - Update CLAUDE.md dependency table (go-mlx, duckdb, parquet, ollama, qdrant now indirect via go-ml/go-rag) - Tidy go.mod (direct vs indirect aligned with actual imports) - Verify go build, go vet, go test all pass Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
a36466a870
commit
4665bea75e
7 changed files with 52 additions and 137 deletions
12
CLAUDE.md
12
CLAUDE.md
|
|
@ -130,7 +130,6 @@ go-ai/
|
|||
│ ├── tools_chat.go # ide_chat_send/history, ide_session_list/create, ide_plan_status
|
||||
│ ├── tools_build.go # ide_build_status/list/logs
|
||||
│ └── tools_dashboard.go # ide_dashboard_overview/activity/metrics
|
||||
└── test-mlx.go # Standalone scoring pipeline test script
|
||||
```
|
||||
|
||||
## Tool Inventory (49 tools)
|
||||
|
|
@ -152,17 +151,20 @@ go-ai/
|
|||
|
||||
## Dependencies
|
||||
|
||||
### Direct
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `forge.lthn.ai/core/go` | Core framework: `pkg/io` (filesystem), `pkg/log`, `pkg/process`, `pkg/ws`, `pkg/webview` |
|
||||
| `forge.lthn.ai/core/go-ml` | ML scoring engine: heuristic scores, judge backend, probes, InfluxDB status |
|
||||
| `forge.lthn.ai/core/go-rag` | RAG: Qdrant vector DB client, Ollama embeddings, markdown chunking |
|
||||
| `forge.lthn.ai/core/go-mlx` | Native Metal GPU inference (Apple Silicon) |
|
||||
| `github.com/modelcontextprotocol/go-sdk` | MCP Go SDK (server, transports, JSON-RPC) |
|
||||
| `github.com/gorilla/websocket` | WebSocket client for IDE bridge |
|
||||
| `github.com/marcboeker/go-duckdb` | DuckDB (analytics) |
|
||||
| `github.com/qdrant/go-client` | Qdrant gRPC client |
|
||||
| `github.com/ollama/ollama` | Ollama API types |
|
||||
| `github.com/stretchr/testify` | Test assertions |
|
||||
|
||||
### Indirect (transitive via go-ml / go-rag)
|
||||
|
||||
`go-mlx`, `go-inference`, `go-duckdb`, `parquet-go`, `ollama`, `qdrant/go-client` are now indirect dependencies pulled in through `go-ml` and `go-rag`. They are not imported directly by go-ai.
|
||||
|
||||
All `forge.lthn.ai/core/*` dependencies use `replace` directives pointing to local sibling directories during development.
|
||||
|
||||
|
|
|
|||
8
TODO.md
8
TODO.md
|
|
@ -6,10 +6,10 @@ Virgil dispatches tasks. Mark `[x]` when done, note commit hash.
|
|||
|
||||
## Phase 1: Post-Split Cleanup
|
||||
|
||||
- [ ] **Remove `test-mlx.go`** — Standalone test script in module root. Not part of the library. Delete it.
|
||||
- [ ] **Verify `go build ./...` passes** — With replace directives pointing at local clones (via go.work or go.mod). Fix any stale import paths that reference old monolith structure.
|
||||
- [ ] **Verify `go vet ./...` passes** — Fix any vet warnings.
|
||||
- [ ] **Run full test suite** — `go test ./...` should pass. 84 tests documented in TEST-RESULTS.md. Confirm they still pass after the split.
|
||||
- [x] **Remove `test-mlx.go`** — Deleted standalone test script from module root.
|
||||
- [x] **Verify `go build ./...` passes** — Clean build, no stale import paths.
|
||||
- [x] **Verify `go vet ./...` passes** — No vet warnings.
|
||||
- [x] **Run full test suite** — All tests pass. Fixed `TestSandboxing_Symlinks_Blocked` (renamed; asserts sandbox blocks symlink escape) and `TestNewTCPTransport_Warning` (added missing security warning to `NewTCPTransport`).
|
||||
|
||||
## Phase 2: go-inference Migration
|
||||
|
||||
|
|
|
|||
20
go.mod
20
go.mod
|
|
@ -4,20 +4,16 @@ go 1.25.5
|
|||
|
||||
require (
|
||||
forge.lthn.ai/core/go v0.0.0
|
||||
forge.lthn.ai/core/go-mlx v0.0.0
|
||||
forge.lthn.ai/core/go-ml v0.0.0
|
||||
forge.lthn.ai/core/go-rag v0.0.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/marcboeker/go-duckdb v1.8.5
|
||||
github.com/modelcontextprotocol/go-sdk v1.3.0
|
||||
github.com/ollama/ollama v0.16.1
|
||||
github.com/parquet-go/parquet-go v0.27.0
|
||||
github.com/qdrant/go-client v1.16.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
forge.lthn.ai/core/go-inference v0.0.0 // indirect
|
||||
forge.lthn.ai/core/go-mlx v0.0.0 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/apache/arrow-go/v18 v18.5.1 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
|
|
@ -31,11 +27,14 @@ require (
|
|||
github.com/klauspost/compress v1.18.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.1 // indirect
|
||||
github.com/marcboeker/go-duckdb v1.8.5 // indirect
|
||||
github.com/ollama/ollama v0.16.1 // indirect
|
||||
github.com/parquet-go/bitpack v1.0.0 // indirect
|
||||
github.com/parquet-go/jsonlite v1.4.0 // indirect
|
||||
github.com/parquet-go/parquet-go v0.27.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.25 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/qdrant/go-client v1.16.2 // indirect
|
||||
github.com/twpayne/go-geom v1.6.1 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
|
|
@ -51,9 +50,10 @@ require (
|
|||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/tools v0.42.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect
|
||||
google.golang.org/grpc v1.78.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace forge.lthn.ai/core/go => ../core
|
||||
|
|
@ -63,3 +63,5 @@ replace forge.lthn.ai/core/go-mlx => ../go-mlx
|
|||
replace forge.lthn.ai/core/go-ml => ../go-ml
|
||||
|
||||
replace forge.lthn.ai/core/go-rag => ../go-rag
|
||||
|
||||
replace forge.lthn.ai/core/go-inference => ../go-inference
|
||||
|
|
|
|||
34
go.sum
34
go.sum
|
|
@ -14,6 +14,8 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
|
|||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
|
|
@ -94,16 +96,16 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
|||
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o=
|
||||
|
|
@ -128,12 +130,12 @@ golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
|||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ func TestSandboxing_Traversal_Sanitized(t *testing.T) {
|
|||
// should validate inputs before calling Medium.
|
||||
}
|
||||
|
||||
func TestSandboxing_Symlinks_Followed(t *testing.T) {
|
||||
func TestSandboxing_Symlinks_Blocked(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
outsideDir := t.TempDir()
|
||||
|
||||
|
|
@ -170,14 +170,11 @@ func TestSandboxing_Symlinks_Followed(t *testing.T) {
|
|||
t.Fatalf("Failed to create service: %v", err)
|
||||
}
|
||||
|
||||
// Symlinks are followed - no traversal blocking at Medium level.
|
||||
// This is intentional for simplicity. Callers wanting to block symlinks
|
||||
// should validate inputs before calling Medium.
|
||||
content, err := s.medium.Read("link")
|
||||
if err != nil {
|
||||
t.Errorf("Expected symlink to be followed, got error: %v", err)
|
||||
}
|
||||
if content != "secret" {
|
||||
t.Errorf("Expected 'secret', got '%s'", content)
|
||||
// Symlinks pointing outside the sandbox root are blocked (security feature).
|
||||
// The sandbox resolves the symlink target and rejects it because it escapes
|
||||
// the workspace boundary.
|
||||
_, err = s.medium.Read("link")
|
||||
if err == nil {
|
||||
t.Error("Expected permission denied for symlink escaping sandbox, but read succeeded")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,12 @@ type TCPTransport struct {
|
|||
|
||||
// NewTCPTransport creates a new TCP transport listener.
|
||||
// It listens on the provided address (e.g. "localhost:9100").
|
||||
// Emits a security warning when binding to 0.0.0.0 (all interfaces).
|
||||
func NewTCPTransport(addr string) (*TCPTransport, error) {
|
||||
host, _, _ := net.SplitHostPort(addr)
|
||||
if host == "0.0.0.0" || host == "" {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: MCP TCP server binding to all interfaces (%s). Use 127.0.0.1 for local-only access.\n", addr)
|
||||
}
|
||||
listener, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
93
test-mlx.go
93
test-mlx.go
|
|
@ -1,93 +0,0 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"forge.lthn.ai/core/go-ml"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== MLX Backend Test ===")
|
||||
fmt.Println()
|
||||
|
||||
// Test 1: Check if we're on the right platform
|
||||
fmt.Println("1. Platform check:")
|
||||
fmt.Printf(" GOOS: %s, GOARCH: %s\n", os.Getenv("GOOS"), os.Getenv("GOARCH"))
|
||||
fmt.Println()
|
||||
|
||||
// Test 2: Try to create backends (without MLX tag, should use HTTP)
|
||||
fmt.Println("2. Backend availability (without MLX build tag):")
|
||||
fmt.Println(" Note: MLX backend requires -tags mlx build flag")
|
||||
fmt.Println()
|
||||
|
||||
// Test 3: Check GGUF model directory
|
||||
fmt.Println("3. GGUF model directory:")
|
||||
modelDir := "/Volumes/Data/lem/gguf/"
|
||||
entries, err := os.ReadDir(modelDir)
|
||||
if err != nil {
|
||||
fmt.Printf(" Error reading directory: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" Found %d files in %s\n", len(entries), modelDir)
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
info, _ := entry.Info()
|
||||
fmt.Printf(" - %s (%.2f GB)\n", entry.Name(), float64(info.Size())/(1024*1024*1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// Test 4: Test scoring pipeline with mock backend
|
||||
fmt.Println("4. Testing scoring pipeline:")
|
||||
|
||||
// Create a mock backend for testing
|
||||
mockBackend := &MockBackend{}
|
||||
|
||||
// Test heuristic scoring
|
||||
response := ml.Response{
|
||||
ID: "test-1",
|
||||
Prompt: "What is 2+2?",
|
||||
Response: "The answer to 2+2 is 4. This is a basic arithmetic operation.",
|
||||
}
|
||||
|
||||
hScore := ml.ScoreHeuristic(response.Response)
|
||||
fmt.Printf(" Heuristic Score: %+v\n", hScore)
|
||||
|
||||
// Test judge (without actual model)
|
||||
judge := ml.NewJudge(mockBackend)
|
||||
fmt.Printf(" Judge created: %v\n", judge != nil)
|
||||
|
||||
// Create scoring engine
|
||||
engine := ml.NewEngine(judge, 2, "all")
|
||||
fmt.Printf(" Engine created: %s\n", engine.String())
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("5. Test probes:")
|
||||
fmt.Println(" Probes loaded from ml package")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("=== Test Complete ===")
|
||||
}
|
||||
|
||||
// MockBackend is a simple backend for testing
|
||||
type MockBackend struct{}
|
||||
|
||||
func (m *MockBackend) Generate(ctx context.Context, prompt string, opts ml.GenOpts) (string, error) {
|
||||
return `{"score": 5, "reasoning": "Mock response"}`, nil
|
||||
}
|
||||
|
||||
func (m *MockBackend) Chat(ctx context.Context, messages []ml.Message, opts ml.GenOpts) (string, error) {
|
||||
return `{"score": 5, "reasoning": "Mock response"}`, nil
|
||||
}
|
||||
|
||||
func (m *MockBackend) Name() string {
|
||||
return "mock"
|
||||
}
|
||||
|
||||
func (m *MockBackend) Available() bool {
|
||||
return true
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue