@aws/agentcore 1.0.0-preview.5 → 1.0.0-preview.6
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 -9
- 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 +988 -627
- 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 +83 -2
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.js +89 -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/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/harness.d.ts +84 -8
- package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/harness.js +27 -3
- package/dist/schema/schemas/primitives/harness.js.map +1 -1
- 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 +35 -0
- package/dist/schema/schemas/primitives/http-gateway.js.map +1 -0
- package/dist/schema/schemas/primitives/index.d.ts +6 -2
- package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/index.js +17 -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 +2 -2
- package/scripts/bundle.mjs +5 -2
- 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
|
@@ -443,6 +443,7 @@ test('AgentCoreStack synthesizes with empty spec', () => {
|
|
|
443
443
|
credentials: [],
|
|
444
444
|
evaluators: [],
|
|
445
445
|
onlineEvalConfigs: [],
|
|
446
|
+
configBundles: [],
|
|
446
447
|
policyEngines: [],
|
|
447
448
|
agentCoreGateways: [],
|
|
448
449
|
mcpRuntimeTools: [],
|
|
@@ -3762,9 +3763,15 @@ Thumbs.db
|
|
|
3762
3763
|
|
|
3763
3764
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/main.py should match snapshot 1`] = `
|
|
3764
3765
|
"import os
|
|
3765
|
-
from
|
|
3766
|
+
from typing import Any
|
|
3767
|
+
|
|
3768
|
+
from langchain_core.messages import HumanMessage{{#if hasConfigBundle}}, SystemMessage{{/if}}
|
|
3766
3769
|
from langgraph.prebuilt import create_react_agent
|
|
3767
3770
|
from langchain.tools import tool
|
|
3771
|
+
{{#if hasConfigBundle}}
|
|
3772
|
+
from langchain_core.callbacks import BaseCallbackHandler
|
|
3773
|
+
from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
|
|
3774
|
+
{{/if}}
|
|
3768
3775
|
from opentelemetry.instrumentation.langchain import LangchainInstrumentor
|
|
3769
3776
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
3770
3777
|
from model.load import load_model
|
|
@@ -3788,6 +3795,14 @@ def get_or_create_model():
|
|
|
3788
3795
|
return _llm
|
|
3789
3796
|
|
|
3790
3797
|
|
|
3798
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
3799
|
+
You are a helpful assistant. Use tools when appropriate.
|
|
3800
|
+
{{#if sessionStorageMountPath}}
|
|
3801
|
+
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
3802
|
+
{{/if}}
|
|
3803
|
+
"""
|
|
3804
|
+
|
|
3805
|
+
|
|
3791
3806
|
# Define a simple function tool
|
|
3792
3807
|
@tool
|
|
3793
3808
|
def add_numbers(a: int, b: int) -> int:
|
|
@@ -3851,13 +3866,28 @@ def list_files(directory: str = "") -> str:
|
|
|
3851
3866
|
tools.extend([file_read, file_write, list_files])
|
|
3852
3867
|
{{/if}}
|
|
3853
3868
|
|
|
3854
|
-
|
|
3855
|
-
You are a helpful assistant. Use tools when appropriate.
|
|
3856
|
-
{{#if sessionStorageMountPath}}
|
|
3857
|
-
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
3858
|
-
{{/if}}
|
|
3859
|
-
"""
|
|
3869
|
+
{{#if hasConfigBundle}}
|
|
3860
3870
|
|
|
3871
|
+
class ConfigBundleCallback(BaseCallbackHandler):
|
|
3872
|
+
"""Injects config bundle values into LangGraph agent at runtime.
|
|
3873
|
+
|
|
3874
|
+
BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
|
|
3875
|
+
for the current runtime ARN from the config bundle service. The SDK caches the
|
|
3876
|
+
result and refreshes on bundle version changes.
|
|
3877
|
+
"""
|
|
3878
|
+
|
|
3879
|
+
def on_chain_start(self, serialized: dict, inputs: dict, **kwargs: Any) -> None:
|
|
3880
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
3881
|
+
prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
|
|
3882
|
+
|
|
3883
|
+
messages = inputs.get("messages", [])
|
|
3884
|
+
if messages and isinstance(messages[0], SystemMessage):
|
|
3885
|
+
messages[0] = SystemMessage(content=prompt)
|
|
3886
|
+
else:
|
|
3887
|
+
messages.insert(0, SystemMessage(content=prompt))
|
|
3888
|
+
inputs["messages"] = messages
|
|
3889
|
+
|
|
3890
|
+
{{/if}}
|
|
3861
3891
|
|
|
3862
3892
|
@app.entrypoint
|
|
3863
3893
|
async def invoke(payload, context):
|
|
@@ -3876,7 +3906,21 @@ async def invoke(payload, context):
|
|
|
3876
3906
|
mcp_tools = await mcp_client.get_tools()
|
|
3877
3907
|
|
|
3878
3908
|
# Define the agent using create_react_agent
|
|
3879
|
-
|
|
3909
|
+
{{#if hasConfigBundle}}
|
|
3910
|
+
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=DEFAULT_SYSTEM_PROMPT)
|
|
3911
|
+
callback = ConfigBundleCallback()
|
|
3912
|
+
|
|
3913
|
+
# Process the user prompt
|
|
3914
|
+
prompt = payload.get("prompt", "What can you help me with?")
|
|
3915
|
+
log.info(f"Agent input: {prompt}")
|
|
3916
|
+
|
|
3917
|
+
# Run the agent with config bundle callback
|
|
3918
|
+
result = await graph.ainvoke(
|
|
3919
|
+
{"messages": [HumanMessage(content=prompt)]},
|
|
3920
|
+
config={"callbacks": [callback]},
|
|
3921
|
+
)
|
|
3922
|
+
{{else}}
|
|
3923
|
+
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=DEFAULT_SYSTEM_PROMPT)
|
|
3880
3924
|
|
|
3881
3925
|
# Process the user prompt
|
|
3882
3926
|
prompt = payload.get("prompt", "What can you help me with?")
|
|
@@ -3884,6 +3928,7 @@ async def invoke(payload, context):
|
|
|
3884
3928
|
|
|
3885
3929
|
# Run the agent
|
|
3886
3930
|
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]})
|
|
3931
|
+
{{/if}}
|
|
3887
3932
|
|
|
3888
3933
|
# Return result
|
|
3889
3934
|
output = result["messages"][-1].content
|
|
@@ -4658,7 +4703,13 @@ Thumbs.db"
|
|
|
4658
4703
|
`;
|
|
4659
4704
|
|
|
4660
4705
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/main.py should match snapshot 1`] = `
|
|
4661
|
-
"from
|
|
4706
|
+
"from typing import Any
|
|
4707
|
+
|
|
4708
|
+
from strands import Agent, tool
|
|
4709
|
+
{{#if hasConfigBundle}}
|
|
4710
|
+
from strands.hooks import HookProvider, HookRegistry, BeforeInvocationEvent, BeforeToolCallEvent
|
|
4711
|
+
from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
|
|
4712
|
+
{{/if}}
|
|
4662
4713
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
4663
4714
|
from model.load import load_model
|
|
4664
4715
|
{{#if hasGateway}}
|
|
@@ -4683,11 +4734,26 @@ mcp_clients = get_all_gateway_mcp_clients()
|
|
|
4683
4734
|
mcp_clients = [get_streamable_http_mcp_client()]
|
|
4684
4735
|
{{/if}}
|
|
4685
4736
|
|
|
4737
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
4738
|
+
You are a helpful assistant. Use tools when appropriate.
|
|
4739
|
+
{{#if sessionStorageMountPath}}
|
|
4740
|
+
You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
|
|
4741
|
+
{{/if}}
|
|
4742
|
+
"""
|
|
4743
|
+
|
|
4744
|
+
{{#if hasConfigBundle}}
|
|
4745
|
+
DEFAULT_TOOL_DESC = "Return the sum of two numbers"
|
|
4746
|
+
{{/if}}
|
|
4747
|
+
|
|
4686
4748
|
# Define a collection of tools used by the model
|
|
4687
4749
|
tools = []
|
|
4688
4750
|
|
|
4689
4751
|
# Define a simple function tool
|
|
4752
|
+
{{#if hasConfigBundle}}
|
|
4753
|
+
@tool(description=DEFAULT_TOOL_DESC)
|
|
4754
|
+
{{else}}
|
|
4690
4755
|
@tool
|
|
4756
|
+
{{/if}}
|
|
4691
4757
|
def add_numbers(a: int, b: int) -> int:
|
|
4692
4758
|
"""Return the sum of two numbers"""
|
|
4693
4759
|
return a+b
|
|
@@ -4751,12 +4817,39 @@ for mcp_client in mcp_clients:
|
|
|
4751
4817
|
if mcp_client:
|
|
4752
4818
|
tools.append(mcp_client)
|
|
4753
4819
|
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4820
|
+
{{#if hasConfigBundle}}
|
|
4821
|
+
|
|
4822
|
+
class ConfigBundleHook(HookProvider):
|
|
4823
|
+
"""Injects config bundle values (system prompt, tool descriptions) before each invocation.
|
|
4824
|
+
|
|
4825
|
+
BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
|
|
4826
|
+
for the current runtime ARN from the config bundle service. The SDK caches the
|
|
4827
|
+
result and refreshes on bundle version changes.
|
|
4828
|
+
"""
|
|
4829
|
+
|
|
4830
|
+
def register_hooks(self, registry: HookRegistry, **kwargs: Any) -> None:
|
|
4831
|
+
registry.add_callback(BeforeInvocationEvent, self._inject_system_prompt)
|
|
4832
|
+
registry.add_callback(BeforeToolCallEvent, self._override_tool_desc)
|
|
4833
|
+
|
|
4834
|
+
def _inject_system_prompt(self, event: BeforeInvocationEvent) -> None:
|
|
4835
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
4836
|
+
prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
|
|
4837
|
+
|
|
4838
|
+
if prompt != event.agent.system_prompt:
|
|
4839
|
+
event.agent.system_prompt = prompt
|
|
4840
|
+
|
|
4841
|
+
def _override_tool_desc(self, event: BeforeToolCallEvent) -> None:
|
|
4842
|
+
config = BedrockAgentCoreContext.get_config_bundle()
|
|
4843
|
+
tool_descs = config.get("toolDescriptions", {})
|
|
4844
|
+
|
|
4845
|
+
tool_name = event.tool_use["name"]
|
|
4846
|
+
override = tool_descs.get(tool_name)
|
|
4847
|
+
if override and event.selected_tool:
|
|
4848
|
+
spec = event.selected_tool.tool_spec
|
|
4849
|
+
if spec and "description" in spec:
|
|
4850
|
+
spec["description"] = override
|
|
4851
|
+
|
|
4758
4852
|
{{/if}}
|
|
4759
|
-
"""
|
|
4760
4853
|
|
|
4761
4854
|
{{#if hasMemory}}
|
|
4762
4855
|
def agent_factory():
|
|
@@ -4768,13 +4861,23 @@ def agent_factory():
|
|
|
4768
4861
|
cache[key] = Agent(
|
|
4769
4862
|
model=load_model(),
|
|
4770
4863
|
session_manager=get_memory_session_manager(session_id, user_id),
|
|
4771
|
-
system_prompt=
|
|
4772
|
-
tools=tools
|
|
4864
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
4865
|
+
tools=tools{{#if hasConfigBundle}},
|
|
4866
|
+
hooks=[ConfigBundleHook()]{{/if}}
|
|
4773
4867
|
)
|
|
4774
4868
|
return cache[key]
|
|
4775
4869
|
return get_or_create_agent
|
|
4776
4870
|
get_or_create_agent = agent_factory()
|
|
4777
4871
|
{{else}}
|
|
4872
|
+
{{#if hasConfigBundle}}
|
|
4873
|
+
def create_agent():
|
|
4874
|
+
return Agent(
|
|
4875
|
+
model=load_model(),
|
|
4876
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
4877
|
+
tools=tools,
|
|
4878
|
+
hooks=[ConfigBundleHook()],
|
|
4879
|
+
)
|
|
4880
|
+
{{else}}
|
|
4778
4881
|
_agent = None
|
|
4779
4882
|
|
|
4780
4883
|
def get_or_create_agent():
|
|
@@ -4782,11 +4885,12 @@ def get_or_create_agent():
|
|
|
4782
4885
|
if _agent is None:
|
|
4783
4886
|
_agent = Agent(
|
|
4784
4887
|
model=load_model(),
|
|
4785
|
-
system_prompt=
|
|
4888
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
4786
4889
|
tools=tools
|
|
4787
4890
|
)
|
|
4788
4891
|
return _agent
|
|
4789
4892
|
{{/if}}
|
|
4893
|
+
{{/if}}
|
|
4790
4894
|
|
|
4791
4895
|
|
|
4792
4896
|
@app.entrypoint
|
|
@@ -4797,8 +4901,12 @@ async def invoke(payload, context):
|
|
|
4797
4901
|
session_id = getattr(context, 'session_id', 'default-session')
|
|
4798
4902
|
user_id = getattr(context, 'user_id', 'default-user')
|
|
4799
4903
|
agent = get_or_create_agent(session_id, user_id)
|
|
4904
|
+
{{else}}
|
|
4905
|
+
{{#if hasConfigBundle}}
|
|
4906
|
+
agent = create_agent()
|
|
4800
4907
|
{{else}}
|
|
4801
4908
|
agent = get_or_create_agent()
|
|
4909
|
+
{{/if}}
|
|
4802
4910
|
{{/if}}
|
|
4803
4911
|
|
|
4804
4912
|
# 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
|