thinkwork-cli 0.13.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +3 -14
  2. package/dist/{api-client-JYZXYQJR.js → api-client-4P4JZOBX.js} +1 -1
  3. package/dist/{chunk-Z2F6RJFR.js → chunk-4OMDWYZQ.js} +4 -5
  4. package/dist/{chunk-ILZKG5WV.js → chunk-AD2NIWB5.js} +434 -69
  5. package/dist/chunk-MWQ7RO76.js +137 -0
  6. package/dist/{chunk-DVPBI5HM.js → chunk-OLUQ4U2Z.js} +26 -26
  7. package/dist/{chunk-QOERT44A.js → chunk-YQCYD6NE.js} +57 -44
  8. package/dist/cli.js +4400 -16431
  9. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
  10. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
  11. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
  12. package/dist/{dist-es-CRV46D5B.js → dist-es-2OTNTL4N.js} +4 -4
  13. package/dist/{dist-es-ENBUC3JP.js → dist-es-2XVAH4BQ.js} +2 -2
  14. package/dist/{dist-es-DCY4IC3Y.js → dist-es-3DPDUJAH.js} +2 -2
  15. package/dist/{dist-es-G7PTG75M.js → dist-es-BNZTBBVC.js} +1 -1
  16. package/dist/{dist-es-GKDBE7E6.js → dist-es-CD2RBDAC.js} +1 -1
  17. package/dist/{dist-es-R7FGL2IB.js → dist-es-I4FW57PS.js} +1 -1
  18. package/dist/{dist-es-USORBXZ5.js → dist-es-KVFWJNDY.js} +4 -4
  19. package/dist/{dist-es-HY3535OI.js → dist-es-PS73DWNL.js} +2 -2
  20. package/dist/{dist-es-LDE437AM.js → dist-es-S3NZQFGT.js} +1 -1
  21. package/dist/{dist-es-G54LBMRN.js → dist-es-SGCA4P32.js} +1 -1
  22. package/dist/{dist-es-Q57SZXZ7.js → dist-es-WBM6J4RA.js} +2 -2
  23. package/dist/{dist-es-P26FWFLT.js → dist-es-ZGVADYIF.js} +8 -8
  24. package/dist/drizzle/0227_analyst_reader_role.sql +17 -26
  25. package/dist/drizzle/0230_analyst_rls.sql +28 -45
  26. package/dist/drizzle/0261_native_auth_control_plane.sql +7 -3
  27. package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
  28. package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
  29. package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
  30. package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
  31. package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
  32. package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
  33. package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
  34. package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
  35. package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
  36. package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
  37. package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
  38. package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
  39. package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
  40. package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
  41. package/dist/drizzle/0284_user_brain_claims.sql +69 -0
  42. package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
  43. package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
  44. package/dist/drizzle/0287_brain_subject.sql +25 -0
  45. package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
  46. package/dist/{loadSso-DJVB7BXE.js → loadSso-ETCXTR4I.js} +2 -2
  47. package/dist/{loadSso-JAMNA3WY.js → loadSso-UBD7KUHE.js} +2 -2
  48. package/dist/plugins/README.md +2 -2
  49. package/dist/plugins/catalog/package.json +0 -3
  50. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -3
  51. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
  52. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -25
  53. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -6
  54. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -15
  55. package/dist/plugins/catalog/src/contracts.ts +15 -0
  56. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -18
  57. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
  58. package/dist/plugins/twenty/package.json +2 -1
  59. package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
  60. package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
  61. package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
  62. package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
  63. package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
  64. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
  65. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
  66. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
  67. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
  68. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
  69. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
  70. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
  71. package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
  72. package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
  73. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
  74. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
  75. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
  76. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
  77. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
  78. package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
  79. package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
  80. package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
  81. package/dist/plugins/twenty/test/manifest.test.ts +2 -4
  82. package/dist/scripts/post-deploy.sh +79 -1
  83. package/dist/{signin-UGDWTGS4.js → signin-5QZNRSOO.js} +2 -2
  84. package/dist/{sso-oidc-Q4VXANXY.js → sso-oidc-XK673P54.js} +2 -2
  85. package/dist/{sts-CWLSE3GH.js → sts-OXI2UALF.js} +6 -134
  86. package/dist/{sts-DNZLNVOV.js → sts-SQW4NBK3.js} +6 -134
  87. package/dist/terraform/examples/greenfield/main.tf +233 -175
  88. package/dist/terraform/examples/greenfield/terraform.tfvars.example +12 -8
  89. package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
  90. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
  91. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
  92. package/dist/terraform/modules/app/agentcore-identity/main.tf +106 -26
  93. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +6 -6
  94. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +216 -99
  95. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +6 -9
  96. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
  97. package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
  98. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +22 -7
  99. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +17 -46
  100. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +65 -3
  101. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
  102. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
  103. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
  104. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
  105. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
  106. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
  107. package/dist/terraform/modules/app/agentcore-identity/variables.tf +6 -0
  108. package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
  109. package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
  110. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
  111. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  112. package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
  113. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
  114. package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
  115. package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
  116. package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
  117. package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
  118. package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
  119. package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
  120. package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
  121. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
  122. package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
  123. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
  124. package/dist/terraform/modules/app/deployment-control-plane/runner.py +2641 -124
  125. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2034 -154
  126. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
  127. package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
  128. package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
  129. package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
  130. package/dist/terraform/modules/app/lambda-api/handlers.tf +411 -723
  131. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +262 -198
  132. package/dist/terraform/modules/app/lambda-api/main.tf +51 -13
  133. package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +4 -181
  134. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
  135. package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
  136. package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -45
  137. package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
  138. package/dist/terraform/modules/app/lambda-api/variables.tf +219 -126
  139. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
  140. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
  141. package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
  142. package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
  143. package/dist/terraform/modules/app/static-site/main.tf +1 -1
  144. package/dist/terraform/modules/app/www-dns/main.tf +9 -27
  145. package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
  146. package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
  147. package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
  148. package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
  149. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
  150. package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
  151. package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
  152. package/dist/terraform/modules/foundation/cognito/main.tf +81 -8
  153. package/dist/terraform/modules/foundation/cognito/outputs.tf +5 -0
  154. package/dist/terraform/modules/foundation/cognito/variables.tf +24 -12
  155. package/dist/terraform/modules/thinkwork/README.md +5 -1
  156. package/dist/terraform/modules/thinkwork/main.tf +376 -374
  157. package/dist/terraform/modules/thinkwork/outputs.tf +12 -158
  158. package/dist/terraform/modules/thinkwork/variables.tf +246 -89
  159. package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
  160. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
  161. package/dist/workspace-defaults/files/ROUTER.md +1 -1
  162. package/dist/workspace-defaults/files/TOOLS.md +9 -39
  163. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
  164. package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
  165. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
  166. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  167. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  168. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
  169. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
  170. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
  171. package/package.json +1 -1
  172. package/dist/drizzle/0261_managed_harness_multiplayer.sql +0 -313
  173. package/dist/drizzle/0262_parallel_harness_threads.sql +0 -9
  174. package/dist/drizzle/0264_harness_tool_execution_ledger.sql +0 -113
  175. package/dist/plugins/company-data/README.md +0 -49
  176. package/dist/plugins/company-data/package.json +0 -21
  177. package/dist/plugins/company-data/src/index.ts +0 -30
  178. package/dist/plugins/company-data/src/manifest.ts +0 -26
  179. package/dist/plugins/company-data/test/manifest.test.ts +0 -116
  180. package/dist/plugins/company-data/tsconfig.json +0 -8
  181. package/dist/plugins/company-etl/README.md +0 -46
  182. package/dist/plugins/company-etl/package.json +0 -21
  183. package/dist/plugins/company-etl/src/index.ts +0 -29
  184. package/dist/plugins/company-etl/src/manifest.ts +0 -26
  185. package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
  186. package/dist/plugins/company-etl/tsconfig.json +0 -8
  187. package/dist/plugins/lastmile/README.md +0 -50
  188. package/dist/plugins/lastmile/package.json +0 -23
  189. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
  190. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
  191. package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
  192. package/dist/plugins/lastmile/src/index.ts +0 -46
  193. package/dist/plugins/lastmile/src/manifest.ts +0 -139
  194. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
  195. package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
  196. package/dist/plugins/lastmile/tsconfig.json +0 -8
  197. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
  198. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
  199. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
  200. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
  201. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
  202. package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
  203. package/dist/terraform/modules/app/agentcore-gateway/main.tf +0 -305
  204. package/dist/terraform/modules/app/agentcore-gateway/outputs.tf +0 -44
  205. package/dist/terraform/modules/app/agentcore-gateway/scripts/delete_gateway.sh +0 -93
  206. package/dist/terraform/modules/app/agentcore-gateway/scripts/read_gateway.sh +0 -33
  207. package/dist/terraform/modules/app/agentcore-gateway/scripts/reconcile_gateway.sh +0 -543
  208. package/dist/terraform/modules/app/agentcore-gateway/variables.tf +0 -70
  209. package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -330
  210. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -72
  211. package/dist/terraform/modules/app/agentcore-harness/scripts/delete_harness.sh +0 -5
  212. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-lifecycle.mjs +0 -430
  213. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-readback.mjs +0 -180
  214. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-tool-contract.mjs +0 -193
  215. package/dist/terraform/modules/app/agentcore-harness/scripts/prune_harness.sh +0 -5
  216. package/dist/terraform/modules/app/agentcore-harness/scripts/read_harness.sh +0 -5
  217. package/dist/terraform/modules/app/agentcore-harness/scripts/reconcile_harness.sh +0 -5
  218. package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -96
  219. package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
  220. package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
  221. package/dist/terraform/modules/app/lambda-api/agentcore-harness-alarms.tf +0 -88
  222. package/dist/terraform/modules/app/lambda-api/agentcore-identity-alarms.tf +0 -91
  223. package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
  224. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
  225. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
  226. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
  227. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
  228. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
  229. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
  230. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
  231. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
