thinkwork-cli 0.5.1 → 0.5.3

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.
@@ -1,66 +1,87 @@
1
- # Memory Engine Module
1
+ # Hindsight Memory Module (optional add-on)
2
2
 
3
- Thinkwork supports pluggable long-term memory for agents. Choose the engine that fits your stage and requirements.
3
+ Thinkwork has two long-term memory systems. **AgentCore managed memory is
4
+ always on** — every agent gets automatic per-turn retention out of the box
5
+ with zero configuration. **Hindsight is an optional add-on** you can layer
6
+ on top for advanced semantic + entity-graph retrieval.
4
7
 
5
- ## Engines
8
+ ## Memory layers
6
9
 
7
- | Engine | `memory_engine` value | Best for | Extra infra | Cost |
8
- |--------|----------------------|----------|-------------|------|
9
- | **AgentCore Managed** | `managed` (default) | All stages. Production-ready, zero-config. | None | $0 additional |
10
- | **Hindsight** | `hindsight` | Advanced recall/reflect with entity graph, cross-encoder reranking. | ECS Fargate + ALB | ~$75/mo (ARM64) |
10
+ | Layer | Backend | Always on | What it stores |
11
+ |-------|---------|-----------|----------------|
12
+ | 1. Workspace files | S3 per-agent | Yes | Scratchpad, working files |
13
+ | 2. Thread history | Aurora `messages` table | Yes | Last 30 turns per thread |
14
+ | 3a. Managed long-term | AgentCore Memory | **Yes** | Semantic facts, preferences, summaries, episodes — extracted automatically from every turn |
15
+ | 3b. Hindsight long-term | Hindsight ECS service | **Optional** | Same purpose as 3a, plus entity graph + BM25 + cross-encoder reranking |
11
16
 
12
- Both engines provide agents with memory tools. The Strands runtime reads `MEMORY_ENGINE` and loads the right tool set:
17
+ ## How retention works
13
18
 
14
- - **Managed**: `remember()`, `recall()`, `forget()` backed by AgentCore Memory API with 4 strategies (semantic facts, user preferences, session summaries, episodic).
15
- - **Hindsight**: `hindsight_retain()`, `hindsight_recall()`, `hindsight_reflect()` backed by the Hindsight service with semantic + BM25 + entity graph + temporal retrieval and cross-encoder reranking.
19
+ The agent container automatically emits a `CreateEvent` into AgentCore
20
+ Memory after every turn (user message + assistant response), via
21
+ `memory.store_turn_pair` in `packages/agentcore/agent-container/memory.py`.
22
+ AgentCore's background strategies extract facts into four namespaces:
16
23
 
17
- ## What's pluggable
24
+ - `assistant_{actorId}` — semantic facts
25
+ - `preferences_{actorId}` — user preferences
26
+ - `session_{sessionId}` — session summaries
27
+ - `episodes_{actorId}/{sessionId}` — episodic memory
18
28
 
19
- Only **Layer 3 (long-term cross-thread memory)** is pluggable. The other memory layers are core infrastructure:
29
+ The agent reads them back via the `recall()` tool. There is no need for
30
+ the model to call `remember()` for routine facts — it only exists for
31
+ user-driven "please remember X" requests.
20
32
 
21
- - **Layer 1** Workspace files on S3 (per-agent scratchpad). Always available.
22
- - **Layer 2** Thread history in Aurora (conversation memory). Always available.
23
- - **Layer 3** Long-term cross-thread recall. **This is what `memory_engine` controls.**
33
+ When Hindsight is enabled, the container ALSO registers
34
+ `hindsight_retain`, `hindsight_recall`, and `hindsight_reflect` tools that
35
+ route to the Hindsight service. `remember()` dual-writes to both backends
36
+ so explicit memories land in both systems.
24
37
 
25
38
  ## Usage
26
39
 
27
- ### Managed (default no extra config needed)
40
+ ### Defaultmanaged memory only (zero config)
28
41
 
29
42
  ```hcl
30
43
  module "thinkwork" {
31
44
  source = "thinkwork-ai/thinkwork/aws"
32
45
 
33
- stage = "prod"
34
- # memory_engine defaults to "managed" — nothing to set
46
+ stage = "prod"
47
+ # enable_hindsight defaults to false — nothing else to set
35
48
  }
36
49
  ```
