Skip to content

Commit a4605ef

Browse files
authored
chore: update CP semantics to expect redesigned namespaces field (#1115)
* chore: update CP semantics to expect redesigned namespaces field * fix: update integ tests pointing to old namespace field * fix: restrict episodic param and formatting
1 parent 7836897 commit a4605ef

21 files changed

Lines changed: 246 additions & 112 deletions

File tree

docs/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ Strategy configuration:
244244
"type": "SEMANTIC",
245245
"name": "custom_semantic",
246246
"description": "Custom semantic memory",
247-
"namespaces": ["/users/facts", "/users/preferences"]
247+
"namespaceTemplates": ["/users/facts", "/users/preferences"]
248248
}
249249
```
250250

docs/memory.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,19 @@ Each strategy can have optional configuration:
196196
"type": "SEMANTIC",
197197
"name": "custom_semantic",
198198
"description": "Custom semantic memory",
199-
"namespaces": ["/users/facts", "/users/preferences"]
199+
"namespaceTemplates": ["/users/facts", "/users/preferences"]
200200
}
201201
```
202202

203-
| Field | Required | Description |
204-
| ---------------------- | ------------- | --------------------------------------------------------------------------- |
205-
| `type` | Yes | Strategy type |
206-
| `name` | No | Custom name (defaults to `<memoryName>-<type>`) |
207-
| `description` | No | Strategy description |
208-
| `namespaces` | No | Array of namespace paths for scoping |
209-
| `reflectionNamespaces` | EPISODIC only | Namespaces for cross-episode reflections (must be a prefix of `namespaces`) |
203+
| Field | Required | Description |
204+
| ------------------------------ | ------------- | --------------------------------------------------------------------------------------------- |
205+
| `type` | Yes | Strategy type |
206+
| `name` | No | Custom name (defaults to `<memoryName>-<type>`) |
207+
| `description` | No | Strategy description |
208+
| `namespaceTemplates` | No | Array of namespace templates for scoping |
209+
| `reflectionNamespaceTemplates` | EPISODIC only | Templates for cross-episode reflections (must be a prefix of `namespaceTemplates`) |
210+
| `namespaces` | No | **Deprecated alias for `namespaceTemplates`.** Accepted for backward compatibility. |
211+
| `reflectionNamespaces` | EPISODIC only | **Deprecated alias for `reflectionNamespaceTemplates`.** Accepted for backward compatibility. |
210212

211213
## Event Expiry
212214

