unique_deep_research 3.2.0__tar.gz → 3.2.2__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.
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/CHANGELOG.md +6 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/PKG-INFO +7 -1
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/pyproject.toml +1 -1
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/service.py +34 -26
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/LICENSE +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/README.md +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/__init__.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/config.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/markdown_utils.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/clarifying_agent.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/openai/oai_research_system_message.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/report_cleanup_prompt.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/research_instructions_agent.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/unique/compress_research_system.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/unique/lead_agent_system.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/unique/report_writer_system_open_deep_research.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/templates/unique/research_agent_system.j2 +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/unique_custom/__init__.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/unique_custom/agents.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/unique_custom/citation.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/unique_custom/state.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/unique_custom/tools.py +0 -0
- {unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/unique_custom/utils.py +0 -0
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.2.2] - 2026-02-05
|
|
9
|
+
- Fix bug where deep research tool was not using the correct headers causing an authentication error
|
|
10
|
+
|
|
11
|
+
## [3.2.1] - 2026-02-05
|
|
12
|
+
- Use deep research logger instead of tool logger
|
|
13
|
+
|
|
8
14
|
## [3.2.0] - 2026-02-03
|
|
9
15
|
- Use a backwards compatible config style
|
|
10
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_deep_research
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.2
|
|
4
4
|
Summary: Deep Research Tool for complex research tasks
|
|
5
5
|
License: Proprietary
|
|
6
6
|
Author: Martin Fadler
|
|
@@ -36,6 +36,12 @@ All notable changes to this project will be documented in this file.
|
|
|
36
36
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
37
37
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
38
38
|
|
|
39
|
+
## [3.2.2] - 2026-02-05
|
|
40
|
+
- Fix bug where deep research tool was not using the correct headers causing an authentication error
|
|
41
|
+
|
|
42
|
+
## [3.2.1] - 2026-02-05
|
|
43
|
+
- Use deep research logger instead of tool logger
|
|
44
|
+
|
|
39
45
|
## [3.2.0] - 2026-02-03
|
|
40
46
|
- Use a backwards compatible config style
|
|
41
47
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from typing import Any, Optional
|
|
2
3
|
|
|
3
4
|
from httpx import AsyncClient
|
|
@@ -65,6 +66,8 @@ from .unique_custom.utils import (
|
|
|
65
66
|
get_next_message_order,
|
|
66
67
|
)
|
|
67
68
|
|
|
69
|
+
_LOGGER = logging.getLogger(__name__)
|
|
70
|
+
|
|
68
71
|
|
|
69
72
|
class DeepResearchToolInput(BaseModel):
|
|
70
73
|
model_config = ConfigDict(extra="forbid")
|
|
@@ -107,9 +110,16 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
107
110
|
self.company_id = event.company_id
|
|
108
111
|
self.user_id = event.user_id
|
|
109
112
|
|
|
110
|
-
self.client = get_async_openai_client(
|
|
113
|
+
self.client = get_async_openai_client(
|
|
114
|
+
additional_headers={
|
|
115
|
+
"x-company-id": self.company_id,
|
|
116
|
+
"x-user-id": self.user_id,
|
|
117
|
+
"x-assistant-id": self.event.payload.assistant_id,
|
|
118
|
+
"x-chat-id": self.chat_id,
|
|
119
|
+
}
|
|
120
|
+
)
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
_LOGGER.info(f"Using async OpenAI client pointed to {self.client.base_url}")
|
|
113
123
|
|
|
114
124
|
self.content_service = ContentService(
|
|
115
125
|
company_id=self.company_id,
|
|
@@ -207,7 +217,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
207
217
|
except Exception as e:
|
|
208
218
|
if self.is_message_execution():
|
|
209
219
|
await self._update_execution_status(MessageExecutionUpdateStatus.FAILED)
|
|
210
|
-
|
|
220
|
+
_LOGGER.exception(f"Deep Research tool run failed: {e}")
|
|
211
221
|
await self.chat_service.modify_assistant_message_async(
|
|
212
222
|
content="Deep Research failed to complete for an unknown reason",
|
|
213
223
|
set_completed_at=True,
|
|
@@ -220,13 +230,13 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
220
230
|
)
|
|
221
231
|
|
|
222
232
|
async def _run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
|
|
223
|
-
|
|
233
|
+
_LOGGER.info("Starting Deep Research tool run")
|
|
224
234
|
|
|
225
235
|
await self._clear_original_message()
|
|
226
236
|
|
|
227
237
|
# Question answer and message execution will have the same message id, so we need to check if it is a message execution
|
|
228
238
|
if await self.is_followup_question_answer() and not self.is_message_execution():
|
|
229
|
-
|
|
239
|
+
_LOGGER.info("This is a follow-up question answer")
|
|
230
240
|
self.chat_service.create_message_execution(
|
|
231
241
|
message_id=self.event.payload.assistant_message.id,
|
|
232
242
|
type=MessageExecutionType.DEEP_RESEARCH,
|
|
@@ -240,7 +250,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
240
250
|
content="",
|
|
241
251
|
)
|
|
242
252
|
if self.is_message_execution():
|
|
243
|
-
|
|
253
|
+
_LOGGER.info("Starting research")
|
|
244
254
|
# Run research
|
|
245
255
|
self.write_message_log_text_message("**Generating research plan**")
|
|
246
256
|
research_brief = await self.generate_research_brief_from_dict(
|
|
@@ -386,15 +396,15 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
386
396
|
result = "", []
|
|
387
397
|
match self.config.engine.get_type():
|
|
388
398
|
case DeepResearchEngine.OPENAI:
|
|
389
|
-
|
|
399
|
+
_LOGGER.info("Running OpenAI research")
|
|
390
400
|
result = await self.openai_research(research_brief)
|
|
391
401
|
case DeepResearchEngine.UNIQUE:
|
|
392
|
-
|
|
402
|
+
_LOGGER.info("Running Custom research")
|
|
393
403
|
result = await self.custom_research(research_brief)
|
|
394
404
|
self.write_message_log_text_message("**Research done**")
|
|
395
405
|
return result
|
|
396
406
|
except Exception as e:
|
|
397
|
-
|
|
407
|
+
_LOGGER.exception(f"Research failed: {e}")
|
|
398
408
|
return "", []
|
|
399
409
|
|
|
400
410
|
async def custom_research(self, research_brief: str) -> tuple[str, list[Any]]:
|
|
@@ -464,14 +474,14 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
464
474
|
content=processed_result,
|
|
465
475
|
references=references,
|
|
466
476
|
)
|
|
467
|
-
|
|
477
|
+
_LOGGER.info(
|
|
468
478
|
f"Custom research completed with {len(references)} validated citations"
|
|
469
479
|
)
|
|
470
480
|
return processed_result, []
|
|
471
481
|
|
|
472
482
|
except Exception as e:
|
|
473
483
|
error_msg = f"Custom research failed: {str(e)}"
|
|
474
|
-
|
|
484
|
+
_LOGGER.exception(error_msg)
|
|
475
485
|
return error_msg, []
|
|
476
486
|
|
|
477
487
|
async def openai_research(self, research_brief: str) -> tuple[str, list[Any]]:
|
|
@@ -553,14 +563,14 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
553
563
|
match event.type:
|
|
554
564
|
case "response.completed":
|
|
555
565
|
if event.response.usage:
|
|
556
|
-
|
|
566
|
+
_LOGGER.info(
|
|
557
567
|
f"OpenAI research token usage: {event.response.usage}"
|
|
558
568
|
)
|
|
559
569
|
# Extract the final output with annotations
|
|
560
570
|
if event.response.output and len(event.response.output) > 0:
|
|
561
571
|
final_output = event.response.output[-1]
|
|
562
572
|
if not isinstance(final_output, ResponseOutputMessage):
|
|
563
|
-
|
|
573
|
+
_LOGGER.warning(
|
|
564
574
|
f"Unexpected output type: {type(final_output)}"
|
|
565
575
|
)
|
|
566
576
|
continue
|
|
@@ -573,9 +583,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
573
583
|
# Extract final report and references
|
|
574
584
|
report_text = content_item.text
|
|
575
585
|
annotations = content_item.annotations or []
|
|
576
|
-
|
|
577
|
-
"Final report extracted from OpenAI stream"
|
|
578
|
-
)
|
|
586
|
+
_LOGGER.info("Final report extracted from OpenAI stream")
|
|
579
587
|
return report_text, annotations
|
|
580
588
|
return event.response.output_text or "", []
|
|
581
589
|
case "response.incomplete":
|
|
@@ -607,7 +615,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
607
615
|
if isinstance(
|
|
608
616
|
event.item.action, ActionSearch
|
|
609
617
|
) and isinstance(event.item.action.query, str):
|
|
610
|
-
|
|
618
|
+
_LOGGER.info("OpenAI web search")
|
|
611
619
|
self.chat_service.create_message_log(
|
|
612
620
|
message_id=self.event.payload.assistant_message.id,
|
|
613
621
|
text="**Searching the web**",
|
|
@@ -630,13 +638,13 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
630
638
|
elif isinstance(
|
|
631
639
|
event.item.action, ActionOpenPage
|
|
632
640
|
) or isinstance(event.item.action, ActionFind):
|
|
633
|
-
|
|
641
|
+
_LOGGER.info("OpenAI reading web page")
|
|
634
642
|
if (
|
|
635
643
|
not event.item.action.url
|
|
636
644
|
or not isinstance(event.item.action.url, str)
|
|
637
645
|
or "https://" not in event.item.action.url
|
|
638
646
|
):
|
|
639
|
-
|
|
647
|
+
_LOGGER.warning(
|
|
640
648
|
f"Invalid URL from OpenAI: {event.item.action}"
|
|
641
649
|
)
|
|
642
650
|
continue
|
|
@@ -646,12 +654,12 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
646
654
|
event.item.action.url,
|
|
647
655
|
)
|
|
648
656
|
if not success:
|
|
649
|
-
|
|
657
|
+
_LOGGER.info(
|
|
650
658
|
f"Failed to crawl URL: {event.item.action.url} but openai still opened the page"
|
|
651
659
|
)
|
|
652
660
|
continue
|
|
653
661
|
if not title:
|
|
654
|
-
|
|
662
|
+
_LOGGER.info(
|
|
655
663
|
f"No title found for URL: {event.item.action.url}"
|
|
656
664
|
)
|
|
657
665
|
continue
|
|
@@ -678,7 +686,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
678
686
|
),
|
|
679
687
|
)
|
|
680
688
|
else:
|
|
681
|
-
|
|
689
|
+
_LOGGER.info(
|
|
682
690
|
f"OpenAI web action unexpected type: {type(event.item)}"
|
|
683
691
|
)
|
|
684
692
|
case "response.failed":
|
|
@@ -699,9 +707,9 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
699
707
|
if event.response.error:
|
|
700
708
|
return event.response.error.message, []
|
|
701
709
|
except Exception as e:
|
|
702
|
-
|
|
710
|
+
_LOGGER.exception(f"Error processing research stream event: {e}")
|
|
703
711
|
|
|
704
|
-
|
|
712
|
+
_LOGGER.error("Stream ended without completion")
|
|
705
713
|
return "", []
|
|
706
714
|
|
|
707
715
|
async def _postprocess_report_with_gpt(self, research_result: str) -> str:
|
|
@@ -737,10 +745,10 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
737
745
|
|
|
738
746
|
formatted_result = response.choices[0].message.content
|
|
739
747
|
if formatted_result:
|
|
740
|
-
|
|
748
|
+
_LOGGER.info("Successfully post-processed research report")
|
|
741
749
|
return formatted_result
|
|
742
750
|
else:
|
|
743
|
-
|
|
751
|
+
_LOGGER.warning("Post-processing returned empty result, using original")
|
|
744
752
|
return research_result
|
|
745
753
|
|
|
746
754
|
def get_tool_call_result_for_loop_history(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_deep_research-3.2.0 → unique_deep_research-3.2.2}/unique_deep_research/markdown_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|