digitalkin 1.0.5.dev3__tar.gz → 1.0.5.dev4__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.5.dev3 → digitalkin-1.0.5.dev4}/PKG-INFO +1 -1
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/pyproject.toml +1 -1
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/__version__.py +1 -1
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/agno_adapter.py +20 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/hitl.py +27 -5
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/module_toolkit.py +21 -4
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/module_runner.py +40 -2
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/agui_mixin.py +175 -9
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/module_context.py +6 -1
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/utility.py +6 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/module.py +8 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/_base_module.py +20 -4
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/communication/exceptions.py +4 -1
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/communication/grpc_communication.py +12 -9
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin.egg-info/PKG-INFO +1 -1
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/LICENSE +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/README.md +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/echo_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/models/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/models/input.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/models/output.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/models/secret.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/models/setup.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/server.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/triggers/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/bench_module/triggers/message_trigger.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/modules/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/modules/archetype_with_tools_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/modules/dynamic_setup_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/monitoring/tests/test_metrics.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/client.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/echo_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/models/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/models/input.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/models/output.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/models/secret.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/models/setup.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/server.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/triggers/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/redis_demo/triggers/message_trigger.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/services/filesystem_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/examples/services/storage_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/setup.cfg +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/agui_tools.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/models.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/base.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/defaults.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/action.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/base.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/kins/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/kins/action.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/kins/kit.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/loader/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/loader/action.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/loader/kit.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/services/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/services/action.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/services/kit.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/tools/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/tools/action.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/registry/tools/kit.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/common/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/common/factories.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/job_manager/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/profiling/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/profiling/step_timer.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/profiling/task_profiler.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/resilience/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/resilience/bulkhead.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/task_executor.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/task_session.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/_base_server.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/gateway_servicer.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/module_server.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/module_servicer.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/stream_session.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/logger.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/base_mixin.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/cost_mixin.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/file_history_mixin.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/logger_mixin.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/mixins/storage_mixin.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/core/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/core/job_manager_models.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/core/redis.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/core/task_monitor.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/events/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/events/agent_events.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/grpc_servers/models.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/grpc_servers/types.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/ag_ui.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/base_types.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/knowledge_files.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/loaded_tools.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/module_types.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/request_metadata.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/select_schema.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/setup_types.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/tool_cache.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/tool_reference.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/services/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/services/filesystem.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/services/registry.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/services/services.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/certificate.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/client/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/client/channel.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/client/circuit_breaker.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/client/client.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/client/grpc.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/gateway.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/log.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/profiling.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/queue.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/redis.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/registry.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/resilience.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/server/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/server/channel.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/server/grpc.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/server/server.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/server/servicer.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/task_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/settings/utils/channel.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/trigger_handler.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/triggers/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/py.typed +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/communication/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/communication/communication_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/communication/default_communication.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/cost/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/filesystem/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/registry/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/registry/grpc_registry.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/registry/registry_models.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/registry/registry_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/secret/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/secret/default_secret.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/secret/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/secret/grpc_secret.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/secret/secret_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/services_config.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/services_models.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/setup/default_setup.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/setup/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/setup/grpc_setup.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/setup/setup_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/storage/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/task_manager/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/task_manager/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/user_profile/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/user_profile/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/conditional_schema.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/dynamic_schema.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/env_manager.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/env_template.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/exceptions.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/json_structure.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/package_discover.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/proto_utils.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/schema_splitter.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/utils/setup_content_validator.py +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin.egg-info/SOURCES.txt +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin.egg-info/requires.txt +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin.egg-info/top_level.txt +0 -0
- {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/tests/test_exceptions.py +0 -0
{digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/agno_adapter.py
RENAMED
|
@@ -676,6 +676,26 @@ class AgnoStreamAdapter:
|
|
|
676
676
|
self._closed_tool_call_ids.add(tool_call_id)
|
|
677
677
|
|
|
678
678
|
content = agno_event.content
|
|
679
|
+
if tool is not None and tool.tool_call_error:
|
|
680
|
+
# Agno flags a raised tool on the completed event, then sends a tool_call_error
|
|
681
|
+
# that the closed-id check drops — so the failure is surfaced here.
|
|
682
|
+
# TODO(validate): AGUI-TOOL-FAILED-STATUS a raised tool surfaces as ToolCallError, not success
|
|
683
|
+
logger.info(
|
|
684
|
+
"[VALIDATE AGUI-TOOL-FAILED-STATUS] tool %s (id=%s) failed: %s",
|
|
685
|
+
tool.tool_name,
|
|
686
|
+
tool_call_id,
|
|
687
|
+
tool.result,
|
|
688
|
+
)
|
|
689
|
+
return [
|
|
690
|
+
ToolCallErrorEvent(
|
|
691
|
+
event=AgentRunEvent.TOOL_CALL_ERROR,
|
|
692
|
+
tool=tool_info,
|
|
693
|
+
error_message=str(tool.result) if tool.result else None,
|
|
694
|
+
subagent_run_id=self._subagent_of(self._run_key),
|
|
695
|
+
timestamp=timestamp,
|
|
696
|
+
metadata=self._last_metadata,
|
|
697
|
+
)
|
|
698
|
+
]
|
|
679
699
|
return [
|
|
680
700
|
ToolCallCompletedEvent(
|
|
681
701
|
event=AgentRunEvent.TOOL_CALL_COMPLETED,
|
|
@@ -11,6 +11,7 @@ import json
|
|
|
11
11
|
import logging
|
|
12
12
|
from typing import TYPE_CHECKING, Any, ClassVar
|
|
13
13
|
|
|
14
|
+
from ag_ui.core.events import Interrupt, RunFinishedInterruptOutcome
|
|
14
15
|
from pydantic import BaseModel, ConfigDict, Field
|
|
15
16
|
|
|
16
17
|
from digitalkin.community.agno.models import PauseInfo
|
|
@@ -268,13 +269,14 @@ class HitlEvents:
|
|
|
268
269
|
run_id: str,
|
|
269
270
|
pending_tool_call_ids: list[str],
|
|
270
271
|
) -> None:
|
|
271
|
-
"""Emit an AG-UI ``RunFinished`` with
|
|
272
|
+
"""Emit an AG-UI ``RunFinished`` with an interrupt outcome.
|
|
272
273
|
|
|
273
274
|
This is the protocol signal telling the front "the run paused on a
|
|
274
|
-
client-side tool; execute it and reply with a ``ToolMessage``".
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
client-side tool; execute it and reply with a ``ToolMessage``". The
|
|
276
|
+
standard ``outcome={type: "interrupt"}`` carries one interrupt per pending
|
|
277
|
+
tool; the legacy ``result.status="awaiting_tool_result"`` is kept for
|
|
278
|
+
existing clients. When an AG-UI run is open, its state first moves the
|
|
279
|
+
tools to ``awaiting_input`` and the run to ``interrupted``.
|
|
278
280
|
|
|
279
281
|
Args:
|
|
280
282
|
context: Current module context.
|
|
@@ -291,11 +293,31 @@ class HitlEvents:
|
|
|
291
293
|
AgUiRunFinishedOutput,
|
|
292
294
|
)
|
|
293
295
|
|
|
296
|
+
run = context.agui_run
|
|
297
|
+
tools = run.state["tools"] if run is not None else {}
|
|
298
|
+
interrupts = [
|
|
299
|
+
Interrupt(
|
|
300
|
+
id=tool_call_id,
|
|
301
|
+
reason="tool_call",
|
|
302
|
+
tool_call_id=tool_call_id,
|
|
303
|
+
message=f"Waiting for the result of {tools.get(tool_call_id, {}).get('name') or 'a frontend tool'}",
|
|
304
|
+
)
|
|
305
|
+
for tool_call_id in pending_tool_call_ids
|
|
306
|
+
]
|
|
307
|
+
if run is not None and run.open:
|
|
308
|
+
run.open = False
|
|
309
|
+
await run.update(
|
|
310
|
+
context,
|
|
311
|
+
*((("tools", tid, "status"), "awaiting_input") for tid in pending_tool_call_ids if tid in tools),
|
|
312
|
+
(("interrupts",), [i.model_dump(mode="json", by_alias=True, exclude_none=True) for i in interrupts]),
|
|
313
|
+
(("run", "status"), "interrupted"),
|
|
314
|
+
)
|
|
294
315
|
output = AgUiOutput(
|
|
295
316
|
root=AgUiRunFinishedOutput(
|
|
296
317
|
event=AgUiRunFinishedEvent(
|
|
297
318
|
thread_id=thread_id,
|
|
298
319
|
run_id=run_id,
|
|
320
|
+
outcome=RunFinishedInterruptOutcome(interrupts=interrupts) if interrupts else None,
|
|
299
321
|
result={
|
|
300
322
|
"status": _AWAITING_STATUS,
|
|
301
323
|
"pending_tool_call_ids": pending_tool_call_ids,
|
{digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/community/agno/module_toolkit.py
RENAMED
|
@@ -25,6 +25,7 @@ from digitalkin.logger import logger
|
|
|
25
25
|
from digitalkin.models.module import ModuleContext
|
|
26
26
|
from digitalkin.models.module.ag_ui import AgUiCustomEventOutput, AgUiOutput
|
|
27
27
|
from digitalkin.models.module.tool_cache import ToolDefinition, ToolModuleInfo
|
|
28
|
+
from digitalkin.services.communication.exceptions import ToolCallError
|
|
28
29
|
|
|
29
30
|
# Default timeout for tool calls in seconds
|
|
30
31
|
DEFAULT_TOOL_TIMEOUT_SECONDS = 300
|
|
@@ -265,7 +266,14 @@ class ModuleToolkit(DkToolkit):
|
|
|
265
266
|
# callbacks is a dict-driven SimpleNamespace (module_context.py:168);
|
|
266
267
|
# send_message may legitimately be absent outside a running job.
|
|
267
268
|
send_message = vars(context.callbacks).get("send_message")
|
|
269
|
+
value = event.get("value")
|
|
270
|
+
url = value.get("url") if isinstance(value, dict) else None
|
|
268
271
|
if send_message is None:
|
|
272
|
+
logger.warning(
|
|
273
|
+
"Dropped custom event '%s' url=%s: no send_message on the agent context",
|
|
274
|
+
event["name"],
|
|
275
|
+
url,
|
|
276
|
+
)
|
|
269
277
|
return
|
|
270
278
|
|
|
271
279
|
try:
|
|
@@ -275,10 +283,15 @@ class ModuleToolkit(DkToolkit):
|
|
|
275
283
|
await send_message(
|
|
276
284
|
AgUiOutput(
|
|
277
285
|
root=AgUiCustomEventOutput(
|
|
278
|
-
event=AgUiCustomEvent(name=event["name"], value=
|
|
286
|
+
event=AgUiCustomEvent(name=event["name"], value=value),
|
|
279
287
|
)
|
|
280
288
|
)
|
|
281
289
|
)
|
|
290
|
+
logger.info(
|
|
291
|
+
"Relayed custom event '%s' url=%s to the agent stream",
|
|
292
|
+
event["name"],
|
|
293
|
+
url,
|
|
294
|
+
)
|
|
282
295
|
except Exception:
|
|
283
296
|
logger.exception("Failed to relay custom event '%s' to the agent stream", event["name"])
|
|
284
297
|
|
|
@@ -467,6 +480,10 @@ class ModuleToolkit(DkToolkit):
|
|
|
467
480
|
Wraps the SDK module's async generator function into an async function
|
|
468
481
|
that Agno can consume, with proper error handling and response formatting.
|
|
469
482
|
|
|
483
|
+
A failure raises ``ToolCallError`` carrying the same JSON body a success-path caller
|
|
484
|
+
would have read: Agno hands ``str(exc)`` to the model unchanged and flags the call
|
|
485
|
+
``tool_call_error``, which is what marks the tool failed for the front.
|
|
486
|
+
|
|
470
487
|
Returns:
|
|
471
488
|
Async function that calls the SDK tool and returns a JSON result, or a
|
|
472
489
|
ToolResult when the tool returned images alongside its text output.
|
|
@@ -509,14 +526,14 @@ class ModuleToolkit(DkToolkit):
|
|
|
509
526
|
duration_ms = round((time.perf_counter() - start_time) * 1000, 2)
|
|
510
527
|
error_msg = f"Tool '{tool_name}' timed out after {timeout}s"
|
|
511
528
|
logger.warning("%s task_id=%s", error_msg, task_id)
|
|
512
|
-
|
|
529
|
+
raise ToolCallError(handle_failure(tool_name, error_msg, duration_ms))
|
|
513
530
|
|
|
514
531
|
except Exception as e:
|
|
515
532
|
outcome = "error"
|
|
516
533
|
duration_ms = round((time.perf_counter() - start_time) * 1000, 2)
|
|
517
534
|
error_msg = f"Failed to call tool '{tool_name}': {e!s}"
|
|
518
535
|
logger.warning("%s task_id=%s", error_msg, task_id, exc_info=True)
|
|
519
|
-
|
|
536
|
+
raise ToolCallError(handle_failure(tool_name, error_msg, duration_ms))
|
|
520
537
|
|
|
521
538
|
else:
|
|
522
539
|
call_timer.mark("gen_consume")
|
|
@@ -536,7 +553,7 @@ class ModuleToolkit(DkToolkit):
|
|
|
536
553
|
|
|
537
554
|
outcome = "no_success"
|
|
538
555
|
error_msg = ModuleToolkit._extract_error_message(error_frame)
|
|
539
|
-
|
|
556
|
+
raise ToolCallError(handle_failure(tool_name, error_msg, duration_ms))
|
|
540
557
|
|
|
541
558
|
finally:
|
|
542
559
|
call_timer.mark("respond")
|
{digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/core/task_manager/module_runner.py
RENAMED
|
@@ -21,9 +21,10 @@ from digitalkin.models.core.task_monitor import CancellationReason
|
|
|
21
21
|
from digitalkin.models.grpc_servers.stream_error_codes import StreamErrorCode
|
|
22
22
|
from digitalkin.models.module.base_types import DataModel
|
|
23
23
|
from digitalkin.models.module.module import ModuleStatus
|
|
24
|
-
from digitalkin.models.module.utility import EndOfStreamOutput, StreamCancelledOutput
|
|
24
|
+
from digitalkin.models.module.utility import EndOfStreamOutput, StreamCancelledOutput, StreamHeartbeatOutput
|
|
25
25
|
from digitalkin.models.services.storage import BaseRole
|
|
26
26
|
from digitalkin.models.settings.gateway import get_gateway_settings
|
|
27
|
+
from digitalkin.models.settings.module import get_module_settings
|
|
27
28
|
from digitalkin.models.settings.profiling import ProfilerMode, get_profiling_settings
|
|
28
29
|
from digitalkin.models.settings.redis import get_redis_settings
|
|
29
30
|
|
|
@@ -143,9 +144,11 @@ class ModuleRunner:
|
|
|
143
144
|
idem_key = f"idem:{task_id}"
|
|
144
145
|
idem_ttl = get_redis_settings().idem_ttl
|
|
145
146
|
eos_written = False
|
|
147
|
+
last_write_ns = time.monotonic_ns()
|
|
146
148
|
|
|
147
149
|
async def _on_output(output_data: Any) -> None:
|
|
148
|
-
nonlocal first_logged, seq, eos_written
|
|
150
|
+
nonlocal first_logged, seq, eos_written, last_write_ns
|
|
151
|
+
last_write_ns = time.monotonic_ns()
|
|
149
152
|
data = output_data.model_dump(mode="json")
|
|
150
153
|
if data.get("root", {}).get("protocol") == "stream.end":
|
|
151
154
|
t_eos_write_start = time.perf_counter_ns()
|
|
@@ -259,6 +262,41 @@ class ModuleRunner:
|
|
|
259
262
|
timer.mark("create_job")
|
|
260
263
|
timer.log("ModuleRunner", task_id)
|
|
261
264
|
|
|
265
|
+
async def _heartbeat() -> None:
|
|
266
|
+
interval_s = get_module_settings().heartbeat_interval_s
|
|
267
|
+
while not eos_written:
|
|
268
|
+
# Sleep only the rest of the silence window, so no gap exceeds one interval.
|
|
269
|
+
remaining_s = interval_s - (time.monotonic_ns() - last_write_ns) / 1e9
|
|
270
|
+
if remaining_s > 0:
|
|
271
|
+
await asyncio.sleep(remaining_s)
|
|
272
|
+
continue
|
|
273
|
+
# TODO(validate): TASK-HEARTBEAT a silent running task keeps its stream open
|
|
274
|
+
logger.info("[VALIDATE TASK-HEARTBEAT] task silent for %.0fs; beating", interval_s, extra=log_extra)
|
|
275
|
+
run = module.context.agui_run
|
|
276
|
+
try:
|
|
277
|
+
if run is not None and run.open:
|
|
278
|
+
await run.update(module.context, (("run", "heartbeatAt"), run.now_ms()))
|
|
279
|
+
else:
|
|
280
|
+
await _on_output(
|
|
281
|
+
DataModel[StreamHeartbeatOutput](
|
|
282
|
+
root=StreamHeartbeatOutput(), annotations={"role": BaseRole.SYSTEM}
|
|
283
|
+
)
|
|
284
|
+
)
|
|
285
|
+
except Exception:
|
|
286
|
+
# The beat task is never awaited: log here or the failure is lost.
|
|
287
|
+
logger.exception("ModuleRunner: heartbeat stopped", extra=log_extra)
|
|
288
|
+
return
|
|
289
|
+
|
|
290
|
+
module_task = self._servicer.job_manager.tasks.get(job_id)
|
|
291
|
+
if module_task is None or eos_written:
|
|
292
|
+
logger.debug(
|
|
293
|
+
"ModuleRunner: no heartbeat (task registered=%s)", module_task is not None, extra=log_extra
|
|
294
|
+
)
|
|
295
|
+
else:
|
|
296
|
+
# The task's done-callback holds the only reference and stops the beat with it.
|
|
297
|
+
beat = asyncio.create_task(_heartbeat())
|
|
298
|
+
module_task.add_done_callback(lambda _: beat.cancel())
|
|
299
|
+
|
|
262
300
|
if await self._redis_client.exists(cancel_key):
|
|
263
301
|
task = self._servicer.job_manager.tasks.get(job_id)
|
|
264
302
|
session = self._servicer.job_manager.tasks_sessions.get(job_id)
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
This mixin provides utilities to convert framework-agnostic agent events
|
|
4
4
|
into AG-UI protocol events and send them through the module context callbacks.
|
|
5
5
|
|
|
6
|
-
The mixin
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
The mixin receives events with all necessary info (including IDs) and emits the
|
|
7
|
+
corresponding AG-UI protocol events. Event-sequence bookkeeping belongs in the adapter;
|
|
8
|
+
the only state kept here is the SDK-owned pipeline view (``AgUiRunState``) mirrored to
|
|
9
|
+
the front as ``STATE_SNAPSHOT`` + ``STATE_DELTA``. See ``docs/agui_events.md``.
|
|
9
10
|
"""
|
|
10
11
|
|
|
11
12
|
from __future__ import annotations
|
|
12
13
|
|
|
13
14
|
import json
|
|
15
|
+
import time
|
|
14
16
|
import uuid
|
|
15
17
|
from typing import TYPE_CHECKING, Any, ClassVar
|
|
16
18
|
|
|
@@ -23,6 +25,7 @@ from ag_ui.core.events import ReasoningStartEvent as AgUiReasoningStartEvent
|
|
|
23
25
|
from ag_ui.core.events import RunErrorEvent as AgUiRunErrorEvent
|
|
24
26
|
from ag_ui.core.events import RunFinishedEvent as AgUiRunFinishedEvent
|
|
25
27
|
from ag_ui.core.events import RunStartedEvent as AgUiRunStartedEvent
|
|
28
|
+
from ag_ui.core.events import StateDeltaEvent, StateSnapshotEvent
|
|
26
29
|
from ag_ui.core.events import SubagentErrorEvent as AgUiSubagentErrorEvent
|
|
27
30
|
from ag_ui.core.events import SubagentFinishedEvent as AgUiSubagentFinishedEvent
|
|
28
31
|
from ag_ui.core.events import SubagentStartedEvent as AgUiSubagentStartedEvent
|
|
@@ -35,6 +38,7 @@ from ag_ui.core.events import ToolCallResultEvent as AgUiToolCallResultEvent
|
|
|
35
38
|
from ag_ui.core.events import ToolCallStartEvent as AgUiToolCallStartEvent
|
|
36
39
|
from pydantic import BaseModel
|
|
37
40
|
|
|
41
|
+
from digitalkin.logger import logger
|
|
38
42
|
from digitalkin.models.events import (
|
|
39
43
|
AgentRunEvent,
|
|
40
44
|
BaseAgentRunEvent,
|
|
@@ -67,6 +71,8 @@ from digitalkin.models.module.ag_ui import (
|
|
|
67
71
|
AgUiRunErrorOutput,
|
|
68
72
|
AgUiRunFinishedOutput,
|
|
69
73
|
AgUiRunStartedOutput,
|
|
74
|
+
AgUiStateDeltaOutput,
|
|
75
|
+
AgUiStateSnapshotOutput,
|
|
70
76
|
AgUiSubagentErrorOutput,
|
|
71
77
|
AgUiSubagentFinishedOutput,
|
|
72
78
|
AgUiSubagentStartedOutput,
|
|
@@ -84,19 +90,110 @@ if TYPE_CHECKING:
|
|
|
84
90
|
from digitalkin.models.module.module_context import ModuleContext
|
|
85
91
|
|
|
86
92
|
|
|
93
|
+
class AgUiRunState:
|
|
94
|
+
"""SDK-owned pipeline state of one task's AG-UI run.
|
|
95
|
+
|
|
96
|
+
The front only renders it: ``snapshot`` replaces its state, ``update`` sends the
|
|
97
|
+
matching JSON Patch. Shape: ``run`` (status, error, heartbeatAt), ``tools`` and
|
|
98
|
+
``subagents`` keyed by id (name, status, startedAt, error), ``interrupts``.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(self) -> None:
|
|
102
|
+
"""Start a running run with an empty pipeline."""
|
|
103
|
+
self.open = True
|
|
104
|
+
self.state: dict[str, Any] = {
|
|
105
|
+
"run": {"status": "running", "error": None, "heartbeatAt": None},
|
|
106
|
+
"tools": {},
|
|
107
|
+
"subagents": {},
|
|
108
|
+
"interrupts": [],
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async def snapshot(self, context: ModuleContext) -> None:
|
|
112
|
+
"""Emit the full state as ``STATE_SNAPSHOT``.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
context: Module context whose callbacks carry the event.
|
|
116
|
+
"""
|
|
117
|
+
await context.callbacks.send_message(
|
|
118
|
+
AgUiOutput(root=AgUiStateSnapshotOutput(event=StateSnapshotEvent(snapshot=self.state)))
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
async def update(self, context: ModuleContext, *changes: tuple[tuple[str, ...], Any]) -> None:
|
|
122
|
+
"""Set each ``(key path, value)`` in the state and emit them as one ``STATE_DELTA``.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
context: Module context whose callbacks carry the event.
|
|
126
|
+
*changes: Key path into the state and the value to set there.
|
|
127
|
+
"""
|
|
128
|
+
ops = []
|
|
129
|
+
for keys, value in changes:
|
|
130
|
+
node = self.state
|
|
131
|
+
for key in keys[:-1]:
|
|
132
|
+
node = node[key]
|
|
133
|
+
ops.append({
|
|
134
|
+
"op": "replace" if keys[-1] in node else "add",
|
|
135
|
+
"path": "/" + "/".join(key.replace("~", "~0").replace("/", "~1") for key in keys),
|
|
136
|
+
"value": value,
|
|
137
|
+
})
|
|
138
|
+
node[keys[-1]] = value.copy() if isinstance(value, dict | list) else value
|
|
139
|
+
await context.callbacks.send_message(AgUiOutput(root=AgUiStateDeltaOutput(event=StateDeltaEvent(delta=ops))))
|
|
140
|
+
|
|
141
|
+
async def fail(
|
|
142
|
+
self,
|
|
143
|
+
context: ModuleContext,
|
|
144
|
+
status: str,
|
|
145
|
+
message: str,
|
|
146
|
+
code: str | None,
|
|
147
|
+
**fields: Any,
|
|
148
|
+
) -> None:
|
|
149
|
+
"""Close the run once: record ``status``/``message`` in state, then emit ``RUN_ERROR``.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
context: Module context whose callbacks carry the events.
|
|
153
|
+
status: Terminal run status, ``failed`` or ``cancelled``.
|
|
154
|
+
message: Human-readable error.
|
|
155
|
+
code: ``RUN_ERROR`` code.
|
|
156
|
+
**fields: Extra AG-UI event fields (metadata).
|
|
157
|
+
"""
|
|
158
|
+
if not self.open:
|
|
159
|
+
logger.info(
|
|
160
|
+
"AG-UI run already closed (%s); dropping %s RUN_ERROR code=%s message=%s",
|
|
161
|
+
self.state["run"]["status"],
|
|
162
|
+
status,
|
|
163
|
+
code,
|
|
164
|
+
message,
|
|
165
|
+
extra=context.session.current_ids(),
|
|
166
|
+
)
|
|
167
|
+
return
|
|
168
|
+
self.open = False
|
|
169
|
+
await self.update(context, (("run", "status"), status), (("run", "error"), message))
|
|
170
|
+
await context.callbacks.send_message(
|
|
171
|
+
AgUiOutput(root=AgUiRunErrorOutput(event=AgUiRunErrorEvent(message=message, code=code, **fields)))
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def now_ms() -> int:
|
|
176
|
+
"""Wall-clock epoch milliseconds, the unit of every ``*At`` field.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Current time in epoch milliseconds.
|
|
180
|
+
"""
|
|
181
|
+
return time.time_ns() // 1_000_000
|
|
182
|
+
|
|
183
|
+
|
|
87
184
|
class AgUiMixin:
|
|
88
185
|
"""Mixin for converting agent events to AG-UI protocol and sending them.
|
|
89
186
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
generating IDs and managing event lifecycle (start/complete sequences).
|
|
187
|
+
Each handler reads IDs from the event and emits the corresponding AG-UI event(s),
|
|
188
|
+
plus the ``STATE_DELTA`` that keeps ``context.agui_run`` in sync. The adapter is
|
|
189
|
+
responsible for generating IDs and managing event lifecycle (start/complete sequences).
|
|
93
190
|
|
|
94
191
|
Usage::
|
|
95
192
|
|
|
96
193
|
class MyTrigger(BaseTrigger, AgUiMixin):
|
|
97
194
|
async def execute(self, context, input_data):
|
|
98
195
|
async for event in agent.run(input_data.message, stream=True):
|
|
99
|
-
await self.
|
|
196
|
+
await self.send_message(context, event)
|
|
100
197
|
"""
|
|
101
198
|
|
|
102
199
|
def __init__(self) -> None:
|
|
@@ -217,6 +314,8 @@ class AgUiMixin:
|
|
|
217
314
|
)
|
|
218
315
|
)
|
|
219
316
|
await self._send_agui(context, output)
|
|
317
|
+
context.agui_run = AgUiRunState()
|
|
318
|
+
await context.agui_run.snapshot(context)
|
|
220
319
|
|
|
221
320
|
async def _handle_text_message_started(
|
|
222
321
|
self,
|
|
@@ -285,6 +384,10 @@ class AgUiMixin:
|
|
|
285
384
|
event.metadata,
|
|
286
385
|
extra=context.session.current_ids(),
|
|
287
386
|
)
|
|
387
|
+
run = context.agui_run
|
|
388
|
+
if run is not None and run.open:
|
|
389
|
+
run.open = False
|
|
390
|
+
await run.update(context, (("run", "status"), "completed"))
|
|
288
391
|
output = AgUiRunFinishedOutput(
|
|
289
392
|
event=AgUiRunFinishedEvent(
|
|
290
393
|
thread_id=self._thread_id,
|
|
@@ -299,8 +402,11 @@ class AgUiMixin:
|
|
|
299
402
|
context: ModuleContext,
|
|
300
403
|
event: RunErrorEvent,
|
|
301
404
|
) -> None:
|
|
302
|
-
"""Handle run error event - emit AG-UI RunError."""
|
|
405
|
+
"""Handle run error event - mark the run failed and emit AG-UI RunError."""
|
|
303
406
|
error_msg = event.content or "Agent run failed"
|
|
407
|
+
if context.agui_run is not None:
|
|
408
|
+
await context.agui_run.fail(context, "failed", error_msg, event.error_type, **self._authored(event))
|
|
409
|
+
return
|
|
304
410
|
output = AgUiRunErrorOutput(
|
|
305
411
|
event=AgUiRunErrorEvent(
|
|
306
412
|
message=error_msg,
|
|
@@ -326,6 +432,14 @@ class AgUiMixin:
|
|
|
326
432
|
)
|
|
327
433
|
)
|
|
328
434
|
await self._send_agui(context, output)
|
|
435
|
+
if context.agui_run is not None and event.subagent_run_id:
|
|
436
|
+
await context.agui_run.update(
|
|
437
|
+
context,
|
|
438
|
+
(
|
|
439
|
+
("subagents", event.subagent_run_id),
|
|
440
|
+
{"name": event.name, "status": "running", "startedAt": AgUiRunState.now_ms(), "error": None},
|
|
441
|
+
),
|
|
442
|
+
)
|
|
329
443
|
|
|
330
444
|
async def _handle_subagent_finished(
|
|
331
445
|
self,
|
|
@@ -341,6 +455,9 @@ class AgUiMixin:
|
|
|
341
455
|
)
|
|
342
456
|
)
|
|
343
457
|
await self._send_agui(context, output)
|
|
458
|
+
run = context.agui_run
|
|
459
|
+
if run is not None and event.subagent_run_id is not None and event.subagent_run_id in run.state["subagents"]:
|
|
460
|
+
await run.update(context, (("subagents", event.subagent_run_id, "status"), "completed"))
|
|
344
461
|
|
|
345
462
|
async def _handle_subagent_error(
|
|
346
463
|
self,
|
|
@@ -361,6 +478,13 @@ class AgUiMixin:
|
|
|
361
478
|
)
|
|
362
479
|
)
|
|
363
480
|
await self._send_agui(context, output)
|
|
481
|
+
run = context.agui_run
|
|
482
|
+
if run is not None and event.subagent_run_id is not None and event.subagent_run_id in run.state["subagents"]:
|
|
483
|
+
await run.update(
|
|
484
|
+
context,
|
|
485
|
+
(("subagents", event.subagent_run_id, "status"), "failed"),
|
|
486
|
+
(("subagents", event.subagent_run_id, "error"), event.message),
|
|
487
|
+
)
|
|
364
488
|
|
|
365
489
|
async def _handle_tool_call_started(
|
|
366
490
|
self,
|
|
@@ -394,6 +518,21 @@ class AgUiMixin:
|
|
|
394
518
|
)
|
|
395
519
|
await self._send_agui(context, args_output)
|
|
396
520
|
|
|
521
|
+
if context.agui_run is not None:
|
|
522
|
+
await context.agui_run.update(
|
|
523
|
+
context,
|
|
524
|
+
(
|
|
525
|
+
("tools", tool_call_id),
|
|
526
|
+
{
|
|
527
|
+
"name": tool.tool_name,
|
|
528
|
+
"status": "running",
|
|
529
|
+
"subagentRunId": event.subagent_run_id,
|
|
530
|
+
"startedAt": AgUiRunState.now_ms(),
|
|
531
|
+
"error": None,
|
|
532
|
+
},
|
|
533
|
+
),
|
|
534
|
+
)
|
|
535
|
+
|
|
397
536
|
async def _handle_tool_call_completed(
|
|
398
537
|
self,
|
|
399
538
|
context: ModuleContext,
|
|
@@ -425,19 +564,46 @@ class AgUiMixin:
|
|
|
425
564
|
)
|
|
426
565
|
await self._send_agui(context, result_output)
|
|
427
566
|
|
|
567
|
+
run = context.agui_run
|
|
568
|
+
if run is not None and tool_call_id in run.state["tools"]:
|
|
569
|
+
await run.update(context, (("tools", tool_call_id, "status"), "completed"))
|
|
570
|
+
|
|
428
571
|
async def _handle_tool_call_error(
|
|
429
572
|
self,
|
|
430
573
|
context: ModuleContext,
|
|
431
574
|
event: ToolCallErrorEvent,
|
|
432
575
|
) -> None:
|
|
433
|
-
"""Handle tool call error event - emit AG-UI ToolCallEnd.
|
|
576
|
+
"""Handle tool call error event - emit AG-UI ToolCallEnd + an error ToolCallResult, mark it failed.
|
|
577
|
+
|
|
578
|
+
``TOOL_CALL_RESULT`` has no error flag, so the failure is carried by its
|
|
579
|
+
``{"error": ...}`` content and by ``tools/<id>/status = failed`` in state.
|
|
580
|
+
"""
|
|
434
581
|
tool = event.tool
|
|
435
582
|
if not tool:
|
|
436
583
|
return
|
|
437
584
|
|
|
438
585
|
tool_call_id = tool.tool_call_id or str(uuid.uuid4())
|
|
586
|
+
error_msg = event.error_message or "Tool call failed"
|
|
439
587
|
output = AgUiToolCallEndOutput(event=AgUiToolCallEndEvent(tool_call_id=tool_call_id, **self._authored(event)))
|
|
440
588
|
await self._send_agui(context, output)
|
|
589
|
+
result_output = AgUiToolCallResultOutput(
|
|
590
|
+
event=AgUiToolCallResultEvent(
|
|
591
|
+
message_id=str(uuid.uuid4()),
|
|
592
|
+
tool_call_id=tool_call_id,
|
|
593
|
+
content=json.dumps({"error": error_msg}),
|
|
594
|
+
role="tool",
|
|
595
|
+
**self._authored(event),
|
|
596
|
+
)
|
|
597
|
+
)
|
|
598
|
+
await self._send_agui(context, result_output)
|
|
599
|
+
|
|
600
|
+
run = context.agui_run
|
|
601
|
+
if run is not None and tool_call_id in run.state["tools"]:
|
|
602
|
+
await run.update(
|
|
603
|
+
context,
|
|
604
|
+
(("tools", tool_call_id, "status"), "failed"),
|
|
605
|
+
(("tools", tool_call_id, "error"), error_msg),
|
|
606
|
+
)
|
|
441
607
|
|
|
442
608
|
async def _handle_reasoning_started(
|
|
443
609
|
self,
|
{digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev4}/src/digitalkin/models/module/module_context.py
RENAMED
|
@@ -4,7 +4,7 @@ import asyncio
|
|
|
4
4
|
from collections.abc import AsyncGenerator, Callable
|
|
5
5
|
from datetime import tzinfo
|
|
6
6
|
from types import SimpleNamespace
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
8
|
from zoneinfo import ZoneInfo
|
|
9
9
|
|
|
10
10
|
from google.protobuf import json_format
|
|
@@ -28,6 +28,9 @@ from digitalkin.services.storage.storage_strategy import StorageStrategy
|
|
|
28
28
|
from digitalkin.services.task_manager.task_manager_strategy import TaskManagerStrategy
|
|
29
29
|
from digitalkin.services.user_profile.user_profile_strategy import UserProfileStrategy
|
|
30
30
|
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from digitalkin.mixins.agui_mixin import AgUiRunState
|
|
33
|
+
|
|
31
34
|
|
|
32
35
|
class Session(SimpleNamespace):
|
|
33
36
|
"""Session data container with mandatory setup_id and mission_id."""
|
|
@@ -116,6 +119,7 @@ class ModuleContext:
|
|
|
116
119
|
shared: dict[str, Any]
|
|
117
120
|
tool_cache: ToolCache
|
|
118
121
|
request_metadata: RequestMetadata
|
|
122
|
+
agui_run: "AgUiRunState | None"
|
|
119
123
|
|
|
120
124
|
def __init__( # All service strategies are mandatory constructor args # ruff: ignore[too-many-arguments, too-many-positional-arguments]
|
|
121
125
|
self,
|
|
@@ -180,6 +184,7 @@ class ModuleContext:
|
|
|
180
184
|
self.shared = shared if shared is not None else {}
|
|
181
185
|
self.tool_cache = tool_cache or ToolCache()
|
|
182
186
|
self.request_metadata = RequestMetadata(request_metadata)
|
|
187
|
+
self.agui_run = None
|
|
183
188
|
|
|
184
189
|
async def get_module_schemas_by_id(
|
|
185
190
|
self,
|
|
@@ -34,6 +34,12 @@ class StreamCancelledOutput(UtilityProtocol):
|
|
|
34
34
|
reason: str = "cancelled"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
class StreamHeartbeatOutput(UtilityProtocol):
|
|
38
|
+
"""Liveness beat from a module that is running but silent; consumers ignore it."""
|
|
39
|
+
|
|
40
|
+
protocol: Literal["stream.heartbeat"] = "stream.heartbeat"
|
|
41
|
+
|
|
42
|
+
|
|
37
43
|
class HealthcheckPingInput(UtilityProtocol):
|
|
38
44
|
"""Input for healthcheck ping request."""
|
|
39
45
|
|
|
@@ -32,6 +32,14 @@ class ModuleSettings(BaseSettings):
|
|
|
32
32
|
file_history_flush_threshold: int = Field(
|
|
33
33
|
default=10, description="Dirty-entry count that triggers a file-history flush."
|
|
34
34
|
)
|
|
35
|
+
heartbeat_interval_s: float = Field(
|
|
36
|
+
default=30.0,
|
|
37
|
+
gt=0,
|
|
38
|
+
description=(
|
|
39
|
+
"Silence after which a running task writes a liveness frame (AG-UI STATE_DELTA or "
|
|
40
|
+
"stream.heartbeat). Keep it below the gateway read/dial-back idle timeouts."
|
|
41
|
+
),
|
|
42
|
+
)
|
|
35
43
|
|
|
36
44
|
|
|
37
45
|
@lru_cache(maxsize=1)
|