graph-agents-cli 0.3.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 (291) hide show
  1. graph_agents_cli/__init__.py +26 -0
  2. graph_agents_cli/_api_policy.py +2145 -0
  3. graph_agents_cli/_approvals.py +400 -0
  4. graph_agents_cli/_build.py +186 -0
  5. graph_agents_cli/_build_info.json +7 -0
  6. graph_agents_cli/_chat_client.py +462 -0
  7. graph_agents_cli/_click.py +157 -0
  8. graph_agents_cli/_defaults.py +139 -0
  9. graph_agents_cli/_experiments.py +64 -0
  10. graph_agents_cli/_http.py +192 -0
  11. graph_agents_cli/_output.py +83 -0
  12. graph_agents_cli/_project.py +462 -0
  13. graph_agents_cli/_remote.py +220 -0
  14. graph_agents_cli/_response_schema.py +264 -0
  15. graph_agents_cli/_runner.py +319 -0
  16. graph_agents_cli/_skills_check.py +274 -0
  17. graph_agents_cli/_tools.py +189 -0
  18. graph_agents_cli/_trust.py +66 -0
  19. graph_agents_cli/api/__init__.py +15 -0
  20. graph_agents_cli/api/_changes.py +506 -0
  21. graph_agents_cli/api/_files.py +658 -0
  22. graph_agents_cli/api/cmd_api.py +2480 -0
  23. graph_agents_cli/deploy/__init__.py +15 -0
  24. graph_agents_cli/deploy/_config.py +171 -0
  25. graph_agents_cli/deploy/_image.py +128 -0
  26. graph_agents_cli/deploy/_kube.py +286 -0
  27. graph_agents_cli/deploy/_modes.py +234 -0
  28. graph_agents_cli/deploy/_preflight.py +370 -0
  29. graph_agents_cli/deploy/_values.py +168 -0
  30. graph_agents_cli/deploy/cmd_deploy.py +1866 -0
  31. graph_agents_cli/deploy/gitops.py +562 -0
  32. graph_agents_cli/deploy/local_load.py +273 -0
  33. graph_agents_cli/dev/__init__.py +13 -0
  34. graph_agents_cli/dev/cmd_build.py +131 -0
  35. graph_agents_cli/dev/cmd_install.py +78 -0
  36. graph_agents_cli/dev/cmd_lint.py +119 -0
  37. graph_agents_cli/dev/cmd_playground.py +297 -0
  38. graph_agents_cli/dev/policy_check.py +1287 -0
  39. graph_agents_cli/eval/__init__.py +22 -0
  40. graph_agents_cli/eval/_client.py +670 -0
  41. graph_agents_cli/eval/_common.py +177 -0
  42. graph_agents_cli/eval/_judge.py +168 -0
  43. graph_agents_cli/eval/_judge_runner.py +238 -0
  44. graph_agents_cli/eval/_paths.py +212 -0
  45. graph_agents_cli/eval/checks.py +581 -0
  46. graph_agents_cli/eval/cmd_analyze.py +278 -0
  47. graph_agents_cli/eval/cmd_compare.py +284 -0
  48. graph_agents_cli/eval/cmd_eval_group.py +80 -0
  49. graph_agents_cli/eval/cmd_generate.py +558 -0
  50. graph_agents_cli/eval/cmd_grade.py +466 -0
  51. graph_agents_cli/eval/cmd_metric.py +156 -0
  52. graph_agents_cli/eval/cmd_run.py +370 -0
  53. graph_agents_cli/eval/cmd_submit.py +400 -0
  54. graph_agents_cli/eval/config.py +435 -0
  55. graph_agents_cli/eval/dataset.py +350 -0
  56. graph_agents_cli/eval/gate.py +420 -0
  57. graph_agents_cli/eval/transcript.py +192 -0
  58. graph_agents_cli/extension/__init__.py +13 -0
  59. graph_agents_cli/extension/_compat.py +86 -0
  60. graph_agents_cli/extension/_loader.py +293 -0
  61. graph_agents_cli/extension/_manifest.py +135 -0
  62. graph_agents_cli/extension/_overrides.py +195 -0
  63. graph_agents_cli/extension/_paths.py +91 -0
  64. graph_agents_cli/extension/_refs.py +193 -0
  65. graph_agents_cli/extension/_resolver.py +453 -0
  66. graph_agents_cli/extension/_schema.py +106 -0
  67. graph_agents_cli/extension/_spec.py +253 -0
  68. graph_agents_cli/extension/_sync.py +102 -0
  69. graph_agents_cli/extension/_trust.py +58 -0
  70. graph_agents_cli/extension/cmd_extension_add.py +259 -0
  71. graph_agents_cli/extension/cmd_extension_group.py +57 -0
  72. graph_agents_cli/extension/cmd_extension_list.py +56 -0
  73. graph_agents_cli/extension/cmd_extension_remove.py +61 -0
  74. graph_agents_cli/extension/cmd_extension_update.py +195 -0
  75. graph_agents_cli/info/__init__.py +13 -0
  76. graph_agents_cli/info/cmd_info.py +222 -0
  77. graph_agents_cli/infra/__init__.py +15 -0
  78. graph_agents_cli/infra/checks.py +1169 -0
  79. graph_agents_cli/infra/cmd_infra.py +103 -0
  80. graph_agents_cli/main.py +591 -0
  81. graph_agents_cli/peer/__init__.py +15 -0
  82. graph_agents_cli/peer/_generate.py +254 -0
  83. graph_agents_cli/peer/cmd_peer.py +1151 -0
  84. graph_agents_cli/run/__init__.py +13 -0
  85. graph_agents_cli/run/_local_server.py +1157 -0
  86. graph_agents_cli/run/_signals.py +141 -0
  87. graph_agents_cli/run/cmd_approvals.py +530 -0
  88. graph_agents_cli/run/cmd_run.py +1421 -0
  89. graph_agents_cli/scaffold/__init__.py +19 -0
  90. graph_agents_cli/scaffold/agents/README.md +24 -0
  91. graph_agents_cli/scaffold/agents/empty_py/.template/templateconfig.yaml +22 -0
  92. graph_agents_cli/scaffold/agents/langgraph/.env.example +292 -0
  93. graph_agents_cli/scaffold/agents/langgraph/.template/templateconfig.yaml +28 -0
  94. graph_agents_cli/scaffold/agents/langgraph/Dockerfile +59 -0
  95. graph_agents_cli/scaffold/agents/langgraph/Dockerfile.langgraph-server +59 -0
  96. graph_agents_cli/scaffold/agents/langgraph/README.md +571 -0
  97. graph_agents_cli/scaffold/agents/langgraph/api-policy.yaml +60 -0
  98. graph_agents_cli/scaffold/agents/langgraph/app/__init__.py +20 -0
  99. graph_agents_cli/scaffold/agents/langgraph/app/agent.py +174 -0
  100. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/__init__.py +15 -0
  101. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a.py +2162 -0
  102. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a_client.py +1167 -0
  103. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/api_client.py +4220 -0
  104. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/approvals.py +1349 -0
  105. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/auth.py +1986 -0
  106. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/chat.py +2962 -0
  107. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/checkpointer.py +432 -0
  108. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/content.py +569 -0
  109. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/db.py +580 -0
  110. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/limits.py +203 -0
  111. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/metrics.py +231 -0
  112. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/middleware.py +361 -0
  113. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/model.py +611 -0
  114. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/playground.py +230 -0
  115. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/run_locks.py +459 -0
  116. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/structured.py +755 -0
  117. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/telemetry.py +681 -0
  118. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/threads.py +493 -0
  119. graph_agents_cli/scaffold/agents/langgraph/app/app_utils/token_exchange.py +959 -0
  120. graph_agents_cli/scaffold/agents/langgraph/app/fast_api_app.py +770 -0
  121. graph_agents_cli/scaffold/agents/langgraph/app/policies/__init__.py +55 -0
  122. graph_agents_cli/scaffold/agents/langgraph/app/policies/custom.py +97 -0
  123. graph_agents_cli/scaffold/agents/langgraph/app/tools/__init__.py +46 -0
  124. graph_agents_cli/scaffold/agents/langgraph/app/tools/example_api.py +92 -0
  125. graph_agents_cli/scaffold/agents/langgraph/app/tools/weather.py +33 -0
  126. graph_agents_cli/scaffold/agents/langgraph/langgraph.json +14 -0
  127. graph_agents_cli/scaffold/agents/langgraph/pyproject.toml +78 -0
  128. graph_agents_cli/scaffold/agents/langgraph/tests/conftest.py +376 -0
  129. graph_agents_cli/scaffold/agents/langgraph/tests/eval/datasets/basic-dataset.json +53 -0
  130. graph_agents_cli/scaffold/agents/langgraph/tests/eval/eval_config.yaml +32 -0
  131. graph_agents_cli/scaffold/agents/langgraph/tests/integration/approval_graph.py +137 -0
  132. graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_issuer.py +216 -0
  133. graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_openai.py +357 -0
  134. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_outcomes.py +569 -0
  135. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_relay.py +479 -0
  136. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_api_surface.py +812 -0
  137. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals.py +1367 -0
  138. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals_server.py +794 -0
  139. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor.py +497 -0
  140. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor_server.py +247 -0
  141. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_history_repair.py +278 -0
  142. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_model_apis.py +242 -0
  143. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_postgres.py +637 -0
  144. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_resilience_postgres.py +770 -0
  145. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_runtime_guardrails.py +854 -0
  146. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_e2e.py +340 -0
  147. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_runtime.py +989 -0
  148. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_answers.py +584 -0
  149. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_server.py +222 -0
  150. graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_token_exchange_issuer.py +650 -0
  151. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/.results/.placeholder +0 -0
  152. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/README.md +22 -0
  153. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/conftest.py +21 -0
  154. graph_agents_cli/scaffold/agents/langgraph/tests/load_test/load_test.py +81 -0
  155. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_client.py +824 -0
  156. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_scoping.py +724 -0
  157. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client.py +1214 -0
  158. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client_hardening.py +716 -0
  159. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_policy_rpc.py +767 -0
  160. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_approval_ledger.py +1536 -0
  161. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_fake_model.py +115 -0
  162. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_jwt_policy.py +991 -0
  163. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_limits.py +310 -0
  164. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging.py +148 -0
  165. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging_hardening.py +271 -0
  166. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_policy.py +378 -0
  167. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_resilience.py +610 -0
  168. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_server_auth.py +702 -0
  169. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_structured.py +673 -0
  170. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_telemetry.py +404 -0
  171. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_thread_listing.py +255 -0
  172. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_threads.py +268 -0
  173. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_token_exchange.py +1320 -0
  174. graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_untrusted_content.py +393 -0
  175. graph_agents_cli/scaffold/agents/langgraph/uv-fastapi.lock +2084 -0
  176. graph_agents_cli/scaffold/agents/langgraph/uv-langgraph-server.lock +2106 -0
  177. graph_agents_cli/scaffold/agents/langgraph/{{cookiecutter.agent_guidance_filename}} +129 -0
  178. graph_agents_cli/scaffold/base_templates/_shared/graph-agents-cli-manifest.yaml +36 -0
  179. graph_agents_cli/scaffold/base_templates/python/.dockerignore +32 -0
  180. graph_agents_cli/scaffold/base_templates/python/.github/CODEOWNERS +30 -0
  181. graph_agents_cli/scaffold/base_templates/python/.github/agent.env +7 -0
  182. graph_agents_cli/scaffold/base_templates/python/.github/workflows/pr_checks.yaml +214 -0
  183. graph_agents_cli/scaffold/base_templates/python/.gitignore +209 -0
  184. graph_agents_cli/scaffold/base_templates/python/tests/unit/test_dummy.py +23 -0
  185. graph_agents_cli/scaffold/base_templates/python/{{cookiecutter.agent_guidance_filename}} +35 -0
  186. graph_agents_cli/scaffold/cmd_scaffold_group.py +49 -0
  187. graph_agents_cli/scaffold/commands/__init__.py +13 -0
  188. graph_agents_cli/scaffold/commands/create.py +1424 -0
  189. graph_agents_cli/scaffold/commands/enhance.py +1652 -0
  190. graph_agents_cli/scaffold/commands/upgrade.py +570 -0
  191. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/agent.env +12 -0
  192. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/promote-to-prod.yaml +371 -0
  193. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/staging.yaml +450 -0
  194. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-dev.yaml +43 -0
  195. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-prod.yaml +41 -0
  196. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-staging.yaml +43 -0
  197. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/.helmignore +14 -0
  198. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/Chart.yaml +21 -0
  199. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/examples/networkpolicy.yaml +103 -0
  200. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/NOTES.txt +48 -0
  201. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/_helpers.tpl +189 -0
  202. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/certificate.yaml +15 -0
  203. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/configmap.yaml +10 -0
  204. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/deployment.yaml +199 -0
  205. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/hpa.yaml +22 -0
  206. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/httproute.yaml +30 -0
  207. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/ingress.yaml +39 -0
  208. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/networkpolicy.yaml +48 -0
  209. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/pdb.yaml +13 -0
  210. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/postgresql-secret.yaml +37 -0
  211. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/service.yaml +15 -0
  212. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/serviceaccount.yaml +13 -0
  213. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/servicemonitor.yaml +42 -0
  214. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-dev.yaml +22 -0
  215. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-prod.yaml +45 -0
  216. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-staging.yaml +29 -0
  217. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values.yaml +396 -0
  218. graph_agents_cli/scaffold/deployment_targets/kubernetes/python/tests/integration/test_chart.py +269 -0
  219. graph_agents_cli/scaffold/deployment_targets/none/README.md +5 -0
  220. graph_agents_cli/scaffold/deployment_targets/none/python/README.md +6 -0
  221. graph_agents_cli/scaffold/utils/__init__.py +13 -0
  222. graph_agents_cli/scaffold/utils/backup.py +212 -0
  223. graph_agents_cli/scaffold/utils/build_record.py +257 -0
  224. graph_agents_cli/scaffold/utils/cli_options.py +184 -0
  225. graph_agents_cli/scaffold/utils/fs.py +83 -0
  226. graph_agents_cli/scaffold/utils/generate_locks.py +214 -0
  227. graph_agents_cli/scaffold/utils/generation_metadata.py +88 -0
  228. graph_agents_cli/scaffold/utils/keyedit.py +768 -0
  229. graph_agents_cli/scaffold/utils/keymerge.py +537 -0
  230. graph_agents_cli/scaffold/utils/language.py +138 -0
  231. graph_agents_cli/scaffold/utils/lock_utils.py +94 -0
  232. graph_agents_cli/scaffold/utils/logging.py +77 -0
  233. graph_agents_cli/scaffold/utils/manifest.py +292 -0
  234. graph_agents_cli/scaffold/utils/merge.py +970 -0
  235. graph_agents_cli/scaffold/utils/merge3.py +216 -0
  236. graph_agents_cli/scaffold/utils/openapi_seed.py +199 -0
  237. graph_agents_cli/scaffold/utils/remote_template.py +376 -0
  238. graph_agents_cli/scaffold/utils/template.py +1352 -0
  239. graph_agents_cli/scaffold/utils/upgrade.py +894 -0
  240. graph_agents_cli/scaffold/utils/version.py +438 -0
  241. graph_agents_cli/secrets/__init__.py +15 -0
  242. graph_agents_cli/secrets/_apply.py +954 -0
  243. graph_agents_cli/secrets/_required.py +188 -0
  244. graph_agents_cli/secrets/cmd_secrets.py +211 -0
  245. graph_agents_cli/setup/__init__.py +13 -0
  246. graph_agents_cli/setup/_antigravity.py +221 -0
  247. graph_agents_cli/setup/cmd_auth.py +1030 -0
  248. graph_agents_cli/setup/cmd_dev_token.py +513 -0
  249. graph_agents_cli/setup/cmd_setup.py +428 -0
  250. graph_agents_cli/setup/cmd_update.py +140 -0
  251. graph_agents_cli/skills/__init__.py +13 -0
  252. graph_agents_cli/skills/_bundle.py +65 -0
  253. graph_agents_cli/skills/data/README.md +19 -0
  254. graph_agents_cli/skills/data/graph-agents-cli-deploy/SKILL.md +357 -0
  255. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/github-settings.md +113 -0
  256. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/gitops.md +137 -0
  257. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/kubernetes.md +315 -0
  258. graph_agents_cli/skills/data/graph-agents-cli-deploy/references/secrets.md +160 -0
  259. graph_agents_cli/skills/data/graph-agents-cli-eval/SKILL.md +303 -0
  260. graph_agents_cli/skills/data/graph-agents-cli-eval/references/dataset_schema.md +282 -0
  261. graph_agents_cli/skills/data/graph-agents-cli-eval/references/metrics-guide.md +143 -0
  262. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/SKILL.md +659 -0
  263. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langchain-models.md +124 -0
  264. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langgraph.md +235 -0
  265. graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/template-contract.md +477 -0
  266. graph_agents_cli/skills/data/graph-agents-cli-observability/SKILL.md +231 -0
  267. graph_agents_cli/skills/data/graph-agents-cli-observability/references/langsmith.md +46 -0
  268. graph_agents_cli/skills/data/graph-agents-cli-observability/references/otel.md +59 -0
  269. graph_agents_cli/skills/data/graph-agents-cli-scaffold/SKILL.md +414 -0
  270. graph_agents_cli/skills/data/graph-agents-cli-scaffold/references/flags.md +134 -0
  271. graph_agents_cli/skills/data/graph-agents-cli-workflow/SKILL.md +478 -0
  272. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/brainstorming.md +118 -0
  273. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/commands.md +419 -0
  274. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/extension.md +156 -0
  275. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/internals.md +67 -0
  276. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/spec-template.md +56 -0
  277. graph_agents_cli/skills/data/graph-agents-cli-workflow/references/terminology.md +119 -0
  278. graph_agents_cli/system/__init__.py +15 -0
  279. graph_agents_cli/system/_apply.py +519 -0
  280. graph_agents_cli/system/_checks.py +1023 -0
  281. graph_agents_cli/system/_deploy.py +215 -0
  282. graph_agents_cli/system/_model.py +363 -0
  283. graph_agents_cli/system/_system.py +664 -0
  284. graph_agents_cli/system/_views.py +208 -0
  285. graph_agents_cli/system/cmd_system.py +423 -0
  286. graph_agents_cli-0.3.1.dist-info/METADATA +162 -0
  287. graph_agents_cli-0.3.1.dist-info/RECORD +291 -0
  288. graph_agents_cli-0.3.1.dist-info/WHEEL +4 -0
  289. graph_agents_cli-0.3.1.dist-info/entry_points.txt +2 -0
  290. graph_agents_cli-0.3.1.dist-info/licenses/LICENSE +201 -0
  291. graph_agents_cli-0.3.1.dist-info/licenses/NOTICE +19 -0
