@aws/agentcore 0.25.0 → 0.27.0
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/dist/assets/README.md +6 -2
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +119 -16
- package/dist/assets/__tests__/input-validation.test.ts +44 -0
- package/dist/assets/agents/AGENTS.md +4 -4
- package/dist/assets/evaluators/autoevals-lambda/execution-role-policy.json +15 -0
- package/dist/assets/evaluators/autoevals-lambda/lambda_function.py +37 -0
- package/dist/assets/evaluators/autoevals-lambda/pyproject.toml +22 -0
- package/dist/assets/evaluators/deepeval-lambda/execution-role-policy.json +15 -0
- package/dist/assets/evaluators/deepeval-lambda/lambda_function.py +29 -0
- package/dist/assets/evaluators/deepeval-lambda/pyproject.toml +19 -0
- package/dist/assets/python/http/autogen/base/README.md +5 -0
- package/dist/assets/python/http/autogen/base/main.py +2 -0
- package/dist/assets/python/http/googleadk/base/README.md +5 -0
- package/dist/assets/python/http/googleadk/base/main.py +2 -0
- package/dist/assets/python/http/langchain_langgraph/base/README.md +5 -0
- package/dist/assets/python/http/langchain_langgraph/base/main.py +4 -0
- package/dist/assets/python/http/openaiagents/base/README.md +5 -0
- package/dist/assets/python/http/openaiagents/base/main.py +2 -0
- package/dist/assets/python/http/strands/base/README.md +6 -0
- package/dist/assets/python/http/strands/base/main.py +40 -4
- package/dist/assets/typescript/http/strands/base/README.md +5 -0
- package/dist/assets/typescript/http/strands/base/main.ts +8 -3
- package/dist/assets/typescript/http/vercelai/base/README.md +5 -0
- package/dist/assets/typescript/http/vercelai/base/main.ts +8 -2
- package/dist/cli/index.mjs +1010 -858
- package/dist/lib/schemas/io/config-io.d.ts +6 -0
- package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
- package/dist/lib/schemas/io/config-io.js +68 -2
- package/dist/lib/schemas/io/config-io.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +8 -0
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/index.d.ts +2 -0
- package/dist/schema/schemas/index.d.ts.map +1 -1
- package/dist/schema/schemas/index.js +4 -0
- package/dist/schema/schemas/index.js.map +1 -1
- package/dist/schema/schemas/primitives/evaluator.d.ts +14 -0
- package/dist/schema/schemas/primitives/evaluator.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/evaluator.js +12 -3
- package/dist/schema/schemas/primitives/evaluator.js.map +1 -1
- package/dist/schema/schemas/primitives/index.d.ts +2 -2
- package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/index.js +4 -2
- package/dist/schema/schemas/primitives/index.js.map +1 -1
- package/npm-shrinkwrap.json +201 -253
- package/package.json +11 -8
package/dist/assets/README.md
CHANGED
|
@@ -13,8 +13,7 @@ my-project/
|
|
|
13
13
|
│ ├── .env.local # Secrets — API keys (gitignored)
|
|
14
14
|
│ ├── .llm-context/ # TypeScript type definitions for AI assistants
|
|
15
15
|
│ │ ├── agentcore.ts # AgentCoreProjectSpec types
|
|
16
|
-
│ │
|
|
17
|
-
│ │ └── mcp.ts # Gateway and MCP tool types
|
|
16
|
+
│ │ └── aws-targets.ts # Deployment target types
|
|
18
17
|
│ └── cdk/ # CDK infrastructure (@aws/agentcore-cdk)
|
|
19
18
|
├── app/ # Agent application code
|
|
20
19
|
└── evaluators/ # Custom evaluator code (if any)
|
|
@@ -37,6 +36,11 @@ Run your agent locally:
|
|
|
37
36
|
agentcore dev
|
|
38
37
|
```
|
|
39
38
|
|
|
39
|
+
### Validate Invocation Input
|
|
40
|
+
|
|
41
|
+
Validate runtime invocation payloads before forwarding them to an agent framework. Keep user prompts typed as strings
|
|
42
|
+
and pass only prompt text to the agent.
|
|
43
|
+
|
|
40
44
|
### Deployment
|
|
41
45
|
|
|
42
46
|
Deploy to AWS:
|
|
@@ -742,6 +742,12 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f
|
|
|
742
742
|
"container/typescript/dockerignore.template",
|
|
743
743
|
"datasets/predefined-v1.jsonl",
|
|
744
744
|
"datasets/simulated-v1.jsonl",
|
|
745
|
+
"evaluators/autoevals-lambda/execution-role-policy.json",
|
|
746
|
+
"evaluators/autoevals-lambda/lambda_function.py",
|
|
747
|
+
"evaluators/autoevals-lambda/pyproject.toml",
|
|
748
|
+
"evaluators/deepeval-lambda/execution-role-policy.json",
|
|
749
|
+
"evaluators/deepeval-lambda/lambda_function.py",
|
|
750
|
+
"evaluators/deepeval-lambda/pyproject.toml",
|
|
745
751
|
"evaluators/python-lambda/execution-role-policy.json",
|
|
746
752
|
"evaluators/python-lambda/lambda_function.py",
|
|
747
753
|
"evaluators/python-lambda/pyproject.toml",
|
|
@@ -3329,6 +3335,11 @@ file defines a Starlette ASGI app with the AutoGen framework running within.
|
|
|
3329
3335
|
|
|
3330
3336
|
\`model/load.py\` instantiates your chosen model provider.
|
|
3331
3337
|
|
|
3338
|
+
## Input Validation
|
|
3339
|
+
|
|
3340
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
3341
|
+
only prompt text to the agent.
|
|
3342
|
+
|
|
3332
3343
|
## Environment Variables
|
|
3333
3344
|
|
|
3334
3345
|
| Variable | Required | Description |
|
|
@@ -3532,6 +3543,8 @@ async def invoke(payload, context):
|
|
|
3532
3543
|
|
|
3533
3544
|
# Process the user prompt
|
|
3534
3545
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
3546
|
+
if not isinstance(prompt, str):
|
|
3547
|
+
raise ValueError("prompt must be a string")
|
|
3535
3548
|
session_id = getattr(context, "session_id", "default-session")
|
|
3536
3549
|
|
|
3537
3550
|
# Reuse the per-session agent (preserves conversation history)
|
|
@@ -3785,6 +3798,11 @@ file defines a Starlette ASGI app with the Google ADK framework running within.
|
|
|
3785
3798
|
|
|
3786
3799
|
\`model/load.py\` instantiates your chosen model provider (Gemini).
|
|
3787
3800
|
|
|
3801
|
+
## Input Validation
|
|
3802
|
+
|
|
3803
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
3804
|
+
only prompt text to the agent.
|
|
3805
|
+
|
|
3788
3806
|
## Environment Variables
|
|
3789
3807
|
|
|
3790
3808
|
| Variable | Required | Description |
|
|
@@ -4052,6 +4070,8 @@ async def invoke(payload, context):
|
|
|
4052
4070
|
|
|
4053
4071
|
# Process the user prompt
|
|
4054
4072
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
4073
|
+
if not isinstance(prompt, str):
|
|
4074
|
+
raise ValueError("prompt must be a string")
|
|
4055
4075
|
session_id = getattr(context, "session_id", "default_session")
|
|
4056
4076
|
user_id = payload.get("user_id", "default_user")
|
|
4057
4077
|
|
|
@@ -4245,6 +4265,11 @@ file defines a Starlette ASGI app with the LangChain/LangGraph framework running
|
|
|
4245
4265
|
|
|
4246
4266
|
\`model/load.py\` instantiates your chosen model provider.
|
|
4247
4267
|
|
|
4268
|
+
## Input Validation
|
|
4269
|
+
|
|
4270
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
4271
|
+
only prompt text to the agent.
|
|
4272
|
+
|
|
4248
4273
|
## Environment Variables
|
|
4249
4274
|
|
|
4250
4275
|
| Variable | Required | Description |
|
|
@@ -4504,6 +4529,8 @@ async def invoke(payload, context):
|
|
|
4504
4529
|
|
|
4505
4530
|
# Process the user prompt
|
|
4506
4531
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
4532
|
+
if not isinstance(prompt, str):
|
|
4533
|
+
raise ValueError("prompt must be a string")
|
|
4507
4534
|
session_id = getattr(context, "session_id", "default-session")
|
|
4508
4535
|
touch_thread(session_id)
|
|
4509
4536
|
log.info(f"Agent input: {prompt}")
|
|
@@ -4523,6 +4550,8 @@ async def invoke(payload, context):
|
|
|
4523
4550
|
|
|
4524
4551
|
# Process the user prompt
|
|
4525
4552
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
4553
|
+
if not isinstance(prompt, str):
|
|
4554
|
+
raise ValueError("prompt must be a string")
|
|
4526
4555
|
session_id = getattr(context, "session_id", "default-session")
|
|
4527
4556
|
touch_thread(session_id)
|
|
4528
4557
|
log.info(f"Agent input: {prompt}")
|
|
@@ -4823,6 +4852,11 @@ file defines a Starlette ASGI app with the OpenAI Agents SDK framework running w
|
|
|
4823
4852
|
|
|
4824
4853
|
\`model/load.py\` instantiates your chosen model provider (OpenAI).
|
|
4825
4854
|
|
|
4855
|
+
## Input Validation
|
|
4856
|
+
|
|
4857
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
4858
|
+
only prompt text to the agent.
|
|
4859
|
+
|
|
4826
4860
|
## Environment Variables
|
|
4827
4861
|
|
|
4828
4862
|
| Variable | Required | Description |
|
|
@@ -5083,6 +5117,8 @@ async def invoke(payload, context):
|
|
|
5083
5117
|
|
|
5084
5118
|
# Process the user prompt
|
|
5085
5119
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
5120
|
+
if not isinstance(prompt, str):
|
|
5121
|
+
raise ValueError("prompt must be a string")
|
|
5086
5122
|
session_id = getattr(context, "session_id", "default-session")
|
|
5087
5123
|
session = get_session(session_id)
|
|
5088
5124
|
|
|
@@ -5268,6 +5304,12 @@ file defines a Starlette ASGI app with the chosen Agent framework SDK running wi
|
|
|
5268
5304
|
|
|
5269
5305
|
\`model/load.py\` instantiates your chosen model provider.
|
|
5270
5306
|
|
|
5307
|
+
## Input Validation
|
|
5308
|
+
|
|
5309
|
+
Validate invocation input before forwarding it to Strands. Keep plain prompts typed as strings. If the app accepts a
|
|
5310
|
+
caller-supplied message history, retain \`strip_trailing_tool_use()\`, which normalizes the history tail before
|
|
5311
|
+
invoking the agent.
|
|
5312
|
+
|
|
5271
5313
|
## Environment Variables
|
|
5272
5314
|
|
|
5273
5315
|
| Variable | Required | Description |
|
|
@@ -5824,17 +5866,53 @@ get_or_create_agent = agent_factory()
|
|
|
5824
5866
|
{{/if}}
|
|
5825
5867
|
|
|
5826
5868
|
|
|
5869
|
+
def strip_trailing_tool_use(messages: Any) -> list[dict]:
|
|
5870
|
+
"""Strip toolUse blocks from the tail until the last message has none."""
|
|
5871
|
+
if not isinstance(messages, list):
|
|
5872
|
+
raise ValueError("messages must be a list")
|
|
5873
|
+
|
|
5874
|
+
messages = list(messages)
|
|
5875
|
+
while messages:
|
|
5876
|
+
last = messages[-1]
|
|
5877
|
+
if not isinstance(last, dict):
|
|
5878
|
+
raise ValueError("each message must be an object")
|
|
5879
|
+
original_content = last.get("content", [])
|
|
5880
|
+
if not isinstance(original_content, list) or not all(isinstance(block, dict) for block in original_content):
|
|
5881
|
+
raise ValueError("each message content value must be a list of content blocks")
|
|
5882
|
+
|
|
5883
|
+
content = [block for block in original_content if "toolUse" not in block]
|
|
5884
|
+
if len(content) == len(original_content):
|
|
5885
|
+
break
|
|
5886
|
+
if content:
|
|
5887
|
+
messages[-1] = {**last, "content": content}
|
|
5888
|
+
break
|
|
5889
|
+
messages.pop()
|
|
5890
|
+
|
|
5891
|
+
return messages
|
|
5892
|
+
|
|
5893
|
+
|
|
5827
5894
|
def _extract_prompt(payload: dict):
|
|
5828
|
-
"""Accept harness
|
|
5895
|
+
"""Accept validated harness messages, tool results, or a plain prompt string."""
|
|
5896
|
+
if not isinstance(payload, dict):
|
|
5897
|
+
raise ValueError("payload must be a JSON object")
|
|
5829
5898
|
if "messages" in payload:
|
|
5830
|
-
return payload["messages"]
|
|
5899
|
+
return strip_trailing_tool_use(payload["messages"])
|
|
5831
5900
|
if "tool_results" in payload:
|
|
5901
|
+
tool_results = payload["tool_results"]
|
|
5902
|
+
if not isinstance(tool_results, list) or not all(
|
|
5903
|
+
isinstance(tool_result, dict) and isinstance(tool_result.get("toolUseId"), str)
|
|
5904
|
+
for tool_result in tool_results
|
|
5905
|
+
):
|
|
5906
|
+
raise ValueError("tool_results must contain objects with a toolUseId string")
|
|
5832
5907
|
return [{"role": "user", "content": [{"toolResult": {
|
|
5833
5908
|
"toolUseId": tr["toolUseId"],
|
|
5834
5909
|
"status": tr.get("status", "success"),
|
|
5835
5910
|
"content": tr.get("content", []),
|
|
5836
|
-
}} for tr in
|
|
5837
|
-
|
|
5911
|
+
}} for tr in tool_results]}]
|
|
5912
|
+
prompt = payload.get("prompt", "")
|
|
5913
|
+
if not isinstance(prompt, str):
|
|
5914
|
+
raise ValueError("prompt must be a string")
|
|
5915
|
+
return prompt
|
|
5838
5916
|
|
|
5839
5917
|
|
|
5840
5918
|
def _has_inline_function_call(messages) -> bool:
|
|
@@ -7258,7 +7336,7 @@ For Container builds, \`BaseRenderer.render()\` automatically copies the \`conta
|
|
|
7258
7336
|
|
|
7259
7337
|
- These assets are rendered by the CLI's template renderer in \`src/cli/templates/\`
|
|
7260
7338
|
- The \`README.md\` and \`agents/AGENTS.md\` are copied verbatim (no template rendering) during project creation
|
|
7261
|
-
- The \`.llm-context/\` files are sourced from \`src/schema/llm-compacted/\` and written during
|
|
7339
|
+
- The \`.llm-context/\` files are sourced from \`src/schema/llm-compacted/\` and written during project creation
|
|
7262
7340
|
"
|
|
7263
7341
|
`;
|
|
7264
7342
|
|
|
@@ -7278,8 +7356,7 @@ my-project/
|
|
|
7278
7356
|
│ ├── .env.local # Secrets — API keys (gitignored)
|
|
7279
7357
|
│ ├── .llm-context/ # TypeScript type definitions for AI assistants
|
|
7280
7358
|
│ │ ├── agentcore.ts # AgentCoreProjectSpec types
|
|
7281
|
-
│ │
|
|
7282
|
-
│ │ └── mcp.ts # Gateway and MCP tool types
|
|
7359
|
+
│ │ └── aws-targets.ts # Deployment target types
|
|
7283
7360
|
│ └── cdk/ # CDK infrastructure (@aws/agentcore-cdk)
|
|
7284
7361
|
├── app/ # Agent application code
|
|
7285
7362
|
└── evaluators/ # Custom evaluator code (if any)
|
|
@@ -7302,6 +7379,11 @@ Run your agent locally:
|
|
|
7302
7379
|
agentcore dev
|
|
7303
7380
|
\`\`\`
|
|
7304
7381
|
|
|
7382
|
+
### Validate Invocation Input
|
|
7383
|
+
|
|
7384
|
+
Validate runtime invocation payloads before forwarding them to an agent framework. Keep user prompts typed as strings
|
|
7385
|
+
and pass only prompt text to the agent.
|
|
7386
|
+
|
|
7305
7387
|
### Deployment
|
|
7306
7388
|
|
|
7307
7389
|
Deploy to AWS:
|
|
@@ -7396,6 +7478,8 @@ Tags defined in \`agentcore.json\` flow through to deployed CloudFormation resou
|
|
|
7396
7478
|
\`agentcore validate\` to check.
|
|
7397
7479
|
4. **Resource Removal:** Use \`agentcore remove\` to remove resources. Run \`agentcore deploy\` after removal to tear down
|
|
7398
7480
|
deployed infrastructure.
|
|
7481
|
+
5. **Invocation Input:** Validate runtime payloads and require text prompts to be strings. If a Strands app accepts a
|
|
7482
|
+
caller-supplied message history, normalize the history tail with \`strip_trailing_tool_use()\` before invocation.
|
|
7399
7483
|
|
|
7400
7484
|
## Directory Structure
|
|
7401
7485
|
|
|
@@ -7409,8 +7493,7 @@ myProject/
|
|
|
7409
7493
|
│ ├── .llm-context/ # TypeScript type definitions for AI assistants
|
|
7410
7494
|
│ │ ├── README.md # Guide to using schema files
|
|
7411
7495
|
│ │ ├── agentcore.ts # AgentCoreProjectSpec types
|
|
7412
|
-
│ │
|
|
7413
|
-
│ │ └── mcp.ts # Gateway and MCP tool types
|
|
7496
|
+
│ │ └── aws-targets.ts # AWS deployment target types
|
|
7414
7497
|
│ └── cdk/ # AWS CDK project (@aws/agentcore-cdk L3 constructs)
|
|
7415
7498
|
├── app/ # Agent application code
|
|
7416
7499
|
└── evaluators/ # Custom evaluator code (if any)
|
|
@@ -7424,12 +7507,11 @@ file maps to a JSON config file and includes validation constraints as comments
|
|
|
7424
7507
|
| JSON Config | Schema File | Root Type |
|
|
7425
7508
|
| --- | --- | --- |
|
|
7426
7509
|
| \`agentcore/agentcore.json\` | \`agentcore/.llm-context/agentcore.ts\` | \`AgentCoreProjectSpec\` |
|
|
7427
|
-
| \`agentcore/agentcore.json\` (gateways) | \`agentcore/.llm-context/mcp.ts\` | \`AgentCoreMcpSpec\` |
|
|
7428
7510
|
| \`agentcore/aws-targets.json\` | \`agentcore/.llm-context/aws-targets.ts\` | \`AwsDeploymentTarget[]\` |
|
|
7429
7511
|
|
|
7430
7512
|
### Key Types
|
|
7431
7513
|
|
|
7432
|
-
- **AgentCoreProjectSpec**: Root config with
|
|
7514
|
+
- **AgentCoreProjectSpec**: Root config with runtimes, memories, knowledge bases, credentials, evaluators, online evals and insights, gateways, policy engines, config bundles, A/B tests, harness registrations, datasets, and payment managers
|
|
7433
7515
|
- **AgentEnvSpec**: Agent configuration (build type, entrypoint, code location, runtime version, network mode)
|
|
7434
7516
|
- **Memory**: Memory resource with strategies (SEMANTIC, SUMMARIZATION, USER_PREFERENCE, EPISODIC) and expiry
|
|
7435
7517
|
- **Credential**: API key or OAuth credential provider
|
|
@@ -7609,6 +7691,11 @@ defines an HTTP server that streams tokens from your chosen Agent framework SDK.
|
|
|
7609
7691
|
|
|
7610
7692
|
\`model/load.ts\` instantiates your chosen model provider.
|
|
7611
7693
|
|
|
7694
|
+
## Input Validation
|
|
7695
|
+
|
|
7696
|
+
The generated Zod request schema keeps plain prompts typed as strings before forwarding them to Strands. Retain this
|
|
7697
|
+
validation when extending the request shape, and pass only prompt text to the agent.
|
|
7698
|
+
|
|
7612
7699
|
## Environment Variables
|
|
7613
7700
|
|
|
7614
7701
|
| Variable | Required | Description |
|
|
@@ -7697,6 +7784,10 @@ const SYSTEM_PROMPT = \`
|
|
|
7697
7784
|
You are a helpful assistant. Use tools when appropriate.
|
|
7698
7785
|
\`;
|
|
7699
7786
|
|
|
7787
|
+
const requestSchema = z.object({
|
|
7788
|
+
prompt: z.string().default(''),
|
|
7789
|
+
});
|
|
7790
|
+
|
|
7700
7791
|
{{#if hasMemory}}
|
|
7701
7792
|
const agentCache = new Map<string, Agent>();
|
|
7702
7793
|
|
|
@@ -7750,7 +7841,8 @@ async function getOrCreateAgent(sessionId: string): Promise<Agent> {
|
|
|
7750
7841
|
|
|
7751
7842
|
const app = new BedrockAgentCoreApp({
|
|
7752
7843
|
invocationHandler: {
|
|
7753
|
-
|
|
7844
|
+
requestSchema,
|
|
7845
|
+
async *process(payload, context) {
|
|
7754
7846
|
{{#if hasMemory}}
|
|
7755
7847
|
const sessionId = context?.sessionId ?? 'default-session';
|
|
7756
7848
|
const actorId = getActorId(payload, context);
|
|
@@ -7762,7 +7854,7 @@ const app = new BedrockAgentCoreApp({
|
|
|
7762
7854
|
|
|
7763
7855
|
{{#if hasMemory}}
|
|
7764
7856
|
try {
|
|
7765
|
-
for await (const event of agent.stream(payload.prompt
|
|
7857
|
+
for await (const event of agent.stream(payload.prompt)) {
|
|
7766
7858
|
if (
|
|
7767
7859
|
event.type === 'modelStreamUpdateEvent' &&
|
|
7768
7860
|
event.event?.type === 'modelContentBlockDeltaEvent' &&
|
|
@@ -7786,7 +7878,7 @@ const app = new BedrockAgentCoreApp({
|
|
|
7786
7878
|
// e.g. Anthropic). Restoring on error keeps the session reusable.
|
|
7787
7879
|
const snapshot = agent.takeSnapshot({ include: ['messages'] });
|
|
7788
7880
|
try {
|
|
7789
|
-
for await (const event of agent.stream(payload.prompt
|
|
7881
|
+
for await (const event of agent.stream(payload.prompt)) {
|
|
7790
7882
|
if (
|
|
7791
7883
|
event.type === 'modelStreamUpdateEvent' &&
|
|
7792
7884
|
event.event?.type === 'modelContentBlockDeltaEvent' &&
|
|
@@ -8066,6 +8158,11 @@ defines an HTTP app that streams tokens using the Vercel AI SDK's \`streamText\`
|
|
|
8066
8158
|
|
|
8067
8159
|
\`model/load.ts\` instantiates your chosen model provider.
|
|
8068
8160
|
|
|
8161
|
+
## Input Validation
|
|
8162
|
+
|
|
8163
|
+
The generated Zod request schema keeps plain prompts typed as strings before forwarding them to the agent framework.
|
|
8164
|
+
Retain this validation when extending the request shape, and pass only prompt text to the agent.
|
|
8165
|
+
|
|
8069
8166
|
## Environment Variables
|
|
8070
8167
|
|
|
8071
8168
|
| Variable | Required | Description |
|
|
@@ -8120,10 +8217,15 @@ Thumbs.db
|
|
|
8120
8217
|
exports[`Assets Directory Snapshots > TypeScript assets > typescript/typescript/http/vercelai/base/main.ts should match snapshot 1`] = `
|
|
8121
8218
|
"import { BedrockAgentCoreApp } from 'bedrock-agentcore/runtime';
|
|
8122
8219
|
import { streamText, type ModelMessage } from 'ai';
|
|
8220
|
+
import { z } from 'zod';
|
|
8123
8221
|
import { loadModel } from './model/load.js';
|
|
8124
8222
|
|
|
8125
8223
|
const SYSTEM_PROMPT = \`You are a helpful assistant.\`;
|
|
8126
8224
|
|
|
8225
|
+
const requestSchema = z.object({
|
|
8226
|
+
prompt: z.string().default(''),
|
|
8227
|
+
});
|
|
8228
|
+
|
|
8127
8229
|
const HISTORY_LIMIT = 128;
|
|
8128
8230
|
|
|
8129
8231
|
// Keeps one message history per sessionId so each session remembers its own
|
|
@@ -8152,10 +8254,11 @@ function getHistory(sessionId: string): ModelMessage[] {
|
|
|
8152
8254
|
|
|
8153
8255
|
const app = new BedrockAgentCoreApp({
|
|
8154
8256
|
invocationHandler: {
|
|
8155
|
-
|
|
8257
|
+
requestSchema,
|
|
8258
|
+
async *process(payload, context) {
|
|
8156
8259
|
const sessionId = context?.sessionId ?? 'default-session';
|
|
8157
8260
|
const history = getHistory(sessionId);
|
|
8158
|
-
const userMessage: ModelMessage = { role: 'user', content: payload.prompt
|
|
8261
|
+
const userMessage: ModelMessage = { role: 'user', content: payload.prompt };
|
|
8159
8262
|
|
|
8160
8263
|
const model = await loadModel();
|
|
8161
8264
|
const result = streamText({
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
const ASSETS_DIR = resolve(__dirname, '..');
|
|
6
|
+
|
|
7
|
+
const PYTHON_HTTP_ENTRYPOINTS = [
|
|
8
|
+
'python/http/autogen/base/main.py',
|
|
9
|
+
'python/http/googleadk/base/main.py',
|
|
10
|
+
'python/http/langchain_langgraph/base/main.py',
|
|
11
|
+
'python/http/openaiagents/base/main.py',
|
|
12
|
+
'python/http/strands/base/main.py',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const TYPESCRIPT_HTTP_ENTRYPOINTS = [
|
|
16
|
+
'typescript/http/strands/base/main.ts',
|
|
17
|
+
'typescript/http/vercelai/base/main.ts',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
describe('HTTP agent template input validation', () => {
|
|
21
|
+
it.each(PYTHON_HTTP_ENTRYPOINTS)('%s rejects non-string prompts', templatePath => {
|
|
22
|
+
const template = readFileSync(resolve(ASSETS_DIR, templatePath), 'utf8');
|
|
23
|
+
|
|
24
|
+
expect(template).toContain('if not isinstance(prompt, str):');
|
|
25
|
+
expect(template).toContain('raise ValueError("prompt must be a string")');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it.each(TYPESCRIPT_HTTP_ENTRYPOINTS)('%s validates prompts with Zod', templatePath => {
|
|
29
|
+
const template = readFileSync(resolve(ASSETS_DIR, templatePath), 'utf8');
|
|
30
|
+
|
|
31
|
+
expect(template).toContain("prompt: z.string().default('')");
|
|
32
|
+
expect(template).toContain('requestSchema,');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('strips toolUse blocks from the Python Strands message-history tail', () => {
|
|
36
|
+
const template = readFileSync(resolve(ASSETS_DIR, 'python/http/strands/base/main.py'), 'utf8');
|
|
37
|
+
|
|
38
|
+
expect(template).toContain('def strip_trailing_tool_use(messages: Any) -> list[dict]:');
|
|
39
|
+
expect(template).toContain('while messages:');
|
|
40
|
+
expect(template).toContain('content = [block for block in original_content if "toolUse" not in block]');
|
|
41
|
+
expect(template).toContain('messages.pop()');
|
|
42
|
+
expect(template).toContain('return strip_trailing_tool_use(payload["messages"])');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -23,6 +23,8 @@ Tags defined in `agentcore.json` flow through to deployed CloudFormation resourc
|
|
|
23
23
|
`agentcore validate` to check.
|
|
24
24
|
4. **Resource Removal:** Use `agentcore remove` to remove resources. Run `agentcore deploy` after removal to tear down
|
|
25
25
|
deployed infrastructure.
|
|
26
|
+
5. **Invocation Input:** Validate runtime payloads and require text prompts to be strings. If a Strands app accepts a
|
|
27
|
+
caller-supplied message history, normalize the history tail with `strip_trailing_tool_use()` before invocation.
|
|
26
28
|
|
|
27
29
|
## Directory Structure
|
|
28
30
|
|
|
@@ -36,8 +38,7 @@ myProject/
|
|
|
36
38
|
│ ├── .llm-context/ # TypeScript type definitions for AI assistants
|
|
37
39
|
│ │ ├── README.md # Guide to using schema files
|
|
38
40
|
│ │ ├── agentcore.ts # AgentCoreProjectSpec types
|
|
39
|
-
│ │
|
|
40
|
-
│ │ └── mcp.ts # Gateway and MCP tool types
|
|
41
|
+
│ │ └── aws-targets.ts # AWS deployment target types
|
|
41
42
|
│ └── cdk/ # AWS CDK project (@aws/agentcore-cdk L3 constructs)
|
|
42
43
|
├── app/ # Agent application code
|
|
43
44
|
└── evaluators/ # Custom evaluator code (if any)
|
|
@@ -51,12 +52,11 @@ file maps to a JSON config file and includes validation constraints as comments
|
|
|
51
52
|
| JSON Config | Schema File | Root Type |
|
|
52
53
|
| --- | --- | --- |
|
|
53
54
|
| `agentcore/agentcore.json` | `agentcore/.llm-context/agentcore.ts` | `AgentCoreProjectSpec` |
|
|
54
|
-
| `agentcore/agentcore.json` (gateways) | `agentcore/.llm-context/mcp.ts` | `AgentCoreMcpSpec` |
|
|
55
55
|
| `agentcore/aws-targets.json` | `agentcore/.llm-context/aws-targets.ts` | `AwsDeploymentTarget[]` |
|
|
56
56
|
|
|
57
57
|
### Key Types
|
|
58
58
|
|
|
59
|
-
- **AgentCoreProjectSpec**: Root config with
|
|
59
|
+
- **AgentCoreProjectSpec**: Root config with runtimes, memories, knowledge bases, credentials, evaluators, online evals and insights, gateways, policy engines, config bundles, A/B tests, harness registrations, datasets, and payment managers
|
|
60
60
|
- **AgentEnvSpec**: Agent configuration (build type, entrypoint, code location, runtime version, network mode)
|
|
61
61
|
- **Memory**: Memory resource with strategies (SEMANTIC, SUMMARIZATION, USER_PREFERENCE, EPISODIC) and expiry
|
|
62
62
|
- **Credential**: API key or OAuth credential provider
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Version": "2012-10-17",
|
|
3
|
+
"Statement": [
|
|
4
|
+
{
|
|
5
|
+
"Effect": "Allow",
|
|
6
|
+
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
|
|
7
|
+
"Resource": "arn:*:logs:*:*:log-group:/aws/lambda/*"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"Effect": "Allow",
|
|
11
|
+
"Action": ["bedrock:InvokeModel"],
|
|
12
|
+
"Resource": "*"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{{#if ModelProviderBedrock}}
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
# litellm's Bedrock provider reads AWS_REGION_NAME; Lambda only sets AWS_REGION/AWS_DEFAULT_REGION.
|
|
5
|
+
os.environ.setdefault("AWS_REGION_NAME", os.environ.get("AWS_REGION", "us-west-2"))
|
|
6
|
+
|
|
7
|
+
from autoevals import {{ EvaluatorClass }}, init
|
|
8
|
+
from autoevals.litellm import LiteLLMClient
|
|
9
|
+
|
|
10
|
+
from bedrock_agentcore.evaluation.custom_code_based_evaluators import (
|
|
11
|
+
EvaluatorInput,
|
|
12
|
+
EvaluatorOutput,
|
|
13
|
+
custom_code_based_evaluator,
|
|
14
|
+
)
|
|
15
|
+
from bedrock_agentcore.evaluation.custom_code_based_evaluators.third_party.autoevals import AutoEvalsAdapter
|
|
16
|
+
|
|
17
|
+
client = LiteLLMClient()
|
|
18
|
+
init(client=client, default_model="{{ Model }}")
|
|
19
|
+
|
|
20
|
+
adapter = AutoEvalsAdapter(metric={{ EvaluatorClass }}(client=client, model="{{ Model }}"){{#if EvaluatorParams}}, {{{ EvaluatorParams }}}{{/if}})
|
|
21
|
+
{{else}}
|
|
22
|
+
from autoevals import {{ EvaluatorClass }}
|
|
23
|
+
|
|
24
|
+
from bedrock_agentcore.evaluation.custom_code_based_evaluators import (
|
|
25
|
+
EvaluatorInput,
|
|
26
|
+
EvaluatorOutput,
|
|
27
|
+
custom_code_based_evaluator,
|
|
28
|
+
)
|
|
29
|
+
from bedrock_agentcore.evaluation.custom_code_based_evaluators.third_party.autoevals import AutoEvalsAdapter
|
|
30
|
+
|
|
31
|
+
adapter = AutoEvalsAdapter(metric={{ EvaluatorClass }}({{#if Model}}model="{{ Model }}"{{/if}}){{#if EvaluatorParams}}, {{{ EvaluatorParams }}}{{/if}})
|
|
32
|
+
{{/if}}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@custom_code_based_evaluator()
|
|
36
|
+
def handler(evaluator_input: EvaluatorInput, context) -> EvaluatorOutput:
|
|
37
|
+
return adapter(evaluator_input, context)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "{{ Name }}"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "AgentCore Code-Based Evaluator (Autoevals)"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"bedrock-agentcore[autoevals]",
|
|
12
|
+
"autoevals>=0.0.80,<1.0.0",
|
|
13
|
+
{{#if ModelProviderBedrock}}
|
|
14
|
+
# autoevals grades via LiteLLMClient -> Bedrock (Converse); litellm replaces the openai judge
|
|
15
|
+
"litellm>=1.60,<1.85",
|
|
16
|
+
{{else}}
|
|
17
|
+
"openai>=1.0.0",
|
|
18
|
+
{{/if}}
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["."]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Version": "2012-10-17",
|
|
3
|
+
"Statement": [
|
|
4
|
+
{
|
|
5
|
+
"Effect": "Allow",
|
|
6
|
+
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
|
|
7
|
+
"Resource": "arn:*:logs:*:*:log-group:/aws/lambda/*"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"Effect": "Allow",
|
|
11
|
+
"Action": ["bedrock:InvokeModel"],
|
|
12
|
+
"Resource": "*"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
os.environ.setdefault("DEEPEVAL_RESULTS_FOLDER", "/tmp/.deepeval")
|
|
4
|
+
os.environ.setdefault("DEEPEVAL_TELEMETRY_OPT_OUT", "YES")
|
|
5
|
+
os.chdir("/tmp")
|
|
6
|
+
|
|
7
|
+
{{#if ModelProviderBedrock}}
|
|
8
|
+
from deepeval.models import AmazonBedrockModel
|
|
9
|
+
{{/if}}
|
|
10
|
+
from deepeval.metrics import {{ EvaluatorClass }}
|
|
11
|
+
|
|
12
|
+
from bedrock_agentcore.evaluation.custom_code_based_evaluators import (
|
|
13
|
+
EvaluatorInput,
|
|
14
|
+
EvaluatorOutput,
|
|
15
|
+
custom_code_based_evaluator,
|
|
16
|
+
)
|
|
17
|
+
from bedrock_agentcore.evaluation.custom_code_based_evaluators.third_party.deepeval import DeepEvalAdapter
|
|
18
|
+
|
|
19
|
+
{{#if ModelProviderBedrock}}
|
|
20
|
+
model = AmazonBedrockModel(model="{{ Model }}", region=os.environ.get("AWS_REGION", "us-west-2"))
|
|
21
|
+
adapter = DeepEvalAdapter(metric={{ EvaluatorClass }}(model=model{{#if EvaluatorParams}}, {{{ EvaluatorParams }}}{{/if}}))
|
|
22
|
+
{{else}}
|
|
23
|
+
adapter = DeepEvalAdapter(metric={{ EvaluatorClass }}({{{ EvaluatorParams }}}))
|
|
24
|
+
{{/if}}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@custom_code_based_evaluator()
|
|
28
|
+
def handler(evaluator_input: EvaluatorInput, context) -> EvaluatorOutput:
|
|
29
|
+
return adapter(evaluator_input, context)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "{{ Name }}"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "AgentCore Code-Based Evaluator (DeepEval)"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"bedrock-agentcore[deepeval]",
|
|
12
|
+
"deepeval>=2.0.0,<3.0.0",
|
|
13
|
+
{{#if ModelProviderBedrock}}
|
|
14
|
+
"aiobotocore>=2.13.0",
|
|
15
|
+
{{/if}}
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[tool.hatch.build.targets.wheel]
|
|
19
|
+
packages = ["."]
|
|
@@ -13,6 +13,11 @@ file defines a Starlette ASGI app with the AutoGen framework running within.
|
|
|
13
13
|
|
|
14
14
|
`model/load.py` instantiates your chosen model provider.
|
|
15
15
|
|
|
16
|
+
## Input Validation
|
|
17
|
+
|
|
18
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
19
|
+
only prompt text to the agent.
|
|
20
|
+
|
|
16
21
|
## Environment Variables
|
|
17
22
|
|
|
18
23
|
| Variable | Required | Description |
|
|
@@ -127,6 +127,8 @@ async def invoke(payload, context):
|
|
|
127
127
|
|
|
128
128
|
# Process the user prompt
|
|
129
129
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
130
|
+
if not isinstance(prompt, str):
|
|
131
|
+
raise ValueError("prompt must be a string")
|
|
130
132
|
session_id = getattr(context, "session_id", "default-session")
|
|
131
133
|
|
|
132
134
|
# Reuse the per-session agent (preserves conversation history)
|
|
@@ -13,6 +13,11 @@ file defines a Starlette ASGI app with the Google ADK framework running within.
|
|
|
13
13
|
|
|
14
14
|
`model/load.py` instantiates your chosen model provider (Gemini).
|
|
15
15
|
|
|
16
|
+
## Input Validation
|
|
17
|
+
|
|
18
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
19
|
+
only prompt text to the agent.
|
|
20
|
+
|
|
16
21
|
## Environment Variables
|
|
17
22
|
|
|
18
23
|
| Variable | Required | Description |
|
|
@@ -191,6 +191,8 @@ async def invoke(payload, context):
|
|
|
191
191
|
|
|
192
192
|
# Process the user prompt
|
|
193
193
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
194
|
+
if not isinstance(prompt, str):
|
|
195
|
+
raise ValueError("prompt must be a string")
|
|
194
196
|
session_id = getattr(context, "session_id", "default_session")
|
|
195
197
|
user_id = payload.get("user_id", "default_user")
|
|
196
198
|
|
|
@@ -13,6 +13,11 @@ file defines a Starlette ASGI app with the LangChain/LangGraph framework running
|
|
|
13
13
|
|
|
14
14
|
`model/load.py` instantiates your chosen model provider.
|
|
15
15
|
|
|
16
|
+
## Input Validation
|
|
17
|
+
|
|
18
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
19
|
+
only prompt text to the agent.
|
|
20
|
+
|
|
16
21
|
## Environment Variables
|
|
17
22
|
|
|
18
23
|
| Variable | Required | Description |
|
|
@@ -183,6 +183,8 @@ async def invoke(payload, context):
|
|
|
183
183
|
|
|
184
184
|
# Process the user prompt
|
|
185
185
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
186
|
+
if not isinstance(prompt, str):
|
|
187
|
+
raise ValueError("prompt must be a string")
|
|
186
188
|
session_id = getattr(context, "session_id", "default-session")
|
|
187
189
|
touch_thread(session_id)
|
|
188
190
|
log.info(f"Agent input: {prompt}")
|
|
@@ -202,6 +204,8 @@ async def invoke(payload, context):
|
|
|
202
204
|
|
|
203
205
|
# Process the user prompt
|
|
204
206
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
207
|
+
if not isinstance(prompt, str):
|
|
208
|
+
raise ValueError("prompt must be a string")
|
|
205
209
|
session_id = getattr(context, "session_id", "default-session")
|
|
206
210
|
touch_thread(session_id)
|
|
207
211
|
log.info(f"Agent input: {prompt}")
|
|
@@ -13,6 +13,11 @@ file defines a Starlette ASGI app with the OpenAI Agents SDK framework running w
|
|
|
13
13
|
|
|
14
14
|
`model/load.py` instantiates your chosen model provider (OpenAI).
|
|
15
15
|
|
|
16
|
+
## Input Validation
|
|
17
|
+
|
|
18
|
+
Validate invocation input before forwarding it to the agent framework. Keep plain prompts typed as strings and pass
|
|
19
|
+
only prompt text to the agent.
|
|
20
|
+
|
|
16
21
|
## Environment Variables
|
|
17
22
|
|
|
18
23
|
| Variable | Required | Description |
|