aboutsummaryrefslogtreecommitdiff
path: root/packages/tools/src/vercel/util.ts
blob: eec29859bca52ded8e4b4f749e592c3e596c1912 (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
import type {
	LanguageModelV2,
	LanguageModelV2CallOptions,
	LanguageModelV2Message,
	LanguageModelV2StreamPart,
	LanguageModelV3,
	LanguageModelV3CallOptions,
	LanguageModelV3Message,
	LanguageModelV3StreamPart,
} from "@ai-sdk/provider"

// Union types for dual SDK version support (V2 = SDK 5, V3 = SDK 6)
export type LanguageModel = LanguageModelV2 | LanguageModelV3
export type LanguageModelCallOptions =
	| LanguageModelV2CallOptions
	| LanguageModelV3CallOptions
export type LanguageModelMessage =
	| LanguageModelV2Message
	| LanguageModelV3Message
export type LanguageModelStreamPart =
	| LanguageModelV2StreamPart
	| LanguageModelV3StreamPart

/**
 * Response structure from the Supermemory profile API.
 */
export interface ProfileStructure {
	profile: {
		/**
		 * Core, stable facts about the user that rarely change.
		 * Examples: name, profession, long-term preferences, goals.
		 */
		static?: Array<{ memory: string; metadata?: Record<string, unknown> }>
		/**
		 * Recently learned or frequently updated information about the user.
		 * Examples: current projects, recent interests, ongoing topics.
		 */
		dynamic?: Array<{ memory: string; metadata?: Record<string, unknown> }>
	}
	searchResults: {
		/**
		 * Memories retrieved based on semantic similarity to the current query.
		 * Most relevant to the immediate conversation context.
		 */
		results: Array<{ memory: string; metadata?: Record<string, unknown> }>
	}
}

/**
 * Simplified profile data for markdown conversion.
 */
export interface ProfileMarkdownData {
	profile: {
		/** Core, stable user facts (name, preferences, goals) */
		static?: string[]
		/** Recently learned or updated information (current projects, interests) */
		dynamic?: string[]
	}
	searchResults: {
		/** Query-relevant memories based on semantic similarity */
		results: Array<{ memory: string }>
	}
}

export type OutputContentItem =
	| { type: "text"; text: string }
	| { type: "reasoning"; text: string }
	| {
			type: "tool-call"
			id: string
			function: { name: string; arguments: string }
	  }
	| { type: "file"; name: string; mediaType: string; data: string }
	| {
			type: "source"
			sourceType: string
			id: string
			url: string
			title: string
	  }

/**
 * Convert profile data to markdown format
 * @param data Profile data with string arrays for static and dynamic memories
 * @returns Markdown string with profile sections
 */
export function convertProfileToMarkdown(data: ProfileMarkdownData): string {
	const sections: string[] = []

	if (data.profile.static && data.profile.static.length > 0) {
		sections.push("## Static Profile")
		sections.push(data.profile.static.map((item) => `- ${item}`).join("\n"))
	}

	if (data.profile.dynamic && data.profile.dynamic.length > 0) {
		sections.push("## Dynamic Profile")
		sections.push(data.profile.dynamic.map((item) => `- ${item}`).join("\n"))
	}

	return sections.join("\n\n")
}

export const getLastUserMessage = (params: LanguageModelCallOptions) => {
	const lastUserMessage = params.prompt
		.slice()
		.reverse()
		.find((prompt: LanguageModelMessage) => prompt.role === "user")
	const memories = lastUserMessage?.content
		.filter((content) => content.type === "text")
		.map((content) => (content as { type: "text"; text: string }).text)
		.join(" ")
	return memories
}

export const filterOutSupermemories = (content: string) => {
	return content.split("User Supermemories: ")[0]
}