agentcore-cli 0.31.1__py3-none-any.whl

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.
Files changed (655) hide show
  1. agentcore/__init__.py +1 -0
  2. agentcore/agent_inspector/NOTICE +9 -0
  3. agentcore/agent_inspector/favicon.svg +60 -0
  4. agentcore/agent_inspector/index.css +1 -0
  5. agentcore/agent_inspector/index.html +14 -0
  6. agentcore/agent_inspector/index.js +289 -0
  7. agentcore/assets/AGENTS.md +60 -0
  8. agentcore/assets/README.md +108 -0
  9. agentcore/assets/agents/AGENTS.md +218 -0
  10. agentcore/assets/cdk/.prettierrc +8 -0
  11. agentcore/assets/cdk/README.md +26 -0
  12. agentcore/assets/cdk/bin/cdk.ts +216 -0
  13. agentcore/assets/cdk/cdk.json +88 -0
  14. agentcore/assets/cdk/gitignore.template +9 -0
  15. agentcore/assets/cdk/jest.config.js +9 -0
  16. agentcore/assets/cdk/lib/cdk-stack.ts +291 -0
  17. agentcore/assets/cdk/npmignore.template +6 -0
  18. agentcore/assets/cdk/package.json +30 -0
  19. agentcore/assets/cdk/test/cdk.test.ts +31 -0
  20. agentcore/assets/cdk/tsconfig.json +28 -0
  21. agentcore/assets/container/python/Dockerfile +47 -0
  22. agentcore/assets/container/python/dockerignore.template +27 -0
  23. agentcore/assets/container/typescript/Dockerfile +25 -0
  24. agentcore/assets/container/typescript/dockerignore.template +24 -0
  25. agentcore/assets/datasets/predefined-v1.jsonl +3 -0
  26. agentcore/assets/datasets/simulated-v1.jsonl +3 -0
  27. agentcore/assets/evaluators/autoevals-lambda/execution-role-policy.json +15 -0
  28. agentcore/assets/evaluators/autoevals-lambda/lambda_function.py +37 -0
  29. agentcore/assets/evaluators/autoevals-lambda/pyproject.toml +22 -0
  30. agentcore/assets/evaluators/deepeval-lambda/execution-role-policy.json +15 -0
  31. agentcore/assets/evaluators/deepeval-lambda/lambda_function.py +29 -0
  32. agentcore/assets/evaluators/deepeval-lambda/pyproject.toml +19 -0
  33. agentcore/assets/evaluators/python-lambda/execution-role-policy.json +10 -0
  34. agentcore/assets/evaluators/python-lambda/lambda_function.py +19 -0
  35. agentcore/assets/evaluators/python-lambda/pyproject.toml +15 -0
  36. agentcore/assets/harness/invoke.py.template +74 -0
  37. agentcore/assets/mcp/python/README.md +27 -0
  38. agentcore/assets/mcp/python/pyproject.toml +22 -0
  39. agentcore/assets/mcp/python/server.py +117 -0
  40. agentcore/assets/mcp/python-lambda/README.md +22 -0
  41. agentcore/assets/mcp/python-lambda/handler.py +144 -0
  42. agentcore/assets/mcp/python-lambda/pyproject.toml +15 -0
  43. agentcore/assets/python/a2a/googleadk/base/README.md +22 -0
  44. agentcore/assets/python/a2a/googleadk/base/gitignore.template +41 -0
  45. agentcore/assets/python/a2a/googleadk/base/main.py +124 -0
  46. agentcore/assets/python/a2a/googleadk/base/model/__init__.py +1 -0
  47. agentcore/assets/python/a2a/googleadk/base/model/load.py +41 -0
  48. agentcore/assets/python/a2a/googleadk/base/pyproject.toml +22 -0
  49. agentcore/assets/python/a2a/langchain_langgraph/base/README.md +22 -0
  50. agentcore/assets/python/a2a/langchain_langgraph/base/gitignore.template +41 -0
  51. agentcore/assets/python/a2a/langchain_langgraph/base/main.py +144 -0
  52. agentcore/assets/python/a2a/langchain_langgraph/base/model/__init__.py +1 -0
  53. agentcore/assets/python/a2a/langchain_langgraph/base/model/load.py +123 -0
  54. agentcore/assets/python/a2a/langchain_langgraph/base/pyproject.toml +26 -0
  55. agentcore/assets/python/a2a/strands/base/README.md +22 -0
  56. agentcore/assets/python/a2a/strands/base/gitignore.template +41 -0
  57. agentcore/assets/python/a2a/strands/base/main.py +113 -0
  58. agentcore/assets/python/a2a/strands/base/model/__init__.py +1 -0
  59. agentcore/assets/python/a2a/strands/base/model/load.py +123 -0
  60. agentcore/assets/python/a2a/strands/base/pyproject.toml +23 -0
  61. agentcore/assets/python/a2a/strands/capabilities/memory/__init__.py +1 -0
  62. agentcore/assets/python/a2a/strands/capabilities/memory/session.py +46 -0
  63. agentcore/assets/python/agui/googleadk/base/README.md +30 -0
  64. agentcore/assets/python/agui/googleadk/base/gitignore.template +41 -0
  65. agentcore/assets/python/agui/googleadk/base/main.py +91 -0
  66. agentcore/assets/python/agui/googleadk/base/model/__init__.py +1 -0
  67. agentcore/assets/python/agui/googleadk/base/model/load.py +41 -0
  68. agentcore/assets/python/agui/googleadk/base/pyproject.toml +25 -0
  69. agentcore/assets/python/agui/langchain_langgraph/base/README.md +22 -0
  70. agentcore/assets/python/agui/langchain_langgraph/base/gitignore.template +41 -0
  71. agentcore/assets/python/agui/langchain_langgraph/base/main.py +130 -0
  72. agentcore/assets/python/agui/langchain_langgraph/base/model/__init__.py +1 -0
  73. agentcore/assets/python/agui/langchain_langgraph/base/model/load.py +123 -0
  74. agentcore/assets/python/agui/langchain_langgraph/base/pyproject.toml +31 -0
  75. agentcore/assets/python/agui/strands/base/README.md +22 -0
  76. agentcore/assets/python/agui/strands/base/gitignore.template +41 -0
  77. agentcore/assets/python/agui/strands/base/main.py +105 -0
  78. agentcore/assets/python/agui/strands/base/model/__init__.py +1 -0
  79. agentcore/assets/python/agui/strands/base/model/load.py +123 -0
  80. agentcore/assets/python/agui/strands/base/pyproject.toml +27 -0
  81. agentcore/assets/python/agui/strands/capabilities/memory/__init__.py +1 -0
  82. agentcore/assets/python/agui/strands/capabilities/memory/session.py +46 -0
  83. agentcore/assets/python/http/autogen/base/README.md +45 -0
  84. agentcore/assets/python/http/autogen/base/gitignore.template +41 -0
  85. agentcore/assets/python/http/autogen/base/main.py +145 -0
  86. agentcore/assets/python/http/autogen/base/mcp_client/__init__.py +1 -0
  87. agentcore/assets/python/http/autogen/base/mcp_client/client.py +28 -0
  88. agentcore/assets/python/http/autogen/base/model/__init__.py +1 -0
  89. agentcore/assets/python/http/autogen/base/model/load.py +136 -0
  90. agentcore/assets/python/http/autogen/base/pyproject.toml +34 -0
  91. agentcore/assets/python/http/bma/base/Dockerfile +41 -0
  92. agentcore/assets/python/http/bma/base/README.md +178 -0
  93. agentcore/assets/python/http/bma/base/client.py +200 -0
  94. agentcore/assets/python/http/bma/base/lifecycle/server.py +641 -0
  95. agentcore/assets/python/http/bma/base/otel/collector.yaml +69 -0
  96. agentcore/assets/python/http/bma/base/plugins/acr-report/.codex-plugin/plugin.json +6 -0
  97. agentcore/assets/python/http/bma/base/plugins/acr-report/skills/acr-report/SKILL.md +16 -0
  98. agentcore/assets/python/http/bma/base/policies/bma-acr-policy.json +11 -0
  99. agentcore/assets/python/http/bma/base/policies/bma-session-policy.json +35 -0
  100. agentcore/assets/python/http/bma/base/policies/bma-session-trust.json +20 -0
  101. agentcore/assets/python/http/bma/base/pyproject.toml +21 -0
  102. agentcore/assets/python/http/googleadk/base/README.md +45 -0
  103. agentcore/assets/python/http/googleadk/base/gitignore.template +41 -0
  104. agentcore/assets/python/http/googleadk/base/main.py +207 -0
  105. agentcore/assets/python/http/googleadk/base/mcp_client/__init__.py +1 -0
  106. agentcore/assets/python/http/googleadk/base/mcp_client/client.py +75 -0
  107. agentcore/assets/python/http/googleadk/base/model/__init__.py +1 -0
  108. agentcore/assets/python/http/googleadk/base/model/load.py +41 -0
  109. agentcore/assets/python/http/googleadk/base/pyproject.toml +24 -0
  110. agentcore/assets/python/http/langchain_langgraph/base/README.md +45 -0
  111. agentcore/assets/python/http/langchain_langgraph/base/gitignore.template +41 -0
  112. agentcore/assets/python/http/langchain_langgraph/base/main.py +227 -0
  113. agentcore/assets/python/http/langchain_langgraph/base/mcp_client/__init__.py +1 -0
  114. agentcore/assets/python/http/langchain_langgraph/base/mcp_client/client.py +79 -0
  115. agentcore/assets/python/http/langchain_langgraph/base/model/__init__.py +1 -0
  116. agentcore/assets/python/http/langchain_langgraph/base/model/load.py +123 -0
  117. agentcore/assets/python/http/langchain_langgraph/base/pyproject.toml +38 -0
  118. agentcore/assets/python/http/openaiagents/base/README.md +45 -0
  119. agentcore/assets/python/http/openaiagents/base/gitignore.template +41 -0
  120. agentcore/assets/python/http/openaiagents/base/main.py +200 -0
  121. agentcore/assets/python/http/openaiagents/base/mcp_client/__init__.py +1 -0
  122. agentcore/assets/python/http/openaiagents/base/mcp_client/client.py +74 -0
  123. agentcore/assets/python/http/openaiagents/base/model/__init__.py +1 -0
  124. agentcore/assets/python/http/openaiagents/base/model/load.py +37 -0
  125. agentcore/assets/python/http/openaiagents/base/pyproject.toml +21 -0
  126. agentcore/assets/python/http/strands/base/README.md +46 -0
  127. agentcore/assets/python/http/strands/base/gitignore.template +41 -0
  128. agentcore/assets/python/http/strands/base/main.py +714 -0
  129. agentcore/assets/python/http/strands/base/mcp_client/__init__.py +1 -0
  130. agentcore/assets/python/http/strands/base/mcp_client/client.py +116 -0
  131. agentcore/assets/python/http/strands/base/model/__init__.py +1 -0
  132. agentcore/assets/python/http/strands/base/model/load.py +239 -0
  133. agentcore/assets/python/http/strands/base/model/mantle_compat.py +21 -0
  134. agentcore/assets/python/http/strands/base/pyproject.toml +31 -0
  135. agentcore/assets/python/http/strands/base/skills/fetcher.py +279 -0
  136. agentcore/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
  137. agentcore/assets/python/http/strands/capabilities/memory/__init__.py +1 -0
  138. agentcore/assets/python/http/strands/capabilities/memory/session.py +47 -0
  139. agentcore/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
  140. agentcore/assets/python/http/strands/capabilities/payments/payments.py +142 -0
  141. agentcore/assets/python/mcp/standalone/base/README.md +36 -0
  142. agentcore/assets/python/mcp/standalone/base/gitignore.template +41 -0
  143. agentcore/assets/python/mcp/standalone/base/main.py +83 -0
  144. agentcore/assets/python/mcp/standalone/base/pyproject.toml +16 -0
  145. agentcore/assets/typescript/.gitkeep +0 -0
  146. agentcore/assets/typescript/http/strands/base/README.md +42 -0
  147. agentcore/assets/typescript/http/strands/base/gitignore.template +22 -0
  148. agentcore/assets/typescript/http/strands/base/main.ts +149 -0
  149. agentcore/assets/typescript/http/strands/base/mcp_client/client.ts +11 -0
  150. agentcore/assets/typescript/http/strands/base/model/load.ts +102 -0
  151. agentcore/assets/typescript/http/strands/base/package.json +38 -0
  152. agentcore/assets/typescript/http/strands/base/tsconfig.json +19 -0
  153. agentcore/assets/typescript/http/strands/capabilities/memory/memory.ts +52 -0
  154. agentcore/assets/typescript/http/vercelai/base/README.md +42 -0
  155. agentcore/assets/typescript/http/vercelai/base/gitignore.template +22 -0
  156. agentcore/assets/typescript/http/vercelai/base/main.ts +70 -0
  157. agentcore/assets/typescript/http/vercelai/base/model/load.ts +121 -0
  158. agentcore/assets/typescript/http/vercelai/base/package.json +35 -0
  159. agentcore/assets/typescript/http/vercelai/base/tsconfig.json +19 -0
  160. agentcore/aws/__init__.py +263 -0
  161. agentcore/aws/_aws_errors.py +72 -0
  162. agentcore/aws/_http.py +176 -0
  163. agentcore/aws/_util.py +37 -0
  164. agentcore/aws/account.py +165 -0
  165. agentcore/aws/agentcore.py +971 -0
  166. agentcore/aws/agentcore_ab_tests.py +230 -0
  167. agentcore/aws/agentcore_batch_evaluation.py +227 -0
  168. agentcore/aws/agentcore_config_bundles.py +220 -0
  169. agentcore/aws/agentcore_control.py +994 -0
  170. agentcore/aws/agentcore_datasets.py +222 -0
  171. agentcore/aws/agentcore_harness.py +330 -0
  172. agentcore/aws/agentcore_payments.py +430 -0
  173. agentcore/aws/agentcore_recommendation.py +140 -0
  174. agentcore/aws/agui_parser.py +131 -0
  175. agentcore/aws/agui_types.py +342 -0
  176. agentcore/aws/api_client.py +87 -0
  177. agentcore/aws/arn.py +18 -0
  178. agentcore/aws/aws_context.py +23 -0
  179. agentcore/aws/bedrock.py +44 -0
  180. agentcore/aws/bedrock_agent.py +129 -0
  181. agentcore/aws/bedrock_import.py +252 -0
  182. agentcore/aws/bedrock_import_types.py +111 -0
  183. agentcore/aws/cloudwatch.py +136 -0
  184. agentcore/aws/connect_shell.py +266 -0
  185. agentcore/aws/iam.py +41 -0
  186. agentcore/aws/partition.py +58 -0
  187. agentcore/aws/policy_generation.py +116 -0
  188. agentcore/aws/region.py +54 -0
  189. agentcore/aws/retry.py +27 -0
  190. agentcore/aws/shell_framer.py +136 -0
  191. agentcore/aws/stage_endpoint.py +39 -0
  192. agentcore/aws/target_region.py +54 -0
  193. agentcore/aws/transaction_search.py +97 -0
  194. agentcore/cdk/__init__.py +10 -0
  195. agentcore/cdk/constants.py +13 -0
  196. agentcore/cdk/local_cdk_project.py +48 -0
  197. agentcore/cdk/toolkit.py +706 -0
  198. agentcore/cli/__init__.py +0 -0
  199. agentcore/cli/commands/__init__.py +0 -0
  200. agentcore/cli/commands/_jobs_common.py +39 -0
  201. agentcore/cli/commands/_run_wizards.py +639 -0
  202. agentcore/cli/commands/add/__init__.py +37 -0
  203. agentcore/cli/commands/add/_commander.py +52 -0
  204. agentcore/cli/commands/add/_common.py +47 -0
  205. agentcore/cli/commands/add/agent_wizard.py +528 -0
  206. agentcore/cli/commands/add/auth_options.py +154 -0
  207. agentcore/cli/commands/add/skill_action.py +105 -0
  208. agentcore/cli/commands/add/skill_command.py +87 -0
  209. agentcore/cli/commands/add/tool_action.py +160 -0
  210. agentcore/cli/commands/add/tool_command.py +117 -0
  211. agentcore/cli/commands/add/validate.py +333 -0
  212. agentcore/cli/commands/capacity_provider/__init__.py +86 -0
  213. agentcore/cli/commands/capacity_provider/action.py +114 -0
  214. agentcore/cli/commands/capacity_provider/constants.py +22 -0
  215. agentcore/cli/commands/config.py +91 -0
  216. agentcore/cli/commands/config_bundle.py +251 -0
  217. agentcore/cli/commands/create/__init__.py +643 -0
  218. agentcore/cli/commands/create/action.py +406 -0
  219. agentcore/cli/commands/create/dependencies.py +91 -0
  220. agentcore/cli/commands/create/harness_validate.py +82 -0
  221. agentcore/cli/commands/create/validate.py +195 -0
  222. agentcore/cli/commands/create/wizard.py +127 -0
  223. agentcore/cli/commands/dataset.py +119 -0
  224. agentcore/cli/commands/deploy/__init__.py +31 -0
  225. agentcore/cli/commands/deploy/_guards.py +25 -0
  226. agentcore/cli/commands/deploy/actions.py +840 -0
  227. agentcore/cli/commands/deploy/command.py +349 -0
  228. agentcore/cli/commands/deploy/progress.py +115 -0
  229. agentcore/cli/commands/deploy/types.py +68 -0
  230. agentcore/cli/commands/deploy/utils.py +43 -0
  231. agentcore/cli/commands/deploy/validate.py +21 -0
  232. agentcore/cli/commands/dev/__init__.py +5 -0
  233. agentcore/cli/commands/dev/_deps.py +50 -0
  234. agentcore/cli/commands/dev/browser_mode.py +270 -0
  235. agentcore/cli/commands/dev/command.py +450 -0
  236. agentcore/cli/commands/dev/terminal_mode.py +379 -0
  237. agentcore/cli/commands/exec/__init__.py +29 -0
  238. agentcore/cli/commands/exec/action.py +442 -0
  239. agentcore/cli/commands/exec/command.py +206 -0
  240. agentcore/cli/commands/exec/types.py +35 -0
  241. agentcore/cli/commands/export/__init__.py +114 -0
  242. agentcore/cli/commands/export/constants.py +21 -0
  243. agentcore/cli/commands/export/fetch_harness_spec.py +234 -0
  244. agentcore/cli/commands/export/harness_action.py +385 -0
  245. agentcore/cli/commands/export/harness_mapper.py +868 -0
  246. agentcore/cli/commands/export/harness_resolver.py +95 -0
  247. agentcore/cli/commands/export/types.py +90 -0
  248. agentcore/cli/commands/export/wizard.py +97 -0
  249. agentcore/cli/commands/feedback/__init__.py +69 -0
  250. agentcore/cli/commands/feedback/action.py +30 -0
  251. agentcore/cli/commands/feedback/consent_prompt.py +35 -0
  252. agentcore/cli/commands/feedback/wizard.py +49 -0
  253. agentcore/cli/commands/fetch/__init__.py +69 -0
  254. agentcore/cli/commands/fetch/action.py +62 -0
  255. agentcore/cli/commands/help.py +65 -0
  256. agentcore/cli/commands/import_/__init__.py +167 -0
  257. agentcore/cli/commands/import_/_js.py +72 -0
  258. agentcore/cli/commands/import_/actions.py +457 -0
  259. agentcore/cli/commands/import_/constants.py +45 -0
  260. agentcore/cli/commands/import_/import_evaluator.py +140 -0
  261. agentcore/cli/commands/import_/import_gateway.py +520 -0
  262. agentcore/cli/commands/import_/import_memory.py +128 -0
  263. agentcore/cli/commands/import_/import_online_eval.py +165 -0
  264. agentcore/cli/commands/import_/import_pipeline.py +145 -0
  265. agentcore/cli/commands/import_/import_runtime.py +214 -0
  266. agentcore/cli/commands/import_/import_utils.py +410 -0
  267. agentcore/cli/commands/import_/phase1_update.py +110 -0
  268. agentcore/cli/commands/import_/phase2_import.py +206 -0
  269. agentcore/cli/commands/import_/resource_import.py +228 -0
  270. agentcore/cli/commands/import_/template_utils.py +148 -0
  271. agentcore/cli/commands/import_/types.py +150 -0
  272. agentcore/cli/commands/import_/yaml_parser.py +265 -0
  273. agentcore/cli/commands/init.py +196 -0
  274. agentcore/cli/commands/invoke/__init__.py +32 -0
  275. agentcore/cli/commands/invoke/_deps.py +73 -0
  276. agentcore/cli/commands/invoke/action.py +840 -0
  277. agentcore/cli/commands/invoke/command.py +490 -0
  278. agentcore/cli/commands/invoke/constants.py +40 -0
  279. agentcore/cli/commands/invoke/guards.py +23 -0
  280. agentcore/cli/commands/invoke/interactive.py +604 -0
  281. agentcore/cli/commands/invoke/resolve.py +149 -0
  282. agentcore/cli/commands/invoke/resolve_prompt.py +60 -0
  283. agentcore/cli/commands/invoke/types.py +61 -0
  284. agentcore/cli/commands/invoke/validate.py +33 -0
  285. agentcore/cli/commands/job_actions.py +239 -0
  286. agentcore/cli/commands/job_history.py +380 -0
  287. agentcore/cli/commands/logs/__init__.py +53 -0
  288. agentcore/cli/commands/logs/action.py +159 -0
  289. agentcore/cli/commands/logs/filter_pattern.py +17 -0
  290. agentcore/cli/commands/logs/guards.py +51 -0
  291. agentcore/cli/commands/logs_evals.py +42 -0
  292. agentcore/cli/commands/package.py +118 -0
  293. agentcore/cli/commands/remove/__init__.py +172 -0
  294. agentcore/cli/commands/remove/skill_command.py +131 -0
  295. agentcore/cli/commands/remove/tool_command.py +59 -0
  296. agentcore/cli/commands/run.py +808 -0
  297. agentcore/cli/commands/run_ingest.py +97 -0
  298. agentcore/cli/commands/shared/__init__.py +0 -0
  299. agentcore/cli/commands/shared/arn_utils.py +9 -0
  300. agentcore/cli/commands/shared/filesystem_utils.py +421 -0
  301. agentcore/cli/commands/shared/header_utils.py +87 -0
  302. agentcore/cli/commands/shared/indexed_key_parser.py +76 -0
  303. agentcore/cli/commands/shared/lifecycle_utils.py +72 -0
  304. agentcore/cli/commands/shared/region_utils.py +20 -0
  305. agentcore/cli/commands/shared/vpc_utils.py +99 -0
  306. agentcore/cli/commands/status/__init__.py +30 -0
  307. agentcore/cli/commands/status/_guards.py +25 -0
  308. agentcore/cli/commands/status/action.py +741 -0
  309. agentcore/cli/commands/status/command.py +321 -0
  310. agentcore/cli/commands/status/constants.py +36 -0
  311. agentcore/cli/commands/status/format_knowledge_base.py +111 -0
  312. agentcore/cli/commands/telemetry.py +79 -0
  313. agentcore/cli/commands/traces/__init__.py +155 -0
  314. agentcore/cli/commands/traces/action.py +123 -0
  315. agentcore/cli/commands/update/__init__.py +63 -0
  316. agentcore/cli/commands/update/action.py +164 -0
  317. agentcore/cli/commands/validate.py +165 -0
  318. agentcore/cli/constants.py +96 -0
  319. agentcore/cli/errors.py +118 -0
  320. agentcore/cli/external_requirements/__init__.py +67 -0
  321. agentcore/cli/external_requirements/checks.py +280 -0
  322. agentcore/cli/external_requirements/detect.py +55 -0
  323. agentcore/cli/external_requirements/versions.py +57 -0
  324. agentcore/cli/groups.py +23 -0
  325. agentcore/cli/interactive.py +85 -0
  326. agentcore/cli/main.py +137 -0
  327. agentcore/cli/naming.py +11 -0
  328. agentcore/cli/notices.py +42 -0
  329. agentcore/cli/project.py +34 -0
  330. agentcore/cli/run_command.py +27 -0
  331. agentcore/cli/tree.py +135 -0
  332. agentcore/cli/update_notifier.py +123 -0
  333. agentcore/cli/variadic.py +50 -0
  334. agentcore/cloudformation/__init__.py +84 -0
  335. agentcore/cloudformation/bootstrap.py +64 -0
  336. agentcore/cloudformation/logical_ids.py +37 -0
  337. agentcore/cloudformation/outputs.py +566 -0
  338. agentcore/cloudformation/stack_discovery.py +75 -0
  339. agentcore/cloudformation/stack_events.py +107 -0
  340. agentcore/cloudformation/stack_status.py +98 -0
  341. agentcore/cloudformation/types.py +44 -0
  342. agentcore/lib/__init__.py +68 -0
  343. agentcore/lib/constants.py +77 -0
  344. agentcore/lib/dependency_management/__init__.py +23 -0
  345. agentcore/lib/dependency_management/messages.py +92 -0
  346. agentcore/lib/dependency_management/plan.py +98 -0
  347. agentcore/lib/dependency_management/semver.py +137 -0
  348. agentcore/lib/dependency_management/sync.py +139 -0
  349. agentcore/lib/dependency_management/types.py +56 -0
  350. agentcore/lib/errors/__init__.py +5 -0
  351. agentcore/lib/errors/types.py +352 -0
  352. agentcore/lib/errors/validation.py +121 -0
  353. agentcore/lib/packaging/__init__.py +81 -0
  354. agentcore/lib/packaging/build_args.py +23 -0
  355. agentcore/lib/packaging/build_context.py +26 -0
  356. agentcore/lib/packaging/build_context_dockerignore.py +45 -0
  357. agentcore/lib/packaging/container.py +95 -0
  358. agentcore/lib/packaging/helpers.py +289 -0
  359. agentcore/lib/packaging/node.py +153 -0
  360. agentcore/lib/packaging/python.py +135 -0
  361. agentcore/lib/packaging/types.py +69 -0
  362. agentcore/lib/packaging/uv.py +45 -0
  363. agentcore/lib/result.py +104 -0
  364. agentcore/lib/schemas/__init__.py +1 -0
  365. agentcore/lib/schemas/io/__init__.py +27 -0
  366. agentcore/lib/schemas/io/config_io.py +458 -0
  367. agentcore/lib/schemas/io/global_config.py +239 -0
  368. agentcore/lib/schemas/io/path_resolver.py +132 -0
  369. agentcore/lib/secrets/__init__.py +18 -0
  370. agentcore/lib/secrets/cipher.py +70 -0
  371. agentcore/lib/secrets/key_provider.py +163 -0
  372. agentcore/lib/secrets/sensitive_keys.py +55 -0
  373. agentcore/lib/time_constants.py +4 -0
  374. agentcore/lib/utils/__init__.py +47 -0
  375. agentcore/lib/utils/aws_account.py +15 -0
  376. agentcore/lib/utils/credentials.py +68 -0
  377. agentcore/lib/utils/dotenv.py +32 -0
  378. agentcore/lib/utils/env.py +105 -0
  379. agentcore/lib/utils/json_format.py +29 -0
  380. agentcore/lib/utils/json_rpc.py +22 -0
  381. agentcore/lib/utils/platform.py +33 -0
  382. agentcore/lib/utils/polling.py +86 -0
  383. agentcore/lib/utils/subprocess.py +135 -0
  384. agentcore/lib/utils/time_parser.py +48 -0
  385. agentcore/lib/utils/validation.py +106 -0
  386. agentcore/logging/__init__.py +10 -0
  387. agentcore/logging/_common.py +77 -0
  388. agentcore/logging/cdk_io_host.py +36 -0
  389. agentcore/logging/create_logger.py +107 -0
  390. agentcore/logging/dev_logger.py +63 -0
  391. agentcore/logging/exec_logger.py +159 -0
  392. agentcore/logging/invoke_logger.py +154 -0
  393. agentcore/logging/remove_logger.py +95 -0
  394. agentcore/operations/__init__.py +0 -0
  395. agentcore/operations/agent/__init__.py +0 -0
  396. agentcore/operations/agent/config_bundle_defaults.py +31 -0
  397. agentcore/operations/agent/generate/__init__.py +28 -0
  398. agentcore/operations/agent/generate/schema_mapper.py +319 -0
  399. agentcore/operations/agent/generate/types.py +172 -0
  400. agentcore/operations/agent/generate/write_agent_to_project.py +67 -0
  401. agentcore/operations/agent/import_/__init__.py +31 -0
  402. agentcore/operations/agent/import_/base_translator.py +449 -0
  403. agentcore/operations/agent/import_/constants.py +23 -0
  404. agentcore/operations/agent/import_/execute.py +127 -0
  405. agentcore/operations/agent/import_/langgraph_translator.py +294 -0
  406. agentcore/operations/agent/import_/pyproject_generator.py +73 -0
  407. agentcore/operations/agent/import_/strands_translator.py +289 -0
  408. agentcore/operations/config_bundle/__init__.py +1 -0
  409. agentcore/operations/config_bundle/bundle_name_variants.py +9 -0
  410. agentcore/operations/config_bundle/diff_versions.py +52 -0
  411. agentcore/operations/config_bundle/resolve_bundle.py +65 -0
  412. agentcore/operations/connectors/__init__.py +3 -0
  413. agentcore/operations/connectors/translators.py +63 -0
  414. agentcore/operations/dataset/__init__.py +21 -0
  415. agentcore/operations/dataset/delete.py +7 -0
  416. agentcore/operations/dataset/publish.py +16 -0
  417. agentcore/operations/dataset/pull.py +21 -0
  418. agentcore/operations/dataset/push.py +201 -0
  419. agentcore/operations/dataset/resolve_dataset.py +65 -0
  420. agentcore/operations/dataset/status.py +18 -0
  421. agentcore/operations/dataset/wait.py +25 -0
  422. agentcore/operations/deploy/__init__.py +152 -0
  423. agentcore/operations/deploy/backfill_vpc_id.py +90 -0
  424. agentcore/operations/deploy/change_detection.py +84 -0
  425. agentcore/operations/deploy/constants.py +58 -0
  426. agentcore/operations/deploy/dependency_sync.py +105 -0
  427. agentcore/operations/deploy/ensure_target.py +30 -0
  428. agentcore/operations/deploy/gateway_status.py +44 -0
  429. agentcore/operations/deploy/managed_memory_notice.py +36 -0
  430. agentcore/operations/deploy/payment_connector_authorization.py +106 -0
  431. agentcore/operations/deploy/post_deploy_datasets.py +96 -0
  432. agentcore/operations/deploy/post_deploy_knowledge_bases.py +104 -0
  433. agentcore/operations/deploy/post_deploy_observability.py +28 -0
  434. agentcore/operations/deploy/post_deploy_online_evals.py +60 -0
  435. agentcore/operations/deploy/pre_deploy_identity.py +505 -0
  436. agentcore/operations/deploy/preflight.py +385 -0
  437. agentcore/operations/deploy/region_override.py +45 -0
  438. agentcore/operations/deploy/teardown.py +153 -0
  439. agentcore/operations/dev/__init__.py +61 -0
  440. agentcore/operations/dev/_http.py +79 -0
  441. agentcore/operations/dev/_server.py +165 -0
  442. agentcore/operations/dev/codezip_dev_server.py +151 -0
  443. agentcore/operations/dev/config.py +128 -0
  444. agentcore/operations/dev/constants.py +9 -0
  445. agentcore/operations/dev/container_dev_server.py +237 -0
  446. agentcore/operations/dev/container_runtime.py +37 -0
  447. agentcore/operations/dev/dev_server.py +244 -0
  448. agentcore/operations/dev/gateway_env.py +25 -0
  449. agentcore/operations/dev/invoke.py +214 -0
  450. agentcore/operations/dev/invoke_a2a.py +204 -0
  451. agentcore/operations/dev/invoke_agui.py +88 -0
  452. agentcore/operations/dev/invoke_mcp.py +145 -0
  453. agentcore/operations/dev/invoke_types.py +30 -0
  454. agentcore/operations/dev/load_dev_env.py +26 -0
  455. agentcore/operations/dev/memory_env.py +19 -0
  456. agentcore/operations/dev/otel/__init__.py +5 -0
  457. agentcore/operations/dev/otel/collector.py +234 -0
  458. agentcore/operations/dev/otel/transforms.py +331 -0
  459. agentcore/operations/dev/payment_env.py +50 -0
  460. agentcore/operations/dev/server.py +28 -0
  461. agentcore/operations/dev/sse_transform.py +30 -0
  462. agentcore/operations/dev/utils.py +152 -0
  463. agentcore/operations/dev/web_ui/__init__.py +31 -0
  464. agentcore/operations/dev/web_ui/constants.py +25 -0
  465. agentcore/operations/dev/web_ui/handlers/__init__.py +36 -0
  466. agentcore/operations/dev/web_ui/handlers/_common.py +36 -0
  467. agentcore/operations/dev/web_ui/handlers/_deployed.py +37 -0
  468. agentcore/operations/dev/web_ui/handlers/a2a_proxy.py +37 -0
  469. agentcore/operations/dev/web_ui/handlers/cloudwatch_traces.py +71 -0
  470. agentcore/operations/dev/web_ui/handlers/harness_invocation.py +89 -0
  471. agentcore/operations/dev/web_ui/handlers/harness_utils.py +95 -0
  472. agentcore/operations/dev/web_ui/handlers/invocations.py +327 -0
  473. agentcore/operations/dev/web_ui/handlers/mcp_proxy.py +119 -0
  474. agentcore/operations/dev/web_ui/handlers/memory.py +84 -0
  475. agentcore/operations/dev/web_ui/handlers/resources.py +351 -0
  476. agentcore/operations/dev/web_ui/handlers/start.py +182 -0
  477. agentcore/operations/dev/web_ui/handlers/status.py +25 -0
  478. agentcore/operations/dev/web_ui/handlers/traces.py +50 -0
  479. agentcore/operations/dev/web_ui/run_web_ui.py +60 -0
  480. agentcore/operations/dev/web_ui/web_server.py +297 -0
  481. agentcore/operations/eval/__init__.py +8 -0
  482. agentcore/operations/eval/list_eval_runs.py +18 -0
  483. agentcore/operations/eval/logs_eval.py +119 -0
  484. agentcore/operations/eval/pause_resume.py +90 -0
  485. agentcore/operations/eval/run_eval.py +354 -0
  486. agentcore/operations/eval/shared/__init__.py +0 -0
  487. agentcore/operations/eval/shared/dataset_loader.py +68 -0
  488. agentcore/operations/eval/shared/dataset_session_provider.py +122 -0
  489. agentcore/operations/eval/shared/evaluator_runner.py +89 -0
  490. agentcore/operations/eval/shared/scenario_executor.py +71 -0
  491. agentcore/operations/eval/shared/span_collector.py +255 -0
  492. agentcore/operations/eval/storage.py +67 -0
  493. agentcore/operations/feedback/__init__.py +21 -0
  494. agentcore/operations/feedback/aperture_client.py +98 -0
  495. agentcore/operations/feedback/build_payload.py +97 -0
  496. agentcore/operations/feedback/constants.py +26 -0
  497. agentcore/operations/feedback/submit_feedback.py +150 -0
  498. agentcore/operations/fetch_access/__init__.py +36 -0
  499. agentcore/operations/fetch_access/_target.py +17 -0
  500. agentcore/operations/fetch_access/fetch_gateway_token.py +75 -0
  501. agentcore/operations/fetch_access/fetch_harness_token.py +72 -0
  502. agentcore/operations/fetch_access/fetch_runtime_token.py +76 -0
  503. agentcore/operations/fetch_access/list_agents.py +18 -0
  504. agentcore/operations/fetch_access/list_gateways.py +26 -0
  505. agentcore/operations/fetch_access/list_harnesses.py +23 -0
  506. agentcore/operations/fetch_access/oauth_token.py +162 -0
  507. agentcore/operations/fetch_access/types.py +34 -0
  508. agentcore/operations/harness/__init__.py +1 -0
  509. agentcore/operations/harness/orphan.py +84 -0
  510. agentcore/operations/harness/skill_utils.py +56 -0
  511. agentcore/operations/identity/__init__.py +33 -0
  512. agentcore/operations/identity/api_key_credential_provider.py +68 -0
  513. agentcore/operations/identity/oauth2_credential_provider.py +95 -0
  514. agentcore/operations/ingest/__init__.py +184 -0
  515. agentcore/operations/init/__init__.py +3 -0
  516. agentcore/operations/init/files.py +59 -0
  517. agentcore/operations/insights/__init__.py +21 -0
  518. agentcore/operations/insights/insights_storage.py +67 -0
  519. agentcore/operations/insights/run_insights.py +148 -0
  520. agentcore/operations/invoke/__init__.py +5 -0
  521. agentcore/operations/invoke/resolve_agent_context.py +85 -0
  522. agentcore/operations/jobs/__init__.py +38 -0
  523. agentcore/operations/jobs/ab_test/__init__.py +0 -0
  524. agentcore/operations/jobs/ab_test/build_options.py +126 -0
  525. agentcore/operations/jobs/ab_test/format.py +121 -0
  526. agentcore/operations/jobs/ab_test/handler.py +412 -0
  527. agentcore/operations/jobs/ab_test/promote.py +142 -0
  528. agentcore/operations/jobs/ab_test/resolve.py +221 -0
  529. agentcore/operations/jobs/batch_evaluation/__init__.py +0 -0
  530. agentcore/operations/jobs/batch_evaluation/build_source.py +68 -0
  531. agentcore/operations/jobs/batch_evaluation/dataset_phase1.py +95 -0
  532. agentcore/operations/jobs/batch_evaluation/format.py +58 -0
  533. agentcore/operations/jobs/batch_evaluation/handler.py +203 -0
  534. agentcore/operations/jobs/insights/__init__.py +0 -0
  535. agentcore/operations/jobs/insights/format.py +65 -0
  536. agentcore/operations/jobs/insights/handler.py +178 -0
  537. agentcore/operations/jobs/recommendation/__init__.py +0 -0
  538. agentcore/operations/jobs/recommendation/apply_to_bundle.py +76 -0
  539. agentcore/operations/jobs/recommendation/build_config.py +271 -0
  540. agentcore/operations/jobs/recommendation/fetch_session_spans.py +93 -0
  541. agentcore/operations/jobs/recommendation/format.py +77 -0
  542. agentcore/operations/jobs/recommendation/handler.py +331 -0
  543. agentcore/operations/jobs/shared/__init__.py +0 -0
  544. agentcore/operations/jobs/shared/constants.py +85 -0
  545. agentcore/operations/jobs/shared/engine.py +187 -0
  546. agentcore/operations/jobs/shared/format.py +104 -0
  547. agentcore/operations/jobs/shared/region.py +34 -0
  548. agentcore/operations/jobs/shared/resolve_agent_state.py +30 -0
  549. agentcore/operations/jobs/shared/storage.py +117 -0
  550. agentcore/operations/jobs/shared/wait.py +30 -0
  551. agentcore/operations/knowledge_base/__init__.py +33 -0
  552. agentcore/operations/knowledge_base/connector_config.py +105 -0
  553. agentcore/operations/knowledge_base/hydrate_data_sources.py +59 -0
  554. agentcore/operations/mcp/__init__.py +4 -0
  555. agentcore/operations/memory/__init__.py +13 -0
  556. agentcore/operations/memory/_records.py +72 -0
  557. agentcore/operations/memory/list_memory_records.py +45 -0
  558. agentcore/operations/memory/retrieve_memory_records.py +52 -0
  559. agentcore/operations/node/__init__.py +15 -0
  560. agentcore/operations/node/setup.py +36 -0
  561. agentcore/operations/python/__init__.py +17 -0
  562. agentcore/operations/python/setup.py +47 -0
  563. agentcore/operations/resolve_agent.py +159 -0
  564. agentcore/operations/session/__init__.py +86 -0
  565. agentcore/operations/traces/__init__.py +29 -0
  566. agentcore/operations/traces/get_trace.py +202 -0
  567. agentcore/operations/traces/insights_query.py +74 -0
  568. agentcore/operations/traces/list_traces.py +46 -0
  569. agentcore/operations/traces/trace_url.py +25 -0
  570. agentcore/operations/traces/types.py +55 -0
  571. agentcore/primitives/__init__.py +0 -0
  572. agentcore/primitives/_gateway_target_wizard.py +293 -0
  573. agentcore/primitives/_gateway_validation.py +442 -0
  574. agentcore/primitives/_harness_cli.py +557 -0
  575. agentcore/primitives/_harness_validation.py +163 -0
  576. agentcore/primitives/_harness_wizard.py +726 -0
  577. agentcore/primitives/_knowledge_base_wizard.py +259 -0
  578. agentcore/primitives/_payment_wizard.py +331 -0
  579. agentcore/primitives/_policy_form.py +160 -0
  580. agentcore/primitives/agent.py +817 -0
  581. agentcore/primitives/auth_utils.py +77 -0
  582. agentcore/primitives/base.py +178 -0
  583. agentcore/primitives/capacity_provider.py +501 -0
  584. agentcore/primitives/config_bundle.py +329 -0
  585. agentcore/primitives/credential.py +387 -0
  586. agentcore/primitives/credential_utils.py +45 -0
  587. agentcore/primitives/dataset.py +211 -0
  588. agentcore/primitives/deployed_gateways.py +34 -0
  589. agentcore/primitives/evaluator.py +909 -0
  590. agentcore/primitives/gateway.py +496 -0
  591. agentcore/primitives/gateway_target.py +988 -0
  592. agentcore/primitives/harness.py +706 -0
  593. agentcore/primitives/knowledge_base.py +477 -0
  594. agentcore/primitives/memory.py +387 -0
  595. agentcore/primitives/online_eval_config.py +365 -0
  596. agentcore/primitives/online_insights.py +275 -0
  597. agentcore/primitives/payment_connector.py +427 -0
  598. agentcore/primitives/payment_eligible.py +20 -0
  599. agentcore/primitives/payment_manager.py +605 -0
  600. agentcore/primitives/payment_validation.py +68 -0
  601. agentcore/primitives/policy.py +622 -0
  602. agentcore/primitives/policy_engine.py +358 -0
  603. agentcore/primitives/registry.py +56 -0
  604. agentcore/primitives/runtime_endpoint.py +361 -0
  605. agentcore/primitives/secret_flag_warning.py +17 -0
  606. agentcore/schema/__init__.py +14 -0
  607. agentcore/schema/_zod.py +395 -0
  608. agentcore/schema/constants.py +306 -0
  609. agentcore/schema/schemas/__init__.py +40 -0
  610. agentcore/schema/schemas/agent_env.py +545 -0
  611. agentcore/schema/schemas/agentcore_project.py +530 -0
  612. agentcore/schema/schemas/auth.py +286 -0
  613. agentcore/schema/schemas/aws_targets.py +72 -0
  614. agentcore/schema/schemas/connections.py +187 -0
  615. agentcore/schema/schemas/deployed_state.py +322 -0
  616. agentcore/schema/schemas/mcp.py +650 -0
  617. agentcore/schema/schemas/mcp_defs.py +54 -0
  618. agentcore/schema/schemas/primitives/__init__.py +52 -0
  619. agentcore/schema/schemas/primitives/ab_test.py +162 -0
  620. agentcore/schema/schemas/primitives/capacity_provider.py +214 -0
  621. agentcore/schema/schemas/primitives/config_bundle.py +48 -0
  622. agentcore/schema/schemas/primitives/dataset.py +55 -0
  623. agentcore/schema/schemas/primitives/evaluator.py +171 -0
  624. agentcore/schema/schemas/primitives/harness.py +710 -0
  625. agentcore/schema/schemas/primitives/knowledge_base.py +90 -0
  626. agentcore/schema/schemas/primitives/memory.py +113 -0
  627. agentcore/schema/schemas/primitives/online_eval_config.py +77 -0
  628. agentcore/schema/schemas/primitives/payment.py +114 -0
  629. agentcore/schema/schemas/primitives/policy.py +83 -0
  630. agentcore/schema/schemas/primitives/tags.py +50 -0
  631. agentcore/schema/schemas/zod_util.py +5 -0
  632. agentcore/schema/types/__init__.py +3 -0
  633. agentcore/schema/types/path.py +16 -0
  634. agentcore/templates/__init__.py +115 -0
  635. agentcore/templates/_handlebars.py +782 -0
  636. agentcore/templates/_js.py +164 -0
  637. agentcore/templates/base_renderer.py +107 -0
  638. agentcore/templates/cdk_renderer.py +129 -0
  639. agentcore/templates/evaluator_renderer.py +39 -0
  640. agentcore/templates/gateway_target_renderer.py +69 -0
  641. agentcore/templates/llm_context/README.md +16 -0
  642. agentcore/templates/llm_context/agentcore.ts +685 -0
  643. agentcore/templates/llm_context/aws-targets.ts +51 -0
  644. agentcore/templates/profiles.py +151 -0
  645. agentcore/templates/render.py +92 -0
  646. agentcore/templates/renderers.py +83 -0
  647. agentcore/templates/schema_assets.py +23 -0
  648. agentcore/templates/template_root.py +28 -0
  649. agentcore/templates/types.py +192 -0
  650. agentcore_cli-0.31.1.dist-info/METADATA +84 -0
  651. agentcore_cli-0.31.1.dist-info/RECORD +655 -0
  652. agentcore_cli-0.31.1.dist-info/WHEEL +4 -0
  653. agentcore_cli-0.31.1.dist-info/entry_points.txt +2 -0
  654. agentcore_cli-0.31.1.dist-info/licenses/LICENSE +175 -0
  655. agentcore_cli-0.31.1.dist-info/licenses/NOTICE +88 -0