@@ -0,0 +1,8 @@
1
+ resource "terraform_data" "twenty_identity_reconciliation" {
2
+ count = 1
3
+ input = "new-idempotent-reconciliation-marker"
4
+
5
+ provisioner "local-exec" {
6
+ command = "printf '%s\\n' reconciled > '${path.root}/reconciled.log'"
7
+ }
8
+ }
@@ -0,0 +1,9 @@
1
+ resource "terraform_data" "twenty_identity_lifecycle" {
2
+ count = 1
3
+ input = "legacy-state-only-marker"
4
+
5
+ provisioner "local-exec" {
6
+ when = destroy
7
+ command = "printf '%s\\n' destroyed > '${path.root}/destroyed.log'"
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ module "agentcore_proof_identity" {
2
+ source = "./agentcore-identity"
3
+ }
@@ -0,0 +1,3 @@
1
+ module "agentcore_proof_identity" {
2
+ source = "./agentcore-identity"
3
+ }
@@ -4,6 +4,12 @@ variable "enabled" {
4
4
  default = false
5
5
  }
6
6
 
7
+ variable "twenty_enabled" {
8
+ description = "THINK-324 — keep the Twenty CRM user-federation identity (shared workload identity, twenty-crm credential provider, DCR client secret) alive independent of the proof plane, so retiring the managed-harness proof (enabled = false) does not destroy the live Twenty connector."
9
+ type = bool
10
+ default = false
11
+ }
12
+
7
13
  variable "stage" {
8
14
  description = "Deployment stage."
9
15
  type = string
@@ -10,12 +10,24 @@ the ThinkWork AgentCore runtime uses for automatic retention:
10
10
  | summaries | `session_{sessionId}` | Per-thread rolling summaries |
11
11
  | episodes | `episodes_{actorId}/{sessionId}` | Episodic memory of past interactions |
12
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.
13
+ Automatic retention is wired through the API's normalized memory layer:
14
+ every turn emits a `CreateEvent` (`AgentCoreAdapter.retainTurn`, actor =
15
+ the user UUID), and AgentCore's background strategies extract facts into
16
+ the namespaces above. Agents read them back via the `recall()` tool, which
17
+ fans out over `assistant_{actorId}`, `preferences_{actorId}` and
18
+ `user_{actorId}`. There is no need for the model to call `remember()`
19
+ explicitly — it only exists for user-driven "please remember X" requests,
20
+ and writes direct records into `user_{actorId}`.
21
+
22
+ **The namespace templates above are a contract**, not an implementation
23
+ detail. Readers that must stay in sync:
24
+
25
+ - `packages/api/src/lib/memory/adapters/agentcore-adapter.ts` (`ACTOR_NAMESPACES`)
26
+ - `packages/agentcore-pi/agent-container/src/tools/memory.ts` (`recallNamespaces`)
27
+
28
+ Changing a template here without changing those makes extraction write
29
+ where nothing reads — silent, and invisible until someone notices the
30
+ agent has amnesia.
19
31
 
20
32
  ## Usage
21
33
 
@@ -42,12 +54,37 @@ The AWS Terraform provider does not (yet) expose a
42
54
  `aws_bedrockagentcore_memory` resource. Until it does, this module drives
43
55
  the lifecycle through the `aws bedrock-agentcore-control` CLI:
44
56
 
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.
57
+ - **Ensure**: `data "external"` runs `scripts/create_or_find_memory.sh` on
58
+ every plan and apply. It pages through `list-memories` for candidates
59
+ matching the logical name, probes each one with `get-memory`, and uses the
60
+ first that is ACTIVE (waiting out a `CREATING` one). Safe to re-run.
48
61
  - **Destroy**: a paired `terraform_data` resource has a destroy-time
49
62
  `local-exec` that calls `delete-memory` on the ID captured during create.
50
63
 
64
+ ## Self-healing
65
+
66
+ The memory ID this module outputs comes from a **live lookup on every
67
+ plan**, never from stored state. If the memory resource is deleted
68
+ out-of-band — as happened to `dev` in THINK-404, where SSM still advertised
69
+ `AGENTCORE_MEMORY_ID` for a resource `GetMemory` returned
70
+ `ResourceNotFound` for — the next plan sees the ID no longer resolves and
71
+ the next apply creates a replacement with the same strategy set, waits for
72
+ it to reach `ACTIVE`, and rewires the runtime to it. No import, no state
73
+ surgery, no manual `create-memory`.
74
+
75
+ Two invariants keep that safe:
76
+
77
+ - **The ensure path never deletes.** Candidates in `DELETING` or `FAILED`
78
+ are skipped, not cleaned up. Deletion happens only through the
79
+ destroy-time provisioner.
80
+ - **Healing is not a replacement.** The destroy provisioner's
81
+ `triggers_replace` is keyed on the memory name and region, not the ID, so
82
+ recovering a new ID for the same logical memory can't fire a delete.
83
+
84
+ The cost of healing is the records: a recreated memory starts empty.
85
+ Extraction refills it from subsequent conversations; nothing recovers the
86
+ old records, because AgentCore has no export of a deleted memory.
87
+
51
88
  When the AWS provider adds a native resource, migrate by importing the
52
89
  existing memory ID into the new resource and removing this module's
53
90
  external data source.
@@ -10,11 +10,18 @@
10
10
  #
11
11
  # **Why not a first-class resource?** The AWS provider does not (yet) expose a
12
12
  # `aws_bedrockagentcore_memory` resource type. Until it does, we drive the
13
- # create/find/destroy lifecycle through the `aws bedrock-agentcore-control`
13
+ # ensure/destroy lifecycle through the `aws bedrock-agentcore-control`
14
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.
15
+ # Terraform via `data "external"`.
16
+ #
17
+ # **Self-healing.** The script is an *ensure*, not a one-shot create: it
18
+ # probes the live resource on every plan and every apply, and recreates it
19
+ # when it has gone missing. That matters because Terraform state can hold a
20
+ # memory ID whose resource was deleted out-of-band (THINK-404 found dev in
21
+ # exactly that state — SSM advertised a memory ID that GetMemory 404'd on,
22
+ # and nothing in the module ever re-checked). The module output therefore
23
+ # reflects the memory that actually exists right now, not the one state
24
+ # remembers.
18
25
  #
19
26
  # **BYO override:** If you already have an AgentCore Memory resource, set
20
27
  # `var.existing_memory_id` to skip provisioning. The module output will echo
@@ -97,12 +104,15 @@ resource "aws_iam_role_policy" "memory_execution" {
97
104
  }
98
105
 
99
106
  ################################################################################
100
- # Create-or-find via shell script (only when no existing_memory_id was given).
107
+ # Ensure via shell script (only when no existing_memory_id was given).
101
108
  #
102
109
  # 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.
110
+ # every plan — if an ACTIVE memory with this name already exists, the script
111
+ # returns that same ID and only drift-corrects its strategy list; if the
112
+ # memory is missing, unresolvable, or DELETING/FAILED, the script creates a
113
+ # replacement and waits for it to reach ACTIVE. It never deletes anything.
114
+ # Inputs are passed as JSON on stdin; outputs MUST be a single JSON object
115
+ # on stdout for `data "external"` to parse.
106
116
  ################################################################################
107
117
 
108
118
  data "external" "memory" {
@@ -121,8 +131,15 @@ data "external" "memory" {
121
131
  #
122
132
  # Terraform's `data "external"` has no destroy hook, so we use a paired
123
133
  # `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.
134
+ # memory by ID.
135
+ #
136
+ # `triggers_replace` is deliberately keyed on the memory *name* and region,
137
+ # NOT on the memory ID. Keying it on the ID would turn every self-heal (new
138
+ # ID for the same logical memory) into a replacement, firing the destroy
139
+ # provisioner against the ID the heal just recovered from — at best a no-op
140
+ # delete of an already-gone resource, at worst a delete of the freshly
141
+ # created one. Renaming or re-regioning the memory is a real replacement and
142
+ # still destroys the old resource; healing is an in-place `input` update.
126
143
  ################################################################################
127
144
 
128
145
  resource "terraform_data" "memory_lifecycle" {
@@ -2,8 +2,9 @@
2
2
  ################################################################################
3
3
  # create_or_find_memory.sh
4
4
  #
5
- # Idempotent create-or-find for a Bedrock AgentCore Memory resource, plus
6
- # drift-correction for the strategy list on already-existing resources.
5
+ # Idempotent **ensure** for a Bedrock AgentCore Memory resource: guarantee
6
+ # that an ACTIVE memory with the desired strategy set exists, and return its
7
+ # live ID. Runs on every plan and every apply.
7
8
  #
8
9
  # Input (stdin, JSON):
9
10
  # {"name": "<logical name>", "region": "<aws-region>",
@@ -11,18 +12,34 @@
11
12
  # Output (stdout, JSON): {"memory_id": "<resource-id>"}
12
13
  #
13
14
  # 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.
15
+ # 1. Pages through `aws bedrock-agentcore-control list-memories` and
16
+ # collects candidates matching by exact `name` OR by ID starting with
17
+ # `name-` (the API uses `{name}-{randomSuffix}` for the resource ID,
18
+ # and `name` sometimes comes back null on existing resources).
19
+ # 2. Probes each candidate with `get-memory`, which is the authoritative
20
+ # answer. A candidate is usable only if get-memory succeeds AND its
21
+ # status is ACTIVE (a CREATING memory is waited out). Candidates that
22
+ # 404, or that report DELETING / FAILED, are skipped.
23
+ # 3. Usable candidate: diff its current strategies against the desired set
24
+ # and `update-memory` with addMemoryStrategies for any that are missing.
25
+ # Adds new strategies without destructive recreation.
26
+ # 4. No usable candidate: `create-memory` with the full desired strategy
27
+ # list, then wait for ACTIVE.
23
28
  #
24
- # Strategy set must match memory.py:STRATEGY_NAMESPACES exactly so the
25
- # agent container's recall() finds records written by the extractors:
29
+ # **Self-healing (THINK-404).** The dev memory was deleted out from under
30
+ # Terraform while state still held its ID, so every runtime read 404'd until
31
+ # a human noticed. Steps 1-2 are what make that unrecoverable-by-hand state
32
+ # impossible: the ID is re-derived from a live probe on every plan, so a
33
+ # missing or dying memory is simply recreated on the next apply and the
34
+ # module output tracks the resource that actually exists. The probe never
35
+ # deletes anything — teardown remains the exclusive job of the destroy-time
36
+ # provisioner in main.tf, whose `triggers_replace` deliberately does NOT
37
+ # include the memory ID so healing can't cascade into a delete.
38
+ #
39
+ # Strategy set must match the namespaces read by
40
+ # `packages/api/src/lib/memory/adapters/agentcore-adapter.ts` and
41
+ # `packages/agentcore-pi/agent-container/src/tools/memory.ts` so recall
42
+ # finds records written by the extractors:
26
43
  # semantic -> assistant_{actorId}
27
44
  # preferences -> preferences_{actorId}
28
45
  # summaries -> session_{sessionId}
@@ -30,7 +47,8 @@
30
47
  #
31
48
  # Called from terraform/modules/app/agentcore-memory/main.tf via
32
49
  # `data "external"`. Keep stdout strictly JSON — any stray echo will break
33
- # Terraform's JSON parser. All diagnostics go to stderr.
50
+ # Terraform's JSON parser. All diagnostics go to stderr. Dependencies are
51
+ # bash, `aws`, and `jq` only, because this runs on the CI runner.
34
52
  ################################################################################
35
53
 
36
54
  set -euo pipefail
@@ -103,18 +121,123 @@ strategies_json='[
103
121
  desired_names=("semantic" "preferences" "summaries" "episodes")
104
122
 
105
123
  # ---------------------------------------------------------------------------
106
- # Step 1: look for an existing memory with this name
124
+ # Helpers
107
125
  # ---------------------------------------------------------------------------
108
126
 
109
- existing_id="$(
110
- aws bedrock-agentcore-control list-memories \
127
+ # Echo the memory's status, or nothing at all when get-memory fails (the
128
+ # resource is gone). get-memory — not the list output — is the authority:
129
+ # list-memories has been observed returning IDs that no longer resolve.
130
+ memory_status() {
131
+ local id="$1" out
132
+ # `|| true` twice, deliberately: under `set -e -o pipefail` a failing
133
+ # get-memory (i.e. the memory is gone — the case this whole function
134
+ # exists to detect) would otherwise abort the script through the command
135
+ # substitution that calls it.
136
+ out="$(aws bedrock-agentcore-control get-memory \
111
137
  --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
- )"
138
+ --memory-id "$id" \
139
+ --output json 2>/dev/null || true)"
140
+ jq -r '.memory.status // empty' <<<"$out" 2>/dev/null || true
141
+ return 0
142
+ }
143
+
144
+ # Block until the memory reports ACTIVE. Returns non-zero if it never gets
145
+ # there (deleted mid-wait, stuck in FAILED, or the wait budget expires).
146
+ # ~5 minutes: creation is normally well under a minute.
147
+ wait_for_active() {
148
+ local id="$1"
149
+ local status
150
+ for _ in $(seq 1 30); do
151
+ status="$(memory_status "$id")"
152
+ case "$status" in
153
+ ACTIVE) return 0 ;;
154
+ "" | FAILED | DELETING)
155
+ echo "[create_or_find_memory] $id is ${status:-gone}; not usable" >&2
156
+ return 1
157
+ ;;
158
+ *)
159
+ echo "[create_or_find_memory] $id is $status; waiting for ACTIVE" >&2
160
+ sleep 10
161
+ ;;
162
+ esac
163
+ done
164
+ echo "[create_or_find_memory] timed out waiting for $id to become ACTIVE" >&2
165
+ return 1
166
+ }
167
+
168
+ # ---------------------------------------------------------------------------
169
+ # Step 1: find a live memory with this name
170
+ #
171
+ # Paginated so a large account can't hide the existing resource behind a
172
+ # page boundary and trick us into creating a duplicate. Every candidate is
173
+ # probed with get-memory before it is trusted — that probe is what heals a
174
+ # memory that was deleted behind Terraform's back.
175
+ # ---------------------------------------------------------------------------
176
+
177
+ candidate_ids=()
178
+ next_token=""
179
+ list_err="$(mktemp)"
180
+ trap 'rm -f "$list_err"' EXIT
181
+ while :; do
182
+ set +e
183
+ if [[ -n "$next_token" ]]; then
184
+ page="$(aws bedrock-agentcore-control list-memories \
185
+ --region "$region" --max-results 100 --next-token "$next_token" \
186
+ --output json 2>"$list_err")"
187
+ else
188
+ page="$(aws bedrock-agentcore-control list-memories \
189
+ --region "$region" --max-results 100 \
190
+ --output json 2>"$list_err")"
191
+ fi
192
+ list_status=$?
193
+ set -e
194
+ # Fail loudly rather than treating an API error as "no memories exist" —
195
+ # that misreading would create a duplicate memory alongside the healthy
196
+ # one and silently split the tenant's records across two resources.
197
+ if [[ $list_status -ne 0 ]]; then
198
+ echo '{"error": "list-memories failed"}' >&2
199
+ cat "$list_err" >&2
200
+ exit "$list_status"
201
+ fi
202
+
203
+ while IFS= read -r id; do
204
+ [[ -n "$id" ]] && candidate_ids+=("$id")
205
+ done < <(
206
+ jq -r --arg n "$name" \
207
+ '.memories[]? | select(.name == $n or ((.id // "") | startswith($n + "-"))) | .id' \
208
+ <<<"$page"
209
+ )
210
+
211
+ next_token="$(jq -r '.nextToken // empty' <<<"$page")"
212
+ [[ -z "$next_token" ]] && break
213
+ done
116
214
 
