Fix API endpoint paths and search threshold

- Changed API_BASE_URL default to http://192.168.1.16:8001
- Added /api prefix normalization to apiRequest
- Fixed search to use POST with low threshold (0.01) for embedding scores
- Fixed get_stats to use total_documents/total_chunks field names
- Fixed list_documents to use stats+tags endpoints (no /documents endpoint)
- Added embedding_model and chat_model to stats output
main
Clawd 3 weeks ago
parent 1f9cdcd922
commit 1ae3e2a0b6

@ -19,10 +19,15 @@ import * as fs from "fs";
import * as path from "path";
// Configuration - can be overridden via environment variables
const API_BASE_URL = process.env.SECOND_BRAIN_API_URL || "https://2brain.coer.nl/api";
// API_BASE_URL should point to the base (e.g., http://192.168.1.16:8001)
// The /api/v1 prefix is added by apiRequest
const API_BASE_URL = (process.env.SECOND_BRAIN_API_URL || "http://192.168.1.16:8001").replace(/\/+$/, "");
const API_USERNAME = process.env.SECOND_BRAIN_USERNAME || "";
const API_PASSWORD = process.env.SECOND_BRAIN_PASSWORD || "";
// Default search threshold - embedding scores are often low, so use a low default
const DEFAULT_SEARCH_THRESHOLD = 0.01;
// Build auth header if credentials provided
function getAuthHeader(): Record<string, string> {
if (API_USERNAME && API_PASSWORD) {
@ -37,7 +42,11 @@ async function apiRequest(
endpoint: string,
options: RequestInit = {}
): Promise<Response> {
const url = `${API_BASE_URL}${endpoint}`;
// Ensure endpoint starts with /api/v1
const normalizedEndpoint = endpoint.startsWith("/api/v1")
? endpoint
: `/api${endpoint.startsWith("/v1") ? endpoint : `/v1${endpoint}`}`;
const url = `${API_BASE_URL}${normalizedEndpoint}`;
const headers = {
...getAuthHeader(),
...options.headers,
@ -321,12 +330,17 @@ async function handleSearch(args: {
query: string;
top_k?: number;
}): Promise<string> {
const params = new URLSearchParams({
q: args.query,
top_k: String(args.top_k || 5),
// Use POST with JSON body for more control over search parameters
const response = await apiRequest(`/v1/search`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: args.query,
limit: args.top_k || 5,
threshold: DEFAULT_SEARCH_THRESHOLD,
hybrid: true,
}),
});
const response = await apiRequest(`/v1/search?${params}`);
const data = await response.json();
if (!response.ok) {
@ -450,30 +464,34 @@ async function handleListDocuments(args: {
folder?: string;
limit?: number;
}): Promise<string> {
const params = new URLSearchParams({
limit: String(args.limit || 20),
});
if (args.folder) params.append("folder", args.folder);
const response = await apiRequest(`/v1/documents?${params}`);
const data = await response.json();
// The /documents endpoint doesn't exist, so we use search with a broad query
// or get stats to show document count
const statsResponse = await apiRequest("/v1/stats");
const stats = await statsResponse.json();
if (!response.ok) {
if (!statsResponse.ok) {
throw new Error(
`Failed to list documents: ${data.detail || response.statusText}`
`Failed to get stats: ${stats.detail || statsResponse.statusText}`
);
}
if (!data.documents || data.documents.length === 0) {
return "No documents found.";
}
// Also get tags to show what's in the vault
const tagsResponse = await apiRequest("/v1/tags");
const tags = await tagsResponse.json();
let output = `📚 Knowledge Base Overview:\n\n`;
output += `- **Documents:** ${stats.total_documents || 0}\n`;
output += `- **Chunks:** ${stats.total_chunks || 0}\n`;
output += `- **Last indexed:** ${stats.last_indexed || "Never"}\n\n`;
let output = `📚 Documents (${data.total}):\n\n`;
for (const doc of data.documents) {
output += `- **${doc.title || doc.path}**`;
if (doc.tags?.length) output += ` [${doc.tags.join(", ")}]`;
output += "\n";
if (Array.isArray(tags) && tags.length > 0) {
output += `**Tags:**\n`;
for (const tag of tags) {
output += `- #${tag.tag} (${tag.count} docs)\n`;
}
}
output += `\n_Use search to find specific documents._`;
return output;
}
@ -489,10 +507,12 @@ async function handleGetStats(): Promise<string> {
}
return `📊 Second Brain Stats:
- Documents: ${data.document_count || 0}
- Chunks: ${data.chunk_count || 0}
- Vault size: ${data.vault_size_mb?.toFixed(2) || 0} MB
- Last indexed: ${data.last_indexed || "Never"}`;
- Documents: ${data.total_documents || data.document_count || 0}
- Chunks: ${data.total_chunks || data.chunk_count || 0}
- Vault size: ${data.vault_size_mb?.toFixed(2) || "N/A"} MB
- Last indexed: ${data.last_indexed || "Never"}
- Embedding model: ${data.embedding_model || "N/A"}
- Chat model: ${data.chat_model || "N/A"}`;
}
async function handleReindex(): Promise<string> {

Loading…
Cancel
Save

Powered by TurnKey Linux.