diff --git a/README.md b/README.md index b2a3be481..7e3e40cce 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ agentcore # interactive TUI ├── runtime # inspect deployed AgentCore Runtimes │ ├── get # fetch a Runtime by id │ ├── list # list Runtimes (server-side paginated) +│ ├── invoke # invoke a Runtime headlessly or in a persistent console │ ├── version │ │ ├── get # get a specific Runtime version │ │ └── list # list a Runtime's versions @@ -116,6 +117,91 @@ agentcore identity api-key-credential-provider update --name my-provider --api-k agentcore identity api-key-credential-provider delete --name my-provider ``` +### Invoke a Runtime + +Headless invocation accepts inline, file, or stdin payload bytes: + +```bash +# Inline +agentcore runtime invoke \ + --id \ + --payload '{"action":"status"}' \ + --content-type application/json \ + --accept text/event-stream + +# File +agentcore runtime invoke --id --payload file://request.json + +# stdin +cat request.json | agentcore runtime invoke --id --payload - +``` + +CUSTOM_JWT Runtimes require `--bearer-token`. The token accepts the same inline, +`file://`, or stdin sources as the payload; payload and token cannot both read +stdin. + +```bash +agentcore runtime invoke \ + --id \ + --payload file://request.json \ + --bearer-token file://$HOME/.config/agentcore/runtime-token +``` + +For MCP Runtimes, initialize first, then pass the returned Runtime and MCP +session IDs to later methods. MCP requests accept both JSON and SSE responses. + +```bash +agentcore runtime invoke \ + --id \ + --payload '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"agentcore-cli","version":"1"}}}' \ + --accept 'application/json, text/event-stream' \ + --mcp-protocol-version 2025-03-26 \ + --mcp-method initialize + +agentcore runtime invoke \ + --id \ + --payload '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \ + --accept 'application/json, text/event-stream' \ + --session-id \ + --mcp-session-id \ + --mcp-protocol-version 2025-03-26 \ + --mcp-method tools/list +``` + +Raw mode streams exact response bytes to stdout and writes response metadata to +stderr. Use `--output-file` for binary responses. `--json` instead buffers one +response and emits a metadata envelope without interpreting the customer body. + +```bash +agentcore runtime invoke \ + --id \ + --payload file://request.bin \ + --content-type application/octet-stream \ + --accept application/octet-stream \ + --output-file response.bin + +agentcore runtime invoke --id --payload '{"action":"status"}' --json +# {"statusCode":200,"contentType":"application/json","bodyEncoding":"utf8","body":"{\"ok\":true}","complete":true} +``` + +Without `--payload`, Runtime Invoke opens a persistent console for repeated +requests. Bare invoke opens the Runtime and endpoint pickers; `--id` skips the +Runtime picker, and `--id` plus `--qualifier` opens the console directly. + +| Shortcut | Action | +| -------- | -------------------------------------------- | +| `Ctrl+D` | Send the request | +| `Ctrl+O` | Open Request Options | +| `Ctrl+T` | Change Runtime or endpoint | +| `Ctrl+V` | Toggle raw and pretty completed JSON | +| `Esc` | Interrupt an active request or navigate back | +| `↑`/`↓` | Scroll response history | + +Runtime Invoke accepts Runtime IDs from the current account only. It does not +accept ARNs, `--version`, `--interactive`, cross-account targets, or custom +request paths. All requests use the Runtime `/invocations` route, including MCP +Runtimes. + Bare Runtime branches and leaves require a TTY on stdin and stdout. Supplying operation flags runs the command headlessly, and `--json` always suppresses TUI rendering. diff --git a/bun.lock b/bun.lock index f001ff39c..840f1e68e 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "": { "name": "agentcore", "dependencies": { - "@aws-sdk/client-bedrock-agentcore": "^3.1079.0", + "@aws-sdk/client-bedrock-agentcore": "^3.1092.0", "@aws-sdk/client-bedrock-agentcore-control": "^3.1079.0", "@aws-sdk/client-iam": "^3.1080.0", "@inkui-cli/data-table": "^0.2.0", @@ -38,39 +38,39 @@ "packages": { "@alcalzone/ansi-tokenize": ["@alcalzone/ansi-tokenize@0.3.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA=="], - "@aws-sdk/client-bedrock-agentcore": ["@aws-sdk/client-bedrock-agentcore@3.1087.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/credential-provider-node": "^3.972.68", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-qv1e7yjIxu4KCRNGkG+Ar/MLYGhyUWkGfjKoAm1H4/jD0viEC1PBklbHJm27HLxYtOcKWYA67k8S0kGb0iJxDA=="], + "@aws-sdk/client-bedrock-agentcore": ["@aws-sdk/client-bedrock-agentcore@3.1094.0", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/credential-provider-node": "^3.972.71", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/fetch-http-handler": "^5.6.6", "@smithy/node-http-handler": "^4.9.6", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-K8+YaYFyaVJvidwVSnmXlHjpOel/qz4ii2TZY2shXbkMoQxftjHuiXlplKeb5pWhzdS092q6YqPR5CZrMH90Ug=="], "@aws-sdk/client-bedrock-agentcore-control": ["@aws-sdk/client-bedrock-agentcore-control@3.1087.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/credential-provider-node": "^3.972.68", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-ZCWITtXgDZG1g8NfTZVMTIwH/NR9eifXRW1g5+d4Jb93MmwbJWLWRSd0xqxgywMay0sqhNOKXHE4nQRIf9glag=="], "@aws-sdk/client-iam": ["@aws-sdk/client-iam@3.1087.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/credential-provider-node": "^3.972.68", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-S2UBBQnPMTREF52WPz7yabvags3rPYLOPwq8LOPNJIekyAIqUwtGN46z2tqGNr+NyGz9cpEI+3brJgkWKQGNIQ=="], - "@aws-sdk/core": ["@aws-sdk/core@3.975.2", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@aws-sdk/xml-builder": "^3.972.35", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.29.3", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-iyeXwziyjJpixq5OmhsIyrSWx8vwcI7gDo4yRUC3EP7NQtOo9iAJiIEc3G+/HkhtNXqOhofiCK7Lc34Sq+fJWg=="], + "@aws-sdk/core": ["@aws-sdk/core@3.976.0", "", { "dependencies": { "@aws-sdk/types": "^3.974.2", "@aws-sdk/xml-builder": "^3.972.36", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.29.4", "@smithy/signature-v4": "^5.6.5", "@smithy/types": "^4.16.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-0cjRaEdlVoOrsNb9pP5q1Syyc8pXw5xSj2Np2ryReRTr9FppIIRVSdZK4lbnfmc2Hvgux/xBOUU6baB7z8//uA=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.58", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-vyGtvK1rY940eq7JT0yIGKuZ+2kpPSJcHibSvGlit5oiMFDamzC7cxBGLl4FLnd6suihMXDI2FSF2dL6TmBqPA=="], + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.60", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-BAkxdoe7tpDDqCghGpuOeHQRbm/2znVvOQm0AvpQbA2tbfMN46doN4zx65fv85ImP3KADwc2zQPmbrlI9MPfMg=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.60", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-g9b9YzDrD5pcKiPBJfCSXRfFMrA39eR0guUhZ5SRm+7vMAVc43+effxbcamxBjSd5bUhrdKo5te/yQuWurLXLA=="], + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.62", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/fetch-http-handler": "^5.6.6", "@smithy/node-http-handler": "^4.9.6", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-g/0fGqKTb9xpKdd9AtpmV5Eo3DFKbnkpA2+w0peISSlu7NfAoWOuYBFxsu+yWBtxU89ka55ezoZBCbFaS8pjYQ=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.2", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/credential-provider-env": "^3.972.58", "@aws-sdk/credential-provider-http": "^3.972.60", "@aws-sdk/credential-provider-login": "^3.972.64", "@aws-sdk/credential-provider-process": "^3.972.58", "@aws-sdk/credential-provider-sso": "^3.973.2", "@aws-sdk/credential-provider-web-identity": "^3.972.64", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Yr7yxNyQ8aHt9Ww0RPFUZx+xiem+vl7vuwhP0tniTijoesJNV5jou9HCgVpI0GEPAF+89TkOvilE5uRrZJnjaw=="], + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.5", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/credential-provider-env": "^3.972.60", "@aws-sdk/credential-provider-http": "^3.972.62", "@aws-sdk/credential-provider-login": "^3.972.67", "@aws-sdk/credential-provider-process": "^3.972.60", "@aws-sdk/credential-provider-sso": "^3.973.4", "@aws-sdk/credential-provider-web-identity": "^3.972.66", "@aws-sdk/nested-clients": "^3.997.34", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/credential-provider-imds": "^4.4.9", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-ylubazcRfq2TVus/qXucSXeC42Qdjp5HQxTu68K/BsdMiZlcSLD1zkpoCgApXZX1Y6YJhtGGs7ZHhO/GuIgBlw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.64", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-YQoSI4d6kXvoenoG/0Jv/PqaAuukHzGmGXGyHBQYeEUNsYovlNAn/Sw1wp/WQbhcQ3HsEMGgjEahvD3igz6ecQ=="], + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.67", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/nested-clients": "^3.997.34", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-CCygIKJ9YbI3n84OClSaSppkgKKHVj2TGT33c6FRORZrYNZQ1POmD+ip0FLYokiJAK7sSdc3YVkOsBm90oxWMQ=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.68", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.58", "@aws-sdk/credential-provider-http": "^3.972.60", "@aws-sdk/credential-provider-ini": "^3.973.2", "@aws-sdk/credential-provider-process": "^3.972.58", "@aws-sdk/credential-provider-sso": "^3.973.2", "@aws-sdk/credential-provider-web-identity": "^3.972.64", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-4akjzW9CjorByYfqXBXmYUh/h7Io3U4DtVgGGh9TQraZ7ZlyJqNyHwDRGiUFnHD+BTOeTbCesCa4sJaK7BGZ7A=="], + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.71", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.60", "@aws-sdk/credential-provider-http": "^3.972.62", "@aws-sdk/credential-provider-ini": "^3.973.5", "@aws-sdk/credential-provider-process": "^3.972.60", "@aws-sdk/credential-provider-sso": "^3.973.4", "@aws-sdk/credential-provider-web-identity": "^3.972.66", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/credential-provider-imds": "^4.4.9", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-HIg7Q2osBzajQwL+1Vkyh2E7Gim3eTNb9RHIsOxDGjW0eZg4oEKtRs5sioCnc73ilhaOm4gX2lHVF8J7+nt2rg=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.58", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-1nYitRCaDmXWUrpBJt6WlcGjLx1JVsMY8rlYuHHsTYTSaYikbixYdQSyINN2VYq1F798uTO9qHAzytL25M8g3A=="], + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.60", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-YIo3f99hM43QdYG8hDzwGemnR/pU95b0kramqSJUTleCqaB7+HwKf7YZFHqvOgTqZTPx/mRmNIqoDRr3U0Z3Tw=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.2", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/token-providers": "3.1087.0", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pjMLaLU/JZi5lVfmR14V1OZqRBTuMHf6AwGNZA0K9hK+JKtO3jcLBarfD8iq5oc8cSowvc/9R32sqMVXZPo6xQ=="], + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.4", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/nested-clients": "^3.997.34", "@aws-sdk/token-providers": "3.1092.0", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-BPdmL8sSBOCv4ngZ+3LHxyc3CNqDCEK37CHioCk7zGrTMY5sUtkH8q+o6qA80nn6w3/fyBPGNE7OIRlmoOxRQA=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.64", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-7Buc7p0OvDHW7iBsu4b+YdS0WnaFBDGKDfbVQqaac9dkWiSiUtIoarBDsA1RmOVXZijaZJDoHJFIQiicQvWRlQ=="], + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.66", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/nested-clients": "^3.997.34", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-kSAziJboOmZmsR9/MTbiNjowl2BPes1bQuJpne4qAZ62ubi8fjfr/aupJSQje6udBoYxXTQbsL0e0kby2la3ng=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.34", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/signature-v4-multi-region": "^3.996.41", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/fetch-http-handler": "^5.6.6", "@smithy/node-http-handler": "^4.9.6", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Y9REVrSwmLM+Qy6sZJ7ofMC2S3Hr3tPP/4CzL5U1olPP7OGoF+6+Px0E49cVQBtSxJtyeLJMf0UaBErfeSahAA=="], - "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.41", "", { "dependencies": { "@aws-sdk/types": "^3.974.2", "@smithy/signature-v4": "^5.6.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-QMUytg+FQMGouc8gHS00KoYih3+N6cqmVI/pQGOIo7Nr7OpQaiXjSYOuL+vsPZ1tymY4LAQ8MYcHJmws5LRxng=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1087.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-umM+qNq16f2fH+VLM5MqXW4ORNQAjk+TOSto73xbUHcKaU41L48j786r3UWQYlejeJk37NlvRYgxBT+MBkfaYQ=="], + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1092.0", "", { "dependencies": { "@aws-sdk/core": "^3.976.0", "@aws-sdk/nested-clients": "^3.997.34", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.29.4", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-hBYUAr6iBLNFcsiWTgtBb0stdSw39VOUq4Sp4A5caCNf66BAZplWN4FleKrVpJx5li2YgdnK2DqoFSMWC642FQ=="], - "@aws-sdk/types": ["@aws-sdk/types@3.974.1", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-W0IQZR0eaBqlBFIIofMapaWkw1W0U+Xi4dvW+BqwmCEMd8Ng2U6IhkxuPSjMVnR8klLjfuS9PeZWUl1N6UaZdg=="], + "@aws-sdk/types": ["@aws-sdk/types@3.974.2", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.35", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pXzaWe3evZhjxDXAlMnqISe/XefTCGwBJG4nFTXaWSgAnMkqPEhxEPqJNhhpGesEvKFhvNpnozJJ4GTL11bRYw=="], + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.36", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-RdGmS1GLrtaTOLE1ElSluMldNrpk9Emq6uYs8SS8iHlu5xTAmM9rRkM91o48+rIRryBtyO9t+uLYCoMG6jVMVA=="], "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="], @@ -118,15 +118,15 @@ "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.74.0", "", { "os": "win32", "cpu": "x64" }, "sha512-VTC9IYTIMrVUk/i6Ms1ohzzDKZFkWn0KU2OBbPBzgmVZ2V30165T/zK4LztTr0Xgp9fZ1qQZ1rsZAu/rEmySlA=="], - "@smithy/core": ["@smithy/core@3.29.3", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A=="], + "@smithy/core": ["@smithy/core@3.29.8", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-rpCbCV+TimOBi3VLNBMmtTvgfOWcFIEAru3+TFlG87SL2F+te4jOnnNR+cf3uR4eJ5Qf4LnT80fqnBKgPRS6zA=="], - "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.8", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-q9J7JTiXrAhB8sDp4px97uEPT7CwKH61Co78grdNQvU8QZAdiuaSRhP0tUVf2ogy36RZTrlMU1rBmDEH+cnkiA=="], + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.13", "", { "dependencies": { "@smithy/core": "^3.29.8", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-X+2HNZhWi5i3rJsCas0LPf6fTQUaKyJ40zd8aTO/bwpRfpU3biYaqLr7C1WMibL7PVKJalpi1PyybjGPNoHC8Q=="], - "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.6.5", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-SuqeisTyPoiIPtIYru/sGxGyXzmZ+8nnFOhC+qRPglt06Ebd1yH//CDltZB2J/3WBNVhwfUaZ0EtHB3cm2X32g=="], + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.6.10", "", { "dependencies": { "@smithy/core": "^3.29.8", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-5/Yj9mS2JjTsB3B8ZX7euh77mrY9aXW23ag1yAmFykSRmA6vldqBrgqmSeQ50EjY+5SB8+aE4w14B6LKbBVEhQ=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.5", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-bNqdxTQTxmLbomSmlkZFz8L6B/feQ2HHzw4L2zY7Ecp2XffYAZq2uzdWDdxJHJFbEvqd+SRuluJso0P8+xPdbw=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.10", "", { "dependencies": { "@smithy/core": "^3.29.8", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-ETQz9v/Z+nTQc6fRWTXxUpxJqwpmzB3Tn3WKAdHwWkeT+m+HE5czs6GNG8vW+4vyxXSls65RVcvOZwk7Q/PS/Q=="], - "@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + "@smithy/signature-v4": ["@smithy/signature-v4@5.6.9", "", { "dependencies": { "@smithy/core": "^3.29.8", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-g5rnEii/mkT0mjVJmlsaOfyNBtHNTecD9Lo4NP8D5HzMUEnZNpz7/FbvBCjNcV4vteHFAxOGiLUYNxPkDZZAPw=="], "@smithy/types": ["@smithy/types@4.16.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg=="], @@ -332,6 +332,30 @@ "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/core": ["@aws-sdk/core@3.975.2", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@aws-sdk/xml-builder": "^3.972.35", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.29.3", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-iyeXwziyjJpixq5OmhsIyrSWx8vwcI7gDo4yRUC3EP7NQtOo9iAJiIEc3G+/HkhtNXqOhofiCK7Lc34Sq+fJWg=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.68", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.58", "@aws-sdk/credential-provider-http": "^3.972.60", "@aws-sdk/credential-provider-ini": "^3.973.2", "@aws-sdk/credential-provider-process": "^3.972.58", "@aws-sdk/credential-provider-sso": "^3.973.2", "@aws-sdk/credential-provider-web-identity": "^3.972.64", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-4akjzW9CjorByYfqXBXmYUh/h7Io3U4DtVgGGh9TQraZ7ZlyJqNyHwDRGiUFnHD+BTOeTbCesCa4sJaK7BGZ7A=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/types": ["@aws-sdk/types@3.974.1", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-W0IQZR0eaBqlBFIIofMapaWkw1W0U+Xi4dvW+BqwmCEMd8Ng2U6IhkxuPSjMVnR8klLjfuS9PeZWUl1N6UaZdg=="], + + "@aws-sdk/client-bedrock-agentcore-control/@smithy/core": ["@smithy/core@3.29.3", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A=="], + + "@aws-sdk/client-bedrock-agentcore-control/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.6.5", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-SuqeisTyPoiIPtIYru/sGxGyXzmZ+8nnFOhC+qRPglt06Ebd1yH//CDltZB2J/3WBNVhwfUaZ0EtHB3cm2X32g=="], + + "@aws-sdk/client-bedrock-agentcore-control/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.5", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-bNqdxTQTxmLbomSmlkZFz8L6B/feQ2HHzw4L2zY7Ecp2XffYAZq2uzdWDdxJHJFbEvqd+SRuluJso0P8+xPdbw=="], + + "@aws-sdk/client-iam/@aws-sdk/core": ["@aws-sdk/core@3.975.2", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@aws-sdk/xml-builder": "^3.972.35", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.29.3", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-iyeXwziyjJpixq5OmhsIyrSWx8vwcI7gDo4yRUC3EP7NQtOo9iAJiIEc3G+/HkhtNXqOhofiCK7Lc34Sq+fJWg=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.68", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.58", "@aws-sdk/credential-provider-http": "^3.972.60", "@aws-sdk/credential-provider-ini": "^3.973.2", "@aws-sdk/credential-provider-process": "^3.972.58", "@aws-sdk/credential-provider-sso": "^3.973.2", "@aws-sdk/credential-provider-web-identity": "^3.972.64", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-4akjzW9CjorByYfqXBXmYUh/h7Io3U4DtVgGGh9TQraZ7ZlyJqNyHwDRGiUFnHD+BTOeTbCesCa4sJaK7BGZ7A=="], + + "@aws-sdk/client-iam/@aws-sdk/types": ["@aws-sdk/types@3.974.1", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-W0IQZR0eaBqlBFIIofMapaWkw1W0U+Xi4dvW+BqwmCEMd8Ng2U6IhkxuPSjMVnR8klLjfuS9PeZWUl1N6UaZdg=="], + + "@aws-sdk/client-iam/@smithy/core": ["@smithy/core@3.29.3", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A=="], + + "@aws-sdk/client-iam/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.6.5", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-SuqeisTyPoiIPtIYru/sGxGyXzmZ+8nnFOhC+qRPglt06Ebd1yH//CDltZB2J/3WBNVhwfUaZ0EtHB3cm2X32g=="], + + "@aws-sdk/client-iam/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.5", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-bNqdxTQTxmLbomSmlkZFz8L6B/feQ2HHzw4L2zY7Ecp2XffYAZq2uzdWDdxJHJFbEvqd+SRuluJso0P8+xPdbw=="], + "listr2/cli-truncate": ["cli-truncate@5.2.0", "", { "dependencies": { "slice-ansi": "^8.0.0", "string-width": "^8.2.0" } }, "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw=="], "log-update/cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], @@ -342,14 +366,94 @@ "react-devtools-core/ws": ["ws@7.5.12", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-1xGnbYN3zbog9CwuNDQULNRrTCLIn46/WmpR1f0w6PsCYQHkylZr5vkd6kfMZYV6pRnQkcPNRyiA8LsrNKyhpg=="], + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.35", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pXzaWe3evZhjxDXAlMnqISe/XefTCGwBJG4nFTXaWSgAnMkqPEhxEPqJNhhpGesEvKFhvNpnozJJ4GTL11bRYw=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.58", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-vyGtvK1rY940eq7JT0yIGKuZ+2kpPSJcHibSvGlit5oiMFDamzC7cxBGLl4FLnd6suihMXDI2FSF2dL6TmBqPA=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.60", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-g9b9YzDrD5pcKiPBJfCSXRfFMrA39eR0guUhZ5SRm+7vMAVc43+effxbcamxBjSd5bUhrdKo5te/yQuWurLXLA=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.2", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/credential-provider-env": "^3.972.58", "@aws-sdk/credential-provider-http": "^3.972.60", "@aws-sdk/credential-provider-login": "^3.972.64", "@aws-sdk/credential-provider-process": "^3.972.58", "@aws-sdk/credential-provider-sso": "^3.973.2", "@aws-sdk/credential-provider-web-identity": "^3.972.64", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Yr7yxNyQ8aHt9Ww0RPFUZx+xiem+vl7vuwhP0tniTijoesJNV5jou9HCgVpI0GEPAF+89TkOvilE5uRrZJnjaw=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.58", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-1nYitRCaDmXWUrpBJt6WlcGjLx1JVsMY8rlYuHHsTYTSaYikbixYdQSyINN2VYq1F798uTO9qHAzytL25M8g3A=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.2", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/token-providers": "3.1087.0", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pjMLaLU/JZi5lVfmR14V1OZqRBTuMHf6AwGNZA0K9hK+JKtO3jcLBarfD8iq5oc8cSowvc/9R32sqMVXZPo6xQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.64", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-7Buc7p0OvDHW7iBsu4b+YdS0WnaFBDGKDfbVQqaac9dkWiSiUtIoarBDsA1RmOVXZijaZJDoHJFIQiicQvWRlQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.8", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-q9J7JTiXrAhB8sDp4px97uEPT7CwKH61Co78grdNQvU8QZAdiuaSRhP0tUVf2ogy36RZTrlMU1rBmDEH+cnkiA=="], + + "@aws-sdk/client-iam/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.35", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pXzaWe3evZhjxDXAlMnqISe/XefTCGwBJG4nFTXaWSgAnMkqPEhxEPqJNhhpGesEvKFhvNpnozJJ4GTL11bRYw=="], + + "@aws-sdk/client-iam/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.58", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-vyGtvK1rY940eq7JT0yIGKuZ+2kpPSJcHibSvGlit5oiMFDamzC7cxBGLl4FLnd6suihMXDI2FSF2dL6TmBqPA=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.60", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-g9b9YzDrD5pcKiPBJfCSXRfFMrA39eR0guUhZ5SRm+7vMAVc43+effxbcamxBjSd5bUhrdKo5te/yQuWurLXLA=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.2", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/credential-provider-env": "^3.972.58", "@aws-sdk/credential-provider-http": "^3.972.60", "@aws-sdk/credential-provider-login": "^3.972.64", "@aws-sdk/credential-provider-process": "^3.972.58", "@aws-sdk/credential-provider-sso": "^3.973.2", "@aws-sdk/credential-provider-web-identity": "^3.972.64", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Yr7yxNyQ8aHt9Ww0RPFUZx+xiem+vl7vuwhP0tniTijoesJNV5jou9HCgVpI0GEPAF+89TkOvilE5uRrZJnjaw=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.58", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-1nYitRCaDmXWUrpBJt6WlcGjLx1JVsMY8rlYuHHsTYTSaYikbixYdQSyINN2VYq1F798uTO9qHAzytL25M8g3A=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.2", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/token-providers": "3.1087.0", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pjMLaLU/JZi5lVfmR14V1OZqRBTuMHf6AwGNZA0K9hK+JKtO3jcLBarfD8iq5oc8cSowvc/9R32sqMVXZPo6xQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.64", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-7Buc7p0OvDHW7iBsu4b+YdS0WnaFBDGKDfbVQqaac9dkWiSiUtIoarBDsA1RmOVXZijaZJDoHJFIQiicQvWRlQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.8", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-q9J7JTiXrAhB8sDp4px97uEPT7CwKH61Co78grdNQvU8QZAdiuaSRhP0tUVf2ogy36RZTrlMU1rBmDEH+cnkiA=="], + "listr2/cli-truncate/slice-ansi": ["slice-ansi@8.0.0", "", { "dependencies": { "ansi-styles": "^6.2.3", "is-fullwidth-code-point": "^5.1.0" } }, "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg=="], "log-update/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], "log-update/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.64", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-YQoSI4d6kXvoenoG/0Jv/PqaAuukHzGmGXGyHBQYeEUNsYovlNAn/Sw1wp/WQbhcQ3HsEMGgjEahvD3igz6ecQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1087.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-umM+qNq16f2fH+VLM5MqXW4ORNQAjk+TOSto73xbUHcKaU41L48j786r3UWQYlejeJk37NlvRYgxBT+MBkfaYQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.64", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-YQoSI4d6kXvoenoG/0Jv/PqaAuukHzGmGXGyHBQYeEUNsYovlNAn/Sw1wp/WQbhcQ3HsEMGgjEahvD3igz6ecQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1087.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/nested-clients": "^3.997.32", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-umM+qNq16f2fH+VLM5MqXW4ORNQAjk+TOSto73xbUHcKaU41L48j786r3UWQYlejeJk37NlvRYgxBT+MBkfaYQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.32", "", { "dependencies": { "@aws-sdk/core": "^3.975.2", "@aws-sdk/signature-v4-multi-region": "^3.996.40", "@aws-sdk/types": "^3.974.1", "@smithy/core": "^3.29.3", "@smithy/fetch-http-handler": "^5.6.5", "@smithy/node-http-handler": "^4.9.5", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-6Yj2fr9XF67cndITea48rchTdVr3VGx6PN47bIKNinJAjLkmaIlz/4EBPCgJ8UmhVopiXmeAuPLI3+DXDDbMhQ=="], + "log-update/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "log-update/cli-cursor/restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.40", "", { "dependencies": { "@aws-sdk/types": "^3.974.1", "@smithy/signature-v4": "^5.6.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wrGZ/authosokclY1DXsiWT/1WjfCI22FuZGgdcilF+XLTXs5dCjAtiFYSPsEToZkbm3Lj2YP8PoWg0yoMNu0g=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-bedrock-agentcore-control/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], + + "@aws-sdk/client-iam/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.6.4", "", { "dependencies": { "@smithy/core": "^3.29.3", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ=="], } } diff --git a/package.json b/package.json index 9a5e0d80e..629a7f835 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "typescript": "^5" }, "dependencies": { - "@aws-sdk/client-bedrock-agentcore": "^3.1079.0", + "@aws-sdk/client-bedrock-agentcore": "^3.1092.0", "@aws-sdk/client-bedrock-agentcore-control": "^3.1079.0", "@aws-sdk/client-iam": "^3.1080.0", "@inkui-cli/data-table": "^0.2.0", diff --git a/src/components/Root.tsx b/src/components/Root.tsx index 5d59130e0..1a7c6ccac 100644 --- a/src/components/Root.tsx +++ b/src/components/Root.tsx @@ -28,6 +28,7 @@ import { RuntimeListEndpointsScreen } from "../handlers/runtime/endpoint/list/sc import { RuntimeVersionScreen } from "../handlers/runtime/version/screen.tsx"; import { RuntimeGetVersionScreen } from "../handlers/runtime/version/get/screen.tsx"; import { RuntimeListVersionsScreen } from "../handlers/runtime/version/list/screen.tsx"; +import { RuntimeInvokeScreen } from "../handlers/runtime/invoke/screen.tsx"; import { RootScreen, HelpScreen } from "../handlers/screen.tsx"; import type { Context } from "../router"; @@ -255,6 +256,18 @@ export function Root({ path, ctx, core, queryClient }: RootProps) { path="agentcore/runtime/endpoint/list/:runtimeId" element={} /> + } + /> + } + /> + } + /> } /> diff --git a/src/components/RuntimeEndpointPicker.tsx b/src/components/RuntimeEndpointPicker.tsx index 509d5ca57..3025327ec 100644 --- a/src/components/RuntimeEndpointPicker.tsx +++ b/src/components/RuntimeEndpointPicker.tsx @@ -27,6 +27,7 @@ export interface RuntimeEndpointPickerProps extends ScreenProps { breadcrumb: string[]; description?: string; onSelect: (qualifier: string) => void; + onEscape?: () => void; } export function RuntimeEndpointPicker({ @@ -36,10 +37,11 @@ export function RuntimeEndpointPicker({ breadcrumb, description, onSelect, + onEscape, }: RuntimeEndpointPickerProps) { const opts = coreOptsFromCtx(ctx); const navigate = useNavigate(); - const goBack = () => navigate(-1); + const goBack = onEscape ?? (() => navigate(-1)); return ( void; + onEscape?: () => void; } export function RuntimePicker({ @@ -35,10 +36,11 @@ export function RuntimePicker({ breadcrumb, description, onSelect, + onEscape, }: RuntimePickerProps) { const opts = coreOptsFromCtx(ctx); const navigate = useNavigate(); - const goBack = () => navigate("/" + breadcrumb.slice(0, -1).join("/")); + const goBack = onEscape ?? (() => navigate("/" + breadcrumb.slice(0, -1).join("/"))); return ( ( + source: AsyncIterable, + signal: AbortSignal, +): AsyncGenerator { + let abort = () => {}; + const aborted = new Promise((_, reject) => { + abort = () => + reject(signal.reason ?? new DOMException("The operation was aborted", "AbortError")); + if (signal.aborted) abort(); + else signal.addEventListener("abort", abort, { once: true }); + }); + aborted.catch(() => {}); + + const iterator = source[Symbol.asyncIterator](); + try { + for (;;) { + const result = await Promise.race([iterator.next(), aborted]); + if (result.done) return; + yield result.value; + } + } finally { + signal.removeEventListener("abort", abort); + void iterator.return?.()?.catch(() => {}); + } +} diff --git a/src/core/core.test.ts b/src/core/core.test.ts index 2c773710a..140a966d4 100644 --- a/src/core/core.test.ts +++ b/src/core/core.test.ts @@ -1,13 +1,18 @@ import { test, expect } from "bun:test"; -import type { BedrockAgentCoreControlClient } from "@aws-sdk/client-bedrock-agentcore-control"; +import { + GetAgentRuntimeCommand, + type BedrockAgentCoreControlClient, +} from "@aws-sdk/client-bedrock-agentcore-control"; import type { IAMClient } from "@aws-sdk/client-iam"; import { + InvokeAgentRuntimeCommand, InvokeAgentRuntimeCommandCommand, InvokeHarnessCommand, type BedrockAgentCoreClient, } from "@aws-sdk/client-bedrock-agentcore"; +import type { RuntimeInvokeRequest } from "../handlers/runtime/types"; import { CoreClient } from "./index"; -import type { ClientConfig } from "./types"; +import type { ClientConfig, CoreFetch } from "./types"; import { toClientConfig } from "./utils"; import { createSilentLogger } from "../testing"; @@ -23,6 +28,48 @@ function fakeIam(config: ClientConfig): IAMClient { return { config, kind: "iam" } as unknown as IAMClient; } +function coreWithDataSend( + send: (command: unknown, options: unknown) => Promise, +): CoreClient { + return new CoreClient({ + createControlClient: fakeControl, + createDataClient: (config) => + ({ config, kind: "data", send }) as unknown as BedrockAgentCoreClient, + createIamClient: fakeIam, + logger: createSilentLogger(), + }); +} + +async function resolveRuntimeApplicationHeaders( + command: InvokeAgentRuntimeCommand, +): Promise<[string, string][]> { + let headers: [string, string][] = []; + const handler = command.middlewareStack.resolve(async (args) => { + headers = Object.entries((args.request as { headers: Record }).headers); + return { output: { statusCode: 204 } as never, response: {} as never }; + }, {} as never); + await handler({ input: command.input, request: { headers: {} } } as never); + return headers; +} + +function customJwtCore(fetch: CoreFetch, endpoint = "https://runtime.test"): CoreClient { + return new CoreClient({ + createControlClient: fakeControl, + createDataClient: (config) => + ({ + config: { + endpointProvider: () => ({ url: new URL(config.endpoint ?? endpoint) }), + }, + send: async () => { + throw new Error("IAM transport must not be used"); + }, + }) as unknown as BedrockAgentCoreClient, + createIamClient: fakeIam, + fetch, + logger: createSilentLogger(), + }); +} + test("control() constructs a client once per config and caches it", () => { let built = 0; const core = new CoreClient({ @@ -96,6 +143,33 @@ test("exposes a harness sub-client", () => { expect(core.harness).toBeDefined(); }); +test("getRuntime sends the abort signal to the control client", async () => { + const sent: { command: unknown; options: unknown }[] = []; + const core = new CoreClient({ + createControlClient: (config) => + ({ + config, + send: async (command: unknown, options: unknown) => { + sent.push({ command, options }); + return {}; + }, + }) as unknown as BedrockAgentCoreControlClient, + createDataClient: fakeData, + createIamClient: fakeIam, + logger: createSilentLogger(), + }); + const controller = new AbortController(); + + await core.runtime.getRuntime("runtime-123", { region: "us-east-1" }, controller.signal); + + expect(sent).toHaveLength(1); + expect(sent[0]!.command).toBeInstanceOf(GetAgentRuntimeCommand); + expect((sent[0]!.command as GetAgentRuntimeCommand).input).toEqual({ + agentRuntimeId: "runtime-123", + }); + expect(sent[0]!.options).toEqual({ abortSignal: controller.signal }); +}); + test("invokeHarness sends an InvokeHarnessCommand on the data client with the abort signal", async () => { // A fake data client that records what send() receives and resolves a canned // response, so we can assert the harness sub-client's SDK translation. @@ -148,17 +222,7 @@ test("invokeHarness stream iteration rejects promptly when aborted mid-stream", await new Promise(() => {}); }, }; - const core = new CoreClient({ - createControlClient: fakeControl, - createDataClient: (config) => - ({ - config, - kind: "data", - send: async () => ({ stream: hangingStream }), - }) as unknown as BedrockAgentCoreClient, - createIamClient: fakeIam, - logger: createSilentLogger(), - }); + const core = coreWithDataSend(async () => ({ stream: hangingStream })); const controller = new AbortController(); const response = await core.harness.invokeHarness( @@ -177,19 +241,9 @@ test("invokeHarness stream iteration rejects promptly when aborted mid-stream", test("invokeAgentRuntimeCommand sends the command on the data client with the abort signal", async () => { const sent: { command: unknown; options: unknown }[] = []; - const core = new CoreClient({ - createControlClient: fakeControl, - createDataClient: (config) => - ({ - config, - kind: "data", - send: async (command: unknown, options: unknown) => { - sent.push({ command, options }); - return { statusCode: 200, stream: undefined }; - }, - }) as unknown as BedrockAgentCoreClient, - createIamClient: fakeIam, - logger: createSilentLogger(), + const core = coreWithDataSend(async (command, options) => { + sent.push({ command, options }); + return { statusCode: 200, stream: undefined }; }); const request = { @@ -205,19 +259,370 @@ test("invokeAgentRuntimeCommand sends the command on the data client with the ab expect(sent[0]!.options).toEqual({ abortSignal: controller.signal }); }); +test("invokeRuntime maps all modeled IAM fields and response metadata", async () => { + const sent: { command: unknown; options: unknown }[] = []; + const body = (async function* () { + yield Uint8Array.from([0, 1, 255]); + })(); + const sdkResponse = { + statusCode: 202, + contentType: "application/octet-stream", + runtimeSessionId: "runtime-session", + mcpSessionId: "mcp-session", + mcpProtocolVersion: "2025-06-18", + traceId: "trace-id", + traceParent: "trace-parent", + traceState: "trace-state", + baggage: "baggage", + response: body, + }; + const core = coreWithDataSend(async (command, options) => { + sent.push({ command, options }); + return sdkResponse; + }); + const request: RuntimeInvokeRequest = { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: Uint8Array.from([123, 125]), + contentType: "application/json", + accept: "text/event-stream", + runtimeSessionId: "runtime-session", + runtimeUserId: "runtime-user", + mcpSessionId: "mcp-session", + mcpProtocolVersion: "2025-06-18", + mcpMethod: "tools/call", + mcpName: "weather", + traceId: "trace-id", + traceParent: "trace-parent", + traceState: "trace-state", + baggage: "tenant=retail", + }; + const controller = new AbortController(); + + const result = await core.runtime.invokeRuntime( + request, + { region: "us-west-2", endpointUrl: "https://custom" }, + controller.signal, + ); + + expect(sent).toHaveLength(1); + expect(sent[0]!.command).toBeInstanceOf(InvokeAgentRuntimeCommand); + const { runtimeId, ...input } = request; + expect((sent[0]!.command as InvokeAgentRuntimeCommand).input).toEqual({ + ...input, + agentRuntimeArn: runtimeId, + }); + expect(sent[0]!.options).toEqual({ abortSignal: controller.signal }); + const { response, ...metadata } = sdkResponse; + expect(result).toEqual({ + ...metadata, + body: response, + }); +}); + +test("invokeRuntime adds ordered application headers outside the modeled IAM input", async () => { + let command: InvokeAgentRuntimeCommand | undefined; + const core = coreWithDataSend(async (sent) => { + command = sent as InvokeAgentRuntimeCommand; + return { statusCode: 204 }; + }); + + await core.runtime.invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new Uint8Array(), + contentType: "application/json", + applicationHeaders: [ + ["X-One", "1"], + ["x-two", "2"], + ], + }, + { region: "us-east-1" }, + ); + + expect(command).toBeInstanceOf(InvokeAgentRuntimeCommand); + expect(command!.input).not.toHaveProperty("applicationHeaders"); + expect(await resolveRuntimeApplicationHeaders(command!)).toEqual([ + ["X-One", "1"], + ["x-two", "2"], + ]); +}); + +test("invokeRuntime aborts an established IAM response stream", async () => { + const source = (async function* () { + yield Buffer.from("partial"); + await new Promise(() => {}); + })(); + const core = coreWithDataSend(async () => ({ + statusCode: 200, + contentType: "text/plain", + response: source, + })); + const controller = new AbortController(); + const response = await core.runtime.invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new Uint8Array(), + contentType: "application/json", + }, + { region: "us-east-1" }, + controller.signal, + ); + const iterator = response.body[Symbol.asyncIterator](); + + expect(await iterator.next()).toEqual({ done: false, value: Buffer.from("partial") }); + const pending = iterator.next(); + controller.abort(); + + const result = await Promise.race([ + pending.then( + () => "completed", + (error: Error) => error.name, + ), + new Promise((resolve) => setTimeout(() => resolve("timed out"), 25)), + ]); + expect(result).toBe("AbortError"); +}); + +test("IAM invoke failures preserve safe SDK diagnostics without arbitrary causes", async () => { + const core = coreWithDataSend(async () => { + throw Object.assign(new Error("failed with secret request content"), { + name: "AccessDeniedException", + $metadata: { + httpStatusCode: 403, + requestId: "request-123", + }, + }); + }); + + const caught = await core.runtime + .invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new Uint8Array(), + contentType: "application/json", + }, + { region: "us-east-1" }, + ) + .catch((caught: Error) => caught); + const error = caught as Error; + + expect(error.message).toBe( + "Runtime invocation failed (AccessDeniedException, HTTP 403, request ID request-123)", + ); + expect(error.message).not.toContain("secret request content"); +}); + +test("CUSTOM_JWT invoke uses the generated endpoint and exact fetch request", async () => { + const calls: { input: string | URL | Request; init?: RequestInit }[] = []; + const controller = new AbortController(); + const fetch = async (input: string | URL | Request, init?: RequestInit): Promise => { + calls.push({ input, init }); + return new Response(Uint8Array.from([1, 2]), { + status: 200, + headers: { + "Content-Type": "application/json", + "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": "returned-runtime", + "Mcp-Session-Id": "returned-mcp", + }, + }); + }; + const core = customJwtCore(fetch); + const payload = Uint8Array.from([123, 0, 125]); + + const result = await core.runtime.invokeRuntime( + { + runtimeId: "runtime/id", + accountId: "123456789012", + qualifier: "prod green", + payload, + contentType: "application/json", + accept: "text/event-stream", + runtimeSessionId: "runtime-session", + runtimeUserId: "runtime-user", + applicationHeaders: [["X-Tenant", "retail"]], + bearerToken: "secret-token", + mcpSessionId: "mcp-session", + mcpProtocolVersion: "2025-06-18", + mcpMethod: "tools/call", + mcpName: "weather", + traceId: "trace-id", + traceParent: "trace-parent", + traceState: "trace-state", + baggage: "tenant=retail", + }, + { region: "us-west-2", endpointUrl: "https://runtime.test/base" }, + controller.signal, + ); + + expect(calls).toHaveLength(1); + expect(String(calls[0]!.input)).toBe( + "https://runtime.test/base/runtimes/runtime%2Fid/invocations?accountId=123456789012&qualifier=prod+green", + ); + expect(calls[0]!.init).toMatchObject({ + method: "POST", + redirect: "error", + body: payload, + signal: controller.signal, + }); + expect(new Headers(calls[0]!.init!.headers)).toEqual( + new Headers({ + Accept: "text/event-stream", + Authorization: "Bearer secret-token", + "Content-Type": "application/json", + "Mcp-Method": "tools/call", + "Mcp-Name": "weather", + "Mcp-Protocol-Version": "2025-06-18", + "Mcp-Session-Id": "mcp-session", + "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": "runtime-session", + "X-Amzn-Bedrock-AgentCore-Runtime-User-Id": "runtime-user", + "X-Amzn-Trace-Id": "trace-id", + "X-Tenant": "retail", + baggage: "tenant=retail", + traceparent: "trace-parent", + tracestate: "trace-state", + }), + ); + expect(result.runtimeSessionId).toBe("returned-runtime"); + expect(result.mcpSessionId).toBe("returned-mcp"); + const resultBytes: Uint8Array[] = []; + for await (const chunk of result.body) resultBytes.push(chunk); + expect(Buffer.concat(resultBytes)).toEqual(Buffer.from([1, 2])); +}); + +test("CUSTOM_JWT rejects non-HTTPS endpoints without calling fetch", async () => { + let fetched = false; + const core = customJwtCore(async () => { + fetched = true; + return new Response(); + }, "http://runtime.test"); + + await expect( + core.runtime.invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new TextEncoder().encode("secret payload"), + contentType: "application/json", + bearerToken: "secret-token", + }, + { region: "us-east-1" }, + ), + ).rejects.toThrow("CUSTOM_JWT requires an HTTPS endpoint"); + expect(fetched).toBe(false); +}); + +test("CUSTOM_JWT modeled header failures do not expose their values", async () => { + let fetched = false; + const core = customJwtCore(async () => { + fetched = true; + return new Response(); + }); + + await expect( + core.runtime.invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new Uint8Array(), + contentType: "application/json", + bearerToken: "secret-token", + traceParent: "secret-header\r\nvalue", + }, + { region: "us-east-1" }, + ), + ).rejects.toThrow(/^Invalid Runtime request header$/); + expect(fetched).toBe(false); +}); + +test("CUSTOM_JWT non-2xx cancels without reading and exposes status only", async () => { + let cancelled = 0; + let read = false; + const response = { + ok: false, + status: 401, + headers: new Headers(), + body: { + cancel: async () => { + cancelled++; + }, + async *[Symbol.asyncIterator]() { + read = true; + yield new TextEncoder().encode("secret response body"); + }, + }, + } as unknown as Response; + const core = customJwtCore(async () => response); + const request: RuntimeInvokeRequest = { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new TextEncoder().encode("secret payload"), + contentType: "application/json", + bearerToken: "secret-token", + }; + + await expect(core.runtime.invokeRuntime(request, { region: "us-east-1" })).rejects.toThrow( + /^HTTP 401$/, + ); + expect(cancelled).toBe(1); + expect(read).toBe(false); +}); + +test("CUSTOM_JWT transport failures do not expose arbitrary causes", async () => { + const core = customJwtCore(async () => { + throw new Error("failed with Bearer secret-token"); + }); + + await expect( + core.runtime.invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new Uint8Array(), + contentType: "application/json", + bearerToken: "secret-token", + }, + { region: "us-east-1" }, + ), + ).rejects.toThrow(/^Runtime invocation failed$/); +}); + +test("invokeRuntime exposes an empty async iterable when the SDK omits the body", async () => { + const core = coreWithDataSend(async () => ({ + statusCode: 204, + contentType: "application/json", + })); + + const response = await core.runtime.invokeRuntime( + { + runtimeId: "runtime-123", + accountId: "123456789012", + qualifier: "DEFAULT", + payload: new Uint8Array(), + contentType: "application/json", + }, + { region: "us-east-1" }, + ); + + const chunks: Uint8Array[] = []; + for await (const chunk of response.body) chunks.push(chunk); + expect(chunks).toEqual([]); +}); + test("invokeHarness returns the stream untouched when no abort signal is given", async () => { const stream = (async function* () {})(); - const core = new CoreClient({ - createControlClient: fakeControl, - createDataClient: (config) => - ({ - config, - kind: "data", - send: async () => ({ stream }), - }) as unknown as BedrockAgentCoreClient, - createIamClient: fakeIam, - logger: createSilentLogger(), - }); + const core = coreWithDataSend(async () => ({ stream })); const response = await core.harness.invokeHarness( { harnessArn: "arn", runtimeSessionId: "s".repeat(40), messages: [] }, diff --git a/src/core/harness.tsx b/src/core/harness.tsx index 69883be40..7a5edeec9 100644 --- a/src/core/harness.tsx +++ b/src/core/harness.tsx @@ -37,6 +37,7 @@ import { } from "@aws-sdk/client-bedrock-agentcore"; import type { CoreHarnessClient, CreateHarnessInput } from "../handlers/harness/types"; import type { AwsClients, CoreOptions } from "./types"; +import { abortable } from "./abortable"; import { ensureDefaultExecutionRole } from "./executionRole"; import { toClientConfig } from "./utils"; @@ -227,36 +228,3 @@ async function retryWhileRoleUnassumable( } } } - -// abortError mirrors the error the SDK rejects with on a pre-stream abort, so -// consumers see one shape either way. -function abortError(): Error { - const error = new Error("The operation was aborted"); - error.name = "AbortError"; - return error; -} - -// abortable relays `source`, rejecting the pending read as soon as `signal` -// aborts. The pre-attached catch swallows the rejection when no read is in -// flight (e.g. abort after the stream ended) to avoid unhandled-rejection -// noise. -async function* abortable(source: AsyncIterable, signal: AbortSignal): AsyncGenerator { - const aborted = new Promise((_, reject) => { - if (signal.aborted) reject(abortError()); - else signal.addEventListener("abort", () => reject(abortError()), { once: true }); - }); - aborted.catch(() => {}); - - const iterator = source[Symbol.asyncIterator](); - try { - for (;;) { - const result = await Promise.race([iterator.next(), aborted]); - if (result.done) return; - yield result.value; - } - } finally { - // Close the SDK stream on early exit to release the connection. Fire and - // forget: its settlement may itself wait on the wedged stream. - void iterator.return?.()?.catch(() => {}); - } -} diff --git a/src/core/index.tsx b/src/core/index.tsx index b08d01a49..d87e4b292 100644 --- a/src/core/index.tsx +++ b/src/core/index.tsx @@ -7,6 +7,7 @@ import { RuntimeClient } from "./runtime"; import type { AwsClients, ClientConfig, + CoreFetch, CreateControlClient, CreateDataClient, CreateIamClient, @@ -18,6 +19,7 @@ import { FsProjectManager } from "./project"; export type { AwsClients, ClientConfig, + CoreFetch, CreateControlClient, CreateDataClient, CreateIamClient, @@ -28,6 +30,7 @@ type CoreClientConfig = { createDataClient: CreateDataClient; createIamClient: CreateIamClient; logger: Logger; + fetch?: CoreFetch; }; // CoreClient is the single entry point to the Bedrock AgentCore APIs. It owns the @@ -47,7 +50,7 @@ export class CoreClient implements AwsClients { // Feature-scoped sub-clients. Access as e.g. `coreClient.harness.getHarness(...)`. readonly harness: HarnessClient = new HarnessClient(this); readonly identity: IdentityClient = new IdentityClient(this); - readonly runtime: RuntimeClient = new RuntimeClient(this); + readonly runtime: RuntimeClient; readonly projectManager: ProjectManager; @@ -56,6 +59,7 @@ export class CoreClient implements AwsClients { this.createDataClient = config.createDataClient; this.createIamClient = config.createIamClient; this.logger = config.logger; + this.runtime = new RuntimeClient(this, config.fetch ?? globalThis.fetch); this.projectManager = new FsProjectManager({ logger: this.logger.child({ module: "projectManager" }), diff --git a/src/core/runtime.tsx b/src/core/runtime.tsx index 77cc6c3e8..63f7a8158 100644 --- a/src/core/runtime.tsx +++ b/src/core/runtime.tsx @@ -10,17 +10,164 @@ import { 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 { InvokeAgentRuntimeCommand } from "@aws-sdk/client-bedrock-agentcore"; +import type { + CoreRuntimeClient, + RuntimeInvokeRequest, + RuntimeInvokeResponse, +} from "../handlers/runtime/types"; +import type { AwsClients, CoreFetch, CoreOptions } from "./types"; +import { abortable } from "./abortable"; import { toClientConfig } from "./utils"; +async function* emptyBody(): AsyncGenerator {} + export class RuntimeClient implements CoreRuntimeClient { - constructor(private readonly clients: AwsClients) {} + constructor( + private readonly clients: AwsClients, + private readonly fetch: CoreFetch, + ) {} + + async invokeRuntime( + request: RuntimeInvokeRequest, + options: CoreOptions, + signal?: AbortSignal, + ): Promise { + const { runtimeId, applicationHeaders, bearerToken, ...input } = request; + if (bearerToken !== undefined) { + const client = this.clients.data(toClientConfig(options)); + const endpoint = client.config.endpointProvider({ + Region: options.region, + Endpoint: options.endpointUrl, + }); + const url = new URL(endpoint.url); + if (url.protocol !== "https:") { + throw new TypeError("CUSTOM_JWT requires an HTTPS endpoint"); + } + url.pathname = `${url.pathname.replace(/\/?$/, "/")}runtimes/${encodeURIComponent(runtimeId)}/invocations`; + url.search = new URLSearchParams({ + accountId: request.accountId, + qualifier: request.qualifier, + }).toString(); + const headers = new Headers(applicationHeaders); + try { + headers.set("Authorization", `Bearer ${bearerToken}`); + } catch { + throw new TypeError("Invalid bearer token"); + } + try { + for (const [name, value] of [ + ["Content-Type", request.contentType], + ["Accept", request.accept], + ["Mcp-Session-Id", request.mcpSessionId], + ["X-Amzn-Bedrock-AgentCore-Runtime-Session-Id", request.runtimeSessionId], + ["Mcp-Protocol-Version", request.mcpProtocolVersion], + ["Mcp-Method", request.mcpMethod], + ["Mcp-Name", request.mcpName], + ["X-Amzn-Bedrock-AgentCore-Runtime-User-Id", request.runtimeUserId], + ["X-Amzn-Trace-Id", request.traceId], + ["traceparent", request.traceParent], + ["tracestate", request.traceState], + ["baggage", request.baggage], + ] as const) { + if (value !== undefined) headers.set(name, value); + } + } catch { + throw new TypeError("Invalid Runtime request header"); + } + let response: Response; + try { + response = await this.fetch(url, { + method: "POST", + redirect: "error", + headers, + body: request.payload as RequestInit["body"], + signal, + }); + } catch (error) { + if (signal?.aborted) throw signal.reason ?? error; + throw new Error("Runtime invocation failed"); + } + if (!response.ok) { + await response.body?.cancel().catch(() => undefined); + throw new Error(`HTTP ${response.status}`); + } + const body = (response.body as AsyncIterable | null) ?? emptyBody(); + return { + statusCode: response.status, + contentType: response.headers.get("content-type") ?? "", + runtimeSessionId: + response.headers.get("x-amzn-bedrock-agentcore-runtime-session-id") ?? undefined, + mcpSessionId: response.headers.get("mcp-session-id") ?? undefined, + mcpProtocolVersion: response.headers.get("mcp-protocol-version") ?? undefined, + traceId: response.headers.get("x-amzn-trace-id") ?? undefined, + traceParent: response.headers.get("traceparent") ?? undefined, + traceState: response.headers.get("tracestate") ?? undefined, + baggage: response.headers.get("baggage") ?? undefined, + body: signal ? abortable(body, signal) : body, + }; + } - async getRuntime(id: string, options: CoreOptions): Promise { + const command = new InvokeAgentRuntimeCommand({ ...input, agentRuntimeArn: runtimeId }); + if (applicationHeaders?.length) { + command.middlewareStack.add( + (next) => async (args) => { + const sdkRequest = args.request as { headers: Record }; + for (const [name, value] of applicationHeaders) sdkRequest.headers[name] = value; + return next(args); + }, + { step: "build", name: "runtimeApplicationHeaders" }, + ); + } + let response; + try { + response = await this.clients.data(toClientConfig(options)).send(command, { + abortSignal: signal, + }); + } catch (error) { + if (signal?.aborted) throw signal.reason ?? error; + const sdkError = error as { + name?: unknown; + $metadata?: { httpStatusCode?: unknown; requestId?: unknown }; + }; + const diagnostics: string[] = []; + if (typeof sdkError?.name === "string" && sdkError.name !== "Error") { + diagnostics.push(sdkError.name); + } + if (typeof sdkError?.$metadata?.httpStatusCode === "number") { + diagnostics.push(`HTTP ${sdkError.$metadata.httpStatusCode}`); + } + if (typeof sdkError?.$metadata?.requestId === "string") { + diagnostics.push(`request ID ${sdkError.$metadata.requestId}`); + } + throw new Error( + `Runtime invocation failed${diagnostics.length ? ` (${diagnostics.join(", ")})` : ""}`, + ); + } + + const body = (response.response as AsyncIterable | undefined) ?? emptyBody(); + return { + statusCode: response.statusCode ?? 0, + contentType: response.contentType ?? "", + runtimeSessionId: response.runtimeSessionId, + mcpSessionId: response.mcpSessionId, + mcpProtocolVersion: response.mcpProtocolVersion, + traceId: response.traceId, + traceParent: response.traceParent, + traceState: response.traceState, + baggage: response.baggage, + body: signal ? abortable(body, signal) : body, + }; + } + + async getRuntime( + id: string, + options: CoreOptions, + signal?: AbortSignal, + ): Promise { return this.clients .control(toClientConfig(options)) - .send(new GetAgentRuntimeCommand({ agentRuntimeId: id })); + .send(new GetAgentRuntimeCommand({ agentRuntimeId: id }), { abortSignal: signal }); } async getRuntimeVersion( diff --git a/src/core/types.tsx b/src/core/types.tsx index 517a0632c..41eaf2c4b 100644 --- a/src/core/types.tsx +++ b/src/core/types.tsx @@ -25,6 +25,9 @@ export interface ClientConfig { export type CreateControlClient = (config: ClientConfig) => BedrockAgentCoreControlClient; export type CreateDataClient = (config: ClientConfig) => BedrockAgentCoreClient; export type CreateIamClient = (config: ClientConfig) => IAMClient; +export type CoreFetch = ( + ...args: Parameters +) => ReturnType; // AwsClients hands out configured SDK clients. CoreClient implements it and its // sub-clients (HarnessClient, etc.) consume it, so they all share the same diff --git a/src/handlers/runtime/index.tsx b/src/handlers/runtime/index.tsx index dfe2b73bb..ad4f2e3e1 100644 --- a/src/handlers/runtime/index.tsx +++ b/src/handlers/runtime/index.tsx @@ -4,6 +4,7 @@ import { renderTui } from "../../tui"; import type { AppIO, Core } from "../types"; import { createRuntimeEndpointHandler } from "./endpoint"; import { createGetRuntimeHandler } from "./get"; +import { createInvokeRuntimeHandler } from "./invoke"; import { createListRuntimesHandler } from "./list"; import { createRuntimeVersionHandler } from "./version"; @@ -13,6 +14,7 @@ export function createRuntimeHandler(core: Core, io: AppIO): Router { .default(renderTui(core, io)) .handler(createGetRuntimeHandler(core)) .handler(createListRuntimesHandler(core)) + .handler(createInvokeRuntimeHandler(core, io)) .handler(createRuntimeVersionHandler(core, io)) .handler(createRuntimeEndpointHandler(core, io)); } diff --git a/src/handlers/runtime/invoke/RequestOptionsScreen.tsx b/src/handlers/runtime/invoke/RequestOptionsScreen.tsx new file mode 100644 index 000000000..5c0c608e7 --- /dev/null +++ b/src/handlers/runtime/invoke/RequestOptionsScreen.tsx @@ -0,0 +1,166 @@ +import { useState } from "react"; +import { Box, Text, useInput } from "ink"; +import { FormTextArea } from "../../../components/FormTextArea"; +import { Select } from "../../../components/ui/select"; +import { TextInput } from "../../../components/ui/text-input"; + +export interface RuntimeInvokeOptions { + payloadSource: "Inline" | "File"; + responseDestination: "Console" | "File"; + payloadPath?: string; + contentType?: string; + accept?: string; + outputPath?: string; + runtimeSessionId?: string; + runtimeUserId?: string; + headers?: string; + bearerToken?: string; + mcpSessionId?: string; + mcpProtocolVersion?: string; + mcpMethod?: string; + mcpName?: string; + traceId?: string; + traceParent?: string; + traceState?: string; + baggage?: string; +} + +type Row = { + field: keyof RuntimeInvokeOptions; + label: string; + choices?: string[]; + multiline?: boolean; + secret?: boolean; +}; + +export function RequestOptionsScreen({ + value, + onChange, + onClose, + customJwt, + mcp, +}: { + value: RuntimeInvokeOptions; + onChange: (value: RuntimeInvokeOptions) => void; + onClose: () => void; + customJwt: boolean; + mcp: boolean; +}) { + const rows = [ + { field: "payloadSource", label: "Payload source", choices: ["Inline", "File"] }, + ...(value.payloadSource === "File" + ? [{ field: "payloadPath", label: "Payload path" } as Row] + : []), + { + field: "contentType", + label: "Content type", + choices: ["application/json", "text/plain", "application/octet-stream", "Custom"], + }, + { + field: "accept", + label: "Accepted response", + choices: [ + "text/event-stream", + "application/json", + "text/plain", + "application/octet-stream", + "Custom", + ], + }, + { + field: "responseDestination", + label: "Response destination", + choices: ["Console", "File"], + }, + ...(value.responseDestination === "File" + ? [{ field: "outputPath", label: "Response path" } as Row] + : []), + { field: "runtimeSessionId", label: "Runtime session ID" }, + { field: "runtimeUserId", label: "Runtime user ID" }, + { field: "headers", label: "Application headers", multiline: true }, + ...(customJwt ? [{ field: "bearerToken", label: "Bearer JWT", secret: true } as Row] : []), + ...(mcp + ? [ + { field: "mcpSessionId", label: "MCP session ID" }, + { field: "mcpProtocolVersion", label: "MCP protocol version" }, + { + field: "mcpMethod", + label: "MCP method", + choices: ["tools/call", "tools/list", "resources/read", "prompts/get", "Custom"], + }, + { field: "mcpName", label: "MCP name" }, + ] + : []), + { field: "traceId", label: "Trace ID" }, + { field: "traceParent", label: "Traceparent" }, + { field: "traceState", label: "Tracestate" }, + { field: "baggage", label: "Baggage" }, + ] as Row[]; + const [selected, setSelected] = useState(0); + const [editing, setEditing] = useState(); + const [draft, setDraft] = useState(""); + const [custom, setCustom] = useState(false); + const row = rows[Math.min(selected, rows.length - 1)]!; + const finish = (next?: string) => { + if (next !== undefined) onChange({ ...value, [row.field]: next }); + setEditing(undefined); + setCustom(false); + }; + + useInput((input, key) => { + if (key.escape) { + if (editing) finish(); + else onClose(); + return; + } + if (editing) { + if (row.multiline && key.ctrl && input === "d") finish(draft); + return; + } + if (key.upArrow) setSelected((current) => Math.max(0, current - 1)); + if (key.downArrow) setSelected((current) => Math.min(rows.length - 1, current + 1)); + if (key.return) { + setDraft(value[row.field] ?? ""); + setCustom(false); + setEditing(row.field); + } + }); + + return ( + + Request Options + {rows.map((item, index) => ( + + {index === selected ? "› " : " "} + {item.label}:{" "} + {item.secret && value[item.field] + ? "*".repeat(value[item.field]!.length) + : value[item.field]} + + ))} + {editing === row.field && row.choices && !custom ? ( +