117
- if [[ -n "$existing_id" && "$existing_id" != "null" ]]; then
215
+ existing_id=""
216
+ for candidate in ${candidate_ids[@]+"${candidate_ids[@]}"}; do
217
+ status="$(memory_status "$candidate")"
218
+ case "$status" in
219
+ ACTIVE)
220
+ existing_id="$candidate"
221
+ break
222
+ ;;
223
+ CREATING)
224
+ if wait_for_active "$candidate"; then
225
+ existing_id="$candidate"
226
+ break
227
+ fi
228
+ ;;
229
+ "")
230
+ # Listed but unresolvable: the resource was deleted out from under us
231
+ # (exactly the state THINK-404 found dev in). Fall through to create.
232
+ echo "[create_or_find_memory] listed memory $candidate no longer exists; will recreate" >&2
233
+ ;;
234
+ *)
235
+ echo "[create_or_find_memory] skipping $candidate in status $status" >&2
236
+ ;;
237
+ esac
238
+ done
239
+
240
+ if [[ -n "$existing_id" ]]; then
118
241
  # ---------------------------------------------------------------------------
119
242
  # Step 2a: memory exists — drift-correct its strategy list
120
243
  #
@@ -128,7 +251,7 @@ if [[ -n "$existing_id" && "$existing_id" != "null" ]]; then
128
251
  --region "$region" \
