diff --git a/src/cli/commands/status/__tests__/action.test.ts b/src/cli/commands/status/__tests__/action.test.ts
index a4b80286..1c3a089d 100644
--- a/src/cli/commands/status/__tests__/action.test.ts
+++ b/src/cli/commands/status/__tests__/action.test.ts
@@ -1,6 +1,7 @@
import type { AgentCoreProjectSpec, DeployedResourceState } from '../../../../schema/index.js';
import { computeResourceStatuses, handleProjectStatus } from '../action.js';
import type { StatusContext } from '../action.js';
+import { buildRuntimeInvocationUrl } from '../constants.js';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const mockGetAgentRuntimeStatus = vi.fn();
@@ -631,3 +632,176 @@ describe('handleProjectStatus — live enrichment', () => {
expect(mockGetEvaluator).not.toHaveBeenCalled();
});
});
+
+describe('buildRuntimeInvocationUrl', () => {
+ it('constructs the correct invocation URL with encoded ARN', () => {
+ const url = buildRuntimeInvocationUrl(
+ 'us-east-1',
+ 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/travelplanner_FlightsMcp-abcdefgh'
+ );
+ expect(url).toBe(
+ 'https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/arn%3Aaws%3Abedrock-agentcore%3Aus-east-1%3A123456789012%3Aruntime%2Ftravelplanner_FlightsMcp-abcdefgh/invocations'
+ );
+ });
+
+ it('handles different regions', () => {
+ const url = buildRuntimeInvocationUrl(
+ 'eu-west-1',
+ 'arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/my-agent-xyz'
+ );
+ expect(url).toBe(
+ 'https://bedrock-agentcore.eu-west-1.amazonaws.com/runtimes/arn%3Aaws%3Abedrock-agentcore%3Aeu-west-1%3A111111111111%3Aruntime%2Fmy-agent-xyz/invocations'
+ );
+ });
+});
+
+describe('handleProjectStatus — invocation URL enrichment', () => {
+ beforeEach(() => {
+ mockGetAgentRuntimeStatus.mockReset();
+ mockGetEvaluator.mockReset();
+ mockGetOnlineEvaluationConfig.mockReset();
+ });
+
+ afterEach(() => vi.clearAllMocks());
+
+ it('sets invocationUrl on deployed agents after runtime status enrichment', async () => {
+ const runtimeArn = 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/proj_MyAgent-abc123';
+
+ mockGetAgentRuntimeStatus.mockResolvedValue({
+ runtimeId: 'proj_MyAgent-abc123',
+ status: 'READY',
+ });
+
+ const ctx: StatusContext = {
+ project: {
+ ...baseProject,
+ runtimes: [{ name: 'MyAgent' }],
+ } as unknown as AgentCoreProjectSpec,
+ awsTargets: [{ name: 'dev', region: 'us-east-1', account: '123456789012' }],
+ deployedState: {
+ targets: {
+ dev: {
+ resources: {
+ runtimes: {
+ MyAgent: {
+ runtimeId: 'proj_MyAgent-abc123',
+ runtimeArn,
+ roleArn: 'arn:aws:iam::123456789012:role/test',
+ },
+ },
+ },
+ },
+ },
+ },
+ } as unknown as StatusContext;
+
+ const result = await handleProjectStatus(ctx);
+
+ expect(result.success).toBe(true);
+ const agentEntry = result.resources.find(r => r.resourceType === 'agent' && r.name === 'MyAgent');
+ expect(agentEntry).toBeDefined();
+ expect(agentEntry!.invocationUrl).toBe(
+ `https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/${encodeURIComponent(runtimeArn)}/invocations`
+ );
+ });
+
+ it('does not set invocationUrl on local-only agents', async () => {
+ const ctx: StatusContext = {
+ project: {
+ ...baseProject,
+ runtimes: [{ name: 'LocalAgent' }],
+ } as unknown as AgentCoreProjectSpec,
+ awsTargets: [{ name: 'dev', region: 'us-east-1', account: '123456789012' }],
+ deployedState: {
+ targets: {
+ dev: {
+ resources: {},
+ },
+ },
+ },
+ } as unknown as StatusContext;
+
+ const result = await handleProjectStatus(ctx);
+
+ expect(result.success).toBe(true);
+ const agentEntry = result.resources.find(r => r.resourceType === 'agent' && r.name === 'LocalAgent');
+ expect(agentEntry).toBeDefined();
+ expect(agentEntry!.invocationUrl).toBeUndefined();
+ });
+
+ it('still sets invocationUrl when runtime status fetch fails', async () => {
+ const runtimeArn = 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/proj_FailAgent-xyz';
+ mockGetAgentRuntimeStatus.mockRejectedValue(new Error('Timeout'));
+
+ const ctx: StatusContext = {
+ project: {
+ ...baseProject,
+ runtimes: [{ name: 'FailAgent' }],
+ } as unknown as AgentCoreProjectSpec,
+ awsTargets: [{ name: 'dev', region: 'us-east-1', account: '123456789012' }],
+ deployedState: {
+ targets: {
+ dev: {
+ resources: {
+ runtimes: {
+ FailAgent: {
+ runtimeId: 'proj_FailAgent-xyz',
+ runtimeArn,
+ roleArn: 'arn:aws:iam::123456789012:role/test',
+ },
+ },
+ },
+ },
+ },
+ },
+ } as unknown as StatusContext;
+
+ const result = await handleProjectStatus(ctx);
+
+ expect(result.success).toBe(true);
+ const agentEntry = result.resources.find(r => r.resourceType === 'agent' && r.name === 'FailAgent');
+ expect(agentEntry).toBeDefined();
+ expect(agentEntry!.error).toBe('Timeout');
+ expect(agentEntry!.invocationUrl).toBe(
+ `https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/${encodeURIComponent(runtimeArn)}/invocations`
+ );
+ });
+
+ it('does not set invocationUrl on pending-removal agents', async () => {
+ mockGetAgentRuntimeStatus.mockResolvedValue({
+ runtimeId: 'proj_OldAgent-abc',
+ status: 'READY',
+ });
+
+ const ctx: StatusContext = {
+ project: {
+ ...baseProject,
+ runtimes: [],
+ } as unknown as AgentCoreProjectSpec,
+ awsTargets: [{ name: 'dev', region: 'us-east-1', account: '123456789012' }],
+ deployedState: {
+ targets: {
+ dev: {
+ resources: {
+ runtimes: {
+ OldAgent: {
+ runtimeId: 'proj_OldAgent-abc',
+ runtimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/proj_OldAgent-abc',
+ roleArn: 'arn:aws:iam::123456789012:role/test',
+ },
+ },
+ },
+ },
+ },
+ },
+ } as unknown as StatusContext;
+
+ const result = await handleProjectStatus(ctx);
+
+ expect(result.success).toBe(true);
+ const agentEntry = result.resources.find(r => r.resourceType === 'agent' && r.name === 'OldAgent');
+ expect(agentEntry).toBeDefined();
+ expect(agentEntry!.deploymentState).toBe('pending-removal');
+ expect(agentEntry!.invocationUrl).toBeUndefined();
+ });
+});
diff --git a/src/cli/commands/status/action.ts b/src/cli/commands/status/action.ts
index 4f9ed1bc..29222fc2 100644
--- a/src/cli/commands/status/action.ts
+++ b/src/cli/commands/status/action.ts
@@ -5,6 +5,7 @@ import { getEvaluator, getOnlineEvaluationConfig } from '../../aws/agentcore-con
import { getErrorMessage } from '../../errors';
import { ExecLogger } from '../../logging';
import type { ResourceDeploymentState } from './constants';
+import { buildRuntimeInvocationUrl } from './constants';
export type { ResourceDeploymentState };
@@ -23,6 +24,7 @@ export interface ResourceStatusEntry {
identifier?: string;
detail?: string;
error?: string;
+ invocationUrl?: string;
}
export interface ProjectStatusResult {
@@ -284,16 +286,20 @@ export async function handleProjectStatus(
const agentState = agentStates[entry.name];
if (!agentState) return;
+ const invocationUrl = entry.identifier
+ ? buildRuntimeInvocationUrl(targetConfig.region, entry.identifier)
+ : undefined;
+
try {
const runtimeStatus = await getAgentRuntimeStatus({
region: targetConfig.region,
runtimeId: agentState.runtimeId,
});
- resources[i] = { ...entry, detail: runtimeStatus.status };
+ resources[i] = { ...entry, detail: runtimeStatus.status, invocationUrl };
logger.log(` ${entry.name}: ${runtimeStatus.status} (${agentState.runtimeId})`);
} catch (error) {
const errorMsg = getErrorMessage(error);
- resources[i] = { ...entry, error: errorMsg };
+ resources[i] = { ...entry, error: errorMsg, invocationUrl };
logger.log(` ${entry.name}: ERROR - ${errorMsg}`, 'error');
}
})
diff --git a/src/cli/commands/status/command.tsx b/src/cli/commands/status/command.tsx
index f7335362..9e6de5e3 100644
--- a/src/cli/commands/status/command.tsx
+++ b/src/cli/commands/status/command.tsx
@@ -154,7 +154,14 @@ export const registerStatus = (program: Command) => {
Agents
{agents.map(entry => (
-
+
+
+ {entry.invocationUrl && (
+
+ {' '}URL: {entry.invocationUrl}
+
+ )}
+
))}
)}
diff --git a/src/cli/commands/status/constants.ts b/src/cli/commands/status/constants.ts
index 6dfbc08d..e9b047d5 100644
--- a/src/cli/commands/status/constants.ts
+++ b/src/cli/commands/status/constants.ts
@@ -13,3 +13,8 @@ export const DEPLOYMENT_STATE_LABELS: Record =
'local-only': 'Local only',
'pending-removal': 'Removed locally',
};
+
+export function buildRuntimeInvocationUrl(region: string, runtimeArn: string): string {
+ const encodedArn = encodeURIComponent(runtimeArn);
+ return `https://bedrock-agentcore.${region}.amazonaws.com/runtimes/${encodedArn}/invocations`;
+}
diff --git a/src/cli/tui/components/ResourceGraph.tsx b/src/cli/tui/components/ResourceGraph.tsx
index e9da36dd..eacb9bd1 100644
--- a/src/cli/tui/components/ResourceGraph.tsx
+++ b/src/cli/tui/components/ResourceGraph.tsx
@@ -72,6 +72,7 @@ function ResourceRow({
statusColor,
deploymentState,
identifier,
+ invocationUrl,
}: {
icon: string;
color: string;
@@ -81,6 +82,7 @@ function ResourceRow({
statusColor?: string;
deploymentState?: ResourceStatusEntry['deploymentState'];
identifier?: string;
+ invocationUrl?: string;
}) {
const badge = deploymentState ? getDeploymentBadge(deploymentState) : undefined;
@@ -98,6 +100,11 @@ function ResourceRow({
{' '}ID: {identifier}
)}
+ {invocationUrl && (
+
+ {' '}URL: {invocationUrl}
+
+ )}
);
}
@@ -182,6 +189,7 @@ export function ResourceGraph({ project, mcp, agentName, resourceStatuses }: Res
statusColor={runtimeStatusColor}
deploymentState={rsEntry?.deploymentState}
identifier={rsEntry?.identifier}
+ invocationUrl={rsEntry?.invocationUrl}
/>
);
})}