digitalkin 1.0.5.dev6__tar.gz → 1.1.0.dev0__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.dev6 → digitalkin-1.1.0.dev0}/PKG-INFO +1 -1
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/pyproject.toml +1 -1
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/__version__.py +1 -1
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/__init__.py +2 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/defaults.py +4 -2
- digitalkin-1.1.0.dev0/src/digitalkin/community/agno/toolkits/knowledge.py +113 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/module_server.py +10 -4
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module_context.py +6 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/__init__.py +3 -0
- digitalkin-1.1.0.dev0/src/digitalkin/models/services/knowledge.py +61 -0
- digitalkin-1.1.0.dev0/src/digitalkin/models/settings/knowledge.py +35 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +1 -0
- digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/__init__.py +16 -0
- digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/default_knowledge.py +88 -0
- digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/exceptions.py +5 -0
- digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/grpc_knowledge.py +145 -0
- digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/knowledge_strategy.py +114 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/services_config.py +11 -2
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/services_models.py +2 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/PKG-INFO +1 -1
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/SOURCES.txt +8 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/LICENSE +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/README.md +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/echo_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/input.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/output.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/secret.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/setup.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/server.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/triggers/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/triggers/message_trigger.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/archetype_with_tools_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/dynamic_setup_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/tests/test_metrics.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/client.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/echo_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/input.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/output.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/secret.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/setup.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/server.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/triggers/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/triggers/message_trigger.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/services/filesystem_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/services/storage_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/setup.cfg +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/agno_adapter.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/agui_tools.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/hitl.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/models.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/module_toolkit.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/base.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/action.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/base.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/action.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/kit.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/action.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/kit.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/services/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/services/action.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/services/kit.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/action.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/kit.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/common/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/common/factories.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/job_manager/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/profiling/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/profiling/step_timer.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/profiling/task_profiler.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/resilience/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/resilience/bulkhead.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/module_runner.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/task_executor.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/task_session.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/_base_server.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/gateway_servicer.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/validation.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/module_servicer.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/stream_session.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/logger.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/agui_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/base_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/cost_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/file_history_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/logger_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/storage_mixin.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/job_manager_models.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/redis.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/task_monitor.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/events/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/events/agent_events.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/models.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/types.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/ag_ui.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/base_types.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/knowledge_files.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/loaded_tools.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module_types.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/request_metadata.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/select_schema.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/setup_types.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/tool_cache.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/tool_reference.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/utility.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/filesystem.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/registry.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/services.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/certificate.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/channel.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/circuit_breaker.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/client.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/grpc.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/gateway.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/log.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/profiling.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/queue.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/redis.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/registry.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/resilience.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/channel.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/grpc.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/server.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/servicer.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/task_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/utils/channel.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/_base_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/trigger_handler.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/py.typed +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/communication_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/default_communication.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/grpc_communication.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/grpc_registry.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/registry_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/default_secret.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/grpc_secret.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/secret_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/default_setup.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/grpc_setup.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/setup_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/conditional_schema.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/dynamic_schema.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/env_manager.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/env_template.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/exceptions.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/json_structure.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/package_discover.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/proto_utils.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/schema_splitter.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/setup_content_validator.py +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/requires.txt +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/top_level.txt +0 -0
- {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/tests/test_exceptions.py +0 -0
{digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/__init__.py
RENAMED
|
@@ -8,6 +8,7 @@ Requires the optional ``agno`` dependency — importing this subpackage without
|
|
|
8
8
|
from digitalkin.community.agno.toolkits.base import DkToolkit
|
|
9
9
|
from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
|
|
10
10
|
from digitalkin.community.agno.toolkits.defaults import DefaultToolkits
|
|
11
|
+
from digitalkin.community.agno.toolkits.knowledge import KnowledgeTools
|
|
11
12
|
from digitalkin.community.agno.toolkits.registry.kins.kit import KinsManager
|
|
12
13
|
from digitalkin.community.agno.toolkits.registry.loader.kit import LoadManager
|
|
13
14
|
from digitalkin.community.agno.toolkits.registry.services.kit import ServicesManager
|
|
@@ -19,6 +20,7 @@ __all__ = [
|
|
|
19
20
|
"DefaultToolkits",
|
|
20
21
|
"DkToolkit",
|
|
21
22
|
"KinsManager",
|
|
23
|
+
"KnowledgeTools",
|
|
22
24
|
"LoadManager",
|
|
23
25
|
"ServicesManager",
|
|
24
26
|
"ToolsManager",
|
{digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/defaults.py
RENAMED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
|
|
8
|
+
from digitalkin.community.agno.toolkits.knowledge import KnowledgeTools
|
|
8
9
|
from digitalkin.community.agno.toolkits.registry.kins.kit import KinsManager
|
|
9
10
|
from digitalkin.community.agno.toolkits.registry.loader.kit import LoadManager
|
|
10
11
|
from digitalkin.community.agno.toolkits.registry.services.kit import ServicesManager
|
|
@@ -20,7 +21,7 @@ if TYPE_CHECKING:
|
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class DefaultToolkits:
|
|
23
|
-
"""Assemble the default DigitalKin toolkits (chat history, user profile, registry).
|
|
24
|
+
"""Assemble the default DigitalKin toolkits (chat history, user profile, knowledge, registry).
|
|
24
25
|
|
|
25
26
|
Two-phase usage — ChatHistoryTools needs the constructed Agent/Team::
|
|
26
27
|
|
|
@@ -46,12 +47,13 @@ class DefaultToolkits:
|
|
|
46
47
|
session_id: The Agno session whose chat history should be readable.
|
|
47
48
|
|
|
48
49
|
Returns:
|
|
49
|
-
[ChatHistoryTools, UserProfileTools,
|
|
50
|
+
[ChatHistoryTools, UserProfileTools, KnowledgeTools,
|
|
50
51
|
(ToolsManager, ServicesManager, KinsManager)?, LoadManager].
|
|
51
52
|
"""
|
|
52
53
|
tools: list[Toolkit] = [
|
|
53
54
|
ChatHistoryTools(session_id=session_id, context=context),
|
|
54
55
|
UserProfileTools(context.user_profile, context=context),
|
|
56
|
+
KnowledgeTools(context.knowledge, context=context),
|
|
55
57
|
]
|
|
56
58
|
if context.setup is not None:
|
|
57
59
|
tools.extend((
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Toolkit exposing the user's connected knowledge base to the agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from digitalkin.community.agno.toolkits.base import DkToolkit
|
|
8
|
+
from digitalkin.logger import logger
|
|
9
|
+
from digitalkin.models.services.knowledge import Citation, Modality
|
|
10
|
+
from digitalkin.services.knowledge.exceptions import KnowledgeServiceError
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from digitalkin.models.module import ModuleContext
|
|
14
|
+
from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class KnowledgeTools(DkToolkit):
|
|
18
|
+
"""Toolkit that lets the agent search the enterprise knowledge base.
|
|
19
|
+
|
|
20
|
+
What the search reaches is what the *current user* connected and may read: the
|
|
21
|
+
permission filter is compiled into the query by the platform, so there is no identity
|
|
22
|
+
to pass and no result to filter afterwards.
|
|
23
|
+
|
|
24
|
+
An empty answer is a legitimate answer — nothing matched, or nothing is connected —
|
|
25
|
+
and is reported as a success with zero results so the agent says so rather than retrying.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, knowledge: KnowledgeStrategy, context: ModuleContext | None = None) -> None:
|
|
29
|
+
"""Initialize the toolkit with the ``search_knowledge_base`` tool.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
knowledge: The module's knowledge service strategy.
|
|
33
|
+
context: Module context; enables AG-UI notifications via the base toolkit.
|
|
34
|
+
"""
|
|
35
|
+
self._knowledge = knowledge
|
|
36
|
+
super().__init__(
|
|
37
|
+
name="knowledge_tools",
|
|
38
|
+
tools=[self.search_knowledge_base],
|
|
39
|
+
context=context,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _row(citation: Citation) -> dict[str, Any]:
|
|
44
|
+
"""Trim a citation to what an agent can reason and cite from.
|
|
45
|
+
|
|
46
|
+
``score`` is dropped on purpose: it is a fused rank comparable only within one
|
|
47
|
+
answer, and a model shown a number reads it as a confidence.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
citation: The citation to render.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The fields worth spending context on.
|
|
54
|
+
"""
|
|
55
|
+
row: dict[str, Any] = {
|
|
56
|
+
"document_id": citation.document_id,
|
|
57
|
+
"title": citation.title,
|
|
58
|
+
"passage": citation.snippet,
|
|
59
|
+
"source": citation.source,
|
|
60
|
+
"source_url": citation.source_url,
|
|
61
|
+
}
|
|
62
|
+
if headings := citation.heading_path:
|
|
63
|
+
row["section"] = " > ".join(headings)
|
|
64
|
+
if citation.modality not in {Modality.TEXT, Modality.UNSPECIFIED}:
|
|
65
|
+
row["modality"] = citation.modality.value
|
|
66
|
+
return row
|
|
67
|
+
|
|
68
|
+
async def search_knowledge_base(
|
|
69
|
+
self,
|
|
70
|
+
query: str,
|
|
71
|
+
sources: list[str] | None = None,
|
|
72
|
+
limit: int = 10,
|
|
73
|
+
) -> str:
|
|
74
|
+
"""Search the user's own documents — their connected Google Drive, Notion, and the like.
|
|
75
|
+
|
|
76
|
+
Use this whenever the answer could live in the user's company documents rather than
|
|
77
|
+
in your general knowledge: internal decisions, meeting notes, specifications,
|
|
78
|
+
contracts, processes, numbers. Prefer one precise question in natural language over
|
|
79
|
+
keywords; the search is semantic as well as lexical.
|
|
80
|
+
|
|
81
|
+
Each result is a whole passage, not an excerpt, plus the URL of the document it came
|
|
82
|
+
from — quote the passage and cite the ``source_url`` rather than paraphrasing blindly.
|
|
83
|
+
Only documents this user is allowed to read are ever returned, so anything you get
|
|
84
|
+
back is safe to show them.
|
|
85
|
+
|
|
86
|
+
An empty result list means nothing matched or nothing is connected: say so, and do
|
|
87
|
+
not call the tool again with the same question.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
query: The question to answer, in natural language (1-4000 characters).
|
|
91
|
+
sources: Restrict the search to these connectors, e.g. ``["google_drive"]`` or
|
|
92
|
+
``["notion"]``. Lowercase connector names only, never a display name like
|
|
93
|
+
``"Google Drive"``. Omit it to search everything the user connected, which
|
|
94
|
+
is almost always what you want.
|
|
95
|
+
limit: How many documents to return, 1-50 (default 10). Several passages of one
|
|
96
|
+
document collapse into a single result, so this counts documents.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
JSON string: ``{"output": {"results": [{"document_id", "title", "passage",
|
|
100
|
+
"source", "source_url", "section"?}], "returned": N}}``, or ``{"error": ...}``
|
|
101
|
+
when the knowledge base could not be reached.
|
|
102
|
+
"""
|
|
103
|
+
try:
|
|
104
|
+
citations = await self._knowledge.search(query, sources=sources, limit=limit)
|
|
105
|
+
except ValueError as error:
|
|
106
|
+
return self._fail(str(error), tool="search_knowledge_base")
|
|
107
|
+
except KnowledgeServiceError as error:
|
|
108
|
+
logger.warning("KnowledgeTools: search failed: %s", error)
|
|
109
|
+
return self._fail("the knowledge base could not be reached", tool="search_knowledge_base")
|
|
110
|
+
|
|
111
|
+
rows = [self._row(citation) for citation in citations]
|
|
112
|
+
await self._notify("knowledge_searched", {"query": query, "sources": sources or [], "results": len(rows)})
|
|
113
|
+
return self._ok({"results": rows, "returned": len(rows)}, tool="search_knowledge_base")
|
{digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/module_server.py
RENAMED
|
@@ -65,7 +65,7 @@ class ModuleServer(BaseServer):
|
|
|
65
65
|
self._gateway_servicer: GatewayServicer | None = None
|
|
66
66
|
self._gateway_redis_client: RedisClient | None = None
|
|
67
67
|
|
|
68
|
-
self.
|
|
68
|
+
self._prepare_platform_configs()
|
|
69
69
|
|
|
70
70
|
def _register_servicers(self) -> None:
|
|
71
71
|
"""Register module and gateway servicers.
|
|
@@ -207,14 +207,20 @@ class ModuleServer(BaseServer):
|
|
|
207
207
|
await GrpcClientWrapper.close_all_cached_channels()
|
|
208
208
|
Bulkhead.clear_all()
|
|
209
209
|
|
|
210
|
-
def
|
|
211
|
-
"""Inject
|
|
210
|
+
def _prepare_platform_configs(self) -> None:
|
|
211
|
+
"""Inject the Service Provider client config into module_class for spawned instances.
|
|
212
|
+
|
|
213
|
+
Covers the services a module never configures itself because they are platform
|
|
214
|
+
machinery served by that same provider: the registry, and the knowledge base the
|
|
215
|
+
customer connected. The server's address wins, as it did for the registry alone.
|
|
216
|
+
"""
|
|
212
217
|
if not self.client_config:
|
|
213
218
|
return
|
|
214
219
|
|
|
215
220
|
if "services_config_params" not in self.module_class.__dict__:
|
|
216
221
|
self.module_class.services_config_params = dict(self.module_class.services_config_params)
|
|
217
|
-
|
|
222
|
+
for service in ("registry", "knowledge"):
|
|
223
|
+
self.module_class.services_config_params[service] = {"client_config": self.client_config}
|
|
218
224
|
|
|
219
225
|
async def _init_and_register(self) -> None:
|
|
220
226
|
"""Initialize registry client, health-check, and register.
|
{digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module_context.py
RENAMED
|
@@ -20,6 +20,7 @@ from digitalkin.services.communication.exceptions import ToolCallError
|
|
|
20
20
|
from digitalkin.services.cost.cost_strategy import CostStrategy
|
|
21
21
|
from digitalkin.services.filesystem.filesystem_strategy import FilesystemStrategy
|
|
22
22
|
from digitalkin.services.identity.identity_strategy import IdentityStrategy
|
|
23
|
+
from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
|
|
23
24
|
from digitalkin.services.registry.exceptions import RegistryModuleNotFoundError
|
|
24
25
|
from digitalkin.services.registry.registry_strategy import RegistryStrategy
|
|
25
26
|
from digitalkin.services.secret.secret_strategy import SecretStrategy
|
|
@@ -104,6 +105,7 @@ class ModuleContext:
|
|
|
104
105
|
cost: CostStrategy
|
|
105
106
|
filesystem: FilesystemStrategy
|
|
106
107
|
identity: IdentityStrategy
|
|
108
|
+
knowledge: KnowledgeStrategy
|
|
107
109
|
registry: RegistryStrategy
|
|
108
110
|
secret: SecretStrategy
|
|
109
111
|
setup: SetupStrategy | None
|
|
@@ -127,6 +129,7 @@ class ModuleContext:
|
|
|
127
129
|
cost: CostStrategy,
|
|
128
130
|
filesystem: FilesystemStrategy,
|
|
129
131
|
identity: IdentityStrategy,
|
|
132
|
+
knowledge: KnowledgeStrategy,
|
|
130
133
|
registry: RegistryStrategy,
|
|
131
134
|
secret: SecretStrategy,
|
|
132
135
|
storage: StorageStrategy,
|
|
@@ -149,6 +152,7 @@ class ModuleContext:
|
|
|
149
152
|
cost: CostStrategy.
|
|
150
153
|
filesystem: FilesystemStrategy.
|
|
151
154
|
identity: IdentityStrategy.
|
|
155
|
+
knowledge: KnowledgeStrategy.
|
|
152
156
|
registry: RegistryStrategy.
|
|
153
157
|
secret: SecretStrategy.
|
|
154
158
|
storage: StorageStrategy.
|
|
@@ -169,6 +173,7 @@ class ModuleContext:
|
|
|
169
173
|
self.cost = cost
|
|
170
174
|
self.filesystem = filesystem
|
|
171
175
|
self.identity = identity
|
|
176
|
+
self.knowledge = knowledge
|
|
172
177
|
self.registry = registry
|
|
173
178
|
self.secret = secret
|
|
174
179
|
self.setup = setup
|
|
@@ -574,6 +579,7 @@ class ModuleContext:
|
|
|
574
579
|
("cost", self.cost),
|
|
575
580
|
("storage", self.storage),
|
|
576
581
|
("registry", self.registry),
|
|
582
|
+
("knowledge", self.knowledge),
|
|
577
583
|
("filesystem", self.filesystem),
|
|
578
584
|
("user_profile", self.user_profile),
|
|
579
585
|
("secret", self.secret),
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"""This module contains the models for the services."""
|
|
2
2
|
|
|
3
3
|
from digitalkin.models.services.filesystem import FileMetadata, FileType, FileUploadMetadata
|
|
4
|
+
from digitalkin.models.services.knowledge import Citation, Modality
|
|
4
5
|
from digitalkin.models.services.storage import BaseMessage, BaseRole, ChatHistory, Role
|
|
5
6
|
|
|
6
7
|
__all__ = [
|
|
7
8
|
"BaseMessage",
|
|
8
9
|
"BaseRole",
|
|
9
10
|
"ChatHistory",
|
|
11
|
+
"Citation",
|
|
10
12
|
"FileMetadata",
|
|
11
13
|
"FileType",
|
|
12
14
|
"FileUploadMetadata",
|
|
15
|
+
"Modality",
|
|
13
16
|
"Role",
|
|
14
17
|
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Knowledge-service data models.
|
|
2
|
+
|
|
3
|
+
The knowledge service searches the enterprise knowledge base a user has connected
|
|
4
|
+
(Google Drive, Notion, ...) through the Context Platform. It answers with citations:
|
|
5
|
+
one per document, carrying the passage that matched and the URL to the original.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Modality(str, Enum):
|
|
15
|
+
"""What kind of content a citation's passage is.
|
|
16
|
+
|
|
17
|
+
Member names mirror the proto ``Modality`` enum, whose values are bare since
|
|
18
|
+
protocol 1.2.0 (``TEXT``, ``IMAGE``, ...) except ``MODALITY_UNSPECIFIED``: they are
|
|
19
|
+
looked up by name from the wire value, so they must match.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
UNSPECIFIED = "unspecified"
|
|
23
|
+
TEXT = "text"
|
|
24
|
+
IMAGE = "image"
|
|
25
|
+
PAGE = "page"
|
|
26
|
+
SLIDE = "slide"
|
|
27
|
+
TABLE = "table"
|
|
28
|
+
AUDIO = "audio"
|
|
29
|
+
VIDEO = "video"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Citation(BaseModel):
|
|
33
|
+
"""One document the search matched, with the passage that matched it.
|
|
34
|
+
|
|
35
|
+
A document contributes a single citation however many of its passages matched,
|
|
36
|
+
which is why ``limit`` counts documents and not passages.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
document_id: str = ""
|
|
40
|
+
title: str = ""
|
|
41
|
+
snippet: str = ""
|
|
42
|
+
score: float = 0.0
|
|
43
|
+
"""Fused rank, NOT a similarity: comparable only against the other citations of the
|
|
44
|
+
same answer, and never to be shown as a confidence."""
|
|
45
|
+
source: str = ""
|
|
46
|
+
"""The connector the document came from, e.g. ``google_drive`` or ``notion``."""
|
|
47
|
+
source_url: str = ""
|
|
48
|
+
modality: Modality = Modality.UNSPECIFIED
|
|
49
|
+
locator: dict[str, Any] = Field(default_factory=dict)
|
|
50
|
+
"""Where the passage sits in the document: ``index``, ``start``, ``end``, ``heading_path``."""
|
|
51
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def heading_path(self) -> list[str]:
|
|
55
|
+
"""The document headings leading to the passage, outermost first.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The heading path, or an empty list when the locator carries none.
|
|
59
|
+
"""
|
|
60
|
+
path = self.locator.get("heading_path")
|
|
61
|
+
return [str(item) for item in path] if isinstance(path, list) else []
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Knowledge-scope runtime settings."""
|
|
2
|
+
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class KnowledgeSettings(BaseSettings):
|
|
10
|
+
"""Knowledge client runtime configuration."""
|
|
11
|
+
|
|
12
|
+
model_config = SettingsConfigDict(env_prefix="DIGITALKIN_KNOWLEDGE_", case_sensitive=False)
|
|
13
|
+
|
|
14
|
+
search_timeout_s: float = Field(
|
|
15
|
+
default=10.0,
|
|
16
|
+
gt=0,
|
|
17
|
+
description="Per-call deadline for a knowledge search (shorter than the global gRPC default).",
|
|
18
|
+
)
|
|
19
|
+
default_limit: int = Field(
|
|
20
|
+
default=10,
|
|
21
|
+
ge=1,
|
|
22
|
+
description="Documents returned when a caller asks for no particular number.",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@lru_cache(maxsize=1)
|
|
27
|
+
def get_knowledge_settings() -> KnowledgeSettings:
|
|
28
|
+
"""Process-wide ``KnowledgeSettings`` singleton.
|
|
29
|
+
|
|
30
|
+
Tests must call ``get_knowledge_settings.cache_clear()`` after mutating env.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
The shared ``KnowledgeSettings`` instance.
|
|
34
|
+
"""
|
|
35
|
+
return KnowledgeSettings()
|
|
@@ -44,6 +44,7 @@ class HealthcheckServicesTrigger(TriggerHandler, BaseMixin):
|
|
|
44
44
|
"cost": context.cost,
|
|
45
45
|
"filesystem": context.filesystem,
|
|
46
46
|
"registry": context.registry,
|
|
47
|
+
"knowledge": context.knowledge,
|
|
47
48
|
"user_profile": context.user_profile,
|
|
48
49
|
}
|
|
49
50
|
services_status: list[ServiceHealthStatus] = []
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""This module is responsible for handling the knowledge service."""
|
|
2
|
+
|
|
3
|
+
from digitalkin.models.services.knowledge import Citation, Modality
|
|
4
|
+
from digitalkin.services.knowledge.default_knowledge import DefaultKnowledge
|
|
5
|
+
from digitalkin.services.knowledge.exceptions import KnowledgeServiceError
|
|
6
|
+
from digitalkin.services.knowledge.grpc_knowledge import GrpcKnowledge
|
|
7
|
+
from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"Citation",
|
|
11
|
+
"DefaultKnowledge",
|
|
12
|
+
"GrpcKnowledge",
|
|
13
|
+
"KnowledgeServiceError",
|
|
14
|
+
"KnowledgeStrategy",
|
|
15
|
+
"Modality",
|
|
16
|
+
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Default knowledge implementation."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from digitalkin.models.services.knowledge import Citation
|
|
7
|
+
from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
|
|
8
|
+
|
|
9
|
+
_WORDS = re.compile(r"\w+", re.UNICODE)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DefaultKnowledge(KnowledgeStrategy):
|
|
13
|
+
"""Local knowledge strategy backed by an in-memory corpus.
|
|
14
|
+
|
|
15
|
+
Keeps ``mode=LOCAL`` usable without the Context Platform: a sandbox or a test seeds
|
|
16
|
+
documents through the strategy config and gets deterministic answers offline::
|
|
17
|
+
|
|
18
|
+
services_config_params = {
|
|
19
|
+
"knowledge": {
|
|
20
|
+
"config": {
|
|
21
|
+
"documents": [
|
|
22
|
+
{
|
|
23
|
+
"document_id": "doc_1",
|
|
24
|
+
"title": "Pricing",
|
|
25
|
+
"snippet": "Apollo moved to per-seat.",
|
|
26
|
+
"source": "google_drive",
|
|
27
|
+
"source_url": "https://...",
|
|
28
|
+
},
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Matching is word overlap over title and snippet — enough to exercise a caller, never
|
|
35
|
+
a substitute for the real hybrid search.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
39
|
+
"""Initialize with the corpus declared in the strategy config."""
|
|
40
|
+
super().__init__(*args, **kwargs)
|
|
41
|
+
documents = (self.config or {}).get("documents") or []
|
|
42
|
+
self._documents: list[Citation] = [
|
|
43
|
+
document if isinstance(document, Citation) else Citation.model_validate(document) for document in documents
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def _overlap(query: str, document: Citation) -> float:
|
|
48
|
+
"""Score a document by how much of the query its text carries.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
query: The search query.
|
|
52
|
+
document: The candidate document.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The share of distinct query words found, between 0 and 1.
|
|
56
|
+
"""
|
|
57
|
+
wanted = {word.casefold() for word in _WORDS.findall(query)}
|
|
58
|
+
if not wanted:
|
|
59
|
+
return 0.0
|
|
60
|
+
haystack = {word.casefold() for word in _WORDS.findall(f"{document.title} {document.snippet}")}
|
|
61
|
+
return len(wanted & haystack) / len(wanted)
|
|
62
|
+
|
|
63
|
+
async def search(
|
|
64
|
+
self,
|
|
65
|
+
query: str,
|
|
66
|
+
sources: list[str] | None = None,
|
|
67
|
+
limit: int | None = None,
|
|
68
|
+
) -> list[Citation]:
|
|
69
|
+
"""Search the in-memory corpus.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
query: What to look for.
|
|
73
|
+
sources: Restrict to these connectors; ``None`` searches the whole corpus.
|
|
74
|
+
limit: Maximum number of documents to return.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The matching documents, best first.
|
|
78
|
+
"""
|
|
79
|
+
text, wanted_sources, bounded = self.normalize(query, sources, limit)
|
|
80
|
+
scored = [
|
|
81
|
+
(score, document)
|
|
82
|
+
for document in self._documents
|
|
83
|
+
if (not wanted_sources or document.source in wanted_sources)
|
|
84
|
+
and (score := self._overlap(text, document)) > 0
|
|
85
|
+
]
|
|
86
|
+
# Title breaks ties, so a corpus always answers in the same order.
|
|
87
|
+
scored.sort(key=lambda pair: (-pair[0], pair[1].title))
|
|
88
|
+
return [document.model_copy(update={"score": score}) for score, document in scored[:bounded]]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""gRPC knowledge client implementation.
|
|
2
|
+
|
|
3
|
+
Searches the enterprise knowledge base through the Service Provider's ContextService,
|
|
4
|
+
which relays to the Context Platform.
|
|
5
|
+
|
|
6
|
+
``SearchDocumentsRequest`` carries no identity: *who* is searching travels as the ambient
|
|
7
|
+
``x-mission-id`` metadata every outbound call already gets
|
|
8
|
+
(:class:`~digitalkin.grpc_servers.interceptors.request_ids.RequestIdClientInterceptor`),
|
|
9
|
+
and the Service Provider resolves it into the user and organization the search runs for.
|
|
10
|
+
A module therefore cannot widen its own scope, and cannot forget to narrow it.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import grpc
|
|
16
|
+
from agentic_mesh_protocol.context.v1 import (
|
|
17
|
+
context_dto_pb2,
|
|
18
|
+
context_enums_pb2,
|
|
19
|
+
context_messages_pb2,
|
|
20
|
+
context_service_pb2_grpc,
|
|
21
|
+
)
|
|
22
|
+
from google.protobuf import json_format
|
|
23
|
+
from grpc_health.v1 import health_pb2, health_pb2_grpc
|
|
24
|
+
|
|
25
|
+
from digitalkin.grpc_servers.exceptions import PermissionDeniedError, ServerError
|
|
26
|
+
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
27
|
+
from digitalkin.grpc_servers.utils.grpc_error_handler import GrpcErrorHandlerMixin
|
|
28
|
+
from digitalkin.logger import logger
|
|
29
|
+
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
30
|
+
from digitalkin.models.services.knowledge import Citation, Modality
|
|
31
|
+
from digitalkin.models.settings.knowledge import get_knowledge_settings
|
|
32
|
+
from digitalkin.services.knowledge.exceptions import KnowledgeServiceError
|
|
33
|
+
from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GrpcKnowledge(KnowledgeStrategy, GrpcClientWrapper, GrpcErrorHandlerMixin):
|
|
37
|
+
"""gRPC-based knowledge client talking to the Service Provider's ContextService."""
|
|
38
|
+
|
|
39
|
+
service_name: str = "ContextService"
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
mission_id: str,
|
|
44
|
+
setup_id: str,
|
|
45
|
+
setup_version_id: str,
|
|
46
|
+
client_config: ClientConfig,
|
|
47
|
+
config: dict[str, Any] | None = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
"""Initialize the gRPC knowledge client."""
|
|
50
|
+
KnowledgeStrategy.__init__(self, mission_id, setup_id, setup_version_id, config)
|
|
51
|
+
self.service_name = "ContextService"
|
|
52
|
+
self._init_channel(client_config)
|
|
53
|
+
self.stub = self._get_or_create_stub(context_service_pb2_grpc.ContextServiceStub)
|
|
54
|
+
logger.debug("Channel client 'Knowledge' initialized successfully")
|
|
55
|
+
|
|
56
|
+
async def close(self) -> None:
|
|
57
|
+
"""Release this instance's pooled gRPC channel ref."""
|
|
58
|
+
await self.close_channel()
|
|
59
|
+
|
|
60
|
+
async def wait_for_ready(self, timeout: float = 1.0) -> bool:
|
|
61
|
+
"""Probe the backend via the standard gRPC Health Check service.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
timeout: Max seconds for the round-trip.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
True if the server responded SERVING, False otherwise.
|
|
68
|
+
"""
|
|
69
|
+
health_stub = health_pb2_grpc.HealthStub(self._channel)
|
|
70
|
+
try:
|
|
71
|
+
response = await health_stub.Check( # type: ignore[attr-defined] # grpc_health generated stub lacks typed Check
|
|
72
|
+
health_pb2.HealthCheckRequest(service=""),
|
|
73
|
+
timeout=timeout,
|
|
74
|
+
)
|
|
75
|
+
except grpc.aio.AioRpcError:
|
|
76
|
+
return False
|
|
77
|
+
return response.status == health_pb2.HealthCheckResponse.SERVING
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def _proto_to_citation(citation: context_messages_pb2.Citation) -> Citation:
|
|
81
|
+
"""Convert a proto ``Citation`` to the SDK model.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
citation: Proto Citation message.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Citation with mapped fields.
|
|
88
|
+
"""
|
|
89
|
+
# Only ``MODALITY_UNSPECIFIED`` still carries the prefix; the rest are bare since protocol 1.2.0.
|
|
90
|
+
modality_name = context_enums_pb2.Modality.Name(citation.modality).removeprefix("MODALITY_")
|
|
91
|
+
return Citation(
|
|
92
|
+
document_id=citation.document_id,
|
|
93
|
+
title=citation.title,
|
|
94
|
+
snippet=citation.snippet,
|
|
95
|
+
score=citation.score,
|
|
96
|
+
source=citation.source,
|
|
97
|
+
source_url=citation.source_url,
|
|
98
|
+
modality=Modality[modality_name],
|
|
99
|
+
locator=json_format.MessageToDict(citation.locator),
|
|
100
|
+
metadata=json_format.MessageToDict(citation.metadata),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def search(
|
|
104
|
+
self,
|
|
105
|
+
query: str,
|
|
106
|
+
sources: list[str] | None = None,
|
|
107
|
+
limit: int | None = None,
|
|
108
|
+
) -> list[Citation]:
|
|
109
|
+
"""Search the knowledge base the current user may read.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
query: What to look for, in natural language.
|
|
113
|
+
sources: Restrict the search to these connectors; ``None`` searches every source.
|
|
114
|
+
limit: Maximum number of documents to return; ``None`` uses the configured default.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
One citation per matching document, best first.
|
|
118
|
+
|
|
119
|
+
Raises:
|
|
120
|
+
ValueError: If the query holds nothing to search for, or a source is not a
|
|
121
|
+
connector name.
|
|
122
|
+
PermissionDeniedError: If the caller is not permitted.
|
|
123
|
+
KnowledgeServiceError: If the gRPC call fails.
|
|
124
|
+
"""
|
|
125
|
+
# Normalized before the error-handler scope: an empty query and an unusable source name
|
|
126
|
+
# are permanent conditions, and must reach the caller as a ValueError rather than be
|
|
127
|
+
# wrapped as a retryable service error.
|
|
128
|
+
text, wanted_sources, bounded = self.normalize(query, sources, limit)
|
|
129
|
+
|
|
130
|
+
async with self.handle_grpc_errors("SearchDocuments", KnowledgeServiceError):
|
|
131
|
+
try:
|
|
132
|
+
response = await self.exec_grpc_query(
|
|
133
|
+
"SearchDocuments",
|
|
134
|
+
context_dto_pb2.SearchDocumentsRequest(query=text, sources=wanted_sources, limit=bounded),
|
|
135
|
+
timeout=get_knowledge_settings().search_timeout_s,
|
|
136
|
+
)
|
|
137
|
+
except PermissionDeniedError:
|
|
138
|
+
raise
|
|
139
|
+
except ServerError as e:
|
|
140
|
+
msg = f"Failed to search the knowledge base: {e}"
|
|
141
|
+
logger.error(msg)
|
|
142
|
+
raise KnowledgeServiceError(msg) from e
|
|
143
|
+
|
|
144
|
+
logger.debug("Knowledge search returned %d document(s)", len(response.results))
|
|
145
|
+
return [self._proto_to_citation(citation) for citation in response.results]
|