bedrock-agentcore 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +1 -1
  2. package/dist/src/memory/integrations/strands/factory.d.ts +78 -0
  3. package/dist/src/memory/integrations/strands/factory.d.ts.map +1 -0
  4. package/dist/src/memory/integrations/strands/factory.js +108 -0
  5. package/dist/src/memory/integrations/strands/factory.js.map +1 -0
  6. package/dist/src/memory/integrations/strands/format.d.ts +17 -0
  7. package/dist/src/memory/integrations/strands/format.d.ts.map +1 -0
  8. package/dist/src/memory/integrations/strands/format.js +29 -0
  9. package/dist/src/memory/integrations/strands/format.js.map +1 -0
  10. package/dist/src/memory/integrations/strands/index.d.ts +11 -0
  11. package/dist/src/memory/integrations/strands/index.d.ts.map +1 -0
  12. package/dist/src/memory/integrations/strands/index.js +6 -0
  13. package/dist/src/memory/integrations/strands/index.js.map +1 -0
  14. package/dist/src/memory/integrations/strands/logger.d.ts +19 -0
  15. package/dist/src/memory/integrations/strands/logger.d.ts.map +1 -0
  16. package/dist/src/memory/integrations/strands/logger.js +27 -0
  17. package/dist/src/memory/integrations/strands/logger.js.map +1 -0
  18. package/dist/src/memory/integrations/strands/sender.d.ts +79 -0
  19. package/dist/src/memory/integrations/strands/sender.d.ts.map +1 -0
  20. package/dist/src/memory/integrations/strands/sender.js +170 -0
  21. package/dist/src/memory/integrations/strands/sender.js.map +1 -0
  22. package/dist/src/memory/integrations/strands/store.d.ts +28 -0
  23. package/dist/src/memory/integrations/strands/store.d.ts.map +1 -0
  24. package/dist/src/memory/integrations/strands/store.js +154 -0
  25. package/dist/src/memory/integrations/strands/store.js.map +1 -0
  26. package/dist/src/memory/integrations/strands/types.d.ts +122 -0
  27. package/dist/src/memory/integrations/strands/types.d.ts.map +1 -0
  28. package/dist/src/memory/integrations/strands/types.js +73 -0
  29. package/dist/src/memory/integrations/strands/types.js.map +1 -0
  30. package/dist/src/runtime/app.d.ts +7 -2
  31. package/dist/src/runtime/app.d.ts.map +1 -1
  32. package/dist/src/runtime/app.js +7 -4
  33. package/dist/src/runtime/app.js.map +1 -1
  34. package/dist/src/runtime/client.d.ts +79 -11
  35. package/dist/src/runtime/client.d.ts.map +1 -1
  36. package/dist/src/runtime/client.js +230 -79
  37. package/dist/src/runtime/client.js.map +1 -1
  38. package/dist/src/runtime/index.d.ts +5 -0
  39. package/dist/src/runtime/index.d.ts.map +1 -1
  40. package/dist/src/runtime/index.js +3 -0
  41. package/dist/src/runtime/index.js.map +1 -1
  42. package/dist/src/runtime/shell/config.d.ts +81 -0
  43. package/dist/src/runtime/shell/config.d.ts.map +1 -0
  44. package/dist/src/runtime/shell/config.js +15 -0
  45. package/dist/src/runtime/shell/config.js.map +1 -0
  46. package/dist/src/runtime/shell/index.d.ts +9 -0
  47. package/dist/src/runtime/shell/index.d.ts.map +1 -0
  48. package/dist/src/runtime/shell/index.js +6 -0
  49. package/dist/src/runtime/shell/index.js.map +1 -0
  50. package/dist/src/runtime/shell/protocol.d.ts +45 -0
  51. package/dist/src/runtime/shell/protocol.d.ts.map +1 -0
  52. package/dist/src/runtime/shell/protocol.js +99 -0
  53. package/dist/src/runtime/shell/protocol.js.map +1 -0
  54. package/dist/src/runtime/shell/session.d.ts +240 -0
  55. package/dist/src/runtime/shell/session.d.ts.map +1 -0
  56. package/dist/src/runtime/shell/session.js +880 -0
  57. package/dist/src/runtime/shell/session.js.map +1 -0
  58. package/dist/src/runtime/shell/validation.d.ts +8 -0
  59. package/dist/src/runtime/shell/validation.d.ts.map +1 -0
  60. package/dist/src/runtime/shell/validation.js +17 -0
  61. package/dist/src/runtime/shell/validation.js.map +1 -0
  62. package/dist/src/runtime/types.d.ts +89 -0
  63. package/dist/src/runtime/types.d.ts.map +1 -1
  64. package/package.json +13 -4
