Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions integrations/kubernetes-deployment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,13 @@ server.registerTool(
const client = await pool.connect();
try {
const result = await client.queryObject<{
id: string;
content: string;
metadata: Record<string, unknown>;
similarity: number;
created_at: string;
}>(
`SELECT content, metadata, created_at,
`SELECT id, content, metadata, created_at,
1 - (embedding <=> $1::vector) AS similarity
FROM thoughts
WHERE 1 - (embedding <=> $1::vector) >= $2
Expand All @@ -157,6 +158,7 @@ server.registerTool(
const m = t.metadata || {};
const parts = [
`--- Result ${i + 1} (${(t.similarity * 100).toFixed(1)}% match) ---`,
`ID: ${t.id}`,
`Captured: ${new Date(t.created_at).toLocaleDateString()}`,
`Type: ${m.type || "unknown"}`,
];
Expand Down Expand Up @@ -235,11 +237,12 @@ server.registerTool(
const client = await pool.connect();
try {
const result = await client.queryObject<{
id: string;
content: string;
metadata: Record<string, unknown>;
created_at: string;
}>(
`SELECT content, metadata, created_at
`SELECT id, content, metadata, created_at
FROM thoughts
${whereClause}
ORDER BY created_at DESC
Expand All @@ -254,7 +257,7 @@ server.registerTool(
const results = result.rows.map((t, i) => {
const m = t.metadata || {};
const tags = Array.isArray(m.topics) ? (m.topics as string[]).join(", ") : "";
return `${i + 1}. [${new Date(t.created_at).toLocaleDateString()}] (${m.type || "??"}${tags ? " - " + tags : ""})\n ${t.content}`;
return `${i + 1}. [${t.id}] [${new Date(t.created_at).toLocaleDateString()}] (${m.type || "??"}${tags ? " - " + tags : ""})\n ${t.content}`;
});

return {
Expand Down Expand Up @@ -410,6 +413,62 @@ server.registerTool(
}
);

// Tool 5: Delete Thought
server.registerTool(
"delete_thought",
{
title: "Delete Thought",
description:
"Delete a thought from the Open Brain by its ID. Irreversible — use search_thoughts or list_thoughts to confirm the correct ID before deleting. Operates across the full database regardless of user context (single-user deployments only).",
inputSchema: {
id: z.string().describe("The ID of the thought to delete (from search_thoughts or list_thoughts output)"),
},
},
async ({ id }) => {
try {
const client = await pool.connect();
try {
// First fetch the thought so we can confirm what was deleted
const existing = await client.queryObject<{ id: string; content: string; metadata: Record<string, unknown> }>(
`SELECT id, content, metadata FROM thoughts WHERE id = $1`,
[id]
);

if (!existing.rows.length) {
return {
content: [{ type: "text" as const, text: `No thought found with ID: ${id}` }],
isError: true,
};
}

await client.queryObject(`DELETE FROM thoughts WHERE id = $1`, [id]);

const t = existing.rows[0];
const m = (t.metadata || {}) as Record<string, unknown>;
const preview = t.content.length > 100
? t.content.substring(0, 100) + "..."
: t.content;

return {
content: [
{
type: "text" as const,
text: `Deleted thought ${id} (${m.type || "unknown"}):\n${preview}`,
},
],
};
} finally {
client.release();
}
} catch (err: unknown) {
return {
content: [{ type: "text" as const, text: `Error: ${(err as Error).message}` }],
isError: true,
};
}
}
);

// --- Hono App with Auth Check ---

const app = new Hono();
Expand Down
68 changes: 65 additions & 3 deletions server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ server.registerTool(
const results = data.map(
(
t: {
id: string;
content: string;
metadata: Record<string, unknown>;
similarity: number;
Expand All @@ -123,6 +124,7 @@ server.registerTool(
const m = t.metadata || {};
const parts = [
`--- Result ${i + 1} (${(t.similarity * 100).toFixed(1)}% match) ---`,
`ID: ${t.id}`,
`Captured: ${new Date(t.created_at).toLocaleDateString()}`,
`Type: ${m.type || "unknown"}`,
];
Expand Down Expand Up @@ -173,7 +175,7 @@ server.registerTool(
try {
let q = supabase
.from("thoughts")
.select("content, metadata, created_at")
.select("id, content, metadata, created_at")
.order("created_at", { ascending: false })
.limit(limit);

Expand Down Expand Up @@ -201,12 +203,12 @@ server.registerTool(

const results = data.map(
(
t: { content: string; metadata: Record<string, unknown>; created_at: string },
t: { id: string; content: string; metadata: Record<string, unknown>; created_at: string },
i: number
) => {
const m = t.metadata || {};
const tags = Array.isArray(m.topics) ? (m.topics as string[]).join(", ") : "";
return `${i + 1}. [${new Date(t.created_at).toLocaleDateString()}] (${m.type || "??"}${tags ? " - " + tags : ""})\n ${t.content}`;
return `${i + 1}. [${t.id}] [${new Date(t.created_at).toLocaleDateString()}] (${m.type || "??"}${tags ? " - " + tags : ""})\n ${t.content}`;
}
);

Expand Down Expand Up @@ -362,6 +364,66 @@ server.registerTool(
}
);

// Tool 5: Delete Thought
server.registerTool(
"delete_thought",
{
title: "Delete Thought",
description:
"Delete a thought from the Open Brain by its ID. Irreversible — use search_thoughts or list_thoughts to confirm the correct ID before deleting. Operates across the full database regardless of user context (single-user deployments only).",
inputSchema: {
id: z.string().describe("The UUID of the thought to delete (from search_thoughts or list_thoughts output)"),
},
},
async ({ id }) => {
try {
// First fetch the thought so we can confirm what was deleted
const { data: existing, error: fetchError } = await supabase
.from("thoughts")
.select("id, content, metadata")
.eq("id", id)
.single();

if (fetchError || !existing) {
return {
content: [{ type: "text" as const, text: `No thought found with ID: ${id}` }],
isError: true,
};
}

const { error } = await supabase
.from("thoughts")
.delete()
.eq("id", id);

if (error) {
return {
content: [{ type: "text" as const, text: `Failed to delete: ${error.message}` }],
isError: true,
};
}

const m = (existing.metadata || {}) as Record<string, unknown>;
const preview = existing.content.length > 100
? existing.content.substring(0, 100) + "..."
: existing.content;
return {
content: [
{
type: "text" as const,
text: `Deleted thought ${id} (${m.type || "unknown"}):\n${preview}`,
},
],
};
} catch (err: unknown) {
return {
content: [{ type: "text" as const, text: `Error: ${(err as Error).message}` }],
isError: true,
};
}
}
);

// --- Hono App with Auth + CORS ---

const corsHeaders = {
Expand Down
Loading