37
50
 
38
- ### Hindsight (opt-in)
51
+ The `terraform/modules/app/agentcore-memory` module is always instantiated
52
+ and provisions the AgentCore Memory resource with the four strategies.
53
+
54
+ ### With the Hindsight add-on
39
55
 
40
56
  ```hcl
41
57
  module "thinkwork" {
42
58
  source = "thinkwork-ai/thinkwork/aws"
43
59
 
44
- stage = "prod"
45
- memory_engine = "hindsight"
60
+ stage = "prod"
61
+ enable_hindsight = true
46
62
 
47
63
  # Optional: pin the Hindsight image version
48
- # hindsight_image_tag = "0.4.22"
64
+ # hindsight_image_tag = "0.5.0"
49
65
  }
50
66
  ```
51
67
 
52
- When `memory_engine = "hindsight"`, Terraform creates:
68
+ When `enable_hindsight = true`, Terraform creates:
53
69
  - ECS Fargate cluster + service (ARM64, 2 vCPU, 4 GB)
54
70
  - Application Load Balancer
55
71
  - Security groups (ALB → Hindsight → Aurora ingress)
56
72
  - CloudWatch log group
57
73
 
58
- When `memory_engine = "managed"`, none of the above is created.
74
+ Cost: ~$75/mo (ARM64 Fargate + ALB hours).
75
+
76
+ ## Turning the add-on on/off
59
77
 
60
- ## Switching engines
78
+ Toggling `enable_hindsight` and re-running `thinkwork deploy`:
61
79
 
62
- Changing `memory_engine` and running `thinkwork deploy` will:
63
- - **managed hindsight**: Create the ECS/ALB infrastructure. Agents start using Hindsight tools on next invoke.
64
- - **hindsight → managed**: Destroy the ECS/ALB infrastructure. Agents fall back to AgentCore memory tools.
80
+ - **false true**: creates the ECS + ALB infra. Agents gain the three
81
+ `hindsight_*` tools on their next invoke. Managed retention continues
82
+ running unchanged.
83
+ - **true → false**: destroys the ECS + ALB infra. Agents lose the
84
+ `hindsight_*` tools. Managed memory keeps working as before.
65
85
 
66
- Memory data is not migrated between engines. Each engine has its own storage backend.
86
+ Memory data is not migrated between backends. Hindsight records and
87
+ AgentCore records live in separate stores.
@@ -1,13 +1,15 @@
1
1
  ################################################################################
2
- # Hindsight Memory Engine — App Module
2
+ # Hindsight Memory (Optional Add-On) — App Module
3
3
  #
4
- # Optional ECS Fargate + ALB service for Hindsight long-term memory.
5
- # Only created when memory_engine = "hindsight". When memory_engine = "managed",
6
- # this module creates nothing and AgentCore's built-in memory is used instead.
4
+ # Optional ECS Fargate + ALB service for Hindsight long-term memory. Only
5
+ # created when `enable_hindsight = true`. AgentCore managed memory is
6
+ # always on (see ../agentcore-memory) Hindsight runs alongside it as an
7
+ # add-on, not as a replacement.
7
8
  #
8
- # Hindsight provides retain/recall/reflect tools for cross-thread,
9
- # cross-session organizational memory. It runs local embeddings + reranker
10
- # and uses the shared Aurora PostgreSQL instance with pgvector.
9
+ # Hindsight provides hindsight_retain/recall/reflect tools for cross-thread
10
+ # organizational memory with entity-graph traversal and cross-encoder
11
+ # reranking. It runs local embeddings + reranker and uses the shared Aurora
12
+ # PostgreSQL instance with pgvector.
11
13
  ################################################################################
12
14
 
