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,268 @@
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
+ """Thread ownership (atomic claim, owner, read-across role, stranger), run locks, redaction."""
16
+
17
+ from __future__ import annotations
18
+
19
+ import ast
20
+ import asyncio
21
+ from pathlib import Path
22
+
23
+ import pytest
24
+ from fastapi import HTTPException
25
+ from langchain_core.messages import AIMessage
26
+
27
+ from {{cookiecutter.agent_directory}}.app_utils.auth import Actor, Principal
28
+ from {{cookiecutter.agent_directory}}.app_utils.chat import serialize_message
29
+ from {{cookiecutter.agent_directory}}.app_utils.db import Database
30
+ from {{cookiecutter.agent_directory}}.app_utils.threads import (
31
+ ThreadBusy,
32
+ ThreadLocks,
33
+ ThreadStore,
34
+ assert_access,
35
+ assert_owner,
36
+ can_access,
37
+ is_owner,
38
+ )
39
+
40
+ OWNER = Principal(id="a", roles=["viewer"])
41
+ STRANGER = Principal(id="b", roles=["viewer"])
42
+ AUDITOR = Principal(id="c", roles=["auditor"])
43
+
44
+
45
+ @pytest.fixture
46
+ def store(monkeypatch: pytest.MonkeyPatch) -> ThreadStore:
47
+ monkeypatch.setenv("AUTH_READ_ACROSS_ROLES", "auditor, ops")
48
+ return ThreadStore(Database("memory"))
49
+
50
+
51
+ async def test_owner_reads_and_continues_its_thread(store: ThreadStore) -> None:
52
+ record = await store.create("t1", OWNER)
53
+ assert is_owner(OWNER, record) and can_access(OWNER, record)
54
+ assert (await store.ensure("t1", OWNER)).principal_id == "a"
55
+ assert [r.thread_id for r in await store.list_for(OWNER)] == ["t1"]
56
+
57
+
58
+ async def test_stranger_is_refused_everywhere(store: ThreadStore) -> None:
59
+ record = await store.create("t1", OWNER)
60
+ assert not can_access(STRANGER, record)
61
+ for check in (assert_access, assert_owner):
62
+ with pytest.raises(HTTPException) as exc:
63
+ check(STRANGER, record)
64
+ assert exc.value.status_code == 403
65
+ with pytest.raises(HTTPException) as exc:
66
+ await store.ensure("t1", STRANGER)
67
+ assert exc.value.status_code == 403
68
+ assert await store.list_for(STRANGER) == []
69
+ # Creating a thread of its own is unchanged.
70
+ assert (await store.ensure("t2", STRANGER)).principal_id == "b"
71
+
72
+
73
+ async def test_read_across_role_reads_but_does_not_write(store: ThreadStore) -> None:
74
+ record = await store.create("t1", OWNER)
75
+ assert can_access(AUDITOR, record) and not is_owner(AUDITOR, record)
76
+ assert_access(AUDITOR, record) # reads are allowed
77
+ assert [r.thread_id for r in await store.list_for(AUDITOR)] == ["t1"]
78
+ with pytest.raises(HTTPException) as exc:
79
+ assert_owner(AUDITOR, record)
80
+ assert exc.value.status_code == 403
81
+ # chat.send (ensure) is a write: a read-across role may not continue another's thread.
82
+ with pytest.raises(HTTPException) as exc:
83
+ await store.ensure("t1", AUDITOR)
84
+ assert exc.value.status_code == 403
85
+
86
+
87
+ async def test_read_across_roles_default_to_none(monkeypatch: pytest.MonkeyPatch) -> None:
88
+ monkeypatch.delenv("AUTH_READ_ACROSS_ROLES", raising=False)
89
+ store = ThreadStore(Database("memory"))
90
+ record = await store.create("t1", OWNER)
91
+ assert not can_access(AUDITOR, record)
92
+
93
+
94
+ def test_serialize_message_omits_tool_args_when_asked() -> None:
95
+ message = AIMessage(
96
+ content="",
97
+ tool_calls=[{"id": "c1", "name": "probe", "args": {"query": "SF"}}],
98
+ )
99
+ with_args = serialize_message(message)
100
+ assert with_args["tool_calls"] == [{"id": "c1", "name": "probe", "args": {"query": "SF"}}]
101
+ without = serialize_message(message, include_tool_args=False)
102
+ assert without["tool_calls"] == [{"id": "c1", "name": "probe"}]
103
+ assert "args" not in without["tool_calls"][0]
104
+
105
+
106
+ async def test_claim_is_atomic_under_concurrency(store: ThreadStore) -> None:
107
+ """Two principals racing for one new id: exactly one owns it, the other is refused."""
108
+ results = await asyncio.gather(store.claim("race", OWNER), store.claim("race", STRANGER))
109
+ assert sorted(created for _, created in results) == [False, True]
110
+ owner = next(record for record, created in results if created).principal_id
111
+ loser = STRANGER if owner == OWNER.id else OWNER
112
+ with pytest.raises(HTTPException) as exc:
113
+ await store.ensure("race", loser)
114
+ assert exc.value.status_code == 403
115
+
116
+
117
+ async def test_continuing_a_thread_moves_its_idle_clock(store: ThreadStore) -> None:
118
+ record = await store.create("t1", OWNER)
119
+ store._memory["t1"].updated_at = "2000-01-01T00:00:00+00:00"
120
+ assert await store.idle_before("2001-01-01T00:00:00+00:00") == ["t1"]
121
+ await store.ensure("t1", OWNER)
122
+ assert await store.idle_before("2001-01-01T00:00:00+00:00") == []
123
+ # The owner is listed hashed, never as the raw principal id.
124
+ assert record.public().keys() == {"thread_id", "owner", "created_at", "updated_at"}
125
+ assert record.public()["owner"] == OWNER.hashed_id() != OWNER.id
126
+
127
+
128
+ async def test_list_is_most_recent_first_and_paged(store: ThreadStore) -> None:
129
+ for i in range(3):
130
+ await store.create(f"t{i}", OWNER)
131
+ store._memory[f"t{i}"].updated_at = f"2026-01-0{i + 1}T00:00:00+00:00"
132
+ assert [r.thread_id for r in await store.list_for(OWNER)] == ["t2", "t1", "t0"]
133
+ assert [r.thread_id for r in await store.list_for(OWNER, limit=1, offset=1)] == ["t1"]
134
+ assert await store.list_for(STRANGER) == []
135
+
136
+
137
+ async def test_one_run_per_thread() -> None:
138
+ locks = ThreadLocks()
139
+ lease = await locks.acquire("t1")
140
+ with pytest.raises(ThreadBusy):
141
+ await locks.acquire("t1")
142
+ other = await locks.acquire("t2") # other threads are independent
143
+ await lease.release()
144
+ await lease.release() # idempotent
145
+ again = await locks.acquire("t1")
146
+ assert locks.held == {"t1", "t2"}
147
+ await again.release()
148
+ await other.release()
149
+ assert locks.held == frozenset()
150
+
151
+
152
+ async def test_the_fence_admits_only_held_threads() -> None:
153
+ """In-process leases never expire; writes to a thread nobody here holds are refused."""
154
+ from {{cookiecutter.agent_directory}}.app_utils.threads import LeaseLost
155
+
156
+ locks = ThreadLocks()
157
+ lease = await locks.acquire("t1")
158
+ locks.fence("t1")
159
+ with pytest.raises(LeaseLost):
160
+ locks.fence("t2")
161
+ await lease.release()
162
+ with pytest.raises(LeaseLost):
163
+ locks.fence("t1")
164
+ with pytest.raises(LeaseLost):
165
+ lease.check()
166
+
167
+
168
+ # --- threads an agent started for its user (0.3) ------------------------------------------
169
+
170
+ ALICE = Principal(id="a", roles=["viewer"])
171
+ CONCIERGE = Principal(id="a", actor=Actor(id="concierge", chain=("concierge",)))
172
+ BILLING = Principal(id="a", actor=Actor(id="billing", chain=("billing",)))
173
+ BOBS_CONCIERGE = Principal(id="b", actor=Actor(id="concierge", chain=("concierge",)))
174
+
175
+
176
+ async def test_the_subject_owns_the_threads_its_agents_start(store: ThreadStore) -> None:
177
+ record = await store.create("t-agent", CONCIERGE)
178
+ assert record.actor == "concierge" and record.principal_id == "a"
179
+ # The person reads, continues and deletes it.
180
+ assert is_owner(ALICE, record) and can_access(ALICE, record)
181
+ assert (await store.ensure("t-agent", ALICE)).actor == "concierge"
182
+ assert [r.thread_id for r in await store.list_for(ALICE)] == ["t-agent"]
183
+
184
+
185
+ async def test_an_agent_reaches_only_its_own_threads_for_the_user(store: ThreadStore) -> None:
186
+ concierge_thread = await store.create("t-concierge", CONCIERGE)
187
+ direct_thread = await store.create("t-direct", ALICE)
188
+ assert is_owner(CONCIERGE, concierge_thread)
189
+ for stranger in (BILLING, BOBS_CONCIERGE):
190
+ assert not can_access(stranger, concierge_thread)
191
+ for check in (assert_access, assert_owner):
192
+ with pytest.raises(HTTPException) as exc:
193
+ check(stranger, concierge_thread)
194
+ assert exc.value.status_code == 403
195
+ assert exc.value.detail == "This thread belongs to another principal."
196
+ with pytest.raises(HTTPException):
197
+ await store.ensure("t-concierge", stranger)
198
+ # A direct thread (one a person started, or one from before 0.3) is no agent's.
199
+ assert not is_owner(CONCIERGE, direct_thread)
200
+ with pytest.raises(HTTPException):
201
+ await store.ensure("t-direct", CONCIERGE)
202
+ assert [r.thread_id for r in await store.list_for(CONCIERGE)] == ["t-concierge"]
203
+ assert await store.list_for(BILLING) == []
204
+
205
+
206
+ async def test_a_delegated_principals_roles_never_read_across(store: ThreadStore) -> None:
207
+ record = await store.create("t1", OWNER)
208
+ agent = Principal(id="c", roles=["auditor"], actor=Actor(id="concierge"))
209
+ assert not can_access(agent, record)
210
+ assert await store.list_for(agent) == []
211
+
212
+
213
+ def test_a_record_without_an_actor_reads_as_direct() -> None:
214
+ from {{cookiecutter.agent_directory}}.app_utils.threads import _record_from_row
215
+
216
+ legacy = _record_from_row({"thread_id": "t", "principal_id": "a", "tenant": None})
217
+ assert legacy.actor == "" and is_owner(ALICE, legacy) and not is_owner(CONCIERGE, legacy)
218
+
219
+
220
+ # Every place the template builds a `Principal`: (file, function, whether it passes `actor`).
221
+ # A site that rebuilds a principal without its actor turns an agent into the person it acts
222
+ # for, so a new site fails this test until it is reviewed and added here.
223
+ REVIEWED_PRINCIPAL_SITES = sorted(
224
+ [
225
+ # A2A: a task owner key's subject hashed to compare it with an approval's requester
226
+ # (the actor compared apart).
227
+ ("app_utils/a2a.py", "owner_is_requester", False),
228
+ ("app_utils/approvals.py", "resume_principal", True), # the requester's @actor
229
+ ("app_utils/auth.py", "authenticate", False), # shared-bearer: one direct principal
230
+ ("app_utils/auth.py", "finalize_principal", False), # direct: only @actor removed
231
+ ("app_utils/auth.py", "finalize_principal", True),
232
+ ("app_utils/auth.py", "on_threads_create_run", False), # hashes the subject only
233
+ ("app_utils/auth.py", "principal_from_claims", True), # jwt: act / azp
234
+ # The forwarded words added to (or taken from) a principal, its actor kept.
235
+ ("app_utils/auth.py", "with_origin", True),
236
+ ("app_utils/threads.py", "owner_hash", False), # hashes the subject only
237
+ ("app_utils/threads.py", "own_view", True),
238
+ ]
239
+ )
240
+
241
+
242
+ def _principal_sites(root: Path) -> list[tuple[str, str, bool]]:
243
+ sites: set[tuple[str, str, bool]] = set()
244
+ for path in sorted(root.rglob("*.py")):
245
+ tree = ast.parse(path.read_text(encoding="utf-8"))
246
+ # Each call's innermost function: `ast.walk` reaches an outer function first.
247
+ innermost: dict[int, tuple[str, ast.Call]] = {}
248
+ for function in ast.walk(tree):
249
+ if not isinstance(function, ast.FunctionDef | ast.AsyncFunctionDef):
250
+ continue
251
+ for node in ast.walk(function):
252
+ if (
253
+ isinstance(node, ast.Call)
254
+ and isinstance(node.func, ast.Name)
255
+ and node.func.id == "Principal"
256
+ ):
257
+ innermost[id(node)] = (function.name, node)
258
+ for name, node in innermost.values():
259
+ has_actor = any(k.arg == "actor" for k in node.keywords)
260
+ sites.add((path.relative_to(root).as_posix(), name, has_actor))
261
+ return sorted(sites)
262
+
263
+
264
+ def test_no_principal_reconstruction_drops_actor() -> None:
265
+ from {{cookiecutter.agent_directory}} import agent
266
+
267
+ root = Path(agent.__file__).parent
268
+ assert _principal_sites(root) == sorted(set(REVIEWED_PRINCIPAL_SITES))