Files
Memoh/packages/agent/client/index.ts
T
2026-01-10 03:04:37 +08:00

120 lines
3.2 KiB
TypeScript

import { createInterface } from 'node:readline'
import { stdin as input, stdout as output } from 'node:process'
import { createAgent } from '../src/agent'
import { createMemorySearch, createAddMemory, filterByTimestamp, MemoryUnit } from '@memohome/memory'
import { ModelClientType } from '@memohome/shared'
// Load environment variables
const MODEL = process.env.MODEL
const BASE_URL = process.env.BASE_URL
const API_KEY = process.env.API_KEY
const EMBEDDING_MODEL = process.env.EMBEDDING_MODEL
const MODEL_CLIENT_TYPE = process.env.MODEL_CLIENT_TYPE || 'openai'
if (!MODEL || !BASE_URL || !API_KEY || !EMBEDDING_MODEL) {
console.error('Error: Missing required environment variables')
console.error('Required: MODEL, BASE_URL, API_KEY, EMBEDDING_MODEL')
console.error('Optional: MODEL_CLIENT_TYPE (default: openai)')
process.exit(1)
}
const USER_ID = 'cli-user'
// Create memory functions
const searchMemory = createMemorySearch({
model: EMBEDDING_MODEL,
apiKey: API_KEY,
baseURL: BASE_URL,
})
const addMemory = createAddMemory({
model: EMBEDDING_MODEL,
apiKey: API_KEY,
baseURL: BASE_URL,
})
// Create agent
const agent = createAgent({
model: {
modelId: MODEL,
baseUrl: BASE_URL,
apiKey: API_KEY,
clientType: MODEL_CLIENT_TYPE as ModelClientType,
name: MODEL,
},
maxContextLoadTime: 60, // 60 minutes
language: 'Same as user input',
onReadMemory: async (from: Date, to: Date) => {
return await filterByTimestamp(from, to, USER_ID)
},
onSearchMemory: async (query: string) => {
return await searchMemory({ user: USER_ID, query, maxResults: 5 })
},
onFinish: async (messages) => {
// Save conversation to memory - type conversion handled internally
const memoryUnit: MemoryUnit = {
messages: messages as unknown as MemoryUnit['messages'],
timestamp: new Date(),
user: USER_ID,
raw: '', // will be generated by addMemory
}
await addMemory({ memory: memoryUnit })
},
})
async function main() {
console.log('🤖 Agent CLI Started')
console.log('Type your message and press Enter. Type "exit" to quit.\n')
// Load context
await agent.loadContext()
const rl = createInterface({ input, output })
rl.on('line', async (line) => {
const userInput = line.trim()
if (userInput === 'exit' || userInput === 'quit') {
console.log('\n👋 Goodbye!')
rl.close()
process.exit(0)
}
if (!userInput) {
rl.prompt()
return
}
try {
process.stdout.write('\n🤖 ')
let hasOutput = false
for await (const event of agent.ask(userInput)) {
if (event.type === 'text-delta' && 'text' in event && event.text) {
process.stdout.write(String(event.text))
hasOutput = true
} else if (event.type === 'tool-call' && 'toolName' in event) {
process.stdout.write(`\n[Tool: ${event.toolName}]`)
hasOutput = true
}
}
if (!hasOutput) {
process.stdout.write('(No response)')
}
console.log('\n')
} catch (error) {
console.error('\n❌ Error:', error instanceof Error ? error.message : String(error))
console.log()
}
rl.prompt()
})
rl.setPrompt('You: ')
rl.prompt()
}
main().catch(console.error)