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.
- graph_agents_cli/__init__.py +26 -0
- graph_agents_cli/_api_policy.py +2145 -0
- graph_agents_cli/_approvals.py +400 -0
- graph_agents_cli/_build.py +186 -0
- graph_agents_cli/_build_info.json +7 -0
- graph_agents_cli/_chat_client.py +462 -0
- graph_agents_cli/_click.py +157 -0
- graph_agents_cli/_defaults.py +139 -0
- graph_agents_cli/_experiments.py +64 -0
- graph_agents_cli/_http.py +192 -0
- graph_agents_cli/_output.py +83 -0
- graph_agents_cli/_project.py +462 -0
- graph_agents_cli/_remote.py +220 -0
- graph_agents_cli/_response_schema.py +264 -0
- graph_agents_cli/_runner.py +319 -0
- graph_agents_cli/_skills_check.py +274 -0
- graph_agents_cli/_tools.py +189 -0
- graph_agents_cli/_trust.py +66 -0
- graph_agents_cli/api/__init__.py +15 -0
- graph_agents_cli/api/_changes.py +506 -0
- graph_agents_cli/api/_files.py +658 -0
- graph_agents_cli/api/cmd_api.py +2480 -0
- graph_agents_cli/deploy/__init__.py +15 -0
- graph_agents_cli/deploy/_config.py +171 -0
- graph_agents_cli/deploy/_image.py +128 -0
- graph_agents_cli/deploy/_kube.py +286 -0
- graph_agents_cli/deploy/_modes.py +234 -0
- graph_agents_cli/deploy/_preflight.py +370 -0
- graph_agents_cli/deploy/_values.py +168 -0
- graph_agents_cli/deploy/cmd_deploy.py +1866 -0
- graph_agents_cli/deploy/gitops.py +562 -0
- graph_agents_cli/deploy/local_load.py +273 -0
- graph_agents_cli/dev/__init__.py +13 -0
- graph_agents_cli/dev/cmd_build.py +131 -0
- graph_agents_cli/dev/cmd_install.py +78 -0
- graph_agents_cli/dev/cmd_lint.py +119 -0
- graph_agents_cli/dev/cmd_playground.py +297 -0
- graph_agents_cli/dev/policy_check.py +1287 -0
- graph_agents_cli/eval/__init__.py +22 -0
- graph_agents_cli/eval/_client.py +670 -0
- graph_agents_cli/eval/_common.py +177 -0
- graph_agents_cli/eval/_judge.py +168 -0
- graph_agents_cli/eval/_judge_runner.py +238 -0
- graph_agents_cli/eval/_paths.py +212 -0
- graph_agents_cli/eval/checks.py +581 -0
- graph_agents_cli/eval/cmd_analyze.py +278 -0
- graph_agents_cli/eval/cmd_compare.py +284 -0
- graph_agents_cli/eval/cmd_eval_group.py +80 -0
- graph_agents_cli/eval/cmd_generate.py +558 -0
- graph_agents_cli/eval/cmd_grade.py +466 -0
- graph_agents_cli/eval/cmd_metric.py +156 -0
- graph_agents_cli/eval/cmd_run.py +370 -0
- graph_agents_cli/eval/cmd_submit.py +400 -0
- graph_agents_cli/eval/config.py +435 -0
- graph_agents_cli/eval/dataset.py +350 -0
- graph_agents_cli/eval/gate.py +420 -0
- graph_agents_cli/eval/transcript.py +192 -0
- graph_agents_cli/extension/__init__.py +13 -0
- graph_agents_cli/extension/_compat.py +86 -0
- graph_agents_cli/extension/_loader.py +293 -0
- graph_agents_cli/extension/_manifest.py +135 -0
- graph_agents_cli/extension/_overrides.py +195 -0
- graph_agents_cli/extension/_paths.py +91 -0
- graph_agents_cli/extension/_refs.py +193 -0
- graph_agents_cli/extension/_resolver.py +453 -0
- graph_agents_cli/extension/_schema.py +106 -0
- graph_agents_cli/extension/_spec.py +253 -0
- graph_agents_cli/extension/_sync.py +102 -0
- graph_agents_cli/extension/_trust.py +58 -0
- graph_agents_cli/extension/cmd_extension_add.py +259 -0
- graph_agents_cli/extension/cmd_extension_group.py +57 -0
- graph_agents_cli/extension/cmd_extension_list.py +56 -0
- graph_agents_cli/extension/cmd_extension_remove.py +61 -0
- graph_agents_cli/extension/cmd_extension_update.py +195 -0
- graph_agents_cli/info/__init__.py +13 -0
- graph_agents_cli/info/cmd_info.py +222 -0
- graph_agents_cli/infra/__init__.py +15 -0
- graph_agents_cli/infra/checks.py +1169 -0
- graph_agents_cli/infra/cmd_infra.py +103 -0
- graph_agents_cli/main.py +591 -0
- graph_agents_cli/peer/__init__.py +15 -0
- graph_agents_cli/peer/_generate.py +254 -0
- graph_agents_cli/peer/cmd_peer.py +1151 -0
- graph_agents_cli/run/__init__.py +13 -0
- graph_agents_cli/run/_local_server.py +1157 -0
- graph_agents_cli/run/_signals.py +141 -0
- graph_agents_cli/run/cmd_approvals.py +530 -0
- graph_agents_cli/run/cmd_run.py +1421 -0
- graph_agents_cli/scaffold/__init__.py +19 -0
- graph_agents_cli/scaffold/agents/README.md +24 -0
- graph_agents_cli/scaffold/agents/empty_py/.template/templateconfig.yaml +22 -0
- graph_agents_cli/scaffold/agents/langgraph/.env.example +292 -0
- graph_agents_cli/scaffold/agents/langgraph/.template/templateconfig.yaml +28 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile +59 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile.langgraph-server +59 -0
- graph_agents_cli/scaffold/agents/langgraph/README.md +571 -0
- graph_agents_cli/scaffold/agents/langgraph/api-policy.yaml +60 -0
- graph_agents_cli/scaffold/agents/langgraph/app/__init__.py +20 -0
- graph_agents_cli/scaffold/agents/langgraph/app/agent.py +174 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/__init__.py +15 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a.py +2162 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a_client.py +1167 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/api_client.py +4220 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/approvals.py +1349 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/auth.py +1986 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/chat.py +2962 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/checkpointer.py +432 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/content.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/db.py +580 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/limits.py +203 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/metrics.py +231 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/middleware.py +361 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/model.py +611 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/playground.py +230 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/run_locks.py +459 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/structured.py +755 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/telemetry.py +681 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/threads.py +493 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/token_exchange.py +959 -0
- graph_agents_cli/scaffold/agents/langgraph/app/fast_api_app.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/__init__.py +55 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/custom.py +97 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/__init__.py +46 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/example_api.py +92 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/weather.py +33 -0
- graph_agents_cli/scaffold/agents/langgraph/langgraph.json +14 -0
- graph_agents_cli/scaffold/agents/langgraph/pyproject.toml +78 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/conftest.py +376 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/datasets/basic-dataset.json +53 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/eval_config.yaml +32 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/approval_graph.py +137 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_issuer.py +216 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_openai.py +357 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_outcomes.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_relay.py +479 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_api_surface.py +812 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals.py +1367 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals_server.py +794 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor.py +497 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor_server.py +247 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_history_repair.py +278 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_model_apis.py +242 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_postgres.py +637 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_resilience_postgres.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_runtime_guardrails.py +854 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_e2e.py +340 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_runtime.py +989 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_answers.py +584 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_server.py +222 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_token_exchange_issuer.py +650 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/.results/.placeholder +0 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/README.md +22 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/conftest.py +21 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/load_test.py +81 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_client.py +824 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_scoping.py +724 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client.py +1214 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client_hardening.py +716 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_policy_rpc.py +767 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_approval_ledger.py +1536 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_fake_model.py +115 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_jwt_policy.py +991 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_limits.py +310 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging.py +148 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging_hardening.py +271 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_policy.py +378 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_resilience.py +610 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_server_auth.py +702 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_structured.py +673 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_telemetry.py +404 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_thread_listing.py +255 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_threads.py +268 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_token_exchange.py +1320 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_untrusted_content.py +393 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-fastapi.lock +2084 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-langgraph-server.lock +2106 -0
- graph_agents_cli/scaffold/agents/langgraph/{{cookiecutter.agent_guidance_filename}} +129 -0
- graph_agents_cli/scaffold/base_templates/_shared/graph-agents-cli-manifest.yaml +36 -0
- graph_agents_cli/scaffold/base_templates/python/.dockerignore +32 -0
- graph_agents_cli/scaffold/base_templates/python/.github/CODEOWNERS +30 -0
- graph_agents_cli/scaffold/base_templates/python/.github/agent.env +7 -0
- graph_agents_cli/scaffold/base_templates/python/.github/workflows/pr_checks.yaml +214 -0
- graph_agents_cli/scaffold/base_templates/python/.gitignore +209 -0
- graph_agents_cli/scaffold/base_templates/python/tests/unit/test_dummy.py +23 -0
- graph_agents_cli/scaffold/base_templates/python/{{cookiecutter.agent_guidance_filename}} +35 -0
- graph_agents_cli/scaffold/cmd_scaffold_group.py +49 -0
- graph_agents_cli/scaffold/commands/__init__.py +13 -0
- graph_agents_cli/scaffold/commands/create.py +1424 -0
- graph_agents_cli/scaffold/commands/enhance.py +1652 -0
- graph_agents_cli/scaffold/commands/upgrade.py +570 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/agent.env +12 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/promote-to-prod.yaml +371 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/staging.yaml +450 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-dev.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-prod.yaml +41 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-staging.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/.helmignore +14 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/Chart.yaml +21 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/examples/networkpolicy.yaml +103 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/NOTES.txt +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/_helpers.tpl +189 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/certificate.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/configmap.yaml +10 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/deployment.yaml +199 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/hpa.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/httproute.yaml +30 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/ingress.yaml +39 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/networkpolicy.yaml +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/pdb.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/postgresql-secret.yaml +37 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/service.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/serviceaccount.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/servicemonitor.yaml +42 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-dev.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-prod.yaml +45 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-staging.yaml +29 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values.yaml +396 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/tests/integration/test_chart.py +269 -0
- graph_agents_cli/scaffold/deployment_targets/none/README.md +5 -0
- graph_agents_cli/scaffold/deployment_targets/none/python/README.md +6 -0
- graph_agents_cli/scaffold/utils/__init__.py +13 -0
- graph_agents_cli/scaffold/utils/backup.py +212 -0
- graph_agents_cli/scaffold/utils/build_record.py +257 -0
- graph_agents_cli/scaffold/utils/cli_options.py +184 -0
- graph_agents_cli/scaffold/utils/fs.py +83 -0
- graph_agents_cli/scaffold/utils/generate_locks.py +214 -0
- graph_agents_cli/scaffold/utils/generation_metadata.py +88 -0
- graph_agents_cli/scaffold/utils/keyedit.py +768 -0
- graph_agents_cli/scaffold/utils/keymerge.py +537 -0
- graph_agents_cli/scaffold/utils/language.py +138 -0
- graph_agents_cli/scaffold/utils/lock_utils.py +94 -0
- graph_agents_cli/scaffold/utils/logging.py +77 -0
- graph_agents_cli/scaffold/utils/manifest.py +292 -0
- graph_agents_cli/scaffold/utils/merge.py +970 -0
- graph_agents_cli/scaffold/utils/merge3.py +216 -0
- graph_agents_cli/scaffold/utils/openapi_seed.py +199 -0
- graph_agents_cli/scaffold/utils/remote_template.py +376 -0
- graph_agents_cli/scaffold/utils/template.py +1352 -0
- graph_agents_cli/scaffold/utils/upgrade.py +894 -0
- graph_agents_cli/scaffold/utils/version.py +438 -0
- graph_agents_cli/secrets/__init__.py +15 -0
- graph_agents_cli/secrets/_apply.py +954 -0
- graph_agents_cli/secrets/_required.py +188 -0
- graph_agents_cli/secrets/cmd_secrets.py +211 -0
- graph_agents_cli/setup/__init__.py +13 -0
- graph_agents_cli/setup/_antigravity.py +221 -0
- graph_agents_cli/setup/cmd_auth.py +1030 -0
- graph_agents_cli/setup/cmd_dev_token.py +513 -0
- graph_agents_cli/setup/cmd_setup.py +428 -0
- graph_agents_cli/setup/cmd_update.py +140 -0
- graph_agents_cli/skills/__init__.py +13 -0
- graph_agents_cli/skills/_bundle.py +65 -0
- graph_agents_cli/skills/data/README.md +19 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/SKILL.md +357 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/github-settings.md +113 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/gitops.md +137 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/kubernetes.md +315 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/secrets.md +160 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/SKILL.md +303 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/dataset_schema.md +282 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/metrics-guide.md +143 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/SKILL.md +659 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langchain-models.md +124 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langgraph.md +235 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/template-contract.md +477 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/SKILL.md +231 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/langsmith.md +46 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/otel.md +59 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/SKILL.md +414 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/references/flags.md +134 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/SKILL.md +478 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/brainstorming.md +118 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/commands.md +419 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/extension.md +156 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/internals.md +67 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/spec-template.md +56 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/terminology.md +119 -0
- graph_agents_cli/system/__init__.py +15 -0
- graph_agents_cli/system/_apply.py +519 -0
- graph_agents_cli/system/_checks.py +1023 -0
- graph_agents_cli/system/_deploy.py +215 -0
- graph_agents_cli/system/_model.py +363 -0
- graph_agents_cli/system/_system.py +664 -0
- graph_agents_cli/system/_views.py +208 -0
- graph_agents_cli/system/cmd_system.py +423 -0
- graph_agents_cli-0.3.1.dist-info/METADATA +162 -0
- graph_agents_cli-0.3.1.dist-info/RECORD +291 -0
- graph_agents_cli-0.3.1.dist-info/WHEEL +4 -0
- graph_agents_cli-0.3.1.dist-info/entry_points.txt +2 -0
- graph_agents_cli-0.3.1.dist-info/licenses/LICENSE +201 -0
- graph_agents_cli-0.3.1.dist-info/licenses/NOTICE +19 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
# Modifications Copyright 2026 graph-agents-cli contributors
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Bundled uv lock files for the ``langgraph`` template (one per runtime).
|
|
17
|
+
|
|
18
|
+
The template ships one lock per runtime, ``uv-fastapi.lock`` and
|
|
19
|
+
``uv-langgraph-server.lock``; ``create`` renames the matching one to
|
|
20
|
+
``uv.lock``. ``generate_locks.py`` regenerates them from the template's
|
|
21
|
+
``pyproject.toml``.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import pathlib
|
|
27
|
+
|
|
28
|
+
from jinja2 import Environment, StrictUndefined
|
|
29
|
+
|
|
30
|
+
from graph_agents_cli._defaults import RUNTIMES
|
|
31
|
+
|
|
32
|
+
LANGGRAPH_TEMPLATE_NAME = "langgraph"
|
|
33
|
+
|
|
34
|
+
# Project name used while resolving; replaced by the cookiecutter placeholder
|
|
35
|
+
# in the committed lock, which `create` fills with the real project name.
|
|
36
|
+
LOCK_PROJECT_NAME = "locked-template"
|
|
37
|
+
LOCK_PROJECT_PLACEHOLDER = "{{cookiecutter.project_name}}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _scaffold_root() -> pathlib.Path:
|
|
41
|
+
"""Return the root of the scaffold package directory."""
|
|
42
|
+
return pathlib.Path(__file__).resolve().parent.parent
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def langgraph_template_dir() -> pathlib.Path:
|
|
46
|
+
"""The bundled ``agents/langgraph`` template directory."""
|
|
47
|
+
return _scaffold_root() / "agents" / LANGGRAPH_TEMPLATE_NAME
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def lock_filename(runtime: str) -> str:
|
|
51
|
+
"""The bundled lock name for ``runtime``: ``uv-<runtime>.lock``."""
|
|
52
|
+
if runtime not in RUNTIMES:
|
|
53
|
+
raise ValueError(f"Unknown runtime '{runtime}'. Expected one of: {', '.join(RUNTIMES)}")
|
|
54
|
+
return f"uv-{runtime}.lock"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
LOCK_FILENAMES: dict[str, str] = {runtime: lock_filename(runtime) for runtime in RUNTIMES}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def render_pyproject(
|
|
61
|
+
template_path: pathlib.Path,
|
|
62
|
+
runtime: str,
|
|
63
|
+
*,
|
|
64
|
+
project_name: str = LOCK_PROJECT_NAME,
|
|
65
|
+
**overrides: object,
|
|
66
|
+
) -> str:
|
|
67
|
+
"""Render the template's ``pyproject.toml`` for ``runtime``.
|
|
68
|
+
|
|
69
|
+
Uses the same variables ``create`` passes to cookiecutter, with placeholder values, so the resolved lock matches a
|
|
70
|
+
rendered project. ``overrides`` replace individual variables.
|
|
71
|
+
"""
|
|
72
|
+
from .template import build_cookiecutter_context
|
|
73
|
+
|
|
74
|
+
context = build_cookiecutter_context(
|
|
75
|
+
project_name=project_name,
|
|
76
|
+
agent_name=LANGGRAPH_TEMPLATE_NAME,
|
|
77
|
+
runtime=runtime,
|
|
78
|
+
deployment_target="kubernetes",
|
|
79
|
+
template_config={"settings": {"agent_directory": "app", "tags": ["langgraph"]}},
|
|
80
|
+
)
|
|
81
|
+
# cookiecutter wraps list variables as single-element choices; unwrap for jinja.
|
|
82
|
+
for key, value in list(context.items()):
|
|
83
|
+
if isinstance(value, list) and len(value) == 1 and isinstance(value[0], list):
|
|
84
|
+
context[key] = value[0]
|
|
85
|
+
context.update(overrides)
|
|
86
|
+
|
|
87
|
+
env = Environment(undefined=StrictUndefined, keep_trailing_newline=True, autoescape=False)
|
|
88
|
+
template = env.from_string(template_path.read_text(encoding="utf-8"))
|
|
89
|
+
return template.render(cookiecutter=context)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def replace_lock_project_name(lock_text: str, project_name: str) -> str:
|
|
93
|
+
"""Fill the project-name placeholder of a bundled lock for a rendered project."""
|
|
94
|
+
return lock_text.replace(LOCK_PROJECT_PLACEHOLDER, project_name)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
# Modifications Copyright 2026 graph-agents-cli contributors
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Welcome banner for the scaffold commands."""
|
|
17
|
+
|
|
18
|
+
import random
|
|
19
|
+
|
|
20
|
+
from graph_agents_cli._output import Console
|
|
21
|
+
|
|
22
|
+
console = Console()
|
|
23
|
+
|
|
24
|
+
MOTTOS = [
|
|
25
|
+
"Your agents are cleared for takeoff.",
|
|
26
|
+
"Launching agents into production, one deploy at a time.",
|
|
27
|
+
"Houston, we have an agent.",
|
|
28
|
+
"To production... and beyond!",
|
|
29
|
+
"One small step for code, one giant leap for agents.",
|
|
30
|
+
"Graphs in, agents out.",
|
|
31
|
+
"3... 2... 1... Agent deployed!",
|
|
32
|
+
"The sky is not the limit when you have agents.",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _get_version() -> str:
|
|
37
|
+
"""Get the package version, with fallback to 'dev'."""
|
|
38
|
+
from graph_agents_cli.scaffold.utils.version import UNKNOWN_VERSION, get_current_version
|
|
39
|
+
|
|
40
|
+
version = get_current_version()
|
|
41
|
+
return "dev" if version == UNKNOWN_VERSION else version
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def display_welcome_banner(
|
|
45
|
+
*,
|
|
46
|
+
agent: str | None = None,
|
|
47
|
+
enhance_mode: bool = False,
|
|
48
|
+
upgrade_mode: bool = False,
|
|
49
|
+
quiet: bool = False,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Display the graph-agents-cli welcome banner.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
agent: Optional agent specification (unused in the text, kept for callers).
|
|
55
|
+
enhance_mode: Whether this is for enhancement mode.
|
|
56
|
+
upgrade_mode: Whether this is for an upgrade.
|
|
57
|
+
quiet: If True, print only the version line (auto-approve/programmatic mode).
|
|
58
|
+
"""
|
|
59
|
+
version = _get_version()
|
|
60
|
+
motto = random.choice(MOTTOS)
|
|
61
|
+
|
|
62
|
+
if quiet:
|
|
63
|
+
console.print(f"[bold blue]graph-agents-cli[/] [dim]v{version}[/]")
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
if enhance_mode:
|
|
67
|
+
line1 = "Enhancing your project with deployment and delivery scaffolding."
|
|
68
|
+
elif upgrade_mode:
|
|
69
|
+
line1 = "Upgrading your project to the current templates."
|
|
70
|
+
else:
|
|
71
|
+
line1 = "Create LangGraph agents that run on your Kubernetes cluster."
|
|
72
|
+
|
|
73
|
+
console.print()
|
|
74
|
+
console.print(f"[bold blue]graph-agents-cli[/] [dim]v{version}[/]")
|
|
75
|
+
console.print(f'[italic dim]"{motto}"[/]')
|
|
76
|
+
console.print(f"[dim]{line1}[/]")
|
|
77
|
+
console.print()
|
|
@@ -0,0 +1,292 @@
|
|
|
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
|
+
"""Post-render reconciliation of the generated project manifest.
|
|
16
|
+
|
|
17
|
+
The ``_shared`` layer renders ``graph-agents-cli-manifest.yaml`` from the
|
|
18
|
+
cookiecutter variables. ``finalize_manifest`` then guarantees the contract
|
|
19
|
+
whatever the template rendered: every create parameter is recorded, the
|
|
20
|
+
``environments`` block exists only for the kubernetes target, ``secrets.keys``
|
|
21
|
+
is never empty (and carries the ``token_env`` of every ``auth: bearer`` API in
|
|
22
|
+
``api-policy.yaml``, and ``TOKEN_EXCHANGE_CLIENT_SECRET`` when an API uses
|
|
23
|
+
``auth: exchange``), ``api_policy`` is present only with a policy file, and
|
|
24
|
+
``process`` is always a key. Values the template already rendered correctly
|
|
25
|
+
are left alone; the file is rewritten only when something had to change.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import logging
|
|
31
|
+
import pathlib
|
|
32
|
+
from dataclasses import dataclass
|
|
33
|
+
from typing import Any
|
|
34
|
+
|
|
35
|
+
import yaml
|
|
36
|
+
|
|
37
|
+
from graph_agents_cli._api_policy import (
|
|
38
|
+
POLICY_FILENAME as API_POLICY_FILENAME,
|
|
39
|
+
)
|
|
40
|
+
from graph_agents_cli._api_policy import (
|
|
41
|
+
ApiSummary,
|
|
42
|
+
ExampleCall,
|
|
43
|
+
secret_envs,
|
|
44
|
+
)
|
|
45
|
+
from graph_agents_cli._defaults import (
|
|
46
|
+
ENVIRONMENTS,
|
|
47
|
+
auth_policy_implemented_default,
|
|
48
|
+
default_secret_keys,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
MANIFEST_FILENAME = "graph-agents-cli-manifest.yaml"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True)
|
|
55
|
+
class CreateParams:
|
|
56
|
+
"""The resolved create parameters recorded in the manifest."""
|
|
57
|
+
|
|
58
|
+
deployment_target: str
|
|
59
|
+
runtime: str
|
|
60
|
+
model_provider: str
|
|
61
|
+
model: str
|
|
62
|
+
checkpointer: str
|
|
63
|
+
registry: str
|
|
64
|
+
cd: str
|
|
65
|
+
auth_policy: str
|
|
66
|
+
has_api_policy: bool = False
|
|
67
|
+
process: str | None = None
|
|
68
|
+
# ``None`` derives the flag from ``auth_policy`` (a fresh scaffold). A recorded
|
|
69
|
+
# value is carried through by ``enhance``/``upgrade`` so the developer's flip
|
|
70
|
+
# after implementing the ``custom`` stub survives a re-render.
|
|
71
|
+
auth_policy_implemented: bool | None = None
|
|
72
|
+
# The APIs declared in ``api-policy.yaml`` (empty without a policy): the
|
|
73
|
+
# templates document their variables and every ``auth: bearer`` API's
|
|
74
|
+
# ``token_env`` (and, for ``auth: exchange``, TOKEN_EXCHANGE_CLIENT_SECRET) joins
|
|
75
|
+
# ``secrets.keys`` so the secret reaches the Secret.
|
|
76
|
+
apis: tuple[ApiSummary, ...] = ()
|
|
77
|
+
# The call the rendered example tool makes (the first operation the policy's
|
|
78
|
+
# first API allows, any method), chosen so lint and the project's policy test
|
|
79
|
+
# accept it; None when that API allows none the example can make (the example
|
|
80
|
+
# is then not rendered).
|
|
81
|
+
example_call: ExampleCall | None = None
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def api_token_envs(self) -> list[str]:
|
|
85
|
+
return secret_envs(self.apis)
|
|
86
|
+
|
|
87
|
+
def resolved_auth_policy_implemented(self) -> bool:
|
|
88
|
+
if self.auth_policy_implemented is not None:
|
|
89
|
+
return bool(self.auth_policy_implemented)
|
|
90
|
+
return auth_policy_implemented_default(self.auth_policy)
|
|
91
|
+
|
|
92
|
+
def as_manifest_dict(self) -> dict[str, Any]:
|
|
93
|
+
"""The ``create_params`` keys this object owns (agent_guidance_filename excluded)."""
|
|
94
|
+
return {
|
|
95
|
+
"deployment_target": self.deployment_target,
|
|
96
|
+
"runtime": self.runtime,
|
|
97
|
+
"model_provider": self.model_provider,
|
|
98
|
+
"model": self.model,
|
|
99
|
+
"checkpointer": self.checkpointer,
|
|
100
|
+
"registry": self.registry,
|
|
101
|
+
"cd": self.cd,
|
|
102
|
+
"auth_policy": self.auth_policy,
|
|
103
|
+
"auth_policy_implemented": self.resolved_auth_policy_implemented(),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def recompute_secret_keys(
|
|
108
|
+
recorded: list[str], old_defaults: list[str], new_defaults: list[str]
|
|
109
|
+
) -> list[str]:
|
|
110
|
+
"""The ``secrets.keys`` allow-list after a provider or runtime change.
|
|
111
|
+
|
|
112
|
+
Template-managed keys follow the new defaults, in their order (so an
|
|
113
|
+
untouched list ends up exactly as a fresh ``create`` writes it): a default
|
|
114
|
+
of the old settings the new ones drop goes, a new default comes in. Keys
|
|
115
|
+
the developer added are kept, after the defaults, and a default the
|
|
116
|
+
developer deliberately removed stays removed while it remains a default.
|
|
117
|
+
"""
|
|
118
|
+
managed = [k for k in new_defaults if k not in old_defaults or k in recorded]
|
|
119
|
+
added_by_user = [k for k in recorded if k not in old_defaults and k not in new_defaults]
|
|
120
|
+
result: list[str] = []
|
|
121
|
+
for key in [*managed, *added_by_user]:
|
|
122
|
+
if key not in result:
|
|
123
|
+
result.append(key)
|
|
124
|
+
return result
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def reconcile_secret_keys(
|
|
128
|
+
project_dir: pathlib.Path, *, previous: CreateParams, current: CreateParams
|
|
129
|
+
) -> tuple[list[str], list[str]]:
|
|
130
|
+
"""Rewrite the manifest's ``secrets.keys`` for ``current``; return ``(added, removed)``.
|
|
131
|
+
|
|
132
|
+
``previous`` holds the settings the recorded list was derived from. Nothing
|
|
133
|
+
is written when the list does not change or the manifest cannot be read.
|
|
134
|
+
"""
|
|
135
|
+
manifest_path = project_dir / MANIFEST_FILENAME
|
|
136
|
+
try:
|
|
137
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
138
|
+
data = yaml.safe_load(f) or {}
|
|
139
|
+
except (OSError, yaml.YAMLError) as e:
|
|
140
|
+
logging.warning("Could not read %s: %s", manifest_path, e)
|
|
141
|
+
return [], []
|
|
142
|
+
if not isinstance(data, dict):
|
|
143
|
+
return [], []
|
|
144
|
+
secrets = data.get("secrets")
|
|
145
|
+
if not isinstance(secrets, dict):
|
|
146
|
+
secrets = {}
|
|
147
|
+
data["secrets"] = secrets
|
|
148
|
+
raw_keys = secrets.get("keys")
|
|
149
|
+
if isinstance(raw_keys, str):
|
|
150
|
+
raw_keys = [raw_keys]
|
|
151
|
+
recorded = [str(k) for k in raw_keys] if raw_keys else []
|
|
152
|
+
old_defaults = default_secret_keys(
|
|
153
|
+
previous.model_provider,
|
|
154
|
+
previous.runtime,
|
|
155
|
+
previous.api_token_envs,
|
|
156
|
+
auth_policy=previous.auth_policy,
|
|
157
|
+
)
|
|
158
|
+
new_defaults = default_secret_keys(
|
|
159
|
+
current.model_provider,
|
|
160
|
+
current.runtime,
|
|
161
|
+
current.api_token_envs,
|
|
162
|
+
auth_policy=current.auth_policy,
|
|
163
|
+
)
|
|
164
|
+
keys = recompute_secret_keys(recorded or old_defaults, old_defaults, new_defaults)
|
|
165
|
+
if keys == recorded:
|
|
166
|
+
return [], []
|
|
167
|
+
secrets["keys"] = keys
|
|
168
|
+
with open(manifest_path, "w", encoding="utf-8") as f:
|
|
169
|
+
yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False)
|
|
170
|
+
return [k for k in keys if k not in recorded], [k for k in recorded if k not in keys]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def default_environments(project_name: str) -> dict[str, dict[str, str]]:
|
|
174
|
+
"""dev/staging/prod with namespace ``<name>-<env>`` and an empty context."""
|
|
175
|
+
return {env: {"context": "", "namespace": f"{project_name}-{env}"} for env in ENVIRONMENTS}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def finalize_manifest(
|
|
179
|
+
project_dir: pathlib.Path,
|
|
180
|
+
*,
|
|
181
|
+
project_name: str,
|
|
182
|
+
params: CreateParams,
|
|
183
|
+
cli_version: str | None = None,
|
|
184
|
+
) -> bool:
|
|
185
|
+
"""Reconcile the rendered manifest with the contract; return True if it was rewritten."""
|
|
186
|
+
manifest_path = project_dir / MANIFEST_FILENAME
|
|
187
|
+
if not manifest_path.exists():
|
|
188
|
+
logging.warning("No %s was rendered in %s", MANIFEST_FILENAME, project_dir)
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
193
|
+
data = yaml.safe_load(f) or {}
|
|
194
|
+
except Exception as e:
|
|
195
|
+
logging.warning("Could not read %s: %s", manifest_path, e)
|
|
196
|
+
return False
|
|
197
|
+
if not isinstance(data, dict):
|
|
198
|
+
logging.warning("%s is not a mapping; leaving it alone", manifest_path)
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
changed = False
|
|
202
|
+
|
|
203
|
+
if data.get("name") != project_name:
|
|
204
|
+
data["name"] = project_name
|
|
205
|
+
changed = True
|
|
206
|
+
if cli_version and data.get("cli_version") != cli_version:
|
|
207
|
+
data["cli_version"] = cli_version
|
|
208
|
+
changed = True
|
|
209
|
+
|
|
210
|
+
create_params = data.get("create_params")
|
|
211
|
+
if not isinstance(create_params, dict):
|
|
212
|
+
create_params = {}
|
|
213
|
+
data["create_params"] = create_params
|
|
214
|
+
changed = True
|
|
215
|
+
for key, value in params.as_manifest_dict().items():
|
|
216
|
+
if create_params.get(key) != value:
|
|
217
|
+
if key == "auth_policy_implemented" and key in create_params:
|
|
218
|
+
logging.info(
|
|
219
|
+
"%s: auth_policy_implemented %r -> %r",
|
|
220
|
+
manifest_path,
|
|
221
|
+
create_params.get(key),
|
|
222
|
+
value,
|
|
223
|
+
)
|
|
224
|
+
create_params[key] = value
|
|
225
|
+
changed = True
|
|
226
|
+
|
|
227
|
+
if params.deployment_target == "kubernetes":
|
|
228
|
+
environments = data.get("environments")
|
|
229
|
+
if not isinstance(environments, dict):
|
|
230
|
+
environments = {}
|
|
231
|
+
merged = dict(environments)
|
|
232
|
+
for env, defaults in default_environments(project_name).items():
|
|
233
|
+
recorded = merged.get(env)
|
|
234
|
+
if not isinstance(recorded, dict):
|
|
235
|
+
merged[env] = dict(defaults)
|
|
236
|
+
else:
|
|
237
|
+
merged[env] = {
|
|
238
|
+
"context": recorded.get("context") or "",
|
|
239
|
+
"namespace": recorded.get("namespace") or defaults["namespace"],
|
|
240
|
+
}
|
|
241
|
+
if merged != environments:
|
|
242
|
+
data["environments"] = merged
|
|
243
|
+
changed = True
|
|
244
|
+
elif "environments" in data:
|
|
245
|
+
del data["environments"]
|
|
246
|
+
changed = True
|
|
247
|
+
|
|
248
|
+
secrets = data.get("secrets")
|
|
249
|
+
if not isinstance(secrets, dict):
|
|
250
|
+
secrets = {}
|
|
251
|
+
data["secrets"] = secrets
|
|
252
|
+
changed = True
|
|
253
|
+
raw_keys = secrets.get("keys")
|
|
254
|
+
if isinstance(raw_keys, str):
|
|
255
|
+
raw_keys = [raw_keys]
|
|
256
|
+
keys = [str(k) for k in raw_keys] if raw_keys else []
|
|
257
|
+
if not keys:
|
|
258
|
+
keys = default_secret_keys(
|
|
259
|
+
params.model_provider,
|
|
260
|
+
params.runtime,
|
|
261
|
+
params.api_token_envs,
|
|
262
|
+
auth_policy=params.auth_policy,
|
|
263
|
+
)
|
|
264
|
+
else:
|
|
265
|
+
# Every bearer API needs its token in the Secret; user-added keys stay.
|
|
266
|
+
keys = [*keys, *(k for k in params.api_token_envs if k not in keys)]
|
|
267
|
+
if secrets.get("keys") != keys:
|
|
268
|
+
secrets["keys"] = keys
|
|
269
|
+
changed = True
|
|
270
|
+
if "owner" not in secrets or secrets.get("owner") is None:
|
|
271
|
+
secrets["owner"] = ""
|
|
272
|
+
changed = True
|
|
273
|
+
|
|
274
|
+
if params.has_api_policy:
|
|
275
|
+
api_policy = data.get("api_policy")
|
|
276
|
+
if not isinstance(api_policy, dict) or not api_policy.get("policy_file"):
|
|
277
|
+
data["api_policy"] = {"policy_file": API_POLICY_FILENAME}
|
|
278
|
+
changed = True
|
|
279
|
+
elif "api_policy" in data:
|
|
280
|
+
del data["api_policy"]
|
|
281
|
+
changed = True
|
|
282
|
+
|
|
283
|
+
process = params.process or None
|
|
284
|
+
if "process" not in data or data.get("process") != process:
|
|
285
|
+
data["process"] = process
|
|
286
|
+
changed = True
|
|
287
|
+
|
|
288
|
+
if changed:
|
|
289
|
+
with open(manifest_path, "w", encoding="utf-8") as f:
|
|
290
|
+
yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False)
|
|
291
|
+
logging.debug("Reconciled %s with the manifest contract", manifest_path)
|
|
292
|
+
return changed
|