digitalkin 1.0.4.dev0__tar.gz → 1.0.4.dev2__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.
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/PKG-INFO +2 -2
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/pyproject.toml +2 -2
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/__version__.py +1 -1
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/action.py +45 -26
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/base.py +10 -9
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/services/action.py +47 -23
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/services/kit.py +4 -2
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/module_servicer.py +24 -5
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/setup/default_setup.py +63 -26
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/setup/grpc_setup.py +37 -26
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/setup/setup_strategy.py +32 -12
- digitalkin-1.0.4.dev2/src/digitalkin/utils/json_structure.py +169 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/setup_content_validator.py +41 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin.egg-info/PKG-INFO +2 -2
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin.egg-info/requires.txt +1 -1
- digitalkin-1.0.4.dev0/src/digitalkin/utils/json_structure.py +0 -363
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/LICENSE +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/README.md +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/echo_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/models/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/models/input.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/models/output.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/models/secret.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/models/setup.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/server.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/triggers/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/bench_module/triggers/message_trigger.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/modules/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/modules/archetype_with_tools_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/modules/dynamic_setup_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/monitoring/tests/test_metrics.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/client.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/echo_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/models/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/models/input.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/models/output.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/models/secret.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/models/setup.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/server.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/triggers/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/redis_demo/triggers/message_trigger.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/services/filesystem_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/examples/services/storage_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/setup.cfg +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/agno_adapter.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/agui_tools.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/hitl.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/models.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/module_toolkit.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/base.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/defaults.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/kins/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/kins/action.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/kins/kit.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/loader/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/loader/action.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/loader/kit.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/services/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/tools/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/tools/action.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/registry/tools/kit.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/common/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/common/factories.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/job_manager/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/profiling/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/profiling/step_timer.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/profiling/task_profiler.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/resilience/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/resilience/bulkhead.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/module_runner.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/redis/redis_state.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/task_executor.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/core/task_manager/task_session.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/_base_server.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/gateway_servicer.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/module_server.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/stream_session.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/logger.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/agui_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/base_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/cost_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/file_history_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/logger_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/mixins/storage_mixin.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/core/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/core/job_manager_models.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/core/redis.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/core/task_monitor.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/events/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/events/agent_events.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/grpc_servers/models.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/grpc_servers/types.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/ag_ui.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/base_types.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/loaded_tools.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/module_context.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/module_types.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/request_metadata.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/select_schema.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/setup_types.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/tool_cache.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/tool_reference.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/module/utility.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/services/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/services/registry.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/services/services.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/gateway.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/grpc_client.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/log.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/profiling.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/queue.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/redis.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/registry.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/resilience.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/server/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/server/channel.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/server/grpc.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/server/server.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/server/servicer.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/task_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/utils/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/settings/utils/channel.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/utils/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/_base_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/trigger_handler.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/triggers/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/py.typed +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/communication/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/communication/communication_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/communication/default_communication.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/communication/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/communication/grpc_communication.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/cost/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/filesystem/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/registry/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/registry/grpc_registry.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/registry/registry_models.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/registry/registry_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/secret/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/secret/default_secret.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/secret/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/secret/grpc_secret.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/secret/secret_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/services_config.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/services_models.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/setup/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/storage/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/task_manager/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/task_manager/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/user_profile/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/user_profile/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/conditional_schema.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/dynamic_schema.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/exceptions.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/package_discover.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/proto_utils.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/utils/schema_splitter.py +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin.egg-info/SOURCES.txt +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin.egg-info/top_level.txt +0 -0
- {digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/tests/test_exceptions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: digitalkin
|
|
3
|
-
Version: 1.0.4.
|
|
3
|
+
Version: 1.0.4.dev2
|
|
4
4
|
Summary: SDK to build kin used in DigitalKin
|
|
5
5
|
Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
|
|
6
6
|
License: Attribution-NonCommercial-ShareAlike 4.0 International
|
|
@@ -453,7 +453,7 @@ Requires-Python: >=3.10
|
|
|
453
453
|
Description-Content-Type: text/markdown
|
|
454
454
|
License-File: LICENSE
|
|
455
455
|
Requires-Dist: ag-ui-protocol==0.1.21.dev1787220377
|
|
456
|
-
Requires-Dist: agentic-mesh-protocol==1.0.2.
|
|
456
|
+
Requires-Dist: agentic-mesh-protocol==1.0.2.dev2
|
|
457
457
|
Requires-Dist: agno<3,>=2.8.0
|
|
458
458
|
Requires-Dist: anyio>=4.13.0
|
|
459
459
|
Requires-Dist: grpcio-health-checking==1.82.1
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
# which is how a nested run's output is attributed to its author. Pinned exactly
|
|
32
32
|
# because it is a dated prerelease; move to >=0.1.21 once that ships stable.
|
|
33
33
|
"ag-ui-protocol==0.1.21.dev1787220377",
|
|
34
|
-
"agentic-mesh-protocol==1.0.2.
|
|
34
|
+
"agentic-mesh-protocol==1.0.2.dev2",
|
|
35
35
|
"agno>=2.8.0,<3",
|
|
36
36
|
"anyio>=4.13.0",
|
|
37
37
|
"grpcio-health-checking==1.82.1",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"pydantic>=2.12.4",
|
|
42
42
|
"redis[hiredis]>=7.4.0,<9",
|
|
43
43
|
]
|
|
44
|
-
version = "1.0.4.
|
|
44
|
+
version = "1.0.4.dev2"
|
|
45
45
|
|
|
46
46
|
[project.optional-dependencies]
|
|
47
47
|
agno = [ "agno>=2.6" ]
|
|
@@ -23,6 +23,7 @@ from digitalkin.models.services.registry import (
|
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
25
|
from digitalkin.community.agno.toolkits.registry.base import RegistryActionCtx
|
|
26
|
+
from digitalkin.models.services.registry import SetupSummary
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class GetAction(RegistryAction):
|
|
@@ -124,26 +125,36 @@ class SearchAction(RegistryAction):
|
|
|
124
125
|
# would both contradict ``total_returned`` and, at exactly ``cap`` rows, promise an empty
|
|
125
126
|
# next page.
|
|
126
127
|
truncated = len(usable) > cap
|
|
127
|
-
rows = [
|
|
128
|
-
{
|
|
129
|
-
"setup_id": setup.setup_id,
|
|
130
|
-
"name": setup.name,
|
|
131
|
-
"module_name": setup.module_name,
|
|
132
|
-
"version": setup.setup_version,
|
|
133
|
-
# Echoed because they are filterable: a caller cannot use the ``tags``,
|
|
134
|
-
# ``visibilities`` or ``statuses`` filters without first seeing the values in use.
|
|
135
|
-
"tags": setup.tags,
|
|
136
|
-
"visibility": setup.visibility.value if setup.visibility else None,
|
|
137
|
-
"status": setup.status.value if setup.status else None,
|
|
138
|
-
"description": (setup.documentation or "")[: self._DOC_PREVIEW_CHARS],
|
|
139
|
-
# The shape of the configuration, so choosing a scope needs no second call:
|
|
140
|
-
# read a key from here and pass it to ``load``.
|
|
141
|
-
"structure": setup.structure,
|
|
142
|
-
}
|
|
143
|
-
for setup in usable[:cap]
|
|
144
|
-
]
|
|
128
|
+
rows = [self._row(setup) for setup in usable[:cap]]
|
|
145
129
|
return {"total_returned": len(rows), "truncated": truncated, "offset": self.offset, "setups": rows}
|
|
146
130
|
|
|
131
|
+
def _row(self, setup: SetupSummary) -> dict[str, Any]:
|
|
132
|
+
"""Trim one search hit to the fields a caller can act on.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
setup: The summary returned by the registry.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
The rendered row.
|
|
139
|
+
"""
|
|
140
|
+
row: dict[str, Any] = {
|
|
141
|
+
"setup_id": setup.setup_id,
|
|
142
|
+
"name": setup.name,
|
|
143
|
+
"module_name": setup.module_name,
|
|
144
|
+
"version": setup.setup_version,
|
|
145
|
+
# Echoed because they are filterable: a caller cannot use the ``tags``,
|
|
146
|
+
# ``visibilities`` or ``statuses`` filters without first seeing the values in use.
|
|
147
|
+
"tags": setup.tags,
|
|
148
|
+
"visibility": setup.visibility.value if setup.visibility else None,
|
|
149
|
+
"status": setup.status.value if setup.status else None,
|
|
150
|
+
"description": (setup.documentation or "")[: self._DOC_PREVIEW_CHARS],
|
|
151
|
+
}
|
|
152
|
+
# Only service setups carry a map. Omitting the key rather than rendering an empty
|
|
153
|
+
# one keeps the feature out of the tools and kins surfaces entirely.
|
|
154
|
+
if setup.structure:
|
|
155
|
+
row["structure"] = setup.structure
|
|
156
|
+
return row
|
|
157
|
+
|
|
147
158
|
|
|
148
159
|
class UpdateAction(RegistryAction):
|
|
149
160
|
"""Update an instance: cut a new version of its configuration, and rename it.
|
|
@@ -169,16 +180,21 @@ class UpdateAction(RegistryAction):
|
|
|
169
180
|
"without changing what the instance currently serves, then activate it later with "
|
|
170
181
|
"``set_version``.",
|
|
171
182
|
)
|
|
172
|
-
|
|
183
|
+
documentation: str | None = Field(
|
|
173
184
|
default=None,
|
|
174
|
-
description="
|
|
175
|
-
"
|
|
176
|
-
|
|
177
|
-
'. [ ] " or \\ (limits["max.tokens"]), index a list element (tools[0]). Omitting it '
|
|
178
|
-
"replaces the stored map with one derived from the raw values, losing every written "
|
|
179
|
-
"summary — supply it whenever the instance had one.",
|
|
185
|
+
description="Free text describing what this instance is for, indexed by ``search``. "
|
|
186
|
+
"Omit to keep the text the instance already has; pass a string to replace it, or an "
|
|
187
|
+
"empty string to clear it.",
|
|
180
188
|
)
|
|
181
189
|
|
|
190
|
+
def _type_payload(self) -> dict[str, Any]: # ruff: ignore[no-self-use]
|
|
191
|
+
"""Fields this object type adds to the update.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Nothing by default; ``services_manager`` overrides it to refresh the structure map.
|
|
195
|
+
"""
|
|
196
|
+
return {}
|
|
197
|
+
|
|
182
198
|
async def execute(self, ctx: RegistryActionCtx) -> Any:
|
|
183
199
|
"""Cut a new version of the setup's content and rename it.
|
|
184
200
|
|
|
@@ -196,7 +212,10 @@ class UpdateAction(RegistryAction):
|
|
|
196
212
|
"name": self.name,
|
|
197
213
|
"content": self.content,
|
|
198
214
|
"set_as_current": self.set_as_current,
|
|
199
|
-
"
|
|
215
|
+
"documentation": (
|
|
216
|
+
setup.current_setup_version.documentation if self.documentation is None else self.documentation
|
|
217
|
+
),
|
|
218
|
+
**self._type_payload(),
|
|
200
219
|
})
|
|
201
220
|
|
|
202
221
|
|
|
@@ -171,22 +171,23 @@ class RegistryAction(BaseAction[RegistryActionCtx], ABC):
|
|
|
171
171
|
|
|
172
172
|
writes: ClassVar[bool] = False
|
|
173
173
|
|
|
174
|
-
@field_validator("name", check_fields=False)
|
|
174
|
+
@field_validator("name", "documentation", check_fields=False)
|
|
175
175
|
@classmethod
|
|
176
|
-
def
|
|
177
|
-
"""Reject control characters in
|
|
176
|
+
def _text_has_no_control_chars(cls, value: str | None) -> str | None:
|
|
177
|
+
"""Reject control characters in user-facing free text so it fails loudly, not silently.
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
escape would reach persistence and be stripped there, altering the value without
|
|
181
|
-
the caller. Applies to any action declaring
|
|
179
|
+
``name`` and ``documentation`` bypass the content validator, so without this a NUL byte
|
|
180
|
+
or ANSI escape would reach persistence and be stripped there, altering the value without
|
|
181
|
+
telling the caller. Applies to any action declaring either (update, service create).
|
|
182
|
+
``None`` is the "leave unchanged" marker on update and has nothing to check.
|
|
182
183
|
|
|
183
184
|
Returns:
|
|
184
|
-
The
|
|
185
|
+
The value unchanged when clean.
|
|
185
186
|
|
|
186
187
|
Raises:
|
|
187
|
-
ValueError: The
|
|
188
|
+
ValueError: The value carries a control character.
|
|
188
189
|
"""
|
|
189
|
-
return SetupContentValidator.reject_control_chars(value)
|
|
190
|
+
return value if value is None else SetupContentValidator.reject_control_chars(value)
|
|
190
191
|
|
|
191
192
|
@field_validator("content", check_fields=False)
|
|
192
193
|
@classmethod
|
|
@@ -24,7 +24,6 @@ from digitalkin.community.agno.toolkits.registry.action import (
|
|
|
24
24
|
UpdateAction,
|
|
25
25
|
)
|
|
26
26
|
from digitalkin.community.agno.toolkits.registry.base import RegistryAction
|
|
27
|
-
from digitalkin.utils.json_structure import JsonStructure
|
|
28
27
|
|
|
29
28
|
if TYPE_CHECKING:
|
|
30
29
|
from digitalkin.community.agno.toolkits.registry.base import RegistryActionCtx
|
|
@@ -50,6 +49,12 @@ class CreateServiceAction(RegistryAction):
|
|
|
50
49
|
description="The service configuration (a non-empty JSON object). "
|
|
51
50
|
"Note: JSON numbers round-trip as floats over the wire.",
|
|
52
51
|
)
|
|
52
|
+
documentation: str = Field(
|
|
53
|
+
default="",
|
|
54
|
+
description="Free text describing what this service is for and when to use it. It is "
|
|
55
|
+
"what ``search`` matches on and previews back, so a service created without it is "
|
|
56
|
+
"findable only by name.",
|
|
57
|
+
)
|
|
53
58
|
structure: dict[str, str] = Field(
|
|
54
59
|
...,
|
|
55
60
|
description="Map of key path -> one-line summary of what lives at it. This is what "
|
|
@@ -58,17 +63,19 @@ class CreateServiceAction(RegistryAction):
|
|
|
58
63
|
"content it describes. Cover each key worth finding on its own; point at a whole "
|
|
59
64
|
"section instead when it is only ever read as a unit. Path syntax: join nested keys "
|
|
60
65
|
'with "." (llm.model); bracket-quote a key containing . [ ] " or \\ '
|
|
61
|
-
'(limits["max.tokens"]); index a list element (tools[0]).
|
|
62
|
-
"
|
|
66
|
+
'(limits["max.tokens"]); index a list element (tools[0]). Keep each description under '
|
|
67
|
+
"512 characters — longer ones are trimmed.",
|
|
63
68
|
)
|
|
64
69
|
|
|
65
70
|
async def execute(self, ctx: RegistryActionCtx) -> Any:
|
|
66
|
-
"""Create the service setup from its name, content and authored key map.
|
|
71
|
+
"""Create the service setup from its name, content, documentation and authored key map.
|
|
67
72
|
|
|
68
73
|
Returns:
|
|
69
74
|
The created service setup.
|
|
70
75
|
"""
|
|
71
|
-
return await ctx.setup.create_service_setup(
|
|
76
|
+
return await ctx.setup.create_service_setup(
|
|
77
|
+
self.name, self.content, documentation=self.documentation, structure=self.structure
|
|
78
|
+
)
|
|
72
79
|
|
|
73
80
|
|
|
74
81
|
class StructureServiceAction(RegistryAction):
|
|
@@ -106,8 +113,9 @@ class LoadServiceAction(RegistryAction):
|
|
|
106
113
|
key: str | None = Field(
|
|
107
114
|
default=None,
|
|
108
115
|
description="One key path copied verbatim from the service's structure map, to read just "
|
|
109
|
-
"that part of the configuration.
|
|
110
|
-
"
|
|
116
|
+
"that part of the configuration. Copy it, do not compose it: a key the configuration "
|
|
117
|
+
"does not have is not an error, it returns the whole document. Omit the key to load "
|
|
118
|
+
"everything deliberately, when the configuration is small or genuinely needed in full.",
|
|
111
119
|
)
|
|
112
120
|
|
|
113
121
|
async def execute(self, ctx: RegistryActionCtx) -> Any:
|
|
@@ -115,25 +123,41 @@ class LoadServiceAction(RegistryAction):
|
|
|
115
123
|
|
|
116
124
|
Guards the object type first: without it ``load`` would happily return a tool's
|
|
117
125
|
internal configuration — the most dangerous type-confusion, since the response
|
|
118
|
-
carries no field the caller could use to notice it read the wrong kind.
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
carries no field the caller could use to notice it read the wrong kind. The read
|
|
127
|
+
itself passes ``key`` to the setup service, so the narrowing happens where the
|
|
128
|
+
document lives; a key the configuration does not have returns the whole document
|
|
129
|
+
rather than an error, which is what the wire does.
|
|
121
130
|
|
|
122
131
|
Returns:
|
|
123
|
-
|
|
132
|
+
``{key: value}`` for a key that resolves, otherwise the whole configuration.
|
|
133
|
+
"""
|
|
134
|
+
await ctx.ensure_kind(self.setup_id)
|
|
135
|
+
setup = await ctx.setup.get_setup({"setup_id": self.setup_id, "structure_key": self.key or ""})
|
|
136
|
+
return setup.current_setup_version.content
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class UpdateServiceAction(UpdateAction):
|
|
140
|
+
"""Update a service, refreshing the key map alongside the configuration.
|
|
141
|
+
|
|
142
|
+
The map belongs to the content it describes, so a new revision needs a new one; the
|
|
143
|
+
stored map is replaced by whatever this call carries.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
structure: dict[str, str] | None = Field(
|
|
147
|
+
default=None,
|
|
148
|
+
description="Refreshed map of key path -> one-line description of what lives at that "
|
|
149
|
+
"leaf, describing the content this call carries. Same form and same 512-character limit "
|
|
150
|
+
"as on create. Omitting it leaves the new revision without a map, so other agents can no "
|
|
151
|
+
"longer see the service's shape — resupply it whenever the service had one.",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def _type_payload(self) -> dict[str, Any]:
|
|
155
|
+
"""Carry the refreshed map onto the new revision.
|
|
124
156
|
|
|
125
|
-
|
|
126
|
-
|
|
157
|
+
Returns:
|
|
158
|
+
The ``structure`` entry for the update payload.
|
|
127
159
|
"""
|
|
128
|
-
|
|
129
|
-
content = setup.current_setup_version.content
|
|
130
|
-
if self.key is None:
|
|
131
|
-
return content
|
|
132
|
-
found = JsonStructure.resolve(content, [self.key])
|
|
133
|
-
if self.key not in found:
|
|
134
|
-
msg = f"{self.key!r} is not a key of this configuration; copy one from its structure"
|
|
135
|
-
raise ValueError(msg)
|
|
136
|
-
return found[self.key]
|
|
160
|
+
return {"structure": self.structure}
|
|
137
161
|
|
|
138
162
|
|
|
139
163
|
ServiceActions = Annotated[
|
|
@@ -142,7 +166,7 @@ ServiceActions = Annotated[
|
|
|
142
166
|
| SearchAction
|
|
143
167
|
| StructureServiceAction
|
|
144
168
|
| LoadServiceAction
|
|
145
|
-
|
|
|
169
|
+
| UpdateServiceAction
|
|
146
170
|
| DeleteAction
|
|
147
171
|
| ChangeVisibilityAction
|
|
148
172
|
| ListVersionsAction
|
|
@@ -43,8 +43,10 @@ class ServicesManager(RegistryObjectToolKit):
|
|
|
43
43
|
"Configurations can be large, so read them in two steps: 'search' returns each "
|
|
44
44
|
"result with a 'structure' map of key path -> what lives there ('structure' fetches "
|
|
45
45
|
"the same map for an id you already hold), then 'load' with a key copied verbatim "
|
|
46
|
-
"from it returns just that part.
|
|
47
|
-
"
|
|
46
|
+
"from it returns just that part. Copy the key, never invent one: a key the "
|
|
47
|
+
"configuration does not have quietly returns everything. Load without a key only when "
|
|
48
|
+
"the whole document is genuinely needed. On create and update you write that map "
|
|
49
|
+
"yourself, describing what "
|
|
48
50
|
"each key is for — it is how other agents find their way around the configuration."
|
|
49
51
|
),
|
|
50
52
|
entrypoint=self.services_manager,
|
{digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/grpc_servers/module_servicer.py
RENAMED
|
@@ -16,6 +16,7 @@ from agentic_mesh_protocol.module.v1 import (
|
|
|
16
16
|
)
|
|
17
17
|
from agentic_mesh_protocol.user_profile.v1 import user_profile_pb2
|
|
18
18
|
from google.protobuf import json_format, struct_pb2
|
|
19
|
+
from pydantic import ValidationError
|
|
19
20
|
|
|
20
21
|
from digitalkin.core.job_manager.base_job_manager import BaseJobManager
|
|
21
22
|
from digitalkin.core.job_manager.single_job_manager import SingleJobManager
|
|
@@ -393,11 +394,29 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
|
|
|
393
394
|
return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
|
|
394
395
|
# Invalidate cached setup so concurrent/subsequent starts refetch the reconfigured version
|
|
395
396
|
self._setup_cache.pop(setup_version.setup_id, None)
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
397
|
+
try:
|
|
398
|
+
config_setup_data = self.module_class.create_config_setup_model(json_format.MessageToDict(request.content))
|
|
399
|
+
setup_version_data = await self.module_class.create_setup_model(
|
|
400
|
+
json_format.MessageToDict(request.setup_version.content),
|
|
401
|
+
config_fields=True,
|
|
402
|
+
)
|
|
403
|
+
except ValidationError as error:
|
|
404
|
+
# Without this the pydantic error escapes the servicer and grpc reports UNKNOWN
|
|
405
|
+
# with a stack trace, so a malformed setup reads as an SDK crash. Name the fields
|
|
406
|
+
# instead: the sender is the only one who can fix them.
|
|
407
|
+
fields = ", ".join(".".join(str(part) for part in item["loc"]) for item in error.errors())
|
|
408
|
+
msg = (
|
|
409
|
+
f"setup version {setup_version.id} does not match the module's setup model (missing/invalid: {fields})"
|
|
410
|
+
)
|
|
411
|
+
logger.error(
|
|
412
|
+
"ConfigSetupModule rejected setup_version=%s: %s",
|
|
413
|
+
setup_version.id,
|
|
414
|
+
error,
|
|
415
|
+
extra={"mission_id": request.mission_id},
|
|
416
|
+
)
|
|
417
|
+
context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
|
|
418
|
+
context.set_details(msg)
|
|
419
|
+
return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
|
|
401
420
|
|
|
402
421
|
if not setup_version_data:
|
|
403
422
|
msg = "No setup data returned."
|
{digitalkin-1.0.4.dev0 → digitalkin-1.0.4.dev2}/src/digitalkin/services/setup/default_setup.py
RENAMED
|
@@ -18,6 +18,7 @@ from digitalkin.services.setup.setup_strategy import (
|
|
|
18
18
|
SetupVersionPage,
|
|
19
19
|
)
|
|
20
20
|
from digitalkin.utils.json_structure import JsonStructure
|
|
21
|
+
from digitalkin.utils.setup_content_validator import SetupContentValidator
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class DefaultSetup(SetupStrategy):
|
|
@@ -70,30 +71,66 @@ class DefaultSetup(SetupStrategy):
|
|
|
70
71
|
'structure_key'.
|
|
71
72
|
|
|
72
73
|
Returns:
|
|
73
|
-
The setup
|
|
74
|
-
|
|
75
|
-
projection of that one path — the local mirror of server-side projection.
|
|
76
|
-
An empty key is treated as absent, because GetSetupRequest.structure_key has
|
|
77
|
-
no proto3 presence and the wire cannot tell the two apart.
|
|
74
|
+
The setup shaped as ``GetSetupResponse`` would carry it — see
|
|
75
|
+
:meth:`_as_wire_read` for the three ways that differs from the stored record.
|
|
78
76
|
|
|
79
77
|
Raises:
|
|
80
78
|
SetupServiceError: setup_id does not exist.
|
|
81
79
|
"""
|
|
82
80
|
setup = self._get_or_raise(setup_dict.get("setup_id", ""))
|
|
83
|
-
|
|
81
|
+
return self._as_wire_read(setup, setup_dict.get("structure_key") or "")
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def _as_wire_read(cls, setup: SetupData, key: str) -> SetupData:
|
|
85
|
+
"""Copy a stored setup down to what a read can actually return.
|
|
86
|
+
|
|
87
|
+
Two ways a read differs from the record, both forced by the protocol:
|
|
88
|
+
the content is projected to ``key``, and the structure map is dropped because
|
|
89
|
+
``GetSetupResponse`` has no field to carry it. Mirroring the second matters as much
|
|
90
|
+
as the first — serving a map here that the gRPC strategy cannot would let code work
|
|
91
|
+
locally and lose the map in production.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
setup: The stored setup.
|
|
95
|
+
key: The requested key path; empty means the whole document.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
A copy safe to hand back; the stored record is untouched.
|
|
99
|
+
"""
|
|
100
|
+
version = setup.current_setup_version
|
|
101
|
+
return setup.model_copy(
|
|
102
|
+
update={
|
|
103
|
+
"current_setup_version": version.model_copy(
|
|
104
|
+
update={"content": cls._project(version.content, key), "structure": {}}
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def _project(content: dict[str, Any], key: str) -> dict[str, Any]:
|
|
111
|
+
"""Narrow a version's content to one key path.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
content: The stored content.
|
|
115
|
+
key: The requested key path; empty means the whole document.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
``{key: value}`` when the path resolves, otherwise the whole document — an
|
|
119
|
+
empty key and an unresolvable one both return everything, which is what the
|
|
120
|
+
backend sends and what ``structure_key``'s lack of proto3 presence forces.
|
|
121
|
+
"""
|
|
84
122
|
if not key:
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
projected.current_setup_version.content = JsonStructure.resolve(setup.current_setup_version.content, [key])
|
|
88
|
-
return projected
|
|
123
|
+
return content
|
|
124
|
+
return JsonStructure.resolve(content, [key]) or content
|
|
89
125
|
|
|
90
126
|
async def create_setup(self, setup_dict: dict[str, Any]) -> SetupData:
|
|
91
127
|
"""Create a new setup; identifiers are generated locally.
|
|
92
128
|
|
|
93
129
|
Args:
|
|
94
|
-
setup_dict: Dictionary with 'name', 'content'
|
|
95
|
-
|
|
96
|
-
|
|
130
|
+
setup_dict: Dictionary with 'name', 'content', optional 'documentation' and
|
|
131
|
+
optional 'structure' — the ``{key path: description}`` map the agent
|
|
132
|
+
wrote for ``content``, stored as written with only each description's
|
|
133
|
+
length bounded.
|
|
97
134
|
|
|
98
135
|
Returns:
|
|
99
136
|
The created setup with its initial version.
|
|
@@ -101,6 +138,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
101
138
|
Raises:
|
|
102
139
|
ValueError: If name or content is invalid.
|
|
103
140
|
"""
|
|
141
|
+
SetupContentValidator.reject_oversized_output_format_spec(setup_dict.get("content") or {})
|
|
104
142
|
setup_id = self._new_id()
|
|
105
143
|
try:
|
|
106
144
|
setup = SetupData(
|
|
@@ -115,12 +153,9 @@ class DefaultSetup(SetupStrategy):
|
|
|
115
153
|
id=self._new_id(),
|
|
116
154
|
setup_id=setup_id,
|
|
117
155
|
version="1.0.0",
|
|
156
|
+
documentation=setup_dict.get("documentation") or "",
|
|
118
157
|
content=setup_dict.get("content") or {},
|
|
119
|
-
structure=(
|
|
120
|
-
JsonStructure.check(setup_dict.get("content") or {}, setup_dict["structure"])
|
|
121
|
-
if setup_dict.get("structure")
|
|
122
|
-
else JsonStructure.describe(setup_dict.get("content") or {})
|
|
123
|
-
),
|
|
158
|
+
structure=JsonStructure.clip(setup_dict.get("structure") or {}),
|
|
124
159
|
creation_date=datetime.datetime.now(datetime.timezone.utc),
|
|
125
160
|
),
|
|
126
161
|
)
|
|
@@ -141,9 +176,11 @@ class DefaultSetup(SetupStrategy):
|
|
|
141
176
|
|
|
142
177
|
Args:
|
|
143
178
|
setup_dict: Dictionary with 'setup_id', 'name', 'content', optional
|
|
144
|
-
'set_as_current' (defaults to True)
|
|
145
|
-
|
|
146
|
-
|
|
179
|
+
'set_as_current' (defaults to True), optional 'documentation' and optional
|
|
180
|
+
'structure'. The map belongs to the content it describes, so a revision
|
|
181
|
+
carries only the map its own call supplied; omitting it leaves the new
|
|
182
|
+
revision without one. Omitting the documentation clears
|
|
183
|
+
it, matching the wire.
|
|
147
184
|
|
|
148
185
|
Returns:
|
|
149
186
|
The updated setup with its current version.
|
|
@@ -158,6 +195,7 @@ class DefaultSetup(SetupStrategy):
|
|
|
158
195
|
if not name or not isinstance(content, dict):
|
|
159
196
|
msg = "setup_id, name and content (object) are required"
|
|
160
197
|
raise ValueError(msg)
|
|
198
|
+
SetupContentValidator.reject_oversized_output_format_spec(content)
|
|
161
199
|
setup.name = name
|
|
162
200
|
# A new revision rather than an in-place edit, matching UpdateSetup on the wire.
|
|
163
201
|
history = self.versions.setdefault(setup.id, [setup.current_setup_version])
|
|
@@ -165,12 +203,11 @@ class DefaultSetup(SetupStrategy):
|
|
|
165
203
|
id=self._new_id(),
|
|
166
204
|
setup_id=setup.id,
|
|
167
205
|
version=f"1.0.{len(history)}",
|
|
206
|
+
# No presence on UpdateSetupRequest, so an omitted value clears it server-side.
|
|
207
|
+
# Mirror that rather than preserving the old text: same input, same result.
|
|
208
|
+
documentation=setup_dict.get("documentation") or "",
|
|
168
209
|
content=content,
|
|
169
|
-
structure=(
|
|
170
|
-
JsonStructure.check(content, setup_dict["structure"])
|
|
171
|
-
if setup_dict.get("structure")
|
|
172
|
-
else JsonStructure.describe(content)
|
|
173
|
-
),
|
|
210
|
+
structure=JsonStructure.clip(setup_dict.get("structure") or {}),
|
|
174
211
|
creation_date=datetime.datetime.now(datetime.timezone.utc),
|
|
175
212
|
)
|
|
176
213
|
history.append(version)
|
|
@@ -20,6 +20,7 @@ from digitalkin.services.setup.exceptions import SetupServiceError
|
|
|
20
20
|
from digitalkin.services.setup.setup_strategy import SetupData, SetupStrategy, SetupVersionData, SetupVersionPage
|
|
21
21
|
from digitalkin.utils.json_structure import JsonStructure
|
|
22
22
|
from digitalkin.utils.proto_utils import ProtoUtils
|
|
23
|
+
from digitalkin.utils.setup_content_validator import SetupContentValidator
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
@@ -133,15 +134,30 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
133
134
|
The validated ``SetupData``.
|
|
134
135
|
|
|
135
136
|
Raises:
|
|
136
|
-
SetupServiceError:
|
|
137
|
+
SetupServiceError: Neither field carries a setup version, or the one that does
|
|
138
|
+
carries no content.
|
|
137
139
|
"""
|
|
138
|
-
if setup_msg.HasField("current_setup_version")
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
embedded = setup_msg.current_setup_version if setup_msg.HasField("current_setup_version") else None
|
|
141
|
+
chosen = version_msg if embedded is None else embedded
|
|
142
|
+
if not chosen.id:
|
|
141
143
|
msg = f"setup '{setup_msg.id}' returned without a setup version"
|
|
142
144
|
raise SetupServiceError(msg)
|
|
143
145
|
data = ProtoUtils.proto_to_dict(setup_msg, with_defaults=True)
|
|
144
|
-
|
|
146
|
+
version = ProtoUtils.proto_to_dict(chosen, with_defaults=True)
|
|
147
|
+
# An unset content Struct is dropped by proto_to_dict rather than rendered as {},
|
|
148
|
+
# so SetupData would fail with a bare "Field required" naming neither the setup nor
|
|
149
|
+
# which of the response's two SetupVersion fields was read. Say both instead: the
|
|
150
|
+
# message carries the version twice and only one of them may hold the payload.
|
|
151
|
+
if "content" not in version:
|
|
152
|
+
source = "setup.current_setup_version" if embedded is not None else "setup_version"
|
|
153
|
+
other = version_msg if embedded is not None else None
|
|
154
|
+
sibling = "not populated" if other is None else ("carries content" if other.content.fields else "empty too")
|
|
155
|
+
msg = (
|
|
156
|
+
f"setup '{setup_msg.id}' version '{chosen.id}' arrived with no content "
|
|
157
|
+
f"(read from {source}; sibling setup_version {sibling})"
|
|
158
|
+
)
|
|
159
|
+
raise SetupServiceError(msg)
|
|
160
|
+
data["current_setup_version"] = version
|
|
145
161
|
if structure is not None:
|
|
146
162
|
data["current_setup_version"]["structure"] = dict(structure)
|
|
147
163
|
return SetupData(**data)
|
|
@@ -183,34 +199,33 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
183
199
|
|
|
184
200
|
Args:
|
|
185
201
|
setup_dict: Dictionary with 'name', 'content', optional 'documentation' and
|
|
186
|
-
optional 'structure' — the
|
|
187
|
-
|
|
188
|
-
|
|
202
|
+
optional 'structure' — the ``{key path: description}`` map the agent
|
|
203
|
+
wrote for ``content``, stored as written with only each description's
|
|
204
|
+
length bounded.
|
|
189
205
|
|
|
190
206
|
Returns:
|
|
191
207
|
The created setup with its initial version and structure.
|
|
192
208
|
|
|
193
209
|
Raises:
|
|
194
|
-
ValueError: If name or content is missing.
|
|
210
|
+
ValueError: If name or content is missing, or output_format_spec is oversized.
|
|
195
211
|
ServerError: If gRPC operation fails.
|
|
196
212
|
SetupServiceError: If the server reports failure or an unexpected error occurs.
|
|
197
213
|
"""
|
|
198
214
|
if not setup_dict.get("name") or not isinstance(setup_dict.get("content"), dict):
|
|
199
215
|
msg = "name and content (object) are required"
|
|
200
216
|
raise ValueError(msg)
|
|
217
|
+
# Outside handle_grpc_errors: an input guard must stay a ValueError, not become a
|
|
218
|
+
# SetupServiceError via the catch-all.
|
|
219
|
+
SetupContentValidator.reject_oversized_output_format_spec(setup_dict["content"])
|
|
201
220
|
async with self.handle_grpc_errors("Setup Creation"):
|
|
202
221
|
content_struct = Struct()
|
|
203
222
|
content_struct.update(setup_dict["content"])
|
|
204
223
|
structure_struct = Struct()
|
|
205
|
-
structure_struct.update(
|
|
206
|
-
JsonStructure.check(setup_dict["content"], setup_dict["structure"])
|
|
207
|
-
if setup_dict.get("structure")
|
|
208
|
-
else JsonStructure.describe(setup_dict["content"])
|
|
209
|
-
)
|
|
224
|
+
structure_struct.update(JsonStructure.clip(setup_dict.get("structure") or {}))
|
|
210
225
|
request = setup_pb2.CreateSetupRequest(
|
|
211
226
|
name=setup_dict["name"],
|
|
212
227
|
content=content_struct,
|
|
213
|
-
documentation=setup_dict.get("documentation"
|
|
228
|
+
documentation=setup_dict.get("documentation") or "",
|
|
214
229
|
structure=structure_struct,
|
|
215
230
|
)
|
|
216
231
|
response = await self.exec_grpc_query("CreateSetup", request)
|
|
@@ -226,16 +241,15 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
226
241
|
Args:
|
|
227
242
|
setup_dict: Dictionary with 'setup_id', 'name', 'content', optional
|
|
228
243
|
'set_as_current' (defaults to True), optional 'documentation' and optional
|
|
229
|
-
'structure'
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
previous version carried.
|
|
244
|
+
'structure'. The map belongs to the content it describes, so a revision
|
|
245
|
+
carries only the map its own call supplied; omitting it leaves the new
|
|
246
|
+
revision without one.
|
|
233
247
|
|
|
234
248
|
Returns:
|
|
235
249
|
The updated setup with its current version and structure.
|
|
236
250
|
|
|
237
251
|
Raises:
|
|
238
|
-
ValueError: If setup_id, name or content is missing.
|
|
252
|
+
ValueError: If setup_id, name or content is missing, or output_format_spec is oversized.
|
|
239
253
|
ServerError: If gRPC operation fails.
|
|
240
254
|
SetupServiceError: If the server reports failure or an unexpected error occurs.
|
|
241
255
|
"""
|
|
@@ -246,15 +260,12 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
246
260
|
):
|
|
247
261
|
msg = "setup_id, name and content (object) are required"
|
|
248
262
|
raise ValueError(msg)
|
|
263
|
+
SetupContentValidator.reject_oversized_output_format_spec(setup_dict["content"])
|
|
249
264
|
async with self.handle_grpc_errors("Setup Update"):
|
|
250
265
|
content_struct = Struct()
|
|
251
266
|
content_struct.update(setup_dict["content"])
|
|
252
267
|
structure_struct = Struct()
|
|
253
|
-
structure_struct.update(
|
|
254
|
-
JsonStructure.check(setup_dict["content"], setup_dict["structure"])
|
|
255
|
-
if setup_dict.get("structure")
|
|
256
|
-
else JsonStructure.describe(setup_dict["content"])
|
|
257
|
-
)
|
|
268
|
+
structure_struct.update(JsonStructure.clip(setup_dict.get("structure") or {}))
|
|
258
269
|
# UpdateSetup cuts a new version rather than editing in place; without
|
|
259
270
|
# set_as_current the setup would keep serving the old content.
|
|
260
271
|
request = setup_pb2.UpdateSetupRequest(
|
|
@@ -262,7 +273,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
|
|
|
262
273
|
name=setup_dict["name"],
|
|
263
274
|
content=content_struct,
|
|
264
275
|
set_as_current=bool(setup_dict.get("set_as_current", True)),
|
|
265
|
-
documentation=setup_dict.get("documentation"
|
|
276
|
+
documentation=setup_dict.get("documentation") or "",
|
|
266
277
|
structure=structure_struct,
|
|
267
278
|
)
|
|
268
279
|
response = await self.exec_grpc_query("UpdateSetup", request)
|