@@ -0,0 +1,310 @@
1
+ # Copyright 2026 graph-agents-cli contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Limits and settings: defaults in code, bad values refused, metadata caps, model limits."""
16
+
17
+ from __future__ import annotations
18
+
19
+ import pytest
20
+
21
+ from {{cookiecutter.agent_directory}}.app_utils import limits
22
+ from {{cookiecutter.agent_directory}}.app_utils.chat import forward_header_names, select_forward_headers
23
+ from {{cookiecutter.agent_directory}}.app_utils.checkpointer import pool_sizes
24
+ from {{cookiecutter.agent_directory}}.app_utils.limits import SettingsError, check_metadata
25
+ from {{cookiecutter.agent_directory}}.app_utils.model import (
26
+ build_model,
27
+ get_judge_model,
28
+ get_model,
29
+ model_api_options,
30
+ model_limits,
31
+ model_options,
32
+ )
33
+
34
+ ENV = (
35
+ "RUN_TIMEOUT_S",
36
+ "RECURSION_LIMIT",
37
+ "MAX_REQUEST_BYTES",
38
+ "MAX_METADATA_KEYS",
39
+ "MAX_METADATA_VALUE_CHARS",
40
+ "SSE_HEARTBEAT_S",
41
+ "RETENTION_DAYS",
42
+ "MODEL_TIMEOUT_S",
43
+ "MODEL_MAX_RETRIES",
44
+ "MODEL_REASONING_EFFORT",
45
+ "MODEL_USE_RESPONSES_API",
46
+ "JUDGE_MODEL_PROVIDER",
47
+ "JUDGE_REASONING_EFFORT",
48
+ "JUDGE_USE_RESPONSES_API",
49
+ "DB_POOL_MIN_SIZE",
50
+ "DB_POOL_MAX_SIZE",
51
+ "AUTH_FORWARD_HEADERS",
52
+ )
53
+
54
+
55
+ @pytest.fixture(autouse=True)
56
+ def clean_env(monkeypatch: pytest.MonkeyPatch) -> None:
57
+ for name in ENV:
58
+ monkeypatch.delenv(name, raising=False)
59
+
60
+
61
+ def test_defaults_are_finite() -> None:
62
+ assert limits.run_timeout_s() == 300
63
+ assert limits.recursion_limit() == 50
64
+ # Room for 24 tool calls one after another (two steps each) plus the answer.
65
+ assert limits.sequential_tool_calls(limits.recursion_limit()) == 24
66
+ assert limits.max_request_bytes() == 1_048_576
67
+ assert limits.max_metadata_keys() == 16
68
+ assert limits.max_metadata_value_chars() == 256
69
+ assert limits.sse_heartbeat_s() == 15
70
+ assert limits.retention_days() == 0
71
+ assert model_limits() == (60.0, 2)
72
+ assert pool_sizes() == (1, 10)
73
+ limits.check_settings()
74
+
75
+
76
+ @pytest.mark.parametrize(
77
+ ("name", "value"),
78
+ [
79
+ ("RUN_TIMEOUT_S", "abc"),
80
+ ("RUN_TIMEOUT_S", "0"),
81
+ ("RUN_TIMEOUT_S", "inf"),
82
+ ("RUN_TIMEOUT_S", "nan"),
83
+ ("RECURSION_LIMIT", "0"),
84
+ ("RECURSION_LIMIT", "2.5"),
85
+ ("MAX_REQUEST_BYTES", "1MB"),
86
+ ("MAX_METADATA_KEYS", "-1"),
87
+ ("SSE_HEARTBEAT_S", "-5"),
88
+ ("RETENTION_DAYS", "seven"),
89
+ ],
90
+ )
91
+ def test_a_bad_value_is_a_startup_error_not_a_silent_default(
92
+ monkeypatch: pytest.MonkeyPatch, name: str, value: str
93
+ ) -> None:
94
+ monkeypatch.setenv(name, value)
95
+ with pytest.raises(SettingsError) as exc:
96
+ limits.check_settings()
97
+ assert name in str(exc.value)
98
+
99
+
100
+ @pytest.mark.parametrize(
101
+ ("name", "value"),
102
+ [
103
+ ("MODEL_TIMEOUT_S", "fast"),
104
+ ("MODEL_TIMEOUT_S", "-1"),
105
+ ("MODEL_MAX_RETRIES", "-1"),
106
+ ("MODEL_MAX_RETRIES", "two"),
107
+ ],
108
+ )
109
+ def test_bad_model_limits_are_refused(
110
+ monkeypatch: pytest.MonkeyPatch, name: str, value: str
111
+ ) -> None:
112
+ monkeypatch.setenv(name, value)
113
+ with pytest.raises(SettingsError):
114
+ model_limits()
115
+
116
+
117
+ @pytest.mark.parametrize(("low", "high"), [("5", "2"), ("0", "0"), ("x", "3"), ("-1", "3")])
118
+ def test_bad_pool_sizes_are_refused(monkeypatch: pytest.MonkeyPatch, low: str, high: str) -> None:
119
+ monkeypatch.setenv("DB_POOL_MIN_SIZE", low)
120
+ monkeypatch.setenv("DB_POOL_MAX_SIZE", high)
121
+ with pytest.raises(SettingsError):
122
+ pool_sizes()
123
+
124
+
125
+ def test_provider_models_get_a_timeout_and_retries(monkeypatch: pytest.MonkeyPatch) -> None:
126
+ model = build_model("openai", "gpt-test", api_key="sk-test")
127
+ assert model.request_timeout == 60.0 and model.max_retries == 2
128
+ monkeypatch.setenv("MODEL_TIMEOUT_S", "12.5")
129
+ monkeypatch.setenv("MODEL_MAX_RETRIES", "0")
130
+ model = build_model("anthropic", "claude-test", api_key="k")
131
+ assert model.default_request_timeout == 12.5 and model.max_retries == 0
132
+ monkeypatch.setenv("MODEL_TIMEOUT_S", "0") # the provider SDK's own default
133
+ model = build_model("openai", "gpt-test", api_key="sk-test")
134
+ assert model.request_timeout is None
135
+ # An explicit argument wins over the environment.
136
+ model = build_model("openai", "gpt-test", api_key="sk-test", timeout=3, max_retries=5)
137
+ assert model.request_timeout == 3 and model.max_retries == 5
138
+
139
+
140
+ def test_openai_models_report_streamed_usage() -> None:
141
+ # langchain-openai asks for streamed usage only for api.openai.com by itself: an
142
+ # OpenAI-compatible endpoint recorded zero tokens (Track C finding F1).
143
+ model = build_model(
144
+ "openai-compatible", "gpt-test", base_url="http://gateway:8080/v1", api_key="k"
145
+ )
146
+ assert model.stream_usage is True
147
+ assert build_model("openai", "gpt-test", api_key="sk-test").stream_usage is True
148
+ # An explicit argument wins.
149
+ model = build_model(
150
+ "openai-compatible", "gpt-test", base_url="http://gw/v1", api_key="k", stream_usage=False
151
+ )
152
+ assert model.stream_usage is False
153
+
154
+
155
+ # --- reasoning effort and the Responses API (OpenAI-API models) ---------------------------
156
+
157
+
158
+ @pytest.fixture
159
+ def openai_model(monkeypatch: pytest.MonkeyPatch) -> None:
160
+ monkeypatch.setenv("MODEL_PROVIDER", "openai")
161
+ monkeypatch.setenv("MODEL_NAME", "gpt-test")
162
+ monkeypatch.setenv("OPENAI_API_KEY", "sk-test")
163
+
164
+
165
+ def test_the_model_api_settings_are_unset_by_default(openai_model: None) -> None:
166
+ assert model_options() == ({}, {})
167
+ model = get_model()
168
+ assert model.reasoning_effort is None and model.use_responses_api is None
169
+
170
+
171
+ @pytest.mark.parametrize(
172
+ ("effort", "switch", "expected"),
173
+ [
174
+ ("high", "true", {"reasoning_effort": "high", "use_responses_api": True}),
175
+ (" NONE ", "False", {"reasoning_effort": "none", "use_responses_api": False}),
176
+ ("xhigh", "", {"reasoning_effort": "xhigh"}),
177
+ ("", "1", {"use_responses_api": True}),
178
+ ("minimal", "off", {"reasoning_effort": "minimal", "use_responses_api": False}),
179
+ ],
180
+ )
181
+ def test_the_model_api_settings_reach_the_model(
182
+ openai_model: None,
183
+ monkeypatch: pytest.MonkeyPatch,
184
+ effort: str,
185
+ switch: str,
186
+ expected: dict[str, object],
187
+ ) -> None:
188
+ monkeypatch.setenv("MODEL_REASONING_EFFORT", effort)
189
+ monkeypatch.setenv("MODEL_USE_RESPONSES_API", switch)
190
+ assert model_api_options() == expected
191
+ model = get_model()
192
+ assert model.reasoning_effort == expected.get("reasoning_effort")
193
+ assert model.use_responses_api == expected.get("use_responses_api")
194
+ # An explicit argument wins over the environment.
195
+ assert get_model(reasoning_effort="low").reasoning_effort == "low"
196
+
197
+
198
+ @pytest.mark.parametrize(
199
+ ("name", "value", "fragment"),
200
+ [
201
+ (
202
+ "MODEL_REASONING_EFFORT",
203
+ "hihg",
204
+ "must be one of none, minimal, low, medium, high, xhigh",
205
+ ),
206
+ ("MODEL_USE_RESPONSES_API", "maybe", "must be true or false"),
207
+ ("JUDGE_REASONING_EFFORT", "max", "must be one of"),
208
+ ("JUDGE_USE_RESPONSES_API", "2", "must be true or false"),
209
+ ],
210
+ )
211
+ def test_a_bad_model_api_setting_stops_startup(
212
+ openai_model: None, monkeypatch: pytest.MonkeyPatch, name: str, value: str, fragment: str
213
+ ) -> None:
214
+ monkeypatch.setenv(name, value)
215
+ with pytest.raises(SettingsError) as exc:
216
+ limits.check_settings(extra=(model_options,))
217
+ assert name in str(exc.value) and fragment in str(exc.value)
218
+
219
+
220
+ @pytest.mark.parametrize("provider", ["anthropic", "gemini"])
221
+ def test_the_model_api_settings_are_refused_for_another_provider(
222
+ monkeypatch: pytest.MonkeyPatch, provider: str
223
+ ) -> None:
224
+ """They would be ignored (they are OpenAI API parameters): startup says so."""
225
+ monkeypatch.setenv("MODEL_PROVIDER", provider)
226
+ monkeypatch.setenv("MODEL_REASONING_EFFORT", "high")
227
+ with pytest.raises(SettingsError) as exc:
228
+ model_options()
229
+ assert "MODEL_REASONING_EFFORT applies to an OpenAI-API model" in str(exc.value)
230
+ assert repr(provider) in str(exc.value)
231
+ monkeypatch.setenv("MODEL_PROVIDER", "fake") # the test model takes and ignores them
232
+ assert model_options() == ({}, {})
233
+
234
+
235
+ def test_the_judge_keeps_the_agents_settings_or_takes_its_own(
236
+ openai_model: None, monkeypatch: pytest.MonkeyPatch
237
+ ) -> None:
238
+ monkeypatch.setenv("MODEL_REASONING_EFFORT", "high")
239
+ monkeypatch.setenv("MODEL_USE_RESPONSES_API", "true")
240
+ agent = {"reasoning_effort": "high", "use_responses_api": True}
241
+ assert model_options() == (agent, agent)
242
+ judge = get_judge_model()
243
+ assert (judge.reasoning_effort, judge.use_responses_api) == ("high", True)
244
+ monkeypatch.setenv("JUDGE_REASONING_EFFORT", "low")
245
+ monkeypatch.setenv("JUDGE_USE_RESPONSES_API", "false")
246
+ assert model_api_options(judge=True) == {"reasoning_effort": "low", "use_responses_api": False}
247
+ assert model_api_options() == agent
248
+ # A judge that is not an OpenAI-API model drops the agent's settings ...
249
+ monkeypatch.delenv("JUDGE_REASONING_EFFORT")
250
+ monkeypatch.delenv("JUDGE_USE_RESPONSES_API")
251
+ monkeypatch.setenv("JUDGE_MODEL_PROVIDER", "anthropic")
252
+ assert model_options() == (agent, {})
253
+ # ... and refuses its own.
254
+ monkeypatch.setenv("JUDGE_USE_RESPONSES_API", "true")
255
+ with pytest.raises(SettingsError) as exc:
256
+ model_options()
257
+ assert "JUDGE_USE_RESPONSES_API applies to an OpenAI-API model" in str(exc.value)
258
+
259
+
260
+ def test_metadata_caps(monkeypatch: pytest.MonkeyPatch) -> None:
261
+ ok = {"a": "x" * 256, "b": 1, "c": 2.5, "d": True, "e": None}
262
+ assert check_metadata(ok) == ok
263
+ for bad in (
264
+ {f"k{i}": 1 for i in range(17)},
265
+ {"a": "x" * 257},
266
+ {"x" * 257: 1},
267
+ {"a": {"nested": 1}},
268
+ {"a": [1]},
269
+ {"": 1},
270
+ {"a": float("nan")},
271
+ ):
272
+ with pytest.raises(ValueError):
273
+ check_metadata(bad)
274
+ monkeypatch.setenv("MAX_METADATA_KEYS", "0")
275
+ assert check_metadata({}) == {}
276
+ with pytest.raises(ValueError):
277
+ check_metadata({"a": 1})
278
+
279
+
280
+ @pytest.mark.parametrize(
281
+ ("thread_id", "valid"),
282
+ [
283
+ ("11111111-1111-1111-1111-111111111111", True),
284
+ ("t-demo_1.a:b", True),
285
+ ("x" * 128, True),
286
+ ("x" * 129, False),
287
+ ("", False),
288
+ ("a b", False),
289
+ ("a/b", False),
290
+ ("a\nb", False),
291
+ ("ümlaut", False),
292
+ ],
293
+ )
294
+ def test_thread_id_form(thread_id: str, valid: bool) -> None:
295
+ assert limits.valid_thread_id(thread_id) is valid
296
+
297
+
298
+ def test_forwarded_headers_are_generic_and_configurable(monkeypatch: pytest.MonkeyPatch) -> None:
299
+ headers = {
300
+ "Authorization": "Bearer k",
301
+ "cookie": "sid=1",
302
+ "x-session-token": "t",
303
+ "x-api-key": "k2",
304
+ }
305
+ assert forward_header_names() == {"authorization", "cookie"}
306
+ assert select_forward_headers(headers) == {"Authorization": "Bearer k", "cookie": "sid=1"}
307
+ monkeypatch.setenv("AUTH_FORWARD_HEADERS", " X-Api-Key , cookie ")
308
+ assert select_forward_headers(headers) == {"cookie": "sid=1", "x-api-key": "k2"}
309
+ monkeypatch.setenv("AUTH_FORWARD_HEADERS", "")
310
+ assert select_forward_headers(headers) == {}
@@ -0,0 +1,148 @@
1
+ # Copyright 2026 graph-agents-cli contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Structured logging: JSON records with correlation ids, levels, formats."""
16
+
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ import logging
21
+ import os
22
+ import subprocess
23
+ import sys
24
+ from collections.abc import Iterator
25
+ from pathlib import Path
26
+
27
+ import pytest
28
+
29
+ from {{cookiecutter.agent_directory}}.app_utils import telemetry
30
+ from {{cookiecutter.agent_directory}}.app_utils.limits import SettingsError
31
+
32
+
33
+ @pytest.fixture
34
+ def root_logging(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]:
35
+ root = logging.getLogger()
36
+ level, handlers = root.level, list(root.handlers)
37
+ for name in ("LOG_LEVEL", "LOG_FORMAT", "APP_ENV"):
38
+ monkeypatch.delenv(name, raising=False)
39
+ yield
40
+ root.handlers = handlers
41
+ root.setLevel(level)
42
+ telemetry.bind_log_context(request_id=None, run_id=None, thread_id=None, principal_hash=None)
43
+
44
+
45
+ def _records(err: str) -> list[dict]:
46
+ return [json.loads(line) for line in err.splitlines() if line.startswith("{")]
47
+
48
+
49
+ def test_json_records_carry_the_correlation_ids(root_logging, capsys) -> None:
50
+ telemetry.setup_logging()
51
+ telemetry.setup_logging() # idempotent: still one handler
52
+ telemetry.bind_log_context(request_id="req-1", run_id="run-1", thread_id="t-1")
53
+ log = logging.getLogger("app.test")
54
+ log.info("run finished", extra={"status": "ok", "latency_ms": 12})
55
+ try:
56
+ raise RuntimeError("boom")
57
+ except RuntimeError:
58
+ log.exception("failed (error_id=%s)", "abc")
59
+ records = _records(capsys.readouterr().err)
60
+ assert len(records) == 2
61
+ first, second = records
62
+ assert first["level"] == "INFO" and first["logger"] == "app.test"
63
+ assert first["message"] == "run finished" and first["status"] == "ok"
64
+ assert first["latency_ms"] == 12
65
+ assert (first["request_id"], first["run_id"], first["thread_id"]) == ("req-1", "run-1", "t-1")
66
+ assert "principal_hash" not in first # unset ids are left out, not "None"
67
+ assert second["exc_type"] == "RuntimeError" and "boom" in second["exception"]
68
+
69
+
70
+ def test_level_and_text_format(root_logging, monkeypatch, capsys) -> None:
71
+ monkeypatch.setenv("LOG_LEVEL", "warning")
72
+ monkeypatch.setenv("LOG_FORMAT", "text")
73
+ telemetry.setup_logging()
74
+ telemetry.bind_log_context(request_id="req-2")
75
+ logging.getLogger("app.test").info("hidden")
76
+ logging.getLogger("app.test").warning("shown")
77
+ err = capsys.readouterr().err
78
+ assert "hidden" not in err and "WARNING app.test [request_id=req-2]: shown" in err
79
+
80
+
81
+ def test_dev_defaults_to_text_and_other_envs_to_json(monkeypatch) -> None:
82
+ monkeypatch.setenv("APP_ENV", "dev")
83
+ assert telemetry.log_format() == "text"
84
+ for other in ("prod", "DEV", " dev "): # only exactly `dev` is dev
85
+ monkeypatch.setenv("APP_ENV", other)
86
+ assert telemetry.log_format() == "json"
87
+
88
+
89
+ def test_lines_logged_before_the_lifespan_follow_log_format_too() -> None:
90
+ """Import-time warnings and uvicorn's startup lines are JSON in JSON mode.
91
+
92
+ Run as uvicorn does: its logging config first, then the app import, then
93
+ its startup lines (before the app's lifespan runs).
94
+ """
95
+ code = (
96
+ "import logging, logging.config\n"
97
+ "import uvicorn.config\n"
98
+ "logging.config.dictConfig(uvicorn.config.LOGGING_CONFIG)\n"
99
+ "import {{cookiecutter.agent_directory}}.fast_api_app\n"
100
+ "logging.getLogger('uvicorn.error').info('Started server process [1]')\n"
101
+ )
102
+ env = dict(os.environ)
103
+ env.update(
104
+ {
105
+ # Set (not removed) so a project .env cannot fill them in.
106
+ "APP_URL": "",
107
+ "LOG_FORMAT": "json",
108
+ "LOG_LEVEL": "INFO",
109
+ "APP_ENV": "prod",
110
+ "RUNTIME": "fastapi",
111
+ "AUTH_POLICY": "shared-bearer",
112
+ "MODEL_PROVIDER": "fake",
113
+ "MODEL_NAME": "fake",
114
+ "CHECKPOINTER": "memory",
115
+ "TRACING_ENABLED": "false",
116
+ }
117
+ )
118
+ result = subprocess.run(
119
+ [sys.executable, "-c", code],
120
+ env=env,
121
+ cwd=Path(__file__).resolve().parents[2],
122
+ capture_output=True,
123
+ text=True,
124
+ timeout=120,
125
+ )
126
+ assert result.returncode == 0, result.stderr
127
+ lines = [line for line in result.stderr.splitlines() if line.strip()]
128
+ for needle in ("APP_URL is not set", "Started server process [1]"):
129
+ matching = [line for line in lines if needle in line]
130
+ assert matching, result.stderr
131
+ assert all(json.loads(line)["message"] for line in matching), matching
132
+
133
+
134
+ @pytest.mark.parametrize(("name", "value"), [("LOG_LEVEL", "LOUD"), ("LOG_FORMAT", "xml")])
135
+ def test_bad_logging_settings_are_refused(monkeypatch, name: str, value: str) -> None:
136
+ monkeypatch.setenv(name, value)
137
+ with pytest.raises(SettingsError):
138
+ telemetry.log_level() if name == "LOG_LEVEL" else telemetry.log_format()
139
+
140
+
141
+ def test_trace_capture_is_metadata_or_full(monkeypatch) -> None:
142
+ for value, expected in (("", "metadata"), ("metadata", "metadata"), (" FULL ", "full")):
143
+ monkeypatch.setenv("TRACE_CAPTURE", value)
144
+ assert telemetry.trace_capture() == expected
145
+ monkeypatch.setenv("TRACE_CAPTURE", "everything")
146
+ with pytest.raises(SettingsError, match="TRACE_CAPTURE"):
147
+ telemetry.trace_capture() # the startup check refuses it
148
+ assert telemetry.capture_mode() == "metadata" # read anyway, it records the least