@aws/agentcore 1.0.0-preview.16 → 1.0.0-preview.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -7
- package/dist/agent-inspector/index.css +1 -1
- package/dist/agent-inspector/index.js +60 -60
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +273 -15
- package/dist/assets/cdk/bin/cdk.ts +2 -8
- package/dist/assets/python/http/strands/base/main.py +13 -3
- package/dist/assets/python/http/strands/base/mcp_client/client.py +4 -1
- package/dist/assets/python/http/strands/base/model/load.py +116 -0
- package/dist/assets/python/http/strands/base/model/mantle_compat.py +21 -0
- package/dist/assets/python/http/strands/base/pyproject.toml +3 -0
- package/dist/assets/typescript/http/strands/base/main.ts +48 -0
- package/dist/assets/typescript/http/strands/base/package.json +3 -2
- package/dist/assets/typescript/http/strands/capabilities/memory/memory.ts +52 -0
- package/dist/cli/index.mjs +572 -606
- package/dist/schema/constants.d.ts +3 -2
- package/dist/schema/constants.d.ts.map +1 -1
- package/dist/schema/constants.js +7 -4
- package/dist/schema/constants.js.map +1 -1
- package/dist/schema/schemas/agent-env.d.ts +43 -0
- package/dist/schema/schemas/agent-env.d.ts.map +1 -1
- package/dist/schema/schemas/agent-env.js +11 -0
- package/dist/schema/schemas/agent-env.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +43 -0
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/connections.d.ts +185 -0
- package/dist/schema/schemas/connections.d.ts.map +1 -0
- package/dist/schema/schemas/connections.js +176 -0
- package/dist/schema/schemas/connections.js.map +1 -0
- package/dist/schema/schemas/index.d.ts +1 -0
- package/dist/schema/schemas/index.d.ts.map +1 -1
- package/dist/schema/schemas/index.js +1 -0
- package/dist/schema/schemas/index.js.map +1 -1
- package/dist/schema/schemas/primitives/harness.d.ts +42 -0
- package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/harness.js +4 -0
- package/dist/schema/schemas/primitives/harness.js.map +1 -1
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -3
- package/scripts/bundle.mjs +12 -60
- package/scripts/run-e2e-local.sh +0 -5
|
@@ -124,15 +124,9 @@ async function main() {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
// Harness
|
|
128
|
-
// forwards it to this child process via AGENTCORE_PREVIEW (see toolkit-lib/wrapper.ts).
|
|
129
|
-
// This app is built separately and cannot see that build-time define, so it gates on the
|
|
130
|
-
// env var. Absent/anything-but-'1' defaults to off so a stale harnesses[] entry in a
|
|
131
|
-
// non-preview build never synthesizes an AWS::BedrockAgentCore::Harness resource.
|
|
132
|
-
const previewEnabled = process.env.AGENTCORE_PREVIEW === '1';
|
|
133
|
-
|
|
127
|
+
// Synthesize an AWS::BedrockAgentCore::Harness resource for each harness entry in the spec.
|
|
134
128
|
const harnessConfigs: HarnessConfig[] = [];
|
|
135
|
-
for (const entry of
|
|
129
|
+
for (const entry of specAny.harnesses ?? []) {
|
|
136
130
|
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
137
131
|
const harnessPath = path.resolve(harnessDir, 'harness.json');
|
|
138
132
|
try {
|
|
@@ -837,6 +831,7 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f
|
|
|
837
831
|
"python/http/strands/base/mcp_client/client.py",
|
|
838
832
|
"python/http/strands/base/model/__init__.py",
|
|
839
833
|
"python/http/strands/base/model/load.py",
|
|
834
|
+
"python/http/strands/base/model/mantle_compat.py",
|
|
840
835
|
"python/http/strands/base/pyproject.toml",
|
|
841
836
|
"python/http/strands/base/skills/fetcher.py",
|
|
842
837
|
"python/http/strands/capabilities/execution-limits/hooks/execution_limits.py",
|
|
@@ -856,6 +851,7 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f
|
|
|
856
851
|
"typescript/http/strands/base/model/load.ts",
|
|
857
852
|
"typescript/http/strands/base/package.json",
|
|
858
853
|
"typescript/http/strands/base/tsconfig.json",
|
|
854
|
+
"typescript/http/strands/capabilities/memory/memory.ts",
|
|
859
855
|
"typescript/http/vercelai/base/README.md",
|
|
860
856
|
"typescript/http/vercelai/base/gitignore.template",
|
|
861
857
|
"typescript/http/vercelai/base/main.ts",
|
|
@@ -5282,7 +5278,7 @@ from mcp_client.client import get_streamable_http_mcp_client
|
|
|
5282
5278
|
from memory.session import get_memory_session_manager
|
|
5283
5279
|
{{/if}}
|
|
5284
5280
|
{{#unless hasFileOperations}}
|
|
5285
|
-
{{#if (or needsOs (some gitSkills "credentialArn"))}}
|
|
5281
|
+
{{#if (or needsOs browserIdentifierEnvVar codeInterpreterIdentifierEnvVar (some gitSkills "credentialArn"))}}
|
|
5286
5282
|
import os
|
|
5287
5283
|
{{/if}}
|
|
5288
5284
|
{{/unless}}
|
|
@@ -5368,10 +5364,20 @@ tools.append(add_numbers)
|
|
|
5368
5364
|
{{/unless}}
|
|
5369
5365
|
{{/if}}
|
|
5370
5366
|
{{#if hasBrowser}}
|
|
5371
|
-
|
|
5367
|
+
{{#if browserIdentifierEnvVar}}
|
|
5368
|
+
_browser_id = os.getenv("{{browserIdentifierEnvVar}}")
|
|
5369
|
+
tools.append(AgentCoreBrowser(**({"identifier": _browser_id} if _browser_id else {})).browser)
|
|
5370
|
+
{{else}}
|
|
5371
|
+
tools.append(AgentCoreBrowser().browser)
|
|
5372
|
+
{{/if}}
|
|
5372
5373
|
{{/if}}
|
|
5373
5374
|
{{#if hasCodeInterpreter}}
|
|
5374
|
-
|
|
5375
|
+
{{#if codeInterpreterIdentifierEnvVar}}
|
|
5376
|
+
_code_interpreter_id = os.getenv("{{codeInterpreterIdentifierEnvVar}}")
|
|
5377
|
+
tools.append(AgentCoreCodeInterpreter(**({"identifier": _code_interpreter_id} if _code_interpreter_id else {})).code_interpreter)
|
|
5378
|
+
{{else}}
|
|
5379
|
+
tools.append(AgentCoreCodeInterpreter().code_interpreter)
|
|
5380
|
+
{{/if}}
|
|
5375
5381
|
{{/if}}
|
|
5376
5382
|
{{#if hasShell}}
|
|
5377
5383
|
@tool
|
|
@@ -5914,7 +5920,10 @@ from bedrock_agentcore.identity import requires_access_token
|
|
|
5914
5920
|
@requires_access_token(
|
|
5915
5921
|
provider_name="{{credentialProviderName}}",
|
|
5916
5922
|
scopes=[{{#if scopes}}"{{scopes}}"{{/if}}],
|
|
5917
|
-
auth_flow="M2M",
|
|
5923
|
+
auth_flow="{{#if authFlow}}{{authFlow}}{{else}}M2M{{/if}}",
|
|
5924
|
+
{{#if customParameters}}
|
|
5925
|
+
custom_parameters={{safeJson customParameters}},
|
|
5926
|
+
{{/if}}
|
|
5918
5927
|
)
|
|
5919
5928
|
def _get_bearer_token_{{snakeCase name}}(*, access_token: str):
|
|
5920
5929
|
"""Obtain OAuth access token via AgentCore Identity for {{name}}."""
|
|
@@ -6017,6 +6026,67 @@ exports[`Assets Directory Snapshots > Python framework assets > python/python/ht
|
|
|
6017
6026
|
|
|
6018
6027
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/model/load.py should match snapshot 1`] = `
|
|
6019
6028
|
"{{#if (eq modelProvider "Bedrock")}}
|
|
6029
|
+
{{#if bedrockMantle}}
|
|
6030
|
+
import os
|
|
6031
|
+
|
|
6032
|
+
from aws_bedrock_token_generator import provide_token
|
|
6033
|
+
{{#if (eq mantleApiFormat "chat_completions")}}
|
|
6034
|
+
from strands.models.openai import OpenAIModel
|
|
6035
|
+
{{else}}
|
|
6036
|
+
{{#if mantleProprietary}}
|
|
6037
|
+
from strands.models.openai_responses import OpenAIResponsesModel
|
|
6038
|
+
{{else}}
|
|
6039
|
+
from model.mantle_compat import MantleCompatResponsesModel
|
|
6040
|
+
{{/if}}
|
|
6041
|
+
{{/if}}
|
|
6042
|
+
|
|
6043
|
+
MODEL_ID = "{{modelId}}"
|
|
6044
|
+
|
|
6045
|
+
|
|
6046
|
+
def load_model():
|
|
6047
|
+
"""
|
|
6048
|
+
Get a Bedrock Mantle model client. These OpenAI-compatible models (e.g. openai.gpt-5.5,
|
|
6049
|
+
openai.gpt-oss-120b) are served via the Bedrock Mantle endpoint, NOT the Converse API — so they
|
|
6050
|
+
are invoked through an OpenAI-style client authenticated with a short-lived Bedrock bearer token.
|
|
6051
|
+
Region is read from AWS_REGION (set by the AgentCore runtime).
|
|
6052
|
+
"""
|
|
6053
|
+
region = os.environ.get("AWS_REGION", os.environ.get("AWS_DEFAULT_REGION", "us-east-1"))
|
|
6054
|
+
token = provide_token(region=region)
|
|
6055
|
+
{{#if mantleProprietary}}
|
|
6056
|
+
# Proprietary OpenAI models only work on the /openai/v1 Mantle path.
|
|
6057
|
+
base_url = f"https://bedrock-mantle.{region}.api.aws/openai/v1"
|
|
6058
|
+
{{else}}
|
|
6059
|
+
# Open-source OpenAI models (gpt-oss-*) only work on the /v1 Mantle path.
|
|
6060
|
+
base_url = f"https://bedrock-mantle.{region}.api.aws/v1"
|
|
6061
|
+
{{/if}}
|
|
6062
|
+
client_args = {"api_key": token, "base_url": base_url}
|
|
6063
|
+
|
|
6064
|
+
params = {}
|
|
6065
|
+
{{#if modelMaxTokens}}
|
|
6066
|
+
{{#if (eq mantleApiFormat "chat_completions")}}
|
|
6067
|
+
params["max_completion_tokens"] = {{modelMaxTokens}}
|
|
6068
|
+
{{else}}
|
|
6069
|
+
params["max_output_tokens"] = {{modelMaxTokens}}
|
|
6070
|
+
{{/if}}
|
|
6071
|
+
{{/if}}
|
|
6072
|
+
{{#if modelTemperature}}
|
|
6073
|
+
params["temperature"] = {{modelTemperature}}
|
|
6074
|
+
{{/if}}
|
|
6075
|
+
{{#if modelTopP}}
|
|
6076
|
+
params["top_p"] = {{modelTopP}}
|
|
6077
|
+
{{/if}}
|
|
6078
|
+
{{#if (eq mantleApiFormat "chat_completions")}}
|
|
6079
|
+
return OpenAIModel(client_args=client_args, model_id=MODEL_ID, params=params)
|
|
6080
|
+
{{else}}
|
|
6081
|
+
# Responses API: Mantle does not persist responses, so disable server-side storage.
|
|
6082
|
+
params["store"] = False
|
|
6083
|
+
{{#if mantleProprietary}}
|
|
6084
|
+
return OpenAIResponsesModel(client_args=client_args, model_id=MODEL_ID, params=params)
|
|
6085
|
+
{{else}}
|
|
6086
|
+
return MantleCompatResponsesModel(client_args=client_args, model_id=MODEL_ID, params=params)
|
|
6087
|
+
{{/if}}
|
|
6088
|
+
{{/if}}
|
|
6089
|
+
{{else}}
|
|
6020
6090
|
from strands.models.bedrock import BedrockModel
|
|
6021
6091
|
|
|
6022
6092
|
|
|
@@ -6024,6 +6094,7 @@ def load_model() -> BedrockModel:
|
|
|
6024
6094
|
"""Get Bedrock model client using IAM credentials."""
|
|
6025
6095
|
return BedrockModel(model_id="{{#if modelId}}{{modelId}}{{else}}global.anthropic.claude-sonnet-4-5-20250929-v1:0{{/if}}")
|
|
6026
6096
|
{{/if}}
|
|
6097
|
+
{{/if}}
|
|
6027
6098
|
{{#if (eq modelProvider "Anthropic")}}
|
|
6028
6099
|
import os
|
|
6029
6100
|
|
|
@@ -6139,6 +6210,85 @@ def load_model() -> GeminiModel:
|
|
|
6139
6210
|
model_id="{{#if modelId}}{{modelId}}{{else}}gemini-2.5-flash{{/if}}",
|
|
6140
6211
|
)
|
|
6141
6212
|
{{/if}}
|
|
6213
|
+
{{#if (eq modelProvider "LiteLLM")}}
|
|
6214
|
+
import os
|
|
6215
|
+
{{#if litellmAdditionalParams}}
|
|
6216
|
+
import json
|
|
6217
|
+
{{/if}}
|
|
6218
|
+
|
|
6219
|
+
from strands.models.litellm import LiteLLMModel
|
|
6220
|
+
{{#if identityProviders.[0].name}}
|
|
6221
|
+
from bedrock_agentcore.identity.auth import requires_api_key
|
|
6222
|
+
|
|
6223
|
+
IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
|
|
6224
|
+
IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
|
|
6225
|
+
|
|
6226
|
+
|
|
6227
|
+
@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
|
|
6228
|
+
def _agentcore_identity_api_key_provider(api_key: str) -> str:
|
|
6229
|
+
"""Fetch API key from AgentCore Identity."""
|
|
6230
|
+
return api_key
|
|
6231
|
+
|
|
6232
|
+
|
|
6233
|
+
def _get_api_key() -> str:
|
|
6234
|
+
"""
|
|
6235
|
+
Uses AgentCore Identity for API key management in deployed environments.
|
|
6236
|
+
For local development, run via 'agentcore dev' which loads agentcore/.env.
|
|
6237
|
+
"""
|
|
6238
|
+
if os.getenv("LOCAL_DEV") == "1":
|
|
6239
|
+
api_key = os.getenv(IDENTITY_ENV_VAR)
|
|
6240
|
+
if not api_key:
|
|
6241
|
+
raise RuntimeError(
|
|
6242
|
+
f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
|
|
6243
|
+
)
|
|
6244
|
+
return api_key
|
|
6245
|
+
return _agentcore_identity_api_key_provider()
|
|
6246
|
+
{{/if}}
|
|
6247
|
+
|
|
6248
|
+
|
|
6249
|
+
|
|
6250
|
+
|
|
6251
|
+
def load_model() -> LiteLLMModel:
|
|
6252
|
+
"""Get a LiteLLM model client (proxies to the provider encoded in model_id)."""
|
|
6253
|
+
client_args = {}
|
|
6254
|
+
{{#if identityProviders.[0].name}}
|
|
6255
|
+
client_args["api_key"] = _get_api_key()
|
|
6256
|
+
{{/if}}
|
|
6257
|
+
{{#if litellmApiBase}}
|
|
6258
|
+
client_args["api_base"] = {{safeJson litellmApiBase}}
|
|
6259
|
+
{{/if}}
|
|
6260
|
+
params = {{#if litellmAdditionalParams}}json.loads({{pyJsonStr litellmAdditionalParams}}){{else}}{}{{/if}}
|
|
6261
|
+
return LiteLLMModel(
|
|
6262
|
+
client_args=client_args,
|
|
6263
|
+
model_id="{{#if modelId}}{{modelId}}{{else}}bedrock/us.anthropic.claude-sonnet-4-5-20250514-v1:0{{/if}}",
|
|
6264
|
+
params=params,
|
|
6265
|
+
)
|
|
6266
|
+
{{/if}}
|
|
6267
|
+
"
|
|
6268
|
+
`;
|
|
6269
|
+
|
|
6270
|
+
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/model/mantle_compat.py should match snapshot 1`] = `
|
|
6271
|
+
"from strands.models.openai_responses import OpenAIResponsesModel
|
|
6272
|
+
|
|
6273
|
+
|
|
6274
|
+
class MantleCompatResponsesModel(OpenAIResponsesModel):
|
|
6275
|
+
"""Workaround for Bedrock Mantle rejecting output_text in EasyInputMessage content arrays.
|
|
6276
|
+
|
|
6277
|
+
Mantle's Pydantic validation only accepts content as a plain string for assistant messages, while
|
|
6278
|
+
real OpenAI accepts both formats. Flatten assistant content arrays to strings so multi-turn works.
|
|
6279
|
+
Used for open-source OpenAI models (gpt-oss-*) on the /v1 Mantle path; proprietary models use the
|
|
6280
|
+
plain OpenAIResponsesModel on /openai/v1.
|
|
6281
|
+
"""
|
|
6282
|
+
|
|
6283
|
+
@classmethod
|
|
6284
|
+
def _format_request_messages(cls, messages):
|
|
6285
|
+
formatted = super()._format_request_messages(messages)
|
|
6286
|
+
for msg in formatted:
|
|
6287
|
+
if msg.get("role") == "assistant" and isinstance(msg.get("content"), list):
|
|
6288
|
+
msg["content"] = "".join(
|
|
6289
|
+
part.get("text", "") for part in msg["content"] if part.get("type") == "output_text"
|
|
6290
|
+
)
|
|
6291
|
+
return formatted
|
|
6142
6292
|
"
|
|
6143
6293
|
`;
|
|
6144
6294
|
|
|
@@ -6161,6 +6311,9 @@ dependencies = [
|
|
|
6161
6311
|
{{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0",
|
|
6162
6312
|
{{/if}}"mcp >= 1.19.0",
|
|
6163
6313
|
{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0",
|
|
6314
|
+
{{/if}}{{#if (eq modelProvider "LiteLLM")}}"litellm >= 1.0.0",
|
|
6315
|
+
{{/if}}{{#if bedrockMantle}}"openai >= 1.0.0",
|
|
6316
|
+
"aws-bedrock-token-generator >= 1.0.0",
|
|
6164
6317
|
{{/if}}"strands-agents >= 1.15.0",
|
|
6165
6318
|
{{#if (or hasBrowser hasCodeInterpreter)}}"strands-agents-tools >= 0.1.0",
|
|
6166
6319
|
{{/if}}{{#if hasBrowser}}"nest-asyncio >= 1.5.0",
|
|
@@ -7385,6 +7538,9 @@ import { Agent, McpClient, tool, type ToolList } from '@strands-agents/sdk';
|
|
|
7385
7538
|
import { z } from 'zod';
|
|
7386
7539
|
import { loadModel } from './model/load.js';
|
|
7387
7540
|
import { getStreamableHttpMcpClient } from './mcp_client/client.js';
|
|
7541
|
+
{{#if hasMemory}}
|
|
7542
|
+
import { getActorId, getOrCreateMemoryManager } from './memory/memory.js';
|
|
7543
|
+
{{/if}}
|
|
7388
7544
|
|
|
7389
7545
|
// Define a collection of MCP clients (filter out anything that failed to initialize)
|
|
7390
7546
|
const mcpClients: McpClient[] = [getStreamableHttpMcpClient()].filter(
|
|
@@ -7413,6 +7569,25 @@ const SYSTEM_PROMPT = \`
|
|
|
7413
7569
|
You are a helpful assistant. Use tools when appropriate.
|
|
7414
7570
|
\`;
|
|
7415
7571
|
|
|
7572
|
+
{{#if hasMemory}}
|
|
7573
|
+
const agentCache = new Map<string, Agent>();
|
|
7574
|
+
|
|
7575
|
+
async function getOrCreateAgent(sessionId: string, actorId: string): Promise<Agent> {
|
|
7576
|
+
const key = \`\${actorId}:\${sessionId}\`;
|
|
7577
|
+
let agent = agentCache.get(key);
|
|
7578
|
+
if (agent) return agent;
|
|
7579
|
+
|
|
7580
|
+
const model = await loadModel();
|
|
7581
|
+
agent = new Agent({
|
|
7582
|
+
model,
|
|
7583
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
7584
|
+
tools,
|
|
7585
|
+
memoryManager: getOrCreateMemoryManager(sessionId, actorId) ?? undefined,
|
|
7586
|
+
});
|
|
7587
|
+
agentCache.set(key, agent);
|
|
7588
|
+
return agent;
|
|
7589
|
+
}
|
|
7590
|
+
{{else}}
|
|
7416
7591
|
let cachedAgent: Agent | null = null;
|
|
7417
7592
|
|
|
7418
7593
|
async function getOrCreateAgent(): Promise<Agent> {
|
|
@@ -7426,12 +7601,37 @@ async function getOrCreateAgent(): Promise<Agent> {
|
|
|
7426
7601
|
}
|
|
7427
7602
|
return cachedAgent;
|
|
7428
7603
|
}
|
|
7604
|
+
{{/if}}
|
|
7429
7605
|
|
|
7430
7606
|
const app = new BedrockAgentCoreApp({
|
|
7431
7607
|
invocationHandler: {
|
|
7432
7608
|
async *process(payload: any, context: any) {
|
|
7609
|
+
{{#if hasMemory}}
|
|
7610
|
+
const sessionId = context?.sessionId ?? 'default-session';
|
|
7611
|
+
const actorId = getActorId(payload, context);
|
|
7612
|
+
const agent = await getOrCreateAgent(sessionId, actorId);
|
|
7613
|
+
{{else}}
|
|
7433
7614
|
const agent = await getOrCreateAgent();
|
|
7434
|
-
|
|
7615
|
+
{{/if}}
|
|
7616
|
+
|
|
7617
|
+
{{#if hasMemory}}
|
|
7618
|
+
try {
|
|
7619
|
+
for await (const event of agent.stream(payload.prompt ?? '')) {
|
|
7620
|
+
if (
|
|
7621
|
+
event.type === 'modelStreamUpdateEvent' &&
|
|
7622
|
+
event.event?.type === 'modelContentBlockDeltaEvent' &&
|
|
7623
|
+
event.event.delta?.type === 'textDelta'
|
|
7624
|
+
) {
|
|
7625
|
+
yield { data: event.event.delta.text };
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7628
|
+
} finally {
|
|
7629
|
+
// Drain in-flight createEvent calls before the runtime can reclaim
|
|
7630
|
+
// the session microVM. flush() is the durability mechanism — without
|
|
7631
|
+
// it, an idle reclamation can lose the tail of the conversation.
|
|
7632
|
+
await agent.memoryManager?.flush();
|
|
7633
|
+
}
|
|
7634
|
+
{{else}}
|
|
7435
7635
|
for await (const event of agent.stream(payload.prompt ?? '')) {
|
|
7436
7636
|
if (
|
|
7437
7637
|
event.type === 'modelStreamUpdateEvent' &&
|
|
@@ -7441,6 +7641,7 @@ const app = new BedrockAgentCoreApp({
|
|
|
7441
7641
|
yield { data: event.event.delta.text };
|
|
7442
7642
|
}
|
|
7443
7643
|
}
|
|
7644
|
+
{{/if}}
|
|
7444
7645
|
},
|
|
7445
7646
|
},
|
|
7446
7647
|
});
|
|
@@ -7593,8 +7794,9 @@ exports[`Assets Directory Snapshots > TypeScript assets > typescript/typescript/
|
|
|
7593
7794
|
"@google/genai": "^1.40.0",
|
|
7594
7795
|
{{/if}}
|
|
7595
7796
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
7596
|
-
"@
|
|
7597
|
-
"
|
|
7797
|
+
"@opentelemetry/api": "^1.9.0",
|
|
7798
|
+
"@strands-agents/sdk": "^1.5.0",
|
|
7799
|
+
"bedrock-agentcore": "^0.3.0",
|
|
7598
7800
|
"tsx": "^4.19.0",
|
|
7599
7801
|
"zod": "^4.4.3"
|
|
7600
7802
|
},
|
|
@@ -7634,6 +7836,62 @@ exports[`Assets Directory Snapshots > TypeScript assets > typescript/typescript/
|
|
|
7634
7836
|
"
|
|
7635
7837
|
`;
|
|
7636
7838
|
|
|
7839
|
+
exports[`Assets Directory Snapshots > TypeScript assets > typescript/typescript/http/strands/capabilities/memory/memory.ts should match snapshot 1`] = `
|
|
7840
|
+
"import { randomUUID } from 'node:crypto';
|
|
7841
|
+
import { MemoryManager } from '@strands-agents/sdk';
|
|
7842
|
+
import { createAgentCoreMemoryStores } from 'bedrock-agentcore/experimental/memory/strands';
|
|
7843
|
+
|
|
7844
|
+
const MEMORY_ID = process.env.{{memoryProviders.[0].envVarName}};
|
|
7845
|
+
|
|
7846
|
+
const CUSTOM_ACTOR_ID_HEADER = 'x-amzn-bedrock-agentcore-runtime-custom-actor-id';
|
|
7847
|
+
|
|
7848
|
+
export function getActorId(payload: any, context: any): string {
|
|
7849
|
+
const raw =
|
|
7850
|
+
context?.headers?.[CUSTOM_ACTOR_ID_HEADER] ||
|
|
7851
|
+
payload?.userId ||
|
|
7852
|
+
context?.sessionId;
|
|
7853
|
+
return typeof raw === 'string' && raw.trim().length > 0 ? raw.trim() : randomUUID();
|
|
7854
|
+
}
|
|
7855
|
+
|
|
7856
|
+
const memoryManagerCache = new Map<string, MemoryManager>();
|
|
7857
|
+
|
|
7858
|
+
export function getOrCreateMemoryManager(sessionId: string, actorId: string): MemoryManager | null {
|
|
7859
|
+
if (!MEMORY_ID) return null;
|
|
7860
|
+
|
|
7861
|
+
const key = \`\${actorId}:\${sessionId}\`;
|
|
7862
|
+
let manager = memoryManagerCache.get(key);
|
|
7863
|
+
if (manager) return manager;
|
|
7864
|
+
|
|
7865
|
+
const stores = createAgentCoreMemoryStores({
|
|
7866
|
+
memoryId: MEMORY_ID,
|
|
7867
|
+
actorId,
|
|
7868
|
+
sessionId,
|
|
7869
|
+
namespaces: [
|
|
7870
|
+
{{#if (includes memoryProviders.[0].strategies "SEMANTIC")}}
|
|
7871
|
+
{ namespace: '/users/{actorId}/facts' },
|
|
7872
|
+
{{/if}}
|
|
7873
|
+
{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}}
|
|
7874
|
+
{ namespace: '/users/{actorId}/preferences' },
|
|
7875
|
+
{{/if}}
|
|
7876
|
+
{{#if (includes memoryProviders.[0].strategies "EPISODIC")}}
|
|
7877
|
+
{ namespace: '/episodes/{actorId}/{sessionId}' },
|
|
7878
|
+
{{/if}}
|
|
7879
|
+
{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}}
|
|
7880
|
+
{ namespace: '/summaries/{actorId}/{sessionId}' },
|
|
7881
|
+
{{/if}}
|
|
7882
|
+
],
|
|
7883
|
+
// readMode defaults to 'per-namespace' (one retrieve call per namespace).
|
|
7884
|
+
// Switch to 'subtree' to consolidate to a single hierarchical recall call.
|
|
7885
|
+
extraction: true,
|
|
7886
|
+
});
|
|
7887
|
+
|
|
7888
|
+
manager = new MemoryManager({ stores });
|
|
7889
|
+
memoryManagerCache.set(key, manager);
|
|
7890
|
+
return manager;
|
|
7891
|
+
}
|
|
7892
|
+
"
|
|
7893
|
+
`;
|
|
7894
|
+
|
|
7637
7895
|
exports[`Assets Directory Snapshots > TypeScript assets > typescript/typescript/http/vercelai/base/README.md should match snapshot 1`] = `
|
|
7638
7896
|
"This is a project generated by the AgentCore CLI!
|
|
7639
7897
|
|
|
@@ -79,15 +79,9 @@ async function main() {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
// Harness
|
|
83
|
-
// forwards it to this child process via AGENTCORE_PREVIEW (see toolkit-lib/wrapper.ts).
|
|
84
|
-
// This app is built separately and cannot see that build-time define, so it gates on the
|
|
85
|
-
// env var. Absent/anything-but-'1' defaults to off so a stale harnesses[] entry in a
|
|
86
|
-
// non-preview build never synthesizes an AWS::BedrockAgentCore::Harness resource.
|
|
87
|
-
const previewEnabled = process.env.AGENTCORE_PREVIEW === '1';
|
|
88
|
-
|
|
82
|
+
// Synthesize an AWS::BedrockAgentCore::Harness resource for each harness entry in the spec.
|
|
89
83
|
const harnessConfigs: HarnessConfig[] = [];
|
|
90
|
-
for (const entry of
|
|
84
|
+
for (const entry of specAny.harnesses ?? []) {
|
|
91
85
|
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
92
86
|
const harnessPath = path.resolve(harnessDir, 'harness.json');
|
|
93
87
|
try {
|
|
@@ -66,7 +66,7 @@ from mcp_client.client import get_streamable_http_mcp_client
|
|
|
66
66
|
from memory.session import get_memory_session_manager
|
|
67
67
|
{{/if}}
|
|
68
68
|
{{#unless hasFileOperations}}
|
|
69
|
-
{{#if (or needsOs (some gitSkills "credentialArn"))}}
|
|
69
|
+
{{#if (or needsOs browserIdentifierEnvVar codeInterpreterIdentifierEnvVar (some gitSkills "credentialArn"))}}
|
|
70
70
|
import os
|
|
71
71
|
{{/if}}
|
|
72
72
|
{{/unless}}
|
|
@@ -152,10 +152,20 @@ tools.append(add_numbers)
|
|
|
152
152
|
{{/unless}}
|
|
153
153
|
{{/if}}
|
|
154
154
|
{{#if hasBrowser}}
|
|
155
|
-
|
|
155
|
+
{{#if browserIdentifierEnvVar}}
|
|
156
|
+
_browser_id = os.getenv("{{browserIdentifierEnvVar}}")
|
|
157
|
+
tools.append(AgentCoreBrowser(**({"identifier": _browser_id} if _browser_id else {})).browser)
|
|
158
|
+
{{else}}
|
|
159
|
+
tools.append(AgentCoreBrowser().browser)
|
|
160
|
+
{{/if}}
|
|
156
161
|
{{/if}}
|
|
157
162
|
{{#if hasCodeInterpreter}}
|
|
158
|
-
|
|
163
|
+
{{#if codeInterpreterIdentifierEnvVar}}
|
|
164
|
+
_code_interpreter_id = os.getenv("{{codeInterpreterIdentifierEnvVar}}")
|
|
165
|
+
tools.append(AgentCoreCodeInterpreter(**({"identifier": _code_interpreter_id} if _code_interpreter_id else {})).code_interpreter)
|
|
166
|
+
{{else}}
|
|
167
|
+
tools.append(AgentCoreCodeInterpreter().code_interpreter)
|
|
168
|
+
{{/if}}
|
|
159
169
|
{{/if}}
|
|
160
170
|
{{#if hasShell}}
|
|
161
171
|
@tool
|
|
@@ -18,7 +18,10 @@ from bedrock_agentcore.identity import requires_access_token
|
|
|
18
18
|
@requires_access_token(
|
|
19
19
|
provider_name="{{credentialProviderName}}",
|
|
20
20
|
scopes=[{{#if scopes}}"{{scopes}}"{{/if}}],
|
|
21
|
-
auth_flow="M2M",
|
|
21
|
+
auth_flow="{{#if authFlow}}{{authFlow}}{{else}}M2M{{/if}}",
|
|
22
|
+
{{#if customParameters}}
|
|
23
|
+
custom_parameters={{safeJson customParameters}},
|
|
24
|
+
{{/if}}
|
|
22
25
|
)
|
|
23
26
|
def _get_bearer_token_{{snakeCase name}}(*, access_token: str):
|
|
24
27
|
"""Obtain OAuth access token via AgentCore Identity for {{name}}."""
|
|
@@ -1,4 +1,65 @@
|
|
|
1
1
|
{{#if (eq modelProvider "Bedrock")}}
|
|
2
|
+
{{#if bedrockMantle}}
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from aws_bedrock_token_generator import provide_token
|
|
6
|
+
{{#if (eq mantleApiFormat "chat_completions")}}
|
|
7
|
+
from strands.models.openai import OpenAIModel
|
|
8
|
+
{{else}}
|
|
9
|
+
{{#if mantleProprietary}}
|
|
10
|
+
from strands.models.openai_responses import OpenAIResponsesModel
|
|
11
|
+
{{else}}
|
|
12
|
+
from model.mantle_compat import MantleCompatResponsesModel
|
|
13
|
+
{{/if}}
|
|
14
|
+
{{/if}}
|
|
15
|
+
|
|
16
|
+
MODEL_ID = "{{modelId}}"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def load_model():
|
|
20
|
+
"""
|
|
21
|
+
Get a Bedrock Mantle model client. These OpenAI-compatible models (e.g. openai.gpt-5.5,
|
|
22
|
+
openai.gpt-oss-120b) are served via the Bedrock Mantle endpoint, NOT the Converse API — so they
|
|
23
|
+
are invoked through an OpenAI-style client authenticated with a short-lived Bedrock bearer token.
|
|
24
|
+
Region is read from AWS_REGION (set by the AgentCore runtime).
|
|
25
|
+
"""
|
|
26
|
+
region = os.environ.get("AWS_REGION", os.environ.get("AWS_DEFAULT_REGION", "us-east-1"))
|
|
27
|
+
token = provide_token(region=region)
|
|
28
|
+
{{#if mantleProprietary}}
|
|
29
|
+
# Proprietary OpenAI models only work on the /openai/v1 Mantle path.
|
|
30
|
+
base_url = f"https://bedrock-mantle.{region}.api.aws/openai/v1"
|
|
31
|
+
{{else}}
|
|
32
|
+
# Open-source OpenAI models (gpt-oss-*) only work on the /v1 Mantle path.
|
|
33
|
+
base_url = f"https://bedrock-mantle.{region}.api.aws/v1"
|
|
34
|
+
{{/if}}
|
|
35
|
+
client_args = {"api_key": token, "base_url": base_url}
|
|
36
|
+
|
|
37
|
+
params = {}
|
|
38
|
+
{{#if modelMaxTokens}}
|
|
39
|
+
{{#if (eq mantleApiFormat "chat_completions")}}
|
|
40
|
+
params["max_completion_tokens"] = {{modelMaxTokens}}
|
|
41
|
+
{{else}}
|
|
42
|
+
params["max_output_tokens"] = {{modelMaxTokens}}
|
|
43
|
+
{{/if}}
|
|
44
|
+
{{/if}}
|
|
45
|
+
{{#if modelTemperature}}
|
|
46
|
+
params["temperature"] = {{modelTemperature}}
|
|
47
|
+
{{/if}}
|
|
48
|
+
{{#if modelTopP}}
|
|
49
|
+
params["top_p"] = {{modelTopP}}
|
|
50
|
+
{{/if}}
|
|
51
|
+
{{#if (eq mantleApiFormat "chat_completions")}}
|
|
52
|
+
return OpenAIModel(client_args=client_args, model_id=MODEL_ID, params=params)
|
|
53
|
+
{{else}}
|
|
54
|
+
# Responses API: Mantle does not persist responses, so disable server-side storage.
|
|
55
|
+
params["store"] = False
|
|
56
|
+
{{#if mantleProprietary}}
|
|
57
|
+
return OpenAIResponsesModel(client_args=client_args, model_id=MODEL_ID, params=params)
|
|
58
|
+
{{else}}
|
|
59
|
+
return MantleCompatResponsesModel(client_args=client_args, model_id=MODEL_ID, params=params)
|
|
60
|
+
{{/if}}
|
|
61
|
+
{{/if}}
|
|
62
|
+
{{else}}
|
|
2
63
|
from strands.models.bedrock import BedrockModel
|
|
3
64
|
|
|
4
65
|
|
|
@@ -6,6 +67,7 @@ def load_model() -> BedrockModel:
|
|
|
6
67
|
"""Get Bedrock model client using IAM credentials."""
|
|
7
68
|
return BedrockModel(model_id="{{#if modelId}}{{modelId}}{{else}}global.anthropic.claude-sonnet-4-5-20250929-v1:0{{/if}}")
|
|
8
69
|
{{/if}}
|
|
70
|
+
{{/if}}
|
|
9
71
|
{{#if (eq modelProvider "Anthropic")}}
|
|
10
72
|
import os
|
|
11
73
|
|
|
@@ -121,3 +183,57 @@ def load_model() -> GeminiModel:
|
|
|
121
183
|
model_id="{{#if modelId}}{{modelId}}{{else}}gemini-2.5-flash{{/if}}",
|
|
122
184
|
)
|
|
123
185
|
{{/if}}
|
|
186
|
+
{{#if (eq modelProvider "LiteLLM")}}
|
|
187
|
+
import os
|
|
188
|
+
{{#if litellmAdditionalParams}}
|
|
189
|
+
import json
|
|
190
|
+
{{/if}}
|
|
191
|
+
|
|
192
|
+
from strands.models.litellm import LiteLLMModel
|
|
193
|
+
{{#if identityProviders.[0].name}}
|
|
194
|
+
from bedrock_agentcore.identity.auth import requires_api_key
|
|
195
|
+
|
|
196
|
+
IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
|
|
197
|
+
IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
|
|
201
|
+
def _agentcore_identity_api_key_provider(api_key: str) -> str:
|
|
202
|
+
"""Fetch API key from AgentCore Identity."""
|
|
203
|
+
return api_key
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _get_api_key() -> str:
|
|
207
|
+
"""
|
|
208
|
+
Uses AgentCore Identity for API key management in deployed environments.
|
|
209
|
+
For local development, run via 'agentcore dev' which loads agentcore/.env.
|
|
210
|
+
"""
|
|
211
|
+
if os.getenv("LOCAL_DEV") == "1":
|
|
212
|
+
api_key = os.getenv(IDENTITY_ENV_VAR)
|
|
213
|
+
if not api_key:
|
|
214
|
+
raise RuntimeError(
|
|
215
|
+
f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
|
|
216
|
+
)
|
|
217
|
+
return api_key
|
|
218
|
+
return _agentcore_identity_api_key_provider()
|
|
219
|
+
{{/if}}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def load_model() -> LiteLLMModel:
|
|
225
|
+
"""Get a LiteLLM model client (proxies to the provider encoded in model_id)."""
|
|
226
|
+
client_args = {}
|
|
227
|
+
{{#if identityProviders.[0].name}}
|
|
228
|
+
client_args["api_key"] = _get_api_key()
|
|
229
|
+
{{/if}}
|
|
230
|
+
{{#if litellmApiBase}}
|
|
231
|
+
client_args["api_base"] = {{safeJson litellmApiBase}}
|
|
232
|
+
{{/if}}
|
|
233
|
+
params = {{#if litellmAdditionalParams}}json.loads({{pyJsonStr litellmAdditionalParams}}){{else}}{}{{/if}}
|
|
234
|
+
return LiteLLMModel(
|
|
235
|
+
client_args=client_args,
|
|
236
|
+
model_id="{{#if modelId}}{{modelId}}{{else}}bedrock/us.anthropic.claude-sonnet-4-5-20250514-v1:0{{/if}}",
|
|
237
|
+
params=params,
|
|
238
|
+
)
|
|
239
|
+
{{/if}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from strands.models.openai_responses import OpenAIResponsesModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MantleCompatResponsesModel(OpenAIResponsesModel):
|
|
5
|
+
"""Workaround for Bedrock Mantle rejecting output_text in EasyInputMessage content arrays.
|
|
6
|
+
|
|
7
|
+
Mantle's Pydantic validation only accepts content as a plain string for assistant messages, while
|
|
8
|
+
real OpenAI accepts both formats. Flatten assistant content arrays to strings so multi-turn works.
|
|
9
|
+
Used for open-source OpenAI models (gpt-oss-*) on the /v1 Mantle path; proprietary models use the
|
|
10
|
+
plain OpenAIResponsesModel on /openai/v1.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _format_request_messages(cls, messages):
|
|
15
|
+
formatted = super()._format_request_messages(messages)
|
|
16
|
+
for msg in formatted:
|
|
17
|
+
if msg.get("role") == "assistant" and isinstance(msg.get("content"), list):
|
|
18
|
+
msg["content"] = "".join(
|
|
19
|
+
part.get("text", "") for part in msg["content"] if part.get("type") == "output_text"
|
|
20
|
+
)
|
|
21
|
+
return formatted
|
|
@@ -16,6 +16,9 @@ dependencies = [
|
|
|
16
16
|
{{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0",
|
|
17
17
|
{{/if}}"mcp >= 1.19.0",
|
|
18
18
|
{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0",
|
|
19
|
+
{{/if}}{{#if (eq modelProvider "LiteLLM")}}"litellm >= 1.0.0",
|
|
20
|
+
{{/if}}{{#if bedrockMantle}}"openai >= 1.0.0",
|
|
21
|
+
"aws-bedrock-token-generator >= 1.0.0",
|
|
19
22
|
{{/if}}"strands-agents >= 1.15.0",
|
|
20
23
|
{{#if (or hasBrowser hasCodeInterpreter)}}"strands-agents-tools >= 0.1.0",
|
|
21
24
|
{{/if}}{{#if hasBrowser}}"nest-asyncio >= 1.5.0",
|