mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat(agent): message send
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { streamText, generateText, ModelMessage, stepCountIs, UserModelMessage } from 'ai'
|
import { streamText, generateText, ModelMessage, stepCountIs, UserModelMessage } from 'ai'
|
||||||
import { AgentParams } from './types'
|
import { AgentParams } from './types'
|
||||||
import { system, schedule as schedulePrompt } from './prompts'
|
import { system, schedule as schedulePrompt } from './prompts'
|
||||||
import { getMemoryTools, getScheduleTools } from './tools'
|
import { getMemoryTools, getScheduleTools, getMessageTools } from './tools'
|
||||||
import { createChatGateway } from '@memohome/ai-gateway'
|
import { createChatGateway } from '@memohome/ai-gateway'
|
||||||
import { Schedule } from '@memohome/shared'
|
import { Schedule } from '@memohome/shared'
|
||||||
|
|
||||||
@@ -10,8 +10,12 @@ export const createAgent = (params: AgentParams) => {
|
|||||||
|
|
||||||
const gateway = createChatGateway(params.model)
|
const gateway = createChatGateway(params.model)
|
||||||
|
|
||||||
const maxContextLoadTime = params.maxContextLoadTime ?? 60
|
const maxContextLoadTime = params.maxContextLoadTime ?? 24 * 60 // 24 hours
|
||||||
const language = params.language ?? 'Same as user input'
|
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 () => {
|
const getTools = async () => {
|
||||||
return {
|
return {
|
||||||
@@ -23,6 +27,10 @@ export const createAgent = (params: AgentParams) => {
|
|||||||
onRemoveSchedule: params.onRemoveSchedule ?? (() => Promise.resolve()),
|
onRemoveSchedule: params.onRemoveSchedule ?? (() => Promise.resolve()),
|
||||||
onSchedule: params.onSchedule ?? (() => Promise.resolve()),
|
onSchedule: params.onSchedule ?? (() => Promise.resolve()),
|
||||||
}),
|
}),
|
||||||
|
...getMessageTools(
|
||||||
|
platforms,
|
||||||
|
params.onSendMessage ?? (() => Promise.resolve())
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +48,8 @@ export const createAgent = (params: AgentParams) => {
|
|||||||
language,
|
language,
|
||||||
locale: params.locale,
|
locale: params.locale,
|
||||||
maxContextLoadTime,
|
maxContextLoadTime,
|
||||||
|
platforms,
|
||||||
|
currentPlatform,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Platform } from '@memohome/shared'
|
||||||
import { time } from './shared'
|
import { time } from './shared'
|
||||||
import { quote } from './utils'
|
import { quote } from './utils'
|
||||||
|
|
||||||
@@ -6,13 +7,18 @@ export interface SystemParams {
|
|||||||
locale?: Intl.LocalesArgument
|
locale?: Intl.LocalesArgument
|
||||||
language: string
|
language: string
|
||||||
maxContextLoadTime: number
|
maxContextLoadTime: number
|
||||||
|
platforms: Platform[]
|
||||||
|
currentPlatform: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const system = ({ date, locale, language, maxContextLoadTime }: SystemParams) => {
|
export const system = ({ date, locale, language, maxContextLoadTime, platforms, currentPlatform }: SystemParams) => {
|
||||||
return `
|
return `
|
||||||
---
|
---
|
||||||
${time({ date, locale })}
|
${time({ date, locale })}
|
||||||
language: ${language}
|
language: ${language}
|
||||||
|
available-platforms:
|
||||||
|
${platforms.map(platform => ` - ${platform.name}`).join('\n')}
|
||||||
|
current-platform: ${currentPlatform}
|
||||||
---
|
---
|
||||||
You are a personal housekeeper assistant, which able to manage the master's daily affairs.
|
You are a personal housekeeper assistant, which able to manage the master's daily affairs.
|
||||||
|
|
||||||
@@ -33,5 +39,13 @@ Your abilities:
|
|||||||
+ The ${quote('pattern')} is the pattern of the schedule with **Cron Syntax**.
|
+ The ${quote('pattern')} is the pattern of the schedule with **Cron Syntax**.
|
||||||
+ The ${quote('command')} is the natural language command to execute, will send to you when the schedule is triggered, which means the command will be executed by presence of you.
|
+ The ${quote('command')} is the natural language command to execute, will send to you when the schedule is triggered, which means the command will be executed by presence of you.
|
||||||
+ The ${quote('maxCalls')} is the maximum number of calls to the schedule, If you want to run the task only once, set it to 1.
|
+ The ${quote('maxCalls')} is the maximum number of calls to the schedule, If you want to run the task only once, set it to 1.
|
||||||
|
- The ${quote('command')} should include the method (e.g. ${quote('send-message')}) for returning the task result. If the user does not specify otherwise, the user should be asked how they would like to be notified.
|
||||||
|
|
||||||
|
**Message**
|
||||||
|
- You can use ${quote('send-message')} to send a message to the master.
|
||||||
|
+ The ${quote('platform')} is the platform to send the message to, it must be one of the ${quote('available-platforms')}.
|
||||||
|
+ The ${quote('message')} is the message to send.
|
||||||
|
+ IF: the problem is initiated by a user, regardless of the platform the user is using, the content should be directly output in the content.
|
||||||
|
+ IF: the issue is initiated by a non-user (such as a scheduled task reminder), then it should be sent using the appropriate tools on the platform specified in the requirements.
|
||||||
`.trim()
|
`.trim()
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './memory'
|
export * from './memory'
|
||||||
export * from './schedule'
|
export * from './schedule'
|
||||||
|
export * from './message'
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Platform } from '@memohome/shared'
|
||||||
|
import { SendMessageOptions } from '../types'
|
||||||
|
import { tool } from 'ai'
|
||||||
|
import z from 'zod'
|
||||||
|
|
||||||
|
export const getMessageTools = (
|
||||||
|
platforms: Platform[],
|
||||||
|
onSendMessage: (platform: string, options: SendMessageOptions) => Promise<void>,
|
||||||
|
) => {
|
||||||
|
const sendMessageTool = tool({
|
||||||
|
description: 'Send a message to a platform',
|
||||||
|
inputSchema: z.object({
|
||||||
|
platform: z.enum(platforms.map(platform => platform.name)),
|
||||||
|
message: z.string(),
|
||||||
|
}),
|
||||||
|
execute: async ({ platform, message }) => {
|
||||||
|
await onSendMessage(platform, { message })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
'send-message': sendMessageTool,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
import type { MemoryUnit } from '@memohome/memory'
|
import type { MemoryUnit } from '@memohome/memory'
|
||||||
import { ChatModel, Schedule } from '@memohome/shared'
|
import { ChatModel, Platform, Schedule } from '@memohome/shared'
|
||||||
import { ModelMessage } from 'ai'
|
import { ModelMessage } from 'ai'
|
||||||
|
|
||||||
|
export interface SendMessageOptions {
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface AgentParams {
|
export interface AgentParams {
|
||||||
model: ChatModel
|
model: ChatModel
|
||||||
|
|
||||||
@@ -18,6 +22,12 @@ export interface AgentParams {
|
|||||||
*/
|
*/
|
||||||
language?: string
|
language?: string
|
||||||
|
|
||||||
|
platforms?: Platform[]
|
||||||
|
|
||||||
|
currentPlatform?: string
|
||||||
|
|
||||||
|
onSendMessage?: (platform: string, options: SendMessageOptions) => Promise<void>
|
||||||
|
|
||||||
onReadMemory?: (from: Date, to: Date) => Promise<MemoryUnit[]>
|
onReadMemory?: (from: Date, to: Date) => Promise<MemoryUnit[]>
|
||||||
|
|
||||||
onSearchMemory?: (query: string) => Promise<object[]>
|
onSearchMemory?: (query: string) => Promise<object[]>
|
||||||
|
|||||||
Binary file not shown.
@@ -6,6 +6,7 @@ export const AgentStreamModel = {
|
|||||||
// Optional overrides - if not provided, will use settings
|
// Optional overrides - if not provided, will use settings
|
||||||
maxContextLoadTime: z.number().int().min(1).max(1440).optional(),
|
maxContextLoadTime: z.number().int().min(1).max(1440).optional(),
|
||||||
language: z.string().optional(),
|
language: z.string().optional(),
|
||||||
|
platform: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { createAgent as createAgentService } from '@memohome/agent'
|
import { createAgent as createAgentService } from '@memohome/agent'
|
||||||
import { createMemory, filterByTimestamp, MemoryUnit } from '@memohome/memory'
|
import { createMemory, filterByTimestamp, MemoryUnit } from '@memohome/memory'
|
||||||
import { ChatModel, EmbeddingModel, Schedule } from '@memohome/shared'
|
import { ChatModel, EmbeddingModel, Platform, Schedule } from '@memohome/shared'
|
||||||
import { createSchedule, deleteSchedule, getActiveSchedules } from '../schedule/service'
|
import { createSchedule, deleteSchedule, getActiveSchedules } from '../schedule/service'
|
||||||
|
import { getActivePlatforms, sendMessageToPlatform } from '../platform/service'
|
||||||
|
|
||||||
// Type for messages passed to onFinish callback
|
// Type for messages passed to onFinish callback
|
||||||
type MessageType = Record<string, unknown>
|
type MessageType = Record<string, unknown>
|
||||||
@@ -13,6 +14,7 @@ export interface CreateAgentStreamParams {
|
|||||||
summaryModel: ChatModel
|
summaryModel: ChatModel
|
||||||
maxContextLoadTime?: number
|
maxContextLoadTime?: number
|
||||||
language?: string
|
language?: string
|
||||||
|
platform?: string
|
||||||
onFinish?: (messages: MessageType[]) => Promise<void>
|
onFinish?: (messages: MessageType[]) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ export async function createAgent(params: CreateAgentStreamParams) {
|
|||||||
summaryModel,
|
summaryModel,
|
||||||
maxContextLoadTime,
|
maxContextLoadTime,
|
||||||
language,
|
language,
|
||||||
|
platform,
|
||||||
onFinish,
|
onFinish,
|
||||||
} = params
|
} = params
|
||||||
|
|
||||||
@@ -33,11 +36,21 @@ export async function createAgent(params: CreateAgentStreamParams) {
|
|||||||
embeddingModel,
|
embeddingModel,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const platforms = await getActivePlatforms()
|
||||||
|
|
||||||
// Create agent
|
// Create agent
|
||||||
const agent = createAgentService({
|
const agent = createAgentService({
|
||||||
model: chatModel,
|
model: chatModel,
|
||||||
maxContextLoadTime,
|
maxContextLoadTime,
|
||||||
language: language || 'Same as user input',
|
language: language || 'Same as user input',
|
||||||
|
platforms: platforms as Platform[],
|
||||||
|
currentPlatform: platform,
|
||||||
|
onSendMessage: async (platform: string, options) => {
|
||||||
|
await sendMessageToPlatform(platform, {
|
||||||
|
message: options.message,
|
||||||
|
userId,
|
||||||
|
})
|
||||||
|
},
|
||||||
onReadMemory: async (from: Date, to: Date) => {
|
onReadMemory: async (from: Date, to: Date) => {
|
||||||
return await filterByTimestamp(from, to, userId)
|
return await filterByTimestamp(from, to, userId)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export class TelegramPlatform extends BasePlatform {
|
|||||||
redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379')
|
redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379')
|
||||||
// private storage?: TelegramRedisStorage
|
// private storage?: TelegramRedisStorage
|
||||||
|
|
||||||
async start(config: Record<string, unknown>): Promise<void> {
|
override async start(config: z.infer<typeof this.config>): Promise<void> {
|
||||||
const botToken = config.botToken as string
|
const botToken = config.botToken as string
|
||||||
if (!botToken) {
|
if (!botToken) {
|
||||||
throw new Error('Bot token is required')
|
throw new Error('Bot token is required')
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export class BasePlatform {
|
|||||||
started: boolean = false
|
started: boolean = false
|
||||||
port: number = 7003
|
port: number = 7003
|
||||||
|
|
||||||
config = z.object()
|
config = z.record(z.string(), z.unknown())
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async start(config: z.infer<typeof this.config>): Promise<void> {}
|
async start(config: z.infer<typeof this.config>): Promise<void> {}
|
||||||
|
|||||||
Reference in New Issue
Block a user