@deployfoundation/foundation-deploy 0.2.39 → 0.2.41
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/dist/bin/app.js +2 -2
- package/dist/bin/foundation-deploy.js +17 -1
- package/dist/{chunk-7rd8c1th.js → chunk-g56mqyfx.js} +91 -74
- package/dist/{chunk-6v0ewr5b.js → chunk-sgh3agpa.js} +10 -1
- package/dist/src/index.js +2 -2
- package/package.json +1 -1
- package/src/deploy/endpoint.ts +27 -0
- package/src/deploy-permissions.ts +3 -1
- package/src/stacks/api-stack.ts +13 -0
package/dist/bin/app.js
CHANGED
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
FoundationPages,
|
|
9
9
|
FoundationPipeline,
|
|
10
10
|
NewsletterStack
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-sgh3agpa.js";
|
|
12
12
|
import {
|
|
13
13
|
adminsFor,
|
|
14
14
|
instanceNames,
|
|
15
15
|
loadInstanceFile,
|
|
16
16
|
provisionsIntegration
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-g56mqyfx.js";
|
|
18
18
|
import"../chunk-dz91avrb.js";
|
|
19
19
|
|
|
20
20
|
// bin/app.ts
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
slackCommandPrefix,
|
|
23
23
|
verifyManifest,
|
|
24
24
|
versionedConfigKey
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-g56mqyfx.js";
|
|
26
26
|
import {
|
|
27
27
|
DEFAULT_RELEASE_BUCKET,
|
|
28
28
|
expectedKeyArn
|
|
@@ -1043,6 +1043,21 @@ var SMOKE_EXPECT = ['"authenticated":true', '"config_source":"s3"'];
|
|
|
1043
1043
|
function smokeSessionId(prefix) {
|
|
1044
1044
|
return `${prefix}-${Math.floor(Date.now() / 1000)}`.padEnd(40, "0");
|
|
1045
1045
|
}
|
|
1046
|
+
async function stopSmokeSession(runner, opts, log) {
|
|
1047
|
+
try {
|
|
1048
|
+
await runner.capture([
|
|
1049
|
+
"bedrock-agentcore",
|
|
1050
|
+
"stop-runtime-session",
|
|
1051
|
+
"--agent-runtime-arn",
|
|
1052
|
+
opts.arn,
|
|
1053
|
+
...opts.qualifier === undefined ? [] : ["--qualifier", opts.qualifier],
|
|
1054
|
+
"--runtime-session-id",
|
|
1055
|
+
opts.sessionId
|
|
1056
|
+
]);
|
|
1057
|
+
} catch {
|
|
1058
|
+
log(" (could not stop the smoke session; it ends at the idle timeout)");
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1046
1061
|
async function smokeInvoke(runner, opts) {
|
|
1047
1062
|
const log = opts.log ?? ((line) => console.log(line));
|
|
1048
1063
|
const payload = opts.payload ?? '{"_smoke_test":true}';
|
|
@@ -1070,6 +1085,7 @@ async function smokeInvoke(runner, opts) {
|
|
|
1070
1085
|
} finally {
|
|
1071
1086
|
await rm(dir, { recursive: true, force: true });
|
|
1072
1087
|
}
|
|
1088
|
+
await stopSmokeSession(runner, opts, log);
|
|
1073
1089
|
log(` ${out.replaceAll(`
|
|
1074
1090
|
`, `
|
|
1075
1091
|
`)}`);
|
|
@@ -1261,31 +1261,45 @@ var contextStorage = new AsyncLocalStorage;
|
|
|
1261
1261
|
// ../core/src/config.ts
|
|
1262
1262
|
import { createHash as createHash2 } from "node:crypto";
|
|
1263
1263
|
import { parse as parseYaml2 } from "yaml";
|
|
1264
|
-
import { z as
|
|
1264
|
+
import { z as z5 } from "zod";
|
|
1265
1265
|
|
|
1266
1266
|
// ../core/src/jobs.ts
|
|
1267
1267
|
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
1268
|
+
import { z as z4 } from "zod";
|
|
1269
|
+
|
|
1270
|
+
// ../core/src/thinking-level.ts
|
|
1268
1271
|
import { z as z3 } from "zod";
|
|
1272
|
+
var ThinkingLevel = z3.enum(["none", "low", "medium", "high", "xhigh", "max"]);
|
|
1273
|
+
|
|
1274
|
+
// ../core/src/jobs.ts
|
|
1269
1275
|
var JOB_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,40}$/;
|
|
1270
|
-
var RawScheduleTrigger =
|
|
1271
|
-
schedule:
|
|
1276
|
+
var RawScheduleTrigger = z4.object({
|
|
1277
|
+
schedule: z4.string().min(1)
|
|
1272
1278
|
}).strict();
|
|
1273
|
-
var RawWebhookTrigger =
|
|
1274
|
-
webhook:
|
|
1279
|
+
var RawWebhookTrigger = z4.object({
|
|
1280
|
+
webhook: z4.object({}).strict()
|
|
1275
1281
|
}).strict();
|
|
1276
|
-
var RawJob =
|
|
1277
|
-
id:
|
|
1278
|
-
name:
|
|
1279
|
-
channel:
|
|
1280
|
-
on:
|
|
1281
|
-
prompt:
|
|
1282
|
-
|
|
1283
|
-
|
|
1282
|
+
var RawJob = z4.object({
|
|
1283
|
+
id: z4.string().regex(JOB_ID_PATTERN),
|
|
1284
|
+
name: z4.string().min(1).max(80),
|
|
1285
|
+
channel: z4.string().regex(/^[CG][A-Z0-9]{8,}$/, "a job runs in a Slack channel id"),
|
|
1286
|
+
on: z4.union([RawScheduleTrigger, RawWebhookTrigger]),
|
|
1287
|
+
prompt: z4.string().min(1).max(4000),
|
|
1288
|
+
thinkingLevel: ThinkingLevel.optional()
|
|
1289
|
+
}).strict().superRefine((job, ctx) => {
|
|
1290
|
+
if (job.thinkingLevel !== undefined && !("schedule" in job.on))
|
|
1291
|
+
ctx.addIssue({
|
|
1292
|
+
code: z4.ZodIssueCode.custom,
|
|
1293
|
+
path: ["thinkingLevel"],
|
|
1294
|
+
message: "thinkingLevel applies to scheduled jobs only"
|
|
1295
|
+
});
|
|
1296
|
+
});
|
|
1297
|
+
var RawJobs = z4.array(RawJob).default([]).superRefine((jobs, ctx) => {
|
|
1284
1298
|
const seen = new Set;
|
|
1285
1299
|
for (const [index, job] of jobs.entries()) {
|
|
1286
1300
|
if (seen.has(job.id)) {
|
|
1287
1301
|
ctx.addIssue({
|
|
1288
|
-
code:
|
|
1302
|
+
code: z4.ZodIssueCode.custom,
|
|
1289
1303
|
path: [index, "id"],
|
|
1290
1304
|
message: `duplicate job id: ${job.id}`
|
|
1291
1305
|
});
|
|
@@ -1306,9 +1320,13 @@ function scheduledJobFingerprint(input) {
|
|
|
1306
1320
|
return createHash("sha256").update(JSON.stringify([input.routineId, input.name, input.channel, input.prompt])).digest("hex");
|
|
1307
1321
|
}
|
|
1308
1322
|
function scheduledJobBindings(jobs) {
|
|
1309
|
-
return jobs.filter(isScheduledJob).map(({ id, name, channel, prompt }) => {
|
|
1323
|
+
return jobs.filter(isScheduledJob).map(({ id, name, channel, prompt, thinkingLevel }) => {
|
|
1310
1324
|
const input = { routineId: `job-${id}`, name, channel, prompt };
|
|
1311
|
-
return {
|
|
1325
|
+
return {
|
|
1326
|
+
routineId: input.routineId,
|
|
1327
|
+
fingerprint: scheduledJobFingerprint(input),
|
|
1328
|
+
...thinkingLevel === undefined ? {} : { thinkingLevel }
|
|
1329
|
+
};
|
|
1312
1330
|
});
|
|
1313
1331
|
}
|
|
1314
1332
|
function jobWebhookKey(instanceSecret, jobId) {
|
|
@@ -1374,11 +1392,10 @@ function capabilityScheduledJobs(config) {
|
|
|
1374
1392
|
|
|
1375
1393
|
// ../core/src/config.ts
|
|
1376
1394
|
var MODEL_RE = /^([a-z0-9-]+)\/(.+)$/;
|
|
1377
|
-
var
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
dailyCap: z4.number().int().min(0).default(40)
|
|
1395
|
+
var RawImages = z5.object({
|
|
1396
|
+
backend: z5.enum(["gemini"]).default("gemini"),
|
|
1397
|
+
model: z5.string().min(1).default("gemini-2.5-flash-image"),
|
|
1398
|
+
dailyCap: z5.number().int().min(0).default(40)
|
|
1382
1399
|
}).strict().default({});
|
|
1383
1400
|
var OMP_MODEL_ROLES = [
|
|
1384
1401
|
"default",
|
|
@@ -1391,40 +1408,40 @@ var OMP_MODEL_ROLES = [
|
|
|
1391
1408
|
"task",
|
|
1392
1409
|
"advisor"
|
|
1393
1410
|
];
|
|
1394
|
-
var RawModelRoles =
|
|
1395
|
-
var RawChannelModels =
|
|
1396
|
-
var RawSubagents =
|
|
1397
|
-
enabled:
|
|
1398
|
-
maxConcurrency:
|
|
1399
|
-
maxRecursionDepth:
|
|
1400
|
-
effort:
|
|
1411
|
+
var RawModelRoles = z5.record(z5.enum(OMP_MODEL_ROLES), z5.string().regex(MODEL_RE)).default({});
|
|
1412
|
+
var RawChannelModels = z5.record(z5.string().regex(/^[CDG][A-Z0-9]+$/, "channelModels keys must be Slack conversation ids"), z5.string().regex(MODEL_RE, "channel model must be provider/modelId")).default({});
|
|
1413
|
+
var RawSubagents = z5.object({
|
|
1414
|
+
enabled: z5.boolean().default(true),
|
|
1415
|
+
maxConcurrency: z5.number().int().min(1).max(8).default(3),
|
|
1416
|
+
maxRecursionDepth: z5.number().int().min(1).max(3).default(2),
|
|
1417
|
+
effort: z5.boolean().default(true)
|
|
1401
1418
|
}).strict().default({});
|
|
1402
|
-
var RawMemory =
|
|
1419
|
+
var RawMemory = z5.object({ ompBackend: z5.enum(["off", "local"]).default("off") }).strict().default({});
|
|
1403
1420
|
var SKILL_SOURCE_SCOPES = ["shared", "instance"];
|
|
1404
1421
|
var RawSkillSourceMetadata = {
|
|
1405
|
-
owner:
|
|
1406
|
-
scope:
|
|
1407
|
-
requires:
|
|
1422
|
+
owner: z5.string().min(1).optional(),
|
|
1423
|
+
scope: z5.enum(SKILL_SOURCE_SCOPES).optional(),
|
|
1424
|
+
requires: z5.array(z5.enum(CAPABILITY_IDS)).optional()
|
|
1408
1425
|
};
|
|
1409
|
-
var RawSkillSource =
|
|
1410
|
-
|
|
1411
|
-
github:
|
|
1412
|
-
ref:
|
|
1413
|
-
path:
|
|
1426
|
+
var RawSkillSource = z5.union([
|
|
1427
|
+
z5.object({
|
|
1428
|
+
github: z5.string().min(1),
|
|
1429
|
+
ref: z5.string().min(1).optional(),
|
|
1430
|
+
path: z5.string().optional(),
|
|
1414
1431
|
...RawSkillSourceMetadata
|
|
1415
1432
|
}).strict(),
|
|
1416
|
-
|
|
1433
|
+
z5.object({ s3: z5.string().min(1), ...RawSkillSourceMetadata }).strict()
|
|
1417
1434
|
]);
|
|
1418
|
-
var RawSkills =
|
|
1419
|
-
sources:
|
|
1420
|
-
promoteTo:
|
|
1435
|
+
var RawSkills = z5.object({
|
|
1436
|
+
sources: z5.array(RawSkillSource).optional(),
|
|
1437
|
+
promoteTo: z5.string().min(1).optional()
|
|
1421
1438
|
}).strict().default({});
|
|
1422
|
-
var RawInstanceConfig =
|
|
1423
|
-
name:
|
|
1424
|
-
model:
|
|
1425
|
-
admins:
|
|
1426
|
-
instructions:
|
|
1427
|
-
timezone:
|
|
1439
|
+
var RawInstanceConfig = z5.object({
|
|
1440
|
+
name: z5.string().min(1),
|
|
1441
|
+
model: z5.string().regex(MODEL_RE, "model must be provider/modelId"),
|
|
1442
|
+
admins: z5.array(z5.string().min(1)).min(1, "admins must list at least one Slack user id"),
|
|
1443
|
+
instructions: z5.string().default(""),
|
|
1444
|
+
timezone: z5.string().default("UTC").refine(isValidTimezone, (tz) => ({ message: `unknown timezone: ${tz}` })),
|
|
1428
1445
|
thinkingLevel: ThinkingLevel.optional(),
|
|
1429
1446
|
skills: RawSkills,
|
|
1430
1447
|
images: RawImages,
|
|
@@ -1501,24 +1518,24 @@ function parseInstanceConfig(yamlText) {
|
|
|
1501
1518
|
}
|
|
1502
1519
|
// ../core/src/company-capabilities.ts
|
|
1503
1520
|
import { parse as parseYaml3 } from "yaml";
|
|
1504
|
-
import { z as
|
|
1521
|
+
import { z as z6 } from "zod";
|
|
1505
1522
|
var COMPANY_CAPABILITY_DECLARATION_VERSION = 1;
|
|
1506
1523
|
var COMPANY_CAPABILITY_DECLARATION_MAX_COUNT = CAPABILITY_IDS.length;
|
|
1507
1524
|
var COMPANY_CAPABILITY_DESCRIPTION_MAX_CHARS = 280;
|
|
1508
1525
|
var COMPANY_CAPABILITY_DECLARATION_MAX_BYTES = 16 * 1024;
|
|
1509
|
-
var RawCompanyCapabilityDeclaration =
|
|
1510
|
-
id:
|
|
1511
|
-
description:
|
|
1526
|
+
var RawCompanyCapabilityDeclaration = z6.object({
|
|
1527
|
+
id: z6.enum(CAPABILITY_IDS),
|
|
1528
|
+
description: z6.string().min(1).max(COMPANY_CAPABILITY_DESCRIPTION_MAX_CHARS).refine((value) => value.trim() === value && !Array.from(value).some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127), "description must not have surrounding whitespace or control characters")
|
|
1512
1529
|
}).strict();
|
|
1513
|
-
var RawCompanyCapabilityDeclarations =
|
|
1514
|
-
version:
|
|
1515
|
-
capabilities:
|
|
1530
|
+
var RawCompanyCapabilityDeclarations = z6.object({
|
|
1531
|
+
version: z6.literal(COMPANY_CAPABILITY_DECLARATION_VERSION),
|
|
1532
|
+
capabilities: z6.array(RawCompanyCapabilityDeclaration).max(COMPANY_CAPABILITY_DECLARATION_MAX_COUNT)
|
|
1516
1533
|
}).strict().superRefine((document, ctx) => {
|
|
1517
1534
|
const seen = new Set;
|
|
1518
1535
|
for (const [index, declaration] of document.capabilities.entries()) {
|
|
1519
1536
|
if (seen.has(declaration.id)) {
|
|
1520
1537
|
ctx.addIssue({
|
|
1521
|
-
code:
|
|
1538
|
+
code: z6.ZodIssueCode.custom,
|
|
1522
1539
|
path: ["capabilities", index, "id"],
|
|
1523
1540
|
message: `duplicate capability declaration: ${declaration.id}`
|
|
1524
1541
|
});
|
|
@@ -1585,13 +1602,13 @@ var LIVE_ENDPOINT_NAME = "live";
|
|
|
1585
1602
|
// src/release/manifest.ts
|
|
1586
1603
|
import { createHash as createHash3 } from "node:crypto";
|
|
1587
1604
|
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
1588
|
-
import { z as
|
|
1605
|
+
import { z as z7 } from "zod";
|
|
1589
1606
|
var RELEASE_VERSION_RE = /^v\d+\.\d+\.\d+$/;
|
|
1590
|
-
var Sha256 =
|
|
1591
|
-
var ReleaseArtifactSchema =
|
|
1592
|
-
key:
|
|
1607
|
+
var Sha256 = z7.string().regex(/^[0-9a-f]{64}$/, "must be a lowercase hex sha256");
|
|
1608
|
+
var ReleaseArtifactSchema = z7.object({
|
|
1609
|
+
key: z7.string().min(1),
|
|
1593
1610
|
sha256: Sha256,
|
|
1594
|
-
bytes:
|
|
1611
|
+
bytes: z7.number().int().nonnegative()
|
|
1595
1612
|
}).strict();
|
|
1596
1613
|
var SIGNING_ALGORITHMS = [
|
|
1597
1614
|
"RSASSA_PSS_SHA_256",
|
|
@@ -1604,21 +1621,21 @@ var SIGNING_ALGORITHMS = [
|
|
|
1604
1621
|
"ECDSA_SHA_384",
|
|
1605
1622
|
"ECDSA_SHA_512"
|
|
1606
1623
|
];
|
|
1607
|
-
var ReleaseManifestSchema =
|
|
1608
|
-
version:
|
|
1609
|
-
gitCommit:
|
|
1610
|
-
createdAt:
|
|
1611
|
-
agentImage:
|
|
1612
|
-
repository:
|
|
1613
|
-
tag:
|
|
1614
|
-
digest:
|
|
1624
|
+
var ReleaseManifestSchema = z7.object({
|
|
1625
|
+
version: z7.string().regex(RELEASE_VERSION_RE, "must be vMAJOR.MINOR.PATCH"),
|
|
1626
|
+
gitCommit: z7.string().regex(/^[0-9a-f]{40}$/, "must be a full commit sha"),
|
|
1627
|
+
createdAt: z7.string().datetime(),
|
|
1628
|
+
agentImage: z7.object({
|
|
1629
|
+
repository: z7.string().min(1),
|
|
1630
|
+
tag: z7.string().min(1),
|
|
1631
|
+
digest: z7.string().regex(/^sha256:[0-9a-f]{64}$/)
|
|
1615
1632
|
}).strict(),
|
|
1616
|
-
lambda:
|
|
1617
|
-
skills:
|
|
1618
|
-
signature:
|
|
1619
|
-
kmsKeyArn:
|
|
1620
|
-
algorithm:
|
|
1621
|
-
value:
|
|
1633
|
+
lambda: z7.record(ReleaseArtifactSchema),
|
|
1634
|
+
skills: z7.object({ key: z7.string().min(1), sha256: Sha256 }).strict(),
|
|
1635
|
+
signature: z7.object({
|
|
1636
|
+
kmsKeyArn: z7.string().min(1),
|
|
1637
|
+
algorithm: z7.enum(SIGNING_ALGORITHMS),
|
|
1638
|
+
value: z7.string().min(1)
|
|
1622
1639
|
}).strict().optional()
|
|
1623
1640
|
}).strict();
|
|
1624
1641
|
function parseManifest(json) {
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
scheduledJobBindings,
|
|
25
25
|
slackCommandPrefixes,
|
|
26
26
|
webhookJobBindings
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-g56mqyfx.js";
|
|
28
28
|
|
|
29
29
|
// src/stacks/agent-stack.ts
|
|
30
30
|
import * as cdk from "aws-cdk-lib";
|
|
@@ -1104,6 +1104,14 @@ class FoundationApi extends cdk2.Stack {
|
|
|
1104
1104
|
`arn:${this.partition}:bedrock-agentcore:${this.region}:${this.account}:runtime/${names.runtimeName}*/runtime-endpoint/*`
|
|
1105
1105
|
]
|
|
1106
1106
|
}));
|
|
1107
|
+
invokerRole.addToPolicy(new iam2.PolicyStatement({
|
|
1108
|
+
sid: "StopSingleUseRuntimeSessions",
|
|
1109
|
+
actions: ["bedrock-agentcore:StopRuntimeSession"],
|
|
1110
|
+
resources: [
|
|
1111
|
+
`arn:${this.partition}:bedrock-agentcore:${this.region}:${this.account}:runtime/${names.runtimeName}*`,
|
|
1112
|
+
`arn:${this.partition}:bedrock-agentcore:${this.region}:${this.account}:runtime/${names.runtimeName}*/runtime-endpoint/*`
|
|
1113
|
+
]
|
|
1114
|
+
}));
|
|
1107
1115
|
invokerRole.addToPolicy(new iam2.PolicyStatement({
|
|
1108
1116
|
sid: "ReadRuntimeEndpointVersion",
|
|
1109
1117
|
actions: ["bedrock-agentcore:GetAgentRuntimeEndpoint"],
|
|
@@ -1937,6 +1945,7 @@ function deployStatements(stack, names, targets, instance) {
|
|
|
1937
1945
|
sid: "SmokeTestRuntime",
|
|
1938
1946
|
actions: [
|
|
1939
1947
|
"bedrock-agentcore:InvokeAgentRuntime",
|
|
1948
|
+
"bedrock-agentcore:StopRuntimeSession",
|
|
1940
1949
|
"bedrock-agentcore:GetAgentRuntime",
|
|
1941
1950
|
"bedrock-agentcore:ListAgentRuntimeVersions",
|
|
1942
1951
|
"bedrock-agentcore:GetAgentRuntimeEndpoint",
|
package/dist/src/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
FoundationPipeline,
|
|
11
11
|
NewsletterStack,
|
|
12
12
|
deployStatements
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-sgh3agpa.js";
|
|
14
14
|
import {
|
|
15
15
|
BUN_VERSION,
|
|
16
16
|
LAMBDA_ENTRY_POINTS,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
skillsKey,
|
|
45
45
|
skipBundle,
|
|
46
46
|
verifyManifest
|
|
47
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-g56mqyfx.js";
|
|
48
48
|
import"../chunk-dz91avrb.js";
|
|
49
49
|
export {
|
|
50
50
|
BUILD_TIMEOUT,
|
package/package.json
CHANGED
package/src/deploy/endpoint.ts
CHANGED
|
@@ -214,6 +214,32 @@ export interface SmokeOptions {
|
|
|
214
214
|
log?: (line: string) => void;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
/**
|
|
218
|
+
* End a smoke session once it has answered. Its id is minted per invoke and
|
|
219
|
+
* never used again, so otherwise the microVM idles out its whole idle timeout
|
|
220
|
+
* billed for its memory (~2 GB-hours each; a deploy runs three). Best-effort:
|
|
221
|
+
* a deployer without the permission still deploys.
|
|
222
|
+
*/
|
|
223
|
+
async function stopSmokeSession(
|
|
224
|
+
runner: EndpointRunner,
|
|
225
|
+
opts: SmokeOptions,
|
|
226
|
+
log: (line: string) => void,
|
|
227
|
+
): Promise<void> {
|
|
228
|
+
try {
|
|
229
|
+
await runner.capture([
|
|
230
|
+
"bedrock-agentcore",
|
|
231
|
+
"stop-runtime-session",
|
|
232
|
+
"--agent-runtime-arn",
|
|
233
|
+
opts.arn,
|
|
234
|
+
...(opts.qualifier === undefined ? [] : ["--qualifier", opts.qualifier]),
|
|
235
|
+
"--runtime-session-id",
|
|
236
|
+
opts.sessionId,
|
|
237
|
+
]);
|
|
238
|
+
} catch {
|
|
239
|
+
log(" (could not stop the smoke session; it ends at the idle timeout)");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
217
243
|
/** Invoke the runtime and assert the response says what a healthy runtime says. */
|
|
218
244
|
export async function smokeInvoke(runner: EndpointRunner, opts: SmokeOptions): Promise<void> {
|
|
219
245
|
const log = opts.log ?? ((line: string) => console.log(line));
|
|
@@ -250,6 +276,7 @@ export async function smokeInvoke(runner: EndpointRunner, opts: SmokeOptions): P
|
|
|
250
276
|
} finally {
|
|
251
277
|
await rm(dir, { recursive: true, force: true });
|
|
252
278
|
}
|
|
279
|
+
await stopSmokeSession(runner, opts, log);
|
|
253
280
|
log(` ${out.replaceAll("\n", "\n ")}`);
|
|
254
281
|
for (const needle of opts.expect ?? SMOKE_EXPECT)
|
|
255
282
|
if (!out.includes(needle)) throw new Error(`smoke test: response does not contain ${needle}`);
|
|
@@ -175,11 +175,13 @@ export function deployStatements(
|
|
|
175
175
|
// `foundation-deploy post-deploy` (and `deploy`'s inline promotion): the
|
|
176
176
|
// smoke test (`_smoke_test`, `_fs_probe`) against DEFAULT, then promotion
|
|
177
177
|
// of the new version onto `live`, which CREATES `live` when an instance
|
|
178
|
-
// brought up by `deploy` alone has none yet (`promoteEndpoint`).
|
|
178
|
+
// brought up by `deploy` alone has none yet (`promoteEndpoint`). Each
|
|
179
|
+
// smoke session is stopped once it answers: nothing invokes it again.
|
|
179
180
|
new iam.PolicyStatement({
|
|
180
181
|
sid: "SmokeTestRuntime",
|
|
181
182
|
actions: [
|
|
182
183
|
"bedrock-agentcore:InvokeAgentRuntime",
|
|
184
|
+
"bedrock-agentcore:StopRuntimeSession",
|
|
183
185
|
"bedrock-agentcore:GetAgentRuntime",
|
|
184
186
|
"bedrock-agentcore:ListAgentRuntimeVersions",
|
|
185
187
|
"bedrock-agentcore:GetAgentRuntimeEndpoint",
|
package/src/stacks/api-stack.ts
CHANGED
|
@@ -529,6 +529,19 @@ export class FoundationApi extends cdk.Stack {
|
|
|
529
529
|
],
|
|
530
530
|
}),
|
|
531
531
|
);
|
|
532
|
+
// A routine fire's session is single-use: the invoker ends it as soon as
|
|
533
|
+
// the fire answers instead of paying for its memory through the idle
|
|
534
|
+
// timeout (`isSingleUseSession` in gateway/src/invoker.ts).
|
|
535
|
+
invokerRole.addToPolicy(
|
|
536
|
+
new iam.PolicyStatement({
|
|
537
|
+
sid: "StopSingleUseRuntimeSessions",
|
|
538
|
+
actions: ["bedrock-agentcore:StopRuntimeSession"],
|
|
539
|
+
resources: [
|
|
540
|
+
`arn:${this.partition}:bedrock-agentcore:${this.region}:${this.account}:runtime/${names.runtimeName}*`,
|
|
541
|
+
`arn:${this.partition}:bedrock-agentcore:${this.region}:${this.account}:runtime/${names.runtimeName}*/runtime-endpoint/*`,
|
|
542
|
+
],
|
|
543
|
+
}),
|
|
544
|
+
);
|
|
532
545
|
// Which version the endpoint serves: the invoker names it in the session
|
|
533
546
|
// id so a thread moves off a pre-deploy microVM on its next turn.
|
|
534
547
|
invokerRole.addToPolicy(
|