129
252
  --memory-id "$existing_id" \
130
253
  --output json 2>/dev/null \
131
- | jq -r '.memory.strategies[]? | .name'
254
+ | jq -r '.memory.strategies[]? | .name' || true
132
255
  )"
133
256
 
134
257
  missing=()
@@ -200,7 +323,7 @@ fi
200
323
  create_output=""
201
324
  create_status=1
202
325
  err_file="$(mktemp)"
203
- trap 'rm -f "$err_file"' EXIT
326
+ trap 'rm -f "$err_file" "$list_err"' EXIT
204
327
  for attempt in $(seq 1 12); do
205
328
  set +e
206
329
  create_output="$(
@@ -240,4 +363,13 @@ if [[ -z "$new_id" || "$new_id" == "null" ]]; then
240
363
  exit 1
241
364
  fi
242
365
 
366
+ # Don't hand Terraform an ID the runtime can't use yet: a memory in CREATING
367
+ # rejects CreateEvent, and downstream SSM/runtime wiring is written in the
368
+ # same apply.
369
+ if ! wait_for_active "$new_id"; then
370
+ echo '{"error": "created memory never became ACTIVE"}' >&2
371
+ exit 1
372
+ fi
373
+
374
+ echo "[create_or_find_memory] created memory $new_id" >&2
243
375
  jq -nc --arg id "$new_id" '{memory_id: $id}'