e2e-tests/fixtures/import/setup_memory_full.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def main():
3131
"semanticMemoryStrategy": {
3232
"name": "bugbash_semantic",
3333
"description": "Semantic strategy for bugbash testing",
34-
"namespaces": ["default"],
34+
"namespaceTemplates": ["default"],
3535
}
3636
},
3737
{
@@ -68,7 +68,7 @@ def main():
6868
print(f" eventExpiryDuration: 30")
6969
print(f" executionRoleArn: {role_arn}")
7070
print(" strategies:")
71-
print(" - type: SEMANTIC, name: bugbash_semantic, namespaces: [default]")
71+
print(" - type: SEMANTIC, name: bugbash_semantic, namespaceTemplates: [default]")
7272
print(" - type: SUMMARIZATION, name: bugbash_summary")
7373
print(" - type: USER_PREFERENCE, name: bugbash_userpref")
7474
print(" tags: {env: bugbash, team: agentcore-cli}")

integ-tests/add-remove-resources.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('integration: add and remove resources', () => {
4444
telemetry.assertMetricEmitted({ command: 'add.memory', exit_reason: 'success' });
4545
});
4646

47-
it('adds a memory with EPISODIC strategy and verifies reflectionNamespaces', async () => {
47+
it('adds a memory with EPISODIC strategy and verifies reflectionNamespaceTemplates', async () => {
4848
const episodicMemName = `EpiMem${Date.now().toString().slice(-6)}`;
4949
const result = await runCLI(
5050
['add', 'memory', '--name', episodicMemName, '--strategies', 'EPISODIC', '--json'],
@@ -56,19 +56,19 @@ describe('integration: add and remove resources', () => {
5656
const json = JSON.parse(result.stdout);
5757
expect(json.success).toBe(true);
5858

59-
// Verify EPISODIC in config with reflectionNamespaces
59+
// Verify EPISODIC in config with reflectionNamespaceTemplates
6060
const config = await readProjectConfig(project.projectPath);
6161
const memories = config.memories as {
6262
name: string;
63-
strategies: { type: string; reflectionNamespaces?: string[] }[];
63+
strategies: { type: string; reflectionNamespaceTemplates?: string[] }[];
6464
}[];
6565
const mem = memories.find(m => m.name === episodicMemName);
6666
expect(mem, 'Memory should exist').toBeTruthy();
6767

6868
const episodic = mem!.strategies.find(s => s.type === 'EPISODIC');
6969
expect(episodic, 'EPISODIC strategy should exist').toBeTruthy();
70-
expect(episodic!.reflectionNamespaces, 'Should have reflectionNamespaces').toBeDefined();
71-
expect(episodic!.reflectionNamespaces!.length).toBeGreaterThan(0);
70+
expect(episodic!.reflectionNamespaceTemplates, 'Should have reflectionNamespaceTemplates').toBeDefined();
71+
expect(episodic!.reflectionNamespaceTemplates!.length).toBeGreaterThan(0);
7272

7373
telemetry.assertMetricEmitted({
7474
command: 'add.memory',

integ-tests/create-memory.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe.skipIf(!prereqs.npm || !prereqs.git)('integration: create with memory o
8080

8181
// longAndShortTerm should have strategies defined
8282
const memory = memories![0]!;
83-
const strategies = memory.strategies as { type: string; reflectionNamespaces?: string[] }[] | undefined;
83+
const strategies = memory.strategies as { type: string; reflectionNamespaceTemplates?: string[] }[] | undefined;
8484
expect(strategies, 'memory should have strategies').toBeDefined();
8585
expect(strategies!.length).toBe(4);
8686

@@ -91,10 +91,10 @@ describe.skipIf(!prereqs.npm || !prereqs.git)('integration: create with memory o
9191
expect(types).toContain('SUMMARIZATION');
9292
expect(types).toContain('EPISODIC');
9393

94-
// Verify EPISODIC has reflectionNamespaces
94+
// Verify EPISODIC has reflectionNamespaceTemplates
9595
const episodic = strategies!.find(s => s.type === 'EPISODIC');
9696
expect(episodic, 'EPISODIC strategy should exist').toBeTruthy();
97-
expect(episodic!.reflectionNamespaces, 'EPISODIC should have reflectionNamespaces').toBeDefined();
98-
expect(episodic!.reflectionNamespaces!.length).toBeGreaterThan(0);
97+
expect(episodic!.reflectionNamespaceTemplates, 'EPISODIC should have reflectionNamespaceTemplates').toBeDefined();
98+
expect(episodic!.reflectionNamespaceTemplates!.length).toBeGreaterThan(0);
9999
});
100100
});

integ-tests/tui/add-memory-episodic.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
*
44
* Drives the "Add Memory" wizard through the TUI to verify that when a user
55
* selects the EPISODIC strategy, it is correctly persisted in agentcore.json
6-
* with both namespaces and reflectionNamespaces.
6+
* with both namespaceTemplates and reflectionNamespaceTemplates.
77
*
88
* Exercises:
99
* - Navigation from HelpScreen -> Add Resource -> Memory
1010
* - Memory name input
1111
* - Expiry selection (default 30 days)
1212
* - Strategy multi-select including EPISODIC
1313
* - Confirm review screen
14-
* - Verification that agentcore.json contains EPISODIC with reflectionNamespaces
14+
* - Verification that agentcore.json contains EPISODIC with reflectionNamespaceTemplates
1515
*/
1616
import { TuiSession, WaitForTimeoutError } from '../../src/tui-harness/index.js';
1717
import { createMinimalProjectDir } from './helpers.js';
@@ -176,14 +176,14 @@ describe('Add Memory with EPISODIC Strategy', () => {
176176
expect(found).toBe(true);
177177
});
178178

179-
it('Step 9: agentcore.json contains EPISODIC with reflectionNamespaces', async () => {
179+
it('Step 9: agentcore.json contains EPISODIC with reflectionNamespaceTemplates', async () => {
180180
const configPath = join(projectDir.dir, 'agentcore', 'agentcore.json');
181181
const raw = await readFileAsync(configPath, 'utf-8');
182182
const config = JSON.parse(raw);
183183

184184
const memories = config.memories as {
185185
name: string;
186-
strategies: { type: string; namespaces?: string[]; reflectionNamespaces?: string[] }[];
186+
strategies: { type: string; namespaceTemplates?: string[]; reflectionNamespaceTemplates?: string[] }[];
187187
}[];
188188
expect(memories.length).toBeGreaterThan(0);
189189

@@ -197,12 +197,12 @@ describe('Add Memory with EPISODIC Strategy', () => {
197197
expect(types).toContain('USER_PREFERENCE');
198198
expect(types).toContain('EPISODIC');
199199

200-
// Verify EPISODIC has namespaces AND reflectionNamespaces
200+
// Verify EPISODIC has namespaceTemplates AND reflectionNamespaceTemplates
201201
const episodic = memory!.strategies.find(s => s.type === 'EPISODIC');
202202
expect(episodic, 'EPISODIC strategy should exist').toBeTruthy();
203-
expect(episodic!.namespaces, 'EPISODIC should have namespaces').toBeDefined();
204-
expect(episodic!.namespaces!.length).toBeGreaterThan(0);
205-
expect(episodic!.reflectionNamespaces, 'EPISODIC should have reflectionNamespaces').toBeDefined();
206-
expect(episodic!.reflectionNamespaces!.length).toBeGreaterThan(0);
203+
expect(episodic!.namespaceTemplates, 'EPISODIC should have namespaceTemplates').toBeDefined();
204+
expect(episodic!.namespaceTemplates!.length).toBeGreaterThan(0);
205+
expect(episodic!.reflectionNamespaceTemplates, 'EPISODIC should have reflectionNamespaceTemplates').toBeDefined();
206+
expect(episodic!.reflectionNamespaceTemplates!.length).toBeGreaterThan(0);
207207
});
208208
});

src/cli/aws/agentcore-control.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ export interface MemoryDetail {
368368
type: string;
369369
name?: string;
370370
description?: string;
371-
namespaces?: string[];
372-
reflectionNamespaces?: string[];
371+
namespaceTemplates?: string[];
372+
reflectionNamespaceTemplates?: string[];
373373
}[];
374374
tags?: Record<string, string>;
375375
encryptionKeyArn?: string;
@@ -422,13 +422,17 @@ export async function getMemoryDetail(options: GetMemoryOptions): Promise<Memory
422422
if (!s.type) {
423423
throw new Error(`Memory ${options.memoryId} has a strategy with missing required field: type`);
424424
}
425-
const episodicNamespaces = s.configuration?.reflection?.episodicReflectionConfiguration?.namespaces;
425+
// Prefer the new `namespaceTemplates` field; fall back to the deprecated `namespaces` field.
426+
const namespaceTemplates = s.namespaceTemplates ?? s.namespaces;
427+
const reflectionConfig = s.configuration?.reflection?.episodicReflectionConfiguration;
428+
const reflectionTemplates = reflectionConfig?.namespaceTemplates ?? reflectionConfig?.namespaces;
426429
return {
427430
type: s.type,
428431
name: s.name,
429432
description: s.description,
430-
namespaces: s.namespaces,
431-
...(episodicNamespaces && episodicNamespaces.length > 0 && { reflectionNamespaces: episodicNamespaces }),
433+
...(namespaceTemplates && namespaceTemplates.length > 0 && { namespaceTemplates }),
434+
...(reflectionTemplates &&
435+
reflectionTemplates.length > 0 && { reflectionNamespaceTemplates: reflectionTemplates }),
432436
};
433437
}),
434438
};

src/cli/commands/add/__tests__/add-memory.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,20 +138,20 @@ describe('add memory command', () => {
138138
const memory = projectSpec.memories.find((m: { name: string }) => m.name === memoryName);
139139

140140
const semantic = memory?.strategies?.find((s: { type: string }) => s.type === 'SEMANTIC');
141-
expect(semantic?.namespaces).toEqual(['/users/{actorId}/facts']);
141+
expect(semantic?.namespaceTemplates).toEqual(['/users/{actorId}/facts']);
142142

143143
const userPref = memory?.strategies?.find((s: { type: string }) => s.type === 'USER_PREFERENCE');
144-
expect(userPref?.namespaces).toEqual(['/users/{actorId}/preferences']);
144+
expect(userPref?.namespaceTemplates).toEqual(['/users/{actorId}/preferences']);
145145

146146
const summarization = memory?.strategies?.find((s: { type: string }) => s.type === 'SUMMARIZATION');
147-
expect(summarization?.namespaces).toEqual(['/summaries/{actorId}/{sessionId}']);
147+
expect(summarization?.namespaceTemplates).toEqual(['/summaries/{actorId}/{sessionId}']);
148148

149149
const episodic = memory?.strategies?.find((s: { type: string }) => s.type === 'EPISODIC');
150-
expect(episodic?.namespaces).toEqual(['/episodes/{actorId}/{sessionId}']);
151-
expect(episodic?.reflectionNamespaces).toEqual(['/episodes/{actorId}']);
150+
expect(episodic?.namespaceTemplates).toEqual(['/episodes/{actorId}/{sessionId}']);
151+
expect(episodic?.reflectionNamespaceTemplates).toEqual(['/episodes/{actorId}']);
152152
});
153153

154-
it('creates memory with EPISODIC strategy including default namespaces and reflectionNamespaces', async () => {
154+
it('creates memory with EPISODIC strategy including default namespaceTemplates and reflectionNamespaceTemplates', async () => {
155155
const memoryName = `epi${Date.now()}`;
156156
const result = await runCLI(
157157
['add', 'memory', '--name', memoryName, '--strategies', 'EPISODIC', '--json'],
@@ -162,8 +162,8 @@ describe('add memory command', () => {
162162
const memory = projectSpec.memories.find((m: { name: string }) => m.name === memoryName);
163163
const episodic = memory?.strategies?.find((s: { type: string }) => s.type === 'EPISODIC');
164164
expect(episodic).toBeTruthy();
165-
expect(episodic?.namespaces).toEqual(['/episodes/{actorId}/{sessionId}']);
166-
expect(episodic?.reflectionNamespaces).toEqual(['/episodes/{actorId}']);
165+
expect(episodic?.namespaceTemplates).toEqual(['/episodes/{actorId}/{sessionId}']);
166+
expect(episodic?.reflectionNamespaceTemplates).toEqual(['/episodes/{actorId}']);
167167
});
168168
});
169169
});

src/cli/commands/create/__tests__/create.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,18 @@ describe('create command', () => {
143143
const memory = projectSpec.memories[0];
144144

145145
const semantic = memory?.strategies?.find((s: { type: string }) => s.type === 'SEMANTIC');
146-
expect(semantic?.namespaces).toEqual(['/users/{actorId}/facts']);
146+
expect(semantic?.namespaceTemplates).toEqual(['/users/{actorId}/facts']);
147147

148148
const userPref = memory?.strategies?.find((s: { type: string }) => s.type === 'USER_PREFERENCE');
149-
expect(userPref?.namespaces).toEqual(['/users/{actorId}/preferences']);
149+
expect(userPref?.namespaceTemplates).toEqual(['/users/{actorId}/preferences']);
150150

151151
const summarization = memory?.strategies?.find((s: { type: string }) => s.type === 'SUMMARIZATION');
152-
expect(summarization?.namespaces).toEqual(['/summaries/{actorId}/{sessionId}']);
152+
expect(summarization?.namespaceTemplates).toEqual(['/summaries/{actorId}/{sessionId}']);
153153

154154
const episodic = memory?.strategies?.find((s: { type: string }) => s.type === 'EPISODIC');
155155
expect(episodic, 'EPISODIC strategy should exist in longAndShortTerm').toBeTruthy();
156-
expect(episodic?.namespaces).toEqual(['/episodes/{actorId}/{sessionId}']);
157-
expect(episodic?.reflectionNamespaces).toEqual(['/episodes/{actorId}']);
156+
expect(episodic?.namespaceTemplates).toEqual(['/episodes/{actorId}/{sessionId}']);
157+
expect(episodic?.reflectionNamespaceTemplates).toEqual(['/episodes/{actorId}']);
158158
});
159159

160160
it('uses --project-name for project and --name for agent resource', async () => {

src/cli/commands/import/import-memory.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ function filterInternalNamespaces(namespaces: string[]): string[] {
4242
function toMemorySpec(memory: MemoryDetail, localName: string): Memory {
4343
const strategies: Memory['strategies'] = memory.strategies.map(s => {
4444
const mappedType = mapStrategyType(s.type);
45-
const filteredNamespaces = s.namespaces ? filterInternalNamespaces(s.namespaces) : [];
45+
const filteredTemplates = s.namespaceTemplates ? filterInternalNamespaces(s.namespaceTemplates) : [];
4646
return {
4747
type: mappedType as Memory['strategies'][number]['type'],
4848
...(s.name && { name: s.name }),
4949
...(s.description && { description: s.description }),
50-
...(filteredNamespaces.length > 0 && { namespaces: filteredNamespaces }),
51-
...(s.reflectionNamespaces &&
52-
s.reflectionNamespaces.length > 0 && { reflectionNamespaces: s.reflectionNamespaces }),
50+
...(filteredTemplates.length > 0 && { namespaceTemplates: filteredTemplates }),
51+
...(s.reflectionNamespaceTemplates &&
52+
s.reflectionNamespaceTemplates.length > 0 && {
53+
reflectionNamespaceTemplates: s.reflectionNamespaceTemplates,
54+
}),
5355
};
5456
});
5557

0 commit comments

Comments
 (0)