@@ -16,13 +16,8 @@ import { ANSI } from '../../constants';
1616import { isPreviewEnabled } from '../../feature-flags' ;
1717import { InvokeLogger } from '../../logging' ;
1818import { formatMcpToolList } from '../../operations/dev/utils' ;
19- import {
20- canFetchHarnessToken ,
21- canFetchRuntimeToken ,
22- fetchHarnessToken ,
23- fetchRuntimeToken ,
24- } from '../../operations/fetch-access' ;
25- import { generateSessionId } from '../../operations/session' ;
19+ import { canFetchHarnessToken , fetchHarnessToken } from '../../operations/fetch-access' ;
20+ import { resolveInvokeTarget } from './resolve' ;
2621import type { InvokeOptions , InvokeResult } from './types' ;
2722import { randomUUID } from 'node:crypto' ;
2823
@@ -49,43 +44,37 @@ export async function loadInvokeConfig(configIO: ConfigIO = new ConfigIO()): Pro
4944export async function handleInvoke ( context : InvokeContext , options : InvokeOptions = { } ) : Promise < InvokeResult > {
5045 const { project, deployedState, awsTargets } = context ;
5146
52- // Resolve target
53- const targetNames = Object . keys ( deployedState . targets ) ;
54- if ( targetNames . length === 0 ) {
55- return {
56- success : false ,
57- error : new ResourceNotFoundError ( 'No deployed targets found. Run `agentcore deploy` first.' ) ,
58- } ;
59- }
60-
61- const selectedTargetName = options . targetName ?? targetNames [ 0 ] ! ;
62-
63- if ( options . targetName && ! targetNames . includes ( options . targetName ) ) {
64- return {
65- success : false ,
66- error : new ResourceNotFoundError (
67- `Target '${ options . targetName } ' not found. Available: ${ targetNames . join ( ', ' ) } `
68- ) ,
69- } ;
70- }
71-
72- const targetState = deployedState . targets [ selectedTargetName ] ;
73- const targetConfig = awsTargets . find ( t => t . name === selectedTargetName ) ;
74-
75- if ( ! targetConfig ) {
76- return {
77- success : false ,
78- error : new ResourceNotFoundError ( `Target config '${ selectedTargetName } ' not found in aws-targets` ) ,
79- } ;
80- }
81-
82- // Preview: route to harness or runtime
47+ // Preview: route to harness before runtime resolution
8348 if ( isPreviewEnabled ( ) ) {
8449 const harnessEntries = project . harnesses ?? [ ] ;
8550 const isHarnessInvoke = options . harnessName != null || ( harnessEntries . length > 0 && project . runtimes . length === 0 ) ;
8651
8752 if ( isHarnessInvoke ) {
88- return handleHarnessInvoke ( project , targetState , targetConfig , selectedTargetName , options ) ;
53+ const targetNames = Object . keys ( deployedState . targets ) ;
54+ if ( targetNames . length === 0 ) {
55+ return {
56+ success : false ,
57+ error : new ResourceNotFoundError ( 'No deployed targets found. Run `agentcore deploy` first.' ) ,
58+ } ;
59+ }
60+ const selectedTarget = options . targetName ?? targetNames [ 0 ] ! ;
61+ if ( options . targetName && ! targetNames . includes ( options . targetName ) ) {
62+ return {
63+ success : false ,
64+ error : new ResourceNotFoundError (
65+ `Target '${ options . targetName } ' not found. Available: ${ targetNames . join ( ', ' ) } `
66+ ) ,
67+ } ;
68+ }
69+ const targetState = deployedState . targets [ selectedTarget ] ;
70+ const targetConfig = awsTargets . find ( t => t . name === selectedTarget ) ;
71+ if ( ! targetConfig ) {
72+ return {
73+ success : false ,
74+ error : new ResourceNotFoundError ( `Target config '${ selectedTarget } ' not found in aws-targets` ) ,
75+ } ;
76+ }
77+ return handleHarnessInvoke ( project , targetState , targetConfig , selectedTarget , options ) ;
8978 }
9079
9180 if ( harnessEntries . length > 0 && project . runtimes . length > 0 && ! options . agentName ) {
@@ -102,32 +91,26 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
10291 }
10392 }
10493
105- if ( project . runtimes . length === 0 ) {
106- return { success : false , error : new ValidationError ( 'No agents defined in configuration' ) } ;
107- }
108-
109- // Resolve agent
110- const agentNames = project . runtimes . map ( a => a . name ) ;
111-
112- if ( ! options . agentName && project . runtimes . length > 1 ) {
113- return {
114- success : false ,
115- error : new ValidationError ( `Multiple runtimes found. Use --runtime to specify one: ${ agentNames . join ( ', ' ) } ` ) ,
116- } ;
117- }
118-
119- const agentSpec = options . agentName ? project . runtimes . find ( a => a . name === options . agentName ) : project . runtimes [ 0 ] ;
94+ const resolved = await resolveInvokeTarget ( {
95+ project,
96+ deployedState,
97+ awsTargets,
98+ agentName : options . agentName ,
99+ targetName : options . targetName ,
100+ bearerToken : options . bearerToken ,
101+ sessionId : options . sessionId ,
102+ } ) ;
120103
121- if ( options . agentName && ! agentSpec ) {
122- return {
123- success : false ,
124- error : new ResourceNotFoundError ( `Agent '${ options . agentName } ' not found. Available: ${ agentNames . join ( ', ' ) } ` ) ,
125- } ;
104+ if ( ! resolved . success ) {
105+ return { success : false , error : resolved . error } ;
126106 }
127107
128- if ( ! agentSpec ) {
129- return { success : false , error : new ValidationError ( 'No agents defined in configuration' ) } ;
130- }
108+ const { agentSpec, targetName : selectedTargetName , targetConfig, runtimeArn, baggage } = resolved ;
109+ options = {
110+ ...options ,
111+ bearerToken : resolved . bearerToken ?? options . bearerToken ,
112+ sessionId : resolved . sessionId ?? options . sessionId ,
113+ } ;
131114
132115 // Warn about VPC mode endpoint requirements
133116 if ( agentSpec . networkMode === 'VPC' ) {
@@ -136,69 +119,11 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
136119 ) ;
137120 }
138121
139- // Get the deployed state for this specific agent
140- const agentState = targetState ?. resources ?. runtimes ?. [ agentSpec . name ] ;
141-
142- if ( ! agentState ) {
143- return {
144- success : false ,
145- error : new ValidationError ( `Agent '${ agentSpec . name } ' is not deployed to target '${ selectedTargetName } '` ) ,
146- } ;
147- }
148-
149- // Build config bundle baggage if a bundle is associated with this agent
150- const deployedBundles = targetState ?. resources ?. configBundles ?? { } ;
151- let baggage : string | undefined ;
152- const bundleSpec = project . configBundles ?. find ( b => {
153- const keys = Object . keys ( b . components ?? { } ) ;
154- return keys . some ( k => k === `{{runtime:${ agentSpec . name } }}` ) ;
155- } ) ;
156- if ( bundleSpec ) {
157- const bundleState = deployedBundles [ bundleSpec . name ] ;
158- if ( bundleState ?. bundleArn && bundleState ?. versionId ) {
159- baggage = `aws.agentcore.configbundle_arn=${ encodeURIComponent ( bundleState . bundleArn ) } ,aws.agentcore.configbundle_version=${ encodeURIComponent ( bundleState . versionId ) } ` ;
160- }
161- }
162-
163- // Auto-fetch bearer token for CUSTOM_JWT agents when not provided
164- if ( agentSpec . authorizerType === 'CUSTOM_JWT' && ! options . bearerToken ) {
165- const canFetch = await canFetchRuntimeToken ( agentSpec . name ) ;
166- if ( canFetch ) {
167- try {
168- const tokenResult = await fetchRuntimeToken ( agentSpec . name , { deployTarget : selectedTargetName } ) ;
169- options = { ...options , bearerToken : tokenResult . token } ;
170- } catch ( err ) {
171- return {
172- success : false ,
173- error : new ValidationError (
174- `CUSTOM_JWT agent requires a bearer token. Auto-fetch failed: ${ err instanceof Error ? err . message : String ( err ) } \nProvide one manually with --bearer-token.` ,
175- { cause : err }
176- ) ,
177- } ;
178- }
179- } else {
180- return {
181- success : false ,
182- error : new ValidationError (
183- `Agent '${ agentSpec . name } ' is configured for CUSTOM_JWT but no bearer token is available.\nEither provide --bearer-token or re-add the agent with --client-id and --client-secret to enable auto-fetch.`
184- ) ,
185- } ;
186- }
187- }
188-
189- // When invoking with a bearer token (OAuth/CUSTOM_JWT), AgentCore does not
190- // auto-generate a runtime session ID the way it does for SigV4 callers. Templates
191- // that wire up AgentCoreMemorySessionManager require a non-null session_id, so
192- // generate one here if the caller didn't pass --session-id.
193- if ( options . bearerToken && ! options . sessionId ) {
194- options = { ...options , sessionId : generateSessionId ( ) } ;
195- }
196-
197122 // Exec mode: run shell command in runtime container
198123 if ( options . exec ) {
199124 const logger = new InvokeLogger ( {
200125 agentName : agentSpec . name ,
201- runtimeArn : agentState . runtimeArn ,
126+ runtimeArn : runtimeArn ,
202127 region : targetConfig . region ,
203128 sessionId : options . sessionId ,
204129 } ) ;
@@ -211,7 +136,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
211136 try {
212137 const result = await executeBashCommand ( {
213138 region : targetConfig . region ,
214- runtimeArn : agentState . runtimeArn ,
139+ runtimeArn : runtimeArn ,
215140 command,
216141 sessionId : options . sessionId ,
217142 timeout : options . timeout ,
@@ -308,7 +233,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
308233 if ( agentSpec . protocol === 'MCP' ) {
309234 const mcpOpts = {
310235 region : targetConfig . region ,
311- runtimeArn : agentState . runtimeArn ,
236+ runtimeArn : runtimeArn ,
312237 userId : options . userId ,
313238 headers : options . headers ,
314239 bearerToken : options . bearerToken ,
@@ -392,7 +317,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
392317 const a2aResult = await invokeA2ARuntime (
393318 {
394319 region : targetConfig . region ,
395- runtimeArn : agentState . runtimeArn ,
320+ runtimeArn : runtimeArn ,
396321 userId : options . userId ,
397322 sessionId : options . sessionId ,
398323 headers : options . headers ,
@@ -427,7 +352,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
427352 if ( agentSpec . protocol === 'AGUI' ) {
428353 const logger = new InvokeLogger ( {
429354 agentName : agentSpec . name ,
430- runtimeArn : agentState . runtimeArn ,
355+ runtimeArn : runtimeArn ,
431356 region : targetConfig . region ,
432357 } ) ;
433358
@@ -438,7 +363,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
438363 const aguiResult = await invokeAguiRuntime (
439364 {
440365 region : targetConfig . region ,
441- runtimeArn : agentState . runtimeArn ,
366+ runtimeArn : runtimeArn ,
442367 sessionId : options . sessionId ,
443368 userId : options . userId ,
444369 logger,
@@ -496,7 +421,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
496421 // Create logger for this invocation
497422 const logger = new InvokeLogger ( {
498423 agentName : agentSpec . name ,
499- runtimeArn : agentState . runtimeArn ,
424+ runtimeArn : runtimeArn ,
500425 region : targetConfig . region ,
501426 sessionId : options . sessionId ,
502427 } ) ;
@@ -509,7 +434,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
509434 try {
510435 const result = await invokeAgentRuntimeStreaming ( {
511436 region : targetConfig . region ,
512- runtimeArn : agentState . runtimeArn ,
437+ runtimeArn : runtimeArn ,
513438 payload : options . prompt ,
514439 sessionId : options . sessionId ,
515440 userId : options . userId ,
@@ -544,7 +469,7 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
544469 // Non-streaming mode
545470 const response = await invokeAgentRuntime ( {
546471 region : targetConfig . region ,
547- runtimeArn : agentState . runtimeArn ,
472+ runtimeArn : runtimeArn ,
548473 payload : options . prompt ,
549474 sessionId : options . sessionId ,
550475 userId : options . userId ,
0 commit comments