Skip to content

Commit cbce862

Browse files
xxuamclaude
andauthored
feat(capacity-provider): complete CLI DevEx for journeys 2-4 (attach, volumes, TUI wizard, J4 delete-session) (#2133)
* feat(capacity-provider): complete journeys 2-4, TUI wizard parity, and DevEx polish - J2/J3: attach a runtime to a capacity provider by name or ARN, and mount CP volumes - J4: `capacity-provider delete-session` data-plane command - TUI: full add-capacity-provider wizard (volumes, encryption/KMS, instance profile, lifecycle timeouts); capacity-provider attach in the agent create/template and BYO flows - paired `--volume-name`/`--volume-size` flags (replacing `--volume name:sizeGiB`) - referential-integrity guard: block removing a capacity provider still referenced by a runtime - drop `[preview]` from the capacity-provider add/remove menus Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(capacity-provider): address PR #2068 review comments - BYO mapper (mapByoConfigToAgent) omits networkMode when a CP is attached — the AgentEnvSpec schema rejects a capacityProviderConfiguration combined with any networkMode, so a BYO CP submission was failing to persist. - delete-session by-name resolution collects all deployed-state matches and disambiguates by region (resolve within --region; reject cross-region ambiguity) instead of blindly taking the first target. - forward capacityProviderConfiguration + volumes through the import path (executeImportAgent params + AgentPrimitive/useAddAgent/create callers). - create rejects the capacity-provider name form (a new project has no sibling to resolve); only an external ARN can attach at create time. - generate + BYO wizard advanced-settings routing matches the steps memo when network and capacityProvider are both selected (CP wins; no skipped screen). - preserve an explicit volumeEncrypted=false in the CP wizard so the primitive emits Encrypted:false (service default is true). - tighten CAPACITY_PROVIDER_ARN_PATTERN to {name}-{10 alnum} so malformed external ARNs fail at validate time (kept in sync with @aws/agentcore-cdk). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent df5a406 commit cbce862

57 files changed

Lines changed: 3166 additions & 231 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ These options are available on all commands:
3939
- `status` - Check deployment status
4040
- `dev` - Local development server (CodeZip: uvicorn with hot-reload; Container: Docker build + run with volume mount)
4141
- `invoke` - Invoke agents (local or deployed)
42+
- `capacity-provider delete-session` - Delete (deprovision) a live capacity provider session (data-plane)
4243
- `run eval` - Run on-demand evaluation against agent sessions
4344
- `evals history` - View past eval run results
4445
- `fetch access` - Fetch access info for a deployed gateway or agent

‎docs/commands.md‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ agentcore add agent \
318318
| `--client-secret <secret>` | OAuth client secret |
319319
| `--request-header-allowlist <headers>` | Comma-separated list of inbound header names to forward to the agent. `X-*` names (e.g. `X-Api-Key`, `X-Custom-Signature`) pass through unchanged; bare names without an `X-` prefix are auto-prefixed with the legacy `X-Amzn-Bedrock-AgentCore-Runtime-Custom-` prefix for backward compatibility. |
320320
| `--session-storage-mount-path <path>` | Absolute mount path for session filesystem storage (e.g. `/mnt/session-storage`) |
321+
| `--capacity-provider <name-or-arn>` | Attach the runtime to a capacity provider (customer-managed EC2 compute). Accepts an in-project capacity-provider name or an external CP ARN. Mutually exclusive with `--network-mode VPC`. |
322+
| `--cp-volume-name <name>` | Capacity provider volume name to mount (repeatable, paired by position with `--cp-volume-mount-path`). The name must match a volume defined on the attached capacity provider. |
323+
| `--cp-volume-mount-path <path>` | Capacity provider volume mount path under `/mnt` (e.g. `/mnt/models`, repeatable, paired with `--cp-volume-name`) |
321324
| `--with-config-bundle` | Wire a config bundle into the generated agent template |
322325
| `--idle-timeout <seconds>` | Idle session timeout in seconds |
323326
| `--max-lifetime <seconds>` | Max instance lifetime in seconds |
@@ -814,7 +817,7 @@ agentcore add capacity-provider \
814817
--security-groups sg-0123456789abcdef0 \
815818
--os LINUX_ARM64 \
816819
--instance-types c7g.large,c7g.xlarge \
817-
--volume data:20 --volume-encrypted \
820+
--volume-name data --volume-size 20 --volume-encrypted \
818821
--idle-instance-timeout 3600 \
819822
--max-lifetime 28800
820823
```
@@ -828,7 +831,8 @@ agentcore add capacity-provider \
828831
| `--security-groups <groups>` | Comma-separated security group IDs, 1–16 (required) |
829832
| `--os <os>` | `LINUX_X86_64` (default) or `LINUX_ARM64` |
830833
| `--instance-types <types>` | Comma-separated allowed EC2 instance types, 1–30 (required) |
831-
| `--volume <name:sizeGiB>` | Named EBS volume as `name:sizeGiB` (repeatable, max 5) |
834+
| `--volume-name <name>` | Named EBS volume name (repeatable, max 5; paired with `--volume-size`) |
835+
| `--volume-size <sizeGiB>` | EBS volume size in GiB (repeatable; paired with `--volume-name`) |
832836
| `--volume-encrypted` | Encrypt EBS volumes |
833837
| `--volume-kms-key <arn>` | KMS key ARN for EBS volume encryption |
834838
| `--instance-profile-arn <arn>` | IAM instance profile ARN for launched instances |
@@ -905,6 +909,35 @@ agentcore dev call-tool --tool myTool --input '{"arg": "value"}'
905909
| `-b, --no-browser` | Use terminal TUI instead of web-based chat UI |
906910
| `--no-traces` | Disable local OTEL trace collection |
907911

912+
### capacity-provider delete-session
913+
914+
Delete (deprovision) a single live capacity provider session. This is a data-plane operation: it terminates the
915+
session's EC2 instance and **permanently deletes any persistent EBS volumes** attached to the session (data loss). The
916+
operation is asynchronous — it returns immediately with status `Deprovisioning`. You get the session id from `invoke`
917+
(it echoes the session it used); there is no list-sessions API.
918+
919+
```bash
920+
# By in-project capacity provider name (resolved to its id from deployed state)
921+
agentcore capacity-provider delete-session --capacity-provider my-pool --session-id <sessionId>
922+
923+
# By capacity provider id, without a project (the data-plane API is keyed on the id)
924+
agentcore capacity-provider delete-session \
925+
--capacity-provider my-pool-a1b2c3d4e5 --session-id <sessionId> --region us-west-2 --yes
926+
927+
# By ARN (the id is extracted from it), without a project (region auto-detected from the ARN)
928+
agentcore capacity-provider delete-session \
929+
--capacity-provider arn:aws:bedrock-agentcore:us-west-2:123456789012:capacity-provider/my-pool-a1b2c3d4e5 \
930+
--session-id <sessionId> --yes
931+
```
932+
933+
| Option | Description |
934+
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
935+
| `--capacity-provider <name-id-or-arn>` | Capacity provider: an in-project name (resolved to its id via deployed state), a capacity provider id, or an ARN (id extracted from it). The API is keyed on the id. (**required**) |
936+
| `--session-id <id>` | Session id to delete (**required**) |
937+
| `--region <region>` | AWS region (auto-detected from the ARN / project otherwise; required with a bare id outside a project unless the environment sets one) |
938+
| `--yes` | Skip the destructive confirmation prompt (required for non-interactive use) |
939+
| `--json` | JSON output |
940+
908941
### invoke
909942

910943
Invoke a deployed agent endpoint.
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import { createTestProject, readProjectConfig, runCLI } from '../src/test-utils/index.js';
2+
import type { TestProject } from '../src/test-utils/index.js';
3+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
4+
5+
const OPERATOR_ROLE_ARN = 'arn:aws:iam::123456789012:role/MyOperatorRole';
6+
7+
describe('integration: attach capacity provider to an agent (J2/J3) + delete-session (J4)', () => {
8+
let project: TestProject;
9+
const cpName = `IntegAttachCp${Date.now().toString().slice(-6)}`;
10+
11+
beforeAll(async () => {
12+
project = await createTestProject({ noAgent: true });
13+
// A capacity provider with a named volume for the runtime to mount (J3).
14+
const cp = await runCLI(
15+
[
16+
'add',
17+
'capacity-provider',
18+
'--name',
19+
cpName,
20+
'--operator-role-arn',
21+
OPERATOR_ROLE_ARN,
22+
'--subnets',
23+
'subnet-0123456789abcdef0',
24+
'--security-groups',
25+
'sg-0123456789abcdef0',
26+
'--os',
27+
'LINUX_X86_64',
28+
'--instance-types',
29+
'c6a.large',
30+
'--volume-name',
31+
'model-weights',
32+
'--volume-size',
33+
'100',
34+
'--json',
35+
],
36+
project.projectPath
37+
);
38+
expect(cp.exitCode, `stdout: ${cp.stdout}, stderr: ${cp.stderr}`).toBe(0);
39+
});
40+
41+
afterAll(async () => {
42+
await project.cleanup();
43+
});
44+
45+
it('attaches a BYO agent to a sibling capacity provider by name and mounts a CP volume', async () => {
46+
const agentName = 'CpAttachAgent';
47+
const result = await runCLI(
48+
[
49+
'add',
50+
'agent',
51+
'--name',
52+
agentName,
53+
'--type',
54+
'byo',
55+
'--language',
56+
'Python',
57+
'--framework',
58+
'Strands',
59+
'--model-provider',
60+
'Bedrock',
61+
'--code-location',
62+
`apps/${agentName}`,
63+
'--capacity-provider',
64+
cpName,
65+
'--cp-volume-name',
66+
'model-weights',
67+
'--cp-volume-mount-path',
68+
'/mnt/models',
69+
'--json',
70+
],
71+
project.projectPath
72+
);
73+
74+
expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
75+
expect(JSON.parse(result.stdout).success).toBe(true);
76+
77+
const config = await readProjectConfig(project.projectPath);
78+
const agent = config.runtimes.find(a => a.name === agentName);
79+
expect(agent, `Agent "${agentName}" should be in config`).toBeTruthy();
80+
expect(agent!.capacityProviderConfiguration).toEqual({ capacityProviderName: cpName });
81+
expect(agent!.filesystemConfigurations).toContainEqual({
82+
capacityProviderVolume: { volumeName: 'model-weights', mountPath: '/mnt/models' },
83+
});
84+
});
85+
86+
it('attaches a BYO agent to an external capacity provider by ARN', async () => {
87+
const agentName = 'CpArnAgent';
88+
const arn = 'arn:aws:bedrock-agentcore:us-west-2:123456789012:capacity-provider/ext_pool-a1b2c3d4e5';
89+
const result = await runCLI(
90+
[
91+
'add',
92+
'agent',
93+
'--name',
94+
agentName,
95+
'--type',
96+
'byo',
97+
'--language',
98+
'Python',
99+
'--framework',
100+
'Strands',
101+
'--model-provider',
102+
'Bedrock',
103+
'--code-location',
104+
`apps/${agentName}`,
105+
'--capacity-provider',
106+
arn,
107+
'--json',
108+
],
109+
project.projectPath
110+
);
111+
112+
expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
113+
const config = await readProjectConfig(project.projectPath);
114+
const agent = config.runtimes.find(a => a.name === agentName);
115+
expect(agent!.capacityProviderConfiguration).toEqual({ capacityProviderArn: arn });
116+
});
117+
118+
it('rejects a CP volume mount without a capacity provider attachment', async () => {
119+
const result = await runCLI(
120+
[
121+
'add',
122+
'agent',
123+
'--name',
124+
'CpVolNoAttach',
125+
'--type',
126+
'byo',
127+
'--language',
128+
'Python',
129+
'--framework',
130+
'Strands',
131+
'--model-provider',
132+
'Bedrock',
133+
'--code-location',
134+
'apps/CpVolNoAttach',
135+
'--cp-volume-name',
136+
'model-weights',
137+
'--cp-volume-mount-path',
138+
'/mnt/models',
139+
'--json',
140+
],
141+
project.projectPath
142+
);
143+
expect(result.exitCode).not.toBe(0);
144+
});
145+
146+
it('rejects attaching a capacity provider together with VPC networking', async () => {
147+
const result = await runCLI(
148+
[
149+
'add',
150+
'agent',
151+
'--name',
152+
'CpVpcAgent',
153+
'--type',
154+
'byo',
155+
'--language',
156+
'Python',
157+
'--framework',
158+
'Strands',
159+
'--model-provider',
160+
'Bedrock',
161+
'--code-location',
162+
'apps/CpVpcAgent',
163+
'--capacity-provider',
164+
cpName,
165+
'--network-mode',
166+
'VPC',
167+
'--subnets',
168+
'subnet-0123456789abcdef0',
169+
'--security-groups',
170+
'sg-0123456789abcdef0',
171+
'--json',
172+
],
173+
project.projectPath
174+
);
175+
expect(result.exitCode).not.toBe(0);
176+
});
177+
178+
it('delete-session rejects an invalid session id', async () => {
179+
const result = await runCLI(
180+
[
181+
'capacity-provider',
182+
'delete-session',
183+
'--capacity-provider',
184+
'arn:aws:bedrock-agentcore:us-west-2:123456789012:capacity-provider/x_pool-a1b2c3d4e5',
185+
'--session-id',
186+
'bad session id',
187+
'--yes',
188+
'--json',
189+
],
190+
project.projectPath
191+
);
192+
expect(result.exitCode).not.toBe(0);
193+
});
194+
});

‎integ-tests/add-remove-capacity-provider.test.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ describe('integration: add and remove capacity providers', () => {
7878
'LINUX_ARM64',
7979
'--instance-types',
8080
'c7g.large,c7g.xlarge',
81-
'--volume',
82-
'data:20',
81+
'--volume-name',
82+
'data',
83+
'--volume-size',
84+
'20',
8385
'--volume-encrypted',
8486
'--idle-instance-timeout',
8587
'3600',

0 commit comments

Comments
 (0)