fix(cli): add --endpoint flag to invoke and set SigV4 qualifier#1648
fix(cli): add --endpoint flag to invoke and set SigV4 qualifier#1648aidandaly24 wants to merge 4 commits into
Conversation
agentcore invoke had no --endpoint flag and the SigV4 InvokeAgentRuntimeCommand was built without a qualifier, so named runtime endpoints (version aliases like prod/staging) could not be targeted and every SigV4 invoke silently hit DEFAULT. Register --endpoint on invoke, thread it through InvokeOptions -> resolve.ts (validated against project.runtimes[].endpoints and deployed runtimeEndpoints) -> action.ts, and set qualifier on both the streaming and non-streaming SigV4 commands in agentcore.ts. Fixes aws#986 Fixes aws#1554
Package TarballHow to installgh release download pr-1648-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.21.0.tgz |
|
Claude Security Review: no high-confidence findings. (run) |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Nice fix — the core plumbing of qualifier through both SigV4 paths is clean, the validation in resolveInvokeTarget matches against both configured and deployed endpoints, and the test setup mocks at the right boundary (AWS SDK client). A couple of things to address before merging.
1. AGENTCORE_RUNTIME_ENDPOINT env var is silently ignored in TUI mode
The help text on line 144 advertises that --endpoint defaults to the env var, but the env var alone never forces CLI mode (only cliOptions.endpoint does, see line 374), and src/cli/tui/screens/invoke/useInvokeFlow.ts never receives the resolved endpoint anyway. So with AGENTCORE_RUNTIME_ENDPOINT=staging and agentcore invoke (no prompt, no flag), the user lands in TUI and silently hits DEFAULT — exactly the failure mode the linked issues describe.
The PR description also says "Also mirror this in the invoke TUI flow (useInvokeFlow.ts) for parity" — but useInvokeFlow.ts is not actually changed. Specifically, invokeAgentRuntimeStreaming is called there (around L789–804) without an endpoint, so even if the env var were honored in TUI mode the qualifier wouldn't make it to the SDK.
Options:
- Resolve the endpoint before the CLI-mode gate and add
resolvedEndpoint !== DEFAULT_ENDPOINT_NAMEto the trigger list at L374, AND plumb it intouseInvokeFlow.ts(passendpointtoinvokeAgentRuntimeStreaming). - Tighten the help text to say the env-var fallback only applies when
--endpointis explicitly given (i.e. don't callresolveEndpointName, just usecliOptions.endpointdirectly). - Move
resolveEndpointNameintoaction.ts/useInvokeFlow.tsso the env-var fallback works uniformly across both flows.
See inline on command.tsx:374.
2. Missing telemetry for the new flag
Per src/cli/telemetry/README.md, new features should include telemetry. The new --endpoint flag is not reflected in InvokeAttrs / computeInvokeAttrs. Suggest adding has_endpoint: boolean (or endpoint_source: 'flag' | 'env' | 'default') to InvokeAttrs in src/cli/telemetry/schemas/command-run.ts and threading it through computeInvokeAttrs so flag adoption is observable. See inline on command.tsx:434.
Out-of-scope note (not blocking this PR)
A2A (invokeA2ARuntime ~agentcore.ts:962) and MCP (mcpRpcCall ~agentcore.ts:719) also build InvokeAgentRuntimeCommand without qualifier, so --endpoint is silently ignored for A2A and MCP-tool invokes. Probably a follow-up — but worth either calling out in the PR body or rejecting --endpoint for those protocols with a clear error rather than silently routing to DEFAULT.
| cliOptions.gatewayTargetName || | ||
| cliOptions.stream || | ||
| cliOptions.runtime || | ||
| cliOptions.endpoint || |
There was a problem hiding this comment.
The help text at line 144 says --endpoint defaults to AGENTCORE_RUNTIME_ENDPOINT, but only cliOptions.endpoint is in this CLI-mode trigger list. If a user sets AGENTCORE_RUNTIME_ENDPOINT=staging and runs agentcore invoke (no prompt, no --endpoint), they drop into TUI mode and the env var is never consulted — the invocation silently hits DEFAULT, the exact failure mode the linked issues describe. useInvokeFlow.ts also never receives the resolved endpoint (it's not modified by this PR).
Fix options:
- Resolve the endpoint via
resolveEndpointName(cliOptions.endpoint)before this if-block, addresolvedEndpoint !== DEFAULT_ENDPOINT_NAMEto the trigger list, and pass the resolved value intouseInvokeFlow.tstoo. - Update the help text and stop calling
resolveEndpointNamehere — just usecliOptions.endpointdirectly so the behavior matches the docs. - Move
resolveEndpointNameintoaction.ts(anduseInvokeFlow.ts) so the env-var fallback works uniformly across CLI and TUI flows.
There was a problem hiding this comment.
Addressed via option 1. The endpoint is now resolved (resolveEndpointName(cliOptions.endpoint)) before the CLI-mode gate, and endpoint !== undefined (i.e. a non-DEFAULT resolved endpoint) is in the CLI-mode trigger list. So AGENTCORE_RUNTIME_ENDPOINT=staging agentcore invoke now forces CLI mode rather than silently dropping into the TUI and hitting DEFAULT. The resolved endpoint is also threaded through the TUI route (App.tsx -> InvokeScreen.tsx -> useInvokeFlow.ts) and passed into invokeAgentRuntimeStreaming, so the qualifier reaches the SDK in TUI mode too. New regression test in invoke.test.ts: 'AGENTCORE_RUNTIME_ENDPOINT (no prompt/flag) forces CLI mode instead of silently routing to the TUI'.
| const options: InvokeOptions = { | ||
| prompt: resolved.prompt, | ||
| agentName: cliOptions.runtime, | ||
| endpoint, |
There was a problem hiding this comment.
Per src/cli/telemetry/README.md, new features should include telemetry. Suggest adding has_endpoint: boolean (or endpoint_source: 'flag' | 'env' | 'default') to InvokeAttrs in src/cli/telemetry/schemas/command-run.ts and threading it through computeInvokeAttrs (called at L390 above) so we can observe flag adoption.
Minimal change: has_endpoint: !!cliOptions.endpoint || !!process.env.AGENTCORE_RUNTIME_ENDPOINT in computeInvokeAttrs.
There was a problem hiding this comment.
Added endpoint_source: 'flag' | 'env' | 'default' to InvokeAttrs (new EndpointSource enum in common-shapes.ts) and a computeEndpointSource() helper threaded through computeInvokeAttrs at both invoke entry points (CLI command.tsx and TUI useInvokeFlow.ts). Covered by new tests in utils.test.ts and invoke.test.ts (endpoint_source flag/env/default).
| .option('--runtime <name>', 'Select specific runtime [non-interactive]') | ||
| .option( | ||
| '--endpoint <name>', | ||
| 'Target a named runtime endpoint (version alias, e.g. prod/staging). Defaults to AGENTCORE_RUNTIME_ENDPOINT env var, then DEFAULT [non-interactive]' |
There was a problem hiding this comment.
This advertises Defaults to AGENTCORE_RUNTIME_ENDPOINT env var, then DEFAULT, but the env-var fallback only fires when some other CLI flag also pushes the invocation into non-interactive mode (see line 374 + useInvokeFlow.ts). Either fix the gate (see comment on L374) or tighten this wording to match actual behavior.
There was a problem hiding this comment.
The help text is now accurate: the env-var fallback fires uniformly. Resolution happens before the CLI-mode gate, and a non-DEFAULT resolved endpoint (whether from --endpoint or AGENTCORE_RUNTIME_ENDPOINT) forces CLI mode, with the resolved value also plumbed into the TUI flow. So 'Defaults to AGENTCORE_RUNTIME_ENDPOINT env var, then DEFAULT' matches the actual behavior in both CLI and TUI paths.
Resolve the invoke endpoint (--endpoint flag -> AGENTCORE_RUNTIME_ENDPOINT
env var -> DEFAULT) before the CLI-mode gate so a non-DEFAULT endpoint
forces CLI mode instead of silently dropping into the TUI and hitting
DEFAULT. Thread the resolved endpoint through the TUI flow (App route ->
InvokeScreen -> useInvokeFlow) into invokeAgentRuntimeStreaming so the
SigV4 qualifier reaches the SDK in TUI mode too.
Add endpoint_source ('flag' | 'env' | 'default') telemetry to InvokeAttrs
via a new EndpointSource enum and computeEndpointSource helper, threaded
through computeInvokeAttrs at both invoke entry points.
|
Claude Security Review: no high-confidence findings. (run) |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
The previous review's concerns (env-var fallback in TUI mode, telemetry instrumentation) have been addressed cleanly. The qualifier plumbing through both SigV4 paths is correct, validation in resolveInvokeTarget checks both configured and deployed endpoints, the env-var fallback is now resolved before the CLI-mode gate, and endpoint_source telemetry is wired through both CLI and TUI entry points.
One new issue: the AGUI path silently ignores --endpoint (see inline comment on agentcore.ts). The PR description's "out-of-scope follow-up" note only calls out A2A and MCP — AGUI has the same silent-DEFAULT routing failure and is the very bug this PR is fixing.
Once that's addressed (either fixed or added to the explicit follow-up scope so it doesn't get lost), this is good to go.
| runtimeSessionId: options.sessionId, | ||
| runtimeUserId: options.userId ?? DEFAULT_RUNTIME_USER_ID, | ||
| ...(options.baggage && { baggage: options.baggage }), | ||
| ...(options.endpoint && { qualifier: options.endpoint }), |
There was a problem hiding this comment.
Note: this comment anchors on the qualifier addition site for the non-streaming SigV4 path, but the issue is in invokeAguiRuntime at agentcore.ts:1088.
invokeAguiRuntime builds InvokeAgentRuntimeCommand here without a qualifier, so agentcore invoke --endpoint prod against an AGUI-protocol agent will silently route to DEFAULT — the same bug this PR is fixing for SigV4 HTTP invokes. The PR description's "out-of-scope follow-up" only calls out A2A (invokeA2ARuntime) and MCP (mcpRpcCall), but AGUI has the same gap.
Options:
- Add
...(options.endpoint && { qualifier: options.endpoint })here (and threadendpointthroughAguiInvokeOptions+ the AGUI call site inaction.ts:636), matching what was done forinvokeAgentRuntime/invokeAgentRuntimeStreaming. - Update the PR description's follow-up scope to explicitly include AGUI alongside A2A and MCP so it doesn't get lost.
- Reject
--endpointwith a clear error for AGUI/A2A/MCP protocols at the validation layer (validate.tsor inaction.tsbefore the protocol branches), so users aren't silently misled.
There was a problem hiding this comment.
Fixed (option 1). AguiInvokeOptions now has an endpoint field, invokeAguiRuntime sets ...(options.endpoint && { qualifier: options.endpoint }) on its InvokeAgentRuntimeCommand, and the resolved endpoint is threaded through both the CLI AGUI call site (action.ts:636) and the TUI AGUI call site (useInvokeFlow.ts). So HTTP, streaming, and AGUI SigV4 invokes all honor --endpoint now. Added qualifier tests for the AGUI path in agentcore-invoke-qualifier.test.ts. The PR-body follow-up note now scopes only A2A (invokeA2ARuntime) and MCP (mcpRpcCall) as remaining work.
invokeAguiRuntime built InvokeAgentRuntimeCommand without a qualifier, so --endpoint was silently ignored for AGUI-protocol agents (routing to DEFAULT) — the same bug this PR fixes for HTTP/streaming. Add an endpoint field to AguiInvokeOptions, set the qualifier on the command, and thread the resolved endpoint through the CLI (action.ts) and TUI (useInvokeFlow.ts) AGUI call sites. Add qualifier tests for the AGUI path.
|
Claude Security Review: no high-confidence findings. (run) |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Nice work threading --endpoint (and the AGENTCORE_RUNTIME_ENDPOINT env-var fallback) through the SigV4, bearer-token, and AGUI paths, and adding telemetry. The earlier reviewer feedback on the env-var gate, help text, AGUI qualifier, and telemetry all look addressed.
One concern about the new regression test — see inline. Otherwise the change looks good.
| expect(json.success).toBe(false); | ||
| expect(result.stderr).not.toContain('requires an interactive terminal'); | ||
| telemetry.assertMetricEmitted({ command: 'invoke', endpoint_source: 'env' }); | ||
| }); |
There was a problem hiding this comment.
This test claims to verify the regression "AGENTCORE_RUNTIME_ENDPOINT (no prompt/flag) forces CLI mode instead of silently routing to the TUI", but the invocation passes --json, which on its own already forces CLI mode (it's in the gate list at command.tsx:380). So even if the new endpoint !== undefined clause were removed entirely, this test would still pass — the env-var-only path is not actually being exercised. The endpoint_source: 'env' telemetry assertion only confirms computeEndpointSource() detected the env var, not that it forced CLI mode.
Fix options:
- Drop
--jsonfrom this test and assert on stderr/stdout containing the action-layer "No prompt provided" error (and stillnot.toContain('requires an interactive terminal')). That actually exercises the regression. - Keep
--jsonbut add a second test without it that asserts the env var alone forces CLI mode (e.g. the action-layer error appears, not the TUI's requireTTY guard). - Replace this test with one that asserts behavior we couldn't get before the fix — e.g. spy/intercept and confirm the action layer receives a non-undefined
endpointwhen only the env var is set.
There was a problem hiding this comment.
Good catch — fixed. Dropped --json (and every other CLI flag) so the env-var-resolved endpoint is the ONLY thing forcing CLI mode, which exercises the new endpoint !== undefined gate clause directly. The test now asserts the action-layer error 'No deployed targets found' appears on stderr (and that 'requires an interactive terminal' does NOT), proving CLI mode was forced rather than routing to the TUI. I verified the negative control: with the endpoint !== undefined clause removed and rebuilt, the same invocation routes to the TUI and hits 'Error: This command requires an interactive terminal', so the test genuinely fails without the fix and passes with it.
The endpoint regression test passed --json, which already forces CLI mode on its own, so it never exercised the new 'endpoint !== undefined' gate clause. Drop --json (and every other CLI flag) so the env-var-resolved endpoint is the ONLY trigger, and assert the action-layer 'No deployed targets found' error appears (not the TUI requireTTY guard). Verified the test fails when the gate clause is removed (routes to TUI) and passes with it.
|
Claude Security Review: no high-confidence findings. (run) |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Reviewed the latest revision. All previously-flagged issues from earlier review rounds have been addressed cleanly:
- Env-var fallback in TUI/CLI gate:
resolveEndpointName(cliOptions.endpoint)is now called before the CLI-mode gate andendpoint !== undefinedis in the trigger list, soAGENTCORE_RUNTIME_ENDPOINT=staging agentcore invokeno longer silently drops into the TUI and hits DEFAULT. - Telemetry:
endpoint_source: flag | env | defaultis added toInvokeAttrsvia the newEndpointSourceenum and wired throughcomputeEndpointSource()at both the CLI (command.tsx) and TUI (useInvokeFlow.ts) entry points. - AGUI parity:
AguiInvokeOptions.endpointis set on theInvokeAgentRuntimeCommandqualifier, plus threaded through both call sites (action.ts:642,useInvokeFlow.ts:678). - Regression test now actually exercises the new gate clause: the
AGENTCORE_RUNTIME_ENDPOINTtest no longer passes--json(which would have forced CLI mode on its own), so the env-var-resolved endpoint is the only thing forcing CLI mode.
Other things I checked and consider fine:
- Mocking in
agentcore-invoke-qualifier.test.tsis at the AWS SDK + credential boundary (matches the existing pattern inagentcore-mcp-bearer.test.ts) — not excessive. - Endpoint validation in
resolveInvokeTargetchecks bothagentSpec.endpointsand deployedruntimeEndpoints, and produces a usefulAvailable: ...error. --endpoint DEFAULTis correctly normalized toundefinedso the SigV4 qualifier is omitted rather than sent explicitly.- A2A and MCP qualifier gaps are explicitly called out as out-of-scope follow-ups in the PR body.
LGTM.
Description
#986 — Add --endpoint flag to agentcore invoke to target specific runtime endpoints
agentcore invokehas no--endpointflag, so users who create named runtime endpoints (version aliases likeprod/stagingviaagentcore add runtime-endpoint) cannot target a specific endpoint from the CLI — invoke always hits the DEFAULT endpoint over SigV4. This is a missing-convenience feature gap, not a malfunction: a complete workaround exists today via--bearer-token(whose path already threads the endpoint qualifier) or by calling the API directly withqualifier.#1554 — Support invoking specific runtime endpoint with --endpoint flag
agentcore invokecan only ever hit a runtime's DEFAULT endpoint; there is no--endpointflag, so named runtime endpoints created viaagentcore add runtime-endpoint(e.g. control/treatment version aliases for A/B testing) cannot be smoke-tested directly. The only workaround is routing through a gateway. As a bonus, the same SigV4-qualifier gap meansrun eval --dataset --endpoint <name>against a SigV4 agent silently invokes DEFAULT while reading spans from the named-endpoint log group, so it can collect zero spans.Fix
Add
--endpoint <name>to invoke and plumb it through to the SDK qualifier. (1) Register the flag in command.tsx and add it to cliOptions/InvokeOptions (types.ts). (2) In resolveInvokeTarget (resolve.ts), accept an endpointName, validate it against project.runtimes[].endpoints[name] and/or deployedState...runtimeEndpoints[${agent}/${name}], and return it as endpoint/qualifier. (3) Pass endpoint into both invokeAgentRuntime (action.ts:748) and invokeAgentRuntimeStreaming (action.ts:710). (4) In agentcore.ts, add...(options.endpoint && { qualifier: options.endpoint })to the two SigV4 InvokeAgentRuntimeCommand builders (lines 362 and 458). DESIGN NOTE confirmed in SDK: the AWS InvokeAgentRuntime API targets endpoints viaqualifier, which is the endpoint NAME, not the ARN (@aws-sdk/client-bedrock-agentcore models_0.d.ts:390-393: "an endpoint name that points to a specific version"); the runtime ARN is unchanged and deployed-state is used only to validate existence. The issue body's wording ("resolve the endpoint ARN and route to it") is technically loose. Also mirror this in the invoke TUI flow (useInvokeFlow.ts) for parity.See the_fix field: register --endpoint on invoke, thread through InvokeOptions->action, AND set
qualifier: options.endpointon the SigV4 InvokeAgentRuntimeCommand (agentcore.ts:362-370,458-466). Reuse existing resolveEndpointName (cloudwatch.ts:9-11) for the AGENTCORE_RUNTIME_ENDPOINT fallback rather than re-implementing it at the command layer.This fix was produced by an automated triage+fix run and validated locally (build + unit suite + symptom reproduction). It is being opened as a draft for CI and human review.
Review feedback addressed
--endpointflag →AGENTCORE_RUNTIME_ENDPOINTenv var →DEFAULT) before the CLI-mode gate incommand.tsx. A non-DEFAULTresolved endpoint is added to the CLI-mode trigger list, soAGENTCORE_RUNTIME_ENDPOINT=staging agentcore invokeno longer silently drops into the TUI and hitsDEFAULT— it forces CLI mode (and reportsNo prompt providedwhen no prompt is given, rather than silently invokingDEFAULT). The resolved endpoint is also threaded all the way into the TUI flow (App.tsxroute →InvokeScreen.tsx→useInvokeFlow.ts) and passed toinvokeAgentRuntimeStreaming, so the qualifier reaches the SDK in TUI mode too.endpoint_source: 'flag' | 'env' | 'default'toInvokeAttrs(src/cli/telemetry/schemas/command-run.ts, newEndpointSourceenum incommon-shapes.ts) and acomputeEndpointSource()helper threaded throughcomputeInvokeAttrsat both invoke entry points (CLIcommand.tsxand TUIuseInvokeFlow.ts) so flag/env adoption is observable.The AGUI path (
invokeAguiRuntime) is now also fixed:AguiInvokeOptionsgained anendpointfield, thequalifieris set on itsInvokeAgentRuntimeCommand, and the resolved endpoint is threaded through both the CLI (action.ts) and TUI (useInvokeFlow.ts) AGUI call sites — so HTTP, streaming, and AGUI SigV4 invokes all honor--endpoint. Covered by new qualifier tests.Follow-up: A2A and MCP qualifier (out of scope for this PR)
invokeA2ARuntimeandmcpRpcCallbuildInvokeAgentRuntimeCommandwithout aqualifier, so--endpointis currently ignored for A2A and MCP-tool invokes (they route toDEFAULT). This PR scopes the qualifier plumbing to the SigV4 invoke paths that the linked issues exercise (HTTP, streaming, AGUI). Threading the qualifier through the A2A and MCP paths — or rejecting--endpointfor those protocols with a clear error — is tracked as a follow-up to keep this change minimal.Related Issue
Closes #986
Closes #1554
Documentation PR
N/A — bug fix; no devguide change required.
Type of Change
Testing
How have you tested the change?
npm run test:unitandnpm run test:integnpm run typechecknpm run lintsrc/assets/, I rannpm run test:update-snapshotsand committed the updated snapshots — N/A, nosrc/assets/changesChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the
terms of your choice.