From 58685136864b6512a538b14ed34c9ce7ba41d152 Mon Sep 17 00:00:00 2001 From: kyteinsky Date: Tue, 23 Jun 2026 18:10:17 +0530 Subject: [PATCH 1/2] chore: move task types to the backend This is done to lift the condition on this PHP app being available for the provider registration in the backend to succeed. Now both the custom task types and the providers live in the backend. Signed-off-by: kyteinsky --- context_chat_backend/controller.py | 110 ++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 9 deletions(-) diff --git a/context_chat_backend/controller.py b/context_chat_backend/controller.py index 63766aa..12d86fa 100644 --- a/context_chat_backend/controller.py +++ b/context_chat_backend/controller.py @@ -4,7 +4,7 @@ # import time -from nc_py_api.ex_app.providers.task_processing import TaskProcessingProvider +from nc_py_api.ex_app.providers.task_processing import ShapeDescriptor, ShapeType, TaskProcessingProvider, TaskType # isort: off from .chain.types import ContextException @@ -100,26 +100,115 @@ def get_enabled_state() -> bool: last_enabled_check = time.time() return app_enabled.is_set() + def enabled_handler(enabled: bool, nc: NextcloudApp | AsyncNextcloudApp) -> str: + SEARCH_TASKTYPE_ID = 'context_chat:context_chat_search' + SEARCH_PROVIDER_ID = 'context_chat-context_chat_search' + CC_TASKTYPE_ID = 'context_chat:context_chat' + CC_PROVIDER_ID = 'context_chat-context_chat' + + # todo: translate user-facing texts try: if enabled: - provider = TaskProcessingProvider( - id='context_chat-context_chat_search', + search_tasktype = TaskType( + id=SEARCH_TASKTYPE_ID, + name='Context Chat search', + description='Search with Context Chat.', + input_shape=[ + ShapeDescriptor( + name='prompt', + description='Search your documents, files and more', + shape_type=ShapeType.TEXT, + ), + ShapeDescriptor( + name='scopeType', + description='Any of the following values: "none", "provider".', + shape_type=ShapeType.TEXT, + ), + ShapeDescriptor( + name='scopeList', + description='List of providers', + shape_type=ShapeType.LIST_OF_TEXTS, + ), + ShapeDescriptor( + name='scopeListMeta', + description='Required to nicely render the scope list in assistant', + shape_type=ShapeType.TEXT, + ), + ShapeDescriptor( + name='limit', + description='Maximum number of results returned by Context Chat', + shape_type=ShapeType.NUMBER, + ), + ], + output_shape=[ + ShapeDescriptor( + name='sources', + description='The sources that were found', + shape_type=ShapeType.LIST_OF_TEXTS, + ), + ], + ) + + search_provider = TaskProcessingProvider( + id=SEARCH_PROVIDER_ID, name='Context Chat', - task_type='context_chat:context_chat_search', + task_type=SEARCH_TASKTYPE_ID, expected_runtime=30, input_shape_defaults={ 'limit': 10, }, ) - nc.providers.task_processing.register(provider) - provider = TaskProcessingProvider( - id='context_chat-context_chat', + nc.providers.task_processing.register(search_provider, search_tasktype) + + cc_tasktype = TaskType( + id=CC_TASKTYPE_ID, + name='Context Chat', + description='Ask a question about your data.', + input_shape=[ + ShapeDescriptor( + name='prompt', + description='Ask a question about your documents, files and more', + shape_type=ShapeType.TEXT, + ), + ShapeDescriptor( + name='scopeType', + description='Any of the following values: "none", "source", "provider".', + shape_type=ShapeType.TEXT, + ), + ShapeDescriptor( + name='scopeList', + description='List of sources or providers', + shape_type=ShapeType.LIST_OF_TEXTS, + ), + ShapeDescriptor( + name='scopeListMeta', + description='Required to nicely render the scope list in assistant', + shape_type=ShapeType.TEXT, + ), + ], + output_shape=[ + ShapeDescriptor( + name='output', + description='The text generated by the model', + shape_type=ShapeType.TEXT, + ), + ShapeDescriptor( + name='sources', + description='The sources referenced to generate the above response', + shape_type=ShapeType.LIST_OF_TEXTS, + ), + ], + ) + + cc_provider = TaskProcessingProvider( + id=CC_PROVIDER_ID, name='Context Chat', - task_type='context_chat:context_chat', + task_type=CC_TASKTYPE_ID, expected_runtime=30, ) - nc.providers.task_processing.register(provider) + nc.providers.task_processing.register(cc_provider, cc_tasktype) + app_enabled.set() if THREAD_STOP_EVENT.is_set(): # If the threads were previously stopped, we start them again @@ -128,6 +217,9 @@ def enabled_handler(enabled: bool, nc: NextcloudApp | AsyncNextcloudApp) -> str: THREAD_STOP_EVENT.clear() else: app_enabled.clear() + nc.providers.task_processing.unregister(SEARCH_PROVIDER_ID) + nc.providers.task_processing.unregister(CC_PROVIDER_ID) + wait_for_bg_threads() except Exception as e: logger.exception('Error in enabled handler:', exc_info=e) From 990db7c928f1093694dff995b99a2d04082ea9cf Mon Sep 17 00:00:00 2001 From: kyteinsky Date: Wed, 24 Jun 2026 11:28:38 +0530 Subject: [PATCH 2/2] fix(ci): short the wait time only when locked is also 0 Signed-off-by: kyteinsky --- .github/workflows/integration-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index fe348dd..2096bfb 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -411,12 +411,12 @@ jobs: scheduled=$(echo "$stats" | jq '[.queued_documents_counts | to_entries[].value] | add // 0') locked=$(echo "$stats" | jq '[.queued_documents_locked_counts | to_entries[].value] | add // 0') echo "Attempt $i: queued_documents=$scheduled locked=$locked" - if [ "$scheduled" = "0" ]; then + if [ "$scheduled" = "0" ] && [ "$locked" = "0" ]; then echo "Queue drained" break fi if [ "$i" = "30" ]; then - echo "Timeout: queue did not drain to zero (queued_documents=$scheduled)" + echo "Timeout: queue did not drain to zero (queued_documents=$scheduled locked=$locked)" exit 1 fi sleep 10