feat(brain): add brain_answer and brain_classify MCP tools
Adds two new LLM-backed MCP tools to the ingestion service: - brain_answer(query): BM25 retrieval + LLM synthesis → answer + sources - brain_classify(text): classifies doc into type/title/tags via LLM Adds llm.Router for primary→fallback routing (berget.ai → iguana). Wired via BRAIN_LLM_PRIMARY_URL/BRAIN_LLM_FALLBACK_URL env vars; no-op when unset so existing deployments are unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@ func TestBrainQueryReturnsResults(t *testing.T) {
|
||||
0o644,
|
||||
))
|
||||
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
resp := toolCall(t, srv, "brain_query", map[string]any{"query": "tdd"})
|
||||
|
||||
require.Nil(t, resp["error"])
|
||||
@@ -53,7 +53,7 @@ func TestBrainQueryReturnsResults(t *testing.T) {
|
||||
|
||||
func TestBrainWriteCreatesFile(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_write", map[string]any{
|
||||
"content": "# Test\n\nbody",
|
||||
@@ -72,7 +72,7 @@ func TestBrainWriteCreatesFile(t *testing.T) {
|
||||
|
||||
func TestBrainWriteRejectsTraversal(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_write", map[string]any{
|
||||
"content": "x",
|
||||
@@ -83,7 +83,7 @@ func TestBrainWriteRejectsTraversal(t *testing.T) {
|
||||
|
||||
func TestBrainWriteAcceptsDoubleDotInName(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_write", map[string]any{
|
||||
"content": "x",
|
||||
@@ -98,7 +98,7 @@ func TestBrainWriteAcceptsDoubleDotInName(t *testing.T) {
|
||||
func TestBrainIngestRawDryRun(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
require.NoError(t, os.MkdirAll(filepath.Join(brainDir, "wiki", "concepts"), 0o755))
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_ingest_raw", map[string]any{
|
||||
"source": "test-source",
|
||||
@@ -130,7 +130,7 @@ func TestBrainIngestRawDryRun(t *testing.T) {
|
||||
|
||||
func TestBrainIngestRejectsBoth(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_ingest", map[string]any{
|
||||
"content": "x",
|
||||
@@ -142,7 +142,7 @@ func TestBrainIngestRejectsBoth(t *testing.T) {
|
||||
|
||||
func TestBrainIngestRequiresOne(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_ingest", map[string]any{})
|
||||
require.NotNil(t, resp["error"])
|
||||
@@ -150,7 +150,7 @@ func TestBrainIngestRequiresOne(t *testing.T) {
|
||||
|
||||
func TestBrainIngestRejectsContentWithoutSource(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_ingest", map[string]any{
|
||||
"content": "x",
|
||||
@@ -160,7 +160,7 @@ func TestBrainIngestRejectsContentWithoutSource(t *testing.T) {
|
||||
|
||||
func TestBrainIngestRequiresLLMConfigured(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil) // nil pipelineCfg → no LLM
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil) // nil pipelineCfg → no LLM
|
||||
|
||||
resp := toolCall(t, srv, "brain_ingest", map[string]any{
|
||||
"content": "some content",
|
||||
@@ -173,7 +173,7 @@ func TestBrainIngestRequiresLLMConfigured(t *testing.T) {
|
||||
|
||||
func TestSessionLogAppends(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
srv := mcp.NewServer(brainDir, nil, nil)
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "session_log", map[string]any{
|
||||
"session_id": "session-x",
|
||||
@@ -190,7 +190,7 @@ func TestSessionLogAppends(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSessionLogRequiresSessionID(t *testing.T) {
|
||||
srv := mcp.NewServer(t.TempDir(), nil, nil)
|
||||
srv := mcp.NewServer(t.TempDir(), nil, nil, nil)
|
||||
resp := toolCall(t, srv, "session_log", map[string]any{"skill": "tdd"})
|
||||
require.NotNil(t, resp["error"])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user