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,150 @@
1
+ """Validate and submit feedback (port of submit-feedback.ts)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import base64
6
+ import hashlib
7
+ import os
8
+ from dataclasses import dataclass
9
+ from typing import Any
10
+ from urllib.parse import unquote, urlsplit
11
+
12
+ from agentcore.lib.errors.types import ValidationError
13
+ from agentcore.operations.feedback import aperture_client
14
+ from agentcore.operations.feedback.build_payload import (
15
+ CLI_VERSION,
16
+ FeedbackMode,
17
+ build_feedback_payload,
18
+ build_user_agent,
19
+ )
20
+ from agentcore.operations.feedback.constants import (
21
+ ALLOWED_SCREENSHOT_EXTENSIONS,
22
+ APERTURE_FORM_CATEGORY,
23
+ APERTURE_FORM_NAME,
24
+ APERTURE_FORM_VERSION,
25
+ MAX_SCREENSHOT_BYTES,
26
+ )
27
+
28
+ FEEDBACK_MESSAGE_MAX_LENGTH = 1000
29
+
30
+
31
+ class FeedbackValidationError(ValidationError):
32
+ """User input the feedback command refuses to send."""
33
+
34
+
35
+ def validate_feedback_message(message: str) -> str | None:
36
+ trimmed = message.strip()
37
+ if not trimmed:
38
+ return "Feedback message cannot be empty."
39
+ if len(trimmed) > FEEDBACK_MESSAGE_MAX_LENGTH:
40
+ return f"Feedback message must be {FEEDBACK_MESSAGE_MAX_LENGTH} characters or fewer."
41
+ return None
42
+
43
+
44
+ @dataclass
45
+ class LoadedScreenshot:
46
+ data: bytes
47
+ file_name: str
48
+ content_type: str
49
+ sha256_base64: str
50
+ size: int
51
+
52
+
53
+ def _expand_tilde(path: str) -> str:
54
+ if path == "~":
55
+ return os.path.expanduser("~")
56
+ if path.startswith("~/"):
57
+ return os.path.join(os.path.expanduser("~"), path[2:])
58
+ return path
59
+
60
+
61
+ def _os_error_reason(exc: OSError) -> str:
62
+ """Node-style fs error text (``ENOENT: no such file or directory, stat '<path>'``)."""
63
+ import errno
64
+
65
+ code = errno.errorcode.get(exc.errno or 0, "EIO")
66
+ return f"{code}: {(exc.strerror or str(exc)).lower()}, stat '{exc.filename}'"
67
+
68
+
69
+ def load_and_validate_screenshot(raw_path: str) -> LoadedScreenshot:
70
+ path = _expand_tilde(raw_path)
71
+ try:
72
+ st = os.stat(path)
73
+ except OSError as exc:
74
+ raise FeedbackValidationError(f"Could not read screenshot at {path}: {_os_error_reason(exc)}") from None
75
+ import stat as stat_mod
76
+
77
+ if stat_mod.S_ISDIR(st.st_mode):
78
+ raise FeedbackValidationError(f"Screenshot path is a directory, not a file: {path}")
79
+ if not stat_mod.S_ISREG(st.st_mode):
80
+ raise FeedbackValidationError(f"Screenshot path is not a regular file: {path}")
81
+ ext = os.path.splitext(path)[1].lower()
82
+ if ext not in ALLOWED_SCREENSHOT_EXTENSIONS:
83
+ raise FeedbackValidationError(f"Screenshot must be one of: {', '.join(ALLOWED_SCREENSHOT_EXTENSIONS)}.")
84
+ try:
85
+ with open(path, "rb") as fh:
86
+ data = fh.read()
87
+ except OSError as exc:
88
+ raise FeedbackValidationError(f"Could not read screenshot at {path}: {_os_error_reason(exc)}") from None
89
+ if len(data) > MAX_SCREENSHOT_BYTES:
90
+ raise FeedbackValidationError(
91
+ f"Screenshot is {len(data) / (1024 * 1024):.1f} MB; maximum allowed size is 100 MB."
92
+ )
93
+ return LoadedScreenshot(
94
+ data=data,
95
+ file_name=os.path.basename(path),
96
+ content_type="image/png" if ext == ".png" else "image/jpeg",
97
+ sha256_base64=base64.b64encode(hashlib.sha256(data).digest()).decode(),
98
+ size=len(data),
99
+ )
100
+
101
+
102
+ def validate_screenshot_path(path: str) -> str | None:
103
+ try:
104
+ load_and_validate_screenshot(path)
105
+ return None
106
+ except FeedbackValidationError as exc:
107
+ return str(exc)
108
+
109
+
110
+ def _object_key_from_presigned_url(url: str) -> str:
111
+ return unquote(urlsplit(url).path.lstrip("/"))
112
+
113
+
114
+ def submit_feedback(message: str, screenshot: str | None = None, mode: FeedbackMode = "cli") -> dict[str, Any]:
115
+ """Returns ``{"id", "timestamp", "reference"}``."""
116
+ error = validate_feedback_message(message)
117
+ if error:
118
+ raise FeedbackValidationError(error)
119
+
120
+ user_agent = build_user_agent(CLI_VERSION)
121
+ reference: str | None = None
122
+ if screenshot:
123
+ file = load_and_validate_screenshot(screenshot)
124
+ presigned = aperture_client.fetch_presigned_url(
125
+ {
126
+ "category": APERTURE_FORM_CATEGORY,
127
+ "name": APERTURE_FORM_NAME,
128
+ "version": APERTURE_FORM_VERSION,
129
+ "fileName": file.file_name,
130
+ "fileSize": file.size,
131
+ "uploadFileSHA256": file.sha256_base64,
132
+ },
133
+ user_agent,
134
+ )
135
+ aperture_client.upload_file_to_s3(presigned, file.data, file.content_type, file.sha256_base64, user_agent)
136
+ reference = _object_key_from_presigned_url(presigned)
137
+
138
+ payload = build_feedback_payload(message.strip(), screenshot_reference=reference, mode=mode)
139
+ response = aperture_client.submit_form(payload, user_agent)
140
+ return {"id": response.get("id"), "timestamp": response.get("timestamp"), "reference": response.get("reference")}
141
+
142
+
143
+ __all__ = [
144
+ "FEEDBACK_MESSAGE_MAX_LENGTH",
145
+ "FeedbackValidationError",
146
+ "load_and_validate_screenshot",
147
+ "submit_feedback",
148
+ "validate_feedback_message",
149
+ "validate_screenshot_path",
150
+ ]
@@ -0,0 +1,36 @@
1
+ """Access info / OAuth tokens for deployed resources (port of src/cli/operations/fetch-access)."""
2
+
3
+ from agentcore.operations.fetch_access.fetch_gateway_token import fetch_gateway_token
4
+ from agentcore.operations.fetch_access.fetch_harness_token import can_fetch_harness_token, fetch_harness_token
5
+ from agentcore.operations.fetch_access.fetch_runtime_token import can_fetch_runtime_token, fetch_runtime_token
6
+ from agentcore.operations.fetch_access.list_agents import list_agents
7
+ from agentcore.operations.fetch_access.list_gateways import list_gateways
8
+ from agentcore.operations.fetch_access.list_harnesses import list_harnesses
9
+ from agentcore.operations.fetch_access.oauth_token import OAuthTokenResult, fetch_oauth_token
10
+ from agentcore.operations.fetch_access.types import (
11
+ AgentInfo,
12
+ FetchResourceType,
13
+ GatewayInfo,
14
+ HarnessInfo,
15
+ ResourceInfo,
16
+ TokenFetchResult,
17
+ )
18
+
19
+ __all__ = [
20
+ "AgentInfo",
21
+ "FetchResourceType",
22
+ "GatewayInfo",
23
+ "HarnessInfo",
24
+ "OAuthTokenResult",
25
+ "ResourceInfo",
26
+ "TokenFetchResult",
27
+ "can_fetch_harness_token",
28
+ "can_fetch_runtime_token",
29
+ "fetch_gateway_token",
30
+ "fetch_harness_token",
31
+ "fetch_oauth_token",
32
+ "fetch_runtime_token",
33
+ "list_agents",
34
+ "list_gateways",
35
+ "list_harnesses",
36
+ ]
@@ -0,0 +1,17 @@
1
+ """Shared deployed-target lookup for list_agents/list_gateways/list_harnesses."""
2
+
3
+ from typing import Any
4
+
5
+ from agentcore.lib.schemas.io.config_io import ConfigIO
6
+
7
+
8
+ def _target_resources(config_io: ConfigIO, deploy_target: str | None) -> tuple[Any, Any] | None:
9
+ deployed_state = config_io.read_deployed_state()
10
+ project_spec = config_io.read_project_spec()
11
+ targets = deployed_state.targets or {}
12
+ if not targets:
13
+ return None
14
+ target = targets.get(deploy_target or next(iter(targets)))
15
+ if target is None:
16
+ return None
17
+ return project_spec, target.resources
@@ -0,0 +1,75 @@
1
+ """Port of src/cli/operations/fetch-access/fetch-gateway-token.ts."""
2
+
3
+ from agentcore.lib.schemas.io.config_io import ConfigIO
4
+ from agentcore.operations.fetch_access import oauth_token
5
+ from agentcore.operations.fetch_access.types import TokenFetchResult
6
+
7
+
8
+ def fetch_gateway_token(
9
+ gateway_name: str,
10
+ *,
11
+ config_io: ConfigIO | None = None,
12
+ deploy_target: str | None = None,
13
+ identity_name: str | None = None,
14
+ ) -> TokenFetchResult:
15
+ config_io = config_io or ConfigIO()
16
+ deployed_state = config_io.read_deployed_state()
17
+ project_spec = config_io.read_project_spec()
18
+
19
+ target_names = list(deployed_state.targets or {})
20
+ if not target_names:
21
+ raise RuntimeError("No deployed targets found. Run `agentcore deploy` first.")
22
+ target_name = deploy_target or target_names[0]
23
+ target = deployed_state.targets.get(target_name)
24
+ if target is None:
25
+ raise RuntimeError(f"Deployment target '{target_name}' not found. Available targets: {', '.join(target_names)}")
26
+
27
+ gateways = project_spec.agent_core_gateways or []
28
+ gateway_spec = next((g for g in gateways if g.name == gateway_name), None)
29
+ if gateway_spec is None:
30
+ available = ", ".join(g.name for g in gateways) or "none"
31
+ raise RuntimeError(f"Gateway '{gateway_name}' not found in MCP configuration. Available gateways: {available}")
32
+
33
+ resources = target.resources
34
+ deployed_gateway = ((resources.gateways if resources else None) or {}).get(gateway_name)
35
+ if deployed_gateway is None and resources and resources.mcp:
36
+ deployed_gateway = (resources.mcp.gateways or {}).get(gateway_name)
37
+ if not (deployed_gateway and deployed_gateway.gateway_url):
38
+ raise RuntimeError(
39
+ f"Gateway '{gateway_name}' does not have a deployed URL. Run `agentcore deploy` to deploy the gateway."
40
+ )
41
+
42
+ gateway_url = deployed_gateway.gateway_url
43
+ auth_type = gateway_spec.authorizer_type
44
+ if auth_type == "NONE":
45
+ return {
46
+ "url": gateway_url,
47
+ "authType": "NONE",
48
+ "message": "No authentication required. Send requests directly to the URL.",
49
+ }
50
+ if auth_type == "AWS_IAM":
51
+ return {
52
+ "url": gateway_url,
53
+ "authType": "AWS_IAM",
54
+ "message": "This gateway uses AWS IAM auth. Sign requests with SigV4 using your IAM credentials.",
55
+ }
56
+
57
+ config = gateway_spec.authorizer_configuration
58
+ jwt_config = config.custom_jwt_authorizer if config else None
59
+ if jwt_config is None:
60
+ raise RuntimeError(
61
+ f"Gateway '{gateway_name}' is configured as CUSTOM_JWT but has no customJwtAuthorizer configuration."
62
+ )
63
+
64
+ result = oauth_token.fetch_oauth_token(
65
+ resource_name=gateway_name,
66
+ jwt_config=jwt_config,
67
+ deployed_state=deployed_state,
68
+ target_name=target_name,
69
+ credentials=project_spec.credentials or [],
70
+ credential_name=identity_name,
71
+ )
72
+ out: TokenFetchResult = {"url": gateway_url, "authType": "CUSTOM_JWT", "token": result.token}
73
+ if result.expires_in is not None:
74
+ out["expiresIn"] = result.expires_in
75
+ return out
@@ -0,0 +1,72 @@
1
+ """Port of src/cli/operations/fetch-access/fetch-harness-token.ts."""
2
+
3
+ import os
4
+ import sys
5
+
6
+ from agentcore.lib.schemas.io.config_io import ConfigIO
7
+ from agentcore.lib.utils.env import read_env_file
8
+ from agentcore.operations.fetch_access import oauth_token
9
+ from agentcore.operations.fetch_access.oauth_token import OAuthTokenResult
10
+ from agentcore.primitives.credential_utils import (
11
+ compute_default_credential_env_var_name,
12
+ compute_managed_oauth_credential_name,
13
+ )
14
+
15
+
16
+ def can_fetch_harness_token(harness_name: str, *, config_io: ConfigIO | None = None) -> bool:
17
+ """True when a CUSTOM_JWT harness has its managed OAuth credential and client secret available."""
18
+ try:
19
+ config_io = config_io or ConfigIO()
20
+ spec = config_io.read_harness_spec(harness_name)
21
+ if spec.authorizer_type != "CUSTOM_JWT":
22
+ return False
23
+ if not (spec.authorizer_configuration and spec.authorizer_configuration.custom_jwt_authorizer):
24
+ return False
25
+ project_spec = config_io.read_project_spec()
26
+ cred_name = compute_managed_oauth_credential_name(harness_name)
27
+ if not any(
28
+ c.authorizer_type == "OAuthCredentialProvider" and c.name == cred_name
29
+ for c in project_spec.credentials or []
30
+ ):
31
+ return False
32
+ prefix = compute_default_credential_env_var_name(cred_name)
33
+ return bool(read_env_file().get(f"{prefix}_CLIENT_SECRET"))
34
+ except Exception as exc: # noqa: BLE001 - "cannot fetch", as upstream
35
+ if os.environ.get("DEBUG"):
36
+ print("[canFetchHarnessToken]", exc, file=sys.stderr)
37
+ return False
38
+
39
+
40
+ def fetch_harness_token(
41
+ harness_name: str,
42
+ *,
43
+ config_io: ConfigIO | None = None,
44
+ deploy_target: str | None = None,
45
+ identity_name: str | None = None,
46
+ ) -> OAuthTokenResult:
47
+ config_io = config_io or ConfigIO()
48
+ deployed_state = config_io.read_deployed_state()
49
+ project_spec = config_io.read_project_spec()
50
+ spec = config_io.read_harness_spec(harness_name)
51
+
52
+ target_names = list(deployed_state.targets or {})
53
+ if not target_names:
54
+ raise RuntimeError("No deployed targets found. Run `agentcore deploy` first.")
55
+ target_name = deploy_target or target_names[0]
56
+
57
+ if spec.authorizer_type != "CUSTOM_JWT":
58
+ raise RuntimeError(f"Harness '{harness_name}' uses {spec.authorizer_type or 'AWS_IAM'} auth, not CUSTOM_JWT.")
59
+ config = spec.authorizer_configuration
60
+ jwt_config = config.custom_jwt_authorizer if config else None
61
+ if jwt_config is None:
62
+ raise RuntimeError(
63
+ f"Harness '{harness_name}' is configured as CUSTOM_JWT but has no customJwtAuthorizer configuration."
64
+ )
65
+ return oauth_token.fetch_oauth_token(
66
+ resource_name=harness_name,
67
+ jwt_config=jwt_config,
68
+ deployed_state=deployed_state,
69
+ target_name=target_name,
70
+ credentials=project_spec.credentials or [],
71
+ credential_name=identity_name,
72
+ )
@@ -0,0 +1,76 @@
1
+ """Port of src/cli/operations/fetch-access/fetch-runtime-token.ts."""
2
+
3
+ from agentcore.lib.schemas.io.config_io import ConfigIO
4
+ from agentcore.lib.utils.env import read_env_file
5
+ from agentcore.operations.fetch_access import oauth_token
6
+ from agentcore.operations.fetch_access.oauth_token import OAuthTokenResult
7
+ from agentcore.primitives.credential_utils import (
8
+ compute_default_credential_env_var_name,
9
+ compute_managed_oauth_credential_name,
10
+ )
11
+
12
+
13
+ def can_fetch_runtime_token(
14
+ agent_name: str, *, config_io: ConfigIO | None = None, identity_name: str | None = None
15
+ ) -> bool:
16
+ """True when a CUSTOM_JWT agent has its managed OAuth credential and client secret available."""
17
+ try:
18
+ config_io = config_io or ConfigIO()
19
+ project_spec = config_io.read_project_spec()
20
+ agent = next((a for a in project_spec.runtimes or [] if a.name == agent_name), None)
21
+ if agent is None or agent.authorizer_type != "CUSTOM_JWT":
22
+ return False
23
+ if not (agent.authorizer_configuration and agent.authorizer_configuration.custom_jwt_authorizer):
24
+ return False
25
+ cred_name = identity_name or compute_managed_oauth_credential_name(agent_name)
26
+ if not any(
27
+ c.authorizer_type == "OAuthCredentialProvider" and c.name == cred_name
28
+ for c in project_spec.credentials or []
29
+ ):
30
+ return False
31
+ prefix = compute_default_credential_env_var_name(cred_name)
32
+ return bool(read_env_file().get(f"{prefix}_CLIENT_SECRET"))
33
+ except Exception: # noqa: BLE001 - "cannot fetch", as upstream
34
+ return False
35
+
36
+
37
+ def fetch_runtime_token(
38
+ agent_name: str,
39
+ *,
40
+ config_io: ConfigIO | None = None,
41
+ deploy_target: str | None = None,
42
+ identity_name: str | None = None,
43
+ ) -> OAuthTokenResult:
44
+ config_io = config_io or ConfigIO()
45
+ deployed_state = config_io.read_deployed_state()
46
+ project_spec = config_io.read_project_spec()
47
+
48
+ target_names = list(deployed_state.targets or {})
49
+ if not target_names:
50
+ raise RuntimeError("No deployed targets found. Run `agentcore deploy` first.")
51
+ target_name = deploy_target or target_names[0]
52
+
53
+ runtimes = project_spec.runtimes or []
54
+ agent = next((a for a in runtimes if a.name == agent_name), None)
55
+ if agent is None:
56
+ available = ", ".join(a.name for a in runtimes) or "none"
57
+ raise RuntimeError(f"Agent '{agent_name}' not found in project. Available agents: {available}")
58
+ if agent.authorizer_type != "CUSTOM_JWT":
59
+ raise RuntimeError(
60
+ f"Agent '{agent_name}' uses {agent.authorizer_type or 'AWS_IAM'} auth, not CUSTOM_JWT. "
61
+ "Token fetch is only needed for CUSTOM_JWT agents."
62
+ )
63
+ config = agent.authorizer_configuration
64
+ jwt_config = config.custom_jwt_authorizer if config else None
65
+ if jwt_config is None:
66
+ raise RuntimeError(
67
+ f"Agent '{agent_name}' is configured as CUSTOM_JWT but has no customJwtAuthorizer configuration."
68
+ )
69
+ return oauth_token.fetch_oauth_token(
70
+ resource_name=agent_name,
71
+ jwt_config=jwt_config,
72
+ deployed_state=deployed_state,
73
+ target_name=target_name,
74
+ credentials=project_spec.credentials or [],
75
+ credential_name=identity_name,
76
+ )
@@ -0,0 +1,18 @@
1
+ """Port of src/cli/operations/fetch-access/list-agents.ts."""
2
+
3
+ from agentcore.lib.schemas.io.config_io import ConfigIO
4
+ from agentcore.operations.fetch_access._target import _target_resources
5
+ from agentcore.operations.fetch_access.types import AgentInfo
6
+
7
+
8
+ def list_agents(*, config_io: ConfigIO | None = None, deploy_target: str | None = None) -> list[AgentInfo]:
9
+ found = _target_resources(config_io or ConfigIO(), deploy_target)
10
+ if found is None:
11
+ return []
12
+ project_spec, resources = found
13
+ deployed = (resources.runtimes if resources else None) or {}
14
+ return [
15
+ {"name": a.name, "authType": a.authorizer_type or "AWS_IAM"}
16
+ for a in project_spec.runtimes or []
17
+ if deployed.get(a.name) and deployed[a.name].runtime_arn
18
+ ]
@@ -0,0 +1,26 @@
1
+ """Port of src/cli/operations/fetch-access/list-gateways.ts."""
2
+
3
+ from agentcore.lib.schemas.io.config_io import ConfigIO
4
+ from agentcore.operations.fetch_access._target import _target_resources
5
+ from agentcore.operations.fetch_access.types import GatewayInfo
6
+
7
+
8
+ def list_gateways(*, config_io: ConfigIO | None = None, deploy_target: str | None = None) -> list[GatewayInfo]:
9
+ found = _target_resources(config_io or ConfigIO(), deploy_target)
10
+ if found is None:
11
+ return []
12
+ project_spec, resources = found
13
+ gateways = project_spec.agent_core_gateways or []
14
+ mcp_deployed = (resources.mcp.gateways if resources and resources.mcp else None) or {}
15
+ result: list[GatewayInfo] = []
16
+ for gateway in gateways:
17
+ deployed = mcp_deployed.get(gateway.name)
18
+ if deployed and deployed.gateway_url:
19
+ result.append({"name": gateway.name, "authType": gateway.authorizer_type})
20
+ # HTTP gateways (deployed via CFN under resources.gateways)
21
+ http_deployed = (resources.gateways if resources else None) or {}
22
+ for gateway in (g for g in gateways if g.protocol_type == "None"):
23
+ deployed = http_deployed.get(gateway.name)
24
+ if deployed and deployed.gateway_arn:
25
+ result.append({"name": gateway.name, "authType": gateway.authorizer_type or "NONE"})
26
+ return result
@@ -0,0 +1,23 @@
1
+ """Port of src/cli/operations/fetch-access/list-harnesses.ts."""
2
+
3
+ from agentcore.lib.schemas.io.config_io import ConfigIO
4
+ from agentcore.operations.fetch_access._target import _target_resources
5
+ from agentcore.operations.fetch_access.types import HarnessInfo
6
+
7
+
8
+ def list_harnesses(*, config_io: ConfigIO | None = None, deploy_target: str | None = None) -> list[HarnessInfo]:
9
+ config_io = config_io or ConfigIO()
10
+ found = _target_resources(config_io, deploy_target)
11
+ if found is None:
12
+ return []
13
+ project_spec, resources = found
14
+ deployed = (resources.harnesses if resources else None) or {}
15
+ result: list[HarnessInfo] = []
16
+ for harness in project_spec.harnesses or []:
17
+ state = deployed.get(harness.name)
18
+ if not (state and state.harness_arn):
19
+ continue
20
+ # A read failure for a deployed harness is a real config problem: let it propagate.
21
+ spec = config_io.read_harness_spec(harness.name)
22
+ result.append({"name": harness.name, "authType": spec.authorizer_type or "AWS_IAM"})
23
+ return result
@@ -0,0 +1,162 @@
1
+ """Port of src/cli/operations/fetch-access/oauth-token.ts (OIDC discovery + client_credentials)."""
2
+
3
+ import json
4
+ import urllib.error
5
+ import urllib.request
6
+ from dataclasses import dataclass
7
+ from typing import Any
8
+ from urllib.parse import urlencode
9
+
10
+ from agentcore.lib.utils.env import read_env_file
11
+ from agentcore.primitives.credential_utils import (
12
+ compute_default_credential_env_var_name,
13
+ compute_managed_oauth_credential_name,
14
+ )
15
+
16
+
17
+ @dataclass
18
+ class OAuthTokenResult:
19
+ token: str
20
+ expires_in: int | None = None
21
+
22
+
23
+ @dataclass
24
+ class HttpResponse:
25
+ status: int
26
+ status_text: str
27
+ body: str
28
+
29
+ @property
30
+ def ok(self) -> bool:
31
+ return 200 <= self.status < 300
32
+
33
+ def json(self) -> Any:
34
+ return json.loads(self.body)
35
+
36
+
37
+ def http_fetch(url: str, *, method: str = "GET", headers: dict[str, str] | None = None, body: str | None = None):
38
+ """Minimal ``fetch()``: returns status/statusText/body without raising on HTTP errors."""
39
+ request = urllib.request.Request(
40
+ url, method=method, headers=headers or {}, data=body.encode() if body is not None else None
41
+ )
42
+ try:
43
+ with urllib.request.urlopen(request, timeout=30) as response:
44
+ return HttpResponse(response.status, response.reason or "", response.read().decode("utf-8", "replace"))
45
+ except urllib.error.HTTPError as exc:
46
+ return HttpResponse(exc.code, exc.reason or "", exc.read().decode("utf-8", "replace"))
47
+
48
+
49
+ def _field(obj: Any, name: str) -> Any:
50
+ return obj.get(name) if isinstance(obj, dict) else getattr(obj, name, None)
51
+
52
+
53
+ def _resolve_client_id(
54
+ deployed_state: Any,
55
+ target_name: str,
56
+ cred_name: str,
57
+ env_var_prefix: str,
58
+ env_vars: dict[str, str],
59
+ allowed_clients: list[str] | None,
60
+ ) -> str | None:
61
+ # Tier 1: deployed-state credentials
62
+ target = (deployed_state.targets or {}).get(target_name)
63
+ resources = target.resources if target else None
64
+ deployed_cred = ((resources.credentials if resources else None) or {}).get(cred_name)
65
+ if deployed_cred is not None:
66
+ client_id = getattr(deployed_cred, "client_id", None) or (deployed_cred.model_extra or {}).get("clientId")
67
+ if client_id:
68
+ return client_id
69
+ # Tier 2: env var <prefix>_CLIENT_ID
70
+ env_client_id = env_vars.get(f"{env_var_prefix}_CLIENT_ID")
71
+ if env_client_id:
72
+ return env_client_id
73
+ # Tier 3: allowedClients[0]
74
+ if allowed_clients:
75
+ return allowed_clients[0]
76
+ return None
77
+
78
+
79
+ def fetch_oauth_token(
80
+ *,
81
+ resource_name: str,
82
+ jwt_config: Any,
83
+ deployed_state: Any,
84
+ target_name: str,
85
+ credentials: list[Any],
86
+ credential_name: str | None = None,
87
+ ) -> OAuthTokenResult:
88
+ """``jwt_config`` is a CustomJwtAuthorizer model (discovery_url, allowed_clients, allowed_scopes)."""
89
+ cred_name = credential_name or compute_managed_oauth_credential_name(resource_name)
90
+ oauth_creds = [c for c in credentials if c.authorizer_type == "OAuthCredentialProvider"]
91
+ credential = next((c for c in oauth_creds if c.name == cred_name), None)
92
+ if credential is None:
93
+ available = [c.name for c in oauth_creds]
94
+ hint = (
95
+ f" Available OAuth credentials: {', '.join(available)}. Use --identity-name to specify one."
96
+ if available
97
+ else ""
98
+ )
99
+ raise RuntimeError(
100
+ f"No managed OAuth credential found for '{resource_name}'. Expected credential '{cred_name}'.{hint}"
101
+ + (" Re-create the resource with --client-id and --client-secret." if not available else "")
102
+ )
103
+
104
+ env_var_prefix = compute_default_credential_env_var_name(cred_name)
105
+ secret_env_var = f"{env_var_prefix}_CLIENT_SECRET"
106
+ env_vars = read_env_file()
107
+ client_secret = env_vars.get(secret_env_var)
108
+ if not client_secret:
109
+ raise RuntimeError(
110
+ f"Client secret not found in environment variable {secret_env_var}. "
111
+ "Ensure .env.local file contains this value."
112
+ )
113
+
114
+ client_id = _resolve_client_id(
115
+ deployed_state, target_name, cred_name, env_var_prefix, env_vars, _field(jwt_config, "allowed_clients")
116
+ )
117
+ if not client_id:
118
+ raise RuntimeError(
119
+ f"Could not determine OAuth client ID for '{resource_name}'. Ensure the resource was created with --client-id."
120
+ )
121
+
122
+ discovery_url = _field(jwt_config, "discovery_url")
123
+ discovery = http_fetch(discovery_url)
124
+ if not discovery.ok:
125
+ raise RuntimeError(f"OIDC discovery failed: {discovery.status} {discovery.status_text} ({discovery_url})")
126
+ discovery_doc = discovery.json()
127
+ token_endpoint = discovery_doc.get("token_endpoint")
128
+ if not token_endpoint:
129
+ raise RuntimeError(f"OIDC discovery response missing 'token_endpoint' field ({discovery_url})")
130
+
131
+ supported = discovery_doc.get("grant_types_supported")
132
+ if supported and "client_credentials" not in supported:
133
+ raise RuntimeError(
134
+ "This OAuth provider does not support the client_credentials grant type. "
135
+ f"Supported grants: {', '.join(supported)}. "
136
+ "Authorization code flows (3-legged OAuth) requiring browser login are not yet supported."
137
+ )
138
+
139
+ params = {"grant_type": "client_credentials", "client_id": client_id, "client_secret": client_secret}
140
+ scopes = _field(jwt_config, "allowed_scopes")
141
+ if scopes:
142
+ params["scope"] = " ".join(scopes)
143
+
144
+ token_response = http_fetch(
145
+ token_endpoint,
146
+ method="POST",
147
+ headers={"Content-Type": "application/x-www-form-urlencoded"},
148
+ body=urlencode(params),
149
+ )
150
+ if not token_response.ok:
151
+ error_body = token_response.body
152
+ if "unsupported_grant_type" in error_body:
153
+ raise RuntimeError(
154
+ "Token request failed: the OAuth provider rejected the client_credentials grant type. "
155
+ "This resource may require an authorization code flow (3-legged OAuth) which is not yet supported."
156
+ )
157
+ raise RuntimeError(f"Token request failed: {token_response.status} {token_response.status_text}. {error_body}")
158
+
159
+ token_data = token_response.json()
160
+ if not token_data.get("access_token"):
161
+ raise RuntimeError("Token response missing access_token field.")
162
+ return OAuthTokenResult(token=token_data["access_token"], expires_in=token_data.get("expires_in"))