diff --git a/docs/memory.md b/docs/memory.md index 0f38513d2..cd429ce57 100644 --- a/docs/memory.md +++ b/docs/memory.md @@ -210,43 +210,6 @@ Each strategy can have optional configuration: | `namespaces` | No | **Deprecated alias for `namespaceTemplates`.** Accepted for backward compatibility. | | `reflectionNamespaces` | EPISODIC only | **Deprecated alias for `reflectionNamespaceTemplates`.** Accepted for backward compatibility. | -## Indexed Metadata Keys - -Indexed keys declare metadata fields on a memory that can be used to filter long-term memory records on retrieval. Up to -10 keys per memory. - -```bash -agentcore add memory \ - --name SupportMemory \ - --strategies SEMANTIC \ - --indexed-key priority:NUMBER \ - --indexed-key agent_type:STRING \ - --indexed-key tags:STRINGLIST -``` - -In `agentcore.json`: - -```json -{ - "name": "SupportMemory", - "strategies": [{ "type": "SEMANTIC" }], - "indexedKeys": [ - { "key": "priority", "type": "NUMBER" }, - { "key": "agent_type", "type": "STRING" }, - { "key": "tags", "type": "STRINGLIST" } - ] -} -``` - -| Type | Description | -| ------------ | --------------------- | -| `STRING` | Single string value | -| `STRINGLIST` | List of string values | -| `NUMBER` | Numeric value | - -Indexed keys require at least one long-term memory strategy. They can only be added to an existing memory — once -declared, an indexed key cannot be removed. - ## Event Expiry Memory events expire after a configurable duration (7-365 days, default 30): diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index df58d345c..4f01163bf 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -15,7 +15,7 @@ "@aws-sdk/client-bedrock": "^3.1012.0", "@aws-sdk/client-bedrock-agent": "^3.1012.0", "@aws-sdk/client-bedrock-agentcore": "^3.1020.0", - "@aws-sdk/client-bedrock-agentcore-control": "^3.1048.0", + "@aws-sdk/client-bedrock-agentcore-control": "^3.1039.0", "@aws-sdk/client-bedrock-runtime": "^3.893.0", "@aws-sdk/client-cloudformation": "^3.893.0", "@aws-sdk/client-cloudwatch-logs": "^3.893.0", @@ -930,20 +930,50 @@ } }, "node_modules/@aws-sdk/client-bedrock-agentcore-control": { - "version": "3.1048.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agentcore-control/-/client-bedrock-agentcore-control-3.1048.0.tgz", - "integrity": "sha512-l8ghHdi/re43kWU+Zsz/I0i2vJIoybTfkMverrViIe2f7y7nYIh+ULdMTCaJeRUFf6WjqM4CC8iDJ2Weml7EqQ==", + "version": "3.1039.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agentcore-control/-/client-bedrock-agentcore-control-3.1039.0.tgz", + "integrity": "sha512-YoJ1rYHikWbsBuTyjADxtYzD+PXmyR2X6NVWkX4AqUtZT1YJC1HW+BsFABlXfItsEOjss3kpsjQHnlMbiCBtig==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/credential-provider-node": "^3.972.38", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.37", + "@aws-sdk/region-config-resolver": "^3.972.13", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.23", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.17", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.32", + "@smithy/middleware-retry": "^4.5.7", + "@smithy/middleware-serde": "^4.2.20", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-body-length-node": "^4.2.3", + "@smithy/util-defaults-mode-browser": "^4.3.49", + "@smithy/util-defaults-mode-node": "^4.2.54", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/util-utf8": "^4.2.2", + "@smithy/util-waiter": "^4.3.0", "tslib": "^2.6.2" }, "engines": { @@ -2132,18 +2162,24 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.974.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.11.tgz", - "integrity": "sha512-QpnINq5FZH6EOaDEkmHdT7eUunbvD27pDNQypaWjFyYz7Zl1q3UCMQErBZxpmfGfI7MvI2TlK8KTkgNpv8b1ug==", + "version": "3.974.7", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.7.tgz", + "integrity": "sha512-YhRC90ofz5oolTJZlA8voU/oUrCB2azi8Usx51k8hhB5LpWbYQMMXKUqSqkoL0Cru+RQJgWTHpAfEDDIwfUhJw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", - "@aws-sdk/xml-builder": "^3.972.24", - "@aws/lambda-invoke-store": "^0.2.2", - "@smithy/core": "^3.24.2", - "@smithy/signature-v4": "^5.4.2", + "@aws-sdk/xml-builder": "^3.972.22", + "@smithy/core": "^3.23.17", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", - "bowser": "^2.11.0", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, "engines": { @@ -2214,14 +2250,14 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.37.tgz", - "integrity": "sha512-/jpPvEh6f7ntmIzf7dNxoNX6Q8vt8UpesCjbW6mFfk4V1NW6bIy9qxcQ6WbA8As5yQhsZOe+xeNd4xHX8kdY2Q==", + "version": "3.972.33", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.33.tgz", + "integrity": "sha512-bJV7eViSJV6GSuuN+VIdNVPdwPsNSf75BiC2v5alPrjR/OCcqgKwSZInKbDFz9mNeizldsyf67jt6YSIiv53Cw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", + "@aws-sdk/core": "^3.974.7", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", + "@smithy/property-provider": "^4.2.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2230,17 +2266,20 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.39.tgz", - "integrity": "sha512-pIgTpisWyWg7X1bUbzSjuUYosYTD0Ghz2M0hkSTmb3a6i3qV3uU+NYJPI/E2XSC0HcsZh5rsLPzeXrkb2DS0Cg==", + "version": "3.972.35", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.35.tgz", + "integrity": "sha512-x/BQGEIdq0oI+4WxLjKmnQvT7CnF9r8ezdGt7wXwxb7ckHXQz0Zmgxt8v3Ne0JaT3R5YefmuybHX6E8EnsDXyA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", + "@aws-sdk/core": "^3.974.7", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.25", "tslib": "^2.6.2" }, "engines": { @@ -2248,22 +2287,23 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.41", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.41.tgz", - "integrity": "sha512-u2tyjaxJJzW8UtW4SM1ZcPMDwO6y+kV+llvou+Adts0FAKyzes5jG4izQN+KX3yE8ZROpS5y1LJ//xL2iSf76w==", + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.37.tgz", + "integrity": "sha512-eUTpmWfd/BKsq9medhCRcu+GRAhFP2Zrn7/2jKDHHOOjCkhrMoTp/t4cEthqFoG7gE0VGp5wUxrXTdvBCmSmJg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/credential-provider-env": "^3.972.37", - "@aws-sdk/credential-provider-http": "^3.972.39", - "@aws-sdk/credential-provider-login": "^3.972.41", - "@aws-sdk/credential-provider-process": "^3.972.37", - "@aws-sdk/credential-provider-sso": "^3.972.41", - "@aws-sdk/credential-provider-web-identity": "^3.972.41", - "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/credential-provider-env": "^3.972.33", + "@aws-sdk/credential-provider-http": "^3.972.35", + "@aws-sdk/credential-provider-login": "^3.972.37", + "@aws-sdk/credential-provider-process": "^3.972.33", + "@aws-sdk/credential-provider-sso": "^3.972.37", + "@aws-sdk/credential-provider-web-identity": "^3.972.37", + "@aws-sdk/nested-clients": "^3.997.5", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2272,15 +2312,17 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.41", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.41.tgz", - "integrity": "sha512-0LBitxXiAiaE5nlFPfpNIww/8FRY/I7WIndWsc9GmNFOM7cE1wNpVNQEGEk9Outg5l8xl+3vybxFyUy4l9q/LQ==", + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.37.tgz", + "integrity": "sha512-Ty68y8ISSC+g5Q3D0K8uAaoINwvfaOslnNpsF/LgVUxyosYXHawcK2yV4HLXDVugiTTYLQfJfcw0ce5meAGkKw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/nested-clients": "^3.997.5", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2289,20 +2331,21 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.42", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.42.tgz", - "integrity": "sha512-D4oon2zbqqsWOJUM99Gm3/ZyJ0IJvTXVN3PyloGb3kQEyI36fjCZheZj422lAgTWWd6TSHgiImLt3RIaLdv3dQ==", + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.38.tgz", + "integrity": "sha512-BQ9XYnBDVxR2HuV5huXYQYF/PZMTsY+EnwfGnCU2cA8Zw63XpkOtPY8WqiMIZMQCrKPQQEiFURS/o9CIolRLqg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.37", - "@aws-sdk/credential-provider-http": "^3.972.39", - "@aws-sdk/credential-provider-ini": "^3.972.41", - "@aws-sdk/credential-provider-process": "^3.972.37", - "@aws-sdk/credential-provider-sso": "^3.972.41", - "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/credential-provider-env": "^3.972.33", + "@aws-sdk/credential-provider-http": "^3.972.35", + "@aws-sdk/credential-provider-ini": "^3.972.37", + "@aws-sdk/credential-provider-process": "^3.972.33", + "@aws-sdk/credential-provider-sso": "^3.972.37", + "@aws-sdk/credential-provider-web-identity": "^3.972.37", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2311,14 +2354,15 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.37.tgz", - "integrity": "sha512-7nVaHBUaWIddASYfVaA9O4D5ZVjewU3sCol9WqZPGfW0nR+0WqE0xHZnD/U2L33PlOB8KNXGKZ6wOES/QijKzg==", + "version": "3.972.33", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.33.tgz", + "integrity": "sha512-yfjGksI9WQbdMObb0VeLXqzTLI+a0qXLJT9gCDiv0+X/xjPpI3mTz6a5FibrhpuEKIe0gSgvs3MaoFZy5cx4WA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", + "@aws-sdk/core": "^3.974.7", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2327,16 +2371,17 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.41", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.41.tgz", - "integrity": "sha512-IOWAWEHe5LkjSKkkUUX9ciV6Y1scHTsnfEkdt5yyC4Slrc7AGbkLPrpntjqh18ksJAMOaVhoBsO8p2WyTcY2wQ==", + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.37.tgz", + "integrity": "sha512-fpwE+20ntpp3i9Xb9vUuQfXLDKYHH+5I2V+ZG96SX1nBzrruhy10RXDgmN7t1etOz3c55stlA3TeQASUA451NQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/nested-clients": "^3.997.9", - "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/nested-clients": "^3.997.5", + "@aws-sdk/token-providers": "3.1039.0", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2345,15 +2390,16 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.41", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.41.tgz", - "integrity": "sha512-mbACk9Yypa8nm4iGZLs0PofOXEcTDOUw6wDnsPXNDNSd2WNXs1tSo+6nc/fh0jLYdfVZThhBL98PHW4aXFsG5A==", + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.37.tgz", + "integrity": "sha512-aryawqyebf+3WhAFNHfF62rekFpYtVcVN7dQ89qnAWsa4n5hJst8qBG6gXC24WHtW7Nnhkf9ScYnjwo0Brn3bw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/nested-clients": "^3.997.5", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2694,20 +2740,49 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.9.tgz", - "integrity": "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ==", + "version": "3.997.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.5.tgz", + "integrity": "sha512-jGFr6DxtcMTmzOkG/a0jCZYv4BBDmeNYVeO+/memSoDkYCJu4Y58xviYmzwJfYyIVSts+X/BVjJm1uGBnwHEMg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/signature-v4-multi-region": "^3.996.27", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.37", + "@aws-sdk/region-config-resolver": "^3.972.13", + "@aws-sdk/signature-v4-multi-region": "^3.996.24", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.23", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.17", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.32", + "@smithy/middleware-retry": "^4.5.7", + "@smithy/middleware-serde": "^4.2.20", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-body-length-node": "^4.2.3", + "@smithy/util-defaults-mode-browser": "^4.3.49", + "@smithy/util-defaults-mode-node": "^4.2.54", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, "engines": { @@ -2731,14 +2806,15 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.27", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.27.tgz", - "integrity": "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg==", + "version": "3.996.24", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.24.tgz", + "integrity": "sha512-amP7tLikppN940wbBFISYqiuzVmpzMS9U3mcgtmVLjX4fdWI/SNCvrXv6ZxfVzTT4cT0rPKOLhFah2xLwzREWw==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/middleware-sdk-s3": "^3.972.36", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/signature-v4": "^5.4.2", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -2747,15 +2823,16 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.1048.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", - "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "version": "3.1039.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1039.0.tgz", + "integrity": "sha512-NMSFL2HwkAOoCeLCQiqoOq5pT3vVbSjww2QZTuYgYknVwhhv125PSDzZIcL5EYnlxuPWjEOdauZK+FspkZDVdw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/core": "^3.974.7", + "@aws-sdk/nested-clients": "^3.997.5", "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, @@ -4965,25 +5042,20 @@ } }, "node_modules/@smithy/core": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.3.tgz", - "integrity": "sha512-Ep/7tPamGY8mgESE3LyLKtxJyy6U52WWAqr/3wial47Sj4u3PiIF73AOGI27UyLy9duTkhZbgzodOfLV4TduZg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/core/node_modules/@smithy/types": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", - "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "version": "3.23.17", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.17.tgz", + "integrity": "sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ==", "license": "Apache-2.0", "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.25", + "@smithy/util-utf8": "^4.2.2", + "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" }, "engines": { @@ -4991,25 +5063,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.3.tgz", - "integrity": "sha512-I2Bti0DKFo2IJyN28ijCsx51BAumEYR4/1yZ1FXyBygy9MqbnMqCev4JPth/MbpRfBSRAX35hITSnAdJRo1u5w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/types": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", - "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.14.tgz", + "integrity": "sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==", "license": "Apache-2.0", "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", "tslib": "^2.6.2" }, "engines": { @@ -5087,25 +5149,15 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.3.tgz", - "integrity": "sha512-F+DRf8IJazRJgYog2A/yJK7eYVc0rqTlRzO+5ZxjJd4WkZoKz0IJRncf7G6t1pdVT3kryJcwuTFhN1c5m6N47A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/types": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", - "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz", + "integrity": "sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==", "license": "Apache-2.0", "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" }, "engines": { @@ -5293,25 +5345,14 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", - "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler/node_modules/@smithy/types": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", - "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.6.1.tgz", + "integrity": "sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg==", "license": "Apache-2.0", "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -5397,25 +5438,18 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.3.tgz", - "integrity": "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4/node_modules/@smithy/types": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", - "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.14.tgz", + "integrity": "sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==", "license": "Apache-2.0", "dependencies": { + "@smithy/is-array-buffer": "^4.2.2", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-uri-escape": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, "engines": { diff --git a/package.json b/package.json index 3491e443f..eb4661183 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@aws-sdk/client-bedrock": "^3.1012.0", "@aws-sdk/client-bedrock-agent": "^3.1012.0", "@aws-sdk/client-bedrock-agentcore": "^3.1020.0", - "@aws-sdk/client-bedrock-agentcore-control": "^3.1048.0", + "@aws-sdk/client-bedrock-agentcore-control": "^3.1039.0", "@aws-sdk/client-bedrock-runtime": "^3.893.0", "@aws-sdk/client-cloudformation": "^3.893.0", "@aws-sdk/client-cloudwatch-logs": "^3.893.0", diff --git a/src/cli/aws/agentcore-control.ts b/src/cli/aws/agentcore-control.ts index 54e89eb3e..159939b17 100644 --- a/src/cli/aws/agentcore-control.ts +++ b/src/cli/aws/agentcore-control.ts @@ -371,7 +371,6 @@ export interface MemoryDetail { namespaceTemplates?: string[]; reflectionNamespaceTemplates?: string[]; }[]; - indexedKeys?: { key: string; type: string }[]; tags?: Record; encryptionKeyArn?: string; executionRoleArn?: string; @@ -409,14 +408,6 @@ export async function getMemoryDetail(options: GetMemoryOptions): Promise { - if (!k.key || !k.type) { - console.warn(`Warning: Skipping malformed indexed key from API response: ${JSON.stringify(k)}`); - return []; - } - return [{ key: k.key, type: k.type }]; - }); - return { memoryId: memory.id, memoryArn: memory.arn, @@ -427,7 +418,6 @@ export async function getMemoryDetail(options: GetMemoryOptions): Promise 0 && { indexedKeys }), strategies: (memory.strategies ?? []).map(s => { if (!s.type) { throw new Error(`Memory ${options.memoryId} has a strategy with missing required field: type`); diff --git a/src/cli/aws/policy-generation.ts b/src/cli/aws/policy-generation.ts index fa75548c6..da58edf81 100644 --- a/src/cli/aws/policy-generation.ts +++ b/src/cli/aws/policy-generation.ts @@ -6,7 +6,7 @@ import { StartPolicyGenerationCommand, waitUntilPolicyGenerationCompleted, } from '@aws-sdk/client-bedrock-agentcore-control'; -import { WaiterState } from '@smithy/core/client'; +import { WaiterState } from '@smithy/util-waiter'; export interface StartPolicyGenerationOptions { policyEngineId: string; diff --git a/src/cli/commands/add/__tests__/validate.test.ts b/src/cli/commands/add/__tests__/validate.test.ts index 070801f40..fdefc6417 100644 --- a/src/cli/commands/add/__tests__/validate.test.ts +++ b/src/cli/commands/add/__tests__/validate.test.ts @@ -1126,118 +1126,6 @@ describe('validate', () => { expect(result.valid).toBe(false); expect(result.error).toContain('does not match the expected schema'); }); - - // Indexed keys: requires LTM strategy - it('rejects --indexed-key without any LTM strategy', () => { - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: undefined, - indexedKey: ['priority:NUMBER'], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('requires at least one long-term memory strategy'); - }); - - it('accepts --indexed-key with an LTM strategy', () => { - expect( - validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: ['priority:NUMBER'], - }) - ).toEqual({ valid: true }); - }); - - it('rejects more than 10 indexed keys', () => { - const eleven = Array.from({ length: 11 }, (_, i) => `k${i}:STRING`); - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: eleven, - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('Maximum 10 indexed keys'); - }); - - it('accepts exactly 10 indexed keys (boundary)', () => { - const ten = Array.from({ length: 10 }, (_, i) => `k${i}:STRING`); - expect(validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'SEMANTIC', indexedKey: ten })).toEqual({ - valid: true, - }); - }); - - it('rejects an empty key (":STRING")', () => { - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: [':STRING'], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('Key name cannot be empty'); - }); - - it('rejects a key longer than 128 characters', () => { - const longKey = 'a'.repeat(129); - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: [`${longKey}:STRING`], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('exceeds maximum length'); - }); - - it('rejects an invalid type token', () => { - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: ['priority:INTEGER'], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('Invalid type'); - }); - - it('rejects duplicate keys', () => { - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: ['priority:NUMBER', 'priority:STRING'], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('Duplicate indexed key'); - }); - - it('rejects whitespace-only key', () => { - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: [' :STRING'], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('whitespace'); - }); - - it('rejects malformed entry without colon', () => { - const result = validateAddMemoryOptions({ - ...validMemoryOptions, - strategies: 'SEMANTIC', - indexedKey: ['priority'], - }); - expect(result.valid).toBe(false); - expect(result.error).toContain('Expected key:TYPE'); - }); - - it.each([ - ['user.email:STRING'], - ['tag/v2:STRINGLIST'], - ['kebab-case:STRING'], - ['x-custom:STRING'], - ['has:colons:in:key:NUMBER'], - ])('accepts punctuation-rich key %s', raw => { - expect(validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'SEMANTIC', indexedKey: [raw] })).toEqual({ - valid: true, - }); - }); }); describe('validateAddCredentialOptions', () => { diff --git a/src/cli/commands/add/types.ts b/src/cli/commands/add/types.ts index a6555e970..c1dd6641f 100644 --- a/src/cli/commands/add/types.ts +++ b/src/cli/commands/add/types.ts @@ -96,7 +96,6 @@ export interface AddMemoryOptions { dataStreamArn?: string; contentLevel?: string; streamDeliveryResources?: string; - indexedKey?: string[]; json?: boolean; } diff --git a/src/cli/commands/add/validate.ts b/src/cli/commands/add/validate.ts index 1429f21cd..b39f89454 100644 --- a/src/cli/commands/add/validate.ts +++ b/src/cli/commands/add/validate.ts @@ -19,7 +19,6 @@ import { } from '../../../schema'; import { ARN_VALIDATION_MESSAGE, isValidArn } from '../shared/arn-utils'; import { validateHeaderAllowlist } from '../shared/header-utils'; -import { MAX_INDEXED_KEYS, parseIndexedKeyArg } from '../shared/indexed-key-parser'; import { parseAndValidateLifecycleOptions } from '../shared/lifecycle-utils'; import { validateVpcOptions } from '../shared/vpc-utils'; import { validateJwtAuthorizerOptions } from './auth-options'; @@ -727,37 +726,6 @@ export function validateAddMemoryOptions(options: AddMemoryOptions): ValidationR } } - if (options.indexedKey && options.indexedKey.length > 0) { - const ltmStrategies = (options.strategies ?? '') - .split(',') - .map(s => s.trim().toUpperCase()) - .filter(Boolean); - if (ltmStrategies.length === 0) { - return { - valid: false, - error: - '--indexed-key requires at least one long-term memory strategy (--strategies). Indexed keys filter long-term memory records on retrieval.', - }; - } - - if (options.indexedKey.length > MAX_INDEXED_KEYS) { - return { valid: false, error: `Maximum ${MAX_INDEXED_KEYS} indexed keys allowed` }; - } - - const seenKeys = new Set(); - for (const raw of options.indexedKey) { - const result = parseIndexedKeyArg(raw); - if (!result.ok) { - return { valid: false, error: result.error }; - } - const { key } = result.value; - if (seenKeys.has(key)) { - return { valid: false, error: `Duplicate indexed key: "${key}"` }; - } - seenKeys.add(key); - } - } - if (options.streamDeliveryResources && (options.dataStreamArn || options.contentLevel || options.deliveryType)) { return { valid: false, diff --git a/src/cli/commands/import/import-memory.ts b/src/cli/commands/import/import-memory.ts index e9f7dc203..73aaf20a6 100644 --- a/src/cli/commands/import/import-memory.ts +++ b/src/cli/commands/import/import-memory.ts @@ -1,5 +1,4 @@ import type { Memory } from '../../../schema'; -import { IndexedKeyTypeSchema } from '../../../schema'; import type { MemoryDetail, MemorySummary } from '../../aws/agentcore-control'; import { getMemoryDetail, listAllMemories } from '../../aws/agentcore-control'; import { withCommandRunTelemetry } from '../../telemetry/cli-command-run.js'; @@ -57,26 +56,10 @@ function toMemorySpec(memory: MemoryDetail, localName: string): Memory { }; }); - // Validate each indexed key's type against our enum. Drop - // entries whose type is not one we recognize with a warning - const indexedKeys: Memory['indexedKeys'] = memory.indexedKeys - ?.flatMap(k => { - const parsedType = IndexedKeyTypeSchema.safeParse(k.type); - if (!parsedType.success) { - console.warn( - `${ANSI.yellow}[warn]${ANSI.reset} Skipping indexed key "${k.key}" with unrecognised type "${k.type}".` - ); - return []; - } - return [{ key: k.key, type: parsedType.data }]; - }) - .filter(Boolean); - return { name: localName, eventExpiryDuration: Math.max(3, Math.min(365, memory.eventExpiryDuration)), strategies, - ...(indexedKeys && indexedKeys.length > 0 && { indexedKeys }), ...(memory.tags && Object.keys(memory.tags).length > 0 && { tags: memory.tags }), ...(memory.encryptionKeyArn && { encryptionKeyArn: memory.encryptionKeyArn }), ...(memory.executionRoleArn && { executionRoleArn: memory.executionRoleArn }), diff --git a/src/cli/commands/shared/indexed-key-parser.ts b/src/cli/commands/shared/indexed-key-parser.ts deleted file mode 100644 index 4ddf19184..000000000 --- a/src/cli/commands/shared/indexed-key-parser.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { IndexedKey, IndexedKeyType } from '../../../schema'; -import { - INDEXED_KEY_NAME_PATTERN, - INDEXED_KEY_NAME_PATTERN_MESSAGE, - IndexedKeyTypeSchema, - MAX_INDEXED_KEYS, - MAX_INDEXED_KEY_NAME_LENGTH, -} from '../../../schema'; - -export { INDEXED_KEY_NAME_PATTERN, MAX_INDEXED_KEYS }; -export const MAX_KEY_NAME_LENGTH = MAX_INDEXED_KEY_NAME_LENGTH; -export const VALID_INDEXED_KEY_TYPES: readonly IndexedKeyType[] = ['STRING', 'STRINGLIST', 'NUMBER']; - -/** - * Validate an indexed key name. Returns `true` when valid, or an error message. - * Shared between the schema-side regex (via constants) and TUI inline validation. - */ -export function validateIndexedKeyName(value: string, existingNames: readonly string[] = []): true | string { - if (!INDEXED_KEY_NAME_PATTERN.test(value)) { - return INDEXED_KEY_NAME_PATTERN_MESSAGE; - } - if (value.trim().length === 0) { - return 'Key cannot be only whitespace'; - } - if (value.length > MAX_INDEXED_KEY_NAME_LENGTH) { - return `Maximum ${MAX_INDEXED_KEY_NAME_LENGTH} characters`; - } - if (existingNames.includes(value)) { - return 'Key already defined'; - } - return true; -} - -export interface IndexedKeyParseError { - ok: false; - error: string; -} - -export interface IndexedKeyParseSuccess { - ok: true; - value: IndexedKey; -} - -export type IndexedKeyParseResult = IndexedKeyParseError | IndexedKeyParseSuccess; - -/** - * Parse a single `key:TYPE` argument into a validated IndexedKey. - * - * Splits on the *last* `:` so that key names may contain `:` (the AgentCore - * service accepts `:` in indexed key names; type tokens never do). - */ -export function parseIndexedKeyArg(raw: string): IndexedKeyParseResult { - const colonIdx = raw.lastIndexOf(':'); - if (colonIdx === -1) { - return { ok: false, error: `Invalid indexed key format: "${raw}". Expected key:TYPE (e.g. priority:NUMBER)` }; - } - const key = raw.slice(0, colonIdx); - const typeToken = raw.slice(colonIdx + 1).toUpperCase(); - - if (!key) { - return { ok: false, error: `Invalid indexed key format: "${raw}". Key name cannot be empty` }; - } - if (key.length > MAX_KEY_NAME_LENGTH) { - return { - ok: false, - error: `Indexed key name "${key}" exceeds maximum length of ${MAX_KEY_NAME_LENGTH} characters`, - }; - } - if (!INDEXED_KEY_NAME_PATTERN.test(key)) { - return { - ok: false, - error: `Invalid indexed key name "${key}". Must contain only alphanumeric characters, whitespace, or the symbols . _ : / = + @ -`, - }; - } - if (key.trim().length === 0) { - return { ok: false, error: `Invalid indexed key name "${key}". Key cannot be only whitespace` }; - } - const parsedType = IndexedKeyTypeSchema.safeParse(typeToken); - if (!parsedType.success) { - return { - ok: false, - error: `Invalid type "${typeToken}" for indexed key "${key}". Must be one of: ${VALID_INDEXED_KEY_TYPES.join(', ')}`, - }; - } - return { ok: true, value: { key, type: parsedType.data } }; -} diff --git a/src/cli/primitives/MemoryPrimitive.tsx b/src/cli/primitives/MemoryPrimitive.tsx index 2fa877e23..6f02941bc 100644 --- a/src/cli/primitives/MemoryPrimitive.tsx +++ b/src/cli/primitives/MemoryPrimitive.tsx @@ -1,7 +1,6 @@ import { ResourceNotFoundError, findConfigRoot, serializeResult, toError } from '../../lib'; import type { Result } from '../../lib/result'; import type { - IndexedKey, Memory, MemoryStrategy, MemoryStrategyType, @@ -17,7 +16,6 @@ import { StreamDeliveryResourcesSchema, } from '../../schema'; import { DEFAULT_DELIVERY_TYPE, validateAddMemoryOptions } from '../commands/add/validate'; -import { parseIndexedKeyArg } from '../commands/shared/indexed-key-parser'; import { getErrorMessage } from '../errors'; import type { RemovalPreview, SchemaChange } from '../operations/remove/types'; import { runCliCommand } from '../telemetry/cli-command-run.js'; @@ -41,8 +39,6 @@ export interface AddMemoryOptions { contentLevel?: string; // Raw JSON for advanced/multi-target configurations. Takes precedence over flat flags. streamDeliveryResources?: string; - // Repeatable flag values as "key:TYPE" strings - indexedKey?: string[]; } /** @@ -79,14 +75,11 @@ export class MemoryPrimitive extends BasePrimitive', 'Stream delivery config as JSON string (advanced, overrides flat flags) [non-interactive]' ) - .option( - '--indexed-key ', - 'Indexed metadata key as key:TYPE (repeatable, max 10). TYPE is STRING, STRINGLIST, or NUMBER [non-interactive]', - (val: string, acc: string[]) => [...acc, val], - [] as string[] - ) .option('--json', 'Output as JSON [non-interactive]') .action( async (cliOptions: { @@ -195,7 +182,6 @@ export class MemoryPrimitive extends BasePrimitive { if (!findConfigRoot()) { @@ -207,9 +193,6 @@ export class MemoryPrimitive extends BasePrimitive { const expiry = cliOptions.expiry ? parseInt(cliOptions.expiry, 10) : undefined; - const indexedKey = - cliOptions.indexedKey && cliOptions.indexedKey.length > 0 ? cliOptions.indexedKey : undefined; - const validation = validateAddMemoryOptions({ name: cliOptions.name, strategies: cliOptions.strategies, @@ -218,7 +201,6 @@ export class MemoryPrimitive extends BasePrimitive s.trim().toUpperCase()) .filter(Boolean); - const indexedKeyCount = cliOptions.indexedKey?.length ?? 0; return { strategy_count: strategyList.length, strategy_semantic: strategyList.includes('SEMANTIC'), strategy_summarization: strategyList.includes('SUMMARIZATION'), strategy_user_preference: strategyList.includes('USER_PREFERENCE'), strategy_episodic: strategyList.includes('EPISODIC'), - indexed_key_count: indexedKeyCount, - has_indexed_keys: indexedKeyCount > 0, }; }); } else { @@ -304,7 +282,6 @@ export class MemoryPrimitive extends BasePrimitive { const project = await this.readProjectSpec(); @@ -324,7 +301,6 @@ export class MemoryPrimitive extends BasePrimitive 0 && { indexedKeys: config.indexedKeys }), ...(config.streamDeliveryResources && { streamDeliveryResources: config.streamDeliveryResources }), }; @@ -365,14 +341,4 @@ export class MemoryPrimitive extends BasePrimitive { - const result = parseIndexedKeyArg(raw); - if (!result.ok) { - throw new Error(result.error); - } - return result.value; - }); - } } diff --git a/src/cli/telemetry/schemas/command-run.ts b/src/cli/telemetry/schemas/command-run.ts index ce358dbf2..47e339b1a 100644 --- a/src/cli/telemetry/schemas/command-run.ts +++ b/src/cli/telemetry/schemas/command-run.ts @@ -61,8 +61,6 @@ const AddMemoryAttrs = safeSchema({ strategy_summarization: z.boolean(), strategy_user_preference: z.boolean(), strategy_episodic: z.boolean(), - indexed_key_count: Count, - has_indexed_keys: z.boolean(), }); const AddCredentialAttrs = safeSchema({ credential_type: CredentialType }); diff --git a/src/cli/tui/hooks/useCreateMemory.ts b/src/cli/tui/hooks/useCreateMemory.ts index e452c27ed..cf891c4f9 100644 --- a/src/cli/tui/hooks/useCreateMemory.ts +++ b/src/cli/tui/hooks/useCreateMemory.ts @@ -9,7 +9,6 @@ interface CreateMemoryConfig { name: string; eventExpiryDuration: number; strategies: { type: string }[]; - indexedKeys?: { key: string; type: string }[]; streaming?: { dataStreamArn: string; contentLevel: string }; } @@ -27,9 +26,6 @@ export function useCreateMemory() { try { const strategiesStr = config.strategies.map(s => s.type).join(','); const strategyList = strategiesStr ? strategiesStr.split(',').map(s => s.trim().toUpperCase()) : []; - const indexedKey = config.indexedKeys?.map(k => `${k.key}:${k.type}`); - const indexedKeyCount = config.indexedKeys?.length ?? 0; - const addResult = await withCommandRunTelemetry( 'add.memory', { @@ -38,8 +34,6 @@ export function useCreateMemory() { strategy_summarization: strategyList.includes('SUMMARIZATION'), strategy_user_preference: strategyList.includes('USER_PREFERENCE'), strategy_episodic: strategyList.includes('EPISODIC'), - indexed_key_count: indexedKeyCount, - has_indexed_keys: indexedKeyCount > 0, }, () => memoryPrimitive.add({ @@ -48,7 +42,6 @@ export function useCreateMemory() { strategies: strategiesStr || undefined, dataStreamArn: config.streaming?.dataStreamArn, contentLevel: config.streaming?.contentLevel, - indexedKey, }) ); if (!addResult.success) { diff --git a/src/cli/tui/screens/memory/AddMemoryScreen.tsx b/src/cli/tui/screens/memory/AddMemoryScreen.tsx index 1006d07cd..da6cb3bdb 100644 --- a/src/cli/tui/screens/memory/AddMemoryScreen.tsx +++ b/src/cli/tui/screens/memory/AddMemoryScreen.tsx @@ -1,7 +1,6 @@ -import type { IndexedKeyType, MemoryStrategyType } from '../../../../schema'; +import type { MemoryStrategyType } from '../../../../schema'; import { AgentNameSchema, StreamContentLevelSchema } from '../../../../schema'; import { ARN_VALIDATION_MESSAGE, isValidArn } from '../../../commands/shared/arn-utils'; -import { validateIndexedKeyName } from '../../../commands/shared/indexed-key-parser'; import { ConfirmReview, Panel, @@ -15,17 +14,10 @@ import type { SelectableItem } from '../../components'; import { HELP_TEXT } from '../../constants'; import { useListNavigation, useMultiSelectNavigation } from '../../hooks'; import { generateUniqueName } from '../../utils'; -import type { AddMemoryConfig, AddMemoryIndexedKeyConfig } from './types'; -import { - CONTENT_LEVEL_OPTIONS, - EVENT_EXPIRY_OPTIONS, - INDEXED_KEY_TYPE_OPTIONS, - MEMORY_STEP_LABELS, - MEMORY_STRATEGY_OPTIONS, -} from './types'; +import type { AddMemoryConfig } from './types'; +import { CONTENT_LEVEL_OPTIONS, EVENT_EXPIRY_OPTIONS, MEMORY_STEP_LABELS, MEMORY_STRATEGY_OPTIONS } from './types'; import { useAddMemoryWizard } from './useAddMemoryWizard'; -import { Box, Text } from 'ink'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; interface AddMemoryScreenProps { onComplete: (config: AddMemoryConfig) => void; @@ -38,16 +30,9 @@ const STREAMING_OPTIONS: SelectableItem[] = [ { id: 'yes', title: 'Yes', description: 'Stream memory record events to a delivery target (e.g. Kinesis)' }, ]; -type IndexedKeysSubStep = 'prompt' | 'keyName' | 'keyType' | 'addAnother'; - export function AddMemoryScreen({ onComplete, onExit, existingMemoryNames }: AddMemoryScreenProps) { const wizard = useAddMemoryWizard(); - // Indexed keys sub-flow state - const [indexedKeysSubStep, setIndexedKeysSubStep] = useState('prompt'); - const [pendingKeyName, setPendingKeyName] = useState(''); - const [collectedKeys, setCollectedKeys] = useState([]); - const strategyItems: SelectableItem[] = useMemo( () => MEMORY_STRATEGY_OPTIONS.map(opt => ({ id: opt.id, title: opt.title, description: opt.description })), [] @@ -63,31 +48,9 @@ export function AddMemoryScreen({ onComplete, onExit, existingMemoryNames }: Add [] ); - const indexedKeyTypeItems: SelectableItem[] = useMemo( - () => INDEXED_KEY_TYPE_OPTIONS.map(opt => ({ id: opt.id, title: opt.title, description: opt.description })), - [] - ); - const isNameStep = wizard.step === 'name'; const isExpiryStep = wizard.step === 'expiry'; const isStrategiesStep = wizard.step === 'strategies'; - const isIndexedKeysStep = wizard.step === 'indexedKeys'; - - /* eslint-disable react-hooks/set-state-in-effect */ - useEffect(() => { - if ( - isIndexedKeysStep && - indexedKeysSubStep === 'prompt' && - collectedKeys.length === 0 && - wizard.config.indexedKeys && - wizard.config.indexedKeys.length > 0 - ) { - setCollectedKeys(wizard.config.indexedKeys); - setIndexedKeysSubStep('addAnother'); - } - }, [isIndexedKeysStep, indexedKeysSubStep, collectedKeys.length, wizard.config.indexedKeys]); - /* eslint-enable react-hooks/set-state-in-effect */ - const isStreamingStep = wizard.step === 'streaming'; const isStreamArnStep = wizard.step === 'streamArn'; const isContentLevelStep = wizard.step === 'contentLevel'; @@ -109,89 +72,6 @@ export function AddMemoryScreen({ onComplete, onExit, existingMemoryNames }: Add requireSelection: false, }); - // Indexed keys sub-flow: initial prompt (yes/no) - const INDEXED_KEYS_PROMPT_OPTIONS: SelectableItem[] = useMemo( - () => [ - { id: 'no', title: 'No', description: 'Skip indexed keys' }, - { id: 'yes', title: 'Yes', description: 'Define keys for metadata filtering on retrieval' }, - ], - [] - ); - - const ADD_ANOTHER_OPTIONS: SelectableItem[] = useMemo( - () => [ - { id: 'no', title: 'No', description: 'Done adding keys' }, - { id: 'yes', title: 'Yes', description: `Add another key (${collectedKeys.length}/10 defined)` }, - { id: 'clear', title: 'Clear keys', description: 'Discard all keys and start over' }, - ], - [collectedKeys.length] - ); - - const indexedKeysPromptNav = useListNavigation({ - items: INDEXED_KEYS_PROMPT_OPTIONS, - onSelect: item => { - if (item.id === 'yes') { - setIndexedKeysSubStep('keyName'); - } else { - wizard.setIndexedKeys([]); - } - }, - onExit: () => wizard.goBack(), - isActive: isIndexedKeysStep && indexedKeysSubStep === 'prompt', - }); - - const handleKeyNameSubmit = useCallback((name: string) => { - setPendingKeyName(name); - setIndexedKeysSubStep('keyType'); - }, []); - - const indexedKeyTypeNav = useListNavigation({ - items: indexedKeyTypeItems, - onSelect: item => { - const newKey: AddMemoryIndexedKeyConfig = { key: pendingKeyName, type: item.id as IndexedKeyType }; - const updated = [...collectedKeys, newKey]; - setCollectedKeys(updated); - setPendingKeyName(''); - if (updated.length >= 10) { - wizard.setIndexedKeys(updated); - setCollectedKeys([]); - setIndexedKeysSubStep('prompt'); - } else { - setIndexedKeysSubStep('addAnother'); - } - }, - onExit: () => setIndexedKeysSubStep('keyName'), - isActive: isIndexedKeysStep && indexedKeysSubStep === 'keyType', - }); - - const addAnotherNav = useListNavigation({ - items: ADD_ANOTHER_OPTIONS, - onSelect: item => { - if (item.id === 'yes') { - setIndexedKeysSubStep('keyName'); - } else if (item.id === 'clear') { - // Discard everything and return to the initial Yes/No prompt as if - // entering the step for the first time. - setCollectedKeys([]); - wizard.clearIndexedKeys(); - setIndexedKeysSubStep('prompt'); - } else { - wizard.setIndexedKeys(collectedKeys); - setCollectedKeys([]); - setIndexedKeysSubStep('prompt'); - } - }, - onExit: () => { - const lastKey = collectedKeys[collectedKeys.length - 1]; - if (lastKey) { - setPendingKeyName(lastKey.key); - setCollectedKeys(collectedKeys.slice(0, -1)); - setIndexedKeysSubStep('keyType'); - } - }, - isActive: isIndexedKeysStep && indexedKeysSubStep === 'addAnother', - }); - const streamingNav = useListNavigation({ items: STREAMING_OPTIONS, onSelect: item => wizard.setStreamingEnabled(item.id === 'yes'), @@ -217,13 +97,9 @@ export function AddMemoryScreen({ onComplete, onExit, existingMemoryNames }: Add ? 'Space toggle · Enter confirm · Esc back' : isExpiryStep || isStreamingStep || isContentLevelStep ? HELP_TEXT.NAVIGATE_SELECT - : isIndexedKeysStep && (indexedKeysSubStep === 'prompt' || indexedKeysSubStep === 'addAnother') - ? HELP_TEXT.NAVIGATE_SELECT - : isIndexedKeysStep && indexedKeysSubStep === 'keyType' - ? HELP_TEXT.NAVIGATE_SELECT - : isConfirmStep - ? HELP_TEXT.CONFIRM_CANCEL - : HELP_TEXT.TEXT_INPUT; + : isConfirmStep + ? HELP_TEXT.CONFIRM_CANCEL + : HELP_TEXT.TEXT_INPUT; const headerContent = ; @@ -232,9 +108,6 @@ export function AddMemoryScreen({ onComplete, onExit, existingMemoryNames }: Add { label: 'Name', value: wizard.config.name }, { label: 'Event Expiry', value: `${wizard.config.eventExpiryDuration} days` }, { label: 'Strategies', value: wizard.config.strategies.map(s => s.type).join(', ') || 'None' }, - ...(wizard.config.indexedKeys && wizard.config.indexedKeys.length > 0 - ? [{ label: 'Indexed Keys', value: wizard.config.indexedKeys.map(k => `${k.key} (${k.type})`).join(', ') }] - : []), ...(wizard.config.streaming ? [ { label: 'Stream ARN', value: wizard.config.streaming.dataStreamArn }, @@ -245,8 +118,6 @@ export function AddMemoryScreen({ onComplete, onExit, existingMemoryNames }: Add [wizard.config] ); - const existingKeyNames = useMemo(() => collectedKeys.map(k => k.key), [collectedKeys]); - return ( )} - {isIndexedKeysStep && indexedKeysSubStep === 'prompt' && ( - - )} - - {isIndexedKeysStep && indexedKeysSubStep === 'keyName' && ( - - {collectedKeys.length > 0 && ( - - {collectedKeys.map(k => ( - - {` ✓ ${k.key} (${k.type})`} - - ))} - - )} - { - setPendingKeyName(''); - if (collectedKeys.length > 0) { - setIndexedKeysSubStep('addAnother'); - } else { - wizard.clearIndexedKeys(); - setIndexedKeysSubStep('prompt'); - } - }} - customValidation={value => validateIndexedKeyName(value, existingKeyNames)} - /> - - )} - - {isIndexedKeysStep && indexedKeysSubStep === 'keyType' && ( - - {collectedKeys.length > 0 && ( - - {collectedKeys.map(k => ( - - {` ✓ ${k.key} (${k.type})`} - - ))} - - )} - - - )} - - {isIndexedKeysStep && indexedKeysSubStep === 'addAnother' && ( - - - {collectedKeys.map(k => ( - - {` ✓ ${k.key} (${k.type})`} - - ))} - - - - )} - {isStreamingStep && ( = { name: 'Name', expiry: 'Expiry', strategies: 'Strategies', - indexedKeys: 'Indexed Keys', streaming: 'Streaming', streamArn: 'Stream ARN', contentLevel: 'Content Level', @@ -86,16 +71,4 @@ export const CONTENT_LEVEL_OPTIONS = [ // Defaults // ───────────────────────────────────────────────────────────────────────────── -const INDEXED_KEY_TYPE_DESCRIPTIONS: Record = { - STRING: 'Single string value', - STRINGLIST: 'List of string values', - NUMBER: 'Numeric value', -}; - -export const INDEXED_KEY_TYPE_OPTIONS = IndexedKeyTypeSchema.options.map(type => ({ - id: type, - title: type, - description: INDEXED_KEY_TYPE_DESCRIPTIONS[type], -})); - export const DEFAULT_EVENT_EXPIRY = 30; diff --git a/src/cli/tui/screens/memory/useAddMemoryWizard.ts b/src/cli/tui/screens/memory/useAddMemoryWizard.ts index 9bf0d410e..aca78e069 100644 --- a/src/cli/tui/screens/memory/useAddMemoryWizard.ts +++ b/src/cli/tui/screens/memory/useAddMemoryWizard.ts @@ -1,21 +1,13 @@ import type { MemoryStrategyType, StreamContentLevel } from '../../../../schema'; -import type { AddMemoryConfig, AddMemoryIndexedKeyConfig, AddMemoryStep, AddMemoryStrategyConfig } from './types'; +import type { AddMemoryConfig, AddMemoryStep, AddMemoryStrategyConfig } from './types'; import { DEFAULT_EVENT_EXPIRY } from './types'; import { useCallback, useMemo, useState } from 'react'; -const BASE_STEPS = ['name', 'expiry', 'strategies'] as const; -const INDEXED_KEYS_STEP = 'indexedKeys' as const; -const STREAMING_STEP = 'streaming' as const; -const STREAMING_DETAIL_STEPS = ['streamArn', 'contentLevel'] as const; -const FIRST_STREAMING_DETAIL_STEP = STREAMING_DETAIL_STEPS[0]; +const BASE_STEPS = ['name', 'expiry', 'strategies', 'streaming'] as const; +const STREAMING_STEPS = ['streamArn', 'contentLevel'] as const; +const FIRST_STREAMING_STEP = STREAMING_STEPS[0]; const CONFIRM_STEP = 'confirm' as const; -const LTM_STRATEGY_TYPES: MemoryStrategyType[] = ['SEMANTIC', 'USER_PREFERENCE', 'SUMMARIZATION', 'EPISODIC']; - -function hasLtmStrategy(strategies: AddMemoryStrategyConfig[]): boolean { - return strategies.some(s => LTM_STRATEGY_TYPES.includes(s.type)); -} - function getDefaultConfig(): AddMemoryConfig { return { name: '', @@ -29,19 +21,10 @@ export function useAddMemoryWizard() { const [step, setStep] = useState('name'); const [enableStreaming, setEnableStreaming] = useState(false); - const allSteps = useMemo(() => { - const steps: AddMemoryStep[] = [...BASE_STEPS]; - if (hasLtmStrategy(config.strategies)) { - steps.push(INDEXED_KEYS_STEP); - } - steps.push(STREAMING_STEP); - if (enableStreaming) { - steps.push(...STREAMING_DETAIL_STEPS); - } - steps.push(CONFIRM_STEP); - return steps; - }, [enableStreaming, config.strategies]); - + const allSteps = useMemo( + () => (enableStreaming ? [...BASE_STEPS, ...STREAMING_STEPS, CONFIRM_STEP] : [...BASE_STEPS, CONFIRM_STEP]), + [enableStreaming] + ); const currentIndex = allSteps.indexOf(step); const goBack = useCallback(() => { @@ -76,28 +59,22 @@ export function useAddMemoryWizard() { [nextStep] ); - const setStrategyTypes = useCallback((types: MemoryStrategyType[]) => { - const strategies: AddMemoryStrategyConfig[] = types.map(type => ({ type })); - const hasLtm = types.some(t => LTM_STRATEGY_TYPES.includes(t)); - // After setting strategies, we need to determine the next step. - // If LTM strategies were selected, next is indexedKeys; otherwise streaming. - setConfig(c => ({ ...c, strategies, ...(hasLtm ? {} : { indexedKeys: undefined }) })); - setStep(hasLtm ? INDEXED_KEYS_STEP : STREAMING_STEP); - }, []); - - const setIndexedKeys = useCallback((indexedKeys: AddMemoryIndexedKeyConfig[]) => { - setConfig(c => ({ ...c, indexedKeys: indexedKeys.length > 0 ? indexedKeys : undefined })); - setStep(STREAMING_STEP); - }, []); - - const clearIndexedKeys = useCallback(() => { - setConfig(c => ({ ...c, indexedKeys: undefined })); - }, []); + const setStrategyTypes = useCallback( + (types: MemoryStrategyType[]) => { + const strategies: AddMemoryStrategyConfig[] = types.map(type => ({ type })); + setConfig(c => ({ ...c, strategies })); + const next = nextStep('strategies'); + if (next) setStep(next); + }, + [nextStep] + ); const setStreamingEnabled = useCallback((enabled: boolean) => { setEnableStreaming(enabled); if (enabled) { - setStep(FIRST_STREAMING_DETAIL_STEP); + // Can't use nextStep() here — allSteps hasn't updated yet since + // setEnableStreaming is queued. Hardcode the known next step. + setStep(FIRST_STREAMING_STEP); } else { setConfig(c => ({ ...c, streaming: undefined })); setStep(CONFIRM_STEP); @@ -110,7 +87,7 @@ export function useAddMemoryWizard() { ...c, streaming: { dataStreamArn, contentLevel: c.streaming?.contentLevel ?? 'FULL_CONTENT' }, })); - const next = nextStep(FIRST_STREAMING_DETAIL_STEP); + const next = nextStep(FIRST_STREAMING_STEP); if (next) setStep(next); }, [nextStep] @@ -148,8 +125,6 @@ export function useAddMemoryWizard() { setName, setExpiry, setStrategyTypes, - setIndexedKeys, - clearIndexedKeys, setStreamingEnabled, setStreamArn, setContentLevel, diff --git a/src/schema/schemas/agentcore-project.ts b/src/schema/schemas/agentcore-project.ts index 8cf22df2a..b3f4d3d6f 100644 --- a/src/schema/schemas/agentcore-project.ts +++ b/src/schema/schemas/agentcore-project.ts @@ -149,77 +149,25 @@ export const StreamDeliveryResourcesSchema = z.object({ export type StreamDeliveryResources = z.infer; -export const IndexedKeyTypeSchema = z.enum(['STRING', 'STRINGLIST', 'NUMBER']); -export type IndexedKeyType = z.infer; - -/** - * Indexed metadata key declaration on a Memory. - * Indexed keys enable filtering memory records on retrieval by attached metadata. - * - * Key pattern matches the AgentCore Control API: alphanumeric characters, whitespace, - * and the symbols `. _ : / = + @ -` (max 128 chars). - * - * Note: indexed keys are append-only on the AWS service side — once added to a Memory, - * a key cannot be removed. Reducing the array on update will fail at deploy time. - */ -export const INDEXED_KEY_NAME_PATTERN = /^[a-zA-Z0-9\s._:/=+@-]+$/; -export const INDEXED_KEY_NAME_PATTERN_MESSAGE = - 'Must contain only alphanumeric characters, whitespace, or the symbols . _ : / = + @ -'; -export const MAX_INDEXED_KEY_NAME_LENGTH = 128; -export const MAX_INDEXED_KEYS = 10; - -export const IndexedKeySchema = z.object({ - key: z - .string() - .min(1) - .max(MAX_INDEXED_KEY_NAME_LENGTH) - .regex(INDEXED_KEY_NAME_PATTERN, INDEXED_KEY_NAME_PATTERN_MESSAGE) - .refine(s => s.trim().length > 0, 'Key cannot be only whitespace'), - type: IndexedKeyTypeSchema, -}); -export type IndexedKey = z.infer; - -export const MemorySchema = z - .object({ - name: MemoryNameSchema, - eventExpiryDuration: z.number().int().min(3).max(365), - // Strategies array can be empty for short-term memory (just base memory with expiration) - // Long-term memory includes strategies like SEMANTIC, SUMMARIZATION, USER_PREFERENCE - strategies: z - .array(MemoryStrategySchema) - .default([]) - .superRefine( - uniqueBy( - strategy => strategy.type, - type => `Duplicate memory strategy type: ${type}` - ) - ), - indexedKeys: z - .array(IndexedKeySchema) - .max(MAX_INDEXED_KEYS) - .superRefine( - uniqueBy( - entry => entry.key, - key => `Duplicate indexed key: ${key}` - ) +export const MemorySchema = z.object({ + name: MemoryNameSchema, + eventExpiryDuration: z.number().int().min(3).max(365), + // Strategies array can be empty for short-term memory (just base memory with expiration) + // Long-term memory includes strategies like SEMANTIC, SUMMARIZATION, USER_PREFERENCE + strategies: z + .array(MemoryStrategySchema) + .default([]) + .superRefine( + uniqueBy( + strategy => strategy.type, + type => `Duplicate memory strategy type: ${type}` ) - .optional(), - tags: TagsSchema.optional(), - encryptionKeyArn: z.string().optional(), - executionRoleArn: z.string().optional(), - streamDeliveryResources: StreamDeliveryResourcesSchema.optional(), - }) - .superRefine((memory, ctx) => { - // Indexed keys filter long-term memory records on retrieval; they have no - // meaning on a short-term-only memory (no strategies => no LTM records). - if (memory.indexedKeys && memory.indexedKeys.length > 0 && memory.strategies.length === 0) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ['indexedKeys'], - message: 'indexedKeys requires at least one memory strategy (long-term memory)', - }); - } - }); + ), + tags: TagsSchema.optional(), + encryptionKeyArn: z.string().optional(), + executionRoleArn: z.string().optional(), + streamDeliveryResources: StreamDeliveryResourcesSchema.optional(), +}); export type Memory = z.infer;