deepanalysts 0.7.2__tar.gz → 0.7.4__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.
Files changed (65) hide show
  1. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/PKG-INFO +5 -5
  2. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/__init__.py +13 -0
  3. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/composite.py +39 -9
  4. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/supabase_storage.py +8 -2
  5. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/__init__.py +16 -1
  6. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/filesystem.py +10 -4
  7. deepanalysts-0.7.4/deepanalysts/middleware/summarization.py +681 -0
  8. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts.egg-info/PKG-INFO +5 -5
  9. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts.egg-info/requires.txt +4 -4
  10. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/pyproject.toml +11 -12
  11. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_composite_backend.py +89 -4
  12. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_filesystem_middleware.py +35 -0
  13. deepanalysts-0.7.4/tests/test_summarization_middleware.py +581 -0
  14. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_supabase_storage_backend.py +35 -0
  15. deepanalysts-0.7.2/deepanalysts/middleware/summarization.py +0 -752
  16. deepanalysts-0.7.2/tests/test_summarization_middleware.py +0 -337
  17. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/README.md +0 -0
  18. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/_messages_reducer.py +0 -0
  19. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/__init__.py +0 -0
  20. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/basement.py +0 -0
  21. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/e2b.py +0 -0
  22. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/filesystem.py +0 -0
  23. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/protocol.py +0 -0
  24. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/sandbox.py +0 -0
  25. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/state.py +0 -0
  26. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/store.py +0 -0
  27. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/backends/utils.py +0 -0
  28. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/clients/__init__.py +0 -0
  29. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/clients/basement.py +0 -0
  30. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/_state.py +0 -0
  31. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/_utils.py +0 -0
  32. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/memory.py +0 -0
  33. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/patch_tool_calls.py +0 -0
  34. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/skills.py +0 -0
  35. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/subagents.py +0 -0
  36. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/middleware/tool_errors.py +0 -0
  37. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/state.py +0 -0
  38. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/streaming.py +0 -0
  39. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/utils/__init__.py +0 -0
  40. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts/utils/retry.py +0 -0
  41. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts.egg-info/SOURCES.txt +0 -0
  42. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts.egg-info/dependency_links.txt +0 -0
  43. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/deepanalysts.egg-info/top_level.txt +0 -0
  44. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/setup.cfg +0 -0
  45. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_basement.py +0 -0
  46. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_e2b_backend.py +0 -0
  47. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_e2b_integration.py +0 -0
  48. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_messages_reducer.py +0 -0
  49. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_prompt_sections.py +0 -0
  50. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_protocol_bridge.py +0 -0
  51. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_regression_files_delta.py +0 -0
  52. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_regression_fs_backport.py +0 -0
  53. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_regression_middleware_tools.py +0 -0
  54. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_regression_new_api.py +0 -0
  55. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_regression_subagents.py +0 -0
  56. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_regression_tier1_backports.py +0 -0
  57. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_sandbox_backend.py +0 -0
  58. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_sandbox_hardening.py +0 -0
  59. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_sandbox_hardening_integration.py +0 -0
  60. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_skills_middleware.py +0 -0
  61. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_store_backend.py +0 -0
  62. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_streaming_transformer.py +0 -0
  63. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_supabase_storage_integration.py +0 -0
  64. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_tool_errors.py +0 -0
  65. {deepanalysts-0.7.2 → deepanalysts-0.7.4}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepanalysts
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: LangChain/LangGraph middleware for building AI agents with memory, skills, and filesystem support
5
5
  Author-email: Ganchuluun Narantsatsralt <tsatsralt@swifttech.cloud>
6
6
  License: MIT
@@ -18,15 +18,15 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
19
  Requires-Python: <4.0,>=3.11
20
20
  Description-Content-Type: text/markdown
