@@ -2,6 +2,7 @@ import { computeManagedOAuthCredentialName } from '../../../../primitives/creden
22import { mapByoConfigToAgent } from '../../../../tui/screens/agent/useAddAgent.js' ;
33import type { GenerateConfig } from '../../../../tui/screens/generate/types.js' ;
44import {
5+ mapExistingMemoriesToProviders ,
56 mapGenerateConfigToAgent ,
67 mapGenerateConfigToRenderConfig ,
78 mapGenerateConfigToResources ,
@@ -53,6 +54,25 @@ describe('mapGenerateInputToMemories', () => {
5354 expect ( semantic ?. namespaces ) . toEqual ( [ '/users/{actorId}/facts' ] ) ;
5455 } ) ;
5556
57+ it ( 'returns memory with single CUSTOM strategy for "custom"' , ( ) => {
58+ const result = mapGenerateInputToMemories ( 'custom' , 'Proj' ) ;
59+ expect ( result ) . toHaveLength ( 1 ) ;
60+ expect ( result [ 0 ] ! . type ) . toBe ( 'AgentCoreMemory' ) ;
61+ expect ( result [ 0 ] ! . name ) . toBe ( 'ProjMemory' ) ;
62+ expect ( result [ 0 ] ! . eventExpiryDuration ) . toBe ( 30 ) ;
63+ const strategies = result [ 0 ] ! . strategies ;
64+ expect ( strategies ) . toHaveLength ( 1 ) ;
65+ expect ( strategies [ 0 ] ! . type ) . toBe ( 'CUSTOM' ) ;
66+ } ) ;
67+
68+ it ( 'does not include namespaces for CUSTOM strategy' , ( ) => {
69+ const result = mapGenerateInputToMemories ( 'custom' , 'Proj' ) ;
70+ const custom = result [ 0 ] ! . strategies [ 0 ] ! ;
71+ expect ( custom . type ) . toBe ( 'CUSTOM' ) ;
72+ expect ( custom ) . not . toHaveProperty ( 'namespaces' ) ;
73+ expect ( custom ) . not . toHaveProperty ( 'reflectionNamespaces' ) ;
74+ } ) ;
75+
5676 it ( 'uses project name in memory name' , ( ) => {
5777 const result = mapGenerateInputToMemories ( 'shortTerm' , 'MyCustomProject' ) ;
5878 expect ( result [ 0 ] ! . name ) . toBe ( 'MyCustomProjectMemory' ) ;
@@ -131,6 +151,14 @@ describe('mapGenerateConfigToResources', () => {
131151 expect ( result . credentials ) . toHaveLength ( 1 ) ;
132152 expect ( result . memories [ 0 ] ! . strategies ) . toHaveLength ( 4 ) ;
133153 } ) ;
154+
155+ it ( 'includes memory with CUSTOM strategy when memory is "custom"' , ( ) => {
156+ const config : GenerateConfig = { ...baseConfig , memory : 'custom' } ;
157+ const result = mapGenerateConfigToResources ( config ) ;
158+ expect ( result . memories ) . toHaveLength ( 1 ) ;
159+ expect ( result . memories [ 0 ] ! . strategies ) . toHaveLength ( 1 ) ;
160+ expect ( result . memories [ 0 ] ! . strategies [ 0 ] ! . type ) . toBe ( 'CUSTOM' ) ;
161+ } ) ;
134162} ) ;
135163
136164describe ( 'mapModelProviderToIdentityProviders' , ( ) => {
@@ -194,6 +222,158 @@ describe('mapGenerateConfigToRenderConfig', () => {
194222 const result = await mapGenerateConfigToRenderConfig ( config , [ ] ) ;
195223 expect ( result . memoryProviders [ 0 ] ! . strategies ) . toEqual ( [ 'SEMANTIC' , 'USER_PREFERENCE' , 'SUMMARIZATION' , 'EPISODIC' ] ) ;
196224 } ) ;
225+
226+ it ( 'populates memoryProviders with CUSTOM strategy for custom memory' , async ( ) => {
227+ const config : GenerateConfig = { ...baseConfig , memory : 'custom' } ;
228+ const result = await mapGenerateConfigToRenderConfig ( config , [ ] ) ;
229+ expect ( result . hasMemory ) . toBe ( true ) ;
230+ expect ( result . memoryProviders ) . toHaveLength ( 1 ) ;
231+ expect ( result . memoryProviders [ 0 ] ! . name ) . toBe ( 'TestProjectMemory' ) ;
232+ expect ( result . memoryProviders [ 0 ] ! . strategies ) . toEqual ( [ 'CUSTOM' ] ) ;
233+ } ) ;
234+
235+ it ( 'includes existing memories in memoryProviders' , async ( ) => {
236+ const existingMemories = [
237+ {
238+ type : 'AgentCoreMemory' as const ,
239+ name : 'SharedMemory' ,
240+ eventExpiryDuration : 30 ,
241+ strategies : [ { type : 'SEMANTIC' as const , namespaces : [ '/users/{actorId}/facts' ] } ] ,
242+ } ,
243+ ] ;
244+ const result = await mapGenerateConfigToRenderConfig ( baseConfig , [ ] , existingMemories ) ;
245+ expect ( result . hasMemory ) . toBe ( true ) ;
246+ expect ( result . memoryProviders ) . toHaveLength ( 1 ) ;
247+ expect ( result . memoryProviders [ 0 ] ! . name ) . toBe ( 'SharedMemory' ) ;
248+ expect ( result . memoryProviders [ 0 ] ! . envVarName ) . toBe ( 'MEMORY_SHAREDMEMORY_ID' ) ;
249+ expect ( result . memoryProviders [ 0 ] ! . strategies ) . toEqual ( [ 'SEMANTIC' ] ) ;
250+ } ) ;
251+
252+ it ( 'deduplicates when existing memory and new memory have the same name' , async ( ) => {
253+ const config : GenerateConfig = { ...baseConfig , memory : 'shortTerm' } ;
254+ const existingMemories = [
255+ {
256+ type : 'AgentCoreMemory' as const ,
257+ name : 'TestProjectMemory' ,
258+ eventExpiryDuration : 30 ,
259+ strategies : [ { type : 'SEMANTIC' as const , namespaces : [ '/users/{actorId}/facts' ] } ] ,
260+ } ,
261+ ] ;
262+ const result = await mapGenerateConfigToRenderConfig ( config , [ ] , existingMemories ) ;
263+ expect ( result . memoryProviders ) . toHaveLength ( 1 ) ;
264+ expect ( result . memoryProviders [ 0 ] ! . name ) . toBe ( 'TestProjectMemory' ) ;
265+ // Existing provider wins - strategies come from the existing memory, not the new shortTerm (empty)
266+ expect ( result . memoryProviders [ 0 ] ! . strategies ) . toEqual ( [ 'SEMANTIC' ] ) ;
267+ } ) ;
268+
269+ it ( 'sets hasMemory true from existing memories even when memory option is "none"' , async ( ) => {
270+ const existingMemories = [
271+ {
272+ type : 'AgentCoreMemory' as const ,
273+ name : 'ProjectMemory' ,
274+ eventExpiryDuration : 30 ,
275+ strategies : [ ] ,
276+ } ,
277+ ] ;
278+ const result = await mapGenerateConfigToRenderConfig ( baseConfig , [ ] , existingMemories ) ;
279+ expect ( result . hasMemory ) . toBe ( true ) ;
280+ expect ( result . memoryProviders ) . toHaveLength ( 1 ) ;
281+ expect ( result . memoryProviders [ 0 ] ! . name ) . toBe ( 'ProjectMemory' ) ;
282+ } ) ;
283+
284+ it ( 'combines existing memories with new custom memory' , async ( ) => {
285+ const config : GenerateConfig = { ...baseConfig , memory : 'custom' , projectName : 'NewAgent' } ;
286+ const existingMemories = [
287+ {
288+ type : 'AgentCoreMemory' as const ,
289+ name : 'SharedMemory' ,
290+ eventExpiryDuration : 30 ,
291+ strategies : [ { type : 'SEMANTIC' as const , namespaces : [ '/users/{actorId}/facts' ] } ] ,
292+ } ,
293+ ] ;
294+ const result = await mapGenerateConfigToRenderConfig ( config , [ ] , existingMemories ) ;
295+ expect ( result . memoryProviders ) . toHaveLength ( 2 ) ;
296+ expect ( result . memoryProviders [ 0 ] ! . name ) . toBe ( 'SharedMemory' ) ;
297+ expect ( result . memoryProviders [ 1 ] ! . name ) . toBe ( 'NewAgentMemory' ) ;
298+ expect ( result . memoryProviders [ 1 ] ! . strategies ) . toEqual ( [ 'CUSTOM' ] ) ;
299+ } ) ;
300+ } ) ;
301+
302+ describe ( 'mapExistingMemoriesToProviders' , ( ) => {
303+ it ( 'maps memories to providers with correct envVarName and strategies' , ( ) => {
304+ const memories = [
305+ {
306+ type : 'AgentCoreMemory' as const ,
307+ name : 'MyMemory' ,
308+ eventExpiryDuration : 30 ,
309+ strategies : [
310+ { type : 'SEMANTIC' as const , namespaces : [ '/users/{actorId}/facts' ] } ,
311+ { type : 'SUMMARIZATION' as const , namespaces : [ '/conversations/{sessionId}/summary' ] } ,
312+ ] ,
313+ } ,
314+ ] ;
315+ const result = mapExistingMemoriesToProviders ( memories ) ;
316+ expect ( result ) . toHaveLength ( 1 ) ;
317+ expect ( result [ 0 ] ! . name ) . toBe ( 'MyMemory' ) ;
318+ expect ( result [ 0 ] ! . envVarName ) . toBe ( 'MEMORY_MYMEMORY_ID' ) ;
319+ expect ( result [ 0 ] ! . strategies ) . toEqual ( [ 'SEMANTIC' , 'SUMMARIZATION' ] ) ;
320+ } ) ;
321+
322+ it ( 'handles memory with CUSTOM strategy (no namespaces)' , ( ) => {
323+ const memories = [
324+ {
325+ type : 'AgentCoreMemory' as const ,
326+ name : 'CustomMem' ,
327+ eventExpiryDuration : 30 ,
328+ strategies : [ { type : 'CUSTOM' as const } ] ,
329+ } ,
330+ ] ;
331+ const result = mapExistingMemoriesToProviders ( memories ) ;
332+ expect ( result ) . toHaveLength ( 1 ) ;
333+ expect ( result [ 0 ] ! . strategies ) . toEqual ( [ 'CUSTOM' ] ) ;
334+ } ) ;
335+
336+ it ( 'handles memory with empty strategies (short-term memory)' , ( ) => {
337+ const memories = [
338+ {
339+ type : 'AgentCoreMemory' as const ,
340+ name : 'ShortTermMem' ,
341+ eventExpiryDuration : 30 ,
342+ strategies : [ ] ,
343+ } ,
344+ ] ;
345+ const result = mapExistingMemoriesToProviders ( memories ) ;
346+ expect ( result ) . toHaveLength ( 1 ) ;
347+ expect ( result [ 0 ] ! . name ) . toBe ( 'ShortTermMem' ) ;
348+ expect ( result [ 0 ] ! . strategies ) . toEqual ( [ ] ) ;
349+ } ) ;
350+
351+ it ( 'maps multiple memories' , ( ) => {
352+ const memories = [
353+ {
354+ type : 'AgentCoreMemory' as const ,
355+ name : 'MemOne' ,
356+ eventExpiryDuration : 30 ,
357+ strategies : [ { type : 'SEMANTIC' as const , namespaces : [ '/users/{actorId}/facts' ] } ] ,
358+ } ,
359+ {
360+ type : 'AgentCoreMemory' as const ,
361+ name : 'MemTwo' ,
362+ eventExpiryDuration : 60 ,
363+ strategies : [ { type : 'CUSTOM' as const } ] ,
364+ } ,
365+ ] ;
366+ const result = mapExistingMemoriesToProviders ( memories ) ;
367+ expect ( result ) . toHaveLength ( 2 ) ;
368+ expect ( result [ 0 ] ! . name ) . toBe ( 'MemOne' ) ;
369+ expect ( result [ 0 ] ! . envVarName ) . toBe ( 'MEMORY_MEMONE_ID' ) ;
370+ expect ( result [ 1 ] ! . name ) . toBe ( 'MemTwo' ) ;
371+ expect ( result [ 1 ] ! . envVarName ) . toBe ( 'MEMORY_MEMTWO_ID' ) ;
372+ } ) ;
373+
374+ it ( 'returns empty array for empty input' , ( ) => {
375+ expect ( mapExistingMemoriesToProviders ( [ ] ) ) . toEqual ( [ ] ) ;
376+ } ) ;
197377} ) ;
198378
199379describe ( 'mapGenerateConfigToAgent protocol mode' , ( ) => {
0 commit comments