@@ -8,7 +8,7 @@ This module owns the dedicated Pi Lambda + log group + IAM role + event-invoke c
8
8
 
9
9
  - `aws_iam_role.agentcore_pi` (`thinkwork-${stage}-agentcore-pi-role`) — assumed by Lambda + Bedrock AgentCore Runtime principals.
10
10
  - `aws_iam_role_policy.agentcore_pi` — baseline permissions (S3 skill catalog, Bedrock model invoke, AgentCore Memory + Code Interpreter, CloudWatch Logs, X-Ray ingestion, ECR pull, SSM parameter access, memory-retain Lambda invoke). Forward-compat additions for U4-U8: Aurora Data API + Secrets Manager scoped to `thinkwork-${stage}-*`.
11
- - `aws_iam_role_policy_attachment.agentcore_pi_vpc_access` — attached when Pi needs private-network access for the OKF EFS mount.
11
+ - `aws_iam_role_policy_attachment.agentcore_pi_vpc_access` — retired (THINK-589): the OKF wiki EFS mount is removed, Pi is not VPC-attached, and the attachment is conditioned off pending deletion in the follow-up PR.
12
12
  - `aws_iam_role_policy.agentcore_pi_dlq_send` — `sqs:SendMessage` against the shared async DLQ (injected via `var.async_dlq_arn`).