13
15
  variable "stage" {
@@ -12,28 +12,33 @@ locals {
12
12
 
13
13
  # Common environment variables shared by all API handlers
14
14
  common_env = {
15
- STAGE = var.stage
16
- DATABASE_URL = "postgresql://${var.db_username}:${urlencode(var.db_password)}@${var.db_cluster_endpoint}:5432/${var.database_name}?sslmode=no-verify"
17
- DATABASE_SECRET_ARN = var.graphql_db_secret_arn
18
- DATABASE_HOST = var.db_cluster_endpoint
19
- DATABASE_NAME = var.database_name
20
- BUCKET_NAME = var.bucket_name
21
- USER_POOL_ID = var.user_pool_id
22
- COGNITO_USER_POOL_ID = var.user_pool_id
23
- ADMIN_CLIENT_ID = var.admin_client_id
24
- MOBILE_CLIENT_ID = var.mobile_client_id
25
- COGNITO_APP_CLIENT_IDS = "${var.admin_client_id},${var.mobile_client_id}"
26
- APPSYNC_ENDPOINT = var.appsync_api_url
27
- APPSYNC_API_KEY = var.appsync_api_key
28
- GRAPHQL_API_KEY = var.appsync_api_key
29
- API_AUTH_SECRET = var.api_auth_secret
30
- THINKWORK_API_SECRET = var.api_auth_secret
31
- MANIFLOW_API_SECRET = var.api_auth_secret
32
- AGENTCORE_INVOKE_URL = var.agentcore_invoke_url
33
- AGENTCORE_FUNCTION_NAME = var.agentcore_function_name
34
- WORKSPACE_BUCKET = var.bucket_name
35
- HINDSIGHT_ENDPOINT = var.hindsight_endpoint
36
- NODE_OPTIONS = "--enable-source-maps"
15
+ STAGE = var.stage
16
+ DATABASE_URL = "postgresql://${var.db_username}:${urlencode(var.db_password)}@${var.db_cluster_endpoint}:5432/${var.database_name}?sslmode=no-verify"
17
+ DATABASE_SECRET_ARN = var.graphql_db_secret_arn
18
+ DATABASE_HOST = var.db_cluster_endpoint
19
+ DATABASE_NAME = var.database_name
20
+ BUCKET_NAME = var.bucket_name
21
+ USER_POOL_ID = var.user_pool_id
22
+ COGNITO_USER_POOL_ID = var.user_pool_id
23
+ ADMIN_CLIENT_ID = var.admin_client_id
24
+ MOBILE_CLIENT_ID = var.mobile_client_id
25
+ COGNITO_APP_CLIENT_IDS = "${var.admin_client_id},${var.mobile_client_id}"
26
+ APPSYNC_ENDPOINT = var.appsync_api_url
27
+ APPSYNC_API_KEY = var.appsync_api_key
28
+ GRAPHQL_API_KEY = var.appsync_api_key
29
+ API_AUTH_SECRET = var.api_auth_secret
30
+ THINKWORK_API_SECRET = var.api_auth_secret
31
+ MANIFLOW_API_SECRET = var.api_auth_secret
32
+ AGENTCORE_FUNCTION_NAME = var.agentcore_function_name
33
+ WORKSPACE_BUCKET = var.bucket_name
34
+ HINDSIGHT_ENDPOINT = var.hindsight_endpoint
35
+ AGENTCORE_MEMORY_ID = var.agentcore_memory_id
36
+ ADMIN_URL = var.admin_url
37
+ DOCS_URL = var.docs_url
38
+ APPSYNC_REALTIME_URL = var.appsync_realtime_url
39
+ ECR_REPOSITORY_URL = var.ecr_repository_url
40
+ AWS_ACCOUNT_ID = var.account_id
41
+ NODE_OPTIONS = "--enable-source-maps"
37
42
  }
38
43
  }
39
44
 
@@ -113,15 +118,15 @@ locals {
113
118
  # Map of route_key → handler name for API Gateway
114
119
  api_routes = local.use_local_zips ? {
115
120
  # GraphQL — the main API entry point
116
- "POST /graphql" = "graphql-http"
117
- "GET /graphql" = "graphql-http"
121
+ "POST /graphql" = "graphql-http"
122
+ "GET /graphql" = "graphql-http"
118
123
 
119
124
  # Health check (keep placeholder alive too)
120
125
  # "GET /health" is handled by placeholder
121
126
 
122
127
  # Agents
123
- "ANY /api/agents/{proxy+}" = "agents"
124
- "ANY /api/agents" = "agents"
128
+ "ANY /api/agents/{proxy+}" = "agents"
129
+ "ANY /api/agents" = "agents"
125
130
 
126
131
  # Agent actions (start/stop/heartbeat/budget)
127
132
  "ANY /api/agent-actions/{proxy+}" = "agent-actions"
@@ -131,25 +136,25 @@ locals {
131
136
  "ANY /api/messages" = "messages"
132
137
 
133
138
  # Teams
134
- "ANY /api/teams/{proxy+}" = "teams"
135
- "ANY /api/teams" = "teams"
139
+ "ANY /api/teams/{proxy+}" = "teams"
140
+ "ANY /api/teams" = "teams"
136
141
  "ANY /api/team-members/{proxy+}" = "team-members"
137
142
 
138
143
  # Tenants
139
- "ANY /api/tenants/{proxy+}" = "tenants"
140
- "ANY /api/tenants" = "tenants"
144
+ "ANY /api/tenants/{proxy+}" = "tenants"
145
+ "ANY /api/tenants" = "tenants"
141
146
 
142
147
  # Users
143
- "ANY /api/users/{proxy+}" = "users"
144
- "ANY /api/users" = "users"
148
+ "ANY /api/users/{proxy+}" = "users"
149
+ "ANY /api/users" = "users"
145
150
 
146
151
  # Invites
147
- "ANY /api/invites/{proxy+}" = "invites"
148
- "ANY /api/invites" = "invites"
152
+ "ANY /api/invites/{proxy+}" = "invites"
153
+ "ANY /api/invites" = "invites"
149
154
 
150
155
  # Skills
151
- "ANY /api/skills/{proxy+}" = "skills"
152
- "ANY /api/skills" = "skills"
156
+ "ANY /api/skills/{proxy+}" = "skills"
157
+ "ANY /api/skills" = "skills"
153
158
 
154
159
  # Activity
155
160
  "ANY /api/activity/{proxy+}" = "activity"
@@ -166,8 +171,8 @@ locals {
166
171
  "ANY /api/routines" = "routines"
167
172
 
168
173
  # Budgets
169
- "ANY /api/budgets/{proxy+}" = "budgets"
170
- "ANY /api/budgets" = "budgets"
174
+ "ANY /api/budgets/{proxy+}" = "budgets"
175
+ "ANY /api/budgets" = "budgets"
171
176
 
172
177
  # Guardrails
173
178
  "ANY /api/guardrails/{proxy+}" = "guardrails"
@@ -168,6 +168,7 @@ resource "aws_iam_role_policy" "lambda_cognito" {
168
168
  Statement = [{
169
169
  Effect = "Allow"
170
170
  Action = [
171
+ "cognito-idp:AdminCreateUser",
171
172
  "cognito-idp:AdminGetUser",
172
173
  "cognito-idp:AdminUpdateUserAttributes",
173
174
  "cognito-idp:ListUsers",
@@ -177,6 +178,20 @@ resource "aws_iam_role_policy" "lambda_cognito" {
177
178
  })
178
179
  }
179
180
 
181
+ resource "aws_iam_role_policy" "lambda_cloudwatch_read" {
182
+ name = "cloudwatch-logs-read"
183
+ role = aws_iam_role.lambda.id
184
+
185
+ policy = jsonencode({
186
+ Version = "2012-10-17"
187
+ Statement = [{
188
+ Effect = "Allow"
189
+ Action = ["logs:FilterLogEvents", "logs:GetLogEvents", "logs:DescribeLogGroups"]
190
+ Resource = "arn:aws:logs:${var.region}:${var.account_id}:log-group:*model-invocations*"
191
+ }]
192
+ })
193
+ }
194
+
180
195
  resource "aws_iam_role_policy" "lambda_bedrock" {
181
196
  name = "bedrock-invoke"
182
197
  role = aws_iam_role.lambda.id
@@ -191,6 +206,49 @@ resource "aws_iam_role_policy" "lambda_bedrock" {
191
206
  })
192
207
  }
193
208
 
209
+ # Allow API Lambdas to directly invoke the AgentCore Lambda. Used by
210
+ # chat-agent-invoke (and future wake-up/retry paths) via InvokeCommand.
211
+ resource "aws_iam_role_policy" "lambda_agentcore_invoke" {
212
+ count = var.agentcore_function_arn != "" ? 1 : 0
213
+ name = "agentcore-invoke"
214
+ role = aws_iam_role.lambda.id
215
+
216
+ policy = jsonencode({
217
+ Version = "2012-10-17"
218
+ Statement = [{
219
+ Effect = "Allow"
220
+ Action = [
221
+ "lambda:InvokeFunction",
222
+ ]
223
+ Resource = [
224
+ var.agentcore_function_arn,
225
+ "${var.agentcore_function_arn}:*",
226
+ ]
227
+ }]
228
+ })
229
+ }
230
+
231
+ # AgentCore Memory read access for the GraphQL memory resolvers.
232
+ # memoryRecords / memorySearch call ListMemoryRecordsCommand to fetch
233
+ # records across the tenant's agents.
234
+ resource "aws_iam_role_policy" "lambda_agentcore_memory" {
235
+ name = "agentcore-memory-read"
236
+ role = aws_iam_role.lambda.id
237
+
238
+ policy = jsonencode({
239
+ Version = "2012-10-17"
240
+ Statement = [{
241
+ Effect = "Allow"
242
+ Action = [
243
+ "bedrock-agentcore:ListMemoryRecords",
244
+ "bedrock-agentcore:RetrieveMemoryRecords",
245
+ "bedrock-agentcore:GetMemoryRecord",
246
+ ]
247
+ Resource = "*"
248
+ }]
249
+ })
250
+ }
251
+
194
252
  ################################################################################
195
253
  # Placeholder Lambda — proves the infrastructure works
196
254
  #
@@ -134,20 +134,50 @@ variable "api_auth_secret" {
134
134
  default = ""
135
135
  }
136
136
 
137
- variable "agentcore_invoke_url" {
138
- description = "Lambda Function URL for AgentCore container invocation"
137
+ variable "hindsight_endpoint" {
138
+ description = "Hindsight API endpoint (empty when enable_hindsight = false)"
139
139
  type = string
140
140
  default = ""
141
141
  }
142
142
 
143
- variable "hindsight_endpoint" {
144
- description = "Hindsight API endpoint (empty when memory_engine = managed)"
143
+ variable "agentcore_memory_id" {
144
+ description = "Bedrock AgentCore Memory resource ID used by the GraphQL memory resolvers to list records across tenant agents."
145
145
  type = string
146
146
  default = ""
147
147
  }
148
148
 
149
149
  variable "agentcore_function_name" {
150
- description = "AgentCore Lambda function name (for direct SDK invoke instead of Function URL)"
150
+ description = "AgentCore Lambda function name (for direct SDK invoke)"
151
+ type = string
152
+ default = ""
153
+ }
154
+
155
+ variable "agentcore_function_arn" {
156
+ description = "AgentCore Lambda function ARN (used to grant lambda:InvokeFunction)"
157
+ type = string
158
+ default = ""
159
+ }
160
+
161
+ variable "admin_url" {
162
+ description = "Admin app URL (e.g. https://d3li9vbqnhv7w.cloudfront.net)"
163
+ type = string
164
+ default = ""
165
+ }
166
+
167
+ variable "docs_url" {
168
+ description = "Docs site URL (e.g. https://d2grg1uavrp7lx.cloudfront.net)"
169
+ type = string
170
+ default = ""
171
+ }
172
+
173
+ variable "appsync_realtime_url" {
174
+ description = "AppSync realtime/WebSocket endpoint URL"
175
+ type = string
176
+ default = ""
177
+ }
178
+
179
+ variable "ecr_repository_url" {
180
+ description = "ECR repository URL for AgentCore container"
151
181
  type = string
152
182
  default = ""
153
183
  }
@@ -11,6 +11,12 @@
11
11
 
12
12
  locals {
13
13
  bucket_name = var.bucket_name != "" ? var.bucket_name : "thinkwork-${var.stage}-storage"
14
+
15
+ # Hindsight is an optional add-on. Preferred toggle: var.enable_hindsight.
16
+ # For one release we also honor the deprecated var.memory_engine == "hindsight"
17
+ # so existing tfvars keep working. The CLI config command also auto-translates
18
+ # between the two. Remove the legacy branch in a future release.
19
+ hindsight_enabled = var.enable_hindsight || var.memory_engine == "hindsight"
14
20
  }
15
21
 
16
22
  ################################################################################
@@ -47,12 +53,12 @@ module "cognito" {
47
53
  stage = var.stage
48
54
  region = var.region
49
55
 
50
- create_cognito = var.create_cognito
51
- existing_user_pool_id = var.existing_user_pool_id
52
- existing_user_pool_arn = var.existing_user_pool_arn
53
- existing_admin_client_id = var.existing_admin_client_id
56
+ create_cognito = var.create_cognito
57
+ existing_user_pool_id = var.existing_user_pool_id
58
+ existing_user_pool_arn = var.existing_user_pool_arn
59
+ existing_admin_client_id = var.existing_admin_client_id
54
60
  existing_mobile_client_id = var.existing_mobile_client_id
55
- existing_identity_pool_id = var.existing_identity_pool_id
61
+ existing_identity_pool_id = var.existing_identity_pool_id
56
62
 
57
63
  google_oauth_client_id = var.google_oauth_client_id
58
64
  google_oauth_client_secret = var.google_oauth_client_secret
@@ -90,7 +96,7 @@ module "s3" {
90
96
  module "database" {
91
97
  source = "../data/aurora-postgres"
92
98
 
93
- stage = var.stage
99
+ stage = var.stage
94
100
 
95
101
  create_database = var.create_database
96
102
  existing_db_cluster_arn = var.existing_db_cluster_arn
@@ -151,9 +157,9 @@ module "api" {
151
157
  bucket_name = module.s3.bucket_name
152
158
  bucket_arn = module.s3.bucket_arn
153
159
 
154
- user_pool_id = module.cognito.user_pool_id
155
- user_pool_arn = module.cognito.user_pool_arn
156
- admin_client_id = module.cognito.admin_client_id
160
+ user_pool_id = module.cognito.user_pool_id
161
+ user_pool_arn = module.cognito.user_pool_arn
162
+ admin_client_id = module.cognito.admin_client_id
157
163
  mobile_client_id = module.cognito.mobile_client_id
158
164
 
159
165
  appsync_api_url = module.appsync.graphql_api_url
@@ -161,12 +167,33 @@ module "api" {
161
167
 
162
168
  kb_service_role_arn = module.bedrock_kb.kb_service_role_arn
163
169
 
164
- lambda_zips_dir = var.lambda_zips_dir
165
- api_auth_secret = var.api_auth_secret
166
- db_password = var.db_password
167
- agentcore_invoke_url = module.agentcore.agentcore_invoke_url
170
+ lambda_zips_dir = var.lambda_zips_dir
171
+ api_auth_secret = var.api_auth_secret
172
+ db_password = var.db_password
168
173
  agentcore_function_name = module.agentcore.agentcore_function_name
169
- hindsight_endpoint = var.memory_engine == "hindsight" ? module.hindsight[0].hindsight_endpoint : ""
174
+ agentcore_function_arn = module.agentcore.agentcore_function_arn
175
+ hindsight_endpoint = local.hindsight_enabled ? module.hindsight[0].hindsight_endpoint : ""
176
+ agentcore_memory_id = module.agentcore_memory.memory_id
177
+ admin_url = "https://${module.admin_site.distribution_domain}"
178
+ docs_url = "https://${module.docs_site.distribution_domain}"
179
+ appsync_realtime_url = module.appsync.graphql_realtime_url
180
+ ecr_repository_url = module.agentcore.ecr_repository_url
181
+ }
182
+
183
+ ################################################################################
184
+ # AgentCore Memory (managed) — always created. Provides automatic per-turn
185
+ # retention via memory.store_turn_pair in the agent container. If the caller
186
+ # already has a memory resource, set `agentcore_memory_id` on the root module
187
+ # to short-circuit provisioning.
188
+ ################################################################################
189
+
190
+ module "agentcore_memory" {
191
+ source = "../app/agentcore-memory"
192
+
193
+ stage = var.stage
194
+ region = var.region
195
+ account_id = var.account_id
196
+ existing_memory_id = var.agentcore_memory_id
170
197
  }
171
198
 
172
199
  module "agentcore" {
@@ -177,9 +204,8 @@ module "agentcore" {
177
204
  region = var.region
178
205
  bucket_name = module.s3.bucket_name
179
206
 
180
- memory_engine = var.memory_engine
181
- hindsight_endpoint = var.memory_engine == "hindsight" ? module.hindsight[0].hindsight_endpoint : ""
182
- agentcore_memory_id = var.agentcore_memory_id
207
+ hindsight_endpoint = local.hindsight_enabled ? module.hindsight[0].hindsight_endpoint : ""
208
+ agentcore_memory_id = module.agentcore_memory.memory_id
183
209
  }
184
210
 
185
211
  module "crons" {
@@ -199,7 +225,7 @@ module "job_triggers" {
199
225
  }
200
226
 
201
227
  module "hindsight" {
202
- count = var.memory_engine == "hindsight" ? 1 : 0
228
+ count = local.hindsight_enabled ? 1 : 0
203
229
  source = "../app/hindsight-memory"
204
230
 
205
231
  stage = var.stage
@@ -81,14 +81,19 @@ output "ecr_repository_url" {
81
81
  value = module.agentcore.ecr_repository_url
82
82
  }
83
83
 
84
- output "memory_engine" {
85
- description = "Which memory engine is active (managed or hindsight)"
86
- value = var.memory_engine
84
+ output "agentcore_memory_id" {
85
+ description = "Bedrock AgentCore Memory resource ID (always present — managed memory is always on)"
86
+ value = module.agentcore_memory.memory_id
87
+ }
88
+
89
+ output "hindsight_enabled" {
90
+ description = "Whether the Hindsight add-on is enabled"
91
+ value = local.hindsight_enabled
87
92
  }
88
93
 
89
94
  output "hindsight_endpoint" {
90
- description = "Hindsight API endpoint (only when memory_engine = hindsight)"
91
- value = var.memory_engine == "hindsight" ? module.hindsight[0].hindsight_endpoint : null
95
+ description = "Hindsight API endpoint (null when enable_hindsight = false)"
96
+ value = local.hindsight_enabled ? module.hindsight[0].hindsight_endpoint : null
92
97
  }
93
98
 
94
99
  # Admin static site
@@ -138,25 +138,31 @@ variable "database_engine" {
138
138
  default = "aurora-serverless"
139
139
  }
140
140
 
141
+ variable "enable_hindsight" {
142
+ description = "Enable Hindsight long-term memory as an optional add-on alongside the always-on AgentCore managed memory. When true, deploys an ECS+ALB service for semantic/entity-graph/cross-encoder retrieval. Default false."
143
+ type = bool
144
+ default = false
145
+ }
146
+
141
147
  variable "memory_engine" {
142
- description = "Memory engine: 'managed' (AgentCore built-in, default) or 'hindsight' (ECS+ALB service, opt-in)"
148
+ description = "DEPRECATED. Use `enable_hindsight` instead. For backwards compatibility, setting this to 'hindsight' is equivalent to `enable_hindsight = true`. AgentCore managed memory is always on and cannot be disabled."
143
149
  type = string
144
- default = "managed"
150
+ default = ""
145
151
 
146
152
  validation {
147
- condition = contains(["managed", "hindsight"], var.memory_engine)
148
- error_message = "memory_engine must be 'managed' or 'hindsight'"
153
+ condition = var.memory_engine == "" || contains(["managed", "hindsight"], var.memory_engine)
154
+ error_message = "memory_engine (deprecated) must be empty, 'managed', or 'hindsight'. Prefer enable_hindsight instead."
149
155
  }
150
156
  }
151
157
 
152
158
  variable "hindsight_image_tag" {
153
- description = "Hindsight Docker image tag (only used when memory_engine = 'hindsight')"
159
+ description = "Hindsight Docker image tag (only used when enable_hindsight = true)"
154
160
  type = string
155
161
  default = "0.5.0"
156
162
  }
157
163
 
158
164
  variable "agentcore_memory_id" {
159
- description = "AgentCore Memory resource ID (only used when memory_engine = 'managed')"
165
+ description = "Optional pre-existing AgentCore Memory resource ID. When set, the agentcore-memory module skips provisioning and reuses this ID. Leave empty to auto-provision."
160
166
  type = string
161
167
  default = ""
162
168
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkwork-cli",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Thinkwork CLI — deploy, manage, and interact with your Thinkwork stack",
5
5
  "license": "MIT",
6
6
  "type": "module",