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,558 @@
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
+ """graph-agents-cli eval generate command: run the agent over a dataset into traces."""
16
+
17
+ from __future__ import annotations
18
+
19
+ import contextlib
20
+ import inspect
21
+ import os
22
+ import sys
23
+ from collections.abc import Callable
24
+ from concurrent.futures import ThreadPoolExecutor, as_completed
25
+ from pathlib import Path
26
+ from typing import Any
27
+ from urllib.parse import urlsplit, urlunsplit
28
+
29
+ import click
30
+ from rich.markup import escape
31
+
32
+ from graph_agents_cli import _http
33
+ from graph_agents_cli._chat_client import redact_credentials
34
+ from graph_agents_cli._output import Console
35
+ from graph_agents_cli._project import find_project_root
36
+ from graph_agents_cli._remote import deprecated_session_token, fold_session_token
37
+ from graph_agents_cli.eval import _paths
38
+ from graph_agents_cli.eval._client import (
39
+ DEFAULT_TIMEOUT,
40
+ STATUS_OK,
41
+ build_case_headers,
42
+ empty_trace,
43
+ run_case,
44
+ )
45
+ from graph_agents_cli.eval._common import (
46
+ EXIT_INCOMPLETE,
47
+ EXIT_OK,
48
+ EvalConfigError,
49
+ project_env,
50
+ project_meta,
51
+ utc_now_iso,
52
+ write_json_file,
53
+ )
54
+ from graph_agents_cli.eval.dataset import Dataset, EvalCase, load_dataset
55
+ from graph_agents_cli.run._signals import shielded, terminate_like_interrupt
56
+
57
+ DEFAULT_CONCURRENCY = 4
58
+ API_KEY_ENV = "GRAPH_AGENTS_CLI_API_KEY"
59
+ # Decisions on role:<name> gates are sent with this credential when set (an
60
+ # approver other than the eval identity); a gate that lists requester is
61
+ # decided as the eval identity, which started the run.
62
+ APPROVER_KEY_ENV = "GRAPH_AGENTS_CLI_APPROVER_API_KEY"
63
+
64
+
65
+ def _start_local_server(project_root: Path, meta: dict[str, Any]) -> tuple[str, Callable[[], None]]:
66
+ """Start (or reuse) the project's local server; returns ``(base_url, teardown)``.
67
+
68
+ Coded against ``run._local_server.ensure_server(project_root, agent_dir, *,
69
+ runtime, ...)`` returning a ``ServerInfo`` with ``base_url`` (or ``port``),
70
+ ``started`` and ``pid``. Only the required parameters the function actually
71
+ declares are filled in (``agent_dir``, ``runtime``, ``language``), so a
72
+ signature change on either side does not break the call.
73
+ """
74
+ from graph_agents_cli.run import _local_server
75
+
76
+ ensure_server = _local_server.ensure_server
77
+ params = inspect.signature(ensure_server).parameters
78
+ args: list[Any] = [project_root]
79
+ kwargs: dict[str, Any] = {}
80
+ for name, param in list(params.items())[1:]:
81
+ if param.default is not inspect.Parameter.empty:
82
+ continue
83
+ value: Any
84
+ if name == "agent_dir":
85
+ value = meta.get("agent_directory") or "app"
86
+ elif name == "runtime":
87
+ value = meta.get("runtime") or "fastapi"
88
+ elif name == "language":
89
+ value = "python"
90
+ else:
91
+ continue
92
+ if param.kind is inspect.Parameter.KEYWORD_ONLY:
93
+ kwargs[name] = value
94
+ else:
95
+ args.append(value)
96
+ info = ensure_server(*args, **kwargs)
97
+
98
+ base_url = getattr(info, "base_url", None)
99
+ if not base_url:
100
+ port = getattr(info, "port", None)
101
+ if port is None:
102
+ raise EvalConfigError("local server start returned no base_url or port")
103
+ base_url = f"http://127.0.0.1:{port}"
104
+ started = bool(getattr(info, "started", True))
105
+ pid = getattr(info, "pid", None)
106
+ # A long session must not look idle to a concurrent `run` (which would
107
+ # replace the server under it): stamp last_activity at a coarse cadence.
108
+ heartbeat = getattr(_local_server, "start_activity_heartbeat", None)
109
+ stop_heartbeat = heartbeat(project_root) if callable(heartbeat) else (lambda: None)
110
+
111
+ def teardown() -> None:
112
+ # A SIGTERM or Ctrl-C now is held until the server is stopped and its
113
+ # record removed, then handled (a stale record would name a dead PID).
114
+ with shielded():
115
+ stop_heartbeat()
116
+ if not started:
117
+ return
118
+ stop = _local_server.stop_server
119
+ try:
120
+ if pid is not None and "pid" in inspect.signature(stop).parameters:
121
+ stop(project_root, pid=pid)
122
+ else:
123
+ stop(project_root)
124
+ except _local_server.ServerStopError as exc:
125
+ # A warning: the traces (or the error that ended the run) stand.
126
+ _local_server.warn_not_stopped(exc)
127
+
128
+ return str(base_url), teardown
129
+
130
+
131
+ def _dispatch(
132
+ cases: list[EvalCase],
133
+ *,
134
+ base_url: str,
135
+ headers: dict[str, str],
136
+ metadata: dict[str, Any],
137
+ concurrency: int,
138
+ timeout: float,
139
+ console: Console,
140
+ decision_headers: dict[str, str] | None = None,
141
+ ) -> list[dict[str, Any]]:
142
+ """Run every case in parallel; input order is preserved in the result."""
143
+ traces: list[dict[str, Any] | None] = [None] * len(cases)
144
+
145
+ def _one(index: int, case: EvalCase) -> tuple[int, dict[str, Any]]:
146
+ try:
147
+ return index, run_case(
148
+ base_url,
149
+ case,
150
+ headers=headers,
151
+ metadata=metadata,
152
+ timeout=timeout,
153
+ decision_headers=decision_headers,
154
+ )
155
+ except Exception as exc: # a worker crash still yields a trace
156
+ trace = empty_trace(case.id)
157
+ trace["status"] = "error"
158
+ trace["error"] = redact_credentials(f"worker crashed: {type(exc).__name__}: {exc}")
159
+ return index, trace
160
+
161
+ pool = ThreadPoolExecutor(max_workers=max(1, concurrency))
162
+ try:
163
+ futures = [pool.submit(_one, i, case) for i, case in enumerate(cases)]
164
+ for future in as_completed(futures):
165
+ index, trace = future.result()
166
+ traces[index] = trace
167
+ status = trace["status"]
168
+ style = "green" if status == STATUS_OK else "red"
169
+ detail = f"{trace['latency_ms']} ms" if status == STATUS_OK else str(trace.get("error"))
170
+ console.print(f"[generate] {trace['case_id']}: [{style}]{status}[/{style}] ({detail})")
171
+ except BaseException:
172
+ # Ctrl-C / SIGTERM: queued cases never start, and the caller's teardown
173
+ # stops the server now instead of after every in-flight call timed out
174
+ # (those calls then fail fast against the stopped server).
175
+ pool.shutdown(wait=False, cancel_futures=True)
176
+ raise
177
+ pool.shutdown(wait=True)
178
+ return [t if t is not None else empty_trace(c.id) for t, c in zip(traces, cases, strict=True)]
179
+
180
+
181
+ _WRITE_METHODS = ("POST", "PUT", "PATCH", "DELETE")
182
+
183
+
184
+ def display_url(url: str) -> str:
185
+ """``url`` as printed and stored, with any ``user:password@`` replaced by ``***@``."""
186
+ parts = urlsplit(url)
187
+ if "@" not in parts.netloc:
188
+ return url
189
+ return urlunsplit(parts._replace(netloc="***@" + parts.netloc.rsplit("@", 1)[1]))
190
+
191
+
192
+ def _policy_write_access(project_root: Path) -> list[str]:
193
+ """``"api (METHOD, ...)"`` for each API whose policy allows a write method.
194
+
195
+ Read from the project's own ``api-policy.yaml``; the deployed image carries
196
+ the policy it was built with, so this is a hint, not a guarantee. Any
197
+ problem reading it yields no hint (``lint`` reports policy problems).
198
+ """
199
+ from graph_agents_cli._api_policy import POLICY_FILENAME, load_policy_document
200
+
201
+ path = project_root / POLICY_FILENAME
202
+ if not path.is_file():
203
+ return []
204
+ try:
205
+ document = load_policy_document(path)
206
+ except Exception:
207
+ return []
208
+ found: list[str] = []
209
+ for name, api in (document.get("apis") or {}).items():
210
+ if not isinstance(api, dict):
211
+ continue
212
+ allowed = _expand([str(m).upper() for m in api.get("allowed_methods") or []])
213
+ operations = api.get("allowed_operations")
214
+ if isinstance(operations, list):
215
+ # An allow-list narrows access to its entries (an entry without
216
+ # `methods` takes the API's allowed_methods).
217
+ methods: set[str] = set()
218
+ for entry in operations:
219
+ pinned = entry.get("methods") if isinstance(entry, dict) else None
220
+ if pinned:
221
+ methods |= _expand([str(m).upper() for m in pinned]) & allowed
222
+ else:
223
+ methods |= allowed
224
+ allowed = methods
225
+ writes = [m for m in _WRITE_METHODS if m in allowed]
226
+ if writes:
227
+ found.append(f"{name} ({', '.join(writes)})")
228
+ return found
229
+
230
+
231
+ def _expand(methods: list[str]) -> set[str]:
232
+ return set(_WRITE_METHODS) | set(methods) if "*" in methods else set(methods)
233
+
234
+
235
+ def warn_live_target(
236
+ console: Console, base_url: str, project_root: Path, cases: int | None
237
+ ) -> None:
238
+ """Say, before any case runs, that `--url` runs the agent's tools for real there."""
239
+ writes = _policy_write_access(project_root)
240
+ what = f"{cases} case(s) will run" if cases else "The cases will run"
241
+ console.print(
242
+ f"[bold yellow]Warning:[/bold yellow] [yellow]{what} against the agent at "
243
+ f"{escape(display_url(base_url))} (--url). Every tool call the agent makes runs for "
244
+ "real in that environment, as the identity these requests authenticate as: tools "
245
+ "that create, change or delete data do so there.[/yellow]"
246
+ )
247
+ if writes:
248
+ console.print(
249
+ "[yellow]This project's api-policy.yaml allows write methods: "
250
+ f"{escape('; '.join(writes))}.[/yellow]"
251
+ )
252
+ console.print(
253
+ "[yellow]Point eval at an environment whose data you can reset, with a dedicated test "
254
+ "identity; never at production data.[/yellow]"
255
+ )
256
+
257
+
258
+ # Headers that carry the eval identity's credential: an approver's decisions go without them.
259
+ _CREDENTIAL_HEADERS = frozenset({"authorization", "cookie", "x-api-key"})
260
+
261
+
262
+ def decision_headers_for(headers: dict[str, str], env: dict[str, str]) -> dict[str, str] | None:
263
+ """The headers decisions on ``role:`` gates go with: the approver's credential when set.
264
+
265
+ Only the approver's bearer credential identifies the decider: the eval
266
+ identity's own credentials (its bearer, cookies, API key header) are left
267
+ out, so a policy that reads them cannot take the decision as the eval
268
+ identity. A gate that lists ``requester`` is decided as the eval identity.
269
+ """
270
+ key = env.get(APPROVER_KEY_ENV, "")
271
+ if not key:
272
+ return None
273
+ decided = {k: v for k, v in headers.items() if k.lower() not in _CREDENTIAL_HEADERS}
274
+ decided["Authorization"] = f"Bearer {key}"
275
+ return decided
276
+
277
+
278
+ def approving_cases(cases: list[EvalCase]) -> list[str]:
279
+ """Ids of the cases whose approvals instructions approve a gated call."""
280
+ return [c.id for c in cases if any(i["decision"] == "approve" for i in c.approvals)]
281
+
282
+
283
+ def _print_incomplete_summary(traces: list[dict[str, Any]], *, remote: bool = False) -> None:
284
+ bad = [t for t in traces if t["status"] != STATUS_OK]
285
+ click.echo("", err=True)
286
+ click.echo(
287
+ f"Generate summary: {len(traces) - len(bad)}/{len(traces)} cases produced a response, "
288
+ f"{len(bad)} did not.",
289
+ err=True,
290
+ )
291
+ for trace in bad:
292
+ click.echo(f" - {trace['case_id']}: {trace['status']}: {trace.get('error')}", err=True)
293
+ if any("HTTP 401 " in str(t.get("error") or "") for t in bad):
294
+ # The same policy-aware hint `run` prints (which credential, and how to send it).
295
+ from graph_agents_cli.run.cmd_run import _auth_hint, _project_auth_policy
296
+
297
+ hint = _auth_hint(_project_auth_policy(remote=remote), remote=remote).strip()
298
+ click.echo(f" {hint}", err=True)
299
+
300
+
301
+ def generate_traces(
302
+ *,
303
+ dataset: str | None = None,
304
+ output: str | None = None,
305
+ url: str | None = None,
306
+ concurrency: int = DEFAULT_CONCURRENCY,
307
+ header: tuple[str, ...] = (),
308
+ cookie: tuple[str, ...] = (),
309
+ session_token: str | None = None,
310
+ app_name: str | None = None,
311
+ timeout: float = DEFAULT_TIMEOUT,
312
+ console: Console | None = None,
313
+ ) -> int:
314
+ """Run the dataset and write the trace file; returns 0 (complete) or 2 (incomplete)."""
315
+ console = console or Console()
316
+ project_root = find_project_root()
317
+ if project_root is None:
318
+ raise EvalConfigError(
319
+ "not inside a graph-agents-cli project (no graph-agents-cli-manifest.yaml found)"
320
+ )
321
+ files = _paths.resolve_input_datasets(project_root, dataset)
322
+ if not files:
323
+ raise EvalConfigError(
324
+ f"no dataset found: pass --dataset PATH or add {_paths.DEFAULT_INPUT_DATASET}"
325
+ )
326
+ ds: Dataset = load_dataset(files)
327
+ output_path = _paths.resolve_output_path(
328
+ project_root,
329
+ output,
330
+ default_dir=_paths.default_traces_dir(project_root),
331
+ prefix=_paths.TRACES_FILE_PREFIX,
332
+ )
333
+ meta = project_meta(project_root)
334
+ app_name = app_name or meta["agent_directory"]
335
+
336
+ env: dict[str, str] = dict(os.environ)
337
+ if not url and not env.get(API_KEY_ENV):
338
+ # The local server enforces the shared-bearer policy with the project's API_KEY.
339
+ local_key = project_env(project_root).get("API_KEY")
340
+ if local_key:
341
+ env[API_KEY_ENV] = local_key
342
+ headers = build_case_headers(header, cookie, session_token, env=env)
343
+ decision_headers = decision_headers_for(headers, env)
344
+
345
+ console.print(
346
+ f"Running [cyan]{len(ds.cases)}[/cyan] case(s) from "
347
+ f"[cyan]{', '.join(str(f.relative_to(project_root)) if f.is_relative_to(project_root) else str(f) for f in files)}[/cyan]"
348
+ )
349
+ metadata = {"dataset_hash": ds.hash, "app_name": app_name}
350
+ # With a local server, SIGTERM/SIGHUP unwind like Ctrl-C: the server this run
351
+ # started is stopped (and its pid file removed) even when a CI timeout kills it.
352
+ with terminate_like_interrupt() if not url else contextlib.nullcontext():
353
+ teardown: Callable[[], None] = lambda: None # noqa: E731
354
+ if url:
355
+ base_url = url.rstrip("/")
356
+ # A proxy setting that would fail every case fails the command once, up front
357
+ # (each case would otherwise record it as its own error).
358
+ _http.check_env_proxies(base_url)
359
+ console.print(f"Target: [cyan]{escape(display_url(base_url))}[/cyan]")
360
+ warn_live_target(console, base_url, project_root, len(ds.cases))
361
+ approving = approving_cases(ds.cases)
362
+ if approving:
363
+ console.print(
364
+ f"[yellow]{len(approving)} case(s) approve gated calls "
365
+ f"({escape(', '.join(approving[:5]))}{', ...' if len(approving) > 5 else ''})"
366
+ ": those calls are sent there as approved.[/yellow]"
367
+ )
368
+ else:
369
+ console.print("Starting the local server...")
370
+ base_url, teardown = _start_local_server(project_root, meta)
371
+ console.print(f"Local server at [cyan]{base_url}[/cyan]")
372
+
373
+ try:
374
+ traces = _dispatch(
375
+ ds.cases,
376
+ base_url=base_url,
377
+ headers=headers,
378
+ metadata=metadata,
379
+ concurrency=concurrency,
380
+ timeout=timeout,
381
+ console=console,
382
+ decision_headers=decision_headers,
383
+ )
384
+ finally:
385
+ teardown()
386
+
387
+ # The model is known only for the project's own local server, which runs the
388
+ # project's settings. The agent at a --url target does not report its model,
389
+ # and the local settings need not be what runs there: its traces name none.
390
+ model = None if url else meta["model"]
391
+ for trace, case in zip(traces, ds.cases, strict=True):
392
+ trace["agent_version"] = meta["agent_version"]
393
+ trace["model"] = model
394
+ trace["case"] = case.raw
395
+
396
+ doc = {
397
+ "dataset_hash": ds.hash,
398
+ "dataset_paths": [
399
+ str(f.relative_to(project_root)) if f.is_relative_to(project_root) else str(f)
400
+ for f in files
401
+ ],
402
+ "generated_at": utc_now_iso(),
403
+ "agent_version": meta["agent_version"],
404
+ "model": model,
405
+ # The project's MODEL_PROVIDER: the agent's only for the local server.
406
+ # `eval grade` warns when that agent ran on the fake model, and for a
407
+ # --url target when these settings name it.
408
+ "model_provider": meta["model_provider"],
409
+ "target": "url" if url else "local",
410
+ "base_url": display_url(base_url),
411
+ "app_name": app_name,
412
+ "traces": traces,
413
+ }
414
+ write_json_file(output_path, doc)
415
+ console.print(f"Traces saved to [green]{output_path}[/green]")
416
+
417
+ if any(t["status"] != STATUS_OK for t in traces):
418
+ _print_incomplete_summary(traces, remote=bool(url))
419
+ return EXIT_INCOMPLETE
420
+ return EXIT_OK
421
+
422
+
423
+ @click.command("generate")
424
+ @click.option(
425
+ "--dataset",
426
+ default=None,
427
+ help=(
428
+ "Dataset file, or a directory of *.json datasets. Defaults to "
429
+ f"{_paths.DEFAULT_INPUT_DATASET}, else every *.json in {_paths.DATASETS_DIR}/."
430
+ ),
431
+ )
432
+ @click.option(
433
+ "--output",
434
+ "-o",
435
+ default=None,
436
+ help=(
437
+ "Traces file, or a directory to write traces_<ts>.json into. Defaults to "
438
+ f"{_paths.ARTIFACTS_DIR}/{_paths.TRACES_SUBDIR}/traces_<ts>.json."
439
+ ),
440
+ )
441
+ @click.option(
442
+ "--url",
443
+ default=None,
444
+ help=(
445
+ "Base URL of a running agent (its POST /chat). Its tools run for real in that "
446
+ "environment, write tools included. When omitted the project's local server is "
447
+ "started for the run and stopped afterwards."
448
+ ),
449
+ )
450
+ @click.option(
451
+ "--concurrency",
452
+ type=click.IntRange(min=1),
453
+ default=DEFAULT_CONCURRENCY,
454
+ show_default=True,
455
+ help="Cases run in parallel, each on its own thread.",
456
+ )
457
+ @click.option(
458
+ "--header",
459
+ "-H",
460
+ "header",
461
+ multiple=True,
462
+ help=(
463
+ "Extra HTTP header 'Key: Value' (repeatable). For a bearer credential use "
464
+ "GRAPH_AGENTS_CLI_API_KEY instead (argv is visible to other local users); an "
465
+ "Authorization header overrides it."
466
+ ),
467
+ )
468
+ @click.option(
469
+ "--cookie",
470
+ multiple=True,
471
+ help="Cookie 'name=value' (repeatable), for a custom auth policy that reads cookies.",
472
+ )
473
+ @click.option(
474
+ "--session-token",
475
+ default=None,
476
+ hidden=True,
477
+ callback=deprecated_session_token,
478
+ help="Deprecated alias of --header 'X-Session-Token: ...'.",
479
+ )
480
+ @click.option(
481
+ "--app-name",
482
+ default=None,
483
+ help="Agent name recorded in the traces and sent as request metadata. Defaults to agent_directory.",
484
+ )
485
+ @click.option(
486
+ "--timeout",
487
+ type=click.FloatRange(min=1),
488
+ default=DEFAULT_TIMEOUT,
489
+ show_default=True,
490
+ help="Seconds allowed per chat call.",
491
+ )
492
+ def cmd_generate(
493
+ *,
494
+ dataset: str | None,
495
+ output: str | None,
496
+ url: str | None,
497
+ concurrency: int,
498
+ header: tuple[str, ...],
499
+ cookie: tuple[str, ...],
500
+ session_token: str | None,
501
+ app_name: str | None,
502
+ timeout: float,
503
+ ) -> None:
504
+ """Run the agent over the eval dataset and write traces.
505
+
506
+ Each case's user messages are sent to POST /chat (SSE) and the events are
507
+ folded into one trace per case: response, tool calls, usage, latency,
508
+ thread and run ids, and a status of ok, error or missing. The trace file
509
+ records the dataset hash so `eval grade` can account for every planned case.
510
+
511
+ Without --url the local server is started through `run`'s server manager
512
+ and stopped after the run. Credentials follow the project's auth policy,
513
+ locally and with --url. Put a bearer credential in GRAPH_AGENTS_CLI_API_KEY
514
+ (sent as 'Authorization: Bearer <value>'): unlike --header, it stays out
515
+ of the process list and your shell history.
516
+
517
+ \b
518
+ shared-bearer GRAPH_AGENTS_CLI_API_KEY=<API_KEY> (locally: the API_KEY in .env)
519
+ jwt GRAPH_AGENTS_CLI_API_KEY=<token> (locally: auth dev-token)
520
+ custom --header 'Name: value' or --cookie name=value
521
+
522
+ With --url every tool the agent calls runs for real in that environment
523
+ (a warning names the target first): cases that create, change or delete
524
+ data do so there. Use a dedicated test identity and data you can reset.
525
+
526
+ A call the API policy gates (an approval block) pauses the run; it is
527
+ decided as the case's "approvals" instructions say ({"decision":
528
+ "approve"|"reject", "match": {...}}) and the run continues. A gate no
529
+ instruction matches makes the case an error: generate never approves on
530
+ its own, and rejects such a gate (as it does one whose decision was
531
+ refused) so that no approval is left pending; one it may not reject goes
532
+ with the case's thread, which it deletes as the eval identity (deleting a
533
+ thread deletes its approvals). The trace records how (approvals[].cleanup),
534
+ and the case error names a gate it could neither reject nor delete, which
535
+ stays pending until it expires or an approver decides it (approves or
536
+ rejects). A gate that lists requester is decided as the eval identity (it
537
+ started the run); any other with GRAPH_AGENTS_CLI_APPROVER_API_KEY as a
538
+ bearer credential when it is set (a principal holding the gate's role).
539
+
540
+ \b
541
+ Exit codes:
542
+ 0 every case produced a trace with a response
543
+ 2 at least one case is error or missing (summary on stderr)
544
+ 3 configuration error (no dataset, malformed case, no project)
545
+ """
546
+ code = generate_traces(
547
+ dataset=dataset,
548
+ output=output,
549
+ url=url,
550
+ concurrency=concurrency,
551
+ header=fold_session_token(header, session_token),
552
+ cookie=cookie,
553
+ session_token=None,
554
+ app_name=app_name,
555
+ timeout=timeout,
556
+ )
557
+ if code:
558
+ sys.exit(code)