@aws/agentcore 0.12.2 → 0.13.1
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 +26 -10
- package/dist/agent-inspector/index.css +1 -1
- package/dist/agent-inspector/index.js +86 -81
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +125 -17
- package/dist/assets/cdk/test/cdk.test.ts +1 -0
- package/dist/assets/python/http/langchain_langgraph/base/main.py +52 -8
- package/dist/assets/python/http/strands/base/main.py +71 -8
- package/dist/cli/index.mjs +972 -610
- package/dist/lib/packaging/build-args.js +2 -2
- package/dist/lib/packaging/build-args.js.map +1 -1
- package/dist/lib/packaging/helpers.d.ts.map +1 -1
- package/dist/lib/packaging/helpers.js +10 -6
- package/dist/lib/packaging/helpers.js.map +1 -1
- package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
- package/dist/lib/schemas/io/config-io.js +9 -1
- package/dist/lib/schemas/io/config-io.js.map +1 -1
- package/dist/lib/schemas/io/global-config.d.ts +33 -0
- package/dist/lib/schemas/io/global-config.d.ts.map +1 -0
- package/dist/lib/schemas/io/global-config.js +89 -0
- package/dist/lib/schemas/io/global-config.js.map +1 -0
- package/dist/lib/schemas/io/index.d.ts +0 -1
- package/dist/lib/schemas/io/index.d.ts.map +1 -1
- package/dist/lib/schemas/io/index.js +1 -3
- package/dist/lib/schemas/io/index.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +81 -0
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.js +87 -1
- package/dist/schema/schemas/agentcore-project.js.map +1 -1
- package/dist/schema/schemas/deployed-state.d.ts +113 -0
- package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
- package/dist/schema/schemas/deployed-state.js +40 -1
- package/dist/schema/schemas/deployed-state.js.map +1 -1
- package/dist/schema/schemas/mcp.js +1 -1
- package/dist/schema/schemas/mcp.js.map +1 -1
- package/dist/schema/schemas/primitives/ab-test.d.ts +141 -0
- package/dist/schema/schemas/primitives/ab-test.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/ab-test.js +97 -0
- package/dist/schema/schemas/primitives/ab-test.js.map +1 -0
- package/dist/schema/schemas/primitives/config-bundle.d.ts +31 -0
- package/dist/schema/schemas/primitives/config-bundle.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/config-bundle.js +38 -0
- package/dist/schema/schemas/primitives/config-bundle.js.map +1 -0
- package/dist/schema/schemas/primitives/http-gateway.d.ts +21 -0
- package/dist/schema/schemas/primitives/http-gateway.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/http-gateway.js +34 -0
- package/dist/schema/schemas/primitives/http-gateway.js.map +1 -0
- package/dist/schema/schemas/primitives/index.d.ts +4 -0
- package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/index.js +15 -1
- package/dist/schema/schemas/primitives/index.js.map +1 -1
- package/dist/schema/schemas/primitives/online-eval-config.d.ts +1 -0
- package/dist/schema/schemas/primitives/online-eval-config.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/online-eval-config.js +2 -0
- package/dist/schema/schemas/primitives/online-eval-config.js.map +1 -1
- package/package.json +6 -4
- package/scripts/bundle.mjs +5 -2
- package/scripts/run-e2e-local.sh +112 -0
- package/dist/lib/schemas/io/cli-config.d.ts +0 -12
- package/dist/lib/schemas/io/cli-config.d.ts.map +0 -1
- package/dist/lib/schemas/io/cli-config.js +0 -35
- package/dist/lib/schemas/io/cli-config.js.map +0 -1
|
@@ -382,6 +382,7 @@ test('AgentCoreStack synthesizes with empty spec', () => {
|
|
|
382
382
|
credentials: [],
|
|
383
383
|
evaluators: [],
|
|
384
384
|
onlineEvalConfigs: [],
|
|
385
|
+
configBundles: [],
|
|
385
386
|
policyEngines: [],
|
|
386
387
|
agentCoreGateways: [],
|
|
387
388
|
mcpRuntimeTools: [],
|
|
@@ -3700,9 +3701,15 @@ Thumbs.db
|
|
|
3700
3701
|
|
|
3701
3702
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/main.py should match snapshot 1`] = `
|
|
3702
3703
|
"import os
|
|
3703
|
-
from
|
|
3704
|
+
from typing import Any
|
|
3705
|
+
|
|
3706
|
+
from langchain_core.messages import HumanMessage{{#if hasConfigBundle}}, SystemMessage{{/if}}
|
|
3704
3707
|
from langgraph.prebuilt import create_react_agent
|
|
3705
3708
|
from langchain.tools import tool
|
|
3709
|
+
{{#if hasConfigBundle}}
|
|
3710
|
+
from langchain_core.callbacks import BaseCallbackHandler
|
|
3711
|
+
from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
|
|
3712
|
+
{{/if}}
|
|
3706
3713
|
from opentelemetry.instrumentation.langchain import LangchainInstrumentor
|
|
3707
3714
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
3708
3715
|
from model.load import load_model
|
|
@@ -3726,6 +3733,14 @@ def get_or_create_model():
|
|
|
3726
3733
|
return _llm
|
|
3727
3734
|
|
|
3728
3735
|
|
|
3736
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
3737
|
+
You are a helpful assistant. Use tools when appropriate.
|
|
3738
|
+
{{#if sessionStorageMountPath}}
|
|
3739
|
+
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
3740
|
+
{{/if}}
|
|
3741
|
+
"""
|
|
3742
|
+
|
|
3743
|
+
|
|
3729
3744
|
# Define a simple function tool
|
|
3730
3745
|
@tool
|
|
3731
3746
|
def add_numbers(a: int, b: int) -> int:
|
|
@@ -3789,13 +3804,28 @@ def list_files(directory: str = "") -> str:
|
|
|
3789
3804
|
tools.extend([file_read, file_write, list_files])
|
|
3790
3805
|
{{/if}}
|
|
3791
3806
|
|
|
3792
|
-
|
|
3793
|
-
You are a helpful assistant. Use tools when appropriate.
|
|
3794
|
-
{{#if sessionStorageMountPath}}
|
|
3795
|
-
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
3796
|
-
{{/if}}
|
|
3797
|
-
"""
|
|
3807
|
+
{{#if hasConfigBundle}}
|
|
3798
3808
|
|
|
3809
|
+
class ConfigBundleCallback(BaseCallbackHandler):
|
|
3810
|
+
"""Injects config bundle values into LangGraph agent at runtime.
|
|
3811
|
+
|
|
3812
|
+
BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
|
|
3813
|
+
for the current runtime ARN from the config bundle service. The SDK caches the
|
|
3814
|
+
result and refreshes on bundle version changes.
|
|
3815
|
+
"""
|
|
3816
|
+
|
|
3817
|
+
def on_chain_start(self, serialized: dict, inputs: dict, **kwargs: Any) -> None:
|
|
3818
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
3819
|
+
prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
|
|
3820
|
+
|
|
3821
|
+
messages = inputs.get("messages", [])
|
|
3822
|
+
if messages and isinstance(messages[0], SystemMessage):
|
|
3823
|
+
messages[0] = SystemMessage(content=prompt)
|
|
3824
|
+
else:
|
|
3825
|
+
messages.insert(0, SystemMessage(content=prompt))
|
|
3826
|
+
inputs["messages"] = messages
|
|
3827
|
+
|
|
3828
|
+
{{/if}}
|
|
3799
3829
|
|
|
3800
3830
|
@app.entrypoint
|
|
3801
3831
|
async def invoke(payload, context):
|
|
@@ -3814,7 +3844,21 @@ async def invoke(payload, context):
|
|
|
3814
3844
|
mcp_tools = await mcp_client.get_tools()
|
|
3815
3845
|
|
|
3816
3846
|
# Define the agent using create_react_agent
|
|
3817
|
-
|
|
3847
|
+
{{#if hasConfigBundle}}
|
|
3848
|
+
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=DEFAULT_SYSTEM_PROMPT)
|
|
3849
|
+
callback = ConfigBundleCallback()
|
|
3850
|
+
|
|
3851
|
+
# Process the user prompt
|
|
3852
|
+
prompt = payload.get("prompt", "What can you help me with?")
|
|
3853
|
+
log.info(f"Agent input: {prompt}")
|
|
3854
|
+
|
|
3855
|
+
# Run the agent with config bundle callback
|
|
3856
|
+
result = await graph.ainvoke(
|
|
3857
|
+
{"messages": [HumanMessage(content=prompt)]},
|
|
3858
|
+
config={"callbacks": [callback]},
|
|
3859
|
+
)
|
|
3860
|
+
{{else}}
|
|
3861
|
+
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=DEFAULT_SYSTEM_PROMPT)
|
|
3818
3862
|
|
|
3819
3863
|
# Process the user prompt
|
|
3820
3864
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
@@ -3822,6 +3866,7 @@ async def invoke(payload, context):
|
|
|
3822
3866
|
|
|
3823
3867
|
# Run the agent
|
|
3824
3868
|
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]})
|
|
3869
|
+
{{/if}}
|
|
3825
3870
|
|
|
3826
3871
|
# Return result
|
|
3827
3872
|
output = result["messages"][-1].content
|
|
@@ -4596,7 +4641,13 @@ Thumbs.db"
|
|
|
4596
4641
|
`;
|
|
4597
4642
|
|
|
4598
4643
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/main.py should match snapshot 1`] = `
|
|
4599
|
-
"from
|
|
4644
|
+
"from typing import Any
|
|
4645
|
+
|
|
4646
|
+
from strands import Agent, tool
|
|
4647
|
+
{{#if hasConfigBundle}}
|
|
4648
|
+
from strands.hooks import HookProvider, HookRegistry, BeforeInvocationEvent, BeforeToolCallEvent
|
|
4649
|
+
from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
|
|
4650
|
+
{{/if}}
|
|
4600
4651
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
4601
4652
|
from model.load import load_model
|
|
4602
4653
|
{{#if hasGateway}}
|
|
@@ -4621,11 +4672,26 @@ mcp_clients = get_all_gateway_mcp_clients()
|
|
|
4621
4672
|
mcp_clients = [get_streamable_http_mcp_client()]
|
|
4622
4673
|
{{/if}}
|
|
4623
4674
|
|
|
4675
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
4676
|
+
You are a helpful assistant. Use tools when appropriate.
|
|
4677
|
+
{{#if sessionStorageMountPath}}
|
|
4678
|
+
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
4679
|
+
{{/if}}
|
|
4680
|
+
"""
|
|
4681
|
+
|
|
4682
|
+
{{#if hasConfigBundle}}
|
|
4683
|
+
DEFAULT_TOOL_DESC = "Return the sum of two numbers"
|
|
4684
|
+
{{/if}}
|
|
4685
|
+
|
|
4624
4686
|
# Define a collection of tools used by the model
|
|
4625
4687
|
tools = []
|
|
4626
4688
|
|
|
4627
4689
|
# Define a simple function tool
|
|
4690
|
+
{{#if hasConfigBundle}}
|
|
4691
|
+
@tool(description=DEFAULT_TOOL_DESC)
|
|
4692
|
+
{{else}}
|
|
4628
4693
|
@tool
|
|
4694
|
+
{{/if}}
|
|
4629
4695
|
def add_numbers(a: int, b: int) -> int:
|
|
4630
4696
|
"""Return the sum of two numbers"""
|
|
4631
4697
|
return a+b
|
|
@@ -4689,12 +4755,39 @@ for mcp_client in mcp_clients:
|
|
|
4689
4755
|
if mcp_client:
|
|
4690
4756
|
tools.append(mcp_client)
|
|
4691
4757
|
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4758
|
+
{{#if hasConfigBundle}}
|
|
4759
|
+
|
|
4760
|
+
class ConfigBundleHook(HookProvider):
|
|
4761
|
+
"""Injects config bundle values (system prompt, tool descriptions) before each invocation.
|
|
4762
|
+
|
|
4763
|
+
BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
|
|
4764
|
+
for the current runtime ARN from the config bundle service. The SDK caches the
|
|
4765
|
+
result and refreshes on bundle version changes.
|
|
4766
|
+
"""
|
|
4767
|
+
|
|
4768
|
+
def register_hooks(self, registry: HookRegistry, **kwargs: Any) -> None:
|
|
4769
|
+
registry.add_callback(BeforeInvocationEvent, self._inject_system_prompt)
|
|
4770
|
+
registry.add_callback(BeforeToolCallEvent, self._override_tool_desc)
|
|
4771
|
+
|
|
4772
|
+
def _inject_system_prompt(self, event: BeforeInvocationEvent) -> None:
|
|
4773
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
4774
|
+
prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
|
|
4775
|
+
|
|
4776
|
+
if prompt != event.agent.system_prompt:
|
|
4777
|
+
event.agent.system_prompt = prompt
|
|
4778
|
+
|
|
4779
|
+
def _override_tool_desc(self, event: BeforeToolCallEvent) -> None:
|
|
4780
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
4781
|
+
tool_descs = config.get("toolDescriptions", {})
|
|
4782
|
+
|
|
4783
|
+
tool_name = event.tool_use["name"]
|
|
4784
|
+
override = tool_descs.get(tool_name)
|
|
4785
|
+
if override and event.selected_tool:
|
|
4786
|
+
spec = event.selected_tool.tool_spec
|
|
4787
|
+
if spec and "description" in spec:
|
|
4788
|
+
spec["description"] = override
|
|
4789
|
+
|
|
4696
4790
|
{{/if}}
|
|
4697
|
-
"""
|
|
4698
4791
|
|
|
4699
4792
|
{{#if hasMemory}}
|
|
4700
4793
|
def agent_factory():
|
|
@@ -4706,13 +4799,23 @@ def agent_factory():
|
|
|
4706
4799
|
cache[key] = Agent(
|
|
4707
4800
|
model=load_model(),
|
|
4708
4801
|
session_manager=get_memory_session_manager(session_id, user_id),
|
|
4709
|
-
system_prompt=
|
|
4710
|
-
tools=tools
|
|
4802
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
4803
|
+
tools=tools{{#if hasConfigBundle}},
|
|
4804
|
+
hooks=[ConfigBundleHook()]{{/if}}
|
|
4711
4805
|
)
|
|
4712
4806
|
return cache[key]
|
|
4713
4807
|
return get_or_create_agent
|
|
4714
4808
|
get_or_create_agent = agent_factory()
|
|
4715
4809
|
{{else}}
|
|
4810
|
+
{{#if hasConfigBundle}}
|
|
4811
|
+
def create_agent():
|
|
4812
|
+
return Agent(
|
|
4813
|
+
model=load_model(),
|
|
4814
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
4815
|
+
tools=tools,
|
|
4816
|
+
hooks=[ConfigBundleHook()],
|
|
4817
|
+
)
|
|
4818
|
+
{{else}}
|
|
4716
4819
|
_agent = None
|
|
4717
4820
|
|
|
4718
4821
|
def get_or_create_agent():
|
|
@@ -4720,11 +4823,12 @@ def get_or_create_agent():
|
|
|
4720
4823
|
if _agent is None:
|
|
4721
4824
|
_agent = Agent(
|
|
4722
4825
|
model=load_model(),
|
|
4723
|
-
system_prompt=
|
|
4826
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
4724
4827
|
tools=tools
|
|
4725
4828
|
)
|
|
4726
4829
|
return _agent
|
|
4727
4830
|
{{/if}}
|
|
4831
|
+
{{/if}}
|
|
4728
4832
|
|
|
4729
4833
|
|
|
4730
4834
|
@app.entrypoint
|
|
@@ -4735,8 +4839,12 @@ async def invoke(payload, context):
|
|
|
4735
4839
|
session_id = getattr(context, 'session_id', 'default-session')
|
|
4736
4840
|
user_id = getattr(context, 'user_id', 'default-user')
|
|
4737
4841
|
agent = get_or_create_agent(session_id, user_id)
|
|
4842
|
+
{{else}}
|
|
4843
|
+
{{#if hasConfigBundle}}
|
|
4844
|
+
agent = create_agent()
|
|
4738
4845
|
{{else}}
|
|
4739
4846
|
agent = get_or_create_agent()
|
|
4847
|
+
{{/if}}
|
|
4740
4848
|
{{/if}}
|
|
4741
4849
|
|
|
4742
4850
|
# Execute and format response
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from langchain_core.messages import HumanMessage{{#if hasConfigBundle}}, SystemMessage{{/if}}
|
|
3
5
|
from langgraph.prebuilt import create_react_agent
|
|
4
6
|
from langchain.tools import tool
|
|
7
|
+
{{#if hasConfigBundle}}
|
|
8
|
+
from langchain_core.callbacks import BaseCallbackHandler
|
|
9
|
+
from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
|
|
10
|
+
{{/if}}
|
|
5
11
|
from opentelemetry.instrumentation.langchain import LangchainInstrumentor
|
|
6
12
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
7
13
|
from model.load import load_model
|
|
@@ -25,6 +31,14 @@ def get_or_create_model():
|
|
|
25
31
|
return _llm
|
|
26
32
|
|
|
27
33
|
|
|
34
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
35
|
+
You are a helpful assistant. Use tools when appropriate.
|
|
36
|
+
{{#if sessionStorageMountPath}}
|
|
37
|
+
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
38
|
+
{{/if}}
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
|
|
28
42
|
# Define a simple function tool
|
|
29
43
|
@tool
|
|
30
44
|
def add_numbers(a: int, b: int) -> int:
|
|
@@ -88,13 +102,28 @@ def list_files(directory: str = "") -> str:
|
|
|
88
102
|
tools.extend([file_read, file_write, list_files])
|
|
89
103
|
{{/if}}
|
|
90
104
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
{{#if hasConfigBundle}}
|
|
106
|
+
|
|
107
|
+
class ConfigBundleCallback(BaseCallbackHandler):
|
|
108
|
+
"""Injects config bundle values into LangGraph agent at runtime.
|
|
109
|
+
|
|
110
|
+
BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
|
|
111
|
+
for the current runtime ARN from the config bundle service. The SDK caches the
|
|
112
|
+
result and refreshes on bundle version changes.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def on_chain_start(self, serialized: dict, inputs: dict, **kwargs: Any) -> None:
|
|
116
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
117
|
+
prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
|
|
97
118
|
|
|
119
|
+
messages = inputs.get("messages", [])
|
|
120
|
+
if messages and isinstance(messages[0], SystemMessage):
|
|
121
|
+
messages[0] = SystemMessage(content=prompt)
|
|
122
|
+
else:
|
|
123
|
+
messages.insert(0, SystemMessage(content=prompt))
|
|
124
|
+
inputs["messages"] = messages
|
|
125
|
+
|
|
126
|
+
{{/if}}
|
|
98
127
|
|
|
99
128
|
@app.entrypoint
|
|
100
129
|
async def invoke(payload, context):
|
|
@@ -113,7 +142,21 @@ async def invoke(payload, context):
|
|
|
113
142
|
mcp_tools = await mcp_client.get_tools()
|
|
114
143
|
|
|
115
144
|
# Define the agent using create_react_agent
|
|
116
|
-
|
|
145
|
+
{{#if hasConfigBundle}}
|
|
146
|
+
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=DEFAULT_SYSTEM_PROMPT)
|
|
147
|
+
callback = ConfigBundleCallback()
|
|
148
|
+
|
|
149
|
+
# Process the user prompt
|
|
150
|
+
prompt = payload.get("prompt", "What can you help me with?")
|
|
151
|
+
log.info(f"Agent input: {prompt}")
|
|
152
|
+
|
|
153
|
+
# Run the agent with config bundle callback
|
|
154
|
+
result = await graph.ainvoke(
|
|
155
|
+
{"messages": [HumanMessage(content=prompt)]},
|
|
156
|
+
config={"callbacks": [callback]},
|
|
157
|
+
)
|
|
158
|
+
{{else}}
|
|
159
|
+
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=DEFAULT_SYSTEM_PROMPT)
|
|
117
160
|
|
|
118
161
|
# Process the user prompt
|
|
119
162
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
@@ -121,6 +164,7 @@ async def invoke(payload, context):
|
|
|
121
164
|
|
|
122
165
|
# Run the agent
|
|
123
166
|
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]})
|
|
167
|
+
{{/if}}
|
|
124
168
|
|
|
125
169
|
# Return result
|
|
126
170
|
output = result["messages"][-1].content
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
from strands import Agent, tool
|
|
4
|
+
{{#if hasConfigBundle}}
|
|
5
|
+
from strands.hooks import HookProvider, HookRegistry, BeforeInvocationEvent, BeforeToolCallEvent
|
|
6
|
+
from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
|
|
7
|
+
{{/if}}
|
|
2
8
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
3
9
|
from model.load import load_model
|
|
4
10
|
{{#if hasGateway}}
|
|
@@ -23,11 +29,26 @@ mcp_clients = get_all_gateway_mcp_clients()
|
|
|
23
29
|
mcp_clients = [get_streamable_http_mcp_client()]
|
|
24
30
|
{{/if}}
|
|
25
31
|
|
|
32
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
33
|
+
You are a helpful assistant. Use tools when appropriate.
|
|
34
|
+
{{#if sessionStorageMountPath}}
|
|
35
|
+
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
36
|
+
{{/if}}
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
{{#if hasConfigBundle}}
|
|
40
|
+
DEFAULT_TOOL_DESC = "Return the sum of two numbers"
|
|
41
|
+
{{/if}}
|
|
42
|
+
|
|
26
43
|
# Define a collection of tools used by the model
|
|
27
44
|
tools = []
|
|
28
45
|
|
|
29
46
|
# Define a simple function tool
|
|
47
|
+
{{#if hasConfigBundle}}
|
|
48
|
+
@tool(description=DEFAULT_TOOL_DESC)
|
|
49
|
+
{{else}}
|
|
30
50
|
@tool
|
|
51
|
+
{{/if}}
|
|
31
52
|
def add_numbers(a: int, b: int) -> int:
|
|
32
53
|
"""Return the sum of two numbers"""
|
|
33
54
|
return a+b
|
|
@@ -91,12 +112,39 @@ for mcp_client in mcp_clients:
|
|
|
91
112
|
if mcp_client:
|
|
92
113
|
tools.append(mcp_client)
|
|
93
114
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
{{#if hasConfigBundle}}
|
|
116
|
+
|
|
117
|
+
class ConfigBundleHook(HookProvider):
|
|
118
|
+
"""Injects config bundle values (system prompt, tool descriptions) before each invocation.
|
|
119
|
+
|
|
120
|
+
BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
|
|
121
|
+
for the current runtime ARN from the config bundle service. The SDK caches the
|
|
122
|
+
result and refreshes on bundle version changes.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def register_hooks(self, registry: HookRegistry, **kwargs: Any) -> None:
|
|
126
|
+
registry.add_callback(BeforeInvocationEvent, self._inject_system_prompt)
|
|
127
|
+
registry.add_callback(BeforeToolCallEvent, self._override_tool_desc)
|
|
128
|
+
|
|
129
|
+
def _inject_system_prompt(self, event: BeforeInvocationEvent) -> None:
|
|
130
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
131
|
+
prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
|
|
132
|
+
|
|
133
|
+
if prompt != event.agent.system_prompt:
|
|
134
|
+
event.agent.system_prompt = prompt
|
|
135
|
+
|
|
136
|
+
def _override_tool_desc(self, event: BeforeToolCallEvent) -> None:
|
|
137
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
138
|
+
tool_descs = config.get("toolDescriptions", {})
|
|
139
|
+
|
|
140
|
+
tool_name = event.tool_use["name"]
|
|
141
|
+
override = tool_descs.get(tool_name)
|
|
142
|
+
if override and event.selected_tool:
|
|
143
|
+
spec = event.selected_tool.tool_spec
|
|
144
|
+
if spec and "description" in spec:
|
|
145
|
+
spec["description"] = override
|
|
146
|
+
|
|
98
147
|
{{/if}}
|
|
99
|
-
"""
|
|
100
148
|
|
|
101
149
|
{{#if hasMemory}}
|
|
102
150
|
def agent_factory():
|
|
@@ -108,13 +156,23 @@ def agent_factory():
|
|
|
108
156
|
cache[key] = Agent(
|
|
109
157
|
model=load_model(),
|
|
110
158
|
session_manager=get_memory_session_manager(session_id, user_id),
|
|
111
|
-
system_prompt=
|
|
112
|
-
tools=tools
|
|
159
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
160
|
+
tools=tools{{#if hasConfigBundle}},
|
|
161
|
+
hooks=[ConfigBundleHook()]{{/if}}
|
|
113
162
|
)
|
|
114
163
|
return cache[key]
|
|
115
164
|
return get_or_create_agent
|
|
116
165
|
get_or_create_agent = agent_factory()
|
|
117
166
|
{{else}}
|
|
167
|
+
{{#if hasConfigBundle}}
|
|
168
|
+
def create_agent():
|
|
169
|
+
return Agent(
|
|
170
|
+
model=load_model(),
|
|
171
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
172
|
+
tools=tools,
|
|
173
|
+
hooks=[ConfigBundleHook()],
|
|
174
|
+
)
|
|
175
|
+
{{else}}
|
|
118
176
|
_agent = None
|
|
119
177
|
|
|
120
178
|
def get_or_create_agent():
|
|
@@ -122,11 +180,12 @@ def get_or_create_agent():
|
|
|
122
180
|
if _agent is None:
|
|
123
181
|
_agent = Agent(
|
|
124
182
|
model=load_model(),
|
|
125
|
-
system_prompt=
|
|
183
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
126
184
|
tools=tools
|
|
127
185
|
)
|
|
128
186
|
return _agent
|
|
129
187
|
{{/if}}
|
|
188
|
+
{{/if}}
|
|
130
189
|
|
|
131
190
|
|
|
132
191
|
@app.entrypoint
|
|
@@ -137,8 +196,12 @@ async def invoke(payload, context):
|
|
|
137
196
|
session_id = getattr(context, 'session_id', 'default-session')
|
|
138
197
|
user_id = getattr(context, 'user_id', 'default-user')
|
|
139
198
|
agent = get_or_create_agent(session_id, user_id)
|
|
199
|
+
{{else}}
|
|
200
|
+
{{#if hasConfigBundle}}
|
|
201
|
+
agent = create_agent()
|
|
140
202
|
{{else}}
|
|
141
203
|
agent = get_or_create_agent()
|
|
204
|
+
{{/if}}
|
|
142
205
|
{{/if}}
|
|
143
206
|
|
|
144
207
|
# Execute and format response
|