This commit is contained in:
vivek varikuti 2026-08-26 03:58:08 +05:30 committed by GitHub
commit 325bb26818
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 145 additions and 0 deletions

View file

@ -50,6 +50,7 @@ Your assistant chooses these tools automatically. Use this table when you need t
| `add_memory` | Save information or forget outdated information | `content` (required), `action` (`save` or `forget`), `containerTag` | Save or forget confirmation |
| `listDocuments` | Browse stored source documents and their summaries | `page`, `limit`, `containerTag` | Document IDs, titles, types, status, dates, and summaries |
| `getDocument` | Read the available content of one document | `documentId` (required) | Document metadata, summary, and available content |
| `deleteDocument` | Permanently delete one document and the memories extracted from it | `documentId` (required) | Deletion confirmation |
| `listMemories` | Browse recent extracted memory entries and their source document IDs | `page`, `limit`, `containerTag` | Memory IDs, text, versions, and source document IDs |
| `listSpaces` | List accessible spaces and resolve a space name to its key | None | Formatted list plus structured `spaces` and `count` fields |
| `whoAmI` | Inspect the authenticated account, permissions, scope, and active space | None | Account and access context |
@ -70,6 +71,8 @@ Use the retrieval tools for different questions:
`add_memory` saves the supplied `content` by default. Set `action` to `forget` when a fact is outdated or should be removed. There is no separate forget tool.
When the exact source is known, `deleteDocument` permanently removes that document and the memories extracted from it by `documentId` (from `listDocuments` or a memory result). Unlike `forget`, it does not rely on content matching, so it cannot remove the wrong memory. Deletion cannot be undone.
If the content is already final, the assistant should use `add_memory`. If you want to review, edit, or choose a space before saving, it should open the `guided-save` widget instead.
### Access control

View file

@ -393,6 +393,15 @@ export class SupermemoryClient {
}
}
async deleteDocument(id: string): Promise<{ id: string }> {
try {
await this.client.documents.delete(id)
return { id }
} catch (error) {
this.handleOperationError("Delete document request", error)
}
}
async listMemoryEntries(
page = 1,
limit = 50,

View file

@ -0,0 +1,77 @@
import { describe, expect, it, vi } from "vitest"
import type { SupermemoryClient } from "../client"
import * as deleteDocument from "./delete-document"
import { errorResult, type ToolDeps } from "./types"
type ToolHandler = (args: { documentId: string }) => Promise<{
content: Array<{ type: string; text: string }>
structuredContent?: { success: boolean; id: string }
isError?: boolean
}>
function registerWithClient(client: Partial<SupermemoryClient>) {
let handler: ToolHandler | undefined
let config: Record<string, unknown> | undefined
const registerTool = vi.fn(
(_name: string, toolConfig: Record<string, unknown>, cb: ToolHandler) => {
config = toolConfig
handler = cb
return {}
},
)
const deps = {
server: { registerTool },
getClient: () => client as SupermemoryClient,
errorResult,
} as unknown as ToolDeps
deleteDocument.register(deps)
if (!handler || !config) throw new Error("Tool was not registered")
return { handler, config, registerTool }
}
describe("deleteDocument tool", () => {
it("deletes the document by id and reports success", async () => {
const deleteDocumentMock = vi.fn().mockResolvedValue({ id: "doc_123" })
const { handler } = registerWithClient({
deleteDocument: deleteDocumentMock,
})
const result = await handler({ documentId: "doc_123" })
expect(deleteDocumentMock).toHaveBeenCalledWith("doc_123")
expect(result.structuredContent).toEqual({ success: true, id: "doc_123" })
expect(result.isError).toBeUndefined()
expect(result.content[0]?.text).toContain("doc_123")
})
it("returns an error result when deletion fails", async () => {
const { handler } = registerWithClient({
deleteDocument: vi
.fn()
.mockRejectedValue(new Error("Document not found")),
})
const result = await handler({ documentId: "doc_missing" })
expect(result.isError).toBe(true)
expect(result.content[0]?.text).toContain("Document not found")
})
it("registers as a destructive, non-read-only tool", () => {
const { config, registerTool } = registerWithClient({
deleteDocument: vi.fn(),
})
expect(registerTool).toHaveBeenCalledWith(
"deleteDocument",
expect.anything(),
expect.any(Function),
)
expect(config?.annotations).toMatchObject({
readOnlyHint: false,
destructiveHint: true,
})
})
})

View file

@ -0,0 +1,47 @@
import { z } from "zod"
import { MEMORY_TOOL_ANNOTATIONS } from "./annotations"
import {
deleteDocumentOutputSchema,
type DeleteDocumentOutput,
} from "./output-schemas"
import { textContent, type ToolDeps } from "./types"
export function register(deps: ToolDeps) {
const inputSchema = z.object({
documentId: z
.string()
.min(1, "Document ID is required")
.max(255, "Document ID exceeds maximum length")
.describe("Document ID returned by listDocuments or a memory result"),
})
deps.server.registerTool(
"deleteDocument",
{
title: "Delete Document",
description:
"Permanently delete one stored document by ID, along with the memories extracted from it. This cannot be undone. Use listDocuments or getDocument first to confirm the target; prefer this over add_memory's forget action when the exact document is known.",
inputSchema,
outputSchema: deleteDocumentOutputSchema,
annotations: MEMORY_TOOL_ANNOTATIONS,
},
async (args) => {
try {
const client = deps.getClient()
await client.deleteDocument(args.documentId)
const structuredContent: DeleteDocumentOutput = {
success: true,
id: args.documentId,
}
return {
content: [
textContent(`Deleted document ${args.documentId} permanently.`),
],
structuredContent,
}
} catch (error) {
return deps.errorResult(error)
}
},
)
}

View file

@ -1,4 +1,5 @@
import * as addMemory from "./add-memory"
import * as deleteDocument from "./delete-document"
import * as fetchGraphData from "./fetch-graph-data"
import * as getDocument from "./get-document"
import * as guidedSave from "./guided-save"
@ -19,6 +20,7 @@ export function registerAllTools(deps: ToolDeps) {
searchMemory.register(deps)
listDocuments.register(deps)
getDocument.register(deps)
deleteDocument.register(deps)
listMemories.register(deps)
listContainerTags.register(deps)
whoAmI.register(deps)

View file

@ -54,6 +54,13 @@ export const addMemoryOutputSchema = z.object({
export type AddMemoryOutput = z.infer<typeof addMemoryOutputSchema>
export const deleteDocumentOutputSchema = z.object({
success: z.boolean(),
id: z.string(),
})
export type DeleteDocumentOutput = z.infer<typeof deleteDocumentOutputSchema>
export const getDocumentOutputSchema = z.object({
document: z.object({
id: z.string(),