import { Type } from "typebox"; import { formatMemoryResult, formatAuthError, formatBillingError, formatUnavailableError, formatGenericError, formatApiKeyMissingError, formatSecurityBlocked } from "../format"; import { checkContent } from "../security"; export function makeMemoryTools(store) { return { add: { name: "alchemyst_memory_add", label: "Alchemyst Memory Add", description: "Persist one or more conversation turns from this coding session to AlchemystAI memory, keyed by session ID, so the conversation can be recalled later.", parameters: Type.Object({ contents: Type.Array( Type.Object({ content: Type.String({ description: "The conversation content" }), messageId: Type.Optional(Type.String()), }), ), groupName: Type.Optional(Type.Array(Type.String())), }), async execute(_toolCallId, params, signal, onUpdate, ctx) { if (!store.client) { return { content: [{ type: "text", text: formatApiKeyMissingError() }], details: {}, }; } const sessionId = ctx.sessionManager.getLeafId() || `session:${store.config.projectName}:${ctx.cwd}`; for (const entry of params.contents) { const check = checkContent(entry.content); if (check.blocked) { return { content: [ { type: "text", text: formatSecurityBlocked(check.category) }, ], details: {}, }; } } const result = await store.client.memoryAdd({ sessionId, contents: params.contents.map((c) => ({ content: c.content, metadata: c.messageId ? { messageId: c.messageId } : undefined, })), metadata: { groupName: params.groupName && params.groupName.length > 0 ? params.groupName : store.config.groupName, }, }); if (!result.ok) { if (result.status === 401 || result.status === 403) return { content: [{ type: "text", text: formatAuthError() }], details: {}, }; if (result.status === 402) return { content: [{ type: "text", text: formatBillingError() }], details: {}, }; if (result.status && result.status >= 500) return { content: [{ type: "text", text: formatUnavailableError() }], details: {}, }; return { content: [{ type: "text", text: formatGenericError(result.error) }], details: {}, }; } return { content: [ { type: "text", text: formatMemoryResult( result.data.context_id, result.data.processed_documents, ), }, ], details: { contextId: result.data.context_id, entries: result.data.processed_documents }, }; }, }, update: { name: "alchemyst_memory_update", label: "Alchemyst Memory Update", description: "Update or amend conversation turns already saved to AlchemystAI memory for the current session.", parameters: Type.Object({ contents: Type.Array( Type.Object({ content: Type.String({ description: "The updated conversation content" }), role: Type.Optional(Type.String()), id: Type.Optional(Type.String()), createdAt: Type.Optional(Type.String()), }), ), }), async execute(_toolCallId, params, signal, onUpdate, ctx) { if (!store.client) { return { content: [{ type: "text", text: formatApiKeyMissingError() }], details: {}, }; } const sessionId = ctx.sessionManager.getLeafId() || `session:${store.config.projectName}:${ctx.cwd}`; for (const entry of params.contents) { const check = checkContent(entry.content); if (check.blocked) { return { content: [ { type: "text", text: formatSecurityBlocked(check.category) }, ], details: {}, }; } } const result = await store.client.memoryUpdate({ sessionId, contents: params.contents.map((c) => ({ content: c.content, role: c.role, id: c.id, createdAt: c.createdAt, })), }); if (!result.ok) { if (result.status === 401 || result.status === 403) return { content: [{ type: "text", text: formatAuthError() }], details: {}, }; if (result.status === 402) return { content: [{ type: "text", text: formatBillingError() }], details: {}, }; if (result.status && result.status >= 500) return { content: [{ type: "text", text: formatUnavailableError() }], details: {}, }; return { content: [{ type: "text", text: formatGenericError(result.error) }], details: {}, }; } return { content: [ { type: "text", text: formatMemoryResult( result.data.memory_id, result.data.updated_entries, ), }, ], details: { memoryId: result.data.memory_id, entries: result.data.updated_entries }, }; }, }, }; }