21
- Requires-Dist: langchain<2.0.0,>=1.3.10
22
- Requires-Dist: langchain-core<2.0.0,>=1.4.0
23
- Requires-Dist: langgraph>=1.2.6
21
+ Requires-Dist: langchain<2.0.0,>=1.3.13
22
+ Requires-Dist: langchain-core<2.0.0,>=1.4.9
23
+ Requires-Dist: langgraph>=1.2.9
24
24
  Requires-Dist: httpx>=0.28.0
25
25
  Requires-Dist: pyyaml>=6.0
26
26
  Requires-Dist: tenacity>=8.2.0
27
27
  Requires-Dist: wcmatch>=8.5.0
28
28
  Provides-Extra: postgres
29
- Requires-Dist: langgraph-checkpoint-postgres>=2.1.0; extra == "postgres"
29
+ Requires-Dist: langgraph-checkpoint-postgres>=3.1.0; extra == "postgres"
30
30
  Requires-Dist: psycopg[binary,pool]>=3.2.0; extra == "postgres"
31
31
  Provides-Extra: e2b
32
32
  Requires-Dist: e2b>=1.0.0; extra == "e2b"
@@ -35,9 +35,15 @@ from deepanalysts.middleware import (
35
35
  SkillsMiddleware,
36
36
  SubAgent,
37
37
  SubAgentMiddleware,
38
+ SummarizationDefaults,
39
+ SummarizationEvent,
38
40
  SummarizationMiddleware,
41
+ SummarizationState,
39
42
  ToolErrorHandlingMiddleware,
43
+ TriggerClause,
40
44
  TruncateArgsSettings,
45
+ compute_summarization_defaults,
46
+ create_summarization_middleware,
41
47
  )
42
48
  from deepanalysts.state import DEFAULT_SNAPSHOT_FREQUENCY, DeepAnalystsState
