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.
@@ -72,10 +72,10 @@ variable "database_engine" {
72
72
  default = "aurora-serverless"
73
73
  }
74
74
 
75
- variable "memory_engine" {
76
- description = "Memory engine: 'managed' (AgentCore built-in, default) or 'hindsight' (ECS+ALB, opt-in)"
77
- type = string
78
- default = "managed"
75
+ variable "enable_hindsight" {
76
+ description = "Optional Hindsight add-on alongside the always-on managed memory (ECS+ALB for semantic + graph retrieval)"
77
+ type = bool
78
+ default = false
79
79
  }
80
80
 
81
81
  variable "google_oauth_client_id" {
@@ -119,7 +119,7 @@ module "thinkwork" {
119
119
 
120
120
  db_password = var.db_password
121
121
  database_engine = var.database_engine
122
- memory_engine = var.memory_engine
122
+ enable_hindsight = var.enable_hindsight
123
123
  google_oauth_client_id = var.google_oauth_client_id
124
124
  google_oauth_client_secret = var.google_oauth_client_secret
125
125
  pre_signup_lambda_zip = var.pre_signup_lambda_zip
@@ -199,16 +199,21 @@ output "database_name" {
199
199
  value = module.thinkwork.database_name
200
200
  }
201
201
 
202
- output "memory_engine" {
203
- description = "Active memory engine (managed or hindsight)"
204
- value = module.thinkwork.memory_engine
202
+ output "hindsight_enabled" {
203
+ description = "Whether the Hindsight add-on is enabled"
204
+ value = module.thinkwork.hindsight_enabled
205
205
  }
206
206
 
207
207
  output "hindsight_endpoint" {
208
- description = "Hindsight API endpoint (null when memory_engine = managed)"
208
+ description = "Hindsight API endpoint (null when enable_hindsight = false)"
209
209
  value = module.thinkwork.hindsight_endpoint
210
210
  }
211
211
 
212
+ output "agentcore_memory_id" {
213
+ description = "AgentCore Memory resource ID used for automatic retention"
214
+ value = module.thinkwork.agentcore_memory_id
215
+ }
216
+
212
217
  output "admin_url" {
213
218
  description = "Admin app URL"
214
219
  value = "https://${module.thinkwork.admin_distribution_domain}"
@@ -12,10 +12,13 @@ account_id = "123456789012" # your AWS account ID
12
12
  # "rds-postgres" — Standard RDS PostgreSQL (dev/test, cheaper, deletion protection off)
13
13
  database_engine = "rds-postgres"
14
14
 
15
- # Memory engine:
16
- # "managed" — AgentCore built-in long-term memory (default, no extra infra)
17
- # "hindsight" Hindsight ECS+ALB service (opt-in, adds retain/recall/reflect tools)
18
- memory_engine = "managed"
15
+ # Memory:
16
+ # AgentCore managed memory is always on every agent gets automatic
17
+ # per-turn retention with zero config. Uncomment the line below to
18
+ # enable Hindsight as an optional add-on (adds an ECS+ALB service for
19
+ # semantic + entity-graph + cross-encoder retrieval tools alongside the
20
+ # built-in remember/recall/forget tools).
21
+ # enable_hindsight = true
19
22
 
20
23
  # Database master password — use a strong password
21
24
  db_password = "CHANGE_ME_strong_password_here"
@@ -0,0 +1,77 @@
1
+ # AgentCore Memory — App Module
2
+
3
+ Provisions an AWS Bedrock AgentCore Memory resource with the four strategies
4
+ the thinkwork Strands agent container uses for automatic retention:
5
+
6
+ | Strategy | Namespace template | Purpose |
7
+ |-------------|------------------------------|------------------------------------------|
8
+ | semantic | `assistant_{actorId}` | Cross-thread facts about the user |
9
+ | preferences | `preferences_{actorId}` | User-stated preferences |
10
+ | summaries | `session_{sessionId}` | Per-thread rolling summaries |
11
+ | episodes | `episodes_{actorId}/{sessionId}` | Episodic memory of past interactions |
12
+
13
+ Automatic retention is wired in the agent container: every turn emits a
14
+ `CreateEvent` via `memory.store_turn_pair`, and AgentCore's background
15
+ strategies extract facts into the namespaces above. Agents can read them
16
+ back via the `recall()` tool (also always registered). There is no need for
17
+ the model to call `remember()` explicitly — it only exists for user-driven
18
+ "please remember X" requests.
19
+
20
+ ## Usage
21
+
22
+ ```hcl
23
+ module "agentcore_memory" {
24
+ source = "../app/agentcore-memory"
25
+
26
+ stage = var.stage
27
+ region = var.region
28
+ # Optional: skip provisioning and reuse an existing memory resource
29
+ # existing_memory_id = "my-pre-existing-memory-id"
30
+ }
31
+
32
+ module "agentcore" {
33
+ source = "../app/agentcore-runtime"
34
+ # ...
35
+ agentcore_memory_id = module.agentcore_memory.memory_id
36
+ }
37
+ ```
38
+
39
+ ## Why a shell script and not a first-class resource?
40
+
41
+ The AWS Terraform provider does not (yet) expose a
42
+ `aws_bedrockagentcore_memory` resource. Until it does, this module drives
43
+ the lifecycle through the `aws bedrock-agentcore-control` CLI:
44
+
45
+ - **Create/find**: `data "external"` runs `scripts/create_or_find_memory.sh`,
46
+ which is idempotent — it looks up an existing memory by name before
47
+ creating a new one. Safe to re-run.
48
+ - **Destroy**: a paired `terraform_data` resource has a destroy-time
49
+ `local-exec` that calls `delete-memory` on the ID captured during create.
50
+
51
+ When the AWS provider adds a native resource, migrate by importing the
52
+ existing memory ID into the new resource and removing this module's
53
+ external data source.
54
+
55
+ ## Requirements
56
+
57
+ - `aws` CLI v2 with `bedrock-agentcore-control` commands (recent versions)
58
+ - `jq` in PATH
59
+ - IAM permissions:
60
+ - `bedrock-agentcore-control:ListMemories`
61
+ - `bedrock-agentcore-control:CreateMemory`
62
+ - `bedrock-agentcore-control:DeleteMemory`
63
+
64
+ ## Cost
65
+
66
+ AgentCore Memory charges per CreateEvent and per memory record extracted.
67
+ With automatic retention enabled, cost scales roughly linearly with chat
68
+ volume. Budget accordingly before enabling in production.
69
+
70
+ ## Migration notes
71
+
72
+ - **Strategies are immutable after creation.** If you need to change a
73
+ namespace template, you must delete and recreate the memory (losing all
74
+ records). Version the `name_prefix` or `stage` if you need to keep the
75
+ old records around during migration.
76
+ - **BYO memory**: pass `existing_memory_id = "..."` to skip provisioning
77
+ entirely. Useful for shared memory across multiple stages.
@@ -0,0 +1,159 @@
1
+ ################################################################################
2
+ # AgentCore Memory — App Module
3
+ #
4
+ # Provisions an AWS Bedrock AgentCore Memory resource with the four strategies
5
+ # the Strands agent container expects (semantic, preferences, summaries,
6
+ # episodes). The resource is always created — AgentCore managed memory is
7
+ # on by default so every agent gets automatic per-turn retention into
8
+ # semantic / preference / summary / episode strategies without any tool-
9
+ # calling by the model.
10
+ #
11
+ # **Why not a first-class resource?** The AWS provider does not (yet) expose a
12
+ # `aws_bedrockagentcore_memory` resource type. Until it does, we drive the
13
+ # create/find/destroy lifecycle through the `aws bedrock-agentcore-control`
14
+ # CLI via a small shell script, and read the resulting memory ID back into
15
+ # Terraform via `data "external"`. The script is idempotent — it lists
16
+ # existing memories with the same name and returns the existing ID if found,
17
+ # which keeps `terraform apply` safe to re-run.
18
+ #
19
+ # **BYO override:** If you already have an AgentCore Memory resource, set
20
+ # `var.existing_memory_id` to skip provisioning. The module output will echo
21
+ # that ID directly and no CLI calls are made.
22
+ ################################################################################
23
+
24
+ terraform {
25
+ required_providers {
26
+ external = {
27
+ source = "hashicorp/external"
28
+ version = ">= 2.3.0"
29
+ }
30
+ }
31
+ }
32
+
33
+ variable "stage" {
34
+ description = "Deployment stage (dev, prod, etc.) — used to name the memory resource"
35
+ type = string
36
+ }
37
+
38
+ variable "name_prefix" {
39
+ description = "Prefix for the Bedrock AgentCore Memory resource name"
40
+ type = string
41
+ default = "thinkwork"
42
+ }
43
+
44
+ variable "existing_memory_id" {
45
+ description = "Optional pre-existing AgentCore Memory ID. When set, the module skips provisioning and passes this ID through."
46
+ type = string
47
+ default = ""
48
+ }
49
+
50
+ variable "region" {
51
+ description = "AWS region"
52
+ type = string
53
+ }
54
+
55
+ variable "account_id" {
56
+ description = "AWS account ID"
57
+ type = string
58
+ default = ""
59
+ }
60
+
61
+ locals {
62
+ memory_name = "${replace(var.name_prefix, "-", "_")}_${replace(var.stage, "-", "_")}"
63
+ bootstrap = var.existing_memory_id == ""
64
+ }
65
+
66
+ ################################################################################
67
+ # IAM Role for custom memory strategies
68
+ ################################################################################
69
+
70
+ resource "aws_iam_role" "memory_execution" {
71
+ count = local.bootstrap ? 1 : 0
72
+ name = "thinkwork-${var.stage}-memory-execution"
73
+
74
+ assume_role_policy = jsonencode({
75
+ Version = "2012-10-17"
76
+ Statement = [{
77
+ Effect = "Allow"
78
+ Principal = { Service = "bedrock-agentcore.amazonaws.com" }
79
+ Action = "sts:AssumeRole"
80
+ }]
81
+ })
82
+ }
83
+
84
+ resource "aws_iam_role_policy" "memory_execution" {
85
+ count = local.bootstrap ? 1 : 0
86
+ name = "memory-execution"
87
+ role = aws_iam_role.memory_execution[0].id
88
+
89
+ policy = jsonencode({
90
+ Version = "2012-10-17"
91
+ Statement = [{
92
+ Effect = "Allow"
93
+ Action = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"]
94
+ Resource = "arn:aws:bedrock:${var.region}::foundation-model/*"
95
+ }]
96
+ })
97
+ }
98
+
99
+ ################################################################################
100
+ # Create-or-find via shell script (only when no existing_memory_id was given).
101
+ #
102
+ # The script produces JSON: `{"memory_id": "..."}`. Terraform re-runs it on
103
+ # every plan — if the memory already exists, the script returns the same ID
104
+ # without side effects. Inputs are passed as JSON on stdin; outputs MUST be
105
+ # a single JSON object on stdout for `data "external"` to parse.
106
+ ################################################################################
107
+
108
+ data "external" "memory" {
109
+ count = local.bootstrap ? 1 : 0
110
+ program = ["bash", "${path.module}/scripts/create_or_find_memory.sh"]
111
+
112
+ query = {
113
+ name = local.memory_name
114
+ region = var.region
115
+ execution_role_arn = aws_iam_role.memory_execution[0].arn
116
+ }
117
+ }
118
+
119
+ ################################################################################
120
+ # Destroy-time cleanup
121
+ #
122
+ # Terraform's `data "external"` has no destroy hook, so we use a paired
123
+ # `terraform_data` resource with a destroy-time local-exec that deletes the
124
+ # memory by ID. `triggers_replace` binds the resource to the memory ID so
125
+ # that replacing one memory correctly destroys the old one.
126
+ ################################################################################
127
+
128
+ resource "terraform_data" "memory_lifecycle" {
129
+ count = local.bootstrap ? 1 : 0
130
+
131
+ input = {
132
+ memory_id = data.external.memory[0].result.memory_id
133
+ region = var.region
134
+ }
135
+
136
+ triggers_replace = [
137
+ local.memory_name,
138
+ var.region,
139
+ ]
140
+
141
+ provisioner "local-exec" {
142
+ when = destroy
143
+ command = "aws bedrock-agentcore-control delete-memory --region ${self.output.region} --memory-id ${self.output.memory_id} || echo 'delete-memory failed (may already be gone)'"
144
+ }
145
+ }
146
+
147
+ ################################################################################
148
+ # Outputs
149
+ ################################################################################
150
+
151
+ output "memory_id" {
152
+ description = "Bedrock AgentCore Memory resource ID — passed into the agent container as AGENTCORE_MEMORY_ID"
153
+ value = local.bootstrap ? data.external.memory[0].result.memory_id : var.existing_memory_id
154
+ }
155
+
156
+ output "memory_name" {
157
+ description = "Logical name used for the memory resource"
158
+ value = local.memory_name
159
+ }
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env bash
2
+ ################################################################################
3
+ # create_or_find_memory.sh
4
+ #
5
+ # Idempotent create-or-find for a Bedrock AgentCore Memory resource, plus
6
+ # drift-correction for the strategy list on already-existing resources.
7
+ #
8
+ # Input (stdin, JSON):
9
+ # {"name": "<logical name>", "region": "<aws-region>",
10
+ # "execution_role_arn": "<optional>"}
11
+ # Output (stdout, JSON): {"memory_id": "<resource-id>"}
12
+ #
13
+ # Behavior:
14
+ # 1. Lists existing memories via `aws bedrock-agentcore-control list-memories`
15
+ # and matches by exact `name` OR by ID starting with `name-` (the API
16
+ # uses `{name}-{randomSuffix}` for the resource ID, and `name` sometimes
17
+ # comes back null on existing resources).
18
+ # 2. If a match exists: get-memory, diff its current strategies against the
19
+ # desired set, and call update-memory with addMemoryStrategies for any
20
+ # that are missing. This lets us add new strategies to an existing
21
+ # memory without destructive recreation.
22
+ # 3. If no match: create-memory with the full desired strategy list.
23
+ #
24
+ # Strategy set must match memory.py:STRATEGY_NAMESPACES exactly so the
25
+ # agent container's recall() finds records written by the extractors:
26
+ # semantic -> assistant_{actorId}
27
+ # preferences -> preferences_{actorId}
28
+ # summaries -> session_{sessionId}
29
+ # episodes -> episodes_{actorId}/{sessionId} (built-in episodicMemoryStrategy)
30
+ #
31
+ # Called from terraform/modules/app/agentcore-memory/main.tf via
32
+ # `data "external"`. Keep stdout strictly JSON — any stray echo will break
33
+ # Terraform's JSON parser. All diagnostics go to stderr.
34
+ ################################################################################
35
+
36
+ set -euo pipefail
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Input
40
+ # ---------------------------------------------------------------------------
41
+
42
+ input="$(cat)"
43
+ name="$(echo "$input" | jq -r '.name // empty')"
44
+ region="$(echo "$input" | jq -r '.region // empty')"
45
+ execution_role_arn="$(echo "$input" | jq -r '.execution_role_arn // empty')"
46
+
47
+ if [[ -z "$name" || -z "$region" ]]; then
48
+ echo '{"error": "name and region are required"}' >&2
49
+ exit 1
50
+ fi
51
+
52
+ # ---------------------------------------------------------------------------
53
+ # Desired strategy set
54
+ #
55
+ # The full list passed to create-memory. Each entry is also a valid item
56
+ # for update-memory's addMemoryStrategies list, so we can reuse the same
57
+ # shape for drift correction. `episodes` uses the built-in
58
+ # `episodicMemoryStrategy` type (NOT customMemoryStrategy — that was the
59
+ # bug that silently dropped episodes on the first deploy).
60
+ #
61
+ # IMPORTANT: episodicMemoryStrategy REQUIRES a reflectionConfiguration whose
62
+ # namespace is a prefix of the episodic namespace. If omitted, the API
63
+ # synthesizes a default reflection namespace of
64
+ # `/strategies/{memoryStrategyId}/actors/{actorId}/` which is NOT a prefix
65
+ # of our flat `episodes_{actorId}/{sessionId}` template, and update-memory
66
+ # fails with ValidationException. We set it to `episodes_{actorId}/` which
67
+ # IS a prefix and gives cross-session reflection records a stable home.
68
+ # ---------------------------------------------------------------------------
69
+
70
+ strategies_json='[
71
+ {
72
+ "semanticMemoryStrategy": {
73
+ "name": "semantic",
74
+ "namespaces": ["assistant_{actorId}"]
75
+ }
76
+ },
77
+ {
78
+ "userPreferenceMemoryStrategy": {
79
+ "name": "preferences",
80
+ "namespaces": ["preferences_{actorId}"]
81
+ }
82
+ },
83
+ {
84
+ "summaryMemoryStrategy": {
85
+ "name": "summaries",
86
+ "namespaces": ["session_{sessionId}"]
87
+ }
88
+ },
89
+ {
90
+ "episodicMemoryStrategy": {
91
+ "name": "episodes",
92
+ "namespaces": ["episodes_{actorId}/{sessionId}"],
93
+ "reflectionConfiguration": {
94
+ "namespaces": ["episodes_{actorId}/"]
95
+ }
96
+ }
97
+ }
98
+ ]'
99
+
100
+ # Map logical strategy name -> the top-level key used in the create/update
101
+ # payload. Used to drift-correct existing memory resources by picking out
102
+ # the entries whose names don't yet exist.
103
+ desired_names=("semantic" "preferences" "summaries" "episodes")
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # Step 1: look for an existing memory with this name
107
+ # ---------------------------------------------------------------------------
108
+
109
+ existing_id="$(
110
+ aws bedrock-agentcore-control list-memories \
111
+ --region "$region" \
112
+ --output json 2>/dev/null \
113
+ | jq -r --arg n "$name" '.memories[]? | select(.name == $n or (.id | startswith($n + "-"))) | .id' \
114
+ | head -n1 || true
115
+ )"
116
+
117
+ if [[ -n "$existing_id" && "$existing_id" != "null" ]]; then
118
+ # ---------------------------------------------------------------------------
119
+ # Step 2a: memory exists — drift-correct its strategy list
120
+ #
121
+ # Fetch current strategies, compute the set of desired strategy names that
122
+ # don't already exist, and call update-memory with addMemoryStrategies for
123
+ # the missing ones. This is idempotent — if everything matches, we call
124
+ # nothing and just return the existing ID.
125
+ # ---------------------------------------------------------------------------
126
+ current_names="$(
127
+ aws bedrock-agentcore-control get-memory \
128
+ --region "$region" \
129
+ --memory-id "$existing_id" \
130
+ --output json 2>/dev/null \
131
+ | jq -r '.memory.strategies[]? | .name'
132
+ )"
133
+
134
+ missing=()
135
+ for d in "${desired_names[@]}"; do
136
+ if ! grep -qxF "$d" <<<"$current_names"; then
137
+ missing+=("$d")
138
+ fi
139
+ done
140
+
141
+ if [[ ${#missing[@]} -gt 0 ]]; then
142
+ echo "[create_or_find_memory] existing memory $existing_id is missing strategies: ${missing[*]}" >&2
143
+
144
+ # Build the addMemoryStrategies list from the entries in strategies_json
145
+ # whose .name field matches a missing strategy.
146
+ add_json="$(
147
+ echo "$strategies_json" \
148
+ | jq --argjson wanted "$(printf '%s\n' "${missing[@]}" | jq -R . | jq -s .)" '
149
+ map(
150
+ select(
151
+ (.semanticMemoryStrategy.name // .userPreferenceMemoryStrategy.name //
152
+ .summaryMemoryStrategy.name // .episodicMemoryStrategy.name //
153
+ .customMemoryStrategy.name) as $n
154
+ | $wanted | index($n)
155
+ )
156
+ )
157
+ '
158
+ )"
159
+
160
+ update_payload="$(jq -nc --argjson add "$add_json" '{addMemoryStrategies: $add}')"
161
+
162
+ # update-memory takes memory-strategies as a structured object with
163
+ # add/modify/delete lists.
164
+ if aws bedrock-agentcore-control update-memory \
165
+ --region "$region" \
166
+ --memory-id "$existing_id" \
167
+ --memory-strategies "$update_payload" \
168
+ --output json >/dev/null 2>&1; then
169
+ echo "[create_or_find_memory] added missing strategies to $existing_id" >&2
170
+ else
171
+ # Capture the error for diagnostics but don't fail the whole apply —
172
+ # retention on the existing strategies still works.
173
+ err="$(aws bedrock-agentcore-control update-memory \
174
+ --region "$region" \
175
+ --memory-id "$existing_id" \
176
+ --memory-strategies "$update_payload" 2>&1 || true)"
177
+ echo "[create_or_find_memory] WARNING: update-memory failed: $err" >&2
178
+ fi
179
+ fi
180
+
181
+ jq -nc --arg id "$existing_id" '{memory_id: $id}'
182
+ exit 0
183
+ fi
184
+
185
+ # ---------------------------------------------------------------------------
186
+ # Step 2b: no existing memory — create one with the full strategy set
187
+ # ---------------------------------------------------------------------------
188
+
189
+ role_arg=""
190
+ if [[ -n "$execution_role_arn" ]]; then
191
+ role_arg="--memory-execution-role-arn $execution_role_arn"
192
+ fi
193
+
194
+ create_output="$(
195
+ aws bedrock-agentcore-control create-memory \
196
+ --region "$region" \
197
+ --name "$name" \
198
+ --memory-strategies "$strategies_json" \
199
+ --event-expiry-duration 365 \
200
+ $role_arg \
201
+ --output json
202
+ )"
203
+
204
+ new_id="$(echo "$create_output" | jq -r '.memory.id // .id')"
205
+
206
+ if [[ -z "$new_id" || "$new_id" == "null" ]]; then
207
+ echo '{"error": "create-memory returned no id"}' >&2
208
+ echo "create-memory output was: $create_output" >&2
209
+ exit 1
210
+ fi
211
+
212
+ jq -nc --arg id "$new_id" '{memory_id: $id}'
@@ -26,20 +26,14 @@ variable "bucket_name" {
26
26
  type = string
27
27
  }
28
28
 
29
- variable "memory_engine" {
30
- description = "Memory engine: 'managed' or 'hindsight'. Passed as MEMORY_ENGINE env var to the container."
31
- type = string
32
- default = "managed"
33
- }
34
-
35
29
  variable "hindsight_endpoint" {
36
- description = "Hindsight API endpoint (only used when memory_engine = 'hindsight')"
30
+ description = "Hindsight API endpoint. Empty string (default) disables Hindsight tools in the container; set to an endpoint URL to enable Hindsight as an add-on alongside the always-on managed memory."
37
31
  type = string
38
32
  default = ""
39
33
  }
40
34
 
41
35
  variable "agentcore_memory_id" {
42
- description = "AgentCore Memory resource ID (only used when memory_engine = 'managed')"
36
+ description = "AgentCore Memory resource ID. Populated automatically by the agentcore-memory module; injected into the container as AGENTCORE_MEMORY_ID for auto-retention."
43
37
  type = string
44
38
  default = ""
45
39
  }
@@ -120,6 +114,25 @@ resource "aws_iam_role_policy" "agentcore" {
120
114
  Action = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", "bedrock:InvokeAgent"]
121
115
  Resource = "arn:aws:bedrock:${var.region}::foundation-model/*"
122
116
  },
117
+ {
118
+ # Automatic memory retention — every agent turn calls CreateEvent
119
+ # to feed AgentCore's background strategies. Also needs read access
120
+ # so the recall() tool can fetch previously extracted records and
121
+ # so forget() can soft-archive old records.
122
+ Sid = "AgentCoreMemoryReadWrite"
123
+ Effect = "Allow"
124
+ Action = [
125
+ "bedrock-agentcore:CreateEvent",
126
+ "bedrock-agentcore:ListEvents",
127
+ "bedrock-agentcore:GetEvent",
128
+ "bedrock-agentcore:ListMemoryRecords",
129
+ "bedrock-agentcore:RetrieveMemoryRecords",
130
+ "bedrock-agentcore:GetMemoryRecord",
131
+ "bedrock-agentcore:BatchCreateMemoryRecords",
132
+ "bedrock-agentcore:BatchUpdateMemoryRecords",
133
+ ]
134
+ Resource = "*"
135
+ },
123
136
  {
124
137
  Sid = "CloudWatchLogs"
125
138
  Effect = "Allow"
@@ -177,7 +190,6 @@ resource "aws_lambda_function" "agentcore" {
177
190
  variables = {
178
191
  PORT = "8080"
179
192
  AWS_LWA_PORT = "8080"
180
- MEMORY_ENGINE = var.memory_engine
181
193
  AGENTCORE_MEMORY_ID = var.agentcore_memory_id
182
194
  AGENTCORE_FILES_BUCKET = var.bucket_name
183
195
  }
@@ -193,10 +205,9 @@ resource "aws_lambda_function" "agentcore" {
193
205
  }
194
206
  }
195
207
 
196
- resource "aws_lambda_function_url" "agentcore" {
197
- function_name = aws_lambda_function.agentcore.function_name
198
- authorization_type = "NONE"
199
- }
208
+ # AgentCore is invoked directly via the Lambda SDK (InvokeCommand) from
209
+ # chat-agent-invoke — no Function URL is needed, and exposing one would be
210
+ # a public attack surface for prompt injection.
200
211
 
201
212
  ################################################################################
202
213
  # Outputs
@@ -212,12 +223,12 @@ output "execution_role_arn" {
212
223
  value = aws_iam_role.agentcore.arn
213
224
  }
214
225
 
215
- output "agentcore_invoke_url" {
216
- description = "Lambda Function URL for the AgentCore container"
217
- value = aws_lambda_function_url.agentcore.function_url
218
- }
219
-
220
226
  output "agentcore_function_name" {
221
227
  description = "AgentCore Lambda function name (for direct SDK invoke)"
222
228
  value = aws_lambda_function.agentcore.function_name
223
229
  }
230
+
231
+ output "agentcore_function_arn" {
232
+ description = "AgentCore Lambda function ARN (for IAM policy on callers)"
233
+ value = aws_lambda_function.agentcore.arn
234
+ }