From 412c31fcccee65a52955d01cff9d97e3c0987723 Mon Sep 17 00:00:00 2001 From: Akhilesh Negi Date: Thu, 19 Jun 2025 14:40:45 +0530 Subject: [PATCH 1/4] check if vector store is linked or not --- backend/app/api/routes/responses.py | 44 +++++++++++++++++++---------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/backend/app/api/routes/responses.py b/backend/app/api/routes/responses.py index fc10cd479..83132f4e0 100644 --- a/backend/app/api/routes/responses.py +++ b/backend/app/api/routes/responses.py @@ -79,6 +79,10 @@ class ResponsesAPIResponse(APIResponse[_APIResponse]): def get_file_search_results(response): results: list[FileResultChunk] = [] + # If response has no output attribute or it's empty, return empty results + if not hasattr(response, "output"): + return results + for tool_call in response.output: if tool_call.type == "file_search_call": results.extend( @@ -106,21 +110,31 @@ def process_response( f"Starting generating response for assistant_id={request.assistant_id}, project_id={request.project_id}, organization_id={organization_id}" ) try: - response = client.responses.create( - model=assistant.model, - previous_response_id=request.response_id, - instructions=assistant.instructions, - tools=[ - { - "type": "file_search", - "vector_store_ids": [assistant.vector_store_id], - "max_num_results": assistant.max_num_results, - } - ], - temperature=assistant.temperature, - input=[{"role": "user", "content": request.question}], - include=["file_search_call.results"], - ) + # Create response with or without tools based on vector_store_id + if assistant.vector_store_id: + response = client.responses.create( + model=assistant.model, + previous_response_id=request.response_id, + instructions=assistant.instructions, + tools=[ + { + "type": "file_search", + "vector_store_ids": [assistant.vector_store_id], + "max_num_results": assistant.max_num_results, + } + ], + temperature=assistant.temperature, + input=[{"role": "user", "content": request.question}], + include=["file_search_call.results"], + ) + else: + response = client.responses.create( + model=assistant.model, + previous_response_id=request.response_id, + instructions=assistant.instructions, + temperature=assistant.temperature, + input=[{"role": "user", "content": request.question}], + ) response_chunks = get_file_search_results(response) logger.info( f"Successfully generated response: response_id={response.id}, assistant={request.assistant_id}, project_id={request.project_id}, organization_id={organization_id}" From 5835245cdf51c5935e7637a465d3cfb253003301 Mon Sep 17 00:00:00 2001 From: Akhilesh Negi Date: Thu, 19 Jun 2025 14:44:43 +0530 Subject: [PATCH 2/4] added testcases --- .../app/tests/api/routes/test_responses.py | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/backend/app/tests/api/routes/test_responses.py b/backend/app/tests/api/routes/test_responses.py index 40de2d81b..257d2585a 100644 --- a/backend/app/tests/api/routes/test_responses.py +++ b/backend/app/tests/api/routes/test_responses.py @@ -70,3 +70,72 @@ def test_responses_endpoint_success( assert response_json["success"] is True assert response_json["data"]["status"] == "processing" assert response_json["data"]["message"] == "Response creation started" + + +@patch("app.api.routes.responses.OpenAI") +@patch("app.api.routes.responses.get_provider_credential") +@patch("app.api.routes.responses.get_assistant_by_id") +def test_responses_endpoint_without_vector_store( + mock_get_assistant, + mock_get_credential, + mock_openai, + db, +): + """Test the /responses endpoint when assistant has no vector store configured.""" + # Setup mock credentials + mock_get_credential.return_value = {"api_key": "test_api_key"} + + # Setup mock assistant without vector store + mock_assistant = MagicMock() + mock_assistant.model = "gpt-4" + mock_assistant.instructions = "Test instructions" + mock_assistant.temperature = 0.1 + mock_assistant.vector_store_id = None # No vector store configured + mock_get_assistant.return_value = mock_assistant + + # Setup mock OpenAI client + mock_client = MagicMock() + mock_openai.return_value = mock_client + + # Setup the mock response object + mock_response = MagicMock() + mock_response.id = "mock_response_id" + mock_response.output_text = "Test output" + mock_response.model = "gpt-4" + mock_response.usage.input_tokens = 10 + mock_response.usage.output_tokens = 5 + mock_response.usage.total_tokens = 15 + # No output attribute since there are no tool calls + mock_client.responses.create.return_value = mock_response + + # Get the Glific project ID + glific_project = db.exec(select(Project).where(Project.name == "Glific")).first() + if not glific_project: + pytest.skip("Glific project not found in the database") + + # Use the original API key from seed data + original_api_key = "ApiKey No3x47A5qoIGhm0kVKjQ77dhCqEdWRIQZlEPzzzh7i8" + + headers = {"X-API-KEY": original_api_key} + request_data = { + "project_id": glific_project.id, + "assistant_id": "assistant_123", + "question": "What is Glific?", + "callback_url": "http://example.com/callback", + } + + response = client.post("/responses", json=request_data, headers=headers) + assert response.status_code == 200 + response_json = response.json() + assert response_json["success"] is True + assert response_json["data"]["status"] == "processing" + assert response_json["data"]["message"] == "Response creation started" + + # Verify OpenAI client was called without tools + mock_client.responses.create.assert_called_once_with( + model=mock_assistant.model, + previous_response_id=None, + instructions=mock_assistant.instructions, + temperature=mock_assistant.temperature, + input=[{"role": "user", "content": "What is Glific?"}], + ) From 3beea742b6f658b999b85bbfd0e048a6af0913c2 Mon Sep 17 00:00:00 2001 From: Akhilesh Negi Date: Thu, 19 Jun 2025 14:59:29 +0530 Subject: [PATCH 3/4] cleanups --- backend/app/api/routes/responses.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/app/api/routes/responses.py b/backend/app/api/routes/responses.py index 83132f4e0..2292d0687 100644 --- a/backend/app/api/routes/responses.py +++ b/backend/app/api/routes/responses.py @@ -79,10 +79,6 @@ class ResponsesAPIResponse(APIResponse[_APIResponse]): def get_file_search_results(response): results: list[FileResultChunk] = [] - # If response has no output attribute or it's empty, return empty results - if not hasattr(response, "output"): - return results - for tool_call in response.output: if tool_call.type == "file_search_call": results.extend( From db04b1055bb5c822e8fbfa141b9c6b9e6c69b47a Mon Sep 17 00:00:00 2001 From: Akhilesh Negi Date: Thu, 19 Jun 2025 22:48:53 +0530 Subject: [PATCH 4/4] refactor --- backend/app/api/routes/responses.py | 42 +++++++++++++---------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/backend/app/api/routes/responses.py b/backend/app/api/routes/responses.py index 2292d0687..ed098af6f 100644 --- a/backend/app/api/routes/responses.py +++ b/backend/app/api/routes/responses.py @@ -107,30 +107,26 @@ def process_response( ) try: # Create response with or without tools based on vector_store_id + params = { + "model": assistant.model, + "previous_response_id": request.response_id, + "instructions": assistant.instructions, + "temperature": assistant.temperature, + "input": [{"role": "user", "content": request.question}], + } + if assistant.vector_store_id: - response = client.responses.create( - model=assistant.model, - previous_response_id=request.response_id, - instructions=assistant.instructions, - tools=[ - { - "type": "file_search", - "vector_store_ids": [assistant.vector_store_id], - "max_num_results": assistant.max_num_results, - } - ], - temperature=assistant.temperature, - input=[{"role": "user", "content": request.question}], - include=["file_search_call.results"], - ) - else: - response = client.responses.create( - model=assistant.model, - previous_response_id=request.response_id, - instructions=assistant.instructions, - temperature=assistant.temperature, - input=[{"role": "user", "content": request.question}], - ) + params["tools"] = [ + { + "type": "file_search", + "vector_store_ids": [assistant.vector_store_id], + "max_num_results": assistant.max_num_results, + } + ] + params["include"] = ["file_search_call.results"] + + response = client.responses.create(**params) + response_chunks = get_file_search_results(response) logger.info( f"Successfully generated response: response_id={response.id}, assistant={request.assistant_id}, project_id={request.project_id}, organization_id={organization_id}"