From 4789727693cfb1228eca5e25dfc3548743c064d3 Mon Sep 17 00:00:00 2001 From: Viswamedha Nalabotu Date: Wed, 18 Mar 2026 23:17:28 +0000 Subject: [PATCH] Updated failing tests --- apps/knowledge/tests/test_api.py | 8 ++- apps/onboarding/tests/test_api.py | 1 + apps/onboarding/viewsets.py | 115 ++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/apps/knowledge/tests/test_api.py b/apps/knowledge/tests/test_api.py index 035f1cd..a6be0f5 100644 --- a/apps/knowledge/tests/test_api.py +++ b/apps/knowledge/tests/test_api.py @@ -1,3 +1,5 @@ +from unittest.mock import patch + from django.contrib.auth import get_user_model from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models.signals import post_save @@ -102,7 +104,8 @@ class KnowledgeApiTests(TestCase): ) self.assertIn(response.status_code, (HTTP_200_OK, HTTP_400_BAD_REQUEST)) - def test_training_file_destroy_path(self): + @patch('apps.knowledge.viewsets.update_agent_prompts_from_file_task') + def test_training_file_destroy_path(self, mock_task): self.client.force_authenticate(self.owner) response = self.client.delete(f'/api/training-file/{self.training_file.uuid}/') self.assertEqual(response.status_code, HTTP_204_NO_CONTENT) @@ -166,7 +169,8 @@ class KnowledgeApiTests(TestCase): response = self.client.delete(f'/api/training-file/{self.training_file.uuid}/') self.assertEqual(response.status_code, HTTP_403_FORBIDDEN) - def test_training_file_destroy_allowed_for_org_manager_member(self): + @patch('apps.knowledge.viewsets.update_agent_prompts_from_file_task') + def test_training_file_destroy_allowed_for_org_manager_member(self, mock_task): manager_member = User.objects.create_user( email_address='manager-member-k@example.com', password='pass1234', diff --git a/apps/onboarding/tests/test_api.py b/apps/onboarding/tests/test_api.py index 3e147c3..c35f8e8 100644 --- a/apps/onboarding/tests/test_api.py +++ b/apps/onboarding/tests/test_api.py @@ -48,6 +48,7 @@ class OnboardingApiTests(TestCase): self.session = OnboardingSession.objects.create( user=self.member, role=self.role, + flow=self.flow, state={'progress': 10}, active_configs={}, ) diff --git a/apps/onboarding/viewsets.py b/apps/onboarding/viewsets.py index 0c4a368..9ac9d28 100644 --- a/apps/onboarding/viewsets.py +++ b/apps/onboarding/viewsets.py @@ -159,6 +159,16 @@ class OnboardingFlowViewSet(RequestParamMixin, ModelViewSet): session = OnboardingSession.objects.filter(user=request.user, role=flow.role, flow=flow).first() if not session: + session = OnboardingSession.objects.filter(user=request.user, role=flow.role).first() + if session: + state = session.state or {} + state['flow_uuid'] = str(flow.uuid) + session.flow = flow + session.state = state + session.save(update_fields=['flow', 'state', 'updated_at']) + serializer = OnboardingSessionSerializer(session) + return Response(serializer.data, status=HTTP_200_OK) + session = OnboardingSession.objects.create( user=request.user, role=flow.role, @@ -751,6 +761,111 @@ class OnboardingSessionViewSet(RequestParamMixin, ModelViewSet): return quiz_result, None + def _call_ka(self, session, page, message): + config = self._get_agent_config(session, 'knowledge') + system_prompt = self._build_system_prompt(config) + page_body = str(page.get('body') or '') if isinstance(page, dict) else '' + page_title = str(page.get('title') or '') if isinstance(page, dict) else '' + context = f"Page: {page_title}\n\n{page_body}" if page_body else page_title + prompt = f"Context:\n{context}\n\nQuestion: {message}" + try: + with httpx.Client(timeout=60.0) as client: + model_id = (config.llm_config or {}).get('model_id', 'meta-llama-3.1-8b') if config else 'meta-llama-3.1-8b' + response = client.post( + settings.INFERENCE_CHAT_COMPLETIONS_ENDPOINT, + json={ + 'model': model_id, + 'messages': [ + {'role': 'system', 'content': system_prompt}, + {'role': 'user', 'content': prompt}, + ], + 'max_tokens': 512, + }, + ) + response.raise_for_status() + return response.json().get('choices', [{}])[0].get('message', {}).get('content', '') or 'No answer available.' + except Exception: + return 'Knowledge agent is temporarily unavailable. Please try again later.' + + def _run_ka_page_revision(self, session, page, message): + config = self._get_agent_config(session, 'knowledge') + system_prompt = self._build_system_prompt(config) + page_body = str(page.get('body') or '') if isinstance(page, dict) else '' + page_title = str(page.get('title') or '') if isinstance(page, dict) else '' + prompt = ( + f"You are revising onboarding page content to incorporate a learner's clarification request.\n\n" + f"Page Title: {page_title}\n" + f"Original Body:\n{page_body}\n\n" + f"Learner's request: {message}\n\n" + f"Rewrite the page body to address the learner's request while preserving the original content structure. " + f"Return only the revised page body." + ) + try: + with httpx.Client(timeout=60.0) as client: + model_id = (config.llm_config or {}).get('model_id', 'meta-llama-3.1-8b') if config else 'meta-llama-3.1-8b' + response = client.post( + settings.INFERENCE_CHAT_COMPLETIONS_ENDPOINT, + json={ + 'model': model_id, + 'messages': [ + {'role': 'system', 'content': system_prompt}, + {'role': 'user', 'content': prompt}, + ], + 'max_tokens': 1024, + }, + ) + response.raise_for_status() + return response.json().get('choices', [{}])[0].get('message', {}).get('content', '') or page_body + except Exception: + return page_body + + @action(detail=True, methods=['post'], url_path='ask-ka') + def ask_ka(self, request, uuid=None): + session = self.get_object() + page_uuid = request.data.get('page_uuid') + message = request.data.get('message') + mode = request.data.get('mode', 'separate') + + if not page_uuid or not message: + return Response({'error': 'page_uuid and message are required.'}, status=HTTP_400_BAD_REQUEST) + + flow = self._get_flow_for_session(session) + page = None + if flow: + page, _ = self._get_page_from_flow(flow, page_uuid) + + if mode == 'update_page': + revised_body = self._run_ka_page_revision(session, page, message) + state = session.state or {} + overrides = state.get('page_overrides', {}) + if not isinstance(overrides, dict): + overrides = {} + overrides[str(page_uuid)] = revised_body + state['page_overrides'] = overrides + session.state = state + session.save(update_fields=['state', 'updated_at']) + return Response({ + 'status': 'ok', + 'updated_page': True, + 'revised_page_body': revised_body, + 'session_state': session.state, + }) + + answer = self._call_ka(session, page, message) + state = session.state or {} + page_help = state.get('page_help', {}) + if not isinstance(page_help, dict): + page_help = {} + page_help[str(page_uuid)] = answer + state['page_help'] = page_help + session.state = state + session.save(update_fields=['state', 'updated_at']) + return Response({ + 'status': 'ok', + 'answer': answer, + 'session_state': session.state, + }) + @action(detail=True, methods=['post'], url_path='interact') def interact(self, request, uuid=None): session = self.get_object()