unique_deep_research 2026.36.0.dev0__tar.gz → 2026.36.0.dev2__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-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/PKG-INFO +3 -3
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/pyproject.toml +3 -3
- unique_deep_research-2026.36.0.dev2/unique_deep_research/invocation_stats.py +5 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/service.py +9 -16
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/unique_custom/utils.py +2 -2
- unique_deep_research-2026.36.0.dev0/unique_deep_research/invocation_stats.py +0 -84
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/README.md +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/__init__.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/config.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/markdown_utils.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/clarifying_agent.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/openai/oai_research_system_message.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/report_cleanup_prompt.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/research_instructions_agent.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/unique/compress_research_system.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/unique/lead_agent_system.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/unique/report_writer_system_open_deep_research.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/templates/unique/research_agent_system.j2 +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/unique_custom/__init__.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/unique_custom/agents.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/unique_custom/citation.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/unique_custom/state.py +0 -0
- {unique_deep_research-2026.36.0.dev0 → unique_deep_research-2026.36.0.dev2}/unique_deep_research/unique_custom/tools.py +0 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-deep-research
|
|
3
|
-
Version: 2026.36.0.
|
|
3
|
+
Version: 2026.36.0.dev2
|
|
4
4
|
Summary: Deep Research Tool for complex research tasks
|
|
5
5
|
Author: Martin Fadler, Sadique Sheik, Fabian Schläpfer, Pascal Hauri
|
|
6
6
|
Author-email: Martin Fadler <martin.fadler@unique.ch>, Sadique Sheik <sadique@unique.ch>, Fabian Schläpfer <fabian@unique.ch>, Pascal Hauri <pascal@unique.ch>
|
|
7
7
|
License: Proprietary
|
|
8
8
|
Requires-Dist: pydantic>=2.8.2,<3
|
|
9
9
|
Requires-Dist: typing-extensions>=4.9.0,<5
|
|
10
|
-
Requires-Dist: unique-toolkit>=2026.36.0.
|
|
10
|
+
Requires-Dist: unique-toolkit>=2026.36.0.dev6,<2026.36.0rc0
|
|
11
11
|
Requires-Dist: jinja2>=3.1.2,<4
|
|
12
12
|
Requires-Dist: openai>=1.99.0,<3
|
|
13
13
|
Requires-Dist: langgraph>=1.0.0,<2
|
|
14
14
|
Requires-Dist: langchain-core>=1.0.0,<2
|
|
15
|
-
Requires-Dist: unique-web-search>=2026.36.0.
|
|
15
|
+
Requires-Dist: unique-web-search>=2026.36.0.dev3,<2026.36.0rc0
|
|
16
16
|
Requires-Dist: httpx>=0.28.0,<0.29
|
|
17
17
|
Requires-Dist: timeout-decorator>=0.5.0,<0.6
|
|
18
18
|
Requires-Dist: beautifulsoup4>=4.12.0,<5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_deep_research"
|
|
3
|
-
version = "2026.36.0.
|
|
3
|
+
version = "2026.36.0.dev2"
|
|
4
4
|
description = "Deep Research Tool for complex research tasks"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Proprietary" }
|
|
@@ -14,12 +14,12 @@ requires-python = ">=3.12,<4"
|
|
|
14
14
|
dependencies = [
|
|
15
15
|
"pydantic>=2.8.2,<3",
|
|
16
16
|
"typing-extensions>=4.9.0,<5",
|
|
17
|
-
"unique-toolkit>=2026.36.0.
|
|
17
|
+
"unique-toolkit>=2026.36.0.dev6,<2026.36.0rc0",
|
|
18
18
|
"jinja2>=3.1.2,<4",
|
|
19
19
|
"openai>=1.99.0,<3",
|
|
20
20
|
"langgraph>=1.0.0,<2",
|
|
21
21
|
"langchain-core>=1.0.0,<2",
|
|
22
|
-
"unique-web-search>=2026.36.0.
|
|
22
|
+
"unique-web-search>=2026.36.0.dev3,<2026.36.0rc0",
|
|
23
23
|
"httpx>=0.28.0,<0.29",
|
|
24
24
|
"timeout-decorator>=0.5.0,<0.6",
|
|
25
25
|
"beautifulsoup4>=4.12.0,<5",
|
|
@@ -50,9 +50,7 @@ from unique_toolkit.language_model.schemas import (
|
|
|
50
50
|
LanguageModelMessageRole,
|
|
51
51
|
)
|
|
52
52
|
from unique_toolkit.short_term_memory.service import ShortTermMemoryService
|
|
53
|
-
from unique_web_search.invocation_stats import
|
|
54
|
-
invocation_stats_scope as web_search_invocation_stats_scope,
|
|
55
|
-
)
|
|
53
|
+
from unique_web_search.invocation_stats import collector as web_search_collector
|
|
56
54
|
|
|
57
55
|
from unique_deep_research.unique_custom.tools import crawl_url, get_today_str
|
|
58
56
|
|
|
@@ -63,12 +61,7 @@ from .config import (
|
|
|
63
61
|
DeepResearchToolConfig,
|
|
64
62
|
UniqueEngine,
|
|
65
63
|
)
|
|
66
|
-
from .invocation_stats import
|
|
67
|
-
invocation_stats_scope,
|
|
68
|
-
record_invocation_stats,
|
|
69
|
-
record_language_model_response,
|
|
70
|
-
record_token_usage,
|
|
71
|
-
)
|
|
64
|
+
from .invocation_stats import collector
|
|
72
65
|
from .markdown_utils import (
|
|
73
66
|
export_report_to_docx,
|
|
74
67
|
postprocess_research_result_with_chunks,
|
|
@@ -270,7 +263,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
270
263
|
)
|
|
271
264
|
|
|
272
265
|
async def run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
|
|
273
|
-
with
|
|
266
|
+
with collector.scope() as invocation_stats:
|
|
274
267
|
sub = self.chat_service.cancellation.on_cancellation.subscribe(
|
|
275
268
|
self._on_cancellation
|
|
276
269
|
)
|
|
@@ -555,7 +548,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
555
548
|
},
|
|
556
549
|
}
|
|
557
550
|
|
|
558
|
-
with
|
|
551
|
+
with web_search_collector.scope() as web_search_invocation_stats:
|
|
559
552
|
try:
|
|
560
553
|
result = await self.chat_service.cancellation.run_with_cancellation(
|
|
561
554
|
custom_agent.ainvoke(initial_state, config=config), # type: ignore[arg-type]
|
|
@@ -566,7 +559,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
566
559
|
# calls happen during ainvoke(); merge it into the outer Deep Research
|
|
567
560
|
# scope even if the graph raises, so tokens already spent before the
|
|
568
561
|
# failure aren't dropped from the failure ToolCallResponse.
|
|
569
|
-
record_invocation_stats(web_search_invocation_stats)
|
|
562
|
+
collector.record_invocation_stats(web_search_invocation_stats)
|
|
570
563
|
|
|
571
564
|
research_result = result.get("final_report", "")
|
|
572
565
|
|
|
@@ -691,7 +684,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
691
684
|
_LOGGER.info(
|
|
692
685
|
f"OpenAI research token usage: {event.response.usage}"
|
|
693
686
|
)
|
|
694
|
-
record_token_usage(
|
|
687
|
+
collector.record_token_usage(
|
|
695
688
|
model_name=self.config.engine.research_model.name,
|
|
696
689
|
usage=event.response.usage,
|
|
697
690
|
source="deep_research.openai_research",
|
|
@@ -872,7 +865,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
872
865
|
temperature=0.1,
|
|
873
866
|
max_tokens=5000,
|
|
874
867
|
)
|
|
875
|
-
record_language_model_response(
|
|
868
|
+
collector.record_language_model_response(
|
|
876
869
|
model_name=self.config.engine.large_model.name,
|
|
877
870
|
response=response,
|
|
878
871
|
source="deep_research.report_cleanup",
|
|
@@ -937,7 +930,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
937
930
|
model_name=self.config.engine.small_model.name,
|
|
938
931
|
content_chunks=None,
|
|
939
932
|
)
|
|
940
|
-
record_language_model_response(
|
|
933
|
+
collector.record_language_model_response(
|
|
941
934
|
model_name=self.config.engine.small_model.name,
|
|
942
935
|
response=response,
|
|
943
936
|
source="deep_research.clarification",
|
|
@@ -969,7 +962,7 @@ class DeepResearchTool(Tool[DeepResearchToolConfig]):
|
|
|
969
962
|
model=self.config.engine.large_model.name,
|
|
970
963
|
messages=chat_messages,
|
|
971
964
|
)
|
|
972
|
-
record_language_model_response(
|
|
965
|
+
collector.record_language_model_response(
|
|
973
966
|
model_name=self.config.engine.large_model.name,
|
|
974
967
|
response=research_response,
|
|
975
968
|
source="deep_research.research_brief",
|
|
@@ -29,7 +29,7 @@ from unique_toolkit.content.service import ContentService
|
|
|
29
29
|
from unique_toolkit.language_model.infos import LanguageModelInfo
|
|
30
30
|
|
|
31
31
|
from ..config import UniqueEngine
|
|
32
|
-
from ..invocation_stats import
|
|
32
|
+
from ..invocation_stats import collector
|
|
33
33
|
from .citation import GlobalCitationManager
|
|
34
34
|
from .state import AgentState, ResearcherState, SupervisorState
|
|
35
35
|
|
|
@@ -586,7 +586,7 @@ async def ainvoke_with_token_handling(
|
|
|
586
586
|
)
|
|
587
587
|
raise e
|
|
588
588
|
else:
|
|
589
|
-
record_language_model_response(
|
|
589
|
+
collector.record_language_model_response(
|
|
590
590
|
model_name=model_info.name,
|
|
591
591
|
response=response,
|
|
592
592
|
source=source,
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
"""Run-scoped collection of Deep Research language-model usage."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from collections.abc import Iterator
|
|
5
|
-
from contextlib import contextmanager
|
|
6
|
-
from contextvars import ContextVar, Token
|
|
7
|
-
from typing import Any
|
|
8
|
-
|
|
9
|
-
from unique_toolkit.language_model.invocation_stats import LanguageModelInvocationStats
|
|
10
|
-
from unique_toolkit.language_model.schemas import LanguageModelTokenUsage
|
|
11
|
-
|
|
12
|
-
_LOGGER = logging.getLogger(__name__)
|
|
13
|
-
|
|
14
|
-
_CURRENT_INVOCATION_STATS: ContextVar[list[LanguageModelInvocationStats] | None] = (
|
|
15
|
-
ContextVar("deep_research_invocation_stats", default=None)
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@contextmanager
|
|
20
|
-
def invocation_stats_scope() -> Iterator[list[LanguageModelInvocationStats]]:
|
|
21
|
-
"""Collect stats for one Deep Research run and isolate concurrent runs."""
|
|
22
|
-
invocation_stats: list[LanguageModelInvocationStats] = []
|
|
23
|
-
token: Token[list[LanguageModelInvocationStats] | None] = (
|
|
24
|
-
_CURRENT_INVOCATION_STATS.set(invocation_stats)
|
|
25
|
-
)
|
|
26
|
-
try:
|
|
27
|
-
yield invocation_stats
|
|
28
|
-
finally:
|
|
29
|
-
_CURRENT_INVOCATION_STATS.reset(token)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def record_token_usage(
|
|
33
|
-
*,
|
|
34
|
-
model_name: str,
|
|
35
|
-
usage: Any,
|
|
36
|
-
source: str,
|
|
37
|
-
) -> None:
|
|
38
|
-
"""Record provider usage when both a run scope and usage are available."""
|
|
39
|
-
invocation_stats = _CURRENT_INVOCATION_STATS.get()
|
|
40
|
-
if invocation_stats is None or usage is None:
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
try:
|
|
44
|
-
token_usage = LanguageModelTokenUsage.model_validate(usage)
|
|
45
|
-
invocation_stats.append(
|
|
46
|
-
LanguageModelInvocationStats.from_usage(
|
|
47
|
-
model_name=model_name,
|
|
48
|
-
token_usage=token_usage,
|
|
49
|
-
source=source,
|
|
50
|
-
)
|
|
51
|
-
)
|
|
52
|
-
except Exception:
|
|
53
|
-
_LOGGER.warning(
|
|
54
|
-
"Unable to parse Deep Research token usage for %s",
|
|
55
|
-
source,
|
|
56
|
-
exc_info=True,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def record_invocation_stats(
|
|
61
|
-
invocations: list[LanguageModelInvocationStats],
|
|
62
|
-
) -> None:
|
|
63
|
-
"""Add invocation stats collected by a nested Deep Research dependency."""
|
|
64
|
-
invocation_stats = _CURRENT_INVOCATION_STATS.get()
|
|
65
|
-
if invocation_stats is not None:
|
|
66
|
-
invocation_stats.extend(invocations)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def record_language_model_response(
|
|
70
|
-
*,
|
|
71
|
-
model_name: str,
|
|
72
|
-
response: Any,
|
|
73
|
-
source: str,
|
|
74
|
-
) -> None:
|
|
75
|
-
"""Record usage from OpenAI SDK, toolkit, or LangChain responses."""
|
|
76
|
-
usage = getattr(response, "usage", None)
|
|
77
|
-
if usage is None:
|
|
78
|
-
usage = getattr(response, "usage_metadata", None)
|
|
79
|
-
if usage is None:
|
|
80
|
-
response_metadata = getattr(response, "response_metadata", None)
|
|
81
|
-
if isinstance(response_metadata, dict):
|
|
82
|
-
usage = response_metadata.get("token_usage")
|
|
83
|
-
|
|
84
|
-
record_token_usage(model_name=model_name, usage=usage, source=source)
|
|
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
|
|
File without changes
|