Skip to content

Commit 482d024

Browse files
committed
refactor(aws): extract createControlClient to avoid per-call client instantiation
Each function in agentcore-control.ts was creating a new BedrockAgentCoreControlClient on every call, wasting HTTP connections and credential resolution. Extracted a shared createControlClient() factory and reuse a single client across paginated listAll* calls. Also added debug warnings when tag fetching fails for runtimes and memories, matching the existing pattern in bedrock-import.ts.
1 parent 187795a commit 482d024

2 files changed

Lines changed: 40 additions & 46 deletions

File tree

src/cli/aws/agentcore-control.ts

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ import {
1212
UpdateOnlineEvaluationConfigCommand,
1313
} from '@aws-sdk/client-bedrock-agentcore-control';
1414

15+
/**
16+
* Create a shared BedrockAgentCoreControlClient for the given region.
17+
* Callers should create one client and reuse it across related operations
18+
* to benefit from connection pooling and credential caching.
19+
*/
20+
export function createControlClient(region: string): BedrockAgentCoreControlClient {
21+
return new BedrockAgentCoreControlClient({
22+
region,
23+
credentials: getCredentialProvider(),
24+
});
25+
}
26+
1527
export interface GetAgentRuntimeStatusOptions {
1628
region: string;
1729
runtimeId: string;
@@ -26,10 +38,7 @@ export interface AgentRuntimeStatusResult {
2638
* Fetch the status of an AgentCore Runtime by runtime ID.
2739
*/
2840
export async function getAgentRuntimeStatus(options: GetAgentRuntimeStatusOptions): Promise<AgentRuntimeStatusResult> {
29-
const client = new BedrockAgentCoreControlClient({
30-
region: options.region,
31-
credentials: getCredentialProvider(),
32-
});
41+
const client = createControlClient(options.region);
3342

3443
const command = new GetAgentRuntimeCommand({
3544
agentRuntimeId: options.runtimeId,
@@ -74,18 +83,18 @@ export interface ListAgentRuntimesResult {
7483
/**
7584
* List all AgentCore Runtimes in the given region.
7685
*/
77-
export async function listAgentRuntimes(options: ListAgentRuntimesOptions): Promise<ListAgentRuntimesResult> {
78-
const client = new BedrockAgentCoreControlClient({
79-
region: options.region,
80-
credentials: getCredentialProvider(),
81-
});
86+
export async function listAgentRuntimes(
87+
options: ListAgentRuntimesOptions,
88+
client?: BedrockAgentCoreControlClient
89+
): Promise<ListAgentRuntimesResult> {
90+
const resolvedClient = client ?? createControlClient(options.region);
8291

8392
const command = new ListAgentRuntimesCommand({
8493
maxResults: options.maxResults,
8594
nextToken: options.nextToken,
8695
});
8796

88-
const response = await client.send(command);
97+
const response = await resolvedClient.send(command);
8998

9099
return {
91100
runtimes: (response.agentRuntimes ?? []).map(r => ({
@@ -104,11 +113,12 @@ export async function listAgentRuntimes(options: ListAgentRuntimesOptions): Prom
104113
* List all AgentCore Runtimes in the given region, paginating through all pages.
105114
*/
106115
export async function listAllAgentRuntimes(options: { region: string }): Promise<AgentRuntimeSummary[]> {
116+
const client = createControlClient(options.region);
107117
const runtimes: AgentRuntimeSummary[] = [];
108118
let nextToken: string | undefined;
109119

110120
do {
111-
const result = await listAgentRuntimes({ region: options.region, maxResults: 100, nextToken });
121+
const result = await listAgentRuntimes({ region: options.region, maxResults: 100, nextToken }, client);
112122
runtimes.push(...result.runtimes);
113123
nextToken = result.nextToken;
114124
} while (nextToken);
@@ -153,10 +163,7 @@ export interface AgentRuntimeDetail {
153163
* Get full details of an AgentCore Runtime by ID.
154164
*/
155165
export async function getAgentRuntimeDetail(options: GetAgentRuntimeOptions): Promise<AgentRuntimeDetail> {
156-
const client = new BedrockAgentCoreControlClient({
157-
region: options.region,
158-
credentials: getCredentialProvider(),
159-
});
166+
const client = createControlClient(options.region);
160167

161168
const command = new GetAgentRuntimeCommand({
162169
agentRuntimeId: options.runtimeId,
@@ -222,8 +229,8 @@ export async function getAgentRuntimeDetail(options: GetAgentRuntimeOptions): Pr
222229
if (tagsResponse.tags && Object.keys(tagsResponse.tags).length > 0) {
223230
tags = tagsResponse.tags;
224231
}
225-
} catch {
226-
// Tags are optional — continue without them if the call fails
232+
} catch (err) {
233+
console.warn(`Warning: Failed to fetch tags for runtime: ${err instanceof Error ? err.message : String(err)}`);
227234
}
228235
}
229236

@@ -275,18 +282,18 @@ export interface ListMemoriesResult {
275282
/**
276283
* List all AgentCore Memories in the given region.
277284
*/
278-
export async function listMemories(options: ListMemoriesOptions): Promise<ListMemoriesResult> {
279-
const client = new BedrockAgentCoreControlClient({
280-
region: options.region,
281-
credentials: getCredentialProvider(),
282-
});
285+
export async function listMemories(
286+
options: ListMemoriesOptions,
287+
client?: BedrockAgentCoreControlClient
288+
): Promise<ListMemoriesResult> {
289+
const resolvedClient = client ?? createControlClient(options.region);
283290

284291
const command = new ListMemoriesCommand({
285292
maxResults: options.maxResults,
286293
nextToken: options.nextToken,
287294
});
288295

289-
const response = await client.send(command);
296+
const response = await resolvedClient.send(command);
290297

291298
return {
292299
memories: (response.memories ?? []).map(m => ({
@@ -304,11 +311,12 @@ export async function listMemories(options: ListMemoriesOptions): Promise<ListMe
304311
* List all AgentCore Memories in the given region, paginating through all pages.
305312
*/
306313
export async function listAllMemories(options: { region: string }): Promise<MemorySummary[]> {
314+
const client = createControlClient(options.region);
307315
const memories: MemorySummary[] = [];
308316
let nextToken: string | undefined;
309317

310318
do {
311-
const result = await listMemories({ region: options.region, maxResults: 100, nextToken });
319+
const result = await listMemories({ region: options.region, maxResults: 100, nextToken }, client);
312320
memories.push(...result.memories);
313321
nextToken = result.nextToken;
314322
} while (nextToken);
@@ -344,10 +352,7 @@ export interface MemoryDetail {
344352
* Get full details of an AgentCore Memory by ID.
345353
*/
346354
export async function getMemoryDetail(options: GetMemoryOptions): Promise<MemoryDetail> {
347-
const client = new BedrockAgentCoreControlClient({
348-
region: options.region,
349-
credentials: getCredentialProvider(),
350-
});
355+
const client = createControlClient(options.region);
351356

352357
const command = new GetMemoryCommand({
353358
memoryId: options.memoryId,
@@ -380,8 +385,8 @@ export async function getMemoryDetail(options: GetMemoryOptions): Promise<Memory
380385
if (tagsResponse.tags && Object.keys(tagsResponse.tags).length > 0) {
381386
tags = tagsResponse.tags;
382387
}
383-
} catch {
384-
// Tags are optional — continue without them if the call fails
388+
} catch (err) {
389+
console.warn(`Warning: Failed to fetch tags for memory: ${err instanceof Error ? err.message : String(err)}`);
385390
}
386391

387392
return {
@@ -429,10 +434,7 @@ export interface GetEvaluatorResult {
429434
}
430435

431436
export async function getEvaluator(options: GetEvaluatorOptions): Promise<GetEvaluatorResult> {
432-
const client = new BedrockAgentCoreControlClient({
433-
region: options.region,
434-
credentials: getCredentialProvider(),
435-
});
437+
const client = createControlClient(options.region);
436438

437439
const command = new GetEvaluatorCommand({
438440
evaluatorId: options.evaluatorId,
@@ -476,10 +478,7 @@ export interface ListEvaluatorsResult {
476478
}
477479

478480
export async function listEvaluators(options: ListEvaluatorsOptions): Promise<ListEvaluatorsResult> {
479-
const client = new BedrockAgentCoreControlClient({
480-
region: options.region,
481-
credentials: getCredentialProvider(),
482-
});
481+
const client = createControlClient(options.region);
483482

484483
const command = new ListEvaluatorsCommand({
485484
maxResults: options.maxResults,
@@ -539,10 +538,7 @@ export async function updateOnlineEvalExecutionStatus(
539538
* Update an online evaluation config with any supported fields.
540539
*/
541540
export async function updateOnlineEvalConfig(options: UpdateOnlineEvalOptions): Promise<UpdateOnlineEvalStatusResult> {
542-
const client = new BedrockAgentCoreControlClient({
543-
region: options.region,
544-
credentials: getCredentialProvider(),
545-
});
541+
const client = createControlClient(options.region);
546542

547543
const command = new UpdateOnlineEvaluationConfigCommand({
548544
onlineEvaluationConfigId: options.onlineEvaluationConfigId,
@@ -577,10 +573,7 @@ export interface GetOnlineEvalConfigResult {
577573
export async function getOnlineEvaluationConfig(
578574
options: GetOnlineEvalConfigOptions
579575
): Promise<GetOnlineEvalConfigResult> {
580-
const client = new BedrockAgentCoreControlClient({
581-
region: options.region,
582-
credentials: getCredentialProvider(),
583-
});
576+
const client = createControlClient(options.region);
584577

585578
const command = new GetOnlineEvaluationConfigCommand({
586579
onlineEvaluationConfigId: options.configId,

src/cli/aws/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export {
99
type ClaudeResponse,
1010
} from './bedrock';
1111
export {
12+
createControlClient,
1213
getAgentRuntimeStatus,
1314
type AgentRuntimeStatusResult,
1415
type GetAgentRuntimeStatusOptions,

0 commit comments

Comments
 (0)