agentnode-sdk 0.12.0__tar.gz → 0.13.0__tar.gz
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.
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/CHANGELOG.md +76 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/PKG-INFO +2 -1
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/__init__.py +1 -1
- agentnode_sdk-0.13.0/agentnode_sdk/cli/auth.py +243 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/main.py +8 -1
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/config.py +23 -1
- agentnode_sdk-0.13.0/agentnode_sdk/credential_store.py +296 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_runner.py +64 -1
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/pyproject.toml +2 -1
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/conftest.py +20 -0
- agentnode_sdk-0.13.0/tests/test_auth_cli_vault.py +221 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_cli.py +4 -1
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_config.py +99 -0
- agentnode_sdk-0.13.0/tests/test_credential_vault.py +217 -0
- agentnode_sdk-0.13.0/tests/test_llm_vault_binding.py +143 -0
- agentnode_sdk-0.12.0/agentnode_sdk/cli/auth.py +0 -113
- agentnode_sdk-0.12.0/agentnode_sdk/credential_store.py +0 -143
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/.env.example +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/.gitignore +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/README.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/REGISTRY_SIGNING_ACTIVATION.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/REGISTRY_SIGNING_SPEC.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/THREAT_MODEL.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/TRUST_STACK.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode.lock +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/_fileutil.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/async_client.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/capability_graph.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/capability_taxonomy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/__init__.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/__main__.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/audit.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/cassette_audit.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/commands.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/complements.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/init.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_commands.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_status.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_submit.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_verify.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/output.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/publish.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/record_cases.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/sandbox_commands.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/serve.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/setup_wizard.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/smart_run.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/templates.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/validate.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/verify_local.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/client.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/compatibility.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/credential_handle.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/credential_resolver.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/detect.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/exceptions.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/guard.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/input_guard.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/installer.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/key_status.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/lock_integrity.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/mcp_server.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/models.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/planner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/references.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/registry_trust.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/resolve.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/resource_provider.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/risk_profile.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/run_log.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtime.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/__init__.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_llm_broker.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_llm_policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_sandbox.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/mcp_runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/python_runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/remote_runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/__init__.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/agent_container_wrapper.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/agent_rpc.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/agent_session.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/backend.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/container_backend.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/types.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/signature.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/signing_key.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/skill.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/sandbox-image/Dockerfile +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/sandbox-image/README.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/analyze_scores.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/batch_verify.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/ci_smoke_test.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/generate_compatibility_artifacts.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/verify_toolcalls.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/weekly_retest.sh +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/README.md +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/__init__.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/container_agent_wrapper.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/fake_llm.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/host_driver.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/trivial_agent.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/__init__.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_llm_broker.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_llm_policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_rpc.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_sandbox_e2e.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_sandbox_routing.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_sandbox_spike.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_session_container.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_async_client.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_audit_ux.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_auto_upgrade_policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_cli_lock.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_cli_run_resolution.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_client.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_client_json_guard.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_client_sprint_b.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_handle.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_integration.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_resolver.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_store.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_detect.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_detect_and_install.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_e2e_runtime.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_edge_cases.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_check.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_config_cache.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_preview.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_schema.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_set.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_status.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_tool_override.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_tool_override_audit.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_tool_override_cli.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_ux.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_input_guard.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_input_guard_escalation.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_install_hardening.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_installer_sprint_b.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_intelligence.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_key_status.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_llm_binding.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_llm_call_runlog.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_lock_integrity.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_lock_runtime.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_audit.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_doctor.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_sandbox.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_server.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_observability.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_planner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_policy.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_policy_integration.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_prompt_specs.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_provider_matrix.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_publish.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_references.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_registry_trust.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_remote_hardening.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_remote_runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_resource_provider.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_resource_specs.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_risk_profile.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_run_log.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_runner.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_runtime.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_runtime_audit.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_backend.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_doctor.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_e2e.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_gate.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_security_hardening.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_signature.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_signing_key.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_skill.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_smart.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_stability.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_toolpack_sandbox.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_v02.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_validate.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_validate_skill.py +0 -0
- {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/validation_lockfile.json +0 -0
|
@@ -1,5 +1,81 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.0 — Credential vault for LLM providers
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **OS-keychain credential storage:** `agentnode auth set openai|anthropic|openrouter`
|
|
8
|
+
now stores the key in the OS keychain (Windows Credential Manager, macOS
|
|
9
|
+
Keychain, Linux Secret Service). `credentials.json` keeps only non-secret
|
|
10
|
+
metadata for keychain-backed entries. If no keychain is available (e.g.
|
|
11
|
+
headless Linux/CI), storage falls back to the plaintext file (0600) — and
|
|
12
|
+
says so honestly.
|
|
13
|
+
- **The LLM runtime now reads stored credentials:** `_auto_detect_llm` falls
|
|
14
|
+
back to the credential store when no env var is set — `agentnode auth set
|
|
15
|
+
openai` is finally picked up by host agents AND the sandboxed-agent LLM
|
|
16
|
+
broker (the key still never enters the sandbox container).
|
|
17
|
+
- `agentnode auth test <provider>` — validates the effective key via a free
|
|
18
|
+
provider endpoint (no completion call, no cost). Exit codes: 0 valid,
|
|
19
|
+
1 rejected, 2 not configured, 3 indeterminate (network errors are never
|
|
20
|
+
reported as "invalid").
|
|
21
|
+
- `agentnode auth set <provider> --from-env ENV_VAR` — import an existing
|
|
22
|
+
environment key into the store.
|
|
23
|
+
- `llm.default_provider` config key — which stored credential to try first
|
|
24
|
+
(`openai`, `anthropic`, `openrouter`). OpenRouter bindings pin the
|
|
25
|
+
namespaced default model (`openai/gpt-4o-mini`).
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `agentnode auth status` now leads with an LLM-provider section showing the
|
|
30
|
+
storage backend and the EFFECTIVE source per provider — including an
|
|
31
|
+
explicit "env var X — overrides stored credential" callout when an
|
|
32
|
+
environment variable shadows a stored key.
|
|
33
|
+
- `agentnode auth list` shows a storage column (OS keychain / plaintext file).
|
|
34
|
+
- Environment variables (and `~/.agentnode/.env`) always override stored
|
|
35
|
+
credentials — explicit/CI intent wins.
|
|
36
|
+
|
|
37
|
+
### Hardened
|
|
38
|
+
|
|
39
|
+
- Keys are never printed (masked last-4 only), never logged (provider/backend
|
|
40
|
+
errors are reported by type, never message), never echoed from provider
|
|
41
|
+
responses, and never enter the sandbox container, audit records, manifests,
|
|
42
|
+
or lockfiles. `auth test` never accepts a key as a CLI argument.
|
|
43
|
+
- Keychain access is probed once per process with a timeout — a locked or
|
|
44
|
+
hanging Secret Service degrades cleanly to file storage instead of blocking.
|
|
45
|
+
|
|
46
|
+
### Upgrade Notes
|
|
47
|
+
|
|
48
|
+
- New dependency: `keyring>=24` (pure Python, installed automatically).
|
|
49
|
+
- Honest scope of the OS keychain: it protects against other local users and
|
|
50
|
+
accidental file exposure; it does NOT protect against programs running as
|
|
51
|
+
the same user. The fallback is a plaintext file (0600) when no keychain is
|
|
52
|
+
available — neither mode is "encrypted at rest by AgentNode".
|
|
53
|
+
- Existing plaintext credentials keep working unchanged. Nothing migrates on
|
|
54
|
+
read; a credential moves into the keychain the next time you `auth set` it.
|
|
55
|
+
- No breaking changes.
|
|
56
|
+
|
|
57
|
+
## 0.12.1 — agent_sandbox config fix
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- **`agent_sandbox` config section was stripped during `load_config()`.** The
|
|
62
|
+
config loader rebuilt the file from defaults and silently dropped a
|
|
63
|
+
hand-written `agent_sandbox` section, so the documented
|
|
64
|
+
`agent_sandbox.enabled: true` config path never took effect (only the
|
|
65
|
+
`AGENTNODE_AGENT_SANDBOX` env var worked), and the host LLM ceiling
|
|
66
|
+
(`agent_sandbox.llm.*`) never reached policy resolution. Both now survive
|
|
67
|
+
loading; the nested `llm` ceiling is passed through verbatim.
|
|
68
|
+
- **`agentnode config set agent_sandbox.enabled true|false` now works** (the
|
|
69
|
+
key was missing from the allowed-keys whitelist) and stores a **real
|
|
70
|
+
boolean** — previously a stored string `"false"` would have been truthy,
|
|
71
|
+
i.e. read as enabled.
|
|
72
|
+
|
|
73
|
+
### Upgrade Notes
|
|
74
|
+
|
|
75
|
+
- No breaking changes. No behavior change unless you use the `agent_sandbox`
|
|
76
|
+
config path; the env var `AGENTNODE_AGENT_SANDBOX` behaves exactly as
|
|
77
|
+
before. The agent sandbox remains **default OFF**.
|
|
78
|
+
|
|
3
79
|
## 0.12.0 — Sandboxed community agents (flag-gated)
|
|
4
80
|
|
|
5
81
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentnode-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.0
|
|
4
4
|
Summary: Python SDK for AgentNode — the open upgrade and discovery infrastructure for AI agents.
|
|
5
5
|
Project-URL: Homepage, https://agentnode.net
|
|
6
6
|
Project-URL: Repository, https://github.com/agentnode-ai/agentnode
|
|
@@ -16,6 +16,7 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
17
|
Requires-Dist: cryptography>=41.0
|
|
18
18
|
Requires-Dist: httpx>=0.25
|
|
19
|
+
Requires-Dist: keyring>=24
|
|
19
20
|
Requires-Dist: mcp>=1.0.0
|
|
20
21
|
Requires-Dist: pyyaml>=6.0
|
|
21
22
|
Provides-Extra: dev
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""agentnode auth — credential management CLI.
|
|
2
|
+
|
|
3
|
+
Secrets are entered via getpass (never argv, never echoed) and only ever
|
|
4
|
+
shown masked (last 4 chars). Storage labels are honest: "OS keychain" or
|
|
5
|
+
"plaintext file" — never "encrypted"."""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import getpass
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from agentnode_sdk.credential_store import (
|
|
13
|
+
LLM_PROVIDER_ENV,
|
|
14
|
+
has_credential,
|
|
15
|
+
list_credentials,
|
|
16
|
+
load_credentials,
|
|
17
|
+
remove_credential,
|
|
18
|
+
set_credential,
|
|
19
|
+
)
|
|
20
|
+
from agentnode_sdk.installer import read_lockfile
|
|
21
|
+
from agentnode_sdk.cli.output import bold, dim, section
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _masked(token: str) -> str:
|
|
25
|
+
"""Only ever show the last 4 chars of a secret."""
|
|
26
|
+
return "..." + token[-4:] if len(token) >= 8 else "..."
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _storage_short(storage: str) -> str:
|
|
30
|
+
return "OS keychain" if storage == "keyring" else "plaintext file"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _llm_effective_source(provider: str) -> tuple[str | None, str]:
|
|
34
|
+
"""(effective key or None, human-readable source) for an LLM provider.
|
|
35
|
+
|
|
36
|
+
Mirrors the runtime's resolution: env (incl. ~/.agentnode/.env) overrides
|
|
37
|
+
the stored credential. Uses metadata only for the stored check here —
|
|
38
|
+
the real keychain read happens in ``auth test``."""
|
|
39
|
+
from agentnode_sdk.runtimes.agent_runner import _load_agentnode_env
|
|
40
|
+
_load_agentnode_env()
|
|
41
|
+
|
|
42
|
+
env_var = LLM_PROVIDER_ENV[provider]
|
|
43
|
+
env_key = os.environ.get(env_var) or None
|
|
44
|
+
meta = load_credentials().get("providers", {}).get(provider)
|
|
45
|
+
stored = isinstance(meta, dict)
|
|
46
|
+
storage = (meta or {}).get("storage", "file")
|
|
47
|
+
|
|
48
|
+
if env_key and stored:
|
|
49
|
+
return env_key, f"env var {env_var} — overrides stored credential"
|
|
50
|
+
if env_key:
|
|
51
|
+
return env_key, f"env var {env_var}"
|
|
52
|
+
if stored:
|
|
53
|
+
return None, _storage_short(storage)
|
|
54
|
+
return None, "not configured"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _resolve_auth_type(provider: str) -> str:
|
|
58
|
+
"""Read auth_type from lockfile connector entry. Falls back to 'api_key'.
|
|
59
|
+
|
|
60
|
+
If multiple installed connectors share a provider with different auth
|
|
61
|
+
types, this returns the first match — may need disambiguation later.
|
|
62
|
+
"""
|
|
63
|
+
lock = read_lockfile()
|
|
64
|
+
for _slug, info in lock.get("packages", {}).items():
|
|
65
|
+
connector = info.get("connector")
|
|
66
|
+
if isinstance(connector, dict) and connector.get("provider", "").lower() == provider:
|
|
67
|
+
return connector.get("auth_type", "api_key")
|
|
68
|
+
return "api_key"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def cmd_auth_set(provider: str, from_env: str | None = None) -> int:
|
|
72
|
+
provider = provider.lower().strip()
|
|
73
|
+
if not provider:
|
|
74
|
+
print(" Error: provider name required.", file=sys.stderr)
|
|
75
|
+
return 1
|
|
76
|
+
if from_env:
|
|
77
|
+
# Import an existing env key (also honors ~/.agentnode/.env). A flag,
|
|
78
|
+
# not a prompt — keeps piped-stdin flows intact.
|
|
79
|
+
from agentnode_sdk.runtimes.agent_runner import _load_agentnode_env
|
|
80
|
+
_load_agentnode_env()
|
|
81
|
+
token = (os.environ.get(from_env) or "").strip()
|
|
82
|
+
if not token:
|
|
83
|
+
print(f" Error: environment variable {from_env} is not set.", file=sys.stderr)
|
|
84
|
+
return 1
|
|
85
|
+
else:
|
|
86
|
+
try:
|
|
87
|
+
token = getpass.getpass(f" Enter access token for {provider}: ")
|
|
88
|
+
except (KeyboardInterrupt, EOFError):
|
|
89
|
+
print("\n Cancelled.")
|
|
90
|
+
return 130
|
|
91
|
+
token = token.strip()
|
|
92
|
+
if not token:
|
|
93
|
+
print(" Error: no token provided.", file=sys.stderr)
|
|
94
|
+
return 1
|
|
95
|
+
auth_type = _resolve_auth_type(provider)
|
|
96
|
+
storage = set_credential(provider, token, auth_type=auth_type)
|
|
97
|
+
if storage == "keyring":
|
|
98
|
+
where = "OS keychain"
|
|
99
|
+
else:
|
|
100
|
+
where = "plaintext file (0600) — OS keychain unavailable on this system"
|
|
101
|
+
print(f"\n Credential stored for {provider} ({_masked(token)}) — storage: {where}.\n")
|
|
102
|
+
return 0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def cmd_auth_list() -> int:
|
|
106
|
+
creds = list_credentials()
|
|
107
|
+
if not creds:
|
|
108
|
+
print("\n No credentials configured.")
|
|
109
|
+
print(dim(" Run `agentnode auth set <provider>` to store a credential.\n"))
|
|
110
|
+
return 0
|
|
111
|
+
print()
|
|
112
|
+
print(section("Credentials"))
|
|
113
|
+
print(f" {'Provider':<14}{'Auth type':<13}{'Storage':<16}{'Stored'}")
|
|
114
|
+
print(f" {'--------':<14}{'--------':<13}{'-------':<16}{'------'}")
|
|
115
|
+
for provider, info in sorted(creds.items()):
|
|
116
|
+
stored = info.get("stored_at", "")[:10]
|
|
117
|
+
auth_type = info.get("auth_type", "unknown")
|
|
118
|
+
storage = _storage_short(info.get("storage", "file"))
|
|
119
|
+
print(f" {provider:<14}{auth_type:<13}{storage:<16}{stored}")
|
|
120
|
+
print(f"\n {len(creds)} credential(s) configured.\n")
|
|
121
|
+
return 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def cmd_auth_remove(provider: str) -> int:
|
|
125
|
+
provider = provider.lower().strip()
|
|
126
|
+
if remove_credential(provider):
|
|
127
|
+
print(f"\n Removed credential for {provider}.\n")
|
|
128
|
+
return 0
|
|
129
|
+
print(f"\n No credential found for {provider}.\n")
|
|
130
|
+
return 1
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def cmd_auth_status() -> int:
|
|
134
|
+
# --- LLM providers (host runtime / sandbox broker) -----------------------
|
|
135
|
+
print()
|
|
136
|
+
print(section("LLM Providers"))
|
|
137
|
+
print(f" {'Provider':<14}{'Status':<16}{'Effective source'}")
|
|
138
|
+
print(f" {'--------':<14}{'------':<16}{'----------------'}")
|
|
139
|
+
for provider in sorted(LLM_PROVIDER_ENV):
|
|
140
|
+
key, source = _llm_effective_source(provider)
|
|
141
|
+
configured = key is not None or source not in ("not configured",)
|
|
142
|
+
status = "configured" if configured else "missing"
|
|
143
|
+
print(f" {provider:<14}{status:<16}{source}")
|
|
144
|
+
print(dim(" Env vars always override stored credentials. "
|
|
145
|
+
"Test a key: agentnode auth test <provider>"))
|
|
146
|
+
|
|
147
|
+
# --- connector packages (unchanged) --------------------------------------
|
|
148
|
+
lock = read_lockfile()
|
|
149
|
+
pkgs = lock.get("packages", {})
|
|
150
|
+
|
|
151
|
+
# Collect provider → list of slugs
|
|
152
|
+
provider_packages: dict[str, list[str]] = {}
|
|
153
|
+
for slug, info in pkgs.items():
|
|
154
|
+
connector = info.get("connector")
|
|
155
|
+
if isinstance(connector, dict) and connector.get("provider"):
|
|
156
|
+
provider = connector["provider"].lower().strip()
|
|
157
|
+
provider_packages.setdefault(provider, []).append(slug)
|
|
158
|
+
|
|
159
|
+
if not provider_packages:
|
|
160
|
+
print("\n No installed packages require connector credentials.\n")
|
|
161
|
+
return 0
|
|
162
|
+
|
|
163
|
+
print()
|
|
164
|
+
print(section("Credential Status"))
|
|
165
|
+
print(f" {'Provider':<14}{'Status':<16}{'Used by'}")
|
|
166
|
+
print(f" {'--------':<14}{'------':<16}{'------'}")
|
|
167
|
+
missing: list[str] = []
|
|
168
|
+
for provider in sorted(provider_packages):
|
|
169
|
+
configured = has_credential(provider)
|
|
170
|
+
status = "configured" if configured else "missing"
|
|
171
|
+
slugs = ", ".join(sorted(provider_packages[provider]))
|
|
172
|
+
print(f" {provider:<14}{status:<16}{slugs}")
|
|
173
|
+
if not configured:
|
|
174
|
+
missing.append(provider)
|
|
175
|
+
|
|
176
|
+
if missing:
|
|
177
|
+
print()
|
|
178
|
+
print(dim(" Fix missing:"))
|
|
179
|
+
for p in missing:
|
|
180
|
+
print(dim(f" agentnode auth set {p}"))
|
|
181
|
+
print()
|
|
182
|
+
return 0
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# Free, cost-less validation endpoints (no completion call, no charge).
|
|
186
|
+
# anthropic REQUIRES the anthropic-version header (a 400 without it would be
|
|
187
|
+
# misread as a bad key); openrouter's /models is UNAUTHENTICATED (validates
|
|
188
|
+
# nothing) — /auth/key is the correct probe.
|
|
189
|
+
_TEST_REQUESTS = {
|
|
190
|
+
"openai": lambda key: (
|
|
191
|
+
"https://api.openai.com/v1/models",
|
|
192
|
+
{"Authorization": f"Bearer {key}"},
|
|
193
|
+
),
|
|
194
|
+
"anthropic": lambda key: (
|
|
195
|
+
"https://api.anthropic.com/v1/models",
|
|
196
|
+
{"x-api-key": key, "anthropic-version": "2023-06-01"},
|
|
197
|
+
),
|
|
198
|
+
"openrouter": lambda key: (
|
|
199
|
+
"https://openrouter.ai/api/v1/auth/key",
|
|
200
|
+
{"Authorization": f"Bearer {key}"},
|
|
201
|
+
),
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def cmd_auth_test(provider: str) -> int:
|
|
206
|
+
"""Validate the EFFECTIVE key for an LLM provider (env beats vault) via a
|
|
207
|
+
free endpoint. Exit codes: 0 valid / 1 rejected (401/403) / 2 not
|
|
208
|
+
configured or unsupported / 3 indeterminate (network/5xx — never reported
|
|
209
|
+
as invalid). Never prints the key (masked last-4 only) and never echoes
|
|
210
|
+
the provider's response body (it can contain key fragments)."""
|
|
211
|
+
provider = provider.lower().strip()
|
|
212
|
+
if provider not in _TEST_REQUESTS:
|
|
213
|
+
supported = ", ".join(sorted(_TEST_REQUESTS))
|
|
214
|
+
print(f" auth test supports: {supported}", file=sys.stderr)
|
|
215
|
+
return 2
|
|
216
|
+
|
|
217
|
+
key, source = _llm_effective_source(provider)
|
|
218
|
+
if key is None:
|
|
219
|
+
# No env override — resolve the stored credential (real keychain read).
|
|
220
|
+
from agentnode_sdk.credential_store import get_llm_api_key
|
|
221
|
+
key = get_llm_api_key(provider)
|
|
222
|
+
if not key:
|
|
223
|
+
print(f"\n {provider}: not configured. Run `agentnode auth set {provider}`.\n")
|
|
224
|
+
return 2
|
|
225
|
+
|
|
226
|
+
url, headers = _TEST_REQUESTS[provider](key)
|
|
227
|
+
import httpx
|
|
228
|
+
try:
|
|
229
|
+
resp = httpx.get(url, headers=headers, timeout=10.0)
|
|
230
|
+
except Exception:
|
|
231
|
+
print(f"\n {provider} ({_masked(key)}, {source}): could not reach the "
|
|
232
|
+
"provider — key validity unknown.\n")
|
|
233
|
+
return 3
|
|
234
|
+
if resp.status_code == 200:
|
|
235
|
+
print(f"\n {provider} ({_masked(key)}, {source}): key is valid.\n")
|
|
236
|
+
return 0
|
|
237
|
+
if resp.status_code in (401, 403):
|
|
238
|
+
print(f"\n {provider} ({_masked(key)}, {source}): key was rejected by "
|
|
239
|
+
f"the provider (HTTP {resp.status_code}).\n")
|
|
240
|
+
return 1
|
|
241
|
+
print(f"\n {provider} ({_masked(key)}, {source}): unexpected provider "
|
|
242
|
+
f"response (HTTP {resp.status_code}) — key validity unknown.\n")
|
|
243
|
+
return 3
|
|
@@ -63,10 +63,14 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
63
63
|
auth_sub = auth_parser.add_subparsers(dest="auth_action")
|
|
64
64
|
auth_set_p = auth_sub.add_parser("set", help="Store a credential for a provider")
|
|
65
65
|
auth_set_p.add_argument("provider")
|
|
66
|
+
auth_set_p.add_argument("--from-env", default=None, metavar="ENV_VAR",
|
|
67
|
+
help="Import the key from this environment variable instead of prompting")
|
|
66
68
|
auth_sub.add_parser("list", help="Show configured credentials")
|
|
67
69
|
auth_rm_p = auth_sub.add_parser("remove", help="Remove a stored credential")
|
|
68
70
|
auth_rm_p.add_argument("provider")
|
|
69
71
|
auth_sub.add_parser("status", help="Check credential status for installed packages")
|
|
72
|
+
auth_test_p = auth_sub.add_parser("test", help="Validate a stored LLM key via a free provider endpoint")
|
|
73
|
+
auth_test_p.add_argument("provider")
|
|
70
74
|
|
|
71
75
|
# config
|
|
72
76
|
config_parser = sub.add_parser("config", help="View or modify settings")
|
|
@@ -270,15 +274,18 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
270
274
|
if args.command == "auth":
|
|
271
275
|
from agentnode_sdk.cli.auth import (
|
|
272
276
|
cmd_auth_set, cmd_auth_list, cmd_auth_remove, cmd_auth_status,
|
|
277
|
+
cmd_auth_test,
|
|
273
278
|
)
|
|
274
279
|
if args.auth_action == "set":
|
|
275
|
-
return cmd_auth_set(args.provider)
|
|
280
|
+
return cmd_auth_set(args.provider, from_env=args.from_env)
|
|
276
281
|
if args.auth_action == "list":
|
|
277
282
|
return cmd_auth_list()
|
|
278
283
|
if args.auth_action == "remove":
|
|
279
284
|
return cmd_auth_remove(args.provider)
|
|
280
285
|
if args.auth_action == "status":
|
|
281
286
|
return cmd_auth_status()
|
|
287
|
+
if args.auth_action == "test":
|
|
288
|
+
return cmd_auth_test(args.provider)
|
|
282
289
|
return cmd_auth_list()
|
|
283
290
|
if args.command == "config":
|
|
284
291
|
if args.config_action == "list":
|
|
@@ -41,6 +41,12 @@ DEFAULTS: dict[str, Any] = {
|
|
|
41
41
|
"compute": "allow",
|
|
42
42
|
"unknown": "prompt",
|
|
43
43
|
},
|
|
44
|
+
"agent_sandbox": {
|
|
45
|
+
"enabled": False,
|
|
46
|
+
},
|
|
47
|
+
"llm": {
|
|
48
|
+
"default_provider": "openai",
|
|
49
|
+
},
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
VALID_VALUES: dict[str, tuple[str, ...]] = {
|
|
@@ -61,6 +67,8 @@ VALID_VALUES: dict[str, tuple[str, ...]] = {
|
|
|
61
67
|
"guard.read": ("allow", "prompt", "deny"),
|
|
62
68
|
"guard.compute": ("allow", "prompt", "deny"),
|
|
63
69
|
"guard.unknown": ("allow", "prompt", "deny"),
|
|
70
|
+
"agent_sandbox.enabled": ("true", "false"),
|
|
71
|
+
"llm.default_provider": ("openai", "anthropic", "openrouter"),
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
|
|
@@ -82,6 +90,8 @@ CONFIG_DESCRIPTIONS: dict[str, str] = {
|
|
|
82
90
|
"guard.read": "Guard policy for tools that read data",
|
|
83
91
|
"guard.compute": "Guard policy for tools that perform computation",
|
|
84
92
|
"guard.unknown": "Guard policy for tools with unknown action type",
|
|
93
|
+
"agent_sandbox.enabled": "Route community (verified/unverified) agents through the container sandbox",
|
|
94
|
+
"llm.default_provider": "Which stored LLM credential to try first (vault resolution order)",
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
|
|
@@ -138,6 +148,18 @@ def _merge_defaults(data: dict) -> dict[str, Any]:
|
|
|
138
148
|
for extra_key in ("rate_limits", "agent_overrides", "tool_overrides"):
|
|
139
149
|
if extra_key in data["guard"]:
|
|
140
150
|
cfg["guard"][extra_key] = data["guard"][extra_key]
|
|
151
|
+
if isinstance(data.get("agent_sandbox"), dict):
|
|
152
|
+
if "enabled" in data["agent_sandbox"]:
|
|
153
|
+
cfg["agent_sandbox"]["enabled"] = data["agent_sandbox"]["enabled"]
|
|
154
|
+
# The nested llm ceiling (max_calls/max_input_chars/max_output_chars/
|
|
155
|
+
# allowed_models/enabled) holds ints/lists — pass it through verbatim,
|
|
156
|
+
# like the guard extra keys above.
|
|
157
|
+
if isinstance(data["agent_sandbox"].get("llm"), dict):
|
|
158
|
+
cfg["agent_sandbox"]["llm"] = data["agent_sandbox"]["llm"]
|
|
159
|
+
if isinstance(data.get("llm"), dict):
|
|
160
|
+
for k in ("default_provider",):
|
|
161
|
+
if k in data["llm"]:
|
|
162
|
+
cfg["llm"][k] = data["llm"][k]
|
|
141
163
|
return cfg
|
|
142
164
|
|
|
143
165
|
|
|
@@ -201,7 +223,7 @@ def set_value(cfg: dict[str, Any], key: str, value: str) -> dict[str, Any]:
|
|
|
201
223
|
f"Allowed: {', '.join(allowed)}"
|
|
202
224
|
)
|
|
203
225
|
|
|
204
|
-
bool_keys = ("credentials.require_before_auto_install",)
|
|
226
|
+
bool_keys = ("credentials.require_before_auto_install", "agent_sandbox.enabled")
|
|
205
227
|
actual_value: Any = value.lower() == "true" if key in bool_keys else value.lower()
|
|
206
228
|
|
|
207
229
|
parts = key.split(".")
|