13
13
  - `aws_cloudwatch_log_group.agentcore_pi` (`/thinkwork/${stage}/agentcore-pi`).
14
14
  - `aws_lambda_function.agentcore_pi` (`thinkwork-${stage}-agentcore-pi`) — `package_type = "Image"`, pulls `${ecr_repository_url}:pi-latest`.
@@ -43,11 +43,9 @@ The Lambda function name changes from `thinkwork-${stage}-agentcore-flue` to `th
43
43
  | `bucket_name` | yes | Primary S3 bucket for skills + workspace files. |
44
44
  | `ecr_repository_url` | yes | Shared ECR repo URL from `module.agentcore_platform.ecr_repository_url`. |
45
45
  | `async_dlq_arn` | yes | Shared async DLQ ARN from `module.agentcore_platform.agentcore_async_dlq_arn`. |
46
- | `hindsight_endpoint` | no | Hindsight API endpoint when enabled; empty disables Hindsight tools. |
47
46
  | `agentcore_memory_id` | no | AgentCore Memory resource ID for auto-retention. |
48
47
  | `api_endpoint` | no | API Gateway base URL for the `/api/skills/complete` callback. |
49
48
  | `api_auth_secret` | no | Service-auth bearer for the same callback. |
50
- | `memory_engine` | no | `hindsight` or `agentcore`; surfaced as `MEMORY_ENGINE` env var. |
51
49
 
52
50
  ## Outputs
53
51
 
@@ -26,34 +26,19 @@ locals {
26
26
  chat_agent_activity_fn_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:${local.chat_agent_activity_fn_name}"
27
27
  manifest_log_fn_name = "thinkwork-${var.stage}-api-manifest-log"
28
28
  manifest_log_fn_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:${local.manifest_log_fn_name}"
29
- # THINK-280 U2 — capability control plane service (capability_search /
30
- # connection_research Pi tools). Direct InvokeCommand, RequestResponse;
31
- # no HTTP route exists for this Lambda.
32
- capability_control_fn_name = "thinkwork-${var.stage}-api-capability-control-service"
33
- capability_control_fn_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:${local.capability_control_fn_name}"
29
+ tool_executions_fn_name = "thinkwork-${var.stage}-api-tool-executions"
30
+ tool_executions_fn_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:${local.tool_executions_fn_name}"
34
31
  # Release-backed deployments use an immutable, source-derived target tag so
35
32
  # changing the release image also changes aws_lambda_function.image_uri.
36
33
  # Reusing pi-latest lets Terraform miss the update even after ECR is retagged.
37
- pi_image_tag = var.source_image_uri != "" ? "pi-${substr(sha256(var.source_image_uri), 0, 16)}" : "pi-latest"
38
- pi_image_uri = "${var.ecr_repository_url}:${local.pi_image_tag}"
39
- okf_efs_vpc_enabled = var.okf_efs_enabled && length(var.okf_efs_subnet_ids) > 0 && length(var.okf_efs_security_group_ids) > 0
40
- private_vpc_enabled = local.okf_efs_vpc_enabled
41
- private_subnet_ids = var.okf_efs_subnet_ids
42
- private_security_group_ids = var.okf_efs_security_group_ids
43
- okf_efs_mount_enabled = local.okf_efs_vpc_enabled && var.okf_efs_file_system_arn != "" && var.okf_efs_read_access_point_arn != ""
44
- okf_efs_iam_statements = local.okf_efs_mount_enabled ? [
45
- {
46
- Sid = "OkfWikiEfsReadOnlyMount"
47
- Effect = "Allow"
48
- Action = ["elasticfilesystem:ClientMount"]
49
- Resource = var.okf_efs_file_system_arn
50
- Condition = {
51
- StringEquals = {
52
- "elasticfilesystem:AccessPointArn" = var.okf_efs_read_access_point_arn
53
- }
54
- }
55
- },
56
- ] : []
34
+ pi_image_tag = var.source_image_uri != "" ? "pi-${substr(sha256(var.source_image_uri), 0, 16)}" : "pi-latest"
35
+ pi_image_uri = "${var.ecr_repository_url}:${local.pi_image_tag}"
36
+ # THINK-589 PR 1 (deprecate-to-no-op): the OKF wiki EFS feature is dead. The
37
+ # okf_efs_* inputs remain declared as deprecated no-ops so customer-stage
38
+ # passthroughs keep working, but nothing is wired regardless of their
39
+ # values: no VPC attach, no EFS mount, no OKF env, no EFS IAM grant.
40
+ # PR 2 deletes the variables outright.
41
+ okf_efs_mount_enabled = false
57
42
  }
58
43
 
59
44
  ################################################################################
@@ -83,7 +68,7 @@ resource "aws_iam_role_policy" "agentcore_pi" {
83
68
 
84
69
  policy = jsonencode({
85
70
  Version = "2012-10-17"
86
- Statement = concat([
71
+ Statement = [
87
72
  {
88
73
  Sid = "S3Access"
89
74
  Effect = "Allow"
@@ -264,13 +249,12 @@ resource "aws_iam_role_policy" "agentcore_pi" {
264
249
  local.chat_agent_finalize_fn_arn,
265
250
  local.chat_agent_activity_fn_arn,
266
251
  local.manifest_log_fn_arn,
267
- local.capability_control_fn_arn,
252
+ local.tool_executions_fn_arn,
268
253
  ]
269
254
  },
270
255
  {
271
- # Aurora Data API — U4 SessionStore and Hindsight exact-memory recall
272
- # read/write via the RDS Data API rather than long-lived Postgres
273
- # connections. Cover both the canonical cluster name and suffixed
256
+ # Aurora Data API — U4 SessionStore reads/writes via the RDS Data
257
+ # API rather than long-lived Postgres connections. Cover both the canonical cluster name and suffixed
274
258
  # replacement names.
275
259
  Sid = "AuroraDataAPI"
276
260
  Effect = "Allow"
@@ -299,12 +283,16 @@ resource "aws_iam_role_policy" "agentcore_pi" {
299
283
  ]
300
284
  Resource = "arn:aws:secretsmanager:${var.region}:${var.account_id}:secret:thinkwork-${var.stage}-*"
301
285
  },
302
- ], local.okf_efs_iam_statements)
286
+ ]
303
287
  })
304
288
  }
305
289
 
290
+ # THINK-589 retired this with the OKF wiki EFS mount (Pi's only VPC
291
+ # attachment at the time). THINK-1082 brings it back for the network-only
292
+ # in_vpc lane: a VPC-attached function needs the ENI grant. Still never
293
+ # created when in_vpc is off.
306
294
  resource "aws_iam_role_policy_attachment" "agentcore_pi_vpc_access" {
307
- count = local.private_vpc_enabled ? 1 : 0
295
+ count = var.in_vpc ? 1 : 0
308
296
 
309
297
  role = aws_iam_role.agentcore_pi.name
310
298
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
@@ -384,51 +372,53 @@ resource "aws_lambda_function" "agentcore_pi" {
384
372
  AWS_LWA_PORT = "8080"
385
373
  AGENTCORE_MEMORY_ID = var.agentcore_memory_id
386
374
  AGENTCORE_FILES_BUCKET = var.bucket_name
387
- MEMORY_ENGINE = var.memory_engine
375
+ MEMORY_ENGINE = "agentcore"
388
376
  REQUESTER_IDLE_MEMORY_LEARNING_ENABLED = tostring(var.requester_idle_memory_learning_enabled)
389
377
  MEMORY_RETAIN_FN_NAME = local.memory_retain_fn_name
390
378
  CHAT_AGENT_FINALIZE_FN_NAME = local.chat_agent_finalize_fn_name
391
379
  CHAT_AGENT_ACTIVITY_FN_NAME = local.chat_agent_activity_fn_name
392
380
  MANIFEST_LOG_FUNCTION_NAME = local.manifest_log_fn_name
393
- CAPABILITY_CONTROL_FN_NAME = local.capability_control_fn_name
394
- HINDSIGHT_ENDPOINT = var.hindsight_endpoint
395
- # THINK-220 cutover flag — see the variable description.
396
- HINDSIGHT_DATABASE_NAME = var.hindsight_database_name
397
- THINKWORK_API_URL = var.api_endpoint
398
- API_AUTH_SECRET = var.api_auth_secret
381
+ TOOL_EXECUTIONS_FUNCTION_NAME = local.tool_executions_fn_name
382
+ THINKWORK_API_URL = var.api_endpoint
383
+ API_AUTH_SECRET = var.api_auth_secret
399
384
  # Plan §005 U4 — AuroraSessionStore uses the RDS Data API to persist
400
385
  # Pi's SessionData blobs against threads.session_data. Empty during
401
386
  # the first greenfield apply (DB cluster doesn't exist yet); the
402
387
  # constructor fail-closes if either is missing at runtime.
403
- DB_CLUSTER_ARN = var.db_cluster_arn
404
- DB_SECRET_ARN = var.db_secret_arn
405
- OKF_WIKI_NAVIGATOR_ENABLED = tostring(local.okf_efs_mount_enabled)
388
+ DB_CLUSTER_ARN = var.db_cluster_arn
389
+ DB_SECRET_ARN = var.db_secret_arn
406
390
  # THINK-173 U6: PUBLIC key only — the container verifies capability
407
391
  # manifests and must never hold signing material (KTD-3).
408
392
  CAPABILITY_SIGNING_PUBLIC_KEY = var.capability_signing_public_key
409
- OKF_WIKI_ROOT = var.okf_efs_mount_path
410
393
  # Per-model Bedrock region overrides, honored by the patched pi-ai
411
394
  # provider (patches/@earendil-works__pi-ai). SigV4 signing and endpoint
412
395
  # selection both follow the override.
413
396
  PI_BEDROCK_MODEL_REGIONS = jsonencode(var.pi_bedrock_model_regions)
397
+ # THINK-324: 1-hour Bedrock prompt-cache TTL (pi-ai resolveCacheRetention).
398
+ # The default 5-minute TTL made any thread idle >5 min pay full uncached
399
+ # input on its next turn.
400
+ PI_CACHE_RETENTION = "long"
414
401
  }
415
402
  }
416
403
 
404
+ # THINK-589: the OKF wiki EFS mount (and the VPC attachment that existed
405
+ # solely to reach it) is removed — no file_system_config, ever.
406
+ # THINK-1082: the VPC attachment returns as a NETWORK-ONLY lane so Pi can sit
407
+ # behind the api-lambda security group with the rest of the agent's database
408
+ # clients. Absent entirely when in_vpc is off.
417
409
  dynamic "vpc_config" {
418
- for_each = local.private_vpc_enabled ? [1] : []
410
+ for_each = var.in_vpc ? [1] : []
419
411
 
420
412
  content {
421
- subnet_ids = local.private_subnet_ids
422
- security_group_ids = local.private_security_group_ids
413
+ subnet_ids = var.vpc_subnet_ids
414
+ security_group_ids = var.vpc_security_group_ids
423
415
  }
424
416
  }
425
417
 
426
- dynamic "file_system_config" {
427
- for_each = local.okf_efs_vpc_enabled ? [1] : []
428
-
429
- content {
430
- arn = var.okf_efs_read_access_point_arn
431
- local_mount_path = var.okf_efs_mount_path
418
+ lifecycle {
419
+ precondition {
420
+ condition = !var.in_vpc || (length(var.vpc_subnet_ids) > 0 && length(var.vpc_security_group_ids) > 0)
421
+ error_message = "in_vpc requires non-empty vpc_subnet_ids and vpc_security_group_ids."
432
422
  }
433
423
  }
434
424
 
@@ -23,16 +23,16 @@ output "agentcore_pi_log_group_name" {
23
23
  }
24
24
 
25
25
  output "okf_wiki_mount_enabled" {
26
- description = "Whether the OKF wiki EFS view is mounted into the Pi Lambda."
26
+ description = "DEPRECATED (THINK-589): always false — the OKF wiki EFS view is never mounted into the Pi Lambda. Removal pending (PR 2)."
27
27
  value = local.okf_efs_mount_enabled
28
28
  }
29
29
 
30
30
  output "okf_wiki_mount_path" {
31
- description = "Pi local mount path for the OKF wiki EFS view."
31
+ description = "DEPRECATED (THINK-589): inert echo of the deprecated okf_efs_mount_path input; nothing is mounted. Removal pending (PR 2)."
32
32
  value = var.okf_efs_mount_path
33
33
  }
34
34
 
35
35
  output "okf_wiki_read_access_point_arn" {
36
- description = "EFS access point ARN mounted by Pi for read-only OKF wiki traversal."
36
+ description = "DEPRECATED (THINK-589): inert echo of the deprecated okf_efs_read_access_point_arn input; nothing is mounted. Removal pending (PR 2)."
37
37
  value = var.okf_efs_read_access_point_arn
38
38
  }