chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { mem0AddMemoriesTool } from '@/tools/mem0/add_memories'
import type { Mem0AddMemoriesParams } from '@/tools/mem0/types'
describe('mem0AddMemoriesTool', () => {
const buildBody = mem0AddMemoriesTool.request.body!
const transformResponse = mem0AddMemoriesTool.transformResponse!
it('uses the v3 add memories endpoint', () => {
expect(mem0AddMemoriesTool.request.url).toBe('https://api.mem0.ai/v3/memories/add/')
expect(mem0AddMemoriesTool.request.method).toBe('POST')
})
it('builds the documented add memories request body', () => {
const body = buildBody({
apiKey: 'test-key',
userId: ' alice ',
messages: [{ role: 'user', content: 'I like Sim.' }],
})
expect(body).toEqual({
messages: [{ role: 'user', content: 'I like Sim.' }],
user_id: 'alice',
})
})
it('accepts JSON string messages from the block code input', () => {
const params: Mem0AddMemoriesParams = {
apiKey: 'test-key',
userId: 'alice',
messages: JSON.stringify([{ role: 'assistant', content: 'I will remember that.' }]),
}
expect(buildBody(params)).toEqual({
messages: [{ role: 'assistant', content: 'I will remember that.' }],
user_id: 'alice',
})
})
it('rejects unsupported message roles before building the request body', () => {
expect(() =>
buildBody({
apiKey: 'test-key',
userId: 'alice',
messages: JSON.stringify([{ role: 'system', content: 'Remember this.' }]),
})
).toThrow('Each message must have role user or assistant and non-empty content')
})
it('extracts queued processing fields from v3 responses', async () => {
const result = await transformResponse(
new Response(
JSON.stringify({
message: 'Memory processing has been queued for background execution',
status: 'PENDING',
event_id: 'evt-123',
})
)
)
expect(result).toEqual({
success: true,
output: {
message: 'Memory processing has been queued for background execution',
status: 'PENDING',
event_id: 'evt-123',
},
})
})
})
+74
View File
@@ -0,0 +1,74 @@
import {
ADD_MEMORY_OUTPUT_PROPERTIES,
type Mem0AddMemoriesParams,
type Mem0AddMemoriesResponse,
} from '@/tools/mem0/types'
import { parseMem0Messages } from '@/tools/mem0/utils'
import type { ToolConfig } from '@/tools/types'
/**
* Add Memories Tool
* @see https://docs.mem0.ai/api-reference/memory/add-memories
*/
export const mem0AddMemoriesTool: ToolConfig<Mem0AddMemoriesParams, Mem0AddMemoriesResponse> = {
id: 'mem0_add_memories',
name: 'Add Memories',
description: 'Add memories to Mem0 for persistent storage and retrieval',
version: '1.0.0',
params: {
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'User ID associated with the memory (e.g., "user_123", "alice@example.com")',
},
messages: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description:
'Array of message objects with role and content (e.g., [{"role": "user", "content": "Hello"}])',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Your Mem0 API key',
},
},
request: {
url: 'https://api.mem0.ai/v3/memories/add/',
method: 'POST',
headers: (params) => ({
Authorization: `Token ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const messages = parseMem0Messages(params.messages)
return {
messages,
user_id: params.userId.trim(),
}
},
},
transformResponse: async (response): Promise<Mem0AddMemoriesResponse> => {
const data = await response.json()
return {
success: true,
output: {
message: data.message ?? '',
status: data.status ?? '',
event_id: data.event_id ?? '',
},
}
},
outputs: {
message: ADD_MEMORY_OUTPUT_PROPERTIES.message,
status: ADD_MEMORY_OUTPUT_PROPERTIES.status,
event_id: ADD_MEMORY_OUTPUT_PROPERTIES.event_id,
},
}
+122
View File
@@ -0,0 +1,122 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { mem0GetMemoriesTool } from '@/tools/mem0/get_memories'
interface Mem0GetParams {
apiKey: string
userId?: string
memoryId?: string
startDate?: string
endDate?: string
page?: number
limit?: number
}
describe('mem0GetMemoriesTool', () => {
const buildUrl = mem0GetMemoriesTool.request.url as (params: Mem0GetParams) => string
const buildMethod = mem0GetMemoriesTool.request.method as (params: Mem0GetParams) => string
const buildBody = mem0GetMemoriesTool.request.body!
const transformResponse = mem0GetMemoriesTool.transformResponse!
it('uses scoped v3 list memories requests', () => {
const params = {
apiKey: 'test-key',
userId: 'user-123',
page: 3,
limit: 25,
}
expect(buildUrl(params)).toBe('https://api.mem0.ai/v3/memories/')
expect(buildMethod(params)).toBe('POST')
expect(buildBody(params)).toEqual({
filters: {
user_id: 'user-123',
},
page: 3,
page_size: 25,
})
})
it('keeps date filters inside the scoped filter object', () => {
const body = buildBody({
apiKey: 'test-key',
userId: 'user-123',
startDate: '2026-01-01',
endDate: '2026-01-31',
})
expect(body).toEqual({
filters: {
user_id: 'user-123',
created_at: {
gte: '2026-01-01',
lte: '2026-01-31',
},
},
page: 1,
page_size: 10,
})
})
it('uses the single-memory endpoint for memoryId requests', () => {
const params = {
apiKey: 'test-key',
userId: 'user-123',
memoryId: 'mem/123',
}
expect(buildUrl(params)).toBe('https://api.mem0.ai/v1/memories/mem%2F123/')
expect(buildMethod(params)).toBe('GET')
expect(buildBody(params)).toBeUndefined()
})
it('extracts memories from paginated v3 responses', async () => {
const result = await transformResponse(
new Response(
JSON.stringify({
count: 2,
next: 'https://api.mem0.ai/v3/memories/?page=2&page_size=25',
previous: null,
results: [
{ id: 'mem-1', memory: 'First memory.', user_id: 'user-123' },
{ id: 'mem-2', memory: 'Second memory.', user_id: 'user-123' },
],
})
)
)
expect(result.output).toEqual({
memories: [
{ id: 'mem-1', memory: 'First memory.', user_id: 'user-123' },
{ id: 'mem-2', memory: 'Second memory.', user_id: 'user-123' },
],
ids: ['mem-1', 'mem-2'],
count: 2,
next: 'https://api.mem0.ai/v3/memories/?page=2&page_size=25',
previous: null,
})
})
it('extracts direct single memory responses without rewriting fields', async () => {
const result = await transformResponse(
new Response(
JSON.stringify({
id: 'mem-1',
memory: 'Stored memory content.',
created_at: '2026-01-01T00:00:00Z',
})
)
)
expect(result.output.memories).toEqual([
{
id: 'mem-1',
memory: 'Stored memory content.',
created_at: '2026-01-01T00:00:00Z',
},
])
expect(result.output.ids).toEqual(['mem-1'])
})
})
+168
View File
@@ -0,0 +1,168 @@
import { isRecordLike } from '@sim/utils/object'
import { MEMORY_OUTPUT_PROPERTIES, type Mem0GetMemoriesParams } from '@/tools/mem0/types'
import type { ToolConfig } from '@/tools/types'
const getMemoriesFromResponse = (data: unknown): unknown[] => {
if (Array.isArray(data)) return data
if (!isRecordLike(data)) return []
if (Array.isArray(data.results)) return data.results
if (isRecordLike(data.memory)) return [data.memory]
if (data.id) return [data]
return []
}
const getMemoryId = (memory: unknown): string | undefined =>
isRecordLike(memory) && typeof memory.id === 'string' ? memory.id : undefined
/**
* Get Memories Tool
* @see https://docs.mem0.ai/api-reference/memory/get-memories
*/
export const mem0GetMemoriesTool: ToolConfig<Mem0GetMemoriesParams> = {
id: 'mem0_get_memories',
name: 'Get Memories',
description: 'Retrieve memories from Mem0 by ID or filter criteria',
version: '1.0.0',
params: {
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'User ID to retrieve memories for (e.g., "user_123", "alice@example.com")',
},
memoryId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Specific memory ID to retrieve (e.g., "mem_abc123")',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start date for filtering by created_at (e.g., "2024-01-15")',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End date for filtering by created_at (e.g., "2024-12-31")',
},
limit: {
type: 'number',
required: false,
default: 10,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (e.g., 10, 50, 100)',
},
page: {
type: 'number',
required: false,
default: 1,
visibility: 'user-or-llm',
description: 'Page number to retrieve for paginated list results',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Your Mem0 API key',
},
},
request: {
url: (params) => {
const memoryId = typeof params.memoryId === 'string' ? params.memoryId.trim() : undefined
if (memoryId) {
return `https://api.mem0.ai/v1/memories/${encodeURIComponent(memoryId)}/`
}
return 'https://api.mem0.ai/v3/memories/'
},
method: (params) =>
typeof params.memoryId === 'string' && params.memoryId.trim() ? 'GET' : 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Token ${params.apiKey}`,
}),
body: (params) => {
if (typeof params.memoryId === 'string' && params.memoryId.trim()) {
return undefined
}
const filters: Record<string, unknown> = {
user_id: params.userId?.trim(),
}
if (params.startDate || params.endDate) {
const dateFilter: Record<string, unknown> = {}
if (params.startDate) {
dateFilter.gte = params.startDate
}
if (params.endDate) {
dateFilter.lte = params.endDate
}
filters.created_at = dateFilter
}
return {
filters,
page: Number(params.page ?? 1),
page_size: Number(params.limit || 10),
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
const memories = getMemoriesFromResponse(data)
const ids = memories.map(getMemoryId).filter((id): id is string => Boolean(id))
return {
success: true,
output: {
memories,
ids,
...(isRecordLike(data) && typeof data.count === 'number' ? { count: data.count } : {}),
...(isRecordLike(data) && (typeof data.next === 'string' || data.next === null)
? { next: data.next }
: {}),
...(isRecordLike(data) && (typeof data.previous === 'string' || data.previous === null)
? { previous: data.previous }
: {}),
},
}
},
outputs: {
memories: {
type: 'array',
description: 'Array of retrieved memory objects',
items: {
type: 'object',
properties: MEMORY_OUTPUT_PROPERTIES,
},
},
ids: {
type: 'array',
description: 'Array of memory IDs that were retrieved',
items: {
type: 'string',
},
},
count: {
type: 'number',
description: 'Total number of memories matching the filters',
optional: true,
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
},
}
+7
View File
@@ -0,0 +1,7 @@
import { mem0AddMemoriesTool } from '@/tools/mem0/add_memories'
import { mem0GetMemoriesTool } from '@/tools/mem0/get_memories'
import { mem0SearchMemoriesTool } from '@/tools/mem0/search_memories'
export { mem0AddMemoriesTool, mem0SearchMemoriesTool, mem0GetMemoriesTool }
export * from '@/tools/mem0/types'
export * from '@/tools/mem0/utils'
@@ -0,0 +1,72 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { mem0SearchMemoriesTool } from '@/tools/mem0/search_memories'
describe('mem0SearchMemoriesTool', () => {
const buildBody = mem0SearchMemoriesTool.request.body!
const transformResponse = mem0SearchMemoriesTool.transformResponse!
it('uses the v3 search endpoint', () => {
expect(mem0SearchMemoriesTool.request.url).toBe('https://api.mem0.ai/v3/memories/search/')
expect(mem0SearchMemoriesTool.request.method).toBe('POST')
})
it('builds the documented search request body', () => {
const body = buildBody({
apiKey: 'test-key',
userId: ' alice ',
query: 'where does the user live?',
limit: 20,
})
expect(body).toEqual({
query: 'where does the user live?',
filters: {
user_id: 'alice',
},
top_k: 20,
})
})
it('extracts results from v3 response envelopes', async () => {
const result = await transformResponse(
new Response(
JSON.stringify({
results: [
{
id: 'mem-1',
memory: 'User lives in San Francisco.',
user_id: 'alice',
categories: ['location'],
score: 0.82,
created_at: '2026-01-15T10:30:00Z',
updated_at: '2026-01-15T10:30:00Z',
},
],
})
)
)
expect(result.output).toEqual({
searchResults: [
{
id: 'mem-1',
memory: 'User lives in San Francisco.',
user_id: 'alice',
agent_id: undefined,
app_id: undefined,
run_id: undefined,
hash: undefined,
metadata: undefined,
categories: ['location'],
created_at: '2026-01-15T10:30:00Z',
updated_at: '2026-01-15T10:30:00Z',
score: 0.82,
},
],
ids: ['mem-1'],
})
})
})
+123
View File
@@ -0,0 +1,123 @@
import { isRecordLike } from '@sim/utils/object'
import type { Mem0Response, Mem0SearchMemoriesParams } from '@/tools/mem0/types'
import { SEARCH_RESULT_OUTPUT_PROPERTIES } from '@/tools/mem0/types'
import type { JsonRecord } from '@/tools/mem0/utils'
import type { ToolConfig } from '@/tools/types'
const getSearchResults = (data: unknown): JsonRecord[] => {
if (!isRecordLike(data) || !Array.isArray(data.results)) return []
return data.results.filter(isRecordLike)
}
const getString = (value: unknown): string | undefined =>
typeof value === 'string' ? value : undefined
const getStringArray = (value: unknown): string[] | undefined =>
Array.isArray(value)
? value.filter((item): item is string => typeof item === 'string')
: undefined
const getNumber = (value: unknown, fallback = 0): number =>
typeof value === 'number' ? value : fallback
/**
* Search Memories Tool
* @see https://docs.mem0.ai/api-reference/memory/search-memories
*/
export const mem0SearchMemoriesTool: ToolConfig<Mem0SearchMemoriesParams, Mem0Response> = {
id: 'mem0_search_memories',
name: 'Search Memories',
description: 'Search for memories in Mem0 using semantic search',
version: '1.0.0',
params: {
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'User ID to search memories for (e.g., "user_123", "alice@example.com")',
},
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Search query to find relevant memories (e.g., "What are my favorite foods?")',
},
limit: {
type: 'number',
required: false,
default: 10,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (e.g., 10, 50, 100)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Your Mem0 API key',
},
},
request: {
url: 'https://api.mem0.ai/v3/memories/search/',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Token ${params.apiKey}`,
}),
body: (params) => {
return {
query: params.query,
filters: {
user_id: params.userId.trim(),
},
top_k: Number(params.limit || 10),
}
},
},
transformResponse: async (response): Promise<Mem0Response> => {
const data = await response.json()
const searchResults = getSearchResults(data).map((result) => ({
id: getString(result.id) ?? '',
memory: getString(result.memory) ?? '',
user_id: getString(result.user_id),
agent_id: getString(result.agent_id),
app_id: getString(result.app_id),
run_id: getString(result.run_id),
hash: getString(result.hash),
metadata: isRecordLike(result.metadata) ? result.metadata : undefined,
categories: getStringArray(result.categories),
created_at: getString(result.created_at),
updated_at: getString(result.updated_at),
score: getNumber(result.score),
}))
const ids = searchResults.map((result) => result.id).filter(Boolean)
return {
success: true,
output: {
searchResults,
ids,
},
}
},
outputs: {
searchResults: {
type: 'array',
description: 'Array of search results with memory data and similarity scores',
items: {
type: 'object',
properties: SEARCH_RESULT_OUTPUT_PROPERTIES,
},
},
ids: {
type: 'array',
description: 'Array of memory IDs found in the search results',
items: {
type: 'string',
},
},
},
}
+191
View File
@@ -0,0 +1,191 @@
import type { OutputProperty, ToolResponse } from '@/tools/types'
export interface Mem0Message {
role: 'user' | 'assistant'
content: string
}
export interface Mem0AddMemoriesParams {
userId: string
messages: Mem0Message[] | string
apiKey: string
}
export interface Mem0SearchMemoriesParams {
userId: string
query: string
limit?: number
apiKey: string
}
export interface Mem0GetMemoriesParams {
userId?: string
memoryId?: string
startDate?: string
endDate?: string
page?: number
limit?: number
apiKey: string
}
export interface Mem0AddMemoriesResponse extends ToolResponse {
output: {
message: string
status: string
event_id: string
}
}
/**
* Shared output property definitions for Mem0 API responses.
* Based on official Mem0 REST API documentation.
* @see https://docs.mem0.ai/api-reference
*/
/**
* Output definition for queued add-memory operations.
* @see https://docs.mem0.ai/api-reference/memory/add-memories
*/
export const ADD_MEMORY_OUTPUT_PROPERTIES = {
message: { type: 'string', description: 'Status message for the queued memory processing job' },
status: {
type: 'string',
description: 'Processing status returned by Mem0',
},
event_id: {
type: 'string',
description: 'Event ID for polling memory processing status',
},
} as const satisfies Record<string, OutputProperty>
/**
* Complete add memory object output definition
*/
export const ADD_MEMORY_OUTPUT: OutputProperty = {
type: 'object',
description: 'Queued memory processing job returned from add operation',
properties: ADD_MEMORY_OUTPUT_PROPERTIES,
}
/**
* Output definition for memory objects returned by get operations.
* Get responses include full memory details with timestamps and ownership info.
* @see https://docs.mem0.ai/api-reference/memory/get-memories
*/
export const MEMORY_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Unique identifier for the memory' },
memory: { type: 'string', description: 'The content of the memory' },
user_id: { type: 'string', description: 'User ID associated with this memory', optional: true },
agent_id: { type: 'string', description: 'Agent ID associated with this memory', optional: true },
app_id: { type: 'string', description: 'App ID associated with this memory', optional: true },
run_id: {
type: 'string',
description: 'Run/session ID associated with this memory',
optional: true,
},
hash: { type: 'string', description: 'Hash of the memory content', optional: true },
metadata: {
type: 'json',
description: 'Custom metadata associated with the memory',
optional: true,
},
categories: {
type: 'json',
description: 'Auto-assigned categories for the memory',
optional: true,
},
created_at: { type: 'string', description: 'ISO 8601 timestamp when the memory was created' },
updated_at: {
type: 'string',
description: 'ISO 8601 timestamp when the memory was last updated',
},
} as const satisfies Record<string, OutputProperty>
/**
* Complete memory object output definition
*/
export const MEMORY_OUTPUT: OutputProperty = {
type: 'object',
description: 'Memory object with full details including timestamps and ownership',
properties: MEMORY_OUTPUT_PROPERTIES,
}
/**
* Output definition for search result objects returned by search operations.
* Search responses include similarity score in addition to memory details.
* @see https://docs.mem0.ai/api-reference/memory/search-memories
*/
export const SEARCH_RESULT_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Unique identifier for the memory' },
memory: { type: 'string', description: 'The content of the memory' },
user_id: { type: 'string', description: 'User ID associated with this memory', optional: true },
agent_id: { type: 'string', description: 'Agent ID associated with this memory', optional: true },
app_id: { type: 'string', description: 'App ID associated with this memory', optional: true },
run_id: {
type: 'string',
description: 'Run/session ID associated with this memory',
optional: true,
},
hash: { type: 'string', description: 'Hash of the memory content', optional: true },
metadata: {
type: 'json',
description: 'Custom metadata associated with the memory',
optional: true,
},
categories: {
type: 'json',
description: 'Auto-assigned categories for the memory',
optional: true,
},
created_at: { type: 'string', description: 'ISO 8601 timestamp when the memory was created' },
updated_at: {
type: 'string',
description: 'ISO 8601 timestamp when the memory was last updated',
},
score: { type: 'number', description: 'Similarity score from vector search' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete search result object output definition
*/
export const SEARCH_RESULT_OUTPUT: OutputProperty = {
type: 'object',
description: 'Search result with memory details and similarity score',
properties: SEARCH_RESULT_OUTPUT_PROPERTIES,
}
export interface Mem0Response extends ToolResponse {
output: {
ids?: string[]
memories?: Array<{
id: string
memory: string
user_id?: string
agent_id?: string
app_id?: string
run_id?: string
hash?: string
metadata?: Record<string, unknown>
categories?: string[]
created_at?: string
updated_at?: string
}>
count?: number
next?: string | null
previous?: string | null
searchResults?: Array<{
id: string
memory: string
user_id?: string
agent_id?: string
app_id?: string
run_id?: string
hash?: string
metadata?: Record<string, unknown>
categories?: string[]
created_at?: string
updated_at?: string
score: number
}>
}
}
+39
View File
@@ -0,0 +1,39 @@
import { toError } from '@sim/utils/errors'
import type { Mem0Message } from '@/tools/mem0/types'
export type JsonRecord = Record<string, unknown>
function isMem0Message(value: unknown): value is Mem0Message {
return (
value !== null &&
typeof value === 'object' &&
'role' in value &&
'content' in value &&
(value.role === 'user' || value.role === 'assistant') &&
typeof value.content === 'string' &&
value.content.length > 0
)
}
export function parseMem0Messages(value: unknown): Mem0Message[] {
let messages: unknown
try {
messages = typeof value === 'string' ? JSON.parse(value) : value
} catch (error) {
throw new Error(`Messages must be valid JSON: ${toError(error).message}`)
}
if (!Array.isArray(messages) || messages.length === 0) {
throw new Error('Messages must be a non-empty array')
}
const validMessages: Mem0Message[] = []
for (const message of messages) {
if (!isMem0Message(message)) {
throw new Error('Each message must have role user or assistant and non-empty content')
}
validMessages.push(message)
}
return validMessages
}