agentcore-cli 0.31.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.
- agentcore/__init__.py +1 -0
- agentcore/agent_inspector/NOTICE +9 -0
- agentcore/agent_inspector/favicon.svg +60 -0
- agentcore/agent_inspector/index.css +1 -0
- agentcore/agent_inspector/index.html +14 -0
- agentcore/agent_inspector/index.js +289 -0
- agentcore/assets/AGENTS.md +60 -0
- agentcore/assets/README.md +108 -0
- agentcore/assets/agents/AGENTS.md +218 -0
- agentcore/assets/cdk/.prettierrc +8 -0
- agentcore/assets/cdk/README.md +26 -0
- agentcore/assets/cdk/bin/cdk.ts +216 -0
- agentcore/assets/cdk/cdk.json +88 -0
- agentcore/assets/cdk/gitignore.template +9 -0
- agentcore/assets/cdk/jest.config.js +9 -0
- agentcore/assets/cdk/lib/cdk-stack.ts +291 -0
- agentcore/assets/cdk/npmignore.template +6 -0
- agentcore/assets/cdk/package.json +30 -0
- agentcore/assets/cdk/test/cdk.test.ts +31 -0
- agentcore/assets/cdk/tsconfig.json +28 -0
- agentcore/assets/container/python/Dockerfile +47 -0
- agentcore/assets/container/python/dockerignore.template +27 -0
- agentcore/assets/container/typescript/Dockerfile +25 -0
- agentcore/assets/container/typescript/dockerignore.template +24 -0
- agentcore/assets/datasets/predefined-v1.jsonl +3 -0
- agentcore/assets/datasets/simulated-v1.jsonl +3 -0
- agentcore/assets/evaluators/autoevals-lambda/execution-role-policy.json +15 -0
- agentcore/assets/evaluators/autoevals-lambda/lambda_function.py +37 -0
- agentcore/assets/evaluators/autoevals-lambda/pyproject.toml +22 -0
- agentcore/assets/evaluators/deepeval-lambda/execution-role-policy.json +15 -0
- agentcore/assets/evaluators/deepeval-lambda/lambda_function.py +29 -0
- agentcore/assets/evaluators/deepeval-lambda/pyproject.toml +19 -0
- agentcore/assets/evaluators/python-lambda/execution-role-policy.json +10 -0
- agentcore/assets/evaluators/python-lambda/lambda_function.py +19 -0
- agentcore/assets/evaluators/python-lambda/pyproject.toml +15 -0
- agentcore/assets/harness/invoke.py.template +74 -0
- agentcore/assets/mcp/python/README.md +27 -0
- agentcore/assets/mcp/python/pyproject.toml +22 -0
- agentcore/assets/mcp/python/server.py +117 -0
- agentcore/assets/mcp/python-lambda/README.md +22 -0
- agentcore/assets/mcp/python-lambda/handler.py +144 -0
- agentcore/assets/mcp/python-lambda/pyproject.toml +15 -0
- agentcore/assets/python/a2a/googleadk/base/README.md +22 -0
- agentcore/assets/python/a2a/googleadk/base/gitignore.template +41 -0
- agentcore/assets/python/a2a/googleadk/base/main.py +124 -0
- agentcore/assets/python/a2a/googleadk/base/model/__init__.py +1 -0
- agentcore/assets/python/a2a/googleadk/base/model/load.py +41 -0
- agentcore/assets/python/a2a/googleadk/base/pyproject.toml +22 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/README.md +22 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/gitignore.template +41 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/main.py +144 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/model/__init__.py +1 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/model/load.py +123 -0
- agentcore/assets/python/a2a/langchain_langgraph/base/pyproject.toml +26 -0
- agentcore/assets/python/a2a/strands/base/README.md +22 -0
- agentcore/assets/python/a2a/strands/base/gitignore.template +41 -0
- agentcore/assets/python/a2a/strands/base/main.py +113 -0
- agentcore/assets/python/a2a/strands/base/model/__init__.py +1 -0
- agentcore/assets/python/a2a/strands/base/model/load.py +123 -0
- agentcore/assets/python/a2a/strands/base/pyproject.toml +23 -0
- agentcore/assets/python/a2a/strands/capabilities/memory/__init__.py +1 -0
- agentcore/assets/python/a2a/strands/capabilities/memory/session.py +46 -0
- agentcore/assets/python/agui/googleadk/base/README.md +30 -0
- agentcore/assets/python/agui/googleadk/base/gitignore.template +41 -0
- agentcore/assets/python/agui/googleadk/base/main.py +91 -0
- agentcore/assets/python/agui/googleadk/base/model/__init__.py +1 -0
- agentcore/assets/python/agui/googleadk/base/model/load.py +41 -0
- agentcore/assets/python/agui/googleadk/base/pyproject.toml +25 -0
- agentcore/assets/python/agui/langchain_langgraph/base/README.md +22 -0
- agentcore/assets/python/agui/langchain_langgraph/base/gitignore.template +41 -0
- agentcore/assets/python/agui/langchain_langgraph/base/main.py +130 -0
- agentcore/assets/python/agui/langchain_langgraph/base/model/__init__.py +1 -0
- agentcore/assets/python/agui/langchain_langgraph/base/model/load.py +123 -0
- agentcore/assets/python/agui/langchain_langgraph/base/pyproject.toml +31 -0
- agentcore/assets/python/agui/strands/base/README.md +22 -0
- agentcore/assets/python/agui/strands/base/gitignore.template +41 -0
- agentcore/assets/python/agui/strands/base/main.py +105 -0
- agentcore/assets/python/agui/strands/base/model/__init__.py +1 -0
- agentcore/assets/python/agui/strands/base/model/load.py +123 -0
- agentcore/assets/python/agui/strands/base/pyproject.toml +27 -0
- agentcore/assets/python/agui/strands/capabilities/memory/__init__.py +1 -0
- agentcore/assets/python/agui/strands/capabilities/memory/session.py +46 -0
- agentcore/assets/python/http/autogen/base/README.md +45 -0
- agentcore/assets/python/http/autogen/base/gitignore.template +41 -0
- agentcore/assets/python/http/autogen/base/main.py +145 -0
- agentcore/assets/python/http/autogen/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/autogen/base/mcp_client/client.py +28 -0
- agentcore/assets/python/http/autogen/base/model/__init__.py +1 -0
- agentcore/assets/python/http/autogen/base/model/load.py +136 -0
- agentcore/assets/python/http/autogen/base/pyproject.toml +34 -0
- agentcore/assets/python/http/bma/base/Dockerfile +41 -0
- agentcore/assets/python/http/bma/base/README.md +178 -0
- agentcore/assets/python/http/bma/base/client.py +200 -0
- agentcore/assets/python/http/bma/base/lifecycle/server.py +641 -0
- agentcore/assets/python/http/bma/base/otel/collector.yaml +69 -0
- agentcore/assets/python/http/bma/base/plugins/acr-report/.codex-plugin/plugin.json +6 -0
- agentcore/assets/python/http/bma/base/plugins/acr-report/skills/acr-report/SKILL.md +16 -0
- agentcore/assets/python/http/bma/base/policies/bma-acr-policy.json +11 -0
- agentcore/assets/python/http/bma/base/policies/bma-session-policy.json +35 -0
- agentcore/assets/python/http/bma/base/policies/bma-session-trust.json +20 -0
- agentcore/assets/python/http/bma/base/pyproject.toml +21 -0
- agentcore/assets/python/http/googleadk/base/README.md +45 -0
- agentcore/assets/python/http/googleadk/base/gitignore.template +41 -0
- agentcore/assets/python/http/googleadk/base/main.py +207 -0
- agentcore/assets/python/http/googleadk/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/googleadk/base/mcp_client/client.py +75 -0
- agentcore/assets/python/http/googleadk/base/model/__init__.py +1 -0
- agentcore/assets/python/http/googleadk/base/model/load.py +41 -0
- agentcore/assets/python/http/googleadk/base/pyproject.toml +24 -0
- agentcore/assets/python/http/langchain_langgraph/base/README.md +45 -0
- agentcore/assets/python/http/langchain_langgraph/base/gitignore.template +41 -0
- agentcore/assets/python/http/langchain_langgraph/base/main.py +227 -0
- agentcore/assets/python/http/langchain_langgraph/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/langchain_langgraph/base/mcp_client/client.py +79 -0
- agentcore/assets/python/http/langchain_langgraph/base/model/__init__.py +1 -0
- agentcore/assets/python/http/langchain_langgraph/base/model/load.py +123 -0
- agentcore/assets/python/http/langchain_langgraph/base/pyproject.toml +38 -0
- agentcore/assets/python/http/openaiagents/base/README.md +45 -0
- agentcore/assets/python/http/openaiagents/base/gitignore.template +41 -0
- agentcore/assets/python/http/openaiagents/base/main.py +200 -0
- agentcore/assets/python/http/openaiagents/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/openaiagents/base/mcp_client/client.py +74 -0
- agentcore/assets/python/http/openaiagents/base/model/__init__.py +1 -0
- agentcore/assets/python/http/openaiagents/base/model/load.py +37 -0
- agentcore/assets/python/http/openaiagents/base/pyproject.toml +21 -0
- agentcore/assets/python/http/strands/base/README.md +46 -0
- agentcore/assets/python/http/strands/base/gitignore.template +41 -0
- agentcore/assets/python/http/strands/base/main.py +714 -0
- agentcore/assets/python/http/strands/base/mcp_client/__init__.py +1 -0
- agentcore/assets/python/http/strands/base/mcp_client/client.py +116 -0
- agentcore/assets/python/http/strands/base/model/__init__.py +1 -0
- agentcore/assets/python/http/strands/base/model/load.py +239 -0
- agentcore/assets/python/http/strands/base/model/mantle_compat.py +21 -0
- agentcore/assets/python/http/strands/base/pyproject.toml +31 -0
- agentcore/assets/python/http/strands/base/skills/fetcher.py +279 -0
- agentcore/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
- agentcore/assets/python/http/strands/capabilities/memory/__init__.py +1 -0
- agentcore/assets/python/http/strands/capabilities/memory/session.py +47 -0
- agentcore/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
- agentcore/assets/python/http/strands/capabilities/payments/payments.py +142 -0
- agentcore/assets/python/mcp/standalone/base/README.md +36 -0
- agentcore/assets/python/mcp/standalone/base/gitignore.template +41 -0
- agentcore/assets/python/mcp/standalone/base/main.py +83 -0
- agentcore/assets/python/mcp/standalone/base/pyproject.toml +16 -0
- agentcore/assets/typescript/.gitkeep +0 -0
- agentcore/assets/typescript/http/strands/base/README.md +42 -0
- agentcore/assets/typescript/http/strands/base/gitignore.template +22 -0
- agentcore/assets/typescript/http/strands/base/main.ts +149 -0
- agentcore/assets/typescript/http/strands/base/mcp_client/client.ts +11 -0
- agentcore/assets/typescript/http/strands/base/model/load.ts +102 -0
- agentcore/assets/typescript/http/strands/base/package.json +38 -0
- agentcore/assets/typescript/http/strands/base/tsconfig.json +19 -0
- agentcore/assets/typescript/http/strands/capabilities/memory/memory.ts +52 -0
- agentcore/assets/typescript/http/vercelai/base/README.md +42 -0
- agentcore/assets/typescript/http/vercelai/base/gitignore.template +22 -0
- agentcore/assets/typescript/http/vercelai/base/main.ts +70 -0
- agentcore/assets/typescript/http/vercelai/base/model/load.ts +121 -0
- agentcore/assets/typescript/http/vercelai/base/package.json +35 -0
- agentcore/assets/typescript/http/vercelai/base/tsconfig.json +19 -0
- agentcore/aws/__init__.py +263 -0
- agentcore/aws/_aws_errors.py +72 -0
- agentcore/aws/_http.py +176 -0
- agentcore/aws/_util.py +37 -0
- agentcore/aws/account.py +165 -0
- agentcore/aws/agentcore.py +971 -0
- agentcore/aws/agentcore_ab_tests.py +230 -0
- agentcore/aws/agentcore_batch_evaluation.py +227 -0
- agentcore/aws/agentcore_config_bundles.py +220 -0
- agentcore/aws/agentcore_control.py +994 -0
- agentcore/aws/agentcore_datasets.py +222 -0
- agentcore/aws/agentcore_harness.py +330 -0
- agentcore/aws/agentcore_payments.py +430 -0
- agentcore/aws/agentcore_recommendation.py +140 -0
- agentcore/aws/agui_parser.py +131 -0
- agentcore/aws/agui_types.py +342 -0
- agentcore/aws/api_client.py +87 -0
- agentcore/aws/arn.py +18 -0
- agentcore/aws/aws_context.py +23 -0
- agentcore/aws/bedrock.py +44 -0
- agentcore/aws/bedrock_agent.py +129 -0
- agentcore/aws/bedrock_import.py +252 -0
- agentcore/aws/bedrock_import_types.py +111 -0
- agentcore/aws/cloudwatch.py +136 -0
- agentcore/aws/connect_shell.py +266 -0
- agentcore/aws/iam.py +41 -0
- agentcore/aws/partition.py +58 -0
- agentcore/aws/policy_generation.py +116 -0
- agentcore/aws/region.py +54 -0
- agentcore/aws/retry.py +27 -0
- agentcore/aws/shell_framer.py +136 -0
- agentcore/aws/stage_endpoint.py +39 -0
- agentcore/aws/target_region.py +54 -0
- agentcore/aws/transaction_search.py +97 -0
- agentcore/cdk/__init__.py +10 -0
- agentcore/cdk/constants.py +13 -0
- agentcore/cdk/local_cdk_project.py +48 -0
- agentcore/cdk/toolkit.py +706 -0
- agentcore/cli/__init__.py +0 -0
- agentcore/cli/commands/__init__.py +0 -0
- agentcore/cli/commands/_jobs_common.py +39 -0
- agentcore/cli/commands/_run_wizards.py +639 -0
- agentcore/cli/commands/add/__init__.py +37 -0
- agentcore/cli/commands/add/_commander.py +52 -0
- agentcore/cli/commands/add/_common.py +47 -0
- agentcore/cli/commands/add/agent_wizard.py +528 -0
- agentcore/cli/commands/add/auth_options.py +154 -0
- agentcore/cli/commands/add/skill_action.py +105 -0
- agentcore/cli/commands/add/skill_command.py +87 -0
- agentcore/cli/commands/add/tool_action.py +160 -0
- agentcore/cli/commands/add/tool_command.py +117 -0
- agentcore/cli/commands/add/validate.py +333 -0
- agentcore/cli/commands/capacity_provider/__init__.py +86 -0
- agentcore/cli/commands/capacity_provider/action.py +114 -0
- agentcore/cli/commands/capacity_provider/constants.py +22 -0
- agentcore/cli/commands/config.py +91 -0
- agentcore/cli/commands/config_bundle.py +251 -0
- agentcore/cli/commands/create/__init__.py +643 -0
- agentcore/cli/commands/create/action.py +406 -0
- agentcore/cli/commands/create/dependencies.py +91 -0
- agentcore/cli/commands/create/harness_validate.py +82 -0
- agentcore/cli/commands/create/validate.py +195 -0
- agentcore/cli/commands/create/wizard.py +127 -0
- agentcore/cli/commands/dataset.py +119 -0
- agentcore/cli/commands/deploy/__init__.py +31 -0
- agentcore/cli/commands/deploy/_guards.py +25 -0
- agentcore/cli/commands/deploy/actions.py +840 -0
- agentcore/cli/commands/deploy/command.py +349 -0
- agentcore/cli/commands/deploy/progress.py +115 -0
- agentcore/cli/commands/deploy/types.py +68 -0
- agentcore/cli/commands/deploy/utils.py +43 -0
- agentcore/cli/commands/deploy/validate.py +21 -0
- agentcore/cli/commands/dev/__init__.py +5 -0
- agentcore/cli/commands/dev/_deps.py +50 -0
- agentcore/cli/commands/dev/browser_mode.py +270 -0
- agentcore/cli/commands/dev/command.py +450 -0
- agentcore/cli/commands/dev/terminal_mode.py +379 -0
- agentcore/cli/commands/exec/__init__.py +29 -0
- agentcore/cli/commands/exec/action.py +442 -0
- agentcore/cli/commands/exec/command.py +206 -0
- agentcore/cli/commands/exec/types.py +35 -0
- agentcore/cli/commands/export/__init__.py +114 -0
- agentcore/cli/commands/export/constants.py +21 -0
- agentcore/cli/commands/export/fetch_harness_spec.py +234 -0
- agentcore/cli/commands/export/harness_action.py +385 -0
- agentcore/cli/commands/export/harness_mapper.py +868 -0
- agentcore/cli/commands/export/harness_resolver.py +95 -0
- agentcore/cli/commands/export/types.py +90 -0
- agentcore/cli/commands/export/wizard.py +97 -0
- agentcore/cli/commands/feedback/__init__.py +69 -0
- agentcore/cli/commands/feedback/action.py +30 -0
- agentcore/cli/commands/feedback/consent_prompt.py +35 -0
- agentcore/cli/commands/feedback/wizard.py +49 -0
- agentcore/cli/commands/fetch/__init__.py +69 -0
- agentcore/cli/commands/fetch/action.py +62 -0
- agentcore/cli/commands/help.py +65 -0
- agentcore/cli/commands/import_/__init__.py +167 -0
- agentcore/cli/commands/import_/_js.py +72 -0
- agentcore/cli/commands/import_/actions.py +457 -0
- agentcore/cli/commands/import_/constants.py +45 -0
- agentcore/cli/commands/import_/import_evaluator.py +140 -0
- agentcore/cli/commands/import_/import_gateway.py +520 -0
- agentcore/cli/commands/import_/import_memory.py +128 -0
- agentcore/cli/commands/import_/import_online_eval.py +165 -0
- agentcore/cli/commands/import_/import_pipeline.py +145 -0
- agentcore/cli/commands/import_/import_runtime.py +214 -0
- agentcore/cli/commands/import_/import_utils.py +410 -0
- agentcore/cli/commands/import_/phase1_update.py +110 -0
- agentcore/cli/commands/import_/phase2_import.py +206 -0
- agentcore/cli/commands/import_/resource_import.py +228 -0
- agentcore/cli/commands/import_/template_utils.py +148 -0
- agentcore/cli/commands/import_/types.py +150 -0
- agentcore/cli/commands/import_/yaml_parser.py +265 -0
- agentcore/cli/commands/init.py +196 -0
- agentcore/cli/commands/invoke/__init__.py +32 -0
- agentcore/cli/commands/invoke/_deps.py +73 -0
- agentcore/cli/commands/invoke/action.py +840 -0
- agentcore/cli/commands/invoke/command.py +490 -0
- agentcore/cli/commands/invoke/constants.py +40 -0
- agentcore/cli/commands/invoke/guards.py +23 -0
- agentcore/cli/commands/invoke/interactive.py +604 -0
- agentcore/cli/commands/invoke/resolve.py +149 -0
- agentcore/cli/commands/invoke/resolve_prompt.py +60 -0
- agentcore/cli/commands/invoke/types.py +61 -0
- agentcore/cli/commands/invoke/validate.py +33 -0
- agentcore/cli/commands/job_actions.py +239 -0
- agentcore/cli/commands/job_history.py +380 -0
- agentcore/cli/commands/logs/__init__.py +53 -0
- agentcore/cli/commands/logs/action.py +159 -0
- agentcore/cli/commands/logs/filter_pattern.py +17 -0
- agentcore/cli/commands/logs/guards.py +51 -0
- agentcore/cli/commands/logs_evals.py +42 -0
- agentcore/cli/commands/package.py +118 -0
- agentcore/cli/commands/remove/__init__.py +172 -0
- agentcore/cli/commands/remove/skill_command.py +131 -0
- agentcore/cli/commands/remove/tool_command.py +59 -0
- agentcore/cli/commands/run.py +808 -0
- agentcore/cli/commands/run_ingest.py +97 -0
- agentcore/cli/commands/shared/__init__.py +0 -0
- agentcore/cli/commands/shared/arn_utils.py +9 -0
- agentcore/cli/commands/shared/filesystem_utils.py +421 -0
- agentcore/cli/commands/shared/header_utils.py +87 -0
- agentcore/cli/commands/shared/indexed_key_parser.py +76 -0
- agentcore/cli/commands/shared/lifecycle_utils.py +72 -0
- agentcore/cli/commands/shared/region_utils.py +20 -0
- agentcore/cli/commands/shared/vpc_utils.py +99 -0
- agentcore/cli/commands/status/__init__.py +30 -0
- agentcore/cli/commands/status/_guards.py +25 -0
- agentcore/cli/commands/status/action.py +741 -0
- agentcore/cli/commands/status/command.py +321 -0
- agentcore/cli/commands/status/constants.py +36 -0
- agentcore/cli/commands/status/format_knowledge_base.py +111 -0
- agentcore/cli/commands/telemetry.py +79 -0
- agentcore/cli/commands/traces/__init__.py +155 -0
- agentcore/cli/commands/traces/action.py +123 -0
- agentcore/cli/commands/update/__init__.py +63 -0
- agentcore/cli/commands/update/action.py +164 -0
- agentcore/cli/commands/validate.py +165 -0
- agentcore/cli/constants.py +96 -0
- agentcore/cli/errors.py +118 -0
- agentcore/cli/external_requirements/__init__.py +67 -0
- agentcore/cli/external_requirements/checks.py +280 -0
- agentcore/cli/external_requirements/detect.py +55 -0
- agentcore/cli/external_requirements/versions.py +57 -0
- agentcore/cli/groups.py +23 -0
- agentcore/cli/interactive.py +85 -0
- agentcore/cli/main.py +137 -0
- agentcore/cli/naming.py +11 -0
- agentcore/cli/notices.py +42 -0
- agentcore/cli/project.py +34 -0
- agentcore/cli/run_command.py +27 -0
- agentcore/cli/tree.py +135 -0
- agentcore/cli/update_notifier.py +123 -0
- agentcore/cli/variadic.py +50 -0
- agentcore/cloudformation/__init__.py +84 -0
- agentcore/cloudformation/bootstrap.py +64 -0
- agentcore/cloudformation/logical_ids.py +37 -0
- agentcore/cloudformation/outputs.py +566 -0
- agentcore/cloudformation/stack_discovery.py +75 -0
- agentcore/cloudformation/stack_events.py +107 -0
- agentcore/cloudformation/stack_status.py +98 -0
- agentcore/cloudformation/types.py +44 -0
- agentcore/lib/__init__.py +68 -0
- agentcore/lib/constants.py +77 -0
- agentcore/lib/dependency_management/__init__.py +23 -0
- agentcore/lib/dependency_management/messages.py +92 -0
- agentcore/lib/dependency_management/plan.py +98 -0
- agentcore/lib/dependency_management/semver.py +137 -0
- agentcore/lib/dependency_management/sync.py +139 -0
- agentcore/lib/dependency_management/types.py +56 -0
- agentcore/lib/errors/__init__.py +5 -0
- agentcore/lib/errors/types.py +352 -0
- agentcore/lib/errors/validation.py +121 -0
- agentcore/lib/packaging/__init__.py +81 -0
- agentcore/lib/packaging/build_args.py +23 -0
- agentcore/lib/packaging/build_context.py +26 -0
- agentcore/lib/packaging/build_context_dockerignore.py +45 -0
- agentcore/lib/packaging/container.py +95 -0
- agentcore/lib/packaging/helpers.py +289 -0
- agentcore/lib/packaging/node.py +153 -0
- agentcore/lib/packaging/python.py +135 -0
- agentcore/lib/packaging/types.py +69 -0
- agentcore/lib/packaging/uv.py +45 -0
- agentcore/lib/result.py +104 -0
- agentcore/lib/schemas/__init__.py +1 -0
- agentcore/lib/schemas/io/__init__.py +27 -0
- agentcore/lib/schemas/io/config_io.py +458 -0
- agentcore/lib/schemas/io/global_config.py +239 -0
- agentcore/lib/schemas/io/path_resolver.py +132 -0
- agentcore/lib/secrets/__init__.py +18 -0
- agentcore/lib/secrets/cipher.py +70 -0
- agentcore/lib/secrets/key_provider.py +163 -0
- agentcore/lib/secrets/sensitive_keys.py +55 -0
- agentcore/lib/time_constants.py +4 -0
- agentcore/lib/utils/__init__.py +47 -0
- agentcore/lib/utils/aws_account.py +15 -0
- agentcore/lib/utils/credentials.py +68 -0
- agentcore/lib/utils/dotenv.py +32 -0
- agentcore/lib/utils/env.py +105 -0
- agentcore/lib/utils/json_format.py +29 -0
- agentcore/lib/utils/json_rpc.py +22 -0
- agentcore/lib/utils/platform.py +33 -0
- agentcore/lib/utils/polling.py +86 -0
- agentcore/lib/utils/subprocess.py +135 -0
- agentcore/lib/utils/time_parser.py +48 -0
- agentcore/lib/utils/validation.py +106 -0
- agentcore/logging/__init__.py +10 -0
- agentcore/logging/_common.py +77 -0
- agentcore/logging/cdk_io_host.py +36 -0
- agentcore/logging/create_logger.py +107 -0
- agentcore/logging/dev_logger.py +63 -0
- agentcore/logging/exec_logger.py +159 -0
- agentcore/logging/invoke_logger.py +154 -0
- agentcore/logging/remove_logger.py +95 -0
- agentcore/operations/__init__.py +0 -0
- agentcore/operations/agent/__init__.py +0 -0
- agentcore/operations/agent/config_bundle_defaults.py +31 -0
- agentcore/operations/agent/generate/__init__.py +28 -0
- agentcore/operations/agent/generate/schema_mapper.py +319 -0
- agentcore/operations/agent/generate/types.py +172 -0
- agentcore/operations/agent/generate/write_agent_to_project.py +67 -0
- agentcore/operations/agent/import_/__init__.py +31 -0
- agentcore/operations/agent/import_/base_translator.py +449 -0
- agentcore/operations/agent/import_/constants.py +23 -0
- agentcore/operations/agent/import_/execute.py +127 -0
- agentcore/operations/agent/import_/langgraph_translator.py +294 -0
- agentcore/operations/agent/import_/pyproject_generator.py +73 -0
- agentcore/operations/agent/import_/strands_translator.py +289 -0
- agentcore/operations/config_bundle/__init__.py +1 -0
- agentcore/operations/config_bundle/bundle_name_variants.py +9 -0
- agentcore/operations/config_bundle/diff_versions.py +52 -0
- agentcore/operations/config_bundle/resolve_bundle.py +65 -0
- agentcore/operations/connectors/__init__.py +3 -0
- agentcore/operations/connectors/translators.py +63 -0
- agentcore/operations/dataset/__init__.py +21 -0
- agentcore/operations/dataset/delete.py +7 -0
- agentcore/operations/dataset/publish.py +16 -0
- agentcore/operations/dataset/pull.py +21 -0
- agentcore/operations/dataset/push.py +201 -0
- agentcore/operations/dataset/resolve_dataset.py +65 -0
- agentcore/operations/dataset/status.py +18 -0
- agentcore/operations/dataset/wait.py +25 -0
- agentcore/operations/deploy/__init__.py +152 -0
- agentcore/operations/deploy/backfill_vpc_id.py +90 -0
- agentcore/operations/deploy/change_detection.py +84 -0
- agentcore/operations/deploy/constants.py +58 -0
- agentcore/operations/deploy/dependency_sync.py +105 -0
- agentcore/operations/deploy/ensure_target.py +30 -0
- agentcore/operations/deploy/gateway_status.py +44 -0
- agentcore/operations/deploy/managed_memory_notice.py +36 -0
- agentcore/operations/deploy/payment_connector_authorization.py +106 -0
- agentcore/operations/deploy/post_deploy_datasets.py +96 -0
- agentcore/operations/deploy/post_deploy_knowledge_bases.py +104 -0
- agentcore/operations/deploy/post_deploy_observability.py +28 -0
- agentcore/operations/deploy/post_deploy_online_evals.py +60 -0
- agentcore/operations/deploy/pre_deploy_identity.py +505 -0
- agentcore/operations/deploy/preflight.py +385 -0
- agentcore/operations/deploy/region_override.py +45 -0
- agentcore/operations/deploy/teardown.py +153 -0
- agentcore/operations/dev/__init__.py +61 -0
- agentcore/operations/dev/_http.py +79 -0
- agentcore/operations/dev/_server.py +165 -0
- agentcore/operations/dev/codezip_dev_server.py +151 -0
- agentcore/operations/dev/config.py +128 -0
- agentcore/operations/dev/constants.py +9 -0
- agentcore/operations/dev/container_dev_server.py +237 -0
- agentcore/operations/dev/container_runtime.py +37 -0
- agentcore/operations/dev/dev_server.py +244 -0
- agentcore/operations/dev/gateway_env.py +25 -0
- agentcore/operations/dev/invoke.py +214 -0
- agentcore/operations/dev/invoke_a2a.py +204 -0
- agentcore/operations/dev/invoke_agui.py +88 -0
- agentcore/operations/dev/invoke_mcp.py +145 -0
- agentcore/operations/dev/invoke_types.py +30 -0
- agentcore/operations/dev/load_dev_env.py +26 -0
- agentcore/operations/dev/memory_env.py +19 -0
- agentcore/operations/dev/otel/__init__.py +5 -0
- agentcore/operations/dev/otel/collector.py +234 -0
- agentcore/operations/dev/otel/transforms.py +331 -0
- agentcore/operations/dev/payment_env.py +50 -0
- agentcore/operations/dev/server.py +28 -0
- agentcore/operations/dev/sse_transform.py +30 -0
- agentcore/operations/dev/utils.py +152 -0
- agentcore/operations/dev/web_ui/__init__.py +31 -0
- agentcore/operations/dev/web_ui/constants.py +25 -0
- agentcore/operations/dev/web_ui/handlers/__init__.py +36 -0
- agentcore/operations/dev/web_ui/handlers/_common.py +36 -0
- agentcore/operations/dev/web_ui/handlers/_deployed.py +37 -0
- agentcore/operations/dev/web_ui/handlers/a2a_proxy.py +37 -0
- agentcore/operations/dev/web_ui/handlers/cloudwatch_traces.py +71 -0
- agentcore/operations/dev/web_ui/handlers/harness_invocation.py +89 -0
- agentcore/operations/dev/web_ui/handlers/harness_utils.py +95 -0
- agentcore/operations/dev/web_ui/handlers/invocations.py +327 -0
- agentcore/operations/dev/web_ui/handlers/mcp_proxy.py +119 -0
- agentcore/operations/dev/web_ui/handlers/memory.py +84 -0
- agentcore/operations/dev/web_ui/handlers/resources.py +351 -0
- agentcore/operations/dev/web_ui/handlers/start.py +182 -0
- agentcore/operations/dev/web_ui/handlers/status.py +25 -0
- agentcore/operations/dev/web_ui/handlers/traces.py +50 -0
- agentcore/operations/dev/web_ui/run_web_ui.py +60 -0
- agentcore/operations/dev/web_ui/web_server.py +297 -0
- agentcore/operations/eval/__init__.py +8 -0
- agentcore/operations/eval/list_eval_runs.py +18 -0
- agentcore/operations/eval/logs_eval.py +119 -0
- agentcore/operations/eval/pause_resume.py +90 -0
- agentcore/operations/eval/run_eval.py +354 -0
- agentcore/operations/eval/shared/__init__.py +0 -0
- agentcore/operations/eval/shared/dataset_loader.py +68 -0
- agentcore/operations/eval/shared/dataset_session_provider.py +122 -0
- agentcore/operations/eval/shared/evaluator_runner.py +89 -0
- agentcore/operations/eval/shared/scenario_executor.py +71 -0
- agentcore/operations/eval/shared/span_collector.py +255 -0
- agentcore/operations/eval/storage.py +67 -0
- agentcore/operations/feedback/__init__.py +21 -0
- agentcore/operations/feedback/aperture_client.py +98 -0
- agentcore/operations/feedback/build_payload.py +97 -0
- agentcore/operations/feedback/constants.py +26 -0
- agentcore/operations/feedback/submit_feedback.py +150 -0
- agentcore/operations/fetch_access/__init__.py +36 -0
- agentcore/operations/fetch_access/_target.py +17 -0
- agentcore/operations/fetch_access/fetch_gateway_token.py +75 -0
- agentcore/operations/fetch_access/fetch_harness_token.py +72 -0
- agentcore/operations/fetch_access/fetch_runtime_token.py +76 -0
- agentcore/operations/fetch_access/list_agents.py +18 -0
- agentcore/operations/fetch_access/list_gateways.py +26 -0
- agentcore/operations/fetch_access/list_harnesses.py +23 -0
- agentcore/operations/fetch_access/oauth_token.py +162 -0
- agentcore/operations/fetch_access/types.py +34 -0
- agentcore/operations/harness/__init__.py +1 -0
- agentcore/operations/harness/orphan.py +84 -0
- agentcore/operations/harness/skill_utils.py +56 -0
- agentcore/operations/identity/__init__.py +33 -0
- agentcore/operations/identity/api_key_credential_provider.py +68 -0
- agentcore/operations/identity/oauth2_credential_provider.py +95 -0
- agentcore/operations/ingest/__init__.py +184 -0
- agentcore/operations/init/__init__.py +3 -0
- agentcore/operations/init/files.py +59 -0
- agentcore/operations/insights/__init__.py +21 -0
- agentcore/operations/insights/insights_storage.py +67 -0
- agentcore/operations/insights/run_insights.py +148 -0
- agentcore/operations/invoke/__init__.py +5 -0
- agentcore/operations/invoke/resolve_agent_context.py +85 -0
- agentcore/operations/jobs/__init__.py +38 -0
- agentcore/operations/jobs/ab_test/__init__.py +0 -0
- agentcore/operations/jobs/ab_test/build_options.py +126 -0
- agentcore/operations/jobs/ab_test/format.py +121 -0
- agentcore/operations/jobs/ab_test/handler.py +412 -0
- agentcore/operations/jobs/ab_test/promote.py +142 -0
- agentcore/operations/jobs/ab_test/resolve.py +221 -0
- agentcore/operations/jobs/batch_evaluation/__init__.py +0 -0
- agentcore/operations/jobs/batch_evaluation/build_source.py +68 -0
- agentcore/operations/jobs/batch_evaluation/dataset_phase1.py +95 -0
- agentcore/operations/jobs/batch_evaluation/format.py +58 -0
- agentcore/operations/jobs/batch_evaluation/handler.py +203 -0
- agentcore/operations/jobs/insights/__init__.py +0 -0
- agentcore/operations/jobs/insights/format.py +65 -0
- agentcore/operations/jobs/insights/handler.py +178 -0
- agentcore/operations/jobs/recommendation/__init__.py +0 -0
- agentcore/operations/jobs/recommendation/apply_to_bundle.py +76 -0
- agentcore/operations/jobs/recommendation/build_config.py +271 -0
- agentcore/operations/jobs/recommendation/fetch_session_spans.py +93 -0
- agentcore/operations/jobs/recommendation/format.py +77 -0
- agentcore/operations/jobs/recommendation/handler.py +331 -0
- agentcore/operations/jobs/shared/__init__.py +0 -0
- agentcore/operations/jobs/shared/constants.py +85 -0
- agentcore/operations/jobs/shared/engine.py +187 -0
- agentcore/operations/jobs/shared/format.py +104 -0
- agentcore/operations/jobs/shared/region.py +34 -0
- agentcore/operations/jobs/shared/resolve_agent_state.py +30 -0
- agentcore/operations/jobs/shared/storage.py +117 -0
- agentcore/operations/jobs/shared/wait.py +30 -0
- agentcore/operations/knowledge_base/__init__.py +33 -0
- agentcore/operations/knowledge_base/connector_config.py +105 -0
- agentcore/operations/knowledge_base/hydrate_data_sources.py +59 -0
- agentcore/operations/mcp/__init__.py +4 -0
- agentcore/operations/memory/__init__.py +13 -0
- agentcore/operations/memory/_records.py +72 -0
- agentcore/operations/memory/list_memory_records.py +45 -0
- agentcore/operations/memory/retrieve_memory_records.py +52 -0
- agentcore/operations/node/__init__.py +15 -0
- agentcore/operations/node/setup.py +36 -0
- agentcore/operations/python/__init__.py +17 -0
- agentcore/operations/python/setup.py +47 -0
- agentcore/operations/resolve_agent.py +159 -0
- agentcore/operations/session/__init__.py +86 -0
- agentcore/operations/traces/__init__.py +29 -0
- agentcore/operations/traces/get_trace.py +202 -0
- agentcore/operations/traces/insights_query.py +74 -0
- agentcore/operations/traces/list_traces.py +46 -0
- agentcore/operations/traces/trace_url.py +25 -0
- agentcore/operations/traces/types.py +55 -0
- agentcore/primitives/__init__.py +0 -0
- agentcore/primitives/_gateway_target_wizard.py +293 -0
- agentcore/primitives/_gateway_validation.py +442 -0
- agentcore/primitives/_harness_cli.py +557 -0
- agentcore/primitives/_harness_validation.py +163 -0
- agentcore/primitives/_harness_wizard.py +726 -0
- agentcore/primitives/_knowledge_base_wizard.py +259 -0
- agentcore/primitives/_payment_wizard.py +331 -0
- agentcore/primitives/_policy_form.py +160 -0
- agentcore/primitives/agent.py +817 -0
- agentcore/primitives/auth_utils.py +77 -0
- agentcore/primitives/base.py +178 -0
- agentcore/primitives/capacity_provider.py +501 -0
- agentcore/primitives/config_bundle.py +329 -0
- agentcore/primitives/credential.py +387 -0
- agentcore/primitives/credential_utils.py +45 -0
- agentcore/primitives/dataset.py +211 -0
- agentcore/primitives/deployed_gateways.py +34 -0
- agentcore/primitives/evaluator.py +909 -0
- agentcore/primitives/gateway.py +496 -0
- agentcore/primitives/gateway_target.py +988 -0
- agentcore/primitives/harness.py +706 -0
- agentcore/primitives/knowledge_base.py +477 -0
- agentcore/primitives/memory.py +387 -0
- agentcore/primitives/online_eval_config.py +365 -0
- agentcore/primitives/online_insights.py +275 -0
- agentcore/primitives/payment_connector.py +427 -0
- agentcore/primitives/payment_eligible.py +20 -0
- agentcore/primitives/payment_manager.py +605 -0
- agentcore/primitives/payment_validation.py +68 -0
- agentcore/primitives/policy.py +622 -0
- agentcore/primitives/policy_engine.py +358 -0
- agentcore/primitives/registry.py +56 -0
- agentcore/primitives/runtime_endpoint.py +361 -0
- agentcore/primitives/secret_flag_warning.py +17 -0
- agentcore/schema/__init__.py +14 -0
- agentcore/schema/_zod.py +395 -0
- agentcore/schema/constants.py +306 -0
- agentcore/schema/schemas/__init__.py +40 -0
- agentcore/schema/schemas/agent_env.py +545 -0
- agentcore/schema/schemas/agentcore_project.py +530 -0
- agentcore/schema/schemas/auth.py +286 -0
- agentcore/schema/schemas/aws_targets.py +72 -0
- agentcore/schema/schemas/connections.py +187 -0
- agentcore/schema/schemas/deployed_state.py +322 -0
- agentcore/schema/schemas/mcp.py +650 -0
- agentcore/schema/schemas/mcp_defs.py +54 -0
- agentcore/schema/schemas/primitives/__init__.py +52 -0
- agentcore/schema/schemas/primitives/ab_test.py +162 -0
- agentcore/schema/schemas/primitives/capacity_provider.py +214 -0
- agentcore/schema/schemas/primitives/config_bundle.py +48 -0
- agentcore/schema/schemas/primitives/dataset.py +55 -0
- agentcore/schema/schemas/primitives/evaluator.py +171 -0
- agentcore/schema/schemas/primitives/harness.py +710 -0
- agentcore/schema/schemas/primitives/knowledge_base.py +90 -0
- agentcore/schema/schemas/primitives/memory.py +113 -0
- agentcore/schema/schemas/primitives/online_eval_config.py +77 -0
- agentcore/schema/schemas/primitives/payment.py +114 -0
- agentcore/schema/schemas/primitives/policy.py +83 -0
- agentcore/schema/schemas/primitives/tags.py +50 -0
- agentcore/schema/schemas/zod_util.py +5 -0
- agentcore/schema/types/__init__.py +3 -0
- agentcore/schema/types/path.py +16 -0
- agentcore/templates/__init__.py +115 -0
- agentcore/templates/_handlebars.py +782 -0
- agentcore/templates/_js.py +164 -0
- agentcore/templates/base_renderer.py +107 -0
- agentcore/templates/cdk_renderer.py +129 -0
- agentcore/templates/evaluator_renderer.py +39 -0
- agentcore/templates/gateway_target_renderer.py +69 -0
- agentcore/templates/llm_context/README.md +16 -0
- agentcore/templates/llm_context/agentcore.ts +685 -0
- agentcore/templates/llm_context/aws-targets.ts +51 -0
- agentcore/templates/profiles.py +151 -0
- agentcore/templates/render.py +92 -0
- agentcore/templates/renderers.py +83 -0
- agentcore/templates/schema_assets.py +23 -0
- agentcore/templates/template_root.py +28 -0
- agentcore/templates/types.py +192 -0
- agentcore_cli-0.31.1.dist-info/METADATA +84 -0
- agentcore_cli-0.31.1.dist-info/RECORD +655 -0
- agentcore_cli-0.31.1.dist-info/WHEEL +4 -0
- agentcore_cli-0.31.1.dist-info/entry_points.txt +2 -0
- agentcore_cli-0.31.1.dist-info/licenses/LICENSE +175 -0
- agentcore_cli-0.31.1.dist-info/licenses/NOTICE +88 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Read/write ``agentcore/.env.local`` with transparent at-rest encryption (port of ``env.ts``)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from collections.abc import Iterable, Mapping
|
|
8
|
+
|
|
9
|
+
from agentcore.lib.constants import ENV_FILE
|
|
10
|
+
from agentcore.lib.secrets import (
|
|
11
|
+
ENC_PREFIX,
|
|
12
|
+
decrypt_secret,
|
|
13
|
+
encrypt_secret,
|
|
14
|
+
is_sensitive_key,
|
|
15
|
+
resolve_candidate_keys,
|
|
16
|
+
resolve_encryption_key,
|
|
17
|
+
)
|
|
18
|
+
from agentcore.lib.utils.dotenv import parse as parse_dotenv
|
|
19
|
+
|
|
20
|
+
_ENV_KEY_RE = re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_env_path(config_root: str | None = None) -> str:
|
|
24
|
+
from agentcore.lib.schemas.io.path_resolver import find_config_root
|
|
25
|
+
|
|
26
|
+
root = config_root or find_config_root()
|
|
27
|
+
if not root:
|
|
28
|
+
raise RuntimeError("Could not find agentcore directory")
|
|
29
|
+
return os.path.join(root, ENV_FILE)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _serialize_env(env: Mapping[str, str | None]) -> str:
|
|
33
|
+
"""Serialise to dotenv ``KEY="value"`` lines (same escaping as upstream)."""
|
|
34
|
+
lines = []
|
|
35
|
+
for k, v in env.items():
|
|
36
|
+
if v is None:
|
|
37
|
+
continue
|
|
38
|
+
if not _ENV_KEY_RE.fullmatch(k):
|
|
39
|
+
raise ValueError(f"Invalid env key: {k}")
|
|
40
|
+
val = str(v).replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n").replace("\r", "\\r")
|
|
41
|
+
lines.append(f'{k}="{val}"')
|
|
42
|
+
return "\n".join(lines) + "\n" if lines else ""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _read_raw(path: str) -> dict[str, str]:
|
|
46
|
+
with open(path, encoding="utf-8") as fh:
|
|
47
|
+
return parse_dotenv(fh.read())
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _write(path: str, content: str) -> None:
|
|
51
|
+
with open(path, "w", encoding="utf-8", newline="") as fh:
|
|
52
|
+
fh.write(content)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def read_env_file(config_root: str | None = None) -> dict[str, str]:
|
|
56
|
+
"""Read ``.env.local``, decrypting ``enc:v1:`` values; legacy plaintext is returned as-is."""
|
|
57
|
+
path = get_env_path(config_root)
|
|
58
|
+
if not os.path.exists(path):
|
|
59
|
+
return {}
|
|
60
|
+
parsed = _read_raw(path)
|
|
61
|
+
if not any(v.startswith(ENC_PREFIX) for v in parsed.values()):
|
|
62
|
+
return parsed
|
|
63
|
+
# Try every available key so a value sealed by either source decrypts.
|
|
64
|
+
keys = resolve_candidate_keys()
|
|
65
|
+
return {k: decrypt_secret(v, keys) if v.startswith(ENC_PREFIX) else v for k, v in parsed.items()}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_env_var(key: str, config_root: str | None = None) -> str | None:
|
|
69
|
+
return read_env_file(config_root).get(key)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _needs_encryption(k: str, v: str | None) -> bool:
|
|
73
|
+
return is_sensitive_key(k) and v is not None and not str(v).startswith(ENC_PREFIX)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _encrypt_sensitive(env: Mapping[str, str | None]) -> dict[str, str | None]:
|
|
77
|
+
"""Encrypt sensitive plaintext values; leave others and already-encrypted values unchanged."""
|
|
78
|
+
if not any(_needs_encryption(k, v) for k, v in env.items()):
|
|
79
|
+
return dict(env)
|
|
80
|
+
key = resolve_encryption_key()
|
|
81
|
+
return {k: encrypt_secret(str(v), key) if _needs_encryption(k, v) else v for k, v in env.items()}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def write_env_file(updates: Mapping[str, str | None], config_root: str | None = None, merge: bool = True) -> None:
|
|
85
|
+
"""Write ``.env.local``, merging with existing values by default and encrypting secrets."""
|
|
86
|
+
path = get_env_path(config_root)
|
|
87
|
+
# Merge against the raw (still encrypted) values so unchanged secrets aren't re-encrypted.
|
|
88
|
+
current: dict[str, str | None] = dict(_read_raw(path)) if merge and os.path.exists(path) else {}
|
|
89
|
+
current.update(updates)
|
|
90
|
+
_write(path, _serialize_env(_encrypt_sensitive(current)))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def set_env_var(key: str, value: str, config_root: str | None = None) -> None:
|
|
94
|
+
write_env_file({key: value}, config_root)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def remove_env_vars(keys: Iterable[str], config_root: str | None = None) -> None:
|
|
98
|
+
path = get_env_path(config_root)
|
|
99
|
+
if not os.path.exists(path):
|
|
100
|
+
return
|
|
101
|
+
current: dict[str, str | None] = dict(_read_raw(path))
|
|
102
|
+
for key in keys:
|
|
103
|
+
current.pop(key, None)
|
|
104
|
+
# Re-encrypts any legacy plaintext among the remaining values.
|
|
105
|
+
_write(path, _serialize_env(_encrypt_sensitive(current)))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""JSON serialisation matching ``JSON.stringify(value, null, indent)`` output."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import math
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _normalize(value: Any) -> Any:
|
|
11
|
+
# JS has a single number type: 1.0 serialises as "1"; NaN/Infinity become null.
|
|
12
|
+
if isinstance(value, float):
|
|
13
|
+
if math.isnan(value) or math.isinf(value):
|
|
14
|
+
return None
|
|
15
|
+
if value.is_integer() and abs(value) < 1e21:
|
|
16
|
+
return int(value)
|
|
17
|
+
return value
|
|
18
|
+
if isinstance(value, dict):
|
|
19
|
+
return {str(k): _normalize(v) for k, v in value.items()}
|
|
20
|
+
if isinstance(value, (list, tuple)):
|
|
21
|
+
return [_normalize(v) for v in value]
|
|
22
|
+
return value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def to_json_string(value: Any, indent: int | None = 2) -> str:
|
|
26
|
+
"""Serialise like ``JSON.stringify(value, null, indent)`` (no trailing newline)."""
|
|
27
|
+
if indent is None:
|
|
28
|
+
return json.dumps(_normalize(value), ensure_ascii=False, separators=(",", ":"))
|
|
29
|
+
return json.dumps(_normalize(value), ensure_ascii=False, indent=indent)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_json_rpc_response(text: str) -> dict[str, Any]:
|
|
8
|
+
"""Parse a JSON-RPC response given as plain JSON or SSE-wrapped (``data: ...`` lines)."""
|
|
9
|
+
trimmed = text.strip()
|
|
10
|
+
try:
|
|
11
|
+
return json.loads(trimmed)
|
|
12
|
+
except ValueError:
|
|
13
|
+
pass # might be SSE format
|
|
14
|
+
|
|
15
|
+
for line in reversed(trimmed.split("\n")):
|
|
16
|
+
if line.startswith("data: "):
|
|
17
|
+
try:
|
|
18
|
+
return json.loads(line[6:])
|
|
19
|
+
except ValueError:
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
raise ValueError(f"Failed to parse JSON-RPC response: {trimmed[:200]}")
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Platform detection and cross-platform helpers (port of ``src/lib/utils/platform.ts``)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
is_windows = sys.platform == "win32"
|
|
9
|
+
is_mac_os = sys.platform == "darwin"
|
|
10
|
+
is_linux = sys.platform.startswith("linux")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_venv_executable(venv_path: str, executable: str) -> str:
|
|
14
|
+
"""Path to an executable in a Python venv (``bin/x`` on Unix, ``Scripts\\x.exe`` on Windows)."""
|
|
15
|
+
bin_dir = "Scripts" if is_windows else "bin"
|
|
16
|
+
ext = ".exe" if is_windows else ""
|
|
17
|
+
return os.path.join(venv_path, bin_dir, executable + ext)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_shell_command() -> str:
|
|
21
|
+
return "cmd" if is_windows else os.environ.get("SHELL", "/bin/sh")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_shell_args(command: str) -> list[str]:
|
|
25
|
+
return ["/c", command] if is_windows else ["-c", command]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def normalize_command(command: str) -> str:
|
|
29
|
+
"""Add ``.exe`` on Windows for well-known commands."""
|
|
30
|
+
if is_windows and not command.endswith((".exe", ".cmd", ".bat")):
|
|
31
|
+
if command.endswith(("python", "node", "npm", "git", "uvicorn", "pip")):
|
|
32
|
+
return command + ".exe"
|
|
33
|
+
return command
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Polling/retry utility (port of ``src/lib/utils/polling.ts``, synchronous)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Generic, Literal, TypeVar
|
|
9
|
+
|
|
10
|
+
from agentcore.lib.errors.types import PollExhaustedError, PollTimeoutError
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True, slots=True)
|
|
16
|
+
class PollResult(Generic[T]):
|
|
17
|
+
done: bool
|
|
18
|
+
value: T | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def poll(
|
|
22
|
+
fn: Callable[[], PollResult[T]],
|
|
23
|
+
*,
|
|
24
|
+
max_attempts: int | None = None,
|
|
25
|
+
timeout_ms: float | None = None,
|
|
26
|
+
delay_ms: float = 5000,
|
|
27
|
+
backoff_factor: float = 1,
|
|
28
|
+
max_delay_ms: float | None = None,
|
|
29
|
+
max_consecutive_errors: int | None = None,
|
|
30
|
+
on_error: Callable[[BaseException], Literal["retry", "abort"]] | None = None,
|
|
31
|
+
) -> T:
|
|
32
|
+
"""Call ``fn`` until it reports ``done``; bounded by attempts and/or wall-clock timeout."""
|
|
33
|
+
if max_attempts is None and timeout_ms is None:
|
|
34
|
+
raise ValueError("poll() requires at least one of max_attempts or timeout_ms")
|
|
35
|
+
|
|
36
|
+
start = time.monotonic()
|
|
37
|
+
elapsed_ms = lambda: (time.monotonic() - start) * 1000 # noqa: E731
|
|
38
|
+
attempts = 0
|
|
39
|
+
consecutive_errors = 0
|
|
40
|
+
current_delay = delay_ms
|
|
41
|
+
last_error: BaseException | None = None
|
|
42
|
+
|
|
43
|
+
while True:
|
|
44
|
+
if max_attempts is not None and attempts >= max_attempts:
|
|
45
|
+
raise PollExhaustedError(max_attempts, cause=last_error)
|
|
46
|
+
if timeout_ms is not None and elapsed_ms() >= timeout_ms:
|
|
47
|
+
raise PollTimeoutError(timeout_ms, cause=last_error)
|
|
48
|
+
|
|
49
|
+
attempts += 1
|
|
50
|
+
try:
|
|
51
|
+
result = fn()
|
|
52
|
+
consecutive_errors = 0
|
|
53
|
+
if result.done:
|
|
54
|
+
return result.value # type: ignore[return-value]
|
|
55
|
+
except Exception as exc:
|
|
56
|
+
if (on_error(exc) if on_error else "retry") == "abort":
|
|
57
|
+
raise
|
|
58
|
+
last_error = exc
|
|
59
|
+
consecutive_errors += 1
|
|
60
|
+
if max_consecutive_errors and consecutive_errors >= max_consecutive_errors:
|
|
61
|
+
raise PollExhaustedError(attempts, cause=last_error) from exc
|
|
62
|
+
|
|
63
|
+
# Don't sleep if that would cross the timeout.
|
|
64
|
+
if timeout_ms is not None and elapsed_ms() + current_delay >= timeout_ms:
|
|
65
|
+
raise PollTimeoutError(timeout_ms, cause=last_error)
|
|
66
|
+
|
|
67
|
+
time.sleep(current_delay / 1000)
|
|
68
|
+
current_delay = (
|
|
69
|
+
min(current_delay * backoff_factor, max_delay_ms) if max_delay_ms else current_delay * backoff_factor
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
_THROTTLING_NAMES = {"ThrottlingException", "Throttling", "TooManyRequestsException", "RequestLimitExceeded"}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def is_throttling_error(err: object) -> bool:
|
|
77
|
+
"""True for AWS throttling/rate-limit errors (botocore ClientError codes or named exceptions)."""
|
|
78
|
+
if err is None:
|
|
79
|
+
return False
|
|
80
|
+
name = ""
|
|
81
|
+
response = getattr(err, "response", None)
|
|
82
|
+
if isinstance(response, dict):
|
|
83
|
+
name = str(response.get("Error", {}).get("Code", "") or "")
|
|
84
|
+
name = name or getattr(err, "name", "") or type(err).__name__
|
|
85
|
+
message = str(getattr(err, "message", "") or (err if isinstance(err, BaseException) else ""))
|
|
86
|
+
return name in _THROTTLING_NAMES or "Rate exceeded" in message or "Throttling" in message
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Subprocess helpers (port of ``src/lib/utils/subprocess.ts``).
|
|
2
|
+
|
|
3
|
+
Nothing runs through a shell. Upstream uses cross-spawn to resolve Windows ``.cmd``/``.bat``
|
|
4
|
+
shims; here ``shutil.which`` does the same resolution before ``subprocess`` runs the command.
|
|
5
|
+
Upstream has async and sync variants; this port is synchronous only.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import shutil
|
|
12
|
+
import signal as _signal
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
from collections.abc import Mapping, Sequence
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import IO, Any, Literal
|
|
18
|
+
|
|
19
|
+
Stdio = Literal["inherit", "ignore", "pipe"] | int | IO[Any] | None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True, slots=True)
|
|
23
|
+
class SubprocessResult:
|
|
24
|
+
stdout: str
|
|
25
|
+
stderr: str
|
|
26
|
+
code: int | None
|
|
27
|
+
signal: str | None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _resolve(command: str) -> str:
|
|
31
|
+
if sys.platform == "win32":
|
|
32
|
+
return shutil.which(command) or command
|
|
33
|
+
return command
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _stdio(value: Stdio) -> Any:
|
|
37
|
+
if value == "inherit":
|
|
38
|
+
return None
|
|
39
|
+
if value == "ignore":
|
|
40
|
+
return subprocess.DEVNULL
|
|
41
|
+
if value == "pipe":
|
|
42
|
+
return subprocess.PIPE
|
|
43
|
+
return value
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _split_returncode(returncode: int) -> tuple[int | None, str | None]:
|
|
47
|
+
if returncode < 0:
|
|
48
|
+
try:
|
|
49
|
+
return None, _signal.Signals(-returncode).name
|
|
50
|
+
except ValueError:
|
|
51
|
+
return None, str(-returncode)
|
|
52
|
+
return returncode, None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _env(env: Mapping[str, str] | None) -> dict[str, str] | None:
|
|
56
|
+
return dict(env) if env is not None else None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def run_subprocess(
|
|
60
|
+
command: str,
|
|
61
|
+
args: Sequence[str],
|
|
62
|
+
*,
|
|
63
|
+
cwd: str | os.PathLike[str] | None = None,
|
|
64
|
+
env: Mapping[str, str] | None = None,
|
|
65
|
+
stdio: Stdio = "inherit",
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Run a command; raise ``RuntimeError`` on a non-zero exit (``OSError`` if it can't start)."""
|
|
68
|
+
proc = subprocess.run(
|
|
69
|
+
[_resolve(command), *args],
|
|
70
|
+
cwd=cwd,
|
|
71
|
+
env=_env(env),
|
|
72
|
+
stdin=_stdio(stdio),
|
|
73
|
+
stdout=_stdio(stdio),
|
|
74
|
+
stderr=_stdio(stdio),
|
|
75
|
+
)
|
|
76
|
+
if proc.returncode == 0:
|
|
77
|
+
return
|
|
78
|
+
code, sig = _split_returncode(proc.returncode)
|
|
79
|
+
reason = f"code {code}" if code is not None else f"signal {sig}"
|
|
80
|
+
raise RuntimeError(f"{command} exited with {reason}")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def check_subprocess(
|
|
84
|
+
command: str,
|
|
85
|
+
args: Sequence[str],
|
|
86
|
+
*,
|
|
87
|
+
cwd: str | os.PathLike[str] | None = None,
|
|
88
|
+
env: Mapping[str, str] | None = None,
|
|
89
|
+
stdio: Stdio = "ignore",
|
|
90
|
+
) -> bool:
|
|
91
|
+
"""Return True iff the command starts and exits 0."""
|
|
92
|
+
try:
|
|
93
|
+
proc = subprocess.run(
|
|
94
|
+
[_resolve(command), *args],
|
|
95
|
+
cwd=cwd,
|
|
96
|
+
env=_env(env),
|
|
97
|
+
stdin=_stdio(stdio),
|
|
98
|
+
stdout=_stdio(stdio),
|
|
99
|
+
stderr=_stdio(stdio),
|
|
100
|
+
)
|
|
101
|
+
except OSError:
|
|
102
|
+
return False
|
|
103
|
+
return proc.returncode == 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def run_subprocess_capture(
|
|
107
|
+
command: str,
|
|
108
|
+
args: Sequence[str],
|
|
109
|
+
*,
|
|
110
|
+
cwd: str | os.PathLike[str] | None = None,
|
|
111
|
+
env: Mapping[str, str] | None = None,
|
|
112
|
+
) -> SubprocessResult:
|
|
113
|
+
"""Run with piped output; never raises. Spawn failures yield ``code=-1`` and the error in stderr."""
|
|
114
|
+
try:
|
|
115
|
+
proc = subprocess.run(
|
|
116
|
+
[_resolve(command), *args],
|
|
117
|
+
cwd=cwd,
|
|
118
|
+
env=_env(env),
|
|
119
|
+
stdin=subprocess.DEVNULL,
|
|
120
|
+
capture_output=True,
|
|
121
|
+
)
|
|
122
|
+
except OSError as exc:
|
|
123
|
+
return SubprocessResult(stdout="", stderr=str(exc), code=-1, signal=None)
|
|
124
|
+
code, sig = _split_returncode(proc.returncode)
|
|
125
|
+
return SubprocessResult(
|
|
126
|
+
stdout=proc.stdout.decode("utf-8", errors="replace"),
|
|
127
|
+
stderr=proc.stderr.decode("utf-8", errors="replace"),
|
|
128
|
+
code=code,
|
|
129
|
+
signal=sig,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# Upstream keeps distinct *Sync variants for CDK bundling; in Python everything is synchronous.
|
|
134
|
+
run_subprocess_capture_sync = run_subprocess_capture
|
|
135
|
+
check_subprocess_sync = check_subprocess
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import time
|
|
5
|
+
from datetime import UTC, datetime
|
|
6
|
+
|
|
7
|
+
_RELATIVE_DURATION_RE = re.compile(r"(\d+)([smhd])")
|
|
8
|
+
_UNIT_TO_MS = {"s": 1_000, "m": 60_000, "h": 3_600_000, "d": 86_400_000}
|
|
9
|
+
_DATE_ONLY_RE = re.compile(r"\d{4}-\d{2}-\d{2}")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _now_ms() -> int:
|
|
13
|
+
return time.time_ns() // 1_000_000
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def parse_time_string(value: str) -> int:
|
|
17
|
+
"""Parse a time string into epoch milliseconds.
|
|
18
|
+
|
|
19
|
+
Supports relative durations (``5m``, ``1h``, ``2d``, ``30s``, meaning "that long ago"),
|
|
20
|
+
ISO 8601, epoch milliseconds (13+ digits) and ``now``.
|
|
21
|
+
"""
|
|
22
|
+
if not value or value.strip() == "":
|
|
23
|
+
raise ValueError("Time string cannot be empty")
|
|
24
|
+
|
|
25
|
+
trimmed = value.strip()
|
|
26
|
+
if trimmed == "now":
|
|
27
|
+
return _now_ms()
|
|
28
|
+
|
|
29
|
+
match = _RELATIVE_DURATION_RE.fullmatch(trimmed)
|
|
30
|
+
if match:
|
|
31
|
+
return _now_ms() - int(match.group(1)) * _UNIT_TO_MS[match.group(2)]
|
|
32
|
+
|
|
33
|
+
if re.fullmatch(r"\d{13,}", trimmed):
|
|
34
|
+
return int(trimmed)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
parsed = datetime.fromisoformat(trimmed)
|
|
38
|
+
except ValueError:
|
|
39
|
+
parsed = None
|
|
40
|
+
if parsed is not None:
|
|
41
|
+
# Like JS Date: date-only forms are UTC; date-times without an offset are local time.
|
|
42
|
+
if parsed.tzinfo is None and _DATE_ONLY_RE.fullmatch(trimmed):
|
|
43
|
+
parsed = parsed.replace(tzinfo=UTC)
|
|
44
|
+
return int(parsed.timestamp() * 1000)
|
|
45
|
+
|
|
46
|
+
raise ValueError(
|
|
47
|
+
f'Invalid time string: "{value}". Use relative durations (5m, 1h, 2d), ISO 8601, epoch ms, or "now".'
|
|
48
|
+
)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Schema validation helpers (port of ``src/lib/utils/zod.ts`` for Pydantic models)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from functools import lru_cache
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, TypeAdapter
|
|
10
|
+
from pydantic import ValidationError as PydanticValidationError
|
|
11
|
+
|
|
12
|
+
_ABSENT: Any = object()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@lru_cache(maxsize=512)
|
|
16
|
+
def _field_adapter(model: type[BaseModel], name: str) -> TypeAdapter[Any]:
|
|
17
|
+
from typing import Annotated
|
|
18
|
+
|
|
19
|
+
info = model.model_fields[name]
|
|
20
|
+
annotation = info.annotation
|
|
21
|
+
if info.metadata:
|
|
22
|
+
annotation = Annotated[(annotation, *info.metadata)] # type: ignore[valid-type]
|
|
23
|
+
return TypeAdapter(annotation)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _nested_model(annotation: Any) -> type[BaseModel] | None:
|
|
27
|
+
"""Unwrap Optional/Union-with-None to a single BaseModel type, if that's what it is."""
|
|
28
|
+
import types
|
|
29
|
+
import typing
|
|
30
|
+
|
|
31
|
+
if isinstance(annotation, type) and issubclass(annotation, BaseModel):
|
|
32
|
+
return annotation
|
|
33
|
+
if typing.get_origin(annotation) in (typing.Union, types.UnionType):
|
|
34
|
+
args = [a for a in typing.get_args(annotation) if a is not type(None)]
|
|
35
|
+
if len(args) == 1:
|
|
36
|
+
return _nested_model(args[0])
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def resilient_parse(
|
|
41
|
+
model: type[BaseModel],
|
|
42
|
+
data: Any,
|
|
43
|
+
*,
|
|
44
|
+
fallback: Any = _ABSENT,
|
|
45
|
+
fill_missing: bool = False,
|
|
46
|
+
keep_unknown: bool = True,
|
|
47
|
+
) -> dict[str, Any]:
|
|
48
|
+
"""Validate ``data`` against ``model`` field by field; invalid fields fall back instead of raising.
|
|
49
|
+
|
|
50
|
+
Keys use the field's alias (the on-disk JSON name). Nested models are parsed recursively.
|
|
51
|
+
With the default ``fallback`` (upstream's ``undefined``), invalid or missing fields are
|
|
52
|
+
simply omitted from the result.
|
|
53
|
+
"""
|
|
54
|
+
if not isinstance(data, Mapping):
|
|
55
|
+
return {}
|
|
56
|
+
result: dict[str, Any] = {}
|
|
57
|
+
known: set[str] = set()
|
|
58
|
+
for name, info in model.model_fields.items():
|
|
59
|
+
key = info.alias or name
|
|
60
|
+
known.add(key)
|
|
61
|
+
if key not in data:
|
|
62
|
+
if fill_missing and fallback is not _ABSENT:
|
|
63
|
+
result[key] = fallback
|
|
64
|
+
continue
|
|
65
|
+
value = data[key]
|
|
66
|
+
nested = _nested_model(info.annotation)
|
|
67
|
+
if nested is not None and isinstance(value, Mapping):
|
|
68
|
+
result[key] = resilient_parse(
|
|
69
|
+
nested, value, fallback=fallback, fill_missing=fill_missing, keep_unknown=keep_unknown
|
|
70
|
+
)
|
|
71
|
+
continue
|
|
72
|
+
try:
|
|
73
|
+
adapter = _field_adapter(model, name)
|
|
74
|
+
result[key] = adapter.dump_python(adapter.validate_python(value), mode="json", by_alias=True)
|
|
75
|
+
except PydanticValidationError:
|
|
76
|
+
if fallback is not _ABSENT:
|
|
77
|
+
result[key] = fallback
|
|
78
|
+
if keep_unknown:
|
|
79
|
+
for key, value in data.items():
|
|
80
|
+
if key not in known:
|
|
81
|
+
result[key] = value
|
|
82
|
+
return result
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _issues_message(exc: PydanticValidationError) -> str:
|
|
86
|
+
return "; ".join(f"{'.'.join(str(p) for p in e['loc'])}: {e['msg']}" for e in exc.errors())
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def validate_agent_schema(spec: Any) -> Any:
|
|
90
|
+
"""Validate an agent spec; raises ``ValueError("Invalid AgentEnvSpec: ...")``."""
|
|
91
|
+
from agentcore.schema import AgentEnvSpec # type: ignore[attr-defined]
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
return AgentEnvSpec.model_validate(spec)
|
|
95
|
+
except PydanticValidationError as exc:
|
|
96
|
+
raise ValueError(f"Invalid AgentEnvSpec: {_issues_message(exc)}") from exc
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def validate_project_schema(spec: Any) -> Any:
|
|
100
|
+
"""Validate a project spec; raises ``ValueError("Invalid AgentCoreProjectSpec: ...")``."""
|
|
101
|
+
from agentcore.schema import AgentCoreProjectSpec # type: ignore[attr-defined]
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
return AgentCoreProjectSpec.model_validate(spec)
|
|
105
|
+
except PydanticValidationError as exc:
|
|
106
|
+
raise ValueError(f"Invalid AgentCoreProjectSpec: {_issues_message(exc)}") from exc
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""CLI loggers (port of upstream ``src/cli/logging``)."""
|
|
2
|
+
|
|
3
|
+
from agentcore.logging.cdk_io_host import create_cdk_io_host
|
|
4
|
+
from agentcore.logging.create_logger import CreateLogger
|
|
5
|
+
from agentcore.logging.dev_logger import DevLogger
|
|
6
|
+
from agentcore.logging.exec_logger import ExecLogger
|
|
7
|
+
from agentcore.logging.invoke_logger import InvokeLogger
|
|
8
|
+
from agentcore.logging.remove_logger import RemoveLogger
|
|
9
|
+
|
|
10
|
+
__all__ = ["CreateLogger", "DevLogger", "ExecLogger", "InvokeLogger", "RemoveLogger", "create_cdk_io_host"]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Formatting helpers shared by the CLI loggers (duplicated per class upstream)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
import time
|
|
7
|
+
from datetime import UTC, datetime
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
ANSI_REGEX = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def strip_ansi(s: str) -> str:
|
|
14
|
+
return ANSI_REGEX.sub("", s)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def now_ms() -> int:
|
|
18
|
+
return int(time.time() * 1000)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def format_timestamp_for_filename(date: datetime) -> str:
|
|
22
|
+
"""YYYYMMDD-HHMMSS in local time."""
|
|
23
|
+
return date.strftime("%Y%m%d-%H%M%S")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def format_time(date: datetime | None = None, with_ms: bool = False) -> str:
|
|
27
|
+
"""HH:MM:SS (or HH:MM:SS.mmm) in local time."""
|
|
28
|
+
date = date or datetime.now()
|
|
29
|
+
text = date.strftime("%H:%M:%S")
|
|
30
|
+
return f"{text}.{date.microsecond // 1000:03d}" if with_ms else text
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def iso_now(date: datetime | None = None) -> str:
|
|
34
|
+
"""JavaScript ``Date.toISOString()``: UTC with millisecond precision and a ``Z`` suffix."""
|
|
35
|
+
date = (date or datetime.now()).astimezone(UTC)
|
|
36
|
+
return date.strftime("%Y-%m-%dT%H:%M:%S.") + f"{date.microsecond // 1000:03d}Z"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def format_duration(ms: int) -> str:
|
|
40
|
+
if ms < 1000:
|
|
41
|
+
return f"{ms}ms"
|
|
42
|
+
seconds = ms / 1000
|
|
43
|
+
if seconds < 60:
|
|
44
|
+
return f"{seconds:.1f}s"
|
|
45
|
+
minutes = int(seconds // 60)
|
|
46
|
+
remaining = round(seconds % 60)
|
|
47
|
+
return f"{minutes}m {remaining}s"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def osc8_link(file_path: str) -> str:
|
|
51
|
+
url = f"file://{file_path}"
|
|
52
|
+
display = os.path.relpath(file_path, os.getcwd())
|
|
53
|
+
return f"\x1b]8;;{url}\x1b\\{display}\x1b]8;;\x1b\\"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def append(file_path: str, text: str) -> None:
|
|
57
|
+
with open(file_path, "a", encoding="utf-8") as f:
|
|
58
|
+
f.write(text)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def write(file_path: str, text: str) -> None:
|
|
62
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
63
|
+
f.write(text)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def js_json(value: Any, indent: int | None = 2) -> str:
|
|
67
|
+
"""``JSON.stringify(value, null, indent)`` with ``None`` values in dicts treated as undefined."""
|
|
68
|
+
|
|
69
|
+
def clean(v: Any) -> Any:
|
|
70
|
+
if isinstance(v, dict):
|
|
71
|
+
return {k: clean(x) for k, x in v.items() if x is not None}
|
|
72
|
+
if isinstance(v, (list, tuple)):
|
|
73
|
+
return [clean(x) for x in v]
|
|
74
|
+
return v
|
|
75
|
+
|
|
76
|
+
separators = (",", ":") if indent is None else None
|
|
77
|
+
return json.dumps(clean(value), indent=indent, separators=separators, ensure_ascii=False, default=str)
|