thinkwork-cli 0.1.0 → 0.2.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.
- package/README.md +3 -3
- package/dist/cli.js +251 -47
- package/dist/terraform/examples/greenfield/main.tf +190 -0
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +28 -0
- package/dist/terraform/modules/_internal/workspace-guard/main.tf +29 -0
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +217 -0
- package/dist/terraform/modules/app/appsync-subscriptions/main.tf +122 -0
- package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +20 -0
- package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +31 -0
- package/dist/terraform/modules/app/crons/main.tf +55 -0
- package/dist/terraform/modules/app/hindsight-memory/README.md +66 -0
- package/dist/terraform/modules/app/hindsight-memory/main.tf +331 -0
- package/dist/terraform/modules/app/job-triggers/main.tf +70 -0
- package/dist/terraform/modules/app/lambda-api/.build/placeholder.zip +0 -0
- package/dist/terraform/modules/app/lambda-api/handlers.tf +311 -0
- package/dist/terraform/modules/app/lambda-api/main.tf +245 -0
- package/dist/terraform/modules/app/lambda-api/outputs.tf +24 -0
- package/dist/terraform/modules/app/lambda-api/variables.tf +153 -0
- package/dist/terraform/modules/app/ses-email/main.tf +51 -0
- package/dist/terraform/modules/app/static-site/main.tf +176 -0
- package/dist/terraform/modules/data/aurora-postgres/README.md +92 -0
- package/dist/terraform/modules/data/aurora-postgres/main.tf +185 -0
- package/dist/terraform/modules/data/aurora-postgres/outputs.tf +30 -0
- package/dist/terraform/modules/data/aurora-postgres/variables.tf +114 -0
- package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +102 -0
- package/dist/terraform/modules/data/s3-buckets/main.tf +91 -0
- package/dist/terraform/modules/foundation/cognito/main.tf +377 -0
- package/dist/terraform/modules/foundation/cognito/outputs.tf +29 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +124 -0
- package/dist/terraform/modules/foundation/dns/main.tf +49 -0
- package/dist/terraform/modules/foundation/kms/main.tf +49 -0
- package/dist/terraform/modules/foundation/vpc/main.tf +137 -0
- package/dist/terraform/modules/foundation/vpc/outputs.tf +14 -0
- package/dist/terraform/modules/foundation/vpc/variables.tf +40 -0
- package/dist/terraform/modules/thinkwork/main.tf +212 -0
- package/dist/terraform/modules/thinkwork/outputs.tf +87 -0
- package/dist/terraform/modules/thinkwork/variables.tf +241 -0
- package/dist/terraform/schema.graphql +199 -0
- package/package.json +2 -2
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
################################################################################
|
|
2
|
+
# AgentCore Runtime — App Module
|
|
3
|
+
#
|
|
4
|
+
# Creates ECR repository, IAM roles, and container build infrastructure
|
|
5
|
+
# for the Strands-based agent runtime. Full implementation ported in Phase 3.
|
|
6
|
+
# Phase 1 creates the ECR repo and IAM scaffolding only.
|
|
7
|
+
################################################################################
|
|
8
|
+
|
|
9
|
+
variable "stage" {
|
|
10
|
+
description = "Deployment stage"
|
|
11
|
+
type = string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
variable "account_id" {
|
|
15
|
+
description = "AWS account ID"
|
|
16
|
+
type = string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
variable "region" {
|
|
20
|
+
description = "AWS region"
|
|
21
|
+
type = string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
variable "bucket_name" {
|
|
25
|
+
description = "Primary S3 bucket for skills and workspace files"
|
|
26
|
+
type = string
|
|
27
|
+
}
|
|
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
|
+
variable "hindsight_endpoint" {
|
|
36
|
+
description = "Hindsight API endpoint (only used when memory_engine = 'hindsight')"
|
|
37
|
+
type = string
|
|
38
|
+
default = ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
variable "agentcore_memory_id" {
|
|
42
|
+
description = "AgentCore Memory resource ID (only used when memory_engine = 'managed')"
|
|
43
|
+
type = string
|
|
44
|
+
default = ""
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
################################################################################
|
|
48
|
+
# ECR Repository
|
|
49
|
+
################################################################################
|
|
50
|
+
|
|
51
|
+
resource "aws_ecr_repository" "agentcore" {
|
|
52
|
+
name = "thinkwork-${var.stage}-agentcore"
|
|
53
|
+
image_tag_mutability = "MUTABLE"
|
|
54
|
+
force_delete = true
|
|
55
|
+
|
|
56
|
+
image_scanning_configuration {
|
|
57
|
+
scan_on_push = true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
tags = {
|
|
61
|
+
Name = "thinkwork-${var.stage}-agentcore"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
resource "aws_ecr_lifecycle_policy" "agentcore" {
|
|
66
|
+
repository = aws_ecr_repository.agentcore.name
|
|
67
|
+
|
|
68
|
+
policy = jsonencode({
|
|
69
|
+
rules = [{
|
|
70
|
+
rulePriority = 1
|
|
71
|
+
description = "Keep last 10 images"
|
|
72
|
+
selection = {
|
|
73
|
+
tagStatus = "any"
|
|
74
|
+
countType = "imageCountMoreThan"
|
|
75
|
+
countNumber = 10
|
|
76
|
+
}
|
|
77
|
+
action = {
|
|
78
|
+
type = "expire"
|
|
79
|
+
}
|
|
80
|
+
}]
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
################################################################################
|
|
85
|
+
# Execution Role
|
|
86
|
+
################################################################################
|
|
87
|
+
|
|
88
|
+
resource "aws_iam_role" "agentcore" {
|
|
89
|
+
name = "thinkwork-${var.stage}-agentcore-role"
|
|
90
|
+
|
|
91
|
+
assume_role_policy = jsonencode({
|
|
92
|
+
Version = "2012-10-17"
|
|
93
|
+
Statement = [{
|
|
94
|
+
Effect = "Allow"
|
|
95
|
+
Principal = { Service = ["ecs-tasks.amazonaws.com", "lambda.amazonaws.com"] }
|
|
96
|
+
Action = "sts:AssumeRole"
|
|
97
|
+
}]
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
resource "aws_iam_role_policy" "agentcore" {
|
|
102
|
+
name = "agentcore-permissions"
|
|
103
|
+
role = aws_iam_role.agentcore.id
|
|
104
|
+
|
|
105
|
+
policy = jsonencode({
|
|
106
|
+
Version = "2012-10-17"
|
|
107
|
+
Statement = [
|
|
108
|
+
{
|
|
109
|
+
Sid = "S3Access"
|
|
110
|
+
Effect = "Allow"
|
|
111
|
+
Action = ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
|
|
112
|
+
Resource = [
|
|
113
|
+
"arn:aws:s3:::${var.bucket_name}",
|
|
114
|
+
"arn:aws:s3:::${var.bucket_name}/*",
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
Sid = "BedrockInvoke"
|
|
119
|
+
Effect = "Allow"
|
|
120
|
+
Action = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", "bedrock:InvokeAgent"]
|
|
121
|
+
Resource = "*"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
Sid = "CloudWatchLogs"
|
|
125
|
+
Effect = "Allow"
|
|
126
|
+
Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]
|
|
127
|
+
Resource = "arn:aws:logs:${var.region}:${var.account_id}:*"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
Sid = "ECRPull"
|
|
131
|
+
Effect = "Allow"
|
|
132
|
+
Action = ["ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "ecr:GetAuthorizationToken"]
|
|
133
|
+
Resource = "*"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
Sid = "SSMParameterAccess"
|
|
137
|
+
Effect = "Allow"
|
|
138
|
+
Action = ["ssm:GetParameter", "ssm:PutParameter"]
|
|
139
|
+
Resource = "arn:aws:ssm:${var.region}:${var.account_id}:parameter/thinkwork/${var.stage}/agentcore/*"
|
|
140
|
+
},
|
|
141
|
+
]
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
################################################################################
|
|
146
|
+
# CloudWatch Log Group
|
|
147
|
+
################################################################################
|
|
148
|
+
|
|
149
|
+
resource "aws_cloudwatch_log_group" "agentcore" {
|
|
150
|
+
name = "/thinkwork/${var.stage}/agentcore"
|
|
151
|
+
retention_in_days = 30
|
|
152
|
+
|
|
153
|
+
tags = {
|
|
154
|
+
Name = "thinkwork-${var.stage}-agentcore-logs"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
################################################################################
|
|
159
|
+
# Lambda Container Image
|
|
160
|
+
################################################################################
|
|
161
|
+
|
|
162
|
+
resource "aws_lambda_function" "agentcore" {
|
|
163
|
+
function_name = "thinkwork-${var.stage}-agentcore"
|
|
164
|
+
role = aws_iam_role.agentcore.arn
|
|
165
|
+
package_type = "Image"
|
|
166
|
+
image_uri = "${aws_ecr_repository.agentcore.repository_url}:latest"
|
|
167
|
+
timeout = 900
|
|
168
|
+
memory_size = 2048
|
|
169
|
+
|
|
170
|
+
environment {
|
|
171
|
+
variables = {
|
|
172
|
+
PORT = "8080"
|
|
173
|
+
AWS_LWA_PORT = "8080"
|
|
174
|
+
MEMORY_ENGINE = var.memory_engine
|
|
175
|
+
AGENTCORE_MEMORY_ID = var.agentcore_memory_id
|
|
176
|
+
AGENTCORE_FILES_BUCKET = var.bucket_name
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
logging_config {
|
|
181
|
+
log_group = aws_cloudwatch_log_group.agentcore.name
|
|
182
|
+
log_format = "Text"
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
tags = {
|
|
186
|
+
Name = "thinkwork-${var.stage}-agentcore"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
resource "aws_lambda_function_url" "agentcore" {
|
|
191
|
+
function_name = aws_lambda_function.agentcore.function_name
|
|
192
|
+
authorization_type = "NONE"
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
################################################################################
|
|
196
|
+
# Outputs
|
|
197
|
+
################################################################################
|
|
198
|
+
|
|
199
|
+
output "ecr_repository_url" {
|
|
200
|
+
description = "ECR repository URL for the AgentCore container"
|
|
201
|
+
value = aws_ecr_repository.agentcore.repository_url
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
output "execution_role_arn" {
|
|
205
|
+
description = "IAM role ARN for AgentCore execution"
|
|
206
|
+
value = aws_iam_role.agentcore.arn
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
output "agentcore_invoke_url" {
|
|
210
|
+
description = "Lambda Function URL for the AgentCore container"
|
|
211
|
+
value = aws_lambda_function_url.agentcore.function_url
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
output "agentcore_function_name" {
|
|
215
|
+
description = "AgentCore Lambda function name (for direct SDK invoke)"
|
|
216
|
+
value = aws_lambda_function.agentcore.function_name
|
|
217
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
################################################################################
|
|
2
|
+
# AppSync Subscriptions — App Module
|
|
3
|
+
#
|
|
4
|
+
# AppSync exists ONLY as a thin realtime/event layer for subscription fan-out.
|
|
5
|
+
# Queries and mutations go through API Gateway V2 → Lambda, NOT through AppSync.
|
|
6
|
+
#
|
|
7
|
+
# Per Decision 9: the unused RDS data source is removed. Only the NONE
|
|
8
|
+
# passthrough data source remains for notification mutations. The schema is
|
|
9
|
+
# a subscription-only fragment, not the full product schema.
|
|
10
|
+
#
|
|
11
|
+
# Post-launch consideration: replace with standard graphql-ws over API Gateway
|
|
12
|
+
# V2 WebSocket API. Not v0.1 scope.
|
|
13
|
+
################################################################################
|
|
14
|
+
|
|
15
|
+
################################################################################
|
|
16
|
+
# GraphQL API
|
|
17
|
+
################################################################################
|
|
18
|
+
|
|
19
|
+
resource "aws_appsync_graphql_api" "subscriptions" {
|
|
20
|
+
name = "thinkwork-${var.stage}-subscriptions"
|
|
21
|
+
authentication_type = "API_KEY"
|
|
22
|
+
xray_enabled = false
|
|
23
|
+
|
|
24
|
+
schema = var.subscription_schema
|
|
25
|
+
|
|
26
|
+
additional_authentication_provider {
|
|
27
|
+
authentication_type = "AWS_IAM"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
additional_authentication_provider {
|
|
31
|
+
authentication_type = "AMAZON_COGNITO_USER_POOLS"
|
|
32
|
+
|
|
33
|
+
user_pool_config {
|
|
34
|
+
user_pool_id = var.user_pool_id
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
tags = {
|
|
39
|
+
Name = "thinkwork-${var.stage}-subscriptions"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
################################################################################
|
|
44
|
+
# API Key — 365 day expiry
|
|
45
|
+
################################################################################
|
|
46
|
+
|
|
47
|
+
resource "aws_appsync_api_key" "main" {
|
|
48
|
+
api_id = aws_appsync_graphql_api.subscriptions.id
|
|
49
|
+
expires = timeadd(timestamp(), "8760h")
|
|
50
|
+
|
|
51
|
+
lifecycle {
|
|
52
|
+
ignore_changes = [expires]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
################################################################################
|
|
57
|
+
# NONE Data Source (passthrough for notification mutations)
|
|
58
|
+
################################################################################
|
|
59
|
+
|
|
60
|
+
resource "aws_appsync_datasource" "none" {
|
|
61
|
+
api_id = aws_appsync_graphql_api.subscriptions.id
|
|
62
|
+
name = "NonePassthrough"
|
|
63
|
+
type = "NONE"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
################################################################################
|
|
67
|
+
# Notification Mutation Resolvers
|
|
68
|
+
#
|
|
69
|
+
# v1 events only — deferred events (onEvalRunUpdated, onCostRecorded) are cut.
|
|
70
|
+
################################################################################
|
|
71
|
+
|
|
72
|
+
locals {
|
|
73
|
+
notification_mutations = [
|
|
74
|
+
"notifyAgentStatus",
|
|
75
|
+
"notifyNewMessage",
|
|
76
|
+
"notifyHeartbeatActivity",
|
|
77
|
+
"notifyThreadUpdate",
|
|
78
|
+
"notifyInboxItemUpdate",
|
|
79
|
+
"notifyThreadTurnUpdate",
|
|
80
|
+
"notifyOrgUpdate",
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
resource "aws_appsync_resolver" "notifications" {
|
|
85
|
+
for_each = toset(local.notification_mutations)
|
|
86
|
+
|
|
87
|
+
api_id = aws_appsync_graphql_api.subscriptions.id
|
|
88
|
+
type = "Mutation"
|
|
89
|
+
field = each.value
|
|
90
|
+
data_source = aws_appsync_datasource.none.name
|
|
91
|
+
|
|
92
|
+
request_template = <<-EOF
|
|
93
|
+
{"version":"2017-02-28","payload":$util.toJson($context.arguments)}
|
|
94
|
+
EOF
|
|
95
|
+
|
|
96
|
+
response_template = <<-EOF
|
|
97
|
+
#set($result = $context.result)
|
|
98
|
+
#if(!$result.updatedAt)
|
|
99
|
+
#set($result.updatedAt = $util.time.nowISO8601())
|
|
100
|
+
#end
|
|
101
|
+
#if(!$result.createdAt)
|
|
102
|
+
#set($result.createdAt = $util.time.nowISO8601())
|
|
103
|
+
#end
|
|
104
|
+
$util.toJson($result)
|
|
105
|
+
EOF
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
################################################################################
|
|
109
|
+
# Custom Domain (optional)
|
|
110
|
+
################################################################################
|
|
111
|
+
|
|
112
|
+
resource "aws_appsync_domain_name" "main" {
|
|
113
|
+
count = var.custom_domain != "" ? 1 : 0
|
|
114
|
+
domain_name = var.custom_domain
|
|
115
|
+
certificate_arn = var.certificate_arn
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
resource "aws_appsync_domain_name_api_association" "main" {
|
|
119
|
+
count = var.custom_domain != "" ? 1 : 0
|
|
120
|
+
api_id = aws_appsync_graphql_api.subscriptions.id
|
|
121
|
+
domain_name = aws_appsync_domain_name.main[0].domain_name
|
|
122
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
output "graphql_api_id" {
|
|
2
|
+
description = "AppSync GraphQL API ID"
|
|
3
|
+
value = aws_appsync_graphql_api.subscriptions.id
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
output "graphql_api_url" {
|
|
7
|
+
description = "AppSync GraphQL endpoint URL (used by backend to push notifications)"
|
|
8
|
+
value = aws_appsync_graphql_api.subscriptions.uris["GRAPHQL"]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
output "graphql_realtime_url" {
|
|
12
|
+
description = "AppSync realtime WebSocket URL (used by frontend subscription clients)"
|
|
13
|
+
value = aws_appsync_graphql_api.subscriptions.uris["REALTIME"]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
output "graphql_api_key" {
|
|
17
|
+
description = "AppSync API key"
|
|
18
|
+
value = aws_appsync_api_key.main.key
|
|
19
|
+
sensitive = true
|
|
20
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
variable "stage" {
|
|
2
|
+
description = "Deployment stage"
|
|
3
|
+
type = string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
variable "region" {
|
|
7
|
+
description = "AWS region"
|
|
8
|
+
type = string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
variable "user_pool_id" {
|
|
12
|
+
description = "Cognito user pool ID for authentication"
|
|
13
|
+
type = string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "subscription_schema" {
|
|
17
|
+
description = "GraphQL schema containing only Subscription + notification Mutation types. This is a subscription-only fragment, NOT the full product schema."
|
|
18
|
+
type = string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
variable "custom_domain" {
|
|
22
|
+
description = "Custom domain for the AppSync API (e.g. subscriptions.thinkwork.ai). Leave empty to skip."
|
|
23
|
+
type = string
|
|
24
|
+
default = ""
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
variable "certificate_arn" {
|
|
28
|
+
description = "ACM certificate ARN for the custom domain (required when custom_domain is set)"
|
|
29
|
+
type = string
|
|
30
|
+
default = ""
|
|
31
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
################################################################################
|
|
2
|
+
# Crons — App Module
|
|
3
|
+
#
|
|
4
|
+
# Scheduled jobs and event-driven processors. Full implementation ported
|
|
5
|
+
# in Phase 4. Phase 1 creates the IAM role and a placeholder cron only.
|
|
6
|
+
#
|
|
7
|
+
# v1 scope: standard crons + wakeup processor.
|
|
8
|
+
# Cut: kg_extract_fanout, kg_extract_worker, span_enrichment (PRD-41B).
|
|
9
|
+
################################################################################
|
|
10
|
+
|
|
11
|
+
variable "stage" {
|
|
12
|
+
description = "Deployment stage"
|
|
13
|
+
type = string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "account_id" {
|
|
17
|
+
description = "AWS account ID"
|
|
18
|
+
type = string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
variable "region" {
|
|
22
|
+
description = "AWS region"
|
|
23
|
+
type = string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
################################################################################
|
|
27
|
+
# Shared IAM Role for Cron Lambdas
|
|
28
|
+
################################################################################
|
|
29
|
+
|
|
30
|
+
resource "aws_iam_role" "cron_lambda" {
|
|
31
|
+
name = "thinkwork-${var.stage}-cron-lambda-role"
|
|
32
|
+
|
|
33
|
+
assume_role_policy = jsonencode({
|
|
34
|
+
Version = "2012-10-17"
|
|
35
|
+
Statement = [{
|
|
36
|
+
Effect = "Allow"
|
|
37
|
+
Principal = { Service = "lambda.amazonaws.com" }
|
|
38
|
+
Action = "sts:AssumeRole"
|
|
39
|
+
}]
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
resource "aws_iam_role_policy_attachment" "cron_basic" {
|
|
44
|
+
role = aws_iam_role.cron_lambda.name
|
|
45
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
################################################################################
|
|
49
|
+
# Outputs
|
|
50
|
+
################################################################################
|
|
51
|
+
|
|
52
|
+
output "cron_lambda_role_arn" {
|
|
53
|
+
description = "IAM role ARN for cron Lambda functions"
|
|
54
|
+
value = aws_iam_role.cron_lambda.arn
|
|
55
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Memory Engine Module
|
|
2
|
+
|
|
3
|
+
Thinkwork supports pluggable long-term memory for agents. Choose the engine that fits your stage and requirements.
|
|
4
|
+
|
|
5
|
+
## Engines
|
|
6
|
+
|
|
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) |
|
|
11
|
+
|
|
12
|
+
Both engines provide agents with memory tools. The Strands runtime reads `MEMORY_ENGINE` and loads the right tool set:
|
|
13
|
+
|
|
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.
|
|
16
|
+
|
|
17
|
+
## What's pluggable
|
|
18
|
+
|
|
19
|
+
Only **Layer 3 (long-term cross-thread memory)** is pluggable. The other memory layers are core infrastructure:
|
|
20
|
+
|
|
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.**
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Managed (default — no extra config needed)
|
|
28
|
+
|
|
29
|
+
```hcl
|
|
30
|
+
module "thinkwork" {
|
|
31
|
+
source = "thinkwork-ai/thinkwork/aws"
|
|
32
|
+
|
|
33
|
+
stage = "prod"
|
|
34
|
+
# memory_engine defaults to "managed" — nothing to set
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Hindsight (opt-in)
|
|
39
|
+
|
|
40
|
+
```hcl
|
|
41
|
+
module "thinkwork" {
|
|
42
|
+
source = "thinkwork-ai/thinkwork/aws"
|
|
43
|
+
|
|
44
|
+
stage = "prod"
|
|
45
|
+
memory_engine = "hindsight"
|
|
46
|
+
|
|
47
|
+
# Optional: pin the Hindsight image version
|
|
48
|
+
# hindsight_image_tag = "0.4.22"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
When `memory_engine = "hindsight"`, Terraform creates:
|
|
53
|
+
- ECS Fargate cluster + service (ARM64, 2 vCPU, 4 GB)
|
|
54
|
+
- Application Load Balancer
|
|
55
|
+
- Security groups (ALB → Hindsight → Aurora ingress)
|
|
56
|
+
- CloudWatch log group
|
|
57
|
+
|
|
58
|
+
When `memory_engine = "managed"`, none of the above is created.
|
|
59
|
+
|
|
60
|
+
## Switching engines
|
|
61
|
+
|
|
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.
|
|
65
|
+
|
|
66
|
+
Memory data is not migrated between engines. Each engine has its own storage backend.
|