@@ -2,53 +2,80 @@ import {
22 defineCommand ,
33 UsageError ,
44 memoryAddPath ,
5+ memoryEndpoint ,
56 detectOutputFormat ,
67 type FlagsDef ,
78 type ParsedFlags ,
89 type MemoryAddRequest ,
910 type MemoryAddResponse ,
11+ type MemoryMessage ,
1012} from "bailian-cli-core" ;
1113import { emitResult , emitBare } from "bailian-cli-runtime" ;
14+ import {
15+ MEMORY_LIBRARY_FLAG ,
16+ MEMORY_WORKSPACE_NOTE ,
17+ PROJECT_ID_FLAG ,
18+ WORKSPACE_FLAG ,
19+ parseJsonArrayFlag ,
20+ parseJsonObjectFlag ,
21+ resolveWorkspaceId ,
22+ } from "./shared.ts" ;
1223
1324const ADD_FLAGS = {
1425 userId : {
1526 type : "string" ,
1627 valueHint : "<id>" ,
17- description : { "en-US" : "User ID (required)" , "zh-CN" : "用户 ID(必填)" } ,
28+ description : {
29+ "en-US" : "Memory entity ID that owns the memory (required)" ,
30+ "zh-CN" : "记忆实体 ID,标识记忆归属对象(必填)" ,
31+ } ,
1832 required : true ,
1933 } ,
2034 messages : {
2135 type : "string" ,
2236 valueHint : "<json>" ,
2337 description : {
24- "en-US" : 'Messages JSON array: [{"role":"user","content":"..."},...]' ,
25- "zh-CN" : '消息 JSON 数组:[{"role":"user","content":"..."},...]' ,
38+ "en-US" : 'Messages JSON array: [{"role":"user","content":"..."},...] (max 50) ' ,
39+ "zh-CN" : '消息 JSON 数组:[{"role":"user","content":"..."},...](最多 50 条) ' ,
2640 } ,
2741 } ,
2842 content : {
2943 type : "string" ,
3044 valueHint : "<text>" ,
31- description : { "en-US" : "Custom content text to memorize" , "zh-CN" : "要记忆的自定义内容文本" } ,
45+ description : {
46+ "en-US" : "Custom content to memorize verbatim; takes precedence over --messages" ,
47+ "zh-CN" : "要原样记忆的自定义内容;优先级高于 --messages" ,
48+ } ,
3249 } ,
3350 profileSchema : {
3451 type : "string" ,
3552 valueHint : "<id>" ,
3653 description : {
37- "en-US" : "Profile schema ID for user profiling " ,
38- "zh-CN" : "用于用户画像的 Profile Schema ID " ,
54+ "en-US" : "Profile schema ID; without it no user profile is extracted " ,
55+ "zh-CN" : "画像模板 ID;不传则不提取用户画像 " ,
3956 } ,
4057 } ,
41- memoryLibraryId : {
58+ metaData : {
4259 type : "string" ,
43- valueHint : "<id >" ,
60+ valueHint : "<json >" ,
4461 description : {
45- "en-US" : "Memory library ID (isolate memory space)" ,
46- "zh-CN" : "记忆库 ID(用于隔离记忆空间)" ,
62+ "en-US" : 'Custom metadata JSON object: {"location_name":"Beijing"}' ,
63+ "zh-CN" : '用户自定义信息 JSON 对象:{"location_name":"北京"}' ,
4764 } ,
4865 } ,
66+ ...PROJECT_ID_FLAG ,
67+ ...MEMORY_LIBRARY_FLAG ,
68+ ...WORKSPACE_FLAG ,
4969} satisfies FlagsDef ;
5070type AddFlags = ParsedFlags < typeof ADD_FLAGS > ;
5171
72+ /** Max messages accepted per AddMemory call (a Q&A pair counts as 2). */
73+ const MAX_MESSAGES = 50 ;
74+ /** Max characters accepted for custom_content. */
75+ const MAX_CONTENT_LENGTH = 512 ;
76+ /** Max characters accepted for user_id. */
77+ const MAX_USER_ID_LENGTH = 64 ;
78+
5279export default defineCommand ( {
5380 description : {
5481 "en-US" : "Add memory from messages or custom content" ,
@@ -57,10 +84,24 @@ export default defineCommand({
5784 auth : "apiKey" ,
5885 usageArgs : "--user-id <id> [--messages <json>] [--content <text>] [flags]" ,
5986 flags : ADD_FLAGS ,
87+ notes : [
88+ MEMORY_WORKSPACE_NOTE ,
89+ {
90+ "en-US" :
91+ "--content and --messages are mutually exclusive: when --content is set, --messages is ignored by the server." ,
92+ "zh-CN" : "--content 与 --messages 互斥:传了 --content 时服务端会忽略 --messages。" ,
93+ } ,
94+ {
95+ "en-US" :
96+ "The response lists the changed memory nodes; one call can add, update or delete several at once." ,
97+ "zh-CN" : "返回结果是变更的记忆片段列表;一次调用可能同时新增、更新或删除多条。" ,
98+ } ,
99+ ] ,
60100 exampleArgs : [
61101 {
62- "en-US" : '--user-id user1 --content "The user likes Python programming"' ,
63- "zh-CN" : '--user-id user1 --content "用户喜欢使用 Python 编程"' ,
102+ "en-US" :
103+ '--user-id user1 --content "The user likes Python programming" --workspace-id ws_xxx' ,
104+ "zh-CN" : '--user-id user1 --content "用户喜欢使用 Python 编程" --workspace-id ws_xxx' ,
64105 } ,
65106 {
66107 "en-US" : '--user-id user1 --messages \'[{"role":"user","content":"I like traveling"}]\'' ,
@@ -70,46 +111,61 @@ export default defineCommand({
70111 "en-US" : '--user-id user1 --content "Lives in Beijing" --profile-schema schema_xxx' ,
71112 "zh-CN" : '--user-id user1 --content "居住在北京" --profile-schema schema_xxx' ,
72113 } ,
114+ {
115+ "en-US" : '--user-id user1 --content "Attended WAIC" --meta-data \'{"location":"Shanghai"}\'' ,
116+ "zh-CN" : '--user-id user1 --content "参加了 WAIC" --meta-data \'{"location":"上海"}\'' ,
117+ } ,
73118 ] ,
74- validate : ( f : AddFlags ) =>
75- ! f . messages && ! f . content ? "Provide --messages or --content." : undefined ,
119+ validate : ( flags : AddFlags ) => {
120+ if ( ! flags . messages && ! flags . content ) return "Provide --messages or --content." ;
121+ if ( flags . userId . length > MAX_USER_ID_LENGTH )
122+ return `--user-id must be at most ${ MAX_USER_ID_LENGTH } characters.` ;
123+ if ( flags . content && flags . content . length > MAX_CONTENT_LENGTH )
124+ return `--content must be at most ${ MAX_CONTENT_LENGTH } characters.` ;
125+ return undefined ;
126+ } ,
76127 async run ( ctx ) {
77128 const { settings, flags } = ctx ;
78- const userId = flags . userId ;
79129
80- const body : MemoryAddRequest = { user_id : userId } ;
130+ const body : MemoryAddRequest = { user_id : flags . userId } ;
81131
82132 if ( flags . messages ) {
83- try {
84- body . messages = JSON . parse ( flags . messages ) ;
85- } catch {
86- throw new UsageError ( "--messages must be valid JSON array" ) ;
133+ const messages = parseJsonArrayFlag < MemoryMessage > ( "--messages" , flags . messages ) ;
134+ if ( messages . length > MAX_MESSAGES ) {
135+ throw new UsageError ( `--messages accepts at most ${ MAX_MESSAGES } messages` ) ;
87136 }
137+ body . messages = messages ;
88138 }
89139
90- if ( flags . content ) {
91- body . custom_content = flags . content ;
92- }
93-
140+ if ( flags . content ) body . custom_content = flags . content ;
141+ if ( flags . metaData ) body . meta_data = parseJsonObjectFlag ( "--meta-data" , flags . metaData ) ;
94142 if ( flags . profileSchema ) body . profile_schema = flags . profileSchema ;
143+ if ( flags . projectId ) body . project_id = flags . projectId ;
95144 if ( flags . memoryLibraryId ) body . memory_library_id = flags . memoryLibraryId ;
96145
97146 const format = detectOutputFormat ( settings . output ) ;
147+ const url = memoryEndpoint ( resolveWorkspaceId ( ctx ) , memoryAddPath ( ) ) ;
98148
99149 if ( settings . dryRun ) {
100- emitResult ( { endpoint : ctx . client . url ( memoryAddPath ( ) ) , request : body } , format ) ;
150+ emitResult ( { endpoint : url , method : "POST" , request : body } , format ) ;
101151 return ;
102152 }
103153
104154 const response = await ctx . client . requestJson < MemoryAddResponse > ( {
105- path : memoryAddPath ( ) ,
155+ path : url ,
106156 method : "POST" ,
107157 body,
108158 } ) ;
109159
110160 if ( settings . quiet || format === "text" ) {
111- const ids = response . memory_ids ?. join ( ", " ) || "none" ;
112- emitBare ( `Memory added. IDs: ${ ids } ` ) ;
161+ const nodes = response . memory_nodes ?? [ ] ;
162+ if ( nodes . length === 0 ) {
163+ emitBare ( "No memory node changed." ) ;
164+ return ;
165+ }
166+ for ( const node of nodes ) {
167+ emitBare ( `[${ node . event ?? "ADD" } ] ${ node . memory_node_id } ${ node . content } ` ) ;
168+ }
113169 } else {
114170 emitResult ( response , format ) ;
115171 }
0 commit comments