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,340 @@
1
+ # Copyright 2026 Google LLC
2
+ # Modifications Copyright 2026 graph-agents-cli contributors
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # https://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """End-to-end test of the server this project runs, in-process.
17
+
18
+ The app is started through its lifespan with `MODEL_PROVIDER=fake` and
19
+ `CHECKPOINTER=memory`, so no model key, database or network is needed, and
20
+ driven through `httpx.AsyncClient` over `ASGITransport`. Tool events are
21
+ exercised with the test-only `probe` tool (`use_test_tools`, see
22
+ `tests/conftest.py`), so these tests hold whatever tools the project has.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import os
28
+ import uuid
29
+ from collections.abc import AsyncIterator
30
+
31
+ # The environment must be in place before the app (and the graph) is imported.
32
+ os.environ.update(
33
+ {
34
+ "MODEL_PROVIDER": "fake",
35
+ "MODEL_NAME": "fake",
36
+ "CHECKPOINTER": "memory",
37
+ "AUTH_POLICY": "shared-bearer",
38
+ "API_KEY": "test-key",
39
+ "APP_ENV": "dev",
40
+ "TRACING_ENABLED": "false",
41
+ "RUNTIME": "fastapi",
42
+ "APP_URL": "http://testserver",
43
+ }
44
+ )
45
+
46
+ import httpx
47
+ import pytest
48
+ from langchain_core.tools import tool
49
+
50
+ from {{cookiecutter.agent_directory}} import agent as agent_module
51
+ from {{cookiecutter.agent_directory}}.app_utils.auth import Principal, reset_policy_cache
52
+ from {{cookiecutter.agent_directory}}.app_utils.chat import RUNTIME
53
+ from {{cookiecutter.agent_directory}}.fast_api_app import app
54
+
55
+ AUTH = {"Authorization": "Bearer test-key"}
56
+ A2A_PATH = "/a2a/{{cookiecutter.agent_directory}}"
57
+ PROBE_PROMPT = "Run the probe for San Francisco"
58
+
59
+
60
+ @tool
61
+ def probe(query: str) -> str:
62
+ """Test-only tool: reports what it was asked about."""
63
+ return f"probe reading for {query}: 42"
64
+
65
+
66
+ @pytest.fixture
67
+ async def client() -> AsyncIterator[httpx.AsyncClient]:
68
+ async with app.router.lifespan_context(app):
69
+ transport = httpx.ASGITransport(app=app)
70
+ async with httpx.AsyncClient(
71
+ transport=transport, base_url="http://testserver", timeout=30
72
+ ) as c:
73
+ yield c
74
+
75
+
76
+ async def _chat(
77
+ client: httpx.AsyncClient, message: str, thread_id: str | None = None
78
+ ) -> list[tuple[str, dict]]:
79
+ body: dict = {"message": message}
80
+ if thread_id:
81
+ body["thread_id"] = thread_id
82
+ events: list[tuple[str, dict]] = []
83
+ async with client.stream(
84
+ "POST", "/chat", json=body, headers={**AUTH, "Accept": "text/event-stream"}
85
+ ) as r:
86
+ assert r.status_code == 200, await r.aread()
87
+ assert r.headers["content-type"].startswith("text/event-stream")
88
+ event = None
89
+ async for line in r.aiter_lines():
90
+ if line.startswith("event:"):
91
+ event = line[6:].strip()
92
+ elif line.startswith("data:") and event:
93
+ import json
94
+
95
+ events.append((event, json.loads(line[5:].strip())))
96
+ event = None
97
+ return events
98
+
99
+
100
+ async def test_health(client: httpx.AsyncClient) -> None:
101
+ r = await client.get("/health")
102
+ assert r.status_code == 200
103
+ assert r.json() == {"status": "ok", "runtime": "fastapi", "checkpointer": "memory"}
104
+
105
+
106
+ async def test_chat_requires_the_bearer_key(client: httpx.AsyncClient) -> None:
107
+ r = await client.post("/chat", json={"message": "hi"})
108
+ assert r.status_code == 401
109
+ r = await client.post("/chat", json={"message": "hi"}, headers={"Authorization": "Bearer nope"})
110
+ assert r.status_code == 401
111
+ r = await client.get("/threads/x/messages")
112
+ assert r.status_code == 401
113
+
114
+
115
+ async def test_chat_sse_event_sequence_with_a_tool_call(
116
+ client: httpx.AsyncClient, use_test_tools
117
+ ) -> None:
118
+ use_test_tools(probe)
119
+ events = await _chat(client, PROBE_PROMPT)
120
+ names = [e for e, _ in events]
121
+ assert names[0] == "message.start"
122
+ assert names[-1] == "message.end"
123
+ assert "tool.call" in names and "tool.result" in names
124
+ assert names.index("tool.call") < names.index("tool.result") < names.index("message.delta")
125
+ start, end = events[0][1], events[-1][1]
126
+ assert start["thread_id"] and start["run_id"] == end["run_id"]
127
+ call = next(d for e, d in events if e == "tool.call")
128
+ assert call["name"] == "probe" and call["args"] == {"query": "San Francisco"}
129
+ result = next(d for e, d in events if e == "tool.result")
130
+ assert result["id"] == call["id"] and result["is_error"] is False
131
+ assert result["result"] == "probe reading for San Francisco: 42"
132
+ text = "".join(d["text"] for e, d in events if e == "message.delta")
133
+ assert "probe reading for San Francisco: 42" in text
134
+ assert end["status"] == "ok" and end["usage"]["output_tokens"] > 0 and end["latency_ms"] >= 0
135
+
136
+
137
+ async def test_the_project_tools_do_not_matter_to_a_plain_chat(
138
+ client: httpx.AsyncClient, use_test_tools
139
+ ) -> None:
140
+ """With no tool bound at all the agent still answers (tools are the project's to change)."""
141
+ use_test_tools()
142
+ events = await _chat(client, PROBE_PROMPT)
143
+ names = [e for e, _ in events]
144
+ assert names[0] == "message.start" and names[-1] == "message.end"
145
+ assert "tool.call" not in names
146
+ text = "".join(d["text"] for e, d in events if e == "message.delta")
147
+ assert PROBE_PROMPT in text
148
+
149
+
150
+ async def test_thread_continuity_and_messages_endpoint(client: httpx.AsyncClient) -> None:
151
+ thread_id = str(uuid.uuid4())
152
+ first = await _chat(client, "hello", thread_id)
153
+ assert first[0][1]["thread_id"] == thread_id
154
+ second = await _chat(client, "thanks", thread_id)
155
+ assert second[0][1]["thread_id"] == thread_id
156
+ r = await client.get(f"/threads/{thread_id}/messages", headers=AUTH)
157
+ assert r.status_code == 200
158
+ messages = r.json()
159
+ assert [m["role"] for m in messages] == ["user", "assistant", "user", "assistant"]
160
+ assert messages[0]["content"] == "hello" and "Hello" in messages[1]["content"]
161
+ r = await client.get(f"/threads/{uuid.uuid4()}/messages", headers=AUTH)
162
+ assert r.status_code == 404
163
+
164
+
165
+ async def test_playground_only_in_dev(
166
+ client: httpx.AsyncClient, monkeypatch: pytest.MonkeyPatch
167
+ ) -> None:
168
+ r = await client.get("/playground")
169
+ assert r.status_code == 200 and "text/html" in r.headers["content-type"] and "/chat" in r.text
170
+ for other in ("prod", "DEV", " dev "): # dev relaxes checks: only the exact value counts
171
+ monkeypatch.setenv("APP_ENV", other)
172
+ r = await client.get("/playground")
173
+ assert r.status_code == 404, other
174
+
175
+
176
+ async def test_openapi_and_docs_exist_only_in_dev(client: httpx.AsyncClient) -> None:
177
+ # This app was built under APP_ENV=dev: the schema and Swagger UI are on.
178
+ assert (await client.get("/openapi.json")).status_code == 200
179
+ assert (await client.get("/docs")).status_code == 200
180
+ assert (await client.get("/redoc")).status_code == 404
181
+ # Built with APP_ENV unset (the deployed default), they are gone.
182
+ import importlib
183
+ import os
184
+
185
+ from {{cookiecutter.agent_directory}} import fast_api_app as module
186
+
187
+ saved = os.environ.pop("APP_ENV", None)
188
+ try:
189
+ prod_app = importlib.reload(module).app
190
+ finally:
191
+ if saved is not None:
192
+ os.environ["APP_ENV"] = saved
193
+ importlib.reload(module)
194
+ async with httpx.AsyncClient(
195
+ transport=httpx.ASGITransport(app=prod_app), base_url="http://testserver"
196
+ ) as prod:
197
+ assert (await prod.get("/openapi.json")).status_code == 404
198
+ assert (await prod.get("/docs")).status_code == 404
199
+ assert prod_app.openapi()["paths"] # LangGraph Server still builds its spec from it
200
+
201
+
202
+ async def test_chat_error_event_replaces_message_end_and_records_the_run(
203
+ client: httpx.AsyncClient, monkeypatch: pytest.MonkeyPatch
204
+ ) -> None:
205
+ async def failing_astream(*args: object, **kwargs: object): # type: ignore[no-untyped-def]
206
+ raise RuntimeError("model down")
207
+ yield # pragma: no cover - makes this an async generator
208
+
209
+ # `_local_events` imports `graph` at call time, so patching the instance is enough.
210
+ monkeypatch.setattr(agent_module.graph, "astream", failing_astream)
211
+ events = await _chat(client, "hello")
212
+ names = [e for e, _ in events]
213
+ assert names == ["message.start", "error"], names
214
+ error = events[1][1]
215
+ run_id = events[0][1]["run_id"]
216
+ # A generic message and an id naming the logged detail; the detail itself
217
+ # only under APP_ENV=dev (this app runs in dev).
218
+ assert error["code"] == "run_failed" and error["run_id"] == run_id
219
+ assert error["message"] == f"The run failed. Reference: {error['error_id']}."
220
+ assert error["detail"] == "RuntimeError: model down"
221
+ monkeypatch.setenv("APP_ENV", "prod")
222
+ error = (await _chat(client, "hello"))[1][1]
223
+ assert "detail" not in error and "model down" not in str(error)
224
+ assert RUNTIME.runs is not None
225
+ record = await RUNTIME.runs.get(run_id)
226
+ assert record is not None
227
+ assert record.status == "error" and record.error_type == "RuntimeError"
228
+
229
+
230
+ @pytest.mark.parametrize(
231
+ ("policy", "marker"),
232
+ [("custom", "AUTH_POLICY=custom"), ("jwt", "AUTH_POLICY=jwt"), ("product-session", "custom")],
233
+ )
234
+ async def test_stub_policies_answer_503_on_every_surface(
235
+ client: httpx.AsyncClient, monkeypatch: pytest.MonkeyPatch, policy: str, marker: str
236
+ ) -> None:
237
+ """`custom` (and its retired name) and the `jwt` placeholder fail closed everywhere."""
238
+ monkeypatch.setenv("AUTH_POLICY", policy)
239
+ reset_policy_cache()
240
+ try:
241
+ assert (await client.get("/health")).status_code == 200
242
+ for method, path, kwargs in (
243
+ ("POST", "/chat", {"json": {"message": "hi"}, "headers": AUTH}),
244
+ ("POST", "/chat", {"json": {"message": "hi"}, "headers": {"Cookie": "sid=1"}}),
245
+ ("GET", "/threads/x/messages", {"headers": AUTH}),
246
+ ("GET", f"{A2A_PATH}/.well-known/agent-card.json", {"headers": AUTH}),
247
+ ("POST", A2A_PATH, {"json": {"jsonrpc": "2.0", "id": "1", "method": "SendMessage"}}),
248
+ ):
249
+ r = await client.request(method, path, **kwargs)
250
+ assert r.status_code == 503, (method, path, r.text)
251
+ assert marker in r.json()["detail"]
252
+ finally:
253
+ reset_policy_cache()
254
+
255
+
256
+ async def test_thread_ownership_and_tool_args_redaction(
257
+ client: httpx.AsyncClient, monkeypatch: pytest.MonkeyPatch, use_test_tools
258
+ ) -> None:
259
+ """Non-owners are refused; a read-across role reads without tool args under metadata capture."""
260
+ use_test_tools(probe)
261
+ thread_id = str(uuid.uuid4())
262
+ await _chat(client, PROBE_PROMPT, thread_id)
263
+ owner = Principal(id="shared", roles=["shared"])
264
+ messages = await RUNTIME.messages(owner, thread_id)
265
+ assistant = next(m for m in messages if m.get("tool_calls"))
266
+ assert assistant["tool_calls"][0]["args"] == {"query": "San Francisco"}
267
+
268
+ from fastapi import HTTPException
269
+
270
+ with pytest.raises(HTTPException) as exc:
271
+ await RUNTIME.messages(Principal(id="stranger"), thread_id)
272
+ assert exc.value.status_code == 403
273
+ assert RUNTIME.threads is not None
274
+ with pytest.raises(HTTPException) as exc:
275
+ await RUNTIME.threads.ensure(thread_id, Principal(id="stranger"))
276
+ assert exc.value.status_code == 403
277
+
278
+ monkeypatch.setenv("AUTH_READ_ACROSS_ROLES", "auditor")
279
+ auditor = Principal(id="auditor", roles=["auditor"])
280
+ messages = await RUNTIME.messages(auditor, thread_id)
281
+ assistant = next(m for m in messages if m.get("tool_calls"))
282
+ assert assistant["tool_calls"][0]["name"] == "probe"
283
+ assert "args" not in assistant["tool_calls"][0]
284
+ monkeypatch.setenv("TRACE_CAPTURE", "full")
285
+ messages = await RUNTIME.messages(auditor, thread_id)
286
+ assert next(m for m in messages if m.get("tool_calls"))["tool_calls"][0]["args"] == {
287
+ "query": "San Francisco"
288
+ }
289
+ # Reading across is not writing: the auditor cannot continue the thread.
290
+ with pytest.raises(HTTPException) as exc:
291
+ await RUNTIME.threads.ensure(thread_id, auditor)
292
+ assert exc.value.status_code == 403
293
+
294
+
295
+ async def test_a2a_card_and_message(client: httpx.AsyncClient) -> None:
296
+ r = await client.get(f"{A2A_PATH}/.well-known/agent-card.json")
297
+ assert r.status_code == 401
298
+ r = await client.get(f"{A2A_PATH}/.well-known/agent-card.json", headers=AUTH)
299
+ assert r.status_code == 200
300
+ card = r.json()
301
+ assert card["name"] == "{{cookiecutter.agent_directory}}"
302
+ assert "bearer" in card["securitySchemes"]
303
+ assert card["supportedInterfaces"][0]["url"] == f"http://testserver{A2A_PATH}"
304
+
305
+ r = await client.post(A2A_PATH, json={"jsonrpc": "2.0", "id": "1", "method": "SendMessage"})
306
+ assert r.status_code == 401
307
+
308
+ from a2a.client import ClientConfig, create_client
309
+ from a2a.types import Message, Part, Role, SendMessageRequest, TaskState
310
+
311
+ transport = httpx.ASGITransport(app=app)
312
+ async with httpx.AsyncClient(
313
+ transport=transport, base_url="http://testserver", headers=AUTH, timeout=30
314
+ ) as http:
315
+ a2a_client = await create_client(
316
+ f"http://testserver{A2A_PATH}", ClientConfig(streaming=True, httpx_client=http)
317
+ )
318
+ message = Message(
319
+ message_id=f"msg-{uuid.uuid4()}", role=Role.ROLE_USER, parts=[Part(text="Hi!")]
320
+ )
321
+ responses = [
322
+ chunk async for chunk in a2a_client.send_message(SendMessageRequest(message=message))
323
+ ]
324
+ assert responses, "No responses received from the A2A stream"
325
+
326
+ def _completed(chunk: object) -> bool:
327
+ if chunk.HasField("status_update"):
328
+ return chunk.status_update.status.state == TaskState.TASK_STATE_COMPLETED
329
+ if chunk.HasField("task"):
330
+ return chunk.task.status.state == TaskState.TASK_STATE_COMPLETED
331
+ return False
332
+
333
+ text = "".join(
334
+ part.text
335
+ for chunk in responses
336
+ if chunk.HasField("artifact_update")
337
+ for part in chunk.artifact_update.artifact.parts
338
+ )
339
+ assert any(_completed(chunk) for chunk in responses), responses
340
+ assert "Hello" in text, responses