43
49
  from deepanalysts.streaming import (
@@ -66,8 +72,15 @@ __all__ = [
66
72
  "CompiledSubAgent",
67
73
  "SkillMetadata",
68
74
  "SubAgent",
75
+ "SummarizationDefaults",
76
+ "SummarizationEvent",
77
+ "SummarizationState",
78
+ "TriggerClause",
69
79
  "TruncateArgsSettings",
70
80
  # Constants
71
81
  "TASK_SYSTEM_PROMPT",
72
82
  "TASK_TOOL_DESCRIPTION",
83
+ # Helpers
84
+ "compute_summarization_defaults",
85
+ "create_summarization_middleware",
73
86
  ]
@@ -9,7 +9,8 @@ from __future__ import annotations
9
9
 
10
10
  import asyncio
11
11
  from collections import defaultdict
12
- from typing import cast
12
+ from dataclasses import replace
13
+ from typing import TypeVar, cast
13
14
 
14
15
  from deepanalysts.backends.protocol import (
15
16
  BackendProtocol,
@@ -49,6 +50,29 @@ def _remap_file_info_path(fi: FileInfo, route_prefix: str) -> FileInfo:
49
50
  )
50
51
 
51
52
 
53
+ _ResultT = TypeVar("_ResultT", WriteResult, EditResult)
54
+
55
+
56
+ def _remap_result_paths(res: _ResultT, route_prefix: str | None) -> _ResultT:
57
+ """Re-prepend a matched route prefix to a write/edit result's paths.
58
+
59
+ Child backends receive route-stripped paths, so the ``path`` (and
60
+ ``files_update`` keys) they return are relative to the route root. Tool
61
+ confirmations echo ``res.path`` back to the model — leaving it stripped
62
+ hands the model a path that routes to a *different* backend on the next
63
+ call (e.g. ``/shared/x.md`` written, ``/x.md`` echoed, follow-up read of
64
+ ``/x.md`` hits the default sandbox and fails).
65
+ """
66
+ if route_prefix is None:
67
+ return res
68
+ prefix = route_prefix.rstrip("/")
69
+ path = f"{prefix}{res.path}" if res.path else res.path
70
+ files_update = res.files_update
71
+ if files_update is not None:
72
+ files_update = {f"{prefix}{k}": v for k, v in files_update.items()}
73
+ return replace(res, path=path, files_update=files_update)
74
+
75
+
52
76
  def _strip_route_from_pattern(pattern: str, route_prefix: str) -> str:
53
77
  """Strip a route prefix from a glob pattern when the pattern targets that route.
54
78
 
@@ -163,8 +187,8 @@ class CompositeBackend(SandboxBackendProtocol):
163
187
  return backend.read(backend_path, offset=offset, limit=limit)
164
188
 
165
189
  def write(self, file_path: str, content: str) -> WriteResult:
166
- backend, backend_path, _rp = self._route(file_path)
167
- return backend.write(backend_path, content)
190
+ backend, backend_path, route_prefix = self._route(file_path)
191
+ return _remap_result_paths(backend.write(backend_path, content), route_prefix)
168
192
 
169
193
  def edit(
170
194
  self,
@@ -173,8 +197,11 @@ class CompositeBackend(SandboxBackendProtocol):
173
197
  new_string: str,
174
198
  replace_all: bool = False,
175
199
  ) -> EditResult:
176
- backend, backend_path, _rp = self._route(file_path)
177
- return backend.edit(backend_path, old_string, new_string, replace_all=replace_all)
200
+ backend, backend_path, route_prefix = self._route(file_path)
201
+ return _remap_result_paths(
202
+ backend.edit(backend_path, old_string, new_string, replace_all=replace_all),
203
+ route_prefix,
204
+ )
178
205
 
179
206
  def grep(
180
207
  self,
@@ -309,8 +336,8 @@ class CompositeBackend(SandboxBackendProtocol):
309
336
  return await backend.aread_result(backend_path, offset=offset, limit=limit)
310
337
 
311
338
  async def awrite(self, file_path: str, content: str) -> WriteResult:
312
- backend, backend_path, _rp = self._route(file_path)
313
- return await backend.awrite(backend_path, content)
339
+ backend, backend_path, route_prefix = self._route(file_path)
340
+ return _remap_result_paths(await backend.awrite(backend_path, content), route_prefix)
314
341
 
315
342
  async def aedit(
316
343
  self,
@@ -319,8 +346,11 @@ class CompositeBackend(SandboxBackendProtocol):
319
346
  new_string: str,
320
347
  replace_all: bool = False,
321
348
  ) -> EditResult:
322
- backend, backend_path, _rp = self._route(file_path)
323
- return await backend.aedit(backend_path, old_string, new_string, replace_all=replace_all)
349
+ backend, backend_path, route_prefix = self._route(file_path)
350
+ return _remap_result_paths(
351
+ await backend.aedit(backend_path, old_string, new_string, replace_all=replace_all),
352
+ route_prefix,
353
+ )
324
354
 
325
355
  async def agrep(
326
356
  self,
@@ -337,6 +337,12 @@ class SupabaseStorageBackend(BackendProtocol):
337
337
  except StorageListError as e:
338
338
  return LsResult(error=f"Error: {e}")
339
339
 
340
+ # Entries must carry the full virtual path, not the bare object name —
341
+ # listing "/research/x/" with entries rendered as "/README.md" reads as
342
+ # a root-level file and the model then read_files the wrong path.
343
+ base = "/" + path.strip("/")
344
+ base = base if base == "/" else f"{base}/"
345
+
340
346
  entries: list[FileInfo] = []
341
347
  for item in items:
342
348
  name = item.get("name", "")
@@ -344,12 +350,12 @@ class SupabaseStorageBackend(BackendProtocol):
344
350
  continue
345
351
 
346
352
  if item.get("id") is None:
347
- entries.append(FileInfo(path=f"/{name}/", is_dir=True, size=0, modified_at=""))
353
+ entries.append(FileInfo(path=f"{base}{name}/", is_dir=True, size=0, modified_at=""))
348
354
  else:
349
355
  metadata = item.get("metadata") or {}
350
356
  entries.append(
351
357
  FileInfo(
352
- path=f"/{name}",
358
+ path=f"{base}{name}",
353
359
  is_dir=False,
354
360
  size=metadata.get("size", 0),
355
361
  modified_at=item.get("updated_at", ""),
@@ -12,7 +12,16 @@ from deepanalysts.middleware.subagents import (
12
12
  SubAgent,
13
13
  SubAgentMiddleware,
14
14
  )
15
- from deepanalysts.middleware.summarization import SummarizationMiddleware, TruncateArgsSettings
15
+ from deepanalysts.middleware.summarization import (
16
+ SummarizationDefaults,
17
+ SummarizationEvent,
18
+ SummarizationMiddleware,
19
+ SummarizationState,
20
+ TriggerClause,
21
+ TruncateArgsSettings,
22
+ compute_summarization_defaults,
23
+ create_summarization_middleware,
24
+ )
16
25
  from deepanalysts.middleware.tool_errors import ToolErrorHandlingMiddleware
17
26
 
18
27
  __all__ = [
@@ -28,10 +37,16 @@ __all__ = [
28
37
  "CompiledSubAgent",
29
38
  "SkillMetadata",
30
39
  "SubAgent",
40
+ "SummarizationDefaults",
41
+ "SummarizationEvent",
42
+ "SummarizationState",
43
+ "TriggerClause",
31
44
  "TruncateArgsSettings",
32
45
  # Constants
33
46
  "TASK_SYSTEM_PROMPT",
34
47
  "TASK_TOOL_DESCRIPTION",
35
48
  # Helpers
49
+ "compute_summarization_defaults",
50
+ "create_summarization_middleware",
36
51
  "private_state_field_names",
37
52
  ]
@@ -736,19 +736,22 @@ class FilesystemMiddleware(AgentMiddleware):
736
736
  res: WriteResult = resolved_backend.write(file_path, content)
737
737
  if res.error:
738
738
  return res.error
739
+ # Byte count lets the model verify a large write completed even
740
+ # after history compaction truncates the content argument.
741
+ confirmation = f"Updated file {res.path} ({len(content.encode('utf-8'))} bytes written)"
739
742
  if res.files_update is not None:
740
743
  return Command(
741
744
  update={
742
745
  "files": res.files_update,
743
746
  "messages": [
744
747
  ToolMessage(
745
- content=f"Updated file {res.path}",
748
+ content=confirmation,
746
749
  tool_call_id=runtime.tool_call_id,
747
750
  )
748
751
  ],
749
752
  }
750
753
  )
751
- return f"Updated file {res.path}"
754
+ return confirmation
752
755
 
753
756
  async def async_write_file(
754
757
  file_path: Annotated[str, "Absolute path to the file to write."],
@@ -763,19 +766,22 @@ class FilesystemMiddleware(AgentMiddleware):
763
766
  res: WriteResult = await resolved_backend.awrite(file_path, content)
764
767
  if res.error:
765
768
  return res.error
769
+ # Byte count lets the model verify a large write completed even
770
+ # after history compaction truncates the content argument.
771
+ confirmation = f"Updated file {res.path} ({len(content.encode('utf-8'))} bytes written)"
766
772
  if res.files_update is not None:
767
773
  return Command(
768
774
  update={
769
775
  "files": res.files_update,
770
776
  "messages": [
771
777
  ToolMessage(
772
- content=f"Updated file {res.path}",
778
+ content=confirmation,
773
779
  tool_call_id=runtime.tool_call_id,
774
780
  )
775
781
  ],
776
782
  }
777
783
  )
778
- return f"Updated file {res.path}"
784
+ return confirmation
779
785
 
780
786
  return StructuredTool.from_function(
781
787
  name="write_file",