@@ -4,6 +4,7 @@ import { createTokenCounter } from '@memo/core/utils/tokenizer'
44import {
55 buildSessionPath ,
66 getSessionsDir ,
7+ getMemoryPath ,
78 loadMemoConfig ,
89 selectProvider ,
910} from '@memo/core/config/config'
@@ -37,12 +38,28 @@ export async function withDefaultDeps(
3738 const loaded = await loadMemoConfig ( )
3839 const config = loaded . config
3940 const tools = deps . tools ?? TOOLKIT
40- const loadPrompt = deps . loadPrompt ?? defaultLoadPrompt
41+ const loadPrompt = async ( ) => {
42+ const basePrompt = await ( deps . loadPrompt ?? defaultLoadPrompt ) ( )
43+ const memoryPath = getMemoryPath ( loaded )
44+ try {
45+ const file = Bun . file ( memoryPath )
46+ if ( await file . exists ( ) ) {
47+ const memory = ( await file . text ( ) ) . trim ( )
48+ if ( memory ) {
49+ return `${ basePrompt } \n\n# 长期记忆\n${ memory } `
50+ }
51+ }
52+ } catch ( err ) {
53+ console . warn ( `读取 memory 失败: ${ ( err as Error ) . message } ` )
54+ }
55+ return basePrompt
56+ }
57+ const streamOutput = options . stream ?? config . stream_output ?? true
4158 return {
4259 tools,
4360 callLLM :
4461 deps . callLLM ??
45- ( async ( messages ) => {
62+ ( async ( messages , onChunk ) => {
4663 const provider = selectProvider ( config , options . providerName )
4764 const apiKey =
4865 process . env [ provider . env_api_key ] ??
@@ -57,22 +74,40 @@ export async function withDefaultDeps(
5774 apiKey,
5875 baseURL : provider . base_url ,
5976 } )
60- const data = await client . chat . completions . create ( {
61- model : provider . model ,
62- messages,
63- temperature : 0.35 ,
64- } )
65- const content = data . choices ?. [ 0 ] ?. message ?. content
66- if ( typeof content !== 'string' ) {
67- throw new Error ( 'OpenAI 兼容接口返回内容为空' )
68- }
69- return {
70- content,
71- usage : {
72- prompt : data . usage ?. prompt_tokens ?? undefined ,
73- completion : data . usage ?. completion_tokens ?? undefined ,
74- total : data . usage ?. total_tokens ?? undefined ,
75- } ,
77+ if ( streamOutput ) {
78+ const stream = await client . chat . completions . create ( {
79+ model : provider . model ,
80+ messages,
81+ temperature : 0.35 ,
82+ stream : true ,
83+ } )
84+ let content = ''
85+ for await ( const part of stream ) {
86+ const delta = part . choices ?. [ 0 ] ?. delta ?. content
87+ if ( delta ) {
88+ content += delta
89+ onChunk ?.( delta )
90+ }
91+ }
92+ return { content, streamed : true }
93+ } else {
94+ const data = await client . chat . completions . create ( {
95+ model : provider . model ,
96+ messages,
97+ temperature : 0.35 ,
98+ } )
99+ const content = data . choices ?. [ 0 ] ?. message ?. content
100+ if ( typeof content !== 'string' ) {
101+ throw new Error ( 'OpenAI 兼容接口返回内容为空' )
102+ }
103+ return {
104+ content,
105+ usage : {
106+ prompt : data . usage ?. prompt_tokens ?? undefined ,
107+ completion : data . usage ?. completion_tokens ?? undefined ,
108+ total : data . usage ?. total_tokens ?? undefined ,
109+ } ,
110+ }
76111 }
77112 } ) ,
78113 loadPrompt,
0 commit comments