@@ -0,0 +1,97 @@
1
+ """`agentcore run ingest` (port of the `ingest` subcommand in src/cli/commands/run/command.tsx)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import signal as signal_module
7
+ import sys
8
+ import threading
9
+
10
+ import typer
11
+
12
+ from agentcore.cli.groups import group
13
+ from agentcore.cli.run_command import run_cli_command
14
+ from agentcore.lib.errors.types import ValidationError
15
+ from agentcore.lib.schemas.io.config_io import ConfigIO
16
+ from agentcore.lib.schemas.io.path_resolver import find_config_root
17
+ from agentcore.operations.ingest import RunKbIngestionInput, run_kb_ingestion_by_name
18
+
19
+
20
+ def _empty_state(): # readDeployedState().catch(() => ({ targets: {} }))
21
+ from agentcore.schema import DeployedState
22
+
23
+ return DeployedState(targets={})
24
+
25
+
26
+ def run_ingest(name: str | None, target: str, data_source: str | None, as_json: bool) -> None:
27
+ if not name:
28
+ raise ValidationError("A --name is required for `agentcore run ingest`.")
29
+ target_name = target or "default"
30
+
31
+ config_io = ConfigIO()
32
+ project = config_io.read_project_spec()
33
+ aws_targets = config_io.read_aws_deployment_targets()
34
+ try:
35
+ deployed_state = config_io.read_deployed_state()
36
+ except Exception: # noqa: BLE001 - missing/invalid state means nothing is deployed
37
+ deployed_state = _empty_state()
38
+
39
+ if not any(kb.name == name for kb in project.knowledge_bases or []):
40
+ raise ValidationError(f"Knowledge base '{name}' is not in agentcore.json.")
41
+ aws_target = next((t for t in aws_targets if t.name == target_name), None)
42
+ if aws_target is None:
43
+ raise ValidationError(f"Deployment target '{target_name}' is not in aws-targets.json.")
44
+
45
+ # Ctrl+C aborts long retry sleeps cleanly. Progress goes to stderr so --json stdout stays parseable.
46
+ abort = threading.Event()
47
+ previous = None
48
+ if threading.current_thread() is threading.main_thread():
49
+ previous = signal_module.signal(signal_module.SIGINT, lambda *_: abort.set())
50
+ try:
51
+ result = run_kb_ingestion_by_name(
52
+ RunKbIngestionInput(
53
+ knowledge_base_name=name,
54
+ deployed_state=deployed_state,
55
+ target_name=target_name,
56
+ region=aws_target.region,
57
+ data_source_uri=data_source,
58
+ signal=abort,
59
+ on_progress=None if as_json else (lambda msg: sys.stderr.write(f"{msg}\n")),
60
+ )
61
+ )
62
+ finally:
63
+ if previous is not None:
64
+ signal_module.signal(signal_module.SIGINT, previous)
65
+
66
+ if not result.success:
67
+ raise result.error
68
+
69
+ jobs = result.value.started_jobs
70
+ if as_json:
71
+ typer.echo(json.dumps({"success": True, "startedJobs": [j.to_json() for j in jobs]}, separators=(",", ":")))
72
+ else:
73
+ typer.echo(f"Started ingestion for '{name}' ({len(jobs)} data source(s)):")
74
+ for job in jobs:
75
+ typer.echo(f" {job.uri} → {job.ingestion_job_id}")
76
+ typer.echo("\nRun 'agentcore status' to track progress.")
77
+
78
+
79
+ def ingest_command(
80
+ name: str | None = typer.Option(None, "--name", help="Knowledge base name (must exist in agentcore.json)"),
81
+ target: str = typer.Option("default", "--target", help='Deployment target name (defaults to "default")'),
82
+ data_source: str | None = typer.Option(
83
+ None, "--data-source", help="Ingest only the data source with this URI (default: all sources)"
84
+ ),
85
+ as_json: bool = typer.Option(False, "--json", help="Output as JSON [non-interactive]"),
86
+ ) -> None:
87
+ if not find_config_root():
88
+ typer.echo("No agentcore project found. Run `agentcore create` first.", err=True)
89
+ raise typer.Exit(1)
90
+ run_cli_command(as_json, lambda: run_ingest(name, target, data_source, as_json))
91
+
92
+
93
+ def register(app: typer.Typer) -> None:
94
+ group("run").command(
95
+ "ingest",
96
+ help="Start a fresh ingestion job for every data source on a deployed knowledge base.",
97
+ )(ingest_command)
File without changes
@@ -0,0 +1,9 @@
1
+ """ARN shape check (port of src/cli/commands/shared/arn-utils.ts)."""
2
+
3
+ _ARN_PART_COUNT = 6
4
+ _ARN_FORMAT = "arn:partition:service:region:account:resource"
5
+ ARN_VALIDATION_MESSAGE = f"Must be a valid ARN ({_ARN_FORMAT})"
6
+
7
+
8
+ def is_valid_arn(value: str) -> bool:
9
+ return value.startswith("arn:") and len(value.split(":")) >= _ARN_PART_COUNT
@@ -0,0 +1,421 @@
1
+ """Filesystem mount helpers for runtimes (port of src/cli/commands/shared/filesystem-utils.ts).
2
+
3
+ Mount entries are camelCase dicts, ready for agentcore.json:
4
+ ``{"accessPointArn": ..., "mountPath": ...}`` and ``{"volumeName": ..., "mountPath": ...}``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from collections.abc import Callable, Sequence
11
+ from dataclasses import dataclass, field
12
+ from typing import Any, Literal
13
+
14
+ from agentcore.aws.account import create_aws_client
15
+ from agentcore.schema import EFS_ACCESS_POINT_ARN_PATTERN, S3_FILES_ACCESS_POINT_ARN_PATTERN
16
+ from agentcore.schema._zod import js_regex
17
+
18
+ _BYO_MOUNT_PATH = js_regex(r"^\/mnt\/[a-zA-Z0-9._-]+\/?$")
19
+
20
+
21
+ @dataclass
22
+ class MountsResult:
23
+ success: bool
24
+ mounts: list[dict[str, str]] = field(default_factory=list)
25
+ error: str | None = None
26
+
27
+
28
+ @dataclass
29
+ class SyncResult:
30
+ success: bool
31
+ error: str | None = None
32
+
33
+
34
+ def _ok() -> SyncResult:
35
+ return SyncResult(True)
36
+
37
+
38
+ def _fail(error: str) -> SyncResult:
39
+ return SyncResult(False, error)
40
+
41
+
42
+ def _err_message(err: BaseException) -> str:
43
+ return str(err)
44
+
45
+
46
+ # --- sync format checks -------------------------------------------------------------------------
47
+
48
+
49
+ def validate_efs_access_point_arn(arn: str) -> Literal[True] | str:
50
+ if not EFS_ACCESS_POINT_ARN_PATTERN.search(arn):
51
+ return (
52
+ f'Invalid EFS access point ARN: "{arn}". Expected '
53
+ "arn:[partition]:elasticfilesystem:{region}:{account}:access-point/fsap-{id}"
54
+ )
55
+ return True
56
+
57
+
58
+ def validate_s3_files_access_point_arn(arn: str) -> Literal[True] | str:
59
+ if not S3_FILES_ACCESS_POINT_ARN_PATTERN.search(arn):
60
+ return (
61
+ f'Invalid S3 Files access point ARN: "{arn}". Expected '
62
+ "arn:[partition]:s3files:{region}:{account}:file-system/fs-{id}/access-point/fsap-{id}"
63
+ )
64
+ return True
65
+
66
+
67
+ def validate_byo_mount_path(path: str) -> Literal[True] | str:
68
+ """Validate a BYO filesystem mount path (/mnt/<name>)."""
69
+ if len(path) < 6 or len(path) > 200:
70
+ return f'Invalid mount path: "{path}". Must be between 6 and 200 characters'
71
+ if not _BYO_MOUNT_PATH.search(path):
72
+ return f'Invalid mount path: "{path}". Must be /mnt/<name> with exactly one subdirectory (e.g. /mnt/tools)'
73
+ return True
74
+
75
+
76
+ def zip_access_point_pairs(
77
+ arns: Sequence[str], mount_paths: Sequence[str], label: Literal["EFS", "S3 Files"]
78
+ ) -> MountsResult:
79
+ if len(arns) != len(mount_paths):
80
+ arn_flag = "--efs-access-point-arn" if label == "EFS" else "--s3-access-point-arn"
81
+ path_flag = "--efs-mount-path" if label == "EFS" else "--s3-mount-path"
82
+ return MountsResult(
83
+ False,
84
+ error=(
85
+ f"{label}: {arn_flag} and {path_flag} must be provided in matching pairs "
86
+ f"(got {len(arns)} ARN(s) and {len(mount_paths)} path(s))"
87
+ ),
88
+ )
89
+ return MountsResult(True, [{"accessPointArn": a, "mountPath": p} for a, p in zip(arns, mount_paths, strict=True)])
90
+
91
+
92
+ def zip_capacity_provider_volume_pairs(volume_names: Sequence[str], mount_paths: Sequence[str]) -> MountsResult:
93
+ if len(volume_names) != len(mount_paths):
94
+ return MountsResult(
95
+ False,
96
+ error=(
97
+ "Capacity provider volumes: --cp-volume-name and --cp-volume-mount-path must be provided in "
98
+ f"matching pairs (got {len(volume_names)} name(s) and {len(mount_paths)} path(s))"
99
+ ),
100
+ )
101
+ return MountsResult(
102
+ True, [{"volumeName": n, "mountPath": p} for n, p in zip(volume_names, mount_paths, strict=True)]
103
+ )
104
+
105
+
106
+ def validate_capacity_provider_volume_mounts(mounts: Sequence[dict[str, str]]) -> SyncResult:
107
+ for mount in mounts:
108
+ name = mount.get("volumeName") or ""
109
+ if not name.strip():
110
+ return _fail("Capacity provider volume name must not be empty")
111
+ path_result = validate_byo_mount_path(mount.get("mountPath", ""))
112
+ if path_result is not True:
113
+ return _fail(path_result)
114
+ return _ok()
115
+
116
+
117
+ def validate_access_point_mounts(
118
+ mounts: Sequence[dict[str, str]], arn_validator: Callable[[str], Literal[True] | str]
119
+ ) -> SyncResult:
120
+ for mount in mounts:
121
+ arn_result = arn_validator(mount["accessPointArn"])
122
+ if arn_result is not True:
123
+ return _fail(arn_result)
124
+ path_result = validate_byo_mount_path(mount["mountPath"])
125
+ if path_result is not True:
126
+ return _fail(path_result)
127
+ return _ok()
128
+
129
+
130
+ def build_filesystem_configurations(
131
+ session_storage_mount_path: str | None = None,
132
+ efs_access_points: Sequence[dict[str, str]] | None = None,
133
+ s3_access_points: Sequence[dict[str, str]] | None = None,
134
+ capacity_provider_volumes: Sequence[dict[str, str]] | None = None,
135
+ ) -> dict[str, Any]:
136
+ """``{"filesystemConfigurations": [...]}`` when any mount is present, else ``{}``."""
137
+
138
+ def norm(p: str) -> str:
139
+ return p[:-1] if p.endswith("/") else p
140
+
141
+ fcs: list[dict[str, Any]] = []
142
+ if session_storage_mount_path:
143
+ fcs.append({"sessionStorage": {"mountPath": norm(session_storage_mount_path)}})
144
+ for ap in efs_access_points or []:
145
+ fcs.append({"efsAccessPoint": {**ap, "mountPath": norm(ap["mountPath"])}})
146
+ for ap in s3_access_points or []:
147
+ fcs.append({"s3FilesAccessPoint": {**ap, "mountPath": norm(ap["mountPath"])}})
148
+ for vol in capacity_provider_volumes or []:
149
+ fcs.append({"capacityProviderVolume": {**vol, "mountPath": norm(vol["mountPath"])}})
150
+ return {"filesystemConfigurations": fcs} if fcs else {}
151
+
152
+
153
+ # --- async validators (Level 1-3) ---------------------------------------------------------------
154
+
155
+
156
+ @dataclass
157
+ class _MountTargetData:
158
+ mount_target_id: str
159
+ subnet_id: str
160
+ vpc_id: str
161
+ availability_zone_id: str | None
162
+ security_group_ids: list[str]
163
+
164
+
165
+ def _region_from_arn(arn: str) -> str:
166
+ return arn.split(":")[3]
167
+
168
+
169
+ def _access_point_id(arn: str) -> str:
170
+ return arn.split("/")[-1]
171
+
172
+
173
+ def _allows_2049(rule: dict[str, Any]) -> bool:
174
+ proto = rule.get("IpProtocol")
175
+ from_port = rule.get("FromPort", 0)
176
+ to_port = rule.get("ToPort", 65535)
177
+ return proto == "-1" or (proto in ("tcp", "6") and from_port <= 2049 and to_port >= 2049)
178
+
179
+
180
+ def _from_anywhere(rule: dict[str, Any]) -> bool:
181
+ return any(r.get("CidrIp") == "0.0.0.0/0" for r in rule.get("IpRanges") or []) or any(
182
+ r.get("CidrIpv6") == "::/0" for r in rule.get("Ipv6Ranges") or []
183
+ )
184
+
185
+
186
+ def validate_efs_access_point_exists(arn: str, region: str) -> SyncResult:
187
+ """Level 1: the EFS access point exists (DescribeAccessPoints)."""
188
+ try:
189
+ client = create_aws_client("efs", region)
190
+ resp = client.describe_access_points(AccessPointId=_access_point_id(arn))
191
+ if not resp.get("AccessPoints"):
192
+ return _fail(f"EFS access point not found: {arn}")
193
+ return _ok()
194
+ except Exception as exc: # noqa: BLE001
195
+ return _fail(f"EFS access point lookup failed for {arn}: {_err_message(exc)}")
196
+
197
+
198
+ def validate_s3_files_access_point_exists(arn: str, region: str) -> SyncResult:
199
+ """Level 1: the S3 Files access point has mount targets (ListMountTargets)."""
200
+ try:
201
+ client = create_aws_client("s3files", region)
202
+ resp = client.list_mount_targets(accessPointId=_access_point_id(arn))
203
+ if not resp.get("mountTargets"):
204
+ return _fail(f"S3 Files access point has no mount targets: {arn}")
205
+ return _ok()
206
+ except Exception as exc: # noqa: BLE001
207
+ return _fail(f"S3 Files access point lookup failed for {arn}: {_err_message(exc)}")
208
+
209
+
210
+ def validate_security_group_egress_port_2049(security_group_ids: Sequence[str], region: str) -> SyncResult:
211
+ """Level 1: at least one agent SG allows outbound TCP 2049 (NFS)."""
212
+ try:
213
+ ec2 = create_aws_client("ec2", region)
214
+ resp = ec2.describe_security_groups(GroupIds=list(security_group_ids))
215
+ for sg in resp.get("SecurityGroups") or []:
216
+ for rule in sg.get("IpPermissionsEgress") or []:
217
+ has_destination = _from_anywhere(rule) or len(rule.get("UserIdGroupPairs") or []) > 0
218
+ if _allows_2049(rule) and has_destination:
219
+ return _ok()
220
+ return _fail(
221
+ f"Agent security groups [{', '.join(security_group_ids)}] do not allow outbound TCP 2049 (NFS). "
222
+ "Add an egress rule for port 2049."
223
+ )
224
+ except Exception as exc: # noqa: BLE001
225
+ return _fail(f"Security group egress check failed: {_err_message(exc)}")
226
+
227
+
228
+ def _resolve_efs_data(arn: str, region: str) -> _MountTargetData | str:
229
+ try:
230
+ client = create_aws_client("efs", region)
231
+ mt_resp = client.describe_mount_targets(AccessPointId=_access_point_id(arn))
232
+ mts = mt_resp.get("MountTargets") or []
233
+ mt = mts[0] if mts else {}
234
+ if not mt.get("MountTargetId") or not mt.get("SubnetId") or not mt.get("VpcId"):
235
+ return f"EFS access point {arn} has no available mount targets"
236
+ sg_resp = client.describe_mount_target_security_groups(MountTargetId=mt["MountTargetId"])
237
+ return _MountTargetData(
238
+ mt["MountTargetId"],
239
+ mt["SubnetId"],
240
+ mt["VpcId"],
241
+ mt.get("AvailabilityZoneId"),
242
+ list(sg_resp.get("SecurityGroups") or []),
243
+ )
244
+ except Exception as exc: # noqa: BLE001
245
+ return f"Failed to resolve EFS mount target for {arn}: {_err_message(exc)}"
246
+
247
+
248
+ def _resolve_s3_files_data(arn: str, region: str) -> _MountTargetData | str:
249
+ try:
250
+ client = create_aws_client("s3files", region)
251
+ list_resp = client.list_mount_targets(accessPointId=_access_point_id(arn))
252
+ mts = list_resp.get("mountTargets") or []
253
+ mt = mts[0] if mts else {}
254
+ if not mt.get("mountTargetId"):
255
+ return f"S3 Files access point {arn} has no available mount targets"
256
+ get_resp = client.get_mount_target(mountTargetId=mt["mountTargetId"])
257
+ if not get_resp.get("subnetId") or not get_resp.get("vpcId"):
258
+ return f"S3 Files mount target {mt['mountTargetId']} is missing subnet or VPC info"
259
+ return _MountTargetData(
260
+ mt["mountTargetId"],
261
+ get_resp["subnetId"],
262
+ get_resp["vpcId"],
263
+ get_resp.get("availabilityZoneId"),
264
+ list(get_resp.get("securityGroups") or []),
265
+ )
266
+ except Exception as exc: # noqa: BLE001
267
+ return f"Failed to resolve S3 Files mount target for {arn}: {_err_message(exc)}"
268
+
269
+
270
+ def _validate_mount_target_in_vpc_and_az(
271
+ data: _MountTargetData, agent_subnet_ids: Sequence[str], agent_vpc_id: str, region: str, label: str
272
+ ) -> SyncResult:
273
+ """Level 2: mount target in the agent VPC, with an agent subnet in its AZ."""
274
+ if data.vpc_id != agent_vpc_id:
275
+ return _fail(f"{label} mount target VPC ({data.vpc_id}) does not match agent VPC ({agent_vpc_id})")
276
+ if not data.availability_zone_id:
277
+ return _ok()
278
+ try:
279
+ ec2 = create_aws_client("ec2", region)
280
+ resp = ec2.describe_subnets(SubnetIds=list(agent_subnet_ids))
281
+ agent_az_ids = {s.get("AvailabilityZoneId") for s in resp.get("Subnets") or [] if s.get("AvailabilityZoneId")}
282
+ if data.availability_zone_id not in agent_az_ids:
283
+ az = data.availability_zone_id
284
+ return _fail(
285
+ f"{label} mount target is in AZ {az} but no agent subnet is in that AZ. "
286
+ f"Add a subnet in AZ {az} to your agent configuration."
287
+ )
288
+ except Exception as exc: # noqa: BLE001
289
+ return _fail(f"Subnet AZ validation failed for {label}: {_err_message(exc)}")
290
+ return _ok()
291
+
292
+
293
+ def _validate_mount_target_inbound_from_agent_sg(
294
+ mount_sg_ids: Sequence[str], agent_sg_ids: Sequence[str], region: str, label: str
295
+ ) -> SyncResult:
296
+ """Level 3: mount target SGs allow inbound TCP 2049 from an agent SG."""
297
+ if not mount_sg_ids:
298
+ return _ok()
299
+ try:
300
+ ec2 = create_aws_client("ec2", region)
301
+ resp = ec2.describe_security_groups(GroupIds=list(mount_sg_ids))
302
+ agent_set = set(agent_sg_ids)
303
+ for sg in resp.get("SecurityGroups") or []:
304
+ for rule in sg.get("IpPermissions") or []:
305
+ if not _allows_2049(rule):
306
+ continue
307
+ from_agent = any(p.get("GroupId") in agent_set for p in rule.get("UserIdGroupPairs") or [])
308
+ if from_agent or _from_anywhere(rule):
309
+ return _ok()
310
+ return _fail(
311
+ f"{label} mount target security groups [{', '.join(mount_sg_ids)}] do not allow inbound TCP 2049 "
312
+ f"from agent security groups [{', '.join(agent_sg_ids)}]. Add an inbound rule for port 2049 from the "
313
+ "agent SG."
314
+ )
315
+ except Exception as exc: # noqa: BLE001
316
+ return _fail(f"Mount target inbound SG check failed for {label}: {_err_message(exc)}")
317
+
318
+
319
+ def validate_filesystem_mounts_configuration(
320
+ *,
321
+ efs_mounts: Sequence[dict[str, str]],
322
+ s3_files_mounts: Sequence[dict[str, str]],
323
+ region: str,
324
+ agent_vpc_id: str | None = None,
325
+ agent_subnet_ids: Sequence[str] | None = None,
326
+ agent_security_group_ids: Sequence[str] | None = None,
327
+ skip_topology_checks: bool = False,
328
+ skip_inbound_sg_checks: bool = False,
329
+ ) -> SyncResult:
330
+ """Levels 1-3 of filesystem validation; returns the first error. Levels lacking data are skipped."""
331
+ if agent_security_group_ids and (efs_mounts or s3_files_mounts):
332
+ egress = validate_security_group_egress_port_2049(agent_security_group_ids, region)
333
+ if not egress.success:
334
+ return egress
335
+
336
+ checks: list[tuple[Sequence[dict[str, str]], str, Callable[[str, str], SyncResult], Callable[..., Any]]] = [
337
+ (efs_mounts, "EFS", validate_efs_access_point_exists, _resolve_efs_data),
338
+ (s3_files_mounts, "S3 Files", validate_s3_files_access_point_exists, _resolve_s3_files_data),
339
+ ]
340
+ for mounts, label, exists, resolve in checks:
341
+ for mount in mounts:
342
+ arn = mount["accessPointArn"]
343
+ mount_region = _region_from_arn(arn)
344
+ result = exists(arn, mount_region)
345
+ if not result.success:
346
+ return result
347
+ if not skip_topology_checks and agent_vpc_id and agent_subnet_ids:
348
+ data = resolve(arn, mount_region)
349
+ if isinstance(data, str):
350
+ return _fail(data)
351
+ vpc_result = _validate_mount_target_in_vpc_and_az(data, agent_subnet_ids, agent_vpc_id, region, label)
352
+ if not vpc_result.success:
353
+ return vpc_result
354
+ if not skip_inbound_sg_checks and agent_security_group_ids:
355
+ # Mount target SGs live in the mount's region, not the agent region.
356
+ sg_result = _validate_mount_target_inbound_from_agent_sg(
357
+ data.security_group_ids, agent_security_group_ids, mount_region, label
358
+ )
359
+ if not sg_result.success:
360
+ return sg_result
361
+ return _ok()
362
+
363
+
364
+ def resolve_and_validate_filesystem_mounts(
365
+ options: dict[str, Any],
366
+ parse_comma_separated_list: Callable[[str | None], list[str] | None],
367
+ ) -> dict[str, list[dict[str, str]]]:
368
+ """Zip CLI flag pairs, resolve the agent VPC from subnets and run Levels 1-3. Raises on failure."""
369
+ efs = zip_access_point_pairs(options.get("efsAccessPointArn") or [], options.get("efsMountPath") or [], "EFS")
370
+ if not efs.success:
371
+ raise Exception(efs.error)
372
+ s3 = zip_access_point_pairs(options.get("s3AccessPointArn") or [], options.get("s3MountPath") or [], "S3 Files")
373
+ if not s3.success:
374
+ raise Exception(s3.error)
375
+
376
+ if efs.mounts or s3.mounts:
377
+ region = (
378
+ options.get("region") or os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION") or "us-east-1"
379
+ )
380
+ subnets = parse_comma_separated_list(options.get("subnets"))
381
+ security_groups = parse_comma_separated_list(options.get("securityGroups"))
382
+ agent_vpc_id: str | None = None
383
+ if subnets:
384
+ try:
385
+ ec2 = create_aws_client("ec2", region)
386
+ resp = ec2.describe_subnets(SubnetIds=list(subnets))
387
+ found = resp.get("Subnets") or []
388
+ agent_vpc_id = found[0].get("VpcId") if found else None
389
+ except Exception: # noqa: BLE001 - Level 2 is skipped when the VPC can't be resolved
390
+ pass
391
+ result = validate_filesystem_mounts_configuration(
392
+ efs_mounts=efs.mounts,
393
+ s3_files_mounts=s3.mounts,
394
+ agent_vpc_id=agent_vpc_id,
395
+ agent_subnet_ids=subnets,
396
+ agent_security_group_ids=security_groups,
397
+ region=region,
398
+ )
399
+ if not result.success:
400
+ raise Exception(result.error)
401
+
402
+ return {"efsMounts": efs.mounts, "s3Mounts": s3.mounts}
403
+
404
+
405
+ __all__ = [
406
+ "MountsResult",
407
+ "SyncResult",
408
+ "build_filesystem_configurations",
409
+ "resolve_and_validate_filesystem_mounts",
410
+ "validate_access_point_mounts",
411
+ "validate_byo_mount_path",
412
+ "validate_capacity_provider_volume_mounts",
413
+ "validate_efs_access_point_arn",
414
+ "validate_efs_access_point_exists",
415
+ "validate_filesystem_mounts_configuration",
416
+ "validate_s3_files_access_point_arn",
417
+ "validate_s3_files_access_point_exists",
418
+ "validate_security_group_egress_port_2049",
419
+ "zip_access_point_pairs",
420
+ "zip_capacity_provider_volume_pairs",
421
+ ]
@@ -0,0 +1,87 @@
1
+ """Request header helpers (port of src/cli/commands/shared/header-utils.ts)."""
2
+
3
+ import re
4
+ from dataclasses import dataclass
5
+
6
+ from agentcore.schema.schemas.agent_env import (
7
+ HEADER_ALLOWLIST_PREFIX,
8
+ HEADER_NAME_PATTERN,
9
+ MAX_HEADER_ALLOWLIST_SIZE,
10
+ check_allowlist_header,
11
+ )
12
+
13
+ __all__ = [
14
+ "HEADER_ALLOWLIST_PREFIX",
15
+ "HEADER_NAME_PATTERN",
16
+ "MAX_HEADER_ALLOWLIST_SIZE",
17
+ "HeaderValidationResult",
18
+ "normalize_header_name",
19
+ "parse_and_normalize_headers",
20
+ "parse_header_flag",
21
+ "parse_header_flags",
22
+ "validate_header_allowlist",
23
+ ]
24
+
25
+
26
+ @dataclass
27
+ class HeaderValidationResult:
28
+ success: bool
29
+ error: str | None = None
30
+
31
+
32
+ def normalize_header_name(value: str) -> str:
33
+ if value.lower() == "authorization":
34
+ return "Authorization"
35
+ if value.lower().startswith(HEADER_ALLOWLIST_PREFIX.lower()):
36
+ return f"{HEADER_ALLOWLIST_PREFIX}{value[len(HEADER_ALLOWLIST_PREFIX) :]}"
37
+ if re.match(r"^x-", value, re.IGNORECASE):
38
+ return value
39
+ return f"{HEADER_ALLOWLIST_PREFIX}{value}"
40
+
41
+
42
+ def parse_and_normalize_headers(value: str) -> list[str]:
43
+ """Split, normalize and de-duplicate (case-insensitively) a comma-separated header list."""
44
+ seen: set[str] = set()
45
+ result: list[str] = []
46
+ for header in (normalize_header_name(s.strip()) for s in value.split(",") if s.strip()):
47
+ if header.lower() not in seen:
48
+ seen.add(header.lower())
49
+ result.append(header)
50
+ return result
51
+
52
+
53
+ def validate_header_allowlist(value: str) -> HeaderValidationResult:
54
+ trimmed = value.strip()
55
+ if trimmed == "":
56
+ return HeaderValidationResult(True)
57
+ names = [s.strip() for s in trimmed.split(",") if s.strip()]
58
+ for name in names:
59
+ error = check_allowlist_header(name)
60
+ if error:
61
+ return HeaderValidationResult(False, error)
62
+ if len(names) > MAX_HEADER_ALLOWLIST_SIZE:
63
+ return HeaderValidationResult(
64
+ False, f"Header allowlist cannot exceed {MAX_HEADER_ALLOWLIST_SIZE} headers. Provided: {len(names)}"
65
+ )
66
+ return HeaderValidationResult(True)
67
+
68
+
69
+ def parse_header_flag(raw: str) -> tuple[str, str] | None:
70
+ """Parse "Key: Value" into (normalized name, value); None when malformed."""
71
+ idx = raw.find(":")
72
+ if idx < 1:
73
+ return None
74
+ name = raw[:idx].strip()
75
+ if not name:
76
+ return None
77
+ return normalize_header_name(name), raw[idx + 1 :].strip()
78
+
79
+
80
+ def parse_header_flags(raw_headers: list[str]) -> dict[str, str]:
81
+ result: dict[str, str] = {}
82
+ for raw in raw_headers:
83
+ parsed = parse_header_flag(raw)
84
+ if parsed is None:
85
+ raise ValueError(f'Invalid header format: "{raw}". Expected "Header-Name: value" or "Header-Name:value".')
86
+ result[parsed[0]] = parsed[1]
87
+ return result