package/README.md CHANGED
@@ -104,7 +104,7 @@ const agent = new Agent({
104
104
  - **Code Interpreter** — Execute Python/JS/TS in a sandbox → [Examples](https://github.com/awslabs/bedrock-agentcore-samples-typescript/tree/main/primitives/tools/code-interpreter)
105
105
  - **Browser** — Cloud-based web automation → [Examples](https://github.com/awslabs/bedrock-agentcore-samples-typescript/tree/main/primitives/tools/browser)
106
106
  - **Identity** — Manage API keys and OAuth tokens → [Examples](https://github.com/awslabs/bedrock-agentcore-samples-typescript/tree/main/primitives/identity)
107
- - **Memory** — Persistent knowledge across sessions (coming soon)
107
+ - **Memory** — Persistent knowledge across sessions (experimental) → [Guide](docs/MEMORY.md)
108
108
  - **Gateway** — Transform APIs into MCP tools (coming soon)
109
109
  - **Observability** — OpenTelemetry tracing (coming soon)
110
110
 
@@ -0,0 +1,78 @@
1
+ import { BedrockAgentCoreClient } from '@aws-sdk/client-bedrock-agentcore';
2
+ import type { AwsCredentialIdentityProvider } from '@aws-sdk/types';
3
+ import type { ExtractionTrigger, MemoryMessageFilter } from '@strands-agents/sdk';
4
+ import { AgentCoreMemoryStore } from './store.js';
5
+ import { type MetadataProvider } from './types.js';
6
+ /** Per-namespace read configuration. */
7
+ export interface AgentCoreNamespaceConfig {
8
+ /** Namespace template, e.g. `/strategy/{id}/actor/{actorId}/preferences`. */
9
+ namespace: string;
10
+ /** Store name; defaults to a slug derived from the namespace. */
11
+ name?: string;
12
+ description?: string;
13
+ maxSearchResults?: number;
14
+ minScore?: number;
15
+ /** Over-fetch multiplier when `minScore` is set (see {@link AgentCoreMemoryStoreConfig.overFetchFactor}). */
16
+ overFetchFactor?: number;
17
+ /** Marks this the single write sink. Defaults to the first namespace when extraction is enabled; see {@link assertWritableTopology}. */
18
+ writable?: boolean;
19
+ }
20
+ /**
21
+ * Object form of the {@link CreateAgentCoreMemoryStoresInput.extraction} switch: writable, with optional
22
+ * control over write cadence and which message content is written.
23
+ */
24
+ export interface AgentCoreExtractionConfig {
25
+ /**
26
+ * When buffered turns are flushed to `createEvent`. Omit for the MemoryManager's default
27
+ * (`IntervalTrigger`); pass any Strands {@link ExtractionTrigger} or an array. A trigger only sets
28
+ * cadence (fire-and-forget) — `MemoryManager.flush()` is what guarantees durability.
29
+ */
30
+ cadence?: ExtractionTrigger | ExtractionTrigger[];
31
+ /**
32
+ * Which message content blocks to exclude before writing (the extraction `filter`). Omit to use the
33
+ * framework default (drops tool use/result). Forwarded to the store's `ExtractionConfig.filter`.
34
+ */
35
+ filter?: MemoryMessageFilter;
36
+ }
37
+ export interface CreateAgentCoreMemoryStoresInput {
38
+ memoryId: string;
39
+ actorId: string;
40
+ sessionId: string;
41
+ /**
42
+ * Read namespaces — one store is built per entry, each reading its own exact namespace prefix. To read a
43
+ * whole subtree instead, that is a single store: construct it directly with
44
+ * `new AgentCoreMemoryStore({ ...identity, namespacePath })`.
45
+ */
46
+ namespaces: AgentCoreNamespaceConfig[];
47
+ /**
48
+ * The single write switch: omit/`false` = recall-only; `true` = writable with the default cadence;
49
+ * `{ cadence?, filter? }` = writable with a custom cadence/filter. The writer namespace is chosen by
50
+ * the per-namespace `writable` flag (else the first).
51
+ */
52
+ extraction?: boolean | AgentCoreExtractionConfig;
53
+ metadataProvider?: MetadataProvider;
54
+ /**
55
+ * Max conversational turns packed into one `createEvent` write (default
56
+ * {@link DEFAULT_MAX_TURNS_PER_EVENT}). Combined with the extraction trigger cadence, this controls
57
+ * write API-call volume: a flush of N turns is sent as `ceil(n / maxTurnsPerEvent)` events.
58
+ */
59
+ maxTurnsPerEvent?: number;
60
+ region?: string;
61
+ credentialsProvider?: AwsCredentialIdentityProvider;
62
+ /** Shared client; one is constructed (and reused across the returned stores) if omitted. */
63
+ client?: BedrockAgentCoreClient;
64
+ }
65
+ /**
66
+ * At most one store may be writable. `createEvent` is namespace-free (it writes the whole conversation to
67
+ * the `(memoryId, actorId, sessionId)` stream), so two writers would emit duplicate events that nothing
68
+ * upstream dedupes — and a store can't see its siblings, so the rule can only be enforced here, at
69
+ * construction. Exported so hand-built (`new`) multi-store setups can guard themselves. With
70
+ * `expectExtraction`, a writer is required (0 writers throws).
71
+ */
72
+ export declare function assertWritableTopology(stores: readonly AgentCoreMemoryStore[], expectExtraction?: boolean): void;
73
+ /**
74
+ * Build the stores for one `(actorId, sessionId)` — one shared client, one writer — ready to spread into
75
+ * `MemoryManagerConfig.stores`. Called once per `(actorId, sessionId)` by a multi-actor server.
76
+ */
77
+ export declare function createAgentCoreMemoryStores(input: CreateAgentCoreMemoryStoresInput): AgentCoreMemoryStore[];
78
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAC1E,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,KAAK,EAAoB,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAA;AAEnB,wCAAwC;AACxC,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6GAA6G;IAC7G,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,wIAAwI;IACxI,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,OAAO,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,CAAA;IACjD;;;OAGG;IACH,MAAM,CAAC,EAAE,mBAAmB,CAAA;CAC7B;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IAEjB;;;;OAIG;IACH,UAAU,EAAE,wBAAwB,EAAE,CAAA;IAEtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAA;IAEhD,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,6BAA6B,CAAA;IACnD,4FAA4F;IAC5F,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAChC;AAwBD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,EAAE,gBAAgB,UAAQ,GAAG,IAAI,CAgB9G;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,gCAAgC,GAAG,oBAAoB,EAAE,CAiF3G"}
@@ -0,0 +1,108 @@
1
+ import { BedrockAgentCoreClient } from '@aws-sdk/client-bedrock-agentcore';
2
+ import { AgentCoreMemoryStore } from './store.js';
3
+ import { DEFAULT_REGION, } from './types.js';
4
+ /** Optional fields are spread conditionally so an explicit `undefined` never violates `exactOptionalPropertyTypes`. */
5
+ function buildStoreConfig(args) {
6
+ const { config, ns, writable, extraction } = args;
7
+ return {
8
+ // Spread the shared identity flat — same client/identity object reused across the set.
9
+ ...config,
10
+ namespace: ns.namespace,
11
+ writable,
12
+ ...(ns.name !== undefined && { name: ns.name }),
13
+ ...(ns.description !== undefined && { description: ns.description }),
14
+ ...(ns.maxSearchResults !== undefined && { maxSearchResults: ns.maxSearchResults }),
15
+ ...(ns.minScore !== undefined && { minScore: ns.minScore }),
16
+ ...(ns.overFetchFactor !== undefined && { overFetchFactor: ns.overFetchFactor }),
17
+ ...(writable && extraction !== undefined && { extraction }),
18
+ };
19
+ }
20
+ /**
21
+ * At most one store may be writable. `createEvent` is namespace-free (it writes the whole conversation to
22
+ * the `(memoryId, actorId, sessionId)` stream), so two writers would emit duplicate events that nothing
23
+ * upstream dedupes — and a store can't see its siblings, so the rule can only be enforced here, at
24
+ * construction. Exported so hand-built (`new`) multi-store setups can guard themselves. With
25
+ * `expectExtraction`, a writer is required (0 writers throws).
26
+ */
27
+ export function assertWritableTopology(stores, expectExtraction = false) {
28
+ const writers = stores.filter((s) => s.writable);
29
+ if (writers.length > 1) {
30
+ throw new Error(`AgentCore memory: at most one store may be writable, but ${writers.length} are ` +
31
+ `(${writers.map((s) => `"${s.name}"`).join(', ')}). createEvent is namespace-free, so multiple ` +
32
+ 'writable stores would write duplicate events to the same (memoryId, actorId, sessionId) stream. ' +
33
+ 'Mark exactly one namespace writable.');
34
+ }
35
+ if (expectExtraction && writers.length === 0) {
36
+ throw new Error('AgentCore memory: extraction is enabled but no store is writable. Mark one namespace ' +
37
+ '`writable: true` (or omit extraction for recall-only).');
38
+ }
39
+ }
40
+ /**
41
+ * Build the stores for one `(actorId, sessionId)` — one shared client, one writer — ready to spread into
42
+ * `MemoryManagerConfig.stores`. Called once per `(actorId, sessionId)` by a multi-actor server.
43
+ */
44
+ export function createAgentCoreMemoryStores(input) {
45
+ if (!Array.isArray(input.namespaces) || input.namespaces.length === 0) {
46
+ throw new Error('createAgentCoreMemoryStores: at least one namespace is required');
47
+ }
48
+ input.namespaces.forEach((ns, i) => {
49
+ if (ns === null || typeof ns !== 'object' || typeof ns.namespace !== 'string' || ns.namespace.trim().length === 0) {
50
+ throw new Error(`createAgentCoreMemoryStores: namespaces[${i}].namespace must be a non-empty string`);
51
+ }
52
+ });
53
+ // Validated here too, not only in the sender: a recall-only set never builds a sender.
54
+ if (input.maxTurnsPerEvent !== undefined &&
55
+ (!Number.isInteger(input.maxTurnsPerEvent) || input.maxTurnsPerEvent < 1)) {
56
+ throw new Error(`createAgentCoreMemoryStores: maxTurnsPerEvent must be a positive integer, got ${input.maxTurnsPerEvent}`);
57
+ }
58
+ // `true` passes through (the MemoryManager applies its own default cadence); only a custom
59
+ // cadence/filter builds an ExtractionConfig. `!Array.isArray` stops a stray array (typeof === 'object')
60
+ // being duck-typed as a config.
61
+ const writeEnabled = input.extraction !== undefined && input.extraction !== false;
62
+ const extractionObj = typeof input.extraction === 'object' && !Array.isArray(input.extraction) ? input.extraction : {};
63
+ const hasCustomConfig = extractionObj.cadence !== undefined || extractionObj.filter !== undefined;
64
+ const extraction = !writeEnabled
65
+ ? undefined
66
+ : hasCustomConfig
67
+ ? {
68
+ ...(extractionObj.cadence !== undefined && { trigger: extractionObj.cadence }),
69
+ ...(extractionObj.filter !== undefined && { filter: extractionObj.filter }),
70
+ }
71
+ : true;
72
+ const client = input.client ??
73
+ new BedrockAgentCoreClient({
74
+ region: input.region ?? process.env.AWS_REGION ?? DEFAULT_REGION,
75
+ ...(input.credentialsProvider && { credentials: input.credentialsProvider }),
76
+ });
77
+ // Shared connection + write identity, built once and reused across every store in this set.
78
+ const config = {
79
+ memoryId: input.memoryId,
80
+ actorId: input.actorId,
81
+ sessionId: input.sessionId,
82
+ ...(input.metadataProvider !== undefined && { metadataProvider: input.metadataProvider }),
83
+ ...(input.maxTurnsPerEvent !== undefined && { maxTurnsPerEvent: input.maxTurnsPerEvent }),
84
+ client,
85
+ };
86
+ // The default writer skips namespaces that explicitly opted out (`writable: false`) rather than
87
+ // overriding them; multiple explicit `writable: true` flags are left intact so assertWritableTopology
88
+ // catches the conflict loudly instead of silently picking one.
89
+ const anyFlagged = input.namespaces.some((ns) => ns.writable === true);
90
+ const defaultWriterIndex = !anyFlagged && writeEnabled ? input.namespaces.findIndex((ns) => ns.writable !== false) : -1;
91
+ if (writeEnabled && !anyFlagged && defaultWriterIndex === -1) {
92
+ throw new Error('createAgentCoreMemoryStores: extraction is enabled but every namespace is marked writable: false; ' +
93
+ 'leave one namespace un-opted-out (or set writable: true on the intended writer).');
94
+ }
95
+ const stores = input.namespaces.map((ns, i) => {
96
+ const isWriter = ns.writable === true || i === defaultWriterIndex;
97
+ return new AgentCoreMemoryStore(buildStoreConfig({
98
+ config,
99
+ ns,
100
+ writable: isWriter,
101
+ extraction: isWriter ? extraction : undefined,
102
+ }));
103
+ });
104
+ // Store-name uniqueness is validated by the MemoryManager constructor, so we don't re-check it here.
105
+ assertWritableTopology(stores, writeEnabled);
106
+ return stores;
107
+ }
108
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { MessageData } from '@strands-agents/sdk';
2
+ /** AgentCore conversational role. Mirrors the SDK `Role` enum values we emit. */
3
+ export type AgentCoreRole = 'USER' | 'ASSISTANT';
4
+ /**
5
+ * Map a Strands message role to the AgentCore conversational role.
6
+ *
7
+ * Strands roles are `'user' | 'assistant'`; AgentCore's `Role` enum also has `OTHER`/`TOOL`, but the
8
+ * conversation-ingestion path only ever produces user/assistant turns, so we map to that subset.
9
+ */
10
+ export declare function mapRole(message: Pick<MessageData, 'role'>): AgentCoreRole;
11
+ export declare function extractText(message: Pick<MessageData, 'content'>): string;
12
+ /**
13
+ * Whether a message is a user/assistant turn carrying extractable text. Tool-only or empty messages
14
+ * yield no useful AgentCore event, so the sender skips them.
15
+ */
16
+ export declare function isUserOrAssistantWithText(message: MessageData): boolean;
17
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,qBAAqB,CAAA;AAE3E,iFAAiF;AACjF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,CAAA;AAEhD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,aAAa,CAEzE;AAMD,wBAAgB,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,MAAM,CAQzE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAEvE"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Map a Strands message role to the AgentCore conversational role.
3
+ *
4
+ * Strands roles are `'user' | 'assistant'`; AgentCore's `Role` enum also has `OTHER`/`TOOL`, but the
5
+ * conversation-ingestion path only ever produces user/assistant turns, so we map to that subset.
6
+ */
7
+ export function mapRole(message) {
8
+ return message.role === 'user' ? 'USER' : 'ASSISTANT';
9
+ }
10
+ function isTextBlock(block) {
11
+ return typeof block === 'object' && block !== null && typeof block.text === 'string';
12
+ }
13
+ export function extractText(message) {
14
+ // Drop empty/blank text blocks before joining so an empty middle block doesn't leave a stray blank
15
+ // line in the concatenation (mirrors the upstream renderer).
16
+ return message.content
17
+ .filter(isTextBlock)
18
+ .map((block) => block.text.trim())
19
+ .filter((text) => text.length > 0)
20
+ .join('\n');
21
+ }
22
+ /**
23
+ * Whether a message is a user/assistant turn carrying extractable text. Tool-only or empty messages
24
+ * yield no useful AgentCore event, so the sender skips them.
25
+ */
26
+ export function isUserOrAssistantWithText(message) {
27
+ return (message.role === 'user' || message.role === 'assistant') && extractText(message).length > 0;
28
+ }
29
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/format.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,OAAkC;IACxD,OAAO,OAAO,CAAC,IAAI,KAAM,MAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAA;AACxE,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ,CAAA;AAC9G,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAqC;IAC/D,mGAAmG;IACnG,6DAA6D;IAC7D,OAAO,OAAO,CAAC,OAAO;SACnB,MAAM,CAAC,WAAW,CAAC;SACnB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACjC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAoB;IAC5D,OAAO,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;AACrG,CAAC"}
@@ -0,0 +1,11 @@
1
+ export { AgentCoreMemoryStore } from './store.js';
2
+ export { createAgentCoreMemoryStores, assertWritableTopology } from './factory.js';
3
+ export { AgentCoreEventSender } from './sender.js';
4
+ export { resolveNamespace, slugifyNamespace, RESERVED_METADATA_PREFIX } from './types.js';
5
+ export { configureMemoryLogging } from './logger.js';
6
+ export type { Logger } from './logger.js';
7
+ export type { AgentCoreMemoryConfig, AgentCoreMemoryStoreConfig, AgentCoreReadTarget, MetadataProvider, } from './types.js';
8
+ export type { CreateAgentCoreMemoryStoresInput, AgentCoreNamespaceConfig, AgentCoreExtractionConfig, } from './factory.js';
9
+ export type { AgentCoreEventSenderConfig } from './sender.js';
10
+ export type { AgentCoreRole } from './format.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACpD,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,YAAY,EACV,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { AgentCoreMemoryStore } from './store.js';
2
+ export { createAgentCoreMemoryStores, assertWritableTopology } from './factory.js';
3
+ export { AgentCoreEventSender } from './sender.js';
4
+ export { resolveNamespace, slugifyNamespace, RESERVED_METADATA_PREFIX } from './types.js';
5
+ export { configureMemoryLogging } from './logger.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Module-local logger mirroring the Strands SDK `Logger` convention (debug/info no-op by default,
3
+ * warn/error to console), with an injection hook so callers can route logs through Pino/Winston/etc.
4
+ *
5
+ * Strands exports `configureLogging` and the `Logger` type but not its global `logger` instance, so an
6
+ * external package cannot import that instance. We therefore own a console-backed default here that
7
+ * matches the SDK's shape; if Strands later exposes its instance, this can delegate to it without
8
+ * touching the call sites (`logger.warn(...)`).
9
+ */
10
+ export interface Logger {
11
+ debug(...args: unknown[]): void;
12
+ info(...args: unknown[]): void;
13
+ warn(...args: unknown[]): void;
14
+ error(...args: unknown[]): void;
15
+ }
16
+ export declare const logger: Logger;
17
+ /** Inject a custom logger for AgentCore memory logging (e.g. to route through the host app's logger). */
18
+ export declare function configureMemoryLogging(customLogger: Logger): void;
19
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC9B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC9B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAChC;AAWD,eAAO,MAAM,MAAM,EAAE,MAKpB,CAAA;AAED,yGAAyG;AACzG,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAEjE"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Module-local logger mirroring the Strands SDK `Logger` convention (debug/info no-op by default,
3
+ * warn/error to console), with an injection hook so callers can route logs through Pino/Winston/etc.
4
+ *
5
+ * Strands exports `configureLogging` and the `Logger` type but not its global `logger` instance, so an
6
+ * external package cannot import that instance. We therefore own a console-backed default here that
7
+ * matches the SDK's shape; if Strands later exposes its instance, this can delegate to it without
8
+ * touching the call sites (`logger.warn(...)`).
9
+ */
10
+ const defaultLogger = {
11
+ debug: () => { },
12
+ info: () => { },
13
+ warn: (...args) => console.warn(...args),
14
+ error: (...args) => console.error(...args),
15
+ };
16
+ let current = defaultLogger;
17
+ export const logger = {
18
+ debug: (...args) => current.debug(...args),
19
+ info: (...args) => current.info(...args),
20
+ warn: (...args) => current.warn(...args),
21
+ error: (...args) => current.error(...args),
22
+ };
23
+ /** Inject a custom logger for AgentCore memory logging (e.g. to route through the host app's logger). */
24
+ export function configureMemoryLogging(customLogger) {
25
+ current = customLogger;
26
+ }
27
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,aAAa,GAAW;IAC5B,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;IACd,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACnD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;CACtD,CAAA;AAED,IAAI,OAAO,GAAW,aAAa,CAAA;AAEnC,MAAM,CAAC,MAAM,MAAM,GAAW;IAC5B,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAC1C,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;CAC3C,CAAA;AAED,yGAAyG;AACzG,MAAM,UAAU,sBAAsB,CAAC,YAAoB;IACzD,OAAO,GAAG,YAAY,CAAA;AACxB,CAAC"}
@@ -0,0 +1,79 @@
1
+ import { type BedrockAgentCoreClient } from '@aws-sdk/client-bedrock-agentcore';
2
+ import type { MessageData } from '@strands-agents/sdk';
3
+ import { type MetadataProvider } from './types.js';
4
+ export interface AgentCoreEventSenderConfig {
5
+ client: BedrockAgentCoreClient;
6
+ memoryId: string;
7
+ actorId: string;
8
+ sessionId: string;
9
+ metadataProvider?: MetadataProvider | undefined;
10
+ /**
11
+ * Run-unique id anchoring the idempotency `clientToken`. Defaults to a fresh UUID per sender. A new
12
+ * sender is built per `(actorId, sessionId)` per process, so this distinguishes runs even when the
13
+ * framework's per-message sequence numbers reset to 0 (e.g. on session restore).
14
+ */
15
+ runId?: string;
16
+ /**
17
+ * Maximum conversational turns packed into a single `createEvent`. A batch larger than this splits
18
+ * into `ceil(n / maxTurnsPerEvent)` events. Defaults to {@link DEFAULT_MAX_TURNS_PER_EVENT}; bounds
19
+ * the payload well under the service limit.
20
+ */
21
+ maxTurnsPerEvent?: number;
22
+ }
23
+ /**
24
+ * Writes a batch of role-tagged messages to AgentCore, packing the turns into as few `createEvent`
25
+ * calls as possible. `createEvent` accepts an array of conversational turns, so one flush of N turns
26
+ * becomes a single call (chunked at `maxTurnsPerEvent`) rather than N calls — this is what lets the
27
+ * extraction trigger cadence actually control API-call volume. AgentCore extracts a multi-turn event
28
+ * into the same long-term records it would from N single-turn events.
29
+ *
30
+ * Error handling is delegated to the Strands `ExtractionCoordinator`: a failed `createEvent` throws
31
+ * out of {@link sendBatch}, which makes the coordinator roll back its high-water mark and re-fire the
32
+ * batch on the next trigger (with its own backoff and repeated-failure logging). The sender therefore
33
+ * keeps no retry/timeout/drop machinery of its own — that would duplicate or fight the coordinator. A
34
+ * caller that wants a per-request timeout configures it on the `client` it passes in (which also bounds
35
+ * the read path).
36
+ *
37
+ * Idempotency: when the framework provides per-message sequence numbers (via
38
+ * `AddMessagesContext.sequenceNumbers`), each event gets a deterministic `clientToken` derived from the
39
+ * sequence range it covers, so a coordinator re-fire of the same batch dedups exactly. Because sequence
40
+ * numbers reset to 0 across runs, the token also folds in a run-unique id (see
41
+ * {@link AgentCoreEventSenderConfig.runId}). Without sequence numbers no token is sent; a re-fire then
42
+ * writes one duplicate event, which AgentCore's server-side consolidation collapses at the record level
43
+ * (wasteful but not incorrect). The token derivation is isolated in {@link tokenForSeqs} so it can move
44
+ * to a stable per-message id when the framework exposes one.
45
+ */
46
+ export declare class AgentCoreEventSender {
47
+ private readonly client;
48
+ private readonly memoryId;
49
+ private readonly actorId;
50
+ private readonly sessionId;
51
+ private readonly metadataProvider;
52
+ private readonly runId;
53
+ private readonly maxTurnsPerEvent;
54
+ constructor(config: AgentCoreEventSenderConfig);
55
+ /**
56
+ * Send a batch. The writable turns are packed into one `createEvent` per {@link EventGroup} (chunked
57
+ * by `maxTurnsPerEvent` and split where per-message metadata changes). `sequenceNumbers` (when the
58
+ * framework provides them) are index-aligned with `messages` and key each event's `clientToken`.
59
+ * Throws an `AggregateError` if any event fails, so the coordinator retries the batch.
60
+ */
61
+ sendBatch(messages: MessageData[], sequenceNumbers?: readonly number[]): Promise<void>;
62
+ /**
63
+ * Partition the sendable turns into events. A new event starts when the per-message metadata changes
64
+ * (the event's `metadata` is per-event in AgentCore, so turns in one event must share it) or when the
65
+ * current event reaches `maxTurnsPerEvent`. With no `metadataProvider`, all turns share the empty
66
+ * signature and collapse into size-capped events.
67
+ */
68
+ private groupIntoEvents;
69
+ private sendEvent;
70
+ /**
71
+ * Deterministic re-fire-stable token for an event covering the given sequence numbers, or `undefined`
72
+ * when any is missing (then we tolerate error-path duplicates; consolidation is the backstop). The
73
+ * token spans the event's `[firstSeq, lastSeq]`; a coordinator re-fire of the same batch reproduces
74
+ * the same range. Never time/random-based per call — the run-unique part is fixed for the sender's
75
+ * lifetime. Isolated here so it can switch to a stable per-message id when the framework exposes one.
76
+ */
77
+ private tokenForSeqs;
78
+ }
79
+ //# sourceMappingURL=sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/sender.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,sBAAsB,EAAsB,MAAM,mCAAmC,CAAA;AACnG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE/E,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,sBAAsB,CAAA;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAC/C;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAoBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA8B;IAC/D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;gBAE7B,MAAM,EAAE,0BAA0B;IAc9C;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B5F;;;;;OAKG;IACH,OAAO,CAAC,eAAe;YAkBT,SAAS;IAmBvB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;CAKrB"}
@@ -0,0 +1,170 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { CreateEventCommand } from '@aws-sdk/client-bedrock-agentcore';
3
+ import { extractText, isUserOrAssistantWithText, mapRole } from './format.js';
4
+ import { DEFAULT_MAX_TURNS_PER_EVENT } from './types.js';
5
+ /**
6
+ * Writes a batch of role-tagged messages to AgentCore, packing the turns into as few `createEvent`
7
+ * calls as possible. `createEvent` accepts an array of conversational turns, so one flush of N turns
8
+ * becomes a single call (chunked at `maxTurnsPerEvent`) rather than N calls — this is what lets the
9
+ * extraction trigger cadence actually control API-call volume. AgentCore extracts a multi-turn event
10
+ * into the same long-term records it would from N single-turn events.
11
+ *
12
+ * Error handling is delegated to the Strands `ExtractionCoordinator`: a failed `createEvent` throws
13
+ * out of {@link sendBatch}, which makes the coordinator roll back its high-water mark and re-fire the
14
+ * batch on the next trigger (with its own backoff and repeated-failure logging). The sender therefore
15
+ * keeps no retry/timeout/drop machinery of its own — that would duplicate or fight the coordinator. A
16
+ * caller that wants a per-request timeout configures it on the `client` it passes in (which also bounds
17
+ * the read path).
18
+ *
19
+ * Idempotency: when the framework provides per-message sequence numbers (via
20
+ * `AddMessagesContext.sequenceNumbers`), each event gets a deterministic `clientToken` derived from the
21
+ * sequence range it covers, so a coordinator re-fire of the same batch dedups exactly. Because sequence
22
+ * numbers reset to 0 across runs, the token also folds in a run-unique id (see
23
+ * {@link AgentCoreEventSenderConfig.runId}). Without sequence numbers no token is sent; a re-fire then
24
+ * writes one duplicate event, which AgentCore's server-side consolidation collapses at the record level
25
+ * (wasteful but not incorrect). The token derivation is isolated in {@link tokenForSeqs} so it can move
26
+ * to a stable per-message id when the framework exposes one.
27
+ */
28
+ export class AgentCoreEventSender {
29
+ client;
30
+ memoryId;
31
+ actorId;
32
+ sessionId;
33
+ metadataProvider;
34
+ runId;
35
+ maxTurnsPerEvent;
36
+ constructor(config) {
37
+ this.client = config.client;
38
+ this.memoryId = config.memoryId;
39
+ this.actorId = config.actorId;
40
+ this.sessionId = config.sessionId;
41
+ this.metadataProvider = config.metadataProvider;
42
+ this.runId = config.runId ?? randomUUID();
43
+ const cap = config.maxTurnsPerEvent ?? DEFAULT_MAX_TURNS_PER_EVENT;
44
+ if (!Number.isInteger(cap) || cap < 1) {
45
+ throw new Error(`AgentCoreEventSender: maxTurnsPerEvent must be a positive integer, got ${cap}`);
46
+ }
47
+ this.maxTurnsPerEvent = cap;
48
+ }
49
+ /**
50
+ * Send a batch. The writable turns are packed into one `createEvent` per {@link EventGroup} (chunked
51
+ * by `maxTurnsPerEvent` and split where per-message metadata changes). `sequenceNumbers` (when the
52
+ * framework provides them) are index-aligned with `messages` and key each event's `clientToken`.
53
+ * Throws an `AggregateError` if any event fails, so the coordinator retries the batch.
54
+ */
55
+ async sendBatch(messages, sequenceNumbers) {
56
+ const sendable = messages
57
+ .map((message, i) => ({ message, seq: sequenceNumbers?.[i] }))
58
+ .filter((m) => isUserOrAssistantWithText(m.message));
59
+ if (sendable.length === 0)
60
+ return;
61
+ // Validate + map metadata for every event BEFORE any network call. A charset violation is a
62
+ // deterministic input error, so it must fail loud-and-early (unwrapped) rather than being caught
63
+ // by the allSettled boundary below and re-wrapped as an opaque AggregateError. No createEvent is
64
+ // attempted if any group's metadata is invalid.
65
+ const events = this.groupIntoEvents(sendable).map((g) => {
66
+ // Omit an empty bag entirely so the event carries no `metadata` field (matches the no-provider case).
67
+ const metadata = g.metadata && Object.keys(g.metadata).length > 0 ? toAgentCoreMetadata(g.metadata) : undefined;
68
+ return { items: g.items, metadata };
69
+ });
70
+ const results = await Promise.allSettled(events.map((e) => this.sendEvent(e)));
71
+ const failures = results.filter((r) => r.status === 'rejected');
72
+ if (failures.length > 0) {
73
+ // Fold the first underlying reason into the message: the coordinator logs `.message` only, so a
74
+ // bare count would hide what actually failed.
75
+ const firstReason = failures[0].reason;
76
+ const firstMessage = firstReason instanceof Error ? firstReason.message : String(firstReason);
77
+ throw new AggregateError(failures.map((f) => f.reason), `AgentCore createEvent failed for ${failures.length} of ${events.length} event(s); first error: ${firstMessage}`);
78
+ }
79
+ }
80
+ /**
81
+ * Partition the sendable turns into events. A new event starts when the per-message metadata changes
82
+ * (the event's `metadata` is per-event in AgentCore, so turns in one event must share it) or when the
83
+ * current event reaches `maxTurnsPerEvent`. With no `metadataProvider`, all turns share the empty
84
+ * signature and collapse into size-capped events.
85
+ */
86
+ groupIntoEvents(sendable) {
87
+ const groups = [];
88
+ let current;
89
+ let currentSig;
90
+ for (const item of sendable) {
91
+ const metadata = this.metadataProvider?.(item.message);
92
+ const sig = metadata ? JSON.stringify(metadata) : '';
93
+ const atCap = current !== undefined && current.items.length >= this.maxTurnsPerEvent;
94
+ if (current === undefined || sig !== currentSig || atCap) {
95
+ current = { items: [], metadata };
96
+ groups.push(current);
97
+ currentSig = sig;
98
+ }
99
+ current.items.push(item);
100
+ }
101
+ return groups;
102
+ }
103
+ async sendEvent(event) {
104
+ const payload = event.items.map((item) => ({
105
+ conversational: { role: mapRole(item.message), content: { text: extractText(item.message) } },
106
+ }));
107
+ const clientToken = this.tokenForSeqs(event.items.map((item) => item.seq));
108
+ const command = new CreateEventCommand({
109
+ memoryId: this.memoryId,
110
+ actorId: this.actorId,
111
+ sessionId: this.sessionId,
112
+ eventTimestamp: new Date(),
113
+ payload,
114
+ ...(clientToken !== undefined && { clientToken }),
115
+ ...(event.metadata && { metadata: event.metadata }),
116
+ });
117
+ await this.client.send(command);
118
+ }
119
+ /**
120
+ * Deterministic re-fire-stable token for an event covering the given sequence numbers, or `undefined`
121
+ * when any is missing (then we tolerate error-path duplicates; consolidation is the backstop). The
122
+ * token spans the event's `[firstSeq, lastSeq]`; a coordinator re-fire of the same batch reproduces
123
+ * the same range. Never time/random-based per call — the run-unique part is fixed for the sender's
124
+ * lifetime. Isolated here so it can switch to a stable per-message id when the framework exposes one.
125
+ */
126
+ tokenForSeqs(seqs) {
127
+ if (seqs.length === 0 || seqs.some((s) => s === undefined))
128
+ return undefined;
129
+ const nums = seqs;
130
+ return `${this.memoryId}-${this.actorId}-${this.runId}-${nums[0]}-${nums[nums.length - 1]}`;
131
+ }
132
+ }
133
+ /**
134
+ * AgentCore restricts `createEvent` metadata values to this character set. The constraint is enforced
135
+ * server-side (not in the AWS SDK types), so a value outside it fails at `createEvent` with an opaque
136
+ * `ValidationException`. We validate client-side and throw a clear, actionable error instead — mirroring
137
+ * the namespace placeholder check.
138
+ */
139
+ const METADATA_VALUE_PATTERN = /^[a-zA-Z0-9\s._:/=+@-]*$/;
140
+ /**
141
+ * Map a metadata bag to AgentCore's `{ stringValue }` event-metadata shape. Non-string values are
142
+ * JSON-stringified. Each resulting value must match {@link METADATA_VALUE_PATTERN}; a value that doesn't
143
+ * (e.g. a string with commas/punctuation, or a stringified array/object whose `[]{}",` are rejected)
144
+ * throws here with the offending key, rather than failing opaquely server-side at `createEvent`.
145
+ *
146
+ * Values that don't produce a usable scalar string are rejected up front: `undefined`/functions/symbols
147
+ * (`JSON.stringify` returns the JS value `undefined`, not a string) and non-finite numbers / `null`
148
+ * (which stringify to the literal `"null"`). Without this guard those slip past the charset test —
149
+ * `undefined` as `{ stringValue: undefined }`, `NaN` as the string `"null"` — and corrupt the event.
150
+ */
151
+ function toAgentCoreMetadata(metadata) {
152
+ const out = {};
153
+ for (const [key, value] of Object.entries(metadata)) {
154
+ if (value === undefined || value === null || (typeof value === 'number' && !Number.isFinite(value))) {
155
+ throw new Error(`AgentCoreEventSender: metadata value for key "${key}" is ${String(value)}, which has no valid ` +
156
+ `string representation. Provide a finite number, boolean, or a string (omit the key instead of ` +
157
+ `passing null/undefined).`);
158
+ }
159
+ const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
160
+ if (typeof stringValue !== 'string' || !METADATA_VALUE_PATTERN.test(stringValue)) {
161
+ throw new Error(`AgentCoreEventSender: metadata value for key "${key}" contains characters AgentCore rejects ` +
162
+ `(allowed: letters, digits, whitespace, and ._:/=+@-). Got ${JSON.stringify(stringValue)}. ` +
163
+ `Note: arrays/objects stringify to JSON containing []{}", which are not allowed — pass a ` +
164
+ `pre-encoded scalar string instead.`);
165
+ }
166
+ out[key] = { stringValue };
167
+ }
168
+ return out;
169
+ }
170
+ //# sourceMappingURL=sender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender.js","sourceRoot":"","sources":["../../../../../src/memory/integrations/strands/sender.ts"],"names":[],"mappings":"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"}