aboutsummaryrefslogtreecommitdiff
path: root/packages/tools/src/vercel/memory-prompt.ts
blob: 8b2e302b782469a1eecb9e0e5a02e5f6c1f75678 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import type { LanguageModelV2CallOptions } from "@ai-sdk/provider"
import type { Logger } from "./logger"
import { convertProfileToMarkdown, type ProfileStructure } from "./util"

const supermemoryProfileSearch = async (
	containerTag: string,
	queryText: string,
): Promise<ProfileStructure> => {
	const payload = queryText
		? JSON.stringify({
				q: queryText,
				containerTag: containerTag,
			})
		: JSON.stringify({
				containerTag: containerTag,
			})

	try {
		const response = await fetch("https://api.supermemory.ai/v4/profile", {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				Authorization: `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
			},
			body: payload,
		})

		if (!response.ok) {
			const errorText = await response.text().catch(() => "Unknown error")
			throw new Error(
				`Supermemory profile search failed: ${response.status} ${response.statusText}. ${errorText}`,
			)
		}

		return await response.json()
	} catch (error) {
		if (error instanceof Error) {
			throw error
		}
		throw new Error(`Supermemory API request failed: ${error}`)
	}
}

export const addSystemPrompt = async (
	params: LanguageModelV2CallOptions,
	containerTag: string,
	logger: Logger,
	mode: "profile" | "query" | "full",
) => {
	const systemPromptExists = params.prompt.some(
		(prompt) => prompt.role === "system",
	)

	const queryText =
		mode !== "profile"
			? params.prompt
					.slice()
					.reverse()
					.find((prompt) => prompt.role === "user")
					?.content?.filter((content) => content.type === "text")
					?.map((content) => (content.type === "text" ? content.text : ""))
					?.join(" ") || ""
			: ""

	const memoriesResponse = await supermemoryProfileSearch(
		containerTag,
		queryText,
	)

	const memoryCountStatic = memoriesResponse.profile.static?.length || 0
	const memoryCountDynamic = memoriesResponse.profile.dynamic?.length || 0

	logger.info("Memory search completed", {
		containerTag,
		memoryCountStatic,
		memoryCountDynamic,
		queryText:
			queryText.substring(0, 100) + (queryText.length > 100 ? "..." : ""),
		mode,
	})

	const profileData =
		mode !== "query" ? convertProfileToMarkdown(memoriesResponse) : ""
	const searchResultsMemories =
		mode !== "profile"
			? `Search results for user's recent message: \n${memoriesResponse.searchResults.results
					.map((result) => `- ${result.memory}`)
					.join("\n")}`
			: ""

	const memories =
		`User Supermemories: \n${profileData}\n${searchResultsMemories}`.trim()
	if (memories) {
		logger.debug("Memory content preview", {
			content: memories,
			fullLength: memories.length,
		})
	}

	if (systemPromptExists) {
		logger.debug("Added memories to existing system prompt")
		return {
			...params,
			prompt: params.prompt.map((prompt) =>
				prompt.role === "system"
					? { ...prompt, content: `${prompt.content} \n ${memories}` }
					: prompt,
			),
		}
	}

	logger.debug(
		"System prompt does not exist, created system prompt with memories",
	)
	return {
		...params,
		prompt: [{ role: "system" as const, content: memories }, ...params.prompt],
	}
}