Skip to content
Merged
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
70 changes: 70 additions & 0 deletions lib/artist/createKnowledgeBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { uploadToArweave } from "@/lib/arweave/uploadToArweave";
import { arweaveGatewayUrl } from "@/lib/arweave/arweaveGatewayUrl";
import { selectAccountInfo } from "@/lib/supabase/account_info/selectAccountInfo";
import { updateAccountInfo } from "@/lib/supabase/account_info/updateAccountInfo";
import { insertAccountInfo } from "@/lib/supabase/account_info/insertAccountInfo";
import type { Knowledge } from "./updateArtistProfile";

/**
* Creates a knowledge base entry for an artist by uploading text to Arweave
* and appending it to the artist's knowledges array.
*
* @param artistId - The artist account ID
* @param knowledgeBaseText - The text content to add to the knowledge base
* @returns The created knowledge entry with Arweave URL
*/
export async function createKnowledgeBase(
artistId: string,
knowledgeBaseText: string,
): Promise<Knowledge> {
if (!knowledgeBaseText || knowledgeBaseText.trim().length === 0) {
throw new Error("Knowledge base text is required");
}

// Upload text to Arweave
const textBuffer = Buffer.from(knowledgeBaseText, "utf-8");
const transaction = await uploadToArweave(textBuffer, "text/plain");
const arweaveUrl = `ar://${transaction.id}`;
const fetchableUrl = arweaveGatewayUrl(arweaveUrl);

// Generate a name from the first line or a default name
const firstLine = knowledgeBaseText.split("\n")[0].trim();
const name = firstLine.length > 0 && firstLine.length <= 100 ? firstLine : "Knowledge Base Entry";

// Create the knowledge entry
const newKnowledge: Knowledge = {
url: fetchableUrl || arweaveUrl,
name,
type: "text/plain",
};

// Get current account_info
const accountInfo = await selectAccountInfo(artistId);

// Get existing knowledges or initialize empty array
const existingKnowledges: Knowledge[] = accountInfo?.knowledges
? (accountInfo.knowledges as unknown as Knowledge[])
: [];

// Append new knowledge (deduplicate by URL)
const knowledgeMap = new Map<string, Knowledge>();
existingKnowledges.forEach(k => {
knowledgeMap.set(k.url, k);
});
knowledgeMap.set(newKnowledge.url, newKnowledge);
const updatedKnowledges = Array.from(knowledgeMap.values());

// Update account_info
if (accountInfo) {
await updateAccountInfo(artistId, {
knowledges: updatedKnowledges as unknown as typeof accountInfo.knowledges,
});
} else {
await insertAccountInfo({
account_id: artistId,
knowledges: updatedKnowledges as unknown as typeof accountInfo.knowledges,
});
}

return newKnowledge;
}
2 changes: 2 additions & 0 deletions lib/mcp/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { registerContactTeamTool } from "./registerContactTeamTool";
import { registerUpdateAccountInfoTool } from "./registerUpdateAccountInfoTool";
import { registerAllArtistSocialsTools } from "./artistSocials";
import { registerSearchWebTool } from "./registerSearchWebTool";
import { registerCreateKnowledgeBaseTool } from "./registerCreateKnowledgeBaseTool";

/**
* Registers all MCP tools on the server.
Expand All @@ -27,4 +28,5 @@ export const registerAllTools = (server: McpServer): void => {
registerContactTeamTool(server);
registerUpdateAccountInfoTool(server);
registerSearchWebTool(server);
registerCreateKnowledgeBaseTool(server);
};
54 changes: 54 additions & 0 deletions lib/mcp/tools/registerCreateKnowledgeBaseTool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { createKnowledgeBase } from "@/lib/artist/createKnowledgeBase";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";
import { getToolResultError } from "@/lib/mcp/getToolResultError";

const createKnowledgeBaseSchema = z.object({
artistId: z
.string()
.min(1, "Artist account ID is required")
.describe(
"The artist_account_id to add the knowledge base to. If not provided, check system prompt for the active artist_account_id.",
),
knowledgeBaseText: z
.string()
.min(1, "Knowledge base text is required")
.describe("Text to add to the knowledge base"),
});

type CreateKnowledgeBaseArgs = z.infer<typeof createKnowledgeBaseSchema>;

/**
* Registers the "create_knowledge_base" tool on the MCP server.
* Adds a knowledge base file to an artist by uploading text to Arweave and appending it to the artist's knowledges.
*
* @param server - The MCP server instance to register the tool on.
*/
export function registerCreateKnowledgeBaseTool(server: McpServer): void {
server.registerTool(
"create_knowledge_base",
{
description: `Adds a knowledge base file to the active artist by generating a text file and appending it to the list of existing knowledge bases. The text will be uploaded to Arweave for permanent storage.`,
inputSchema: createKnowledgeBaseSchema,
},
async (args: CreateKnowledgeBaseArgs) => {
try {
const knowledge = await createKnowledgeBase(args.artistId, args.knowledgeBaseText);

const response = {
success: true,
knowledge,
message: "Knowledge base text prepared for creation and storage.",
};

return getToolResultSuccess(response);
} catch (error) {
console.error("Error creating knowledge base:", error);
return getToolResultError(
error instanceof Error ? error.message : "Failed to create knowledge base",
);
}
},
);
}