Files
Memoh/packages/agent/src/agent.ts
T
2026-01-12 15:06:46 +08:00

125 lines
3.3 KiB
TypeScript

import { streamText, generateText, ModelMessage, stepCountIs, UserModelMessage } from 'ai'
import { AgentParams } from './types'
import { system, schedule as schedulePrompt } from './prompts'
import { getMemoryTools, getScheduleTools, getMessageTools } from './tools'
import { createChatGateway } from '@memohome/ai-gateway'
import { Schedule } from '@memohome/shared'
export const createAgent = (params: AgentParams) => {
const messages: ModelMessage[] = []
const gateway = createChatGateway(params.model)
const maxContextLoadTime = params.maxContextLoadTime ?? 24 * 60 // 24 hours
const language = params.language ?? 'Same as user input'
const platforms = params.platforms ?? []
const currentPlatform = params.platforms
? platforms.find(p => p.name === params.currentPlatform)?.name ?? 'Unknown Platform'
: 'client'
const getTools = async () => {
return {
...getMemoryTools({
searchMemory: params.onSearchMemory ?? (() => Promise.resolve([]))
}),
...getScheduleTools({
onGetSchedules: params.onGetSchedules ?? (() => Promise.resolve([])),
onRemoveSchedule: params.onRemoveSchedule ?? (() => Promise.resolve()),
onSchedule: params.onSchedule ?? (() => Promise.resolve()),
}),
...getMessageTools(
platforms,
params.onSendMessage ?? (() => Promise.resolve())
),
}
}
const loadContext = async () => {
const from = new Date(Date.now() - maxContextLoadTime * 60 * 1000)
const to = new Date()
const memory = await params.onReadMemory?.(from, to) ?? []
const context = memory.flatMap(m => m.messages)
messages.unshift(...context)
}
const getSystemPrompt = () => {
return system({
date: new Date(),
language,
locale: params.locale,
maxContextLoadTime,
platforms,
currentPlatform,
})
}
const getSchedulePrompt = (schedule: Schedule) => {
return schedulePrompt({
schedule,
locale: params.locale,
date: new Date(),
})
}
async function askDirectly(input: string) {
await loadContext()
const user = {
role: 'user',
content: input,
} as UserModelMessage
messages.push(user)
const { response } = await generateText({
model: gateway,
system: getSystemPrompt(),
messages,
tools: await getTools(),
})
await params.onFinish?.([
user as ModelMessage,
...response.messages,
])
}
async function* ask(input: string) {
await loadContext()
const user = {
role: 'user',
content: input,
} as UserModelMessage
messages.push(user)
const { fullStream, response } = streamText({
model: gateway,
system: getSystemPrompt(),
prepareStep: async () => {
return {
system: getSystemPrompt(),
}
},
stopWhen: stepCountIs(10),
messages,
tools: await getTools(),
})
for await (const event of fullStream) {
yield event
}
const newMessages = (await response).messages
await params.onFinish?.([
user as ModelMessage,
...newMessages,
])
}
const triggerSchedule = async (schedule: Schedule) => {
const prompt = getSchedulePrompt(schedule)
await askDirectly(prompt)
}
return {
ask,
askDirectly,
loadContext,
getSystemPrompt,
getSchedulePrompt,
triggerSchedule,
}
}