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,350 @@
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
+ """Eval dataset loading and validation (``tests/eval/datasets/*.json``).
16
+
17
+ Dataset shape::
18
+
19
+ {"cases": [{"id": "greeting",
20
+ "messages": [{"role": "user", "content": "hi"}],
21
+ "approvals": [{"decision": "approve", "match": {"operation_id": "cancelOrder"}}],
22
+ "expect": {...}, "judge": {"response_quality": {"threshold": 4}},
23
+ "reference": "...", "context": "...", "metadata": {}}]}
24
+
25
+ ``approvals`` tells ``eval generate`` how to decide each call the agent's
26
+ policy gates (an API's ``approval`` block): the first instruction whose
27
+ ``match`` names the paused call decides it. A gate no instruction matches is
28
+ a case error: a case must say what a human would do.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ from dataclasses import dataclass, field
34
+ from pathlib import Path
35
+ from typing import Any
36
+
37
+ from graph_agents_cli._approvals import match_problem
38
+ from graph_agents_cli.eval._common import EvalConfigError, canonical_hash, load_json_file
39
+
40
+ EXPECT_KEYS: tuple[str, ...] = (
41
+ "contains",
42
+ "not_contains",
43
+ "regex",
44
+ "json_schema",
45
+ "tool_calls",
46
+ "ordered",
47
+ "no_tool_calls",
48
+ "max_latency_ms",
49
+ "max_tokens",
50
+ "case_insensitive",
51
+ "scope",
52
+ "approvals",
53
+ "no_approvals",
54
+ )
55
+
56
+ # A case's `approvals` instructions: how generate decides a gated call.
57
+ APPROVAL_DECISIONS: tuple[str, ...] = ("approve", "reject")
58
+ APPROVAL_INSTRUCTION_KEYS: tuple[str, ...] = ("decision", "match")
59
+ # `expect.approvals` items: which gate the run hit, and how it ended.
60
+ APPROVAL_OUTCOMES: tuple[str, ...] = ("gated", "approved", "rejected")
61
+ APPROVAL_EXPECT_KEYS: tuple[str, ...] = ("match", "status")
62
+
63
+ # Which turns of a multi-turn case the expect checks read: the final turn (the
64
+ # reply being graded) or every turn. A single-turn case is the same either way.
65
+ SCOPE_FINAL_TURN = "final_turn"
66
+ SCOPE_ALL_TURNS = "all_turns"
67
+ EXPECT_SCOPES: tuple[str, ...] = (SCOPE_FINAL_TURN, SCOPE_ALL_TURNS)
68
+
69
+ EXPECT_DEFAULTS: dict[str, Any] = {
70
+ "contains": [],
71
+ "not_contains": [],
72
+ "regex": None,
73
+ "json_schema": None,
74
+ "tool_calls": None,
75
+ "ordered": False,
76
+ "no_tool_calls": False,
77
+ "max_latency_ms": None,
78
+ "max_tokens": None,
79
+ # contains / not_contains compare case-insensitively unless this is false:
80
+ # a refusal check such as not_contains ["deleted"] must also catch "Deleted".
81
+ "case_insensitive": True,
82
+ "scope": SCOPE_FINAL_TURN,
83
+ "approvals": None,
84
+ "no_approvals": False,
85
+ }
86
+
87
+ MESSAGE_ROLES: tuple[str, ...] = ("user", "assistant", "system")
88
+
89
+
90
+ @dataclass
91
+ class EvalCase:
92
+ id: str
93
+ messages: list[dict[str, Any]]
94
+ expect: dict[str, Any] = field(default_factory=lambda: dict(EXPECT_DEFAULTS))
95
+ judge: dict[str, dict[str, Any]] = field(default_factory=dict)
96
+ reference: str | None = None
97
+ context: str | None = None
98
+ metadata: dict[str, Any] = field(default_factory=dict)
99
+ raw: dict[str, Any] = field(default_factory=dict)
100
+ # How generate decides the gated calls this case reaches ({decision, match}).
101
+ approvals: list[dict[str, Any]] = field(default_factory=list)
102
+
103
+ def user_messages(self) -> list[str]:
104
+ return [str(m.get("content", "")) for m in self.messages if m.get("role") == "user"]
105
+
106
+ def conversation_text(self) -> str:
107
+ return "\n".join(f"{m.get('role', '?')}: {m.get('content', '')}" for m in self.messages)
108
+
109
+
110
+ @dataclass
111
+ class Dataset:
112
+ cases: list[EvalCase]
113
+ hash: str
114
+ sources: list[Path] = field(default_factory=list)
115
+
116
+ @property
117
+ def case_ids(self) -> list[str]:
118
+ return [c.id for c in self.cases]
119
+
120
+ def by_id(self) -> dict[str, EvalCase]:
121
+ return {c.id: c for c in self.cases}
122
+
123
+
124
+ def _where(source: Path | None, index: int) -> str:
125
+ return f"{source}: cases[{index}]" if source else f"cases[{index}]"
126
+
127
+
128
+ def parse_case(raw: Any, index: int = 0, source: Path | None = None) -> EvalCase:
129
+ """Validate one raw case dict into an :class:`EvalCase`.
130
+
131
+ Raises :class:`EvalConfigError` (exit 3) for a malformed case.
132
+ """
133
+ where = _where(source, index)
134
+ if not isinstance(raw, dict):
135
+ raise EvalConfigError(f"{where}: a case must be an object")
136
+ case_id = raw.get("id")
137
+ if not isinstance(case_id, str) or not case_id.strip():
138
+ raise EvalConfigError(f"{where}: 'id' must be a non-empty string")
139
+
140
+ messages = raw.get("messages")
141
+ if not isinstance(messages, list) or not messages:
142
+ raise EvalConfigError(f"{where} ({case_id}): 'messages' must be a non-empty list")
143
+ for i, message in enumerate(messages):
144
+ if not isinstance(message, dict):
145
+ raise EvalConfigError(f"{where} ({case_id}): messages[{i}] must be an object")
146
+ role = message.get("role")
147
+ if role not in MESSAGE_ROLES:
148
+ raise EvalConfigError(
149
+ f"{where} ({case_id}): messages[{i}].role must be one of {', '.join(MESSAGE_ROLES)}"
150
+ )
151
+ if not isinstance(message.get("content"), str):
152
+ raise EvalConfigError(f"{where} ({case_id}): messages[{i}].content must be a string")
153
+ if not any(m.get("role") == "user" for m in messages):
154
+ raise EvalConfigError(f"{where} ({case_id}): 'messages' must contain a user message")
155
+
156
+ expect_raw = raw.get("expect")
157
+ expect = dict(EXPECT_DEFAULTS)
158
+ if expect_raw is not None:
159
+ if not isinstance(expect_raw, dict):
160
+ raise EvalConfigError(f"{where} ({case_id}): 'expect' must be an object")
161
+ unknown = sorted(set(expect_raw) - set(EXPECT_KEYS))
162
+ if unknown:
163
+ raise EvalConfigError(
164
+ f"{where} ({case_id}): unknown expect key(s) {', '.join(unknown)}; "
165
+ f"known: {', '.join(EXPECT_KEYS)}"
166
+ )
167
+ for key, value in expect_raw.items():
168
+ if value is not None:
169
+ expect[key] = value
170
+ _validate_expect(expect, f"{where} ({case_id})")
171
+
172
+ judge_raw = raw.get("judge")
173
+ judge: dict[str, dict[str, Any]] = {}
174
+ if judge_raw is not None:
175
+ if not isinstance(judge_raw, dict):
176
+ raise EvalConfigError(f"{where} ({case_id}): 'judge' must be an object")
177
+ for name, spec in judge_raw.items():
178
+ if spec is None:
179
+ spec = {}
180
+ elif isinstance(spec, int | float) and not isinstance(spec, bool):
181
+ spec = {"threshold": spec}
182
+ if not isinstance(spec, dict):
183
+ raise EvalConfigError(
184
+ f"{where} ({case_id}): judge.{name} must be an object like {{'threshold': 4}}"
185
+ )
186
+ threshold = spec.get("threshold")
187
+ if threshold is not None and (
188
+ isinstance(threshold, bool) or not isinstance(threshold, int | float)
189
+ ):
190
+ raise EvalConfigError(
191
+ f"{where} ({case_id}): judge.{name}.threshold must be a number"
192
+ )
193
+ judge[str(name)] = dict(spec)
194
+
195
+ for text_key in ("reference", "context"):
196
+ value = raw.get(text_key)
197
+ if value is not None and not isinstance(value, str):
198
+ raise EvalConfigError(f"{where} ({case_id}): '{text_key}' must be a string")
199
+
200
+ metadata = raw.get("metadata") or {}
201
+ if not isinstance(metadata, dict):
202
+ raise EvalConfigError(f"{where} ({case_id}): 'metadata' must be an object")
203
+
204
+ return EvalCase(
205
+ id=case_id,
206
+ messages=messages,
207
+ expect=expect,
208
+ judge=judge,
209
+ reference=raw.get("reference"),
210
+ context=raw.get("context"),
211
+ metadata=metadata,
212
+ raw=raw,
213
+ approvals=_parse_approval_instructions(raw.get("approvals"), f"{where} ({case_id})"),
214
+ )
215
+
216
+
217
+ def _match_error(match: Any, where: str) -> None:
218
+ problem = match_problem(match)
219
+ if problem:
220
+ raise EvalConfigError(f"{where}.match: {problem}")
221
+
222
+
223
+ def _parse_approval_instructions(value: Any, where: str) -> list[dict[str, Any]]:
224
+ """A case's ``approvals``: ``[{"decision": "approve"|"reject", "match": {...}}]``."""
225
+ if value is None:
226
+ return []
227
+ if not isinstance(value, list):
228
+ raise EvalConfigError(f"{where}: 'approvals' must be a list of {{decision, match}}")
229
+ instructions = []
230
+ for index, item in enumerate(value):
231
+ at = f"{where}: approvals[{index}]"
232
+ if not isinstance(item, dict):
233
+ raise EvalConfigError(f"{at} must be an object with decision and match")
234
+ unknown = sorted(set(item) - set(APPROVAL_INSTRUCTION_KEYS), key=str)
235
+ if unknown:
236
+ raise EvalConfigError(
237
+ f"{at}: unknown key(s) {', '.join(map(str, unknown))} "
238
+ f"(known: {', '.join(APPROVAL_INSTRUCTION_KEYS)})"
239
+ )
240
+ if item.get("decision") not in APPROVAL_DECISIONS:
241
+ raise EvalConfigError(f"{at}.decision must be one of {', '.join(APPROVAL_DECISIONS)}")
242
+ _match_error(item.get("match"), at)
243
+ instructions.append({"decision": item["decision"], "match": dict(item["match"])})
244
+ return instructions
245
+
246
+
247
+ def _validate_expect(expect: dict[str, Any], where: str) -> None:
248
+ for key in ("contains", "not_contains"):
249
+ value = expect[key]
250
+ if isinstance(value, str):
251
+ expect[key] = [value]
252
+ elif not isinstance(value, list) or not all(isinstance(v, str) for v in value):
253
+ raise EvalConfigError(f"{where}: expect.{key} must be a list of strings")
254
+ if expect["regex"] is not None and not isinstance(expect["regex"], str):
255
+ raise EvalConfigError(f"{where}: expect.regex must be a string")
256
+ if expect["json_schema"] is not None and not isinstance(expect["json_schema"], dict | bool):
257
+ raise EvalConfigError(f"{where}: expect.json_schema must be a JSON schema object")
258
+ tool_calls = expect["tool_calls"]
259
+ if tool_calls is not None:
260
+ if not isinstance(tool_calls, list):
261
+ raise EvalConfigError(f"{where}: expect.tool_calls must be a list")
262
+ for i, call in enumerate(tool_calls):
263
+ if isinstance(call, str):
264
+ tool_calls[i] = {"name": call}
265
+ continue
266
+ if not isinstance(call, dict) or not isinstance(call.get("name"), str):
267
+ raise EvalConfigError(
268
+ f"{where}: expect.tool_calls[{i}] must be {{'name': ..., 'args_subset': {{...}}}}"
269
+ )
270
+ if call.get("args_subset") is not None and not isinstance(call["args_subset"], dict):
271
+ raise EvalConfigError(
272
+ f"{where}: expect.tool_calls[{i}].args_subset must be an object"
273
+ )
274
+ for key in ("ordered", "no_tool_calls", "case_insensitive"):
275
+ if not isinstance(expect[key], bool):
276
+ raise EvalConfigError(f"{where}: expect.{key} must be true or false")
277
+ if expect["scope"] not in EXPECT_SCOPES:
278
+ raise EvalConfigError(
279
+ f"{where}: expect.scope must be one of {', '.join(EXPECT_SCOPES)} "
280
+ f"(got {expect['scope']!r})"
281
+ )
282
+ for key in ("max_latency_ms", "max_tokens"):
283
+ value = expect[key]
284
+ if value is not None and (isinstance(value, bool) or not isinstance(value, int | float)):
285
+ raise EvalConfigError(f"{where}: expect.{key} must be a number")
286
+ if expect["no_tool_calls"] and expect["tool_calls"]:
287
+ raise EvalConfigError(f"{where}: expect.no_tool_calls and expect.tool_calls conflict")
288
+ if not isinstance(expect["no_approvals"], bool):
289
+ raise EvalConfigError(f"{where}: expect.no_approvals must be true or false")
290
+ approvals = expect["approvals"]
291
+ if approvals is not None:
292
+ if not isinstance(approvals, list):
293
+ raise EvalConfigError(f"{where}: expect.approvals must be a list of {{match, status}}")
294
+ if not approvals:
295
+ # An empty list would check nothing and always pass.
296
+ raise EvalConfigError(
297
+ f"{where}: expect.approvals is empty (it would check nothing); list the gated "
298
+ "calls, or use expect.no_approvals: true"
299
+ )
300
+ for i, item in enumerate(approvals):
301
+ at = f"{where}: expect.approvals[{i}]"
302
+ if not isinstance(item, dict):
303
+ raise EvalConfigError(f"{at} must be an object with match (and status)")
304
+ unknown = sorted(set(item) - set(APPROVAL_EXPECT_KEYS), key=str)
305
+ if unknown:
306
+ raise EvalConfigError(
307
+ f"{at}: unknown key(s) {', '.join(map(str, unknown))} "
308
+ f"(known: {', '.join(APPROVAL_EXPECT_KEYS)})"
309
+ )
310
+ if item.get("status", "gated") not in APPROVAL_OUTCOMES:
311
+ raise EvalConfigError(f"{at}.status must be one of {', '.join(APPROVAL_OUTCOMES)}")
312
+ _match_error(item.get("match"), at)
313
+ if expect["no_approvals"] and expect["approvals"]:
314
+ raise EvalConfigError(f"{where}: expect.no_approvals and expect.approvals conflict")
315
+
316
+
317
+ def dataset_hash(raw_cases: list[dict[str, Any]]) -> str:
318
+ """The dataset hash recorded in traces and results: over the canonical cases list."""
319
+ return canonical_hash({"cases": raw_cases})
320
+
321
+
322
+ def load_dataset(paths: list[Path]) -> Dataset:
323
+ """Load and merge one or more dataset files; ids must be unique across them."""
324
+ if not paths:
325
+ raise EvalConfigError("no dataset files given")
326
+ cases: list[EvalCase] = []
327
+ raw_cases: list[dict[str, Any]] = []
328
+ seen: dict[str, Path] = {}
329
+ for path in paths:
330
+ data = load_json_file(path, "dataset")
331
+ if not isinstance(data, dict) or not isinstance(data.get("cases"), list):
332
+ raise EvalConfigError(f"dataset {path} must be an object with a 'cases' list")
333
+ if not data["cases"]:
334
+ raise EvalConfigError(f"dataset {path} has no cases")
335
+ for index, raw in enumerate(data["cases"]):
336
+ case = parse_case(raw, index, path)
337
+ if case.id in seen:
338
+ raise EvalConfigError(
339
+ f"duplicate case id {case.id!r} in {path} (first seen in {seen[case.id]})"
340
+ )
341
+ seen[case.id] = path
342
+ cases.append(case)
343
+ raw_cases.append(raw)
344
+ return Dataset(cases=cases, hash=dataset_hash(raw_cases), sources=list(paths))
345
+
346
+
347
+ def cases_from_raw(raw_cases: list[dict[str, Any]]) -> Dataset:
348
+ """Build a :class:`Dataset` from case dicts embedded in a trace file."""
349
+ cases = [parse_case(raw, i) for i, raw in enumerate(raw_cases)]
350
+ return Dataset(cases=cases, hash=dataset_hash(raw_cases))