@aws/agentcore 1.0.0-preview.11 → 1.0.0-preview.12
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/agent-inspector/index.css +1 -1
- package/dist/agent-inspector/index.js +83 -78
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +446 -144
- package/dist/assets/cdk/bin/cdk.ts +4 -0
- package/dist/assets/cdk/lib/cdk-stack.ts +2 -0
- package/dist/assets/cdk/package.json +1 -1
- package/dist/assets/python/a2a/googleadk/base/main.py +24 -16
- package/dist/assets/python/a2a/langchain_langgraph/base/main.py +24 -16
- package/dist/assets/python/a2a/strands/base/main.py +23 -17
- package/dist/assets/python/agui/googleadk/base/main.py +62 -2
- package/dist/assets/python/agui/langchain_langgraph/base/main.py +56 -0
- package/dist/assets/python/agui/strands/base/main.py +63 -1
- package/dist/assets/python/http/autogen/base/main.py +27 -19
- package/dist/assets/python/http/googleadk/base/main.py +24 -16
- package/dist/assets/python/http/langchain_langgraph/base/main.py +24 -16
- package/dist/assets/python/http/openaiagents/base/main.py +24 -16
- package/dist/assets/python/http/strands/base/main.py +23 -17
- package/dist/assets/python/mcp/standalone/base/main.py +58 -0
- package/dist/cli/index.mjs +685 -639
- package/dist/lib/errors/types.d.ts +3 -0
- package/dist/lib/errors/types.d.ts.map +1 -1
- package/dist/lib/errors/types.js +10 -1
- package/dist/lib/errors/types.js.map +1 -1
- package/dist/lib/errors/zod.js +1 -1
- package/dist/lib/errors/zod.js.map +1 -1
- package/dist/lib/result.d.ts +6 -4
- package/dist/lib/result.d.ts.map +1 -1
- package/dist/lib/result.js +7 -0
- package/dist/lib/result.js.map +1 -1
- package/dist/schema/schemas/agent-env.d.ts +50 -4
- package/dist/schema/schemas/agent-env.d.ts.map +1 -1
- package/dist/schema/schemas/agent-env.js +102 -4
- package/dist/schema/schemas/agent-env.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +12 -2
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/harness.d.ts +8 -0
- package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/harness.js +23 -0
- package/dist/schema/schemas/primitives/harness.js.map +1 -1
- package/npm-shrinkwrap.json +281 -366
- package/package.json +12 -7
|
@@ -111,6 +111,8 @@ async function main() {
|
|
|
111
111
|
codeLocation?: string;
|
|
112
112
|
tools?: { type: string; name: string }[];
|
|
113
113
|
apiKeyArn?: string;
|
|
114
|
+
efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
115
|
+
s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
114
116
|
}[] = [];
|
|
115
117
|
for (const entry of specAny.harnesses ?? []) {
|
|
116
118
|
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
@@ -127,6 +129,8 @@ async function main() {
|
|
|
127
129
|
codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
|
|
128
130
|
tools: harnessSpec.tools,
|
|
129
131
|
apiKeyArn: harnessSpec.model?.apiKeyArn,
|
|
132
|
+
efsAccessPoints: harnessSpec.efsAccessPoints,
|
|
133
|
+
s3AccessPoints: harnessSpec.s3AccessPoints,
|
|
130
134
|
});
|
|
131
135
|
} catch (err) {
|
|
132
136
|
throw new Error(
|
|
@@ -312,6 +316,8 @@ export interface HarnessConfig {
|
|
|
312
316
|
codeLocation?: string;
|
|
313
317
|
tools?: { type: string; name: string }[];
|
|
314
318
|
apiKeyArn?: string;
|
|
319
|
+
efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
320
|
+
s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
315
321
|
}
|
|
316
322
|
|
|
317
323
|
export interface AgentCoreStackProps extends StackProps {
|
|
@@ -408,7 +414,7 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/package.json should m
|
|
|
408
414
|
"@types/node": "^24.10.1",
|
|
409
415
|
"jest": "^29.7.0",
|
|
410
416
|
"ts-jest": "^29.2.5",
|
|
411
|
-
"aws-cdk": "2.
|
|
417
|
+
"aws-cdk": "2.1126.0",
|
|
412
418
|
"prettier": "^3.4.2",
|
|
413
419
|
"typescript": "~5.9.3"
|
|
414
420
|
},
|
|
@@ -1063,7 +1069,9 @@ Thumbs.db
|
|
|
1063
1069
|
`;
|
|
1064
1070
|
|
|
1065
1071
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/main.py should match snapshot 1`] = `
|
|
1066
|
-
"
|
|
1072
|
+
"{{#if needsOs}}
|
|
1073
|
+
import os
|
|
1074
|
+
{{/if}}
|
|
1067
1075
|
from google.adk.agents import Agent
|
|
1068
1076
|
from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
|
|
1069
1077
|
from google.adk.runners import Runner
|
|
@@ -1082,18 +1090,21 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
1082
1090
|
|
|
1083
1091
|
tools = [add_numbers]
|
|
1084
1092
|
|
|
1085
|
-
{{#if
|
|
1086
|
-
|
|
1093
|
+
{{#if needsOs}}
|
|
1094
|
+
_MOUNT_PATHS = [
|
|
1095
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
1096
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
1097
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
1098
|
+
]
|
|
1087
1099
|
|
|
1088
1100
|
def _safe_resolve(path: str) -> str:
|
|
1089
|
-
|
|
1090
|
-
resolved
|
|
1091
|
-
|
|
1092
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
1101
|
+
resolved = os.path.realpath(path)
|
|
1102
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
1103
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
1093
1104
|
return resolved
|
|
1094
1105
|
|
|
1095
1106
|
def file_read(path: str) -> str:
|
|
1096
|
-
"""Read a file from
|
|
1107
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
1097
1108
|
try:
|
|
1098
1109
|
full_path = _safe_resolve(path)
|
|
1099
1110
|
with open(full_path) as f:
|
|
@@ -1104,7 +1115,7 @@ def file_read(path: str) -> str:
|
|
|
1104
1115
|
return f"Error reading '{path}': {e.strerror}"
|
|
1105
1116
|
|
|
1106
1117
|
def file_write(path: str, content: str) -> str:
|
|
1107
|
-
"""Write
|
|
1118
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
1108
1119
|
try:
|
|
1109
1120
|
full_path = _safe_resolve(path)
|
|
1110
1121
|
parent = os.path.dirname(full_path)
|
|
@@ -1118,25 +1129,28 @@ def file_write(path: str, content: str) -> str:
|
|
|
1118
1129
|
except OSError as e:
|
|
1119
1130
|
return f"Error writing '{path}': {e.strerror}"
|
|
1120
1131
|
|
|
1121
|
-
def list_files(
|
|
1122
|
-
"""List files in
|
|
1132
|
+
def list_files(path: str) -> str:
|
|
1133
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
1123
1134
|
try:
|
|
1124
|
-
|
|
1125
|
-
entries = os.listdir(
|
|
1135
|
+
full_path = _safe_resolve(path)
|
|
1136
|
+
entries = os.listdir(full_path)
|
|
1126
1137
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
1127
1138
|
except ValueError as e:
|
|
1128
1139
|
return str(e)
|
|
1129
1140
|
except OSError as e:
|
|
1130
|
-
return f"Error listing '{
|
|
1141
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
1131
1142
|
|
|
1132
1143
|
tools.extend([file_read, file_write, list_files])
|
|
1133
1144
|
{{/if}}
|
|
1134
1145
|
|
|
1135
1146
|
AGENT_INSTRUCTION = """
|
|
1136
1147
|
You are a helpful assistant. Use tools when appropriate.
|
|
1137
|
-
{{#if
|
|
1138
|
-
You have
|
|
1139
|
-
{{
|
|
1148
|
+
{{#if needsOs}}
|
|
1149
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
1150
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
1151
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
1152
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
1153
|
+
{{/each}}{{/if}}
|
|
1140
1154
|
"""
|
|
1141
1155
|
|
|
1142
1156
|
agent = Agent(
|
|
@@ -1322,7 +1336,9 @@ Thumbs.db
|
|
|
1322
1336
|
`;
|
|
1323
1337
|
|
|
1324
1338
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/main.py should match snapshot 1`] = `
|
|
1325
|
-
"
|
|
1339
|
+
"{{#if needsOs}}
|
|
1340
|
+
import os
|
|
1341
|
+
{{/if}}
|
|
1326
1342
|
from langchain_core.tools import tool
|
|
1327
1343
|
from langgraph.prebuilt import create_react_agent
|
|
1328
1344
|
from opentelemetry.instrumentation.langchain import LangchainInstrumentor
|
|
@@ -1345,19 +1361,22 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
1345
1361
|
|
|
1346
1362
|
tools = [add_numbers]
|
|
1347
1363
|
|
|
1348
|
-
{{#if
|
|
1349
|
-
|
|
1364
|
+
{{#if needsOs}}
|
|
1365
|
+
_MOUNT_PATHS = [
|
|
1366
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
1367
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
1368
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
1369
|
+
]
|
|
1350
1370
|
|
|
1351
1371
|
def _safe_resolve(path: str) -> str:
|
|
1352
|
-
|
|
1353
|
-
resolved
|
|
1354
|
-
|
|
1355
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
1372
|
+
resolved = os.path.realpath(path)
|
|
1373
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
1374
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
1356
1375
|
return resolved
|
|
1357
1376
|
|
|
1358
1377
|
@tool
|
|
1359
1378
|
def file_read(path: str) -> str:
|
|
1360
|
-
"""Read a file from
|
|
1379
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
1361
1380
|
try:
|
|
1362
1381
|
full_path = _safe_resolve(path)
|
|
1363
1382
|
with open(full_path) as f:
|
|
@@ -1369,7 +1388,7 @@ def file_read(path: str) -> str:
|
|
|
1369
1388
|
|
|
1370
1389
|
@tool
|
|
1371
1390
|
def file_write(path: str, content: str) -> str:
|
|
1372
|
-
"""Write
|
|
1391
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
1373
1392
|
try:
|
|
1374
1393
|
full_path = _safe_resolve(path)
|
|
1375
1394
|
parent = os.path.dirname(full_path)
|
|
@@ -1384,25 +1403,28 @@ def file_write(path: str, content: str) -> str:
|
|
|
1384
1403
|
return f"Error writing '{path}': {e.strerror}"
|
|
1385
1404
|
|
|
1386
1405
|
@tool
|
|
1387
|
-
def list_files(
|
|
1388
|
-
"""List files in
|
|
1406
|
+
def list_files(path: str) -> str:
|
|
1407
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
1389
1408
|
try:
|
|
1390
|
-
|
|
1391
|
-
entries = os.listdir(
|
|
1409
|
+
full_path = _safe_resolve(path)
|
|
1410
|
+
entries = os.listdir(full_path)
|
|
1392
1411
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
1393
1412
|
except ValueError as e:
|
|
1394
1413
|
return str(e)
|
|
1395
1414
|
except OSError as e:
|
|
1396
|
-
return f"Error listing '{
|
|
1415
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
1397
1416
|
|
|
1398
1417
|
tools.extend([file_read, file_write, list_files])
|
|
1399
1418
|
{{/if}}
|
|
1400
1419
|
|
|
1401
1420
|
SYSTEM_PROMPT = """
|
|
1402
1421
|
You are a helpful assistant. Use tools when appropriate.
|
|
1403
|
-
{{#if
|
|
1404
|
-
You have
|
|
1405
|
-
{{
|
|
1422
|
+
{{#if needsOs}}
|
|
1423
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
1424
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
1425
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
1426
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
1427
|
+
{{/each}}{{/if}}
|
|
1406
1428
|
"""
|
|
1407
1429
|
|
|
1408
1430
|
model = load_model()
|
|
@@ -1696,7 +1718,7 @@ from model.load import load_model
|
|
|
1696
1718
|
{{#if hasMemory}}
|
|
1697
1719
|
from memory.session import get_memory_session_manager
|
|
1698
1720
|
{{/if}}
|
|
1699
|
-
{{#if
|
|
1721
|
+
{{#if needsOs}}
|
|
1700
1722
|
import os
|
|
1701
1723
|
{{/if}}
|
|
1702
1724
|
|
|
@@ -1709,19 +1731,22 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
1709
1731
|
|
|
1710
1732
|
tools = [add_numbers]
|
|
1711
1733
|
|
|
1712
|
-
{{#if
|
|
1713
|
-
|
|
1734
|
+
{{#if needsOs}}
|
|
1735
|
+
_MOUNT_PATHS = [
|
|
1736
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
1737
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
1738
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
1739
|
+
]
|
|
1714
1740
|
|
|
1715
1741
|
def _safe_resolve(path: str) -> str:
|
|
1716
|
-
|
|
1717
|
-
resolved
|
|
1718
|
-
|
|
1719
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
1742
|
+
resolved = os.path.realpath(path)
|
|
1743
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
1744
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
1720
1745
|
return resolved
|
|
1721
1746
|
|
|
1722
1747
|
@tool
|
|
1723
1748
|
def file_read(path: str) -> str:
|
|
1724
|
-
"""Read a file from
|
|
1749
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
1725
1750
|
try:
|
|
1726
1751
|
full_path = _safe_resolve(path)
|
|
1727
1752
|
with open(full_path) as f:
|
|
@@ -1733,7 +1758,7 @@ def file_read(path: str) -> str:
|
|
|
1733
1758
|
|
|
1734
1759
|
@tool
|
|
1735
1760
|
def file_write(path: str, content: str) -> str:
|
|
1736
|
-
"""Write
|
|
1761
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
1737
1762
|
try:
|
|
1738
1763
|
full_path = _safe_resolve(path)
|
|
1739
1764
|
parent = os.path.dirname(full_path)
|
|
@@ -1748,25 +1773,28 @@ def file_write(path: str, content: str) -> str:
|
|
|
1748
1773
|
return f"Error writing '{path}': {e.strerror}"
|
|
1749
1774
|
|
|
1750
1775
|
@tool
|
|
1751
|
-
def list_files(
|
|
1752
|
-
"""List files in
|
|
1776
|
+
def list_files(path: str) -> str:
|
|
1777
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
1753
1778
|
try:
|
|
1754
|
-
|
|
1755
|
-
entries = os.listdir(
|
|
1779
|
+
full_path = _safe_resolve(path)
|
|
1780
|
+
entries = os.listdir(full_path)
|
|
1756
1781
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
1757
1782
|
except ValueError as e:
|
|
1758
1783
|
return str(e)
|
|
1759
1784
|
except OSError as e:
|
|
1760
|
-
return f"Error listing '{
|
|
1785
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
1761
1786
|
|
|
1762
1787
|
tools.extend([file_read, file_write, list_files])
|
|
1763
1788
|
{{/if}}
|
|
1764
1789
|
|
|
1765
1790
|
SYSTEM_PROMPT = """
|
|
1766
1791
|
You are a helpful assistant. Use tools when appropriate.
|
|
1767
|
-
{{#if
|
|
1768
|
-
You have
|
|
1769
|
-
{{
|
|
1792
|
+
{{#if needsOs}}
|
|
1793
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
1794
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
1795
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
1796
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
1797
|
+
{{/each}}{{/if}}
|
|
1770
1798
|
"""
|
|
1771
1799
|
|
|
1772
1800
|
{{#if hasMemory}}
|
|
@@ -2093,16 +2121,76 @@ exports[`Assets Directory Snapshots > Python framework assets > python/python/ag
|
|
|
2093
2121
|
"import os
|
|
2094
2122
|
import uvicorn
|
|
2095
2123
|
from google.adk.agents import LlmAgent
|
|
2124
|
+
from google.adk.tools import FunctionTool
|
|
2096
2125
|
from ag_ui_adk import ADKAgent, AGUIToolset, create_adk_app
|
|
2097
2126
|
from model.load import load_model
|
|
2098
2127
|
|
|
2099
2128
|
load_model()
|
|
2100
2129
|
|
|
2130
|
+
{{#if needsOs}}
|
|
2131
|
+
_MOUNT_PATHS = [
|
|
2132
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
2133
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
2134
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
2135
|
+
]
|
|
2136
|
+
|
|
2137
|
+
def _safe_resolve(path: str) -> str:
|
|
2138
|
+
resolved = os.path.realpath(path)
|
|
2139
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
2140
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
2141
|
+
return resolved
|
|
2142
|
+
|
|
2143
|
+
def file_read(path: str) -> str:
|
|
2144
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2145
|
+
try:
|
|
2146
|
+
full_path = _safe_resolve(path)
|
|
2147
|
+
with open(full_path) as f:
|
|
2148
|
+
return f.read()
|
|
2149
|
+
except ValueError as e:
|
|
2150
|
+
return str(e)
|
|
2151
|
+
except OSError as e:
|
|
2152
|
+
return f"Error reading '{path}': {e.strerror}"
|
|
2153
|
+
|
|
2154
|
+
def file_write(path: str, content: str) -> str:
|
|
2155
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2156
|
+
try:
|
|
2157
|
+
full_path = _safe_resolve(path)
|
|
2158
|
+
parent = os.path.dirname(full_path)
|
|
2159
|
+
if parent:
|
|
2160
|
+
os.makedirs(parent, exist_ok=True)
|
|
2161
|
+
with open(full_path, "w") as f:
|
|
2162
|
+
f.write(content)
|
|
2163
|
+
return f"Written to {path}"
|
|
2164
|
+
except ValueError as e:
|
|
2165
|
+
return str(e)
|
|
2166
|
+
except OSError as e:
|
|
2167
|
+
return f"Error writing '{path}': {e.strerror}"
|
|
2168
|
+
|
|
2169
|
+
def list_files(path: str) -> str:
|
|
2170
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
2171
|
+
try:
|
|
2172
|
+
full_path = _safe_resolve(path)
|
|
2173
|
+
entries = os.listdir(full_path)
|
|
2174
|
+
return "\\n".join(entries) if entries else "(empty directory)"
|
|
2175
|
+
except ValueError as e:
|
|
2176
|
+
return str(e)
|
|
2177
|
+
except OSError as e:
|
|
2178
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
2179
|
+
|
|
2180
|
+
_fs_tools = [FunctionTool(file_read), FunctionTool(file_write), FunctionTool(list_files)]
|
|
2181
|
+
{{/if}}
|
|
2182
|
+
|
|
2101
2183
|
agent = LlmAgent(
|
|
2102
2184
|
name="{{ name }}",
|
|
2103
2185
|
model="gemini-2.5-flash",
|
|
2104
|
-
instruction="You are a helpful assistant.
|
|
2105
|
-
|
|
2186
|
+
instruction="""You are a helpful assistant.
|
|
2187
|
+
{{#if needsOs}}
|
|
2188
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
2189
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
2190
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
2191
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
2192
|
+
{{/each}}{{/if}}""",
|
|
2193
|
+
tools=[AGUIToolset(), {{#if needsOs}}*_fs_tools{{/if}}],
|
|
2106
2194
|
)
|
|
2107
2195
|
|
|
2108
2196
|
adk_agent = ADKAgent(
|
|
@@ -2301,6 +2389,62 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
2301
2389
|
|
|
2302
2390
|
|
|
2303
2391
|
backend_tools = [add_numbers]
|
|
2392
|
+
|
|
2393
|
+
{{#if needsOs}}
|
|
2394
|
+
_MOUNT_PATHS = [
|
|
2395
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
2396
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
2397
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
2398
|
+
]
|
|
2399
|
+
|
|
2400
|
+
def _safe_resolve(path: str) -> str:
|
|
2401
|
+
resolved = os.path.realpath(path)
|
|
2402
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
2403
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
2404
|
+
return resolved
|
|
2405
|
+
|
|
2406
|
+
@tool
|
|
2407
|
+
def file_read(path: str) -> str:
|
|
2408
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2409
|
+
try:
|
|
2410
|
+
full_path = _safe_resolve(path)
|
|
2411
|
+
with open(full_path) as f:
|
|
2412
|
+
return f.read()
|
|
2413
|
+
except ValueError as e:
|
|
2414
|
+
return str(e)
|
|
2415
|
+
except OSError as e:
|
|
2416
|
+
return f"Error reading '{path}': {e.strerror}"
|
|
2417
|
+
|
|
2418
|
+
@tool
|
|
2419
|
+
def file_write(path: str, content: str) -> str:
|
|
2420
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2421
|
+
try:
|
|
2422
|
+
full_path = _safe_resolve(path)
|
|
2423
|
+
parent = os.path.dirname(full_path)
|
|
2424
|
+
if parent:
|
|
2425
|
+
os.makedirs(parent, exist_ok=True)
|
|
2426
|
+
with open(full_path, "w") as f:
|
|
2427
|
+
f.write(content)
|
|
2428
|
+
return f"Written to {path}"
|
|
2429
|
+
except ValueError as e:
|
|
2430
|
+
return str(e)
|
|
2431
|
+
except OSError as e:
|
|
2432
|
+
return f"Error writing '{path}': {e.strerror}"
|
|
2433
|
+
|
|
2434
|
+
@tool
|
|
2435
|
+
def list_files(path: str) -> str:
|
|
2436
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
2437
|
+
try:
|
|
2438
|
+
full_path = _safe_resolve(path)
|
|
2439
|
+
entries = os.listdir(full_path)
|
|
2440
|
+
return "\\n".join(entries) if entries else "(empty directory)"
|
|
2441
|
+
except ValueError as e:
|
|
2442
|
+
return str(e)
|
|
2443
|
+
except OSError as e:
|
|
2444
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
2445
|
+
|
|
2446
|
+
backend_tools.extend([file_read, file_write, list_files])
|
|
2447
|
+
{{/if}}
|
|
2304
2448
|
model = load_model()
|
|
2305
2449
|
|
|
2306
2450
|
|
|
@@ -2613,9 +2757,71 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
2613
2757
|
|
|
2614
2758
|
tools = [add_numbers]
|
|
2615
2759
|
|
|
2760
|
+
{{#if needsOs}}
|
|
2761
|
+
_MOUNT_PATHS = [
|
|
2762
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
2763
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
2764
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
2765
|
+
]
|
|
2766
|
+
|
|
2767
|
+
def _safe_resolve(path: str) -> str:
|
|
2768
|
+
resolved = os.path.realpath(path)
|
|
2769
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
2770
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
2771
|
+
return resolved
|
|
2772
|
+
|
|
2773
|
+
@tool
|
|
2774
|
+
def file_read(path: str) -> str:
|
|
2775
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2776
|
+
try:
|
|
2777
|
+
full_path = _safe_resolve(path)
|
|
2778
|
+
with open(full_path) as f:
|
|
2779
|
+
return f.read()
|
|
2780
|
+
except ValueError as e:
|
|
2781
|
+
return str(e)
|
|
2782
|
+
except OSError as e:
|
|
2783
|
+
return f"Error reading '{path}': {e.strerror}"
|
|
2784
|
+
|
|
2785
|
+
@tool
|
|
2786
|
+
def file_write(path: str, content: str) -> str:
|
|
2787
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2788
|
+
try:
|
|
2789
|
+
full_path = _safe_resolve(path)
|
|
2790
|
+
parent = os.path.dirname(full_path)
|
|
2791
|
+
if parent:
|
|
2792
|
+
os.makedirs(parent, exist_ok=True)
|
|
2793
|
+
with open(full_path, "w") as f:
|
|
2794
|
+
f.write(content)
|
|
2795
|
+
return f"Written to {path}"
|
|
2796
|
+
except ValueError as e:
|
|
2797
|
+
return str(e)
|
|
2798
|
+
except OSError as e:
|
|
2799
|
+
return f"Error writing '{path}': {e.strerror}"
|
|
2800
|
+
|
|
2801
|
+
@tool
|
|
2802
|
+
def list_files(path: str) -> str:
|
|
2803
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
2804
|
+
try:
|
|
2805
|
+
full_path = _safe_resolve(path)
|
|
2806
|
+
entries = os.listdir(full_path)
|
|
2807
|
+
return "\\n".join(entries) if entries else "(empty directory)"
|
|
2808
|
+
except ValueError as e:
|
|
2809
|
+
return str(e)
|
|
2810
|
+
except OSError as e:
|
|
2811
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
2812
|
+
|
|
2813
|
+
tools.extend([file_read, file_write, list_files])
|
|
2814
|
+
{{/if}}
|
|
2815
|
+
|
|
2616
2816
|
agent = Agent(
|
|
2617
2817
|
model=load_model(),
|
|
2618
|
-
system_prompt="You are a helpful assistant. Use tools when appropriate.
|
|
2818
|
+
system_prompt="""You are a helpful assistant. Use tools when appropriate.
|
|
2819
|
+
{{#if needsOs}}
|
|
2820
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
2821
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
2822
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
2823
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
2824
|
+
{{/each}}{{/if}}""",
|
|
2619
2825
|
tools=tools,
|
|
2620
2826
|
)
|
|
2621
2827
|
|
|
@@ -2940,7 +3146,9 @@ Thumbs.db
|
|
|
2940
3146
|
`;
|
|
2941
3147
|
|
|
2942
3148
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/main.py should match snapshot 1`] = `
|
|
2943
|
-
"
|
|
3149
|
+
"{{#if needsOs}}
|
|
3150
|
+
import os
|
|
3151
|
+
{{/if}}
|
|
2944
3152
|
from autogen_agentchat.agents import AssistantAgent
|
|
2945
3153
|
from autogen_core.tools import FunctionTool
|
|
2946
3154
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
@@ -2964,18 +3172,21 @@ add_numbers_tool = FunctionTool(
|
|
|
2964
3172
|
# Define a collection of tools used by the model
|
|
2965
3173
|
tools = [add_numbers_tool]
|
|
2966
3174
|
|
|
2967
|
-
{{#if
|
|
2968
|
-
|
|
3175
|
+
{{#if needsOs}}
|
|
3176
|
+
_MOUNT_PATHS = [
|
|
3177
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
3178
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
3179
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
3180
|
+
]
|
|
2969
3181
|
|
|
2970
3182
|
def _safe_resolve(path: str) -> str:
|
|
2971
|
-
|
|
2972
|
-
resolved
|
|
2973
|
-
|
|
2974
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
3183
|
+
resolved = os.path.realpath(path)
|
|
3184
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
3185
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
2975
3186
|
return resolved
|
|
2976
3187
|
|
|
2977
3188
|
def file_read(path: str) -> str:
|
|
2978
|
-
"""Read a file from
|
|
3189
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2979
3190
|
try:
|
|
2980
3191
|
full_path = _safe_resolve(path)
|
|
2981
3192
|
with open(full_path) as f:
|
|
@@ -2986,7 +3197,7 @@ def file_read(path: str) -> str:
|
|
|
2986
3197
|
return f"Error reading '{path}': {e.strerror}"
|
|
2987
3198
|
|
|
2988
3199
|
def file_write(path: str, content: str) -> str:
|
|
2989
|
-
"""Write
|
|
3200
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
2990
3201
|
try:
|
|
2991
3202
|
full_path = _safe_resolve(path)
|
|
2992
3203
|
parent = os.path.dirname(full_path)
|
|
@@ -3000,29 +3211,32 @@ def file_write(path: str, content: str) -> str:
|
|
|
3000
3211
|
except OSError as e:
|
|
3001
3212
|
return f"Error writing '{path}': {e.strerror}"
|
|
3002
3213
|
|
|
3003
|
-
def list_files(
|
|
3004
|
-
"""List files in
|
|
3214
|
+
def list_files(path: str) -> str:
|
|
3215
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
3005
3216
|
try:
|
|
3006
|
-
|
|
3007
|
-
entries = os.listdir(
|
|
3217
|
+
full_path = _safe_resolve(path)
|
|
3218
|
+
entries = os.listdir(full_path)
|
|
3008
3219
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
3009
3220
|
except ValueError as e:
|
|
3010
3221
|
return str(e)
|
|
3011
3222
|
except OSError as e:
|
|
3012
|
-
return f"Error listing '{
|
|
3223
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
3013
3224
|
|
|
3014
3225
|
tools.extend([
|
|
3015
|
-
FunctionTool(file_read, description="Read a file from
|
|
3016
|
-
FunctionTool(file_write, description="Write
|
|
3017
|
-
FunctionTool(list_files, description="List files in
|
|
3226
|
+
FunctionTool(file_read, description="Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."),
|
|
3227
|
+
FunctionTool(file_write, description="Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."),
|
|
3228
|
+
FunctionTool(list_files, description="List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."),
|
|
3018
3229
|
])
|
|
3019
3230
|
{{/if}}
|
|
3020
3231
|
|
|
3021
3232
|
SYSTEM_MESSAGE = """
|
|
3022
3233
|
You are a helpful assistant. Use tools when appropriate.
|
|
3023
|
-
{{#if
|
|
3024
|
-
You have
|
|
3025
|
-
{{
|
|
3234
|
+
{{#if needsOs}}
|
|
3235
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
3236
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
3237
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
3238
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
3239
|
+
{{/each}}{{/if}}
|
|
3026
3240
|
"""
|
|
3027
3241
|
|
|
3028
3242
|
@app.entrypoint
|
|
@@ -3364,7 +3578,9 @@ Thumbs.db
|
|
|
3364
3578
|
`;
|
|
3365
3579
|
|
|
3366
3580
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/main.py should match snapshot 1`] = `
|
|
3367
|
-
"
|
|
3581
|
+
"{{#if needsOs}}
|
|
3582
|
+
import os
|
|
3583
|
+
{{/if}}
|
|
3368
3584
|
from google.adk.agents import Agent
|
|
3369
3585
|
from google.adk.runners import Runner
|
|
3370
3586
|
from google.adk.sessions import InMemorySessionService
|
|
@@ -3395,18 +3611,21 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
3395
3611
|
# Define a collection of tools used by the model
|
|
3396
3612
|
tools = [add_numbers]
|
|
3397
3613
|
|
|
3398
|
-
{{#if
|
|
3399
|
-
|
|
3614
|
+
{{#if needsOs}}
|
|
3615
|
+
_MOUNT_PATHS = [
|
|
3616
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
3617
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
3618
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
3619
|
+
]
|
|
3400
3620
|
|
|
3401
3621
|
def _safe_resolve(path: str) -> str:
|
|
3402
|
-
|
|
3403
|
-
resolved
|
|
3404
|
-
|
|
3405
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
3622
|
+
resolved = os.path.realpath(path)
|
|
3623
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
3624
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
3406
3625
|
return resolved
|
|
3407
3626
|
|
|
3408
3627
|
def file_read(path: str) -> str:
|
|
3409
|
-
"""Read a file from
|
|
3628
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
3410
3629
|
try:
|
|
3411
3630
|
full_path = _safe_resolve(path)
|
|
3412
3631
|
with open(full_path) as f:
|
|
@@ -3417,7 +3636,7 @@ def file_read(path: str) -> str:
|
|
|
3417
3636
|
return f"Error reading '{path}': {e.strerror}"
|
|
3418
3637
|
|
|
3419
3638
|
def file_write(path: str, content: str) -> str:
|
|
3420
|
-
"""Write
|
|
3639
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
3421
3640
|
try:
|
|
3422
3641
|
full_path = _safe_resolve(path)
|
|
3423
3642
|
parent = os.path.dirname(full_path)
|
|
@@ -3431,25 +3650,28 @@ def file_write(path: str, content: str) -> str:
|
|
|
3431
3650
|
except OSError as e:
|
|
3432
3651
|
return f"Error writing '{path}': {e.strerror}"
|
|
3433
3652
|
|
|
3434
|
-
def list_files(
|
|
3435
|
-
"""List files in
|
|
3653
|
+
def list_files(path: str) -> str:
|
|
3654
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
3436
3655
|
try:
|
|
3437
|
-
|
|
3438
|
-
entries = os.listdir(
|
|
3656
|
+
full_path = _safe_resolve(path)
|
|
3657
|
+
entries = os.listdir(full_path)
|
|
3439
3658
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
3440
3659
|
except ValueError as e:
|
|
3441
3660
|
return str(e)
|
|
3442
3661
|
except OSError as e:
|
|
3443
|
-
return f"Error listing '{
|
|
3662
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
3444
3663
|
|
|
3445
3664
|
tools.extend([file_read, file_write, list_files])
|
|
3446
3665
|
{{/if}}
|
|
3447
3666
|
|
|
3448
3667
|
AGENT_INSTRUCTION = """
|
|
3449
3668
|
I can answer your questions using the knowledge I have!
|
|
3450
|
-
{{#if
|
|
3451
|
-
You have
|
|
3452
|
-
{{
|
|
3669
|
+
{{#if needsOs}}
|
|
3670
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
3671
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
3672
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
3673
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
3674
|
+
{{/each}}{{/if}}
|
|
3453
3675
|
"""
|
|
3454
3676
|
|
|
3455
3677
|
# Get MCP Toolset
|
|
@@ -3777,7 +3999,9 @@ Thumbs.db
|
|
|
3777
3999
|
`;
|
|
3778
4000
|
|
|
3779
4001
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/main.py should match snapshot 1`] = `
|
|
3780
|
-
"
|
|
4002
|
+
"{{#if needsOs}}
|
|
4003
|
+
import os
|
|
4004
|
+
{{/if}}
|
|
3781
4005
|
from typing import Any
|
|
3782
4006
|
|
|
3783
4007
|
from langchain_core.messages import HumanMessage{{#if hasConfigBundle}}, SystemMessage{{/if}}
|
|
@@ -3812,9 +4036,12 @@ def get_or_create_model():
|
|
|
3812
4036
|
|
|
3813
4037
|
DEFAULT_SYSTEM_PROMPT = """
|
|
3814
4038
|
You are a helpful assistant. Use tools when appropriate.
|
|
3815
|
-
{{#if
|
|
3816
|
-
You have
|
|
3817
|
-
{{
|
|
4039
|
+
{{#if needsOs}}
|
|
4040
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
4041
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
4042
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
4043
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
4044
|
+
{{/each}}{{/if}}
|
|
3818
4045
|
"""
|
|
3819
4046
|
|
|
3820
4047
|
|
|
@@ -3828,19 +4055,22 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
3828
4055
|
# Define a collection of tools used by the model
|
|
3829
4056
|
tools = [add_numbers]
|
|
3830
4057
|
|
|
3831
|
-
{{#if
|
|
3832
|
-
|
|
4058
|
+
{{#if needsOs}}
|
|
4059
|
+
_MOUNT_PATHS = [
|
|
4060
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
4061
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
4062
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
4063
|
+
]
|
|
3833
4064
|
|
|
3834
4065
|
def _safe_resolve(path: str) -> str:
|
|
3835
|
-
|
|
3836
|
-
resolved
|
|
3837
|
-
|
|
3838
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
4066
|
+
resolved = os.path.realpath(path)
|
|
4067
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
4068
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
3839
4069
|
return resolved
|
|
3840
4070
|
|
|
3841
4071
|
@tool
|
|
3842
4072
|
def file_read(path: str) -> str:
|
|
3843
|
-
"""Read a file from
|
|
4073
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
3844
4074
|
try:
|
|
3845
4075
|
full_path = _safe_resolve(path)
|
|
3846
4076
|
with open(full_path) as f:
|
|
@@ -3852,7 +4082,7 @@ def file_read(path: str) -> str:
|
|
|
3852
4082
|
|
|
3853
4083
|
@tool
|
|
3854
4084
|
def file_write(path: str, content: str) -> str:
|
|
3855
|
-
"""Write
|
|
4085
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
3856
4086
|
try:
|
|
3857
4087
|
full_path = _safe_resolve(path)
|
|
3858
4088
|
parent = os.path.dirname(full_path)
|
|
@@ -3867,16 +4097,16 @@ def file_write(path: str, content: str) -> str:
|
|
|
3867
4097
|
return f"Error writing '{path}': {e.strerror}"
|
|
3868
4098
|
|
|
3869
4099
|
@tool
|
|
3870
|
-
def list_files(
|
|
3871
|
-
"""List files in
|
|
4100
|
+
def list_files(path: str) -> str:
|
|
4101
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
3872
4102
|
try:
|
|
3873
|
-
|
|
3874
|
-
entries = os.listdir(
|
|
4103
|
+
full_path = _safe_resolve(path)
|
|
4104
|
+
entries = os.listdir(full_path)
|
|
3875
4105
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
3876
4106
|
except ValueError as e:
|
|
3877
4107
|
return str(e)
|
|
3878
4108
|
except OSError as e:
|
|
3879
|
-
return f"Error listing '{
|
|
4109
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
3880
4110
|
|
|
3881
4111
|
tools.extend([file_read, file_write, list_files])
|
|
3882
4112
|
{{/if}}
|
|
@@ -4305,7 +4535,9 @@ Thumbs.db
|
|
|
4305
4535
|
`;
|
|
4306
4536
|
|
|
4307
4537
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/main.py should match snapshot 1`] = `
|
|
4308
|
-
"
|
|
4538
|
+
"{{#if needsOs}}
|
|
4539
|
+
import os
|
|
4540
|
+
{{/if}}
|
|
4309
4541
|
from agents import Agent, Runner, function_tool
|
|
4310
4542
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
4311
4543
|
from model.load import load_model
|
|
@@ -4344,19 +4576,22 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
4344
4576
|
|
|
4345
4577
|
tools = [add_numbers]
|
|
4346
4578
|
|
|
4347
|
-
{{#if
|
|
4348
|
-
|
|
4579
|
+
{{#if needsOs}}
|
|
4580
|
+
_MOUNT_PATHS = [
|
|
4581
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
4582
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
4583
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
4584
|
+
]
|
|
4349
4585
|
|
|
4350
4586
|
def _safe_resolve(path: str) -> str:
|
|
4351
|
-
|
|
4352
|
-
resolved
|
|
4353
|
-
|
|
4354
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
4587
|
+
resolved = os.path.realpath(path)
|
|
4588
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
4589
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
4355
4590
|
return resolved
|
|
4356
4591
|
|
|
4357
4592
|
@function_tool
|
|
4358
4593
|
def file_read(path: str) -> str:
|
|
4359
|
-
"""Read a file from
|
|
4594
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
4360
4595
|
try:
|
|
4361
4596
|
full_path = _safe_resolve(path)
|
|
4362
4597
|
with open(full_path) as f:
|
|
@@ -4368,7 +4603,7 @@ def file_read(path: str) -> str:
|
|
|
4368
4603
|
|
|
4369
4604
|
@function_tool
|
|
4370
4605
|
def file_write(path: str, content: str) -> str:
|
|
4371
|
-
"""Write
|
|
4606
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
4372
4607
|
try:
|
|
4373
4608
|
full_path = _safe_resolve(path)
|
|
4374
4609
|
parent = os.path.dirname(full_path)
|
|
@@ -4383,25 +4618,28 @@ def file_write(path: str, content: str) -> str:
|
|
|
4383
4618
|
return f"Error writing '{path}': {e.strerror}"
|
|
4384
4619
|
|
|
4385
4620
|
@function_tool
|
|
4386
|
-
def list_files(
|
|
4387
|
-
"""List files in
|
|
4621
|
+
def list_files(path: str) -> str:
|
|
4622
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
4388
4623
|
try:
|
|
4389
|
-
|
|
4390
|
-
entries = os.listdir(
|
|
4624
|
+
full_path = _safe_resolve(path)
|
|
4625
|
+
entries = os.listdir(full_path)
|
|
4391
4626
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
4392
4627
|
except ValueError as e:
|
|
4393
4628
|
return str(e)
|
|
4394
4629
|
except OSError as e:
|
|
4395
|
-
return f"Error listing '{
|
|
4630
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
4396
4631
|
|
|
4397
4632
|
tools.extend([file_read, file_write, list_files])
|
|
4398
4633
|
{{/if}}
|
|
4399
4634
|
|
|
4400
4635
|
INSTRUCTIONS = """
|
|
4401
4636
|
You are a helpful assistant. Use tools when appropriate.
|
|
4402
|
-
{{#if
|
|
4403
|
-
You have
|
|
4404
|
-
{{
|
|
4637
|
+
{{#if needsOs}}
|
|
4638
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
4639
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
4640
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
4641
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
4642
|
+
{{/each}}{{/if}}
|
|
4405
4643
|
"""
|
|
4406
4644
|
|
|
4407
4645
|
# Define the agent execution
|
|
@@ -4736,7 +4974,7 @@ from mcp_client.client import get_streamable_http_mcp_client
|
|
|
4736
4974
|
{{#if hasMemory}}
|
|
4737
4975
|
from memory.session import get_memory_session_manager
|
|
4738
4976
|
{{/if}}
|
|
4739
|
-
{{#if
|
|
4977
|
+
{{#if needsOs}}
|
|
4740
4978
|
import os
|
|
4741
4979
|
{{/if}}
|
|
4742
4980
|
|
|
@@ -4752,9 +4990,12 @@ mcp_clients = [get_streamable_http_mcp_client()]
|
|
|
4752
4990
|
|
|
4753
4991
|
DEFAULT_SYSTEM_PROMPT = """
|
|
4754
4992
|
You are a helpful assistant. Use tools when appropriate.
|
|
4755
|
-
{{#if
|
|
4756
|
-
You have
|
|
4757
|
-
{{
|
|
4993
|
+
{{#if needsOs}}
|
|
4994
|
+
You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
|
|
4995
|
+
{{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
|
|
4996
|
+
{{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
|
|
4997
|
+
{{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
|
|
4998
|
+
{{/each}}{{/if}}
|
|
4758
4999
|
"""
|
|
4759
5000
|
|
|
4760
5001
|
{{#if hasConfigBundle}}
|
|
@@ -4775,19 +5016,22 @@ def add_numbers(a: int, b: int) -> int:
|
|
|
4775
5016
|
return a+b
|
|
4776
5017
|
tools.append(add_numbers)
|
|
4777
5018
|
|
|
4778
|
-
{{#if
|
|
4779
|
-
|
|
5019
|
+
{{#if needsOs}}
|
|
5020
|
+
_MOUNT_PATHS = [
|
|
5021
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
5022
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
5023
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
5024
|
+
]
|
|
4780
5025
|
|
|
4781
5026
|
def _safe_resolve(path: str) -> str:
|
|
4782
|
-
|
|
4783
|
-
resolved
|
|
4784
|
-
|
|
4785
|
-
raise ValueError(f"Path '{path}' is outside the storage boundary")
|
|
5027
|
+
resolved = os.path.realpath(path)
|
|
5028
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
5029
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
4786
5030
|
return resolved
|
|
4787
5031
|
|
|
4788
5032
|
@tool
|
|
4789
5033
|
def file_read(path: str) -> str:
|
|
4790
|
-
"""Read a file from
|
|
5034
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
4791
5035
|
try:
|
|
4792
5036
|
full_path = _safe_resolve(path)
|
|
4793
5037
|
with open(full_path) as f:
|
|
@@ -4799,7 +5043,7 @@ def file_read(path: str) -> str:
|
|
|
4799
5043
|
|
|
4800
5044
|
@tool
|
|
4801
5045
|
def file_write(path: str, content: str) -> str:
|
|
4802
|
-
"""Write
|
|
5046
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
4803
5047
|
try:
|
|
4804
5048
|
full_path = _safe_resolve(path)
|
|
4805
5049
|
parent = os.path.dirname(full_path)
|
|
@@ -4814,16 +5058,16 @@ def file_write(path: str, content: str) -> str:
|
|
|
4814
5058
|
return f"Error writing '{path}': {e.strerror}"
|
|
4815
5059
|
|
|
4816
5060
|
@tool
|
|
4817
|
-
def list_files(
|
|
4818
|
-
"""List files in
|
|
5061
|
+
def list_files(path: str) -> str:
|
|
5062
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
4819
5063
|
try:
|
|
4820
|
-
|
|
4821
|
-
entries = os.listdir(
|
|
5064
|
+
full_path = _safe_resolve(path)
|
|
5065
|
+
entries = os.listdir(full_path)
|
|
4822
5066
|
return "\\n".join(entries) if entries else "(empty directory)"
|
|
4823
5067
|
except ValueError as e:
|
|
4824
5068
|
return str(e)
|
|
4825
5069
|
except OSError as e:
|
|
4826
|
-
return f"Error listing '{
|
|
5070
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
4827
5071
|
|
|
4828
5072
|
tools.extend([file_read, file_write, list_files])
|
|
4829
5073
|
{{/if}}
|
|
@@ -5321,10 +5565,68 @@ Thumbs.db
|
|
|
5321
5565
|
`;
|
|
5322
5566
|
|
|
5323
5567
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/main.py should match snapshot 1`] = `
|
|
5324
|
-
"
|
|
5568
|
+
"{{#if needsOs}}
|
|
5569
|
+
import os
|
|
5570
|
+
{{/if}}
|
|
5571
|
+
from mcp.server.fastmcp import FastMCP
|
|
5325
5572
|
|
|
5326
5573
|
mcp = FastMCP("{{ name }}", host="0.0.0.0", stateless_http=True)
|
|
5327
5574
|
|
|
5575
|
+
{{#if needsOs}}
|
|
5576
|
+
_MOUNT_PATHS = [
|
|
5577
|
+
{{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
|
|
5578
|
+
{{#each efsMounts}}"{{mountPath}}",{{/each}}
|
|
5579
|
+
{{#each s3Mounts}}"{{mountPath}}",{{/each}}
|
|
5580
|
+
]
|
|
5581
|
+
|
|
5582
|
+
def _safe_resolve(path: str) -> str:
|
|
5583
|
+
resolved = os.path.realpath(path)
|
|
5584
|
+
if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
|
|
5585
|
+
raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
|
|
5586
|
+
return resolved
|
|
5587
|
+
|
|
5588
|
+
@mcp.tool()
|
|
5589
|
+
def file_read(path: str) -> str:
|
|
5590
|
+
"""Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
5591
|
+
try:
|
|
5592
|
+
full_path = _safe_resolve(path)
|
|
5593
|
+
with open(full_path) as f:
|
|
5594
|
+
return f.read()
|
|
5595
|
+
except ValueError as e:
|
|
5596
|
+
return str(e)
|
|
5597
|
+
except OSError as e:
|
|
5598
|
+
return f"Error reading '{path}': {e.strerror}"
|
|
5599
|
+
|
|
5600
|
+
@mcp.tool()
|
|
5601
|
+
def file_write(path: str, content: str) -> str:
|
|
5602
|
+
"""Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
|
|
5603
|
+
try:
|
|
5604
|
+
full_path = _safe_resolve(path)
|
|
5605
|
+
parent = os.path.dirname(full_path)
|
|
5606
|
+
if parent:
|
|
5607
|
+
os.makedirs(parent, exist_ok=True)
|
|
5608
|
+
with open(full_path, "w") as f:
|
|
5609
|
+
f.write(content)
|
|
5610
|
+
return f"Written to {path}"
|
|
5611
|
+
except ValueError as e:
|
|
5612
|
+
return str(e)
|
|
5613
|
+
except OSError as e:
|
|
5614
|
+
return f"Error writing '{path}': {e.strerror}"
|
|
5615
|
+
|
|
5616
|
+
@mcp.tool()
|
|
5617
|
+
def list_files(path: str) -> str:
|
|
5618
|
+
"""List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
|
|
5619
|
+
try:
|
|
5620
|
+
full_path = _safe_resolve(path)
|
|
5621
|
+
entries = os.listdir(full_path)
|
|
5622
|
+
return "\\n".join(entries) if entries else "(empty directory)"
|
|
5623
|
+
except ValueError as e:
|
|
5624
|
+
return str(e)
|
|
5625
|
+
except OSError as e:
|
|
5626
|
+
return f"Error listing '{path}': {e.strerror}"
|
|
5627
|
+
|
|
5628
|
+
{{/if}}
|
|
5629
|
+
|
|
5328
5630
|
|
|
5329
5631
|
@mcp.tool()
|
|
5330
5632
|
def add_numbers(a: int, b: int) -> int:
|