diff --git a/README.md b/README.md index 12896485a..01463c596 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,15 @@ agentcore # interactive TUI │ ├── list │ ├── update │ └── delete +├── runtime # inspect deployed AgentCore Runtimes +│ ├── get # fetch a Runtime by id +│ ├── list # list Runtimes (server-side paginated) +│ ├── version +│ │ ├── get # get a specific Runtime version +│ │ └── list # list a Runtime's versions +│ └── endpoint +│ ├── get # get a Runtime endpoint by qualifier +│ └── list # list a Runtime's endpoints └── config # read/write global config values ``` @@ -84,6 +93,14 @@ agentcore harness invoke --id --session-id --qualifier PRO # Run a shell command inside the agent runtime agentcore harness exec --id --command "ls -la" --json + +# Inspect deployed Runtimes without project configuration or deployment +agentcore runtime get --id +agentcore runtime list --max-results 20 +agentcore runtime version get --id --version +agentcore runtime version list --id --max-results 20 +agentcore runtime endpoint get --id --qualifier DEFAULT +agentcore runtime endpoint list --id --max-results 20 ``` --- diff --git a/src/components/RouterScreen.test.tsx b/src/components/RouterScreen.test.tsx index 8dbd8ee3b..44e1705bd 100644 --- a/src/components/RouterScreen.test.tsx +++ b/src/components/RouterScreen.test.tsx @@ -15,6 +15,8 @@ describe("menu rendering", () => { const frame = r.lastFrame()!; expect(frame).toContain("harness"); expect(frame).toContain("manage agentcore harnesses"); + expect(frame).toContain("runtime"); + expect(frame).toContain("inspect AgentCore Runtimes"); expect(frame).toContain("config"); expect(frame).toContain("read/write global config values"); r.unmount(); @@ -86,7 +88,7 @@ describe("navigation", () => { await waitForText(r.lastFrame, "❯ harness"); await r.press("down"); - await waitForText(r.lastFrame, "❯ config"); + await waitForText(r.lastFrame, "❯ runtime"); r.unmount(); }); diff --git a/src/core/index.tsx b/src/core/index.tsx index fe3957c29..b28fa5323 100644 --- a/src/core/index.tsx +++ b/src/core/index.tsx @@ -2,6 +2,7 @@ import { BedrockAgentCoreControlClient } from "@aws-sdk/client-bedrock-agentcore import { BedrockAgentCoreClient } from "@aws-sdk/client-bedrock-agentcore"; import { IAMClient } from "@aws-sdk/client-iam"; import { HarnessClient } from "./harness"; +import { RuntimeClient } from "./runtime"; import type { AwsClients, ClientConfig, @@ -29,6 +30,7 @@ export class CoreClient implements AwsClients { // Feature-scoped sub-clients. Access as e.g. `coreClient.harness.getHarness(...)`. readonly harness: HarnessClient = new HarnessClient(this); + readonly runtime: RuntimeClient = new RuntimeClient(this); constructor( private readonly createControlClient: CreateControlClient, diff --git a/src/core/runtime.tsx b/src/core/runtime.tsx new file mode 100644 index 000000000..77cc6c3e8 --- /dev/null +++ b/src/core/runtime.tsx @@ -0,0 +1,91 @@ +import { + GetAgentRuntimeCommand, + GetAgentRuntimeEndpointCommand, + ListAgentRuntimeEndpointsCommand, + ListAgentRuntimesCommand, + ListAgentRuntimeVersionsCommand, + type GetAgentRuntimeEndpointResponse, + type GetAgentRuntimeResponse, + type ListAgentRuntimeEndpointsResponse, + type ListAgentRuntimesResponse, + type ListAgentRuntimeVersionsResponse, +} from "@aws-sdk/client-bedrock-agentcore-control"; +import type { CoreRuntimeClient } from "../handlers/runtime/types"; +import type { AwsClients, CoreOptions } from "./types"; +import { toClientConfig } from "./utils"; + +export class RuntimeClient implements CoreRuntimeClient { + constructor(private readonly clients: AwsClients) {} + + async getRuntime(id: string, options: CoreOptions): Promise { + return this.clients + .control(toClientConfig(options)) + .send(new GetAgentRuntimeCommand({ agentRuntimeId: id })); + } + + async getRuntimeVersion( + id: string, + version: string, + options: CoreOptions, + ): Promise { + return this.clients.control(toClientConfig(options)).send( + new GetAgentRuntimeCommand({ + agentRuntimeId: id, + agentRuntimeVersion: version, + }), + ); + } + + async getRuntimeEndpoint( + id: string, + qualifier: string, + options: CoreOptions, + ): Promise { + return this.clients.control(toClientConfig(options)).send( + new GetAgentRuntimeEndpointCommand({ + agentRuntimeId: id, + endpointName: qualifier, + }), + ); + } + + async listRuntimes( + nextToken: string | undefined, + maxResults: number | undefined, + options: CoreOptions, + ): Promise { + return this.clients + .control(toClientConfig(options)) + .send(new ListAgentRuntimesCommand({ nextToken, maxResults })); + } + + async listRuntimeVersions( + id: string, + nextToken: string | undefined, + maxResults: number | undefined, + options: CoreOptions, + ): Promise { + return this.clients.control(toClientConfig(options)).send( + new ListAgentRuntimeVersionsCommand({ + agentRuntimeId: id, + nextToken, + maxResults, + }), + ); + } + + async listRuntimeEndpoints( + id: string, + nextToken: string | undefined, + maxResults: number | undefined, + options: CoreOptions, + ): Promise { + return this.clients.control(toClientConfig(options)).send( + new ListAgentRuntimeEndpointsCommand({ + agentRuntimeId: id, + nextToken, + maxResults, + }), + ); + } +} diff --git a/src/handlers/index.tsx b/src/handlers/index.tsx index 5820179cb..3707fc373 100644 --- a/src/handlers/index.tsx +++ b/src/handlers/index.tsx @@ -1,5 +1,6 @@ import { Router } from "../router"; import { createHarnessHandler } from "./harness/index.tsx"; +import { createRuntimeHandler } from "./runtime/index.tsx"; import { DebugKey, EndpointKey, JsonKey, RegionKey } from "./keys.tsx"; import { createConfigHandler } from "./config/"; import { createProjectHandler } from "./project/index.ts"; @@ -33,6 +34,7 @@ export function createRootHandler(core: Core, config: RootHandlerConfig): Router // Install sub handlers root.handler(createHarnessHandler(core, io)); + root.handler(createRuntimeHandler(core, io)); root.handler(createConfigHandler(io)); root.handler(createProjectHandler()); diff --git a/src/handlers/root.test.tsx b/src/handlers/root.test.tsx index 221c1daad..b79eaec2f 100644 --- a/src/handlers/root.test.tsx +++ b/src/handlers/root.test.tsx @@ -9,6 +9,11 @@ describe("createRootHandler", () => { logger: createSilentLogger(), }); expect(root.name()).toBe("agentcore"); - expect(root.children().map((c) => c.name())).toEqual(["harness", "config", "project"]); + expect(root.children().map((c) => c.name())).toEqual([ + "harness", + "runtime", + "config", + "project", + ]); }); }); diff --git a/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.140854af01fd7827.json b/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.140854af01fd7827.json new file mode 100644 index 000000000..136610f6c --- /dev/null +++ b/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.140854af01fd7827.json @@ -0,0 +1,33 @@ +{ + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "2", + "createdAt": { + "$date": "2026-07-21T15:24:52.318Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:21.499Z" + }, + "roleArn": "arn:aws:iam::685197708687:role/tf_acc_test_1997929140646926281", + "networkConfiguration": { + "networkMode": "PUBLIC" + }, + "status": "READY", + "lifecycleConfiguration": { + "idleRuntimeSessionTimeout": 900, + "maxLifetime": 28800 + }, + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "workloadIdentityDetails": { + "workloadIdentityArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:workload-identity-directory/default/workload-identity/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx" + }, + "agentRuntimeArtifact": { + "containerConfiguration": { + "containerUri": "public.ecr.aws/y5s8y8h8/harness-us-west-2:latest" + } + }, + "metadataConfiguration": { + "requireMMDSV2": true + } +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.97ebe200714d941e.json b/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.97ebe200714d941e.json new file mode 100644 index 000000000..758a51ee2 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.97ebe200714d941e.json @@ -0,0 +1,33 @@ +{ + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "1", + "createdAt": { + "$date": "2026-07-21T15:24:53.572Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:24:53.572Z" + }, + "roleArn": "arn:aws:iam::685197708687:role/tf_acc_test_1997929140646926281", + "networkConfiguration": { + "networkMode": "PUBLIC" + }, + "status": "READY", + "lifecycleConfiguration": { + "idleRuntimeSessionTimeout": 900, + "maxLifetime": 28800 + }, + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "workloadIdentityDetails": { + "workloadIdentityArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:workload-identity-directory/default/workload-identity/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx" + }, + "agentRuntimeArtifact": { + "containerConfiguration": { + "containerUri": "public.ecr.aws/y5s8y8h8/harness-us-west-2:latest" + } + }, + "metadataConfiguration": { + "requireMMDSV2": true + } +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.9b8f562f35114475.json b/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.9b8f562f35114475.json new file mode 100644 index 000000000..3e9097e0d --- /dev/null +++ b/src/handlers/runtime/__fixtures__/GetAgentRuntimeCommand.9b8f562f35114475.json @@ -0,0 +1,6 @@ +{ + "$error": { + "name": "ResourceNotFoundException", + "message": "Agent with agentId: missing_runtime-0000000000, accountId: 685197708687, and version: null not found!" + } +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/GetAgentRuntimeEndpointCommand.1aa8574ea8360d43.json b/src/handlers/runtime/__fixtures__/GetAgentRuntimeEndpointCommand.1aa8574ea8360d43.json new file mode 100644 index 000000000..aebcbf8dc --- /dev/null +++ b/src/handlers/runtime/__fixtures__/GetAgentRuntimeEndpointCommand.1aa8574ea8360d43.json @@ -0,0 +1,14 @@ +{ + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/DEFAULT", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "createdAt": { + "$date": "2026-07-21T15:24:52.560Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:21.499Z" + }, + "name": "DEFAULT", + "id": "DEFAULT", + "liveVersion": "2" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.140854af01fd7827.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.140854af01fd7827.json new file mode 100644 index 000000000..9a3012f28 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.140854af01fd7827.json @@ -0,0 +1,33 @@ +{ + "runtimeEndpoints": [ + { + "name": "runtimeReadOnlyFixture", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/runtimeReadOnlyFixture", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "runtimeReadOnlyFixture", + "createdAt": { + "$date": "2026-07-21T15:25:40.102Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:40.952Z" + }, + "liveVersion": "2", + "description": "Stable shared endpoint for AgentCore CLI Runtime read-only fixture recording" + }, + { + "name": "DEFAULT", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/DEFAULT", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "DEFAULT", + "createdAt": { + "$date": "2026-07-21T15:24:52.560Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:21.499Z" + }, + "liveVersion": "2" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.1d171c98cd60b7c4.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.1d171c98cd60b7c4.json new file mode 100644 index 000000000..eb0718f4b --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.1d171c98cd60b7c4.json @@ -0,0 +1,18 @@ +{ + "runtimeEndpoints": [ + { + "name": "DEFAULT", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/DEFAULT", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "DEFAULT", + "createdAt": { + "$date": "2026-07-21T15:24:52.560Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:21.499Z" + }, + "liveVersion": "2" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.52cf5ddfc336d4d2.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.52cf5ddfc336d4d2.json new file mode 100644 index 000000000..40c06bccd --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimeEndpointsCommand.52cf5ddfc336d4d2.json @@ -0,0 +1,20 @@ +{ + "runtimeEndpoints": [ + { + "name": "runtimeReadOnlyFixture", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/runtimeReadOnlyFixture", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "runtimeReadOnlyFixture", + "createdAt": { + "$date": "2026-07-21T15:25:40.102Z" + }, + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:40.952Z" + }, + "liveVersion": "2", + "description": "Stable shared endpoint for AgentCore CLI Runtime read-only fixture recording" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgHTCX90veyHQpW0JbzdFgJCAAAB7DCCAegGCSqGSIb3DQEHBqCCAdkwggHVAgEAMIIBzgYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzXdq_zR1bimIWtQ_0CARCAggGfKjn69njYg3vBDeIAyLfH8q9m_O480LF2QMDi6BTVyJ70W0yKBU6bFBR3UvX61r_dQRqviT_A7gP1nndeLPIVoeaoH5E66U9njh8TO9uBRArYUqmdMtoN2zL4z4pPXncZzBtBDrSetRhOk_Az6YyGFPuZRqbn9o054gP5b4AMLENbckixIotwZPbYl7_WHNev0IZYhNaqXIgDjgyI517p0mRrWfRe4Ddv1G-bpox-6zIg5IVw1K38EQjvdk55Ct0ivrWvPpN_xTqETf6E1nkjtgMu3OGm-sKqZtdpVfAI_1cElM6pDi6HJ2bRx5rNFav1gybOp9mFRGRpNGMpUppDQ-SmCalZ7t8wqWCt0nKzn8kAtBqVOIIMSXwUfgvjiE9IsM2g3nPGSXwmOkKwAl3hck9Y5UQsN8tSyyxSEhqXbEJBra0LRKEtj2f4tVnQ6NHrXxgrfU3TfRopLs1PjRXSY-e_XUScXbQ7taQJDuC1r11isln9EZRje0iQ8unWWSnZvFdVcvAqzfWlz9fG3Kz1bj9fCQ0-l4aeY64N6nJijw==" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.140854af01fd7827.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.140854af01fd7827.json new file mode 100644 index 000000000..c51ceb30b --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.140854af01fd7827.json @@ -0,0 +1,26 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "2", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:21.499Z" + }, + "status": "READY" + }, + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "1", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": { + "$date": "2026-07-21T15:24:53.572Z" + }, + "status": "READY" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.52cf5ddfc336d4d2.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.52cf5ddfc336d4d2.json new file mode 100644 index 000000000..15f0e1a34 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.52cf5ddfc336d4d2.json @@ -0,0 +1,16 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "2", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": { + "$date": "2026-07-21T15:25:21.499Z" + }, + "status": "READY" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgEwXMAtTGTZFyWB6KZJtPn-AAAB0jCCAc4GCSqGSIb3DQEHBqCCAb8wggG7AgEAMIIBtAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAylUsElcghzf4NUBekCARCAggGFF5whr4_8k1-yrxtlajLC17iTtz9pMjqudZrl7Y8ThJ9zRhnUFv8pbwu7RhGP7PaJKPIQD4StFOj3OSUXBL5dXN81JpbJSIrHm5Hxq0VS_q9hszeRO97gG6ltMo4Qmu17dFndYD0amjEpHDcp4b1d-bHrKu1exmbqwo0cak87FinliDqGAd7tClaOOry60psmqDxpxpgmSvPnw7LfT3t4R-pM4oo1gxGELSmXWV_7qaWRpSKSrLr7ZD67nssylo5F4hB9ut1KQMvLBYALvzHeI5Na873JU8oYtU1unOAoCrl1AqTCS3sS0RgqbYrOLmw0bKgxk4-OjbYyH2n72BiD1lcMdk95ZYG7ZXkhn6NZQsdVDVT1Ez-RKU6ry5CBMlQdo8GXQ1quzdGqnPwXAWKs80jGPf9C10vhVmL1fQ9DFlfZIo4b0h3ztZEon8IX84cXnEJX41up7qJWqefRHrirOjsvUwBpRK8brnreCQ1JeJeBY065x69iBAQWH3e9AI2lcPBvVR0=" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.d9f8a63aba5fece2.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.d9f8a63aba5fece2.json new file mode 100644 index 000000000..72f75b943 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimeVersionsCommand.d9f8a63aba5fece2.json @@ -0,0 +1,15 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "1", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": { + "$date": "2026-07-21T15:24:53.572Z" + }, + "status": "READY" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimesCommand.21b26ceeb17ddd46.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimesCommand.21b26ceeb17ddd46.json new file mode 100644 index 000000000..ff1965d51 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimesCommand.21b26ceeb17ddd46.json @@ -0,0 +1,15 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/harness_tf_acc_test_1997929140646926281-Z7D2FxDMk2", + "agentRuntimeId": "harness_tf_acc_test_1997929140646926281-Z7D2FxDMk2", + "agentRuntimeVersion": "1", + "agentRuntimeName": "harness_tf_acc_test_1997929140646926281", + "lastUpdatedAt": { + "$date": "2026-05-01T18:19:03.512Z" + }, + "status": "READY" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgERE3Zyf3dYmd2LiyBNyCGEAAABnDCCAZgGCSqGSIb3DQEHBqCCAYkwggGFAgEAMIIBfgYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAyfUbmfL0KkkYuZZjACARCAggFPo8_Z_n6DRJs7flKkMS76z_JFSAm1blzGlN7POeFElkiXsL7aZjMsXg4ZA_23v5B-MkGPNDk-JX3nvwhPY-m4ykso-CkulJ6-Ek1jq2OqRTUw0B3c0LEGJKBGa38UzkKv1Vz2gEDELmDHJV8pMfa6oR4aUMi_ak20jSTTCvinG7vEuToL5raasFar5772NrT1Rs0h_VQ_P3EIiw-XWUONLv3pkVP7PAfGSB7wI3pWYHMXZGPzxlUrkpUMM_arxdNkweYTbuzjx2hZyws0W-eLlqhy-veF82FpJj4Yshb6TsIQnBlUCl-Sf9PDbBBbBrmg08-h6BumkebR1OIRVISn5FRodYKirS4UdZdCiAiRVT5jKy6EWdCVc2rUiD2R7CA_jR2U_nPVPuJU0YA4y2ZMeAg4l-q-2h001YWYfGtIN967xQbRCKc6nU95IhKLZSM=" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/ListAgentRuntimesCommand.7d2e22c637f6b633.json b/src/handlers/runtime/__fixtures__/ListAgentRuntimesCommand.7d2e22c637f6b633.json new file mode 100644 index 000000000..fd8948080 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/ListAgentRuntimesCommand.7d2e22c637f6b633.json @@ -0,0 +1,16 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/testdeploymentnow_MyAgent-NbnwifHv2x", + "agentRuntimeId": "testdeploymentnow_MyAgent-NbnwifHv2x", + "agentRuntimeVersion": "1", + "agentRuntimeName": "testdeploymentnow_MyAgent", + "description": "AgentCore Runtime: testdeploymentnow_MyAgent", + "lastUpdatedAt": { + "$date": "2026-02-10T21:07:43.525Z" + }, + "status": "READY" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgG6cGcJPqi0LZHbjKr5ChQAAAABjjCCAYoGCSqGSIb3DQEHBqCCAXswggF3AgEAMIIBcAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzvpT6lITCSPK2ByJMCARCAggFB8UZbtS6rwjN4RLfbZ2CtSBZLpk6aGGY0Yq_ssMBfZkm9Z48YyBRdnJGu97eA7UcLpUY486A2fjR9OO7zlXqmXjHhQyHuWIMPFfzQklRG8aRwg36oSiwEKTqaviU1_fyI4SNlm-Jh1vobCDp8hZUOgM91j0FwpxtgkN3QP083tsRGXopXyk4L40VQL5w1x4SYOGozT1GcWgQJxXYnxV6756-Ph7kPoTQap-qISzcPugud5rXsXlleFa0YBt40tk39WZP6221FehU526dWU38q9g_-_AE2QpugnUQMRyJjAMtyEbo2wRLjiSLe_nyf8qgmZtygvl5Dgs-csa4dMek7mwQLwIzfoPhqIIMSyuQmn_o07XIygHneYtHzzAWKpXQ0RPiTy_pZiiNv0iZkWov8xKvoehHnWJJTDPRmsTiwJF4k" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/endpoint-get.golden.json b/src/handlers/runtime/__fixtures__/endpoint-get.golden.json new file mode 100644 index 000000000..edffedd55 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/endpoint-get.golden.json @@ -0,0 +1,10 @@ +{ + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/DEFAULT", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "createdAt": "2026-07-21T15:24:52.560Z", + "lastUpdatedAt": "2026-07-21T15:25:21.499Z", + "name": "DEFAULT", + "id": "DEFAULT", + "liveVersion": "2" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/endpoint-list-id-over-48.golden.json b/src/handlers/runtime/__fixtures__/endpoint-list-id-over-48.golden.json new file mode 100644 index 000000000..8d42016d4 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/endpoint-list-id-over-48.golden.json @@ -0,0 +1,25 @@ +{ + "runtimeEndpoints": [ + { + "name": "runtimeReadOnlyFixture", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/runtimeReadOnlyFixture", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "runtimeReadOnlyFixture", + "createdAt": "2026-07-21T15:25:40.102Z", + "lastUpdatedAt": "2026-07-21T15:25:40.952Z", + "liveVersion": "2", + "description": "Stable shared endpoint for AgentCore CLI Runtime read-only fixture recording" + }, + { + "name": "DEFAULT", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/DEFAULT", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "DEFAULT", + "createdAt": "2026-07-21T15:24:52.560Z", + "lastUpdatedAt": "2026-07-21T15:25:21.499Z", + "liveVersion": "2" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/endpoint-list-page-1.golden.json b/src/handlers/runtime/__fixtures__/endpoint-list-page-1.golden.json new file mode 100644 index 000000000..e086e5748 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/endpoint-list-page-1.golden.json @@ -0,0 +1,16 @@ +{ + "runtimeEndpoints": [ + { + "name": "runtimeReadOnlyFixture", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/runtimeReadOnlyFixture", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "runtimeReadOnlyFixture", + "createdAt": "2026-07-21T15:25:40.102Z", + "lastUpdatedAt": "2026-07-21T15:25:40.952Z", + "liveVersion": "2", + "description": "Stable shared endpoint for AgentCore CLI Runtime read-only fixture recording" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgHTCX90veyHQpW0JbzdFgJCAAAB7DCCAegGCSqGSIb3DQEHBqCCAdkwggHVAgEAMIIBzgYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzXdq_zR1bimIWtQ_0CARCAggGfKjn69njYg3vBDeIAyLfH8q9m_O480LF2QMDi6BTVyJ70W0yKBU6bFBR3UvX61r_dQRqviT_A7gP1nndeLPIVoeaoH5E66U9njh8TO9uBRArYUqmdMtoN2zL4z4pPXncZzBtBDrSetRhOk_Az6YyGFPuZRqbn9o054gP5b4AMLENbckixIotwZPbYl7_WHNev0IZYhNaqXIgDjgyI517p0mRrWfRe4Ddv1G-bpox-6zIg5IVw1K38EQjvdk55Ct0ivrWvPpN_xTqETf6E1nkjtgMu3OGm-sKqZtdpVfAI_1cElM6pDi6HJ2bRx5rNFav1gybOp9mFRGRpNGMpUppDQ-SmCalZ7t8wqWCt0nKzn8kAtBqVOIIMSXwUfgvjiE9IsM2g3nPGSXwmOkKwAl3hck9Y5UQsN8tSyyxSEhqXbEJBra0LRKEtj2f4tVnQ6NHrXxgrfU3TfRopLs1PjRXSY-e_XUScXbQ7taQJDuC1r11isln9EZRje0iQ8unWWSnZvFdVcvAqzfWlz9fG3Kz1bj9fCQ0-l4aeY64N6nJijw==" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/endpoint-list-page-2.golden.json b/src/handlers/runtime/__fixtures__/endpoint-list-page-2.golden.json new file mode 100644 index 000000000..4a083a46f --- /dev/null +++ b/src/handlers/runtime/__fixtures__/endpoint-list-page-2.golden.json @@ -0,0 +1,14 @@ +{ + "runtimeEndpoints": [ + { + "name": "DEFAULT", + "agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx/runtime-endpoint/DEFAULT", + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "status": "READY", + "id": "DEFAULT", + "createdAt": "2026-07-21T15:24:52.560Z", + "lastUpdatedAt": "2026-07-21T15:25:21.499Z", + "liveVersion": "2" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/get.golden.json b/src/handlers/runtime/__fixtures__/get.golden.json new file mode 100644 index 000000000..e98511f8d --- /dev/null +++ b/src/handlers/runtime/__fixtures__/get.golden.json @@ -0,0 +1,29 @@ +{ + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "2", + "createdAt": "2026-07-21T15:24:52.318Z", + "lastUpdatedAt": "2026-07-21T15:25:21.499Z", + "roleArn": "arn:aws:iam::685197708687:role/tf_acc_test_1997929140646926281", + "networkConfiguration": { + "networkMode": "PUBLIC" + }, + "status": "READY", + "lifecycleConfiguration": { + "idleRuntimeSessionTimeout": 900, + "maxLifetime": 28800 + }, + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "workloadIdentityDetails": { + "workloadIdentityArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:workload-identity-directory/default/workload-identity/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx" + }, + "agentRuntimeArtifact": { + "containerConfiguration": { + "containerUri": "public.ecr.aws/y5s8y8h8/harness-us-west-2:latest" + } + }, + "metadataConfiguration": { + "requireMMDSV2": true + } +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/list-page-1.golden.json b/src/handlers/runtime/__fixtures__/list-page-1.golden.json new file mode 100644 index 000000000..6750263fb --- /dev/null +++ b/src/handlers/runtime/__fixtures__/list-page-1.golden.json @@ -0,0 +1,14 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/testdeploymentnow_MyAgent-NbnwifHv2x", + "agentRuntimeId": "testdeploymentnow_MyAgent-NbnwifHv2x", + "agentRuntimeVersion": "1", + "agentRuntimeName": "testdeploymentnow_MyAgent", + "description": "AgentCore Runtime: testdeploymentnow_MyAgent", + "lastUpdatedAt": "2026-02-10T21:07:43.525Z", + "status": "READY" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgG6cGcJPqi0LZHbjKr5ChQAAAABjjCCAYoGCSqGSIb3DQEHBqCCAXswggF3AgEAMIIBcAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzvpT6lITCSPK2ByJMCARCAggFB8UZbtS6rwjN4RLfbZ2CtSBZLpk6aGGY0Yq_ssMBfZkm9Z48YyBRdnJGu97eA7UcLpUY486A2fjR9OO7zlXqmXjHhQyHuWIMPFfzQklRG8aRwg36oSiwEKTqaviU1_fyI4SNlm-Jh1vobCDp8hZUOgM91j0FwpxtgkN3QP083tsRGXopXyk4L40VQL5w1x4SYOGozT1GcWgQJxXYnxV6756-Ph7kPoTQap-qISzcPugud5rXsXlleFa0YBt40tk39WZP6221FehU526dWU38q9g_-_AE2QpugnUQMRyJjAMtyEbo2wRLjiSLe_nyf8qgmZtygvl5Dgs-csa4dMek7mwQLwIzfoPhqIIMSyuQmn_o07XIygHneYtHzzAWKpXQ0RPiTy_pZiiNv0iZkWov8xKvoehHnWJJTDPRmsTiwJF4k" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/list-page-2.golden.json b/src/handlers/runtime/__fixtures__/list-page-2.golden.json new file mode 100644 index 000000000..4dbd30372 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/list-page-2.golden.json @@ -0,0 +1,13 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/harness_tf_acc_test_1997929140646926281-Z7D2FxDMk2", + "agentRuntimeId": "harness_tf_acc_test_1997929140646926281-Z7D2FxDMk2", + "agentRuntimeVersion": "1", + "agentRuntimeName": "harness_tf_acc_test_1997929140646926281", + "lastUpdatedAt": "2026-05-01T18:19:03.512Z", + "status": "READY" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgERE3Zyf3dYmd2LiyBNyCGEAAABnDCCAZgGCSqGSIb3DQEHBqCCAYkwggGFAgEAMIIBfgYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAyfUbmfL0KkkYuZZjACARCAggFPo8_Z_n6DRJs7flKkMS76z_JFSAm1blzGlN7POeFElkiXsL7aZjMsXg4ZA_23v5B-MkGPNDk-JX3nvwhPY-m4ykso-CkulJ6-Ek1jq2OqRTUw0B3c0LEGJKBGa38UzkKv1Vz2gEDELmDHJV8pMfa6oR4aUMi_ak20jSTTCvinG7vEuToL5raasFar5772NrT1Rs0h_VQ_P3EIiw-XWUONLv3pkVP7PAfGSB7wI3pWYHMXZGPzxlUrkpUMM_arxdNkweYTbuzjx2hZyws0W-eLlqhy-veF82FpJj4Yshb6TsIQnBlUCl-Sf9PDbBBbBrmg08-h6BumkebR1OIRVISn5FRodYKirS4UdZdCiAiRVT5jKy6EWdCVc2rUiD2R7CA_jR2U_nPVPuJU0YA4y2ZMeAg4l-q-2h001YWYfGtIN967xQbRCKc6nU95IhKLZSM=" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/version-get.golden.json b/src/handlers/runtime/__fixtures__/version-get.golden.json new file mode 100644 index 000000000..a3c34e7e8 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/version-get.golden.json @@ -0,0 +1,29 @@ +{ + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "1", + "createdAt": "2026-07-21T15:24:53.572Z", + "lastUpdatedAt": "2026-07-21T15:24:53.572Z", + "roleArn": "arn:aws:iam::685197708687:role/tf_acc_test_1997929140646926281", + "networkConfiguration": { + "networkMode": "PUBLIC" + }, + "status": "READY", + "lifecycleConfiguration": { + "idleRuntimeSessionTimeout": 900, + "maxLifetime": 28800 + }, + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "workloadIdentityDetails": { + "workloadIdentityArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:workload-identity-directory/default/workload-identity/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx" + }, + "agentRuntimeArtifact": { + "containerConfiguration": { + "containerUri": "public.ecr.aws/y5s8y8h8/harness-us-west-2:latest" + } + }, + "metadataConfiguration": { + "requireMMDSV2": true + } +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/version-list-id-over-48.golden.json b/src/handlers/runtime/__fixtures__/version-list-id-over-48.golden.json new file mode 100644 index 000000000..2d13dd8f7 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/version-list-id-over-48.golden.json @@ -0,0 +1,22 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "2", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": "2026-07-21T15:25:21.499Z", + "status": "READY" + }, + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "1", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": "2026-07-21T15:24:53.572Z", + "status": "READY" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/version-list-page-1.golden.json b/src/handlers/runtime/__fixtures__/version-list-page-1.golden.json new file mode 100644 index 000000000..69321a84e --- /dev/null +++ b/src/handlers/runtime/__fixtures__/version-list-page-1.golden.json @@ -0,0 +1,14 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "2", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": "2026-07-21T15:25:21.499Z", + "status": "READY" + } + ], + "nextToken": "AQICAHiNyEvxZzpFuVHtBl-B3jfZBBM36tDjm8_cCisOa4ihlgEwXMAtTGTZFyWB6KZJtPn-AAAB0jCCAc4GCSqGSIb3DQEHBqCCAb8wggG7AgEAMIIBtAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAylUsElcghzf4NUBekCARCAggGFF5whr4_8k1-yrxtlajLC17iTtz9pMjqudZrl7Y8ThJ9zRhnUFv8pbwu7RhGP7PaJKPIQD4StFOj3OSUXBL5dXN81JpbJSIrHm5Hxq0VS_q9hszeRO97gG6ltMo4Qmu17dFndYD0amjEpHDcp4b1d-bHrKu1exmbqwo0cak87FinliDqGAd7tClaOOry60psmqDxpxpgmSvPnw7LfT3t4R-pM4oo1gxGELSmXWV_7qaWRpSKSrLr7ZD67nssylo5F4hB9ut1KQMvLBYALvzHeI5Na873JU8oYtU1unOAoCrl1AqTCS3sS0RgqbYrOLmw0bKgxk4-OjbYyH2n72BiD1lcMdk95ZYG7ZXkhn6NZQsdVDVT1Ez-RKU6ry5CBMlQdo8GXQ1quzdGqnPwXAWKs80jGPf9C10vhVmL1fQ9DFlfZIo4b0h3ztZEon8IX84cXnEJX41up7qJWqefRHrirOjsvUwBpRK8brnreCQ1JeJeBY065x69iBAQWH3e9AI2lcPBvVR0=" +} \ No newline at end of file diff --git a/src/handlers/runtime/__fixtures__/version-list-page-2.golden.json b/src/handlers/runtime/__fixtures__/version-list-page-2.golden.json new file mode 100644 index 000000000..0e4e287c3 --- /dev/null +++ b/src/handlers/runtime/__fixtures__/version-list-page-2.golden.json @@ -0,0 +1,13 @@ +{ + "agentRuntimes": [ + { + "agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:runtime/agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeId": "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx", + "agentRuntimeVersion": "1", + "agentRuntimeName": "agentcore_cli_runtime_read_only_fixture", + "description": "Stable shared resource for AgentCore CLI Runtime read-only fixture recording", + "lastUpdatedAt": "2026-07-21T15:24:53.572Z", + "status": "READY" + } + ] +} \ No newline at end of file diff --git a/src/handlers/runtime/endpoint/get/index.tsx b/src/handlers/runtime/endpoint/get/index.tsx new file mode 100644 index 000000000..f4b342920 --- /dev/null +++ b/src/handlers/runtime/endpoint/get/index.tsx @@ -0,0 +1,29 @@ +import z from "zod"; +import { createHandler, flag } from "../../../../router"; +import { JsonRendererKey } from "../../../../tui"; +import type { Core } from "../../../types"; +import { coreOptsFromCtx } from "../../../utils"; + +export const createGetRuntimeEndpointHandler = (core: Core) => + createHandler({ + name: "get", + description: "get a Runtime endpoint", + flags: [ + flag("id", "the ID of the Runtime", z.string().optional()), + flag("qualifier", "the endpoint name (qualifier)", z.string().optional()), + ], + handle: async (ctx, flags) => { + if (!flags.id) { + throw new TypeError("required option '--id ' not specified"); + } + if (!flags.qualifier) { + throw new TypeError("required option '--qualifier ' not specified"); + } + + ctx + .require(JsonRendererKey) + .renderJson( + await core.runtime.getRuntimeEndpoint(flags.id, flags.qualifier, coreOptsFromCtx(ctx)), + ); + }, + }); diff --git a/src/handlers/runtime/endpoint/index.tsx b/src/handlers/runtime/endpoint/index.tsx new file mode 100644 index 000000000..23254220d --- /dev/null +++ b/src/handlers/runtime/endpoint/index.tsx @@ -0,0 +1,12 @@ +import { Router } from "../../../router"; +import type { AppIO, Core } from "../../types"; +import { createHelpDefault } from "../help"; +import { createGetRuntimeEndpointHandler } from "./get"; +import { createListRuntimeEndpointsHandler } from "./list"; + +export function createRuntimeEndpointHandler(core: Core, io: AppIO): Router { + return new Router("endpoint", "inspect AgentCore Runtime endpoints") + .default(createHelpDefault(io)) + .handler(createGetRuntimeEndpointHandler(core)) + .handler(createListRuntimeEndpointsHandler(core)); +} diff --git a/src/handlers/runtime/endpoint/list/index.tsx b/src/handlers/runtime/endpoint/list/index.tsx new file mode 100644 index 000000000..b6f492dc6 --- /dev/null +++ b/src/handlers/runtime/endpoint/list/index.tsx @@ -0,0 +1,32 @@ +import z from "zod"; +import { createHandler, flag } from "../../../../router"; +import { JsonRendererKey } from "../../../../tui"; +import type { Core } from "../../../types"; +import { coreOptsFromCtx } from "../../../utils"; + +export const createListRuntimeEndpointsHandler = (core: Core) => + createHandler({ + name: "list", + description: "list a Runtime's endpoints", + flags: [ + flag("id", "the ID of the Runtime", z.string().optional()), + flag("next-token", "pagination token returned by a previous request", z.string().optional()), + flag("max-results", "maximum number of items to return", z.number().optional()), + ], + handle: async (ctx, flags) => { + if (!flags.id) { + throw new TypeError("required option '--id ' not specified"); + } + + ctx + .require(JsonRendererKey) + .renderJson( + await core.runtime.listRuntimeEndpoints( + flags.id, + flags["next-token"], + flags["max-results"], + coreOptsFromCtx(ctx), + ), + ); + }, + }); diff --git a/src/handlers/runtime/get/index.tsx b/src/handlers/runtime/get/index.tsx new file mode 100644 index 000000000..b62f3e88d --- /dev/null +++ b/src/handlers/runtime/get/index.tsx @@ -0,0 +1,21 @@ +import z from "zod"; +import { createHandler, flag } from "../../../router"; +import { JsonRendererKey } from "../../../tui"; +import type { Core } from "../../types"; +import { coreOptsFromCtx } from "../../utils"; + +export const createGetRuntimeHandler = (core: Core) => + createHandler({ + name: "get", + description: "get an AgentCore Runtime", + flags: [flag("id", "the ID of the Runtime", z.string().optional())], + handle: async (ctx, flags) => { + if (!flags.id) { + throw new TypeError("required option '--id ' not specified"); + } + + ctx + .require(JsonRendererKey) + .renderJson(await core.runtime.getRuntime(flags.id, coreOptsFromCtx(ctx))); + }, + }); diff --git a/src/handlers/runtime/help.tsx b/src/handlers/runtime/help.tsx new file mode 100644 index 000000000..6a9755abc --- /dev/null +++ b/src/handlers/runtime/help.tsx @@ -0,0 +1,9 @@ +import { CommandKey, type DefaultHandle } from "../../router"; +import type { AppIO } from "../types"; + +export function createHelpDefault(io: AppIO): DefaultHandle { + return async (ctx) => { + const help = ctx.require(CommandKey).helpInformation(); + io.stdout.write(help.endsWith("\n") ? help : `${help}\n`); + }; +} diff --git a/src/handlers/runtime/index.tsx b/src/handlers/runtime/index.tsx new file mode 100644 index 000000000..a33bb00cd --- /dev/null +++ b/src/handlers/runtime/index.tsx @@ -0,0 +1,16 @@ +import { Router } from "../../router"; +import type { AppIO, Core } from "../types"; +import { createRuntimeEndpointHandler } from "./endpoint"; +import { createGetRuntimeHandler } from "./get"; +import { createHelpDefault } from "./help"; +import { createListRuntimesHandler } from "./list"; +import { createRuntimeVersionHandler } from "./version"; + +export function createRuntimeHandler(core: Core, io: AppIO): Router { + return new Router("runtime", "inspect AgentCore Runtimes") + .default(createHelpDefault(io)) + .handler(createGetRuntimeHandler(core)) + .handler(createListRuntimesHandler(core)) + .handler(createRuntimeVersionHandler(core, io)) + .handler(createRuntimeEndpointHandler(core, io)); +} diff --git a/src/handlers/runtime/list/index.tsx b/src/handlers/runtime/list/index.tsx new file mode 100644 index 000000000..08728b2e3 --- /dev/null +++ b/src/handlers/runtime/list/index.tsx @@ -0,0 +1,26 @@ +import z from "zod"; +import { createHandler, flag } from "../../../router"; +import { JsonRendererKey } from "../../../tui"; +import type { Core } from "../../types"; +import { coreOptsFromCtx } from "../../utils"; + +export const createListRuntimesHandler = (core: Core) => + createHandler({ + name: "list", + description: "list AgentCore Runtimes", + flags: [ + flag("next-token", "pagination token returned by a previous request", z.string().optional()), + flag("max-results", "maximum number of items to return", z.number().optional()), + ], + handle: async (ctx, flags) => { + ctx + .require(JsonRendererKey) + .renderJson( + await core.runtime.listRuntimes( + flags["next-token"], + flags["max-results"], + coreOptsFromCtx(ctx), + ), + ); + }, + }); diff --git a/src/handlers/runtime/runtime.test.tsx b/src/handlers/runtime/runtime.test.tsx new file mode 100644 index 000000000..5685d8619 --- /dev/null +++ b/src/handlers/runtime/runtime.test.tsx @@ -0,0 +1,248 @@ +import { describe, expect, test } from "bun:test"; +import { join } from "node:path"; +import { CoreClient } from "../../core"; +import { createSilentLogger, fixtureFactories, matchGolden, testIO } from "../../testing"; +import { createRootHandler } from "../index"; + +const REGION = "us-west-2"; +const FIXTURES = join(import.meta.dir, "__fixtures__"); + +// The shared E2E fixture Runtime has versions 1 and 2 plus DEFAULT and +// runtimeReadOnlyFixture endpoints. The account has multiple Runtimes for +// Runtime pagination. Page-two requests use the token returned by page one. +// Record with AWS_PROFILE=e2e-test RECORD=1 bun test src/handlers/runtime/runtime.test.tsx. +const FIXTURE_RUNTIME_ID = "agentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhx"; +const MISSING_RUNTIME_ID = "missing_runtime-0000000000"; + +function createFixtureCore(): CoreClient { + const { createControlClient, createDataClient, createIamClient } = fixtureFactories(FIXTURES); + return new CoreClient(createControlClient, createDataClient, createIamClient); +} + +async function run(args: string[]): Promise { + const io = testIO(); + const root = createRootHandler(createFixtureCore(), { + io: io.io, + logger: createSilentLogger(), + }); + + await root.route(["node", "agentcore", ...args, "--region", REGION]); + return io.stdout(); +} + +describe("runtime command hierarchy", () => { + test("registers the Runtime read-only command hierarchy", () => { + const root = createRootHandler(createFixtureCore(), { + io: testIO().io, + logger: createSilentLogger(), + }); + const runtime = root.children().find((child) => child.name() === "runtime"); + + expect(runtime?.children().map((child) => child.name())).toEqual([ + "get", + "list", + "version", + "endpoint", + ]); + expect( + runtime + ?.children() + .find((child) => child.name() === "version") + ?.children() + .map((child) => child.name()), + ).toEqual(["get", "list"]); + expect( + runtime + ?.children() + .find((child) => child.name() === "endpoint") + ?.children() + .map((child) => child.name()), + ).toEqual(["get", "list"]); + }); + + test.each(["runtime", "runtime version", "runtime endpoint"])( + "prints help for bare `%s` without an SDK call", + async (command) => { + const stdout = await run(command.split(" ")); + + expect(stdout).toContain(`Usage: agentcore ${command}`); + expect(stdout).toContain("Commands:"); + }, + ); +}); + +describe("runtime read-only commands", () => { + test("gets a Runtime whose ID exceeds the 48-character Runtime name limit", async () => { + expect(FIXTURE_RUNTIME_ID.length).toBeGreaterThan(48); + + const stdout = await run(["runtime", "get", "--id", FIXTURE_RUNTIME_ID]); + + matchGolden(FIXTURES, "get.golden.json", stdout); + expect(JSON.parse(stdout).agentRuntimeId).toBe(FIXTURE_RUNTIME_ID); + }); + + test("paginates Runtime list with --max-results and --next-token", async () => { + const firstPage = await run(["runtime", "list", "--max-results", "1"]); + matchGolden(FIXTURES, "list-page-1.golden.json", firstPage); + + const first = JSON.parse(firstPage); + expect(first.agentRuntimes).toHaveLength(1); + expect(first.nextToken).toBeString(); + + const secondPage = await run([ + "runtime", + "list", + "--max-results", + "1", + "--next-token", + first.nextToken, + ]); + matchGolden(FIXTURES, "list-page-2.golden.json", secondPage); + expect(JSON.parse(secondPage).agentRuntimes).toHaveLength(1); + }); + + test("gets a Runtime version using an ID exceeding the 48-character Runtime name limit", async () => { + const stdout = await run([ + "runtime", + "version", + "get", + "--id", + FIXTURE_RUNTIME_ID, + "--version", + "1", + ]); + + matchGolden(FIXTURES, "version-get.golden.json", stdout); + const parsed = JSON.parse(stdout); + expect(parsed.agentRuntimeId).toBe(FIXTURE_RUNTIME_ID); + expect(parsed.agentRuntimeVersion).toBe("1"); + }); + + test("paginates Runtime version list with --max-results and --next-token", async () => { + const firstPage = await run([ + "runtime", + "version", + "list", + "--id", + FIXTURE_RUNTIME_ID, + "--max-results", + "1", + ]); + matchGolden(FIXTURES, "version-list-page-1.golden.json", firstPage); + + const first = JSON.parse(firstPage); + expect(first.agentRuntimes).toHaveLength(1); + expect(first.nextToken).toBeString(); + + const secondPage = await run([ + "runtime", + "version", + "list", + "--id", + FIXTURE_RUNTIME_ID, + "--max-results", + "1", + "--next-token", + first.nextToken, + ]); + matchGolden(FIXTURES, "version-list-page-2.golden.json", secondPage); + expect(JSON.parse(secondPage).agentRuntimes).toHaveLength(1); + }); + + test("maps the endpoint qualifier using an ID exceeding the 48-character Runtime name limit", async () => { + const stdout = await run([ + "runtime", + "endpoint", + "get", + "--id", + FIXTURE_RUNTIME_ID, + "--qualifier", + "DEFAULT", + ]); + + matchGolden(FIXTURES, "endpoint-get.golden.json", stdout); + const parsed = JSON.parse(stdout); + expect(parsed.agentRuntimeArn).toContain(FIXTURE_RUNTIME_ID); + expect(parsed.name).toBe("DEFAULT"); + }); + + test("paginates Runtime endpoint list with --max-results and --next-token", async () => { + const firstPage = await run([ + "runtime", + "endpoint", + "list", + "--id", + FIXTURE_RUNTIME_ID, + "--max-results", + "1", + ]); + matchGolden(FIXTURES, "endpoint-list-page-1.golden.json", firstPage); + + const first = JSON.parse(firstPage); + expect(first.runtimeEndpoints).toHaveLength(1); + expect(first.nextToken).toBeString(); + + const secondPage = await run([ + "runtime", + "endpoint", + "list", + "--id", + FIXTURE_RUNTIME_ID, + "--max-results", + "1", + "--next-token", + first.nextToken, + ]); + matchGolden(FIXTURES, "endpoint-list-page-2.golden.json", secondPage); + expect(JSON.parse(secondPage).runtimeEndpoints).toHaveLength(1); + }); + + test.each([ + ["runtime get", ["runtime", "get"], /--id/], + ["runtime version get", ["runtime", "version", "get"], /--id/], + [ + "runtime version get --id ", + ["runtime", "version", "get", "--id", FIXTURE_RUNTIME_ID], + /--version/, + ], + ["runtime version list", ["runtime", "version", "list"], /--id/], + ["runtime endpoint get", ["runtime", "endpoint", "get"], /--id/], + [ + "runtime endpoint get --id ", + ["runtime", "endpoint", "get", "--id", FIXTURE_RUNTIME_ID], + /--qualifier/, + ], + ["runtime endpoint list", ["runtime", "endpoint", "list"], /--id/], + ] as const)("rejects a missing required selector for `%s`", async (_label, args, message) => { + expect(run([...args])).rejects.toThrow(message); + }); + + test.each([ + [ + "runtime version list", + ["runtime", "version", "list", "--id", FIXTURE_RUNTIME_ID], + "version-list-id-over-48.golden.json", + "agentRuntimes", + ], + [ + "runtime endpoint list", + ["runtime", "endpoint", "list", "--id", FIXTURE_RUNTIME_ID], + "endpoint-list-id-over-48.golden.json", + "runtimeEndpoints", + ], + ] as const)( + "accepts a Runtime ID exceeding the 48-character Runtime name limit for `%s`", + async (_label, args, golden, collection) => { + const stdout = await run([...args]); + + matchGolden(FIXTURES, golden, stdout); + expect(JSON.parse(stdout)[collection].length).toBeGreaterThan(0); + }, + ); + + test("propagates ResourceNotFoundException from Runtime get", async () => { + await expect(run(["runtime", "get", "--id", MISSING_RUNTIME_ID])).rejects.toMatchObject({ + name: "ResourceNotFoundException", + }); + }); +}); diff --git a/src/handlers/runtime/types.tsx b/src/handlers/runtime/types.tsx new file mode 100644 index 000000000..e2f219f1b --- /dev/null +++ b/src/handlers/runtime/types.tsx @@ -0,0 +1,39 @@ +import type { + GetAgentRuntimeEndpointResponse, + GetAgentRuntimeResponse, + ListAgentRuntimeEndpointsResponse, + ListAgentRuntimesResponse, + ListAgentRuntimeVersionsResponse, +} from "@aws-sdk/client-bedrock-agentcore-control"; +import type { CoreOptions } from "../../core/types"; + +export interface CoreRuntimeClient { + getRuntime(id: string, options: CoreOptions): Promise; + getRuntimeVersion( + id: string, + version: string, + options: CoreOptions, + ): Promise; + getRuntimeEndpoint( + id: string, + qualifier: string, + options: CoreOptions, + ): Promise; + listRuntimes( + nextToken: string | undefined, + maxResults: number | undefined, + options: CoreOptions, + ): Promise; + listRuntimeVersions( + id: string, + nextToken: string | undefined, + maxResults: number | undefined, + options: CoreOptions, + ): Promise; + listRuntimeEndpoints( + id: string, + nextToken: string | undefined, + maxResults: number | undefined, + options: CoreOptions, + ): Promise; +} diff --git a/src/handlers/runtime/version/get/index.tsx b/src/handlers/runtime/version/get/index.tsx new file mode 100644 index 000000000..3d82c53b3 --- /dev/null +++ b/src/handlers/runtime/version/get/index.tsx @@ -0,0 +1,29 @@ +import z from "zod"; +import { createHandler, flag } from "../../../../router"; +import { JsonRendererKey } from "../../../../tui"; +import type { Core } from "../../../types"; +import { coreOptsFromCtx } from "../../../utils"; + +export const createGetRuntimeVersionHandler = (core: Core) => + createHandler({ + name: "get", + description: "get a specific Runtime version", + flags: [ + flag("id", "the ID of the Runtime", z.string().optional()), + flag("version", "the Runtime version to get", z.string().optional()), + ], + handle: async (ctx, flags) => { + if (!flags.id) { + throw new TypeError("required option '--id ' not specified"); + } + if (!flags.version) { + throw new TypeError("required option '--version ' not specified"); + } + + ctx + .require(JsonRendererKey) + .renderJson( + await core.runtime.getRuntimeVersion(flags.id, flags.version, coreOptsFromCtx(ctx)), + ); + }, + }); diff --git a/src/handlers/runtime/version/index.tsx b/src/handlers/runtime/version/index.tsx new file mode 100644 index 000000000..57e40d439 --- /dev/null +++ b/src/handlers/runtime/version/index.tsx @@ -0,0 +1,12 @@ +import { Router } from "../../../router"; +import type { AppIO, Core } from "../../types"; +import { createHelpDefault } from "../help"; +import { createGetRuntimeVersionHandler } from "./get"; +import { createListRuntimeVersionsHandler } from "./list"; + +export function createRuntimeVersionHandler(core: Core, io: AppIO): Router { + return new Router("version", "inspect AgentCore Runtime versions") + .default(createHelpDefault(io)) + .handler(createGetRuntimeVersionHandler(core)) + .handler(createListRuntimeVersionsHandler(core)); +} diff --git a/src/handlers/runtime/version/list/index.tsx b/src/handlers/runtime/version/list/index.tsx new file mode 100644 index 000000000..b2c20b599 --- /dev/null +++ b/src/handlers/runtime/version/list/index.tsx @@ -0,0 +1,32 @@ +import z from "zod"; +import { createHandler, flag } from "../../../../router"; +import { JsonRendererKey } from "../../../../tui"; +import type { Core } from "../../../types"; +import { coreOptsFromCtx } from "../../../utils"; + +export const createListRuntimeVersionsHandler = (core: Core) => + createHandler({ + name: "list", + description: "list a Runtime's versions", + flags: [ + flag("id", "the ID of the Runtime", z.string().optional()), + flag("next-token", "pagination token returned by a previous request", z.string().optional()), + flag("max-results", "maximum number of items to return", z.number().optional()), + ], + handle: async (ctx, flags) => { + if (!flags.id) { + throw new TypeError("required option '--id ' not specified"); + } + + ctx + .require(JsonRendererKey) + .renderJson( + await core.runtime.listRuntimeVersions( + flags.id, + flags["next-token"], + flags["max-results"], + coreOptsFromCtx(ctx), + ), + ); + }, + }); diff --git a/src/handlers/types.tsx b/src/handlers/types.tsx index 00aab42a2..3e95a2b14 100644 --- a/src/handlers/types.tsx +++ b/src/handlers/types.tsx @@ -1,8 +1,10 @@ import type { CoreHarnessClient } from "./harness/types.tsx"; +import type { CoreRuntimeClient } from "./runtime/types.tsx"; import type { Context } from "../router"; export interface Core { harness: CoreHarnessClient; + runtime: CoreRuntimeClient; } // AppIO is the set of standard streams the app reads from and writes to. It is diff --git a/src/testing/TestCoreClient.tsx b/src/testing/TestCoreClient.tsx index 2bc9b000c..c12f17aad 100644 --- a/src/testing/TestCoreClient.tsx +++ b/src/testing/TestCoreClient.tsx @@ -8,6 +8,11 @@ import type { DeleteHarnessResponse, GetHarnessResponse, GetHarnessEndpointResponse, + GetAgentRuntimeEndpointResponse, + GetAgentRuntimeResponse, + ListAgentRuntimeEndpointsResponse, + ListAgentRuntimesResponse, + ListAgentRuntimeVersionsResponse, ListHarnessesResponse, ListHarnessEndpointsResponse, ListHarnessVersionsResponse, @@ -26,6 +31,7 @@ import type { } from "@aws-sdk/client-bedrock-agentcore"; import type { Core } from "../handlers/types"; import type { CoreHarnessClient, CreateHarnessInput } from "../handlers/harness/types"; +import type { CoreRuntimeClient } from "../handlers/runtime/types"; import type { CoreOptions } from "../core/types"; // TestCoreClient is a hand-controllable `Core` for tests. It implements the same @@ -64,6 +70,15 @@ const DEFAULT_UPDATE_ENDPOINT_RESPONSE: UpdateHarnessEndpointResponse = {} as UpdateHarnessEndpointResponse; const DEFAULT_DELETE_ENDPOINT_RESPONSE: DeleteHarnessEndpointResponse = {} as DeleteHarnessEndpointResponse; +const DEFAULT_GET_RUNTIME_RESPONSE = {} as GetAgentRuntimeResponse; +const DEFAULT_GET_RUNTIME_ENDPOINT_RESPONSE = {} as GetAgentRuntimeEndpointResponse; +const DEFAULT_LIST_RUNTIMES_RESPONSE: ListAgentRuntimesResponse = { agentRuntimes: [] }; +const DEFAULT_LIST_RUNTIME_VERSIONS_RESPONSE: ListAgentRuntimeVersionsResponse = { + agentRuntimes: [], +}; +const DEFAULT_LIST_RUNTIME_ENDPOINTS_RESPONSE: ListAgentRuntimeEndpointsResponse = { + runtimeEndpoints: [], +}; // abortError mirrors the error the SDK's abort handling rejects with. function abortError(): Error { @@ -404,7 +419,56 @@ export class TestHarnessClient implements CoreHarnessClient { } } +class TestRuntimeClient implements CoreRuntimeClient { + async getRuntime(_id: string, _options: CoreOptions): Promise { + return DEFAULT_GET_RUNTIME_RESPONSE; + } + + async getRuntimeVersion( + _id: string, + _version: string, + _options: CoreOptions, + ): Promise { + return DEFAULT_GET_RUNTIME_RESPONSE; + } + + async getRuntimeEndpoint( + _id: string, + _qualifier: string, + _options: CoreOptions, + ): Promise { + return DEFAULT_GET_RUNTIME_ENDPOINT_RESPONSE; + } + + async listRuntimes( + _nextToken: string | undefined, + _maxResults: number | undefined, + _options: CoreOptions, + ): Promise { + return DEFAULT_LIST_RUNTIMES_RESPONSE; + } + + async listRuntimeVersions( + _id: string, + _nextToken: string | undefined, + _maxResults: number | undefined, + _options: CoreOptions, + ): Promise { + return DEFAULT_LIST_RUNTIME_VERSIONS_RESPONSE; + } + + async listRuntimeEndpoints( + _id: string, + _nextToken: string | undefined, + _maxResults: number | undefined, + _options: CoreOptions, + ): Promise { + return DEFAULT_LIST_RUNTIME_ENDPOINTS_RESPONSE; + } +} + // TestCoreClient implements the Core contract with fully controllable sub-clients. export class TestCoreClient implements Core { readonly harness = new TestHarnessClient(); + readonly runtime = new TestRuntimeClient(); }