deepagents 0.2.7__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
@@ -2,6 +2,7 @@
2
2
  # ruff: noqa: E501
3
3
 
4
4
  import os
5
+ import re
5
6
  from collections.abc import Awaitable, Callable, Sequence
6
7
  from typing import Annotated, Literal, NotRequired
7
8
 
@@ -14,7 +15,7 @@ from langchain.agents.middleware.types import (
14
15
  from langchain.tools import ToolRuntime
15
16
  from langchain.tools.tool_node import ToolCallRequest
16
17
  from langchain_core.messages import ToolMessage
17
- from langchain_core.tools import BaseTool, tool
18
+ from langchain_core.tools import BaseTool, StructuredTool
18
19
  from langgraph.types import Command
19
20
  from typing_extensions import TypedDict
20
21
 
@@ -92,12 +93,16 @@ def _file_data_reducer(left: dict[str, FileData] | None, right: dict[str, FileDa
92
93
 
93
94
 
94
95
  def _validate_path(path: str, *, allowed_prefixes: Sequence[str] | None = None) -> str:
95
- """Validate and normalize file path for security.
96
+ r"""Validate and normalize file path for security.
96
97
 
97
98
  Ensures paths are safe to use by preventing directory traversal attacks
98
99
  and enforcing consistent formatting. All paths are normalized to use
99
100
  forward slashes and start with a leading slash.
100
101
 
102
+ This function is designed for virtual filesystem paths and rejects
103
+ Windows absolute paths (e.g., C:/..., F:/...) to maintain consistency
104
+ and prevent path format ambiguity.
105
+
101
106
  Args:
102
107
  path: The path to validate and normalize.
103
108
  allowed_prefixes: Optional list of allowed path prefixes. If provided,
@@ -107,14 +112,16 @@ def _validate_path(path: str, *, allowed_prefixes: Sequence[str] | None = None)
107
112
  Normalized canonical path starting with `/` and using forward slashes.
108
113
 
109
114
  Raises:
110
- ValueError: If path contains traversal sequences (`..` or `~`) or does
111
- not start with an allowed prefix when `allowed_prefixes` is specified.
115
+ ValueError: If path contains traversal sequences (`..` or `~`), is a
116
+ Windows absolute path (e.g., C:/...), or does not start with an
117
+ allowed prefix when `allowed_prefixes` is specified.
112
118
 
113
119
  Example:
114
120
  ```python
115
121
  validate_path("foo/bar") # Returns: "/foo/bar"
116
122
  validate_path("/./foo//bar") # Returns: "/foo/bar"
117
123
  validate_path("../etc/passwd") # Raises ValueError
124
+ validate_path(r"C:\\Users\\file.txt") # Raises ValueError
118
125
  validate_path("/data/file.txt", allowed_prefixes=["/data/"]) # OK
119
126
  validate_path("/etc/file.txt", allowed_prefixes=["/data/"]) # Raises ValueError
120
127
  ```
@@ -123,6 +130,12 @@ def _validate_path(path: str, *, allowed_prefixes: Sequence[str] | None = None)
123
130
  msg = f"Path traversal not allowed: {path}"
124
131
  raise ValueError(msg)
125
132
 
133
+ # Reject Windows absolute paths (e.g., C:\..., D:/...)
134
+ # This maintains consistency in virtual filesystem paths
135
+ if re.match(r"^[a-zA-Z]:", path):
136
+ msg = f"Windows absolute paths are not supported: {path}. Please use virtual paths starting with / (e.g., /workspace/file.txt)"
137
+ raise ValueError(msg)
138
+
126
139
  normalized = os.path.normpath(path)
127
140
  normalized = normalized.replace("\\", "/")
128
141
 
@@ -312,14 +325,30 @@ def _ls_tool_generator(
312
325
  """
313
326
  tool_description = custom_description or LIST_FILES_TOOL_DESCRIPTION
314
327
 
315
- @tool(description=tool_description)
316
- def ls(runtime: ToolRuntime[None, FilesystemState], path: str) -> list[str]:
328
+ def sync_ls(runtime: ToolRuntime[None, FilesystemState], path: str) -> str:
329
+ """Synchronous wrapper for ls tool."""
317
330
  resolved_backend = _get_backend(backend, runtime)
318
331
  validated_path = _validate_path(path)
319
332
  infos = resolved_backend.ls_info(validated_path)
320
- return [fi.get("path", "") for fi in infos]
333
+ paths = [fi.get("path", "") for fi in infos]
334
+ result = truncate_if_too_long(paths)
335
+ return str(result)
321
336
 
322
- return ls
337
+ async def async_ls(runtime: ToolRuntime[None, FilesystemState], path: str) -> str:
338
+ """Asynchronous wrapper for ls tool."""
339
+ resolved_backend = _get_backend(backend, runtime)
340
+ validated_path = _validate_path(path)
341
+ infos = await resolved_backend.als_info(validated_path)
342
+ paths = [fi.get("path", "") for fi in infos]
343
+ result = truncate_if_too_long(paths)
344
+ return str(result)
345
+
346
+ return StructuredTool.from_function(
347
+ name="ls",
348
+ description=tool_description,
349
+ func=sync_ls,
350
+ coroutine=async_ls,
351
+ )
323
352
 
324
353
 
325
354
  def _read_file_tool_generator(
@@ -337,18 +366,34 @@ def _read_file_tool_generator(
337
366
  """
338
367
  tool_description = custom_description or READ_FILE_TOOL_DESCRIPTION
339
368
 
340
- @tool(description=tool_description)
341
- def read_file(
369
+ def sync_read_file(
342
370
  file_path: str,
343
371
  runtime: ToolRuntime[None, FilesystemState],
344
372
  offset: int = DEFAULT_READ_OFFSET,
345
373
  limit: int = DEFAULT_READ_LIMIT,
346
374
  ) -> str:
375
+ """Synchronous wrapper for read_file tool."""
347
376
  resolved_backend = _get_backend(backend, runtime)
348
377
  file_path = _validate_path(file_path)
349
378
  return resolved_backend.read(file_path, offset=offset, limit=limit)
350
379
 
351
- return read_file
380
+ async def async_read_file(
381
+ file_path: str,
382
+ runtime: ToolRuntime[None, FilesystemState],
383
+ offset: int = DEFAULT_READ_OFFSET,
384
+ limit: int = DEFAULT_READ_LIMIT,
385
+ ) -> str:
386
+ """Asynchronous wrapper for read_file tool."""
387
+ resolved_backend = _get_backend(backend, runtime)
388
+ file_path = _validate_path(file_path)
389
+ return await resolved_backend.aread(file_path, offset=offset, limit=limit)
390
+
391
+ return StructuredTool.from_function(
392
+ name="read_file",
393
+ description=tool_description,
394
+ func=sync_read_file,
395
+ coroutine=async_read_file,
396
+ )
352
397
 
353
398
 
354
399
  def _write_file_tool_generator(
@@ -366,12 +411,12 @@ def _write_file_tool_generator(
366
411
  """
367
412
  tool_description = custom_description or WRITE_FILE_TOOL_DESCRIPTION
368
413
 
369
- @tool(description=tool_description)
370
- def write_file(
414
+ def sync_write_file(
371
415
  file_path: str,
372
416
  content: str,
373
417
  runtime: ToolRuntime[None, FilesystemState],
374
418
  ) -> Command | str:
419
+ """Synchronous wrapper for write_file tool."""
375
420
  resolved_backend = _get_backend(backend, runtime)
376
421
  file_path = _validate_path(file_path)
377
422
  res: WriteResult = resolved_backend.write(file_path, content)
@@ -392,7 +437,38 @@ def _write_file_tool_generator(
392
437
  )
393
438
  return f"Updated file {res.path}"
394
439
 
395
- return write_file
440
+ async def async_write_file(
441
+ file_path: str,
442
+ content: str,
443
+ runtime: ToolRuntime[None, FilesystemState],
444
+ ) -> Command | str:
445
+ """Asynchronous wrapper for write_file tool."""
446
+ resolved_backend = _get_backend(backend, runtime)
447
+ file_path = _validate_path(file_path)
448
+ res: WriteResult = await resolved_backend.awrite(file_path, content)
449
+ if res.error:
450
+ return res.error
451
+ # If backend returns state update, wrap into Command with ToolMessage
452
+ if res.files_update is not None:
453
+ return Command(
454
+ update={
455
+ "files": res.files_update,
456
+ "messages": [
457
+ ToolMessage(
458
+ content=f"Updated file {res.path}",
459
+ tool_call_id=runtime.tool_call_id,
460
+ )
461
+ ],
462
+ }
463
+ )
464
+ return f"Updated file {res.path}"
465
+
466
+ return StructuredTool.from_function(
467
+ name="write_file",
468
+ description=tool_description,
469
+ func=sync_write_file,
470
+ coroutine=async_write_file,
471
+ )
396
472
 
397
473
 
398
474
  def _edit_file_tool_generator(
@@ -410,8 +486,7 @@ def _edit_file_tool_generator(
410
486
  """
411
487
  tool_description = custom_description or EDIT_FILE_TOOL_DESCRIPTION
412
488
 
413
- @tool(description=tool_description)
414
- def edit_file(
489
+ def sync_edit_file(
415
490
  file_path: str,
416
491
  old_string: str,
417
492
  new_string: str,
@@ -419,6 +494,7 @@ def _edit_file_tool_generator(
419
494
  *,
420
495
  replace_all: bool = False,
421
496
  ) -> Command | str:
497
+ """Synchronous wrapper for edit_file tool."""
422
498
  resolved_backend = _get_backend(backend, runtime)
423
499
  file_path = _validate_path(file_path)
424
500
  res: EditResult = resolved_backend.edit(file_path, old_string, new_string, replace_all=replace_all)
@@ -438,7 +514,40 @@ def _edit_file_tool_generator(
438
514
  )
439
515
  return f"Successfully replaced {res.occurrences} instance(s) of the string in '{res.path}'"
440
516
 
441
- return edit_file
517
+ async def async_edit_file(
518
+ file_path: str,
519
+ old_string: str,
520
+ new_string: str,
521
+ runtime: ToolRuntime[None, FilesystemState],
522
+ *,
523
+ replace_all: bool = False,
524
+ ) -> Command | str:
525
+ """Asynchronous wrapper for edit_file tool."""
526
+ resolved_backend = _get_backend(backend, runtime)
527
+ file_path = _validate_path(file_path)
528
+ res: EditResult = await resolved_backend.aedit(file_path, old_string, new_string, replace_all=replace_all)
529
+ if res.error:
530
+ return res.error
531
+ if res.files_update is not None:
532
+ return Command(
533
+ update={
534
+ "files": res.files_update,
535
+ "messages": [
536
+ ToolMessage(
537
+ content=f"Successfully replaced {res.occurrences} instance(s) of the string in '{res.path}'",
538
+ tool_call_id=runtime.tool_call_id,
539
+ )
540
+ ],
541
+ }
542
+ )
543
+ return f"Successfully replaced {res.occurrences} instance(s) of the string in '{res.path}'"
544
+
545
+ return StructuredTool.from_function(
546
+ name="edit_file",
547
+ description=tool_description,
548
+ func=sync_edit_file,
549
+ coroutine=async_edit_file,
550
+ )
442
551
 
443
552
 
444
553
  def _glob_tool_generator(
@@ -456,13 +565,28 @@ def _glob_tool_generator(
456
565
  """
457
566
  tool_description = custom_description or GLOB_TOOL_DESCRIPTION
458
567
 
459
- @tool(description=tool_description)
460
- def glob(pattern: str, runtime: ToolRuntime[None, FilesystemState], path: str = "/") -> list[str]:
568
+ def sync_glob(pattern: str, runtime: ToolRuntime[None, FilesystemState], path: str = "/") -> str:
569
+ """Synchronous wrapper for glob tool."""
461
570
  resolved_backend = _get_backend(backend, runtime)
462
571
  infos = resolved_backend.glob_info(pattern, path=path)
463
- return [fi.get("path", "") for fi in infos]
572
+ paths = [fi.get("path", "") for fi in infos]
573
+ result = truncate_if_too_long(paths)
574
+ return str(result)
575
+
576
+ async def async_glob(pattern: str, runtime: ToolRuntime[None, FilesystemState], path: str = "/") -> str:
577
+ """Asynchronous wrapper for glob tool."""
578
+ resolved_backend = _get_backend(backend, runtime)
579
+ infos = await resolved_backend.aglob_info(pattern, path=path)
580
+ paths = [fi.get("path", "") for fi in infos]
581
+ result = truncate_if_too_long(paths)
582
+ return str(result)
464
583
 
465
- return glob
584
+ return StructuredTool.from_function(
585
+ name="glob",
586
+ description=tool_description,
587
+ func=sync_glob,
588
+ coroutine=async_glob,
589
+ )
466
590
 
467
591
 
468
592
  def _grep_tool_generator(
@@ -480,14 +604,14 @@ def _grep_tool_generator(
480
604
  """
481
605
  tool_description = custom_description or GREP_TOOL_DESCRIPTION
482
606
 
483
- @tool(description=tool_description)
484
- def grep(
607
+ def sync_grep(
485
608
  pattern: str,
486
609
  runtime: ToolRuntime[None, FilesystemState],
487
610
  path: str | None = None,
488
611
  glob: str | None = None,
489
612
  output_mode: Literal["files_with_matches", "content", "count"] = "files_with_matches",
490
613
  ) -> str:
614
+ """Synchronous wrapper for grep tool."""
491
615
  resolved_backend = _get_backend(backend, runtime)
492
616
  raw = resolved_backend.grep_raw(pattern, path=path, glob=glob)
493
617
  if isinstance(raw, str):
@@ -495,7 +619,27 @@ def _grep_tool_generator(
495
619
  formatted = format_grep_matches(raw, output_mode)
496
620
  return truncate_if_too_long(formatted) # type: ignore[arg-type]
497
621
 
498
- return grep
622
+ async def async_grep(
623
+ pattern: str,
624
+ runtime: ToolRuntime[None, FilesystemState],
625
+ path: str | None = None,
626
+ glob: str | None = None,
627
+ output_mode: Literal["files_with_matches", "content", "count"] = "files_with_matches",
628
+ ) -> str:
629
+ """Asynchronous wrapper for grep tool."""
630
+ resolved_backend = _get_backend(backend, runtime)
631
+ raw = await resolved_backend.agrep_raw(pattern, path=path, glob=glob)
632
+ if isinstance(raw, str):
633
+ return raw
634
+ formatted = format_grep_matches(raw, output_mode)
635
+ return truncate_if_too_long(formatted) # type: ignore[arg-type]
636
+
637
+ return StructuredTool.from_function(
638
+ name="grep",
639
+ description=tool_description,
640
+ func=sync_grep,
641
+ coroutine=async_grep,
642
+ )
499
643
 
500
644
 
501
645
  def _supports_execution(backend: BackendProtocol) -> bool:
@@ -536,11 +680,11 @@ def _execute_tool_generator(
536
680
  """
537
681
  tool_description = custom_description or EXECUTE_TOOL_DESCRIPTION
538
682
 
539
- @tool(description=tool_description)
540
- def execute(
683
+ def sync_execute(
541
684
  command: str,
542
685
  runtime: ToolRuntime[None, FilesystemState],
543
686
  ) -> str:
687
+ """Synchronous wrapper for execute tool."""
544
688
  resolved_backend = _get_backend(backend, runtime)
545
689
 
546
690
  # Runtime check - fail gracefully if not supported
@@ -569,7 +713,45 @@ def _execute_tool_generator(
569
713
 
570
714
  return "".join(parts)
571
715
 
572
- return execute
716
+ async def async_execute(
717
+ command: str,
718
+ runtime: ToolRuntime[None, FilesystemState],
719
+ ) -> str:
720
+ """Asynchronous wrapper for execute tool."""
721
+ resolved_backend = _get_backend(backend, runtime)
722
+
723
+ # Runtime check - fail gracefully if not supported
724
+ if not _supports_execution(resolved_backend):
725
+ return (
726
+ "Error: Execution not available. This agent's backend "
727
+ "does not support command execution (SandboxBackendProtocol). "
728
+ "To use the execute tool, provide a backend that implements SandboxBackendProtocol."
729
+ )
730
+
731
+ try:
732
+ result = await resolved_backend.aexecute(command)
733
+ except NotImplementedError as e:
734
+ # Handle case where execute() exists but raises NotImplementedError
735
+ return f"Error: Execution not available. {e}"
736
+
737
+ # Format output for LLM consumption
738
+ parts = [result.output]
739
+
740
+ if result.exit_code is not None:
741
+ status = "succeeded" if result.exit_code == 0 else "failed"
742
+ parts.append(f"\n[Command {status} with exit code {result.exit_code}]")
743
+
744
+ if result.truncated:
745
+ parts.append("\n[Output was truncated due to size limits]")
746
+
747
+ return "".join(parts)
748
+
749
+ return StructuredTool.from_function(
750
+ name="execute",
751
+ description=tool_description,
752
+ func=sync_execute,
753
+ coroutine=async_execute,
754
+ )
573
755
 
574
756
 
575
757
  TOOL_GENERATORS = {
@@ -468,7 +468,8 @@ class SubAgentMiddleware(AgentMiddleware):
468
468
  ) -> ModelResponse:
469
469
  """Update the system prompt to include instructions on using subagents."""
470
470
  if self.system_prompt is not None:
471
- request.system_prompt = request.system_prompt + "\n\n" + self.system_prompt if request.system_prompt else self.system_prompt
471
+ system_prompt = request.system_prompt + "\n\n" + self.system_prompt if request.system_prompt else self.system_prompt
472
+ return handler(request.override(system_prompt=system_prompt))
472
473
  return handler(request)
473
474
 
474
475
  async def awrap_model_call(
@@ -478,5 +479,6 @@ class SubAgentMiddleware(AgentMiddleware):
478
479
  ) -> ModelResponse:
479
480
  """(async) Update the system prompt to include instructions on using subagents."""
480
481
  if self.system_prompt is not None:
481
- request.system_prompt = request.system_prompt + "\n\n" + self.system_prompt if request.system_prompt else self.system_prompt
482
+ system_prompt = request.system_prompt + "\n\n" + self.system_prompt if request.system_prompt else self.system_prompt
483
+ return await handler(request.override(system_prompt=system_prompt))
482
484
  return await handler(request)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagents
3
- Version: 0.2.7
3
+ Version: 0.3.0
4
4
  Summary: General purpose 'deep agent' with sub-agent spawning, todo list capabilities, and mock file system. Built on LangGraph.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
@@ -11,13 +11,10 @@ Project-URL: Slack, https://www.langchain.com/join-community
11
11
  Project-URL: Reddit, https://www.reddit.com/r/LangChain/
12
12
  Requires-Python: <4.0,>=3.11
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: langchain-anthropic<2.0.0,>=1.0.0
15
- Requires-Dist: langchain<2.0.0,>=1.0.2
16
- Requires-Dist: langchain-core<2.0.0,>=1.0.0
14
+ Requires-Dist: langchain-anthropic<2.0.0,>=1.2.0
15
+ Requires-Dist: langchain<2.0.0,>=1.1.0
16
+ Requires-Dist: langchain-core<2.0.0,>=1.1.0
17
17
  Requires-Dist: wcmatch
18
- Requires-Dist: daytona>=0.113.0
19
- Requires-Dist: runloop-api-client>=0.66.1
20
- Requires-Dist: tavily>=1.1.0
21
18
 
22
19
  # 🧠🤖Deep Agents
23
20
 
@@ -27,7 +24,7 @@ This architecture, however, can yield agents that are “shallow” and fail to
27
24
  Applications like “Deep Research”, "Manus", and “Claude Code” have gotten around this limitation by implementing a combination of four things:
28
25
  a **planning tool**, **sub agents**, access to a **file system**, and a **detailed prompt**.
29
26
 
30
- <img src="deep_agents.png" alt="deep agent" width="600"/>
27
+ <img src="../../deep_agents.png" alt="deep agent" width="600"/>
31
28
 
32
29
  `deepagents` is a Python package that implements these in a general purpose way so that you can easily create a Deep Agent for your application. For a full overview and quickstart of `deepagents`, the best resource is our [docs](https://docs.langchain.com/oss/python/deepagents/overview).
33
30
 
@@ -0,0 +1,18 @@
1
+ deepagents/__init__.py,sha256=9BVNn4lfF5N8l2KY8Ttxi82zO609I-fGqoSIF7DAxiU,342
2
+ deepagents/graph.py,sha256=u3gLVZMLA1xdZV_Mo0RPyQGOqO5VZkckoz1xPRWuZxw,6776
3
+ deepagents/backends/__init__.py,sha256=BOKu2cQ1OdMyO_l2rLqZQiXppYFmQbx7OIQb7WYwvZc,457
4
+ deepagents/backends/composite.py,sha256=A7J301EPlKJtTM1q1dL3hX-rDns-wallUsT66R_TaVA,22557
5
+ deepagents/backends/filesystem.py,sha256=kGBFuW3ie0LLz4wXCPGJm3WAiYpimJTgEwodJSnXWCs,21477
6
+ deepagents/backends/protocol.py,sha256=HUmIrwYGduPfDcs_wtOzVU2QPA9kICZuGO-sUwxzz5I,15997
7
+ deepagents/backends/sandbox.py,sha256=8Bi8itqjW2PpXORlIfT8thMN1aBXExgHz8cm8xwVaxI,10864
8
+ deepagents/backends/state.py,sha256=yRfrEyHAl5NemkpMhBTU0TLAfgxF5t-TZpE3Pd3_PJg,6387
9
+ deepagents/backends/store.py,sha256=0mmeTsim4J8bjcf62dljwNrDv4PavT2KHdGbaBzVzRE,15197
10
+ deepagents/backends/utils.py,sha256=Iyk2jW-gfoLvMnz-W_2FRCoJW_j3r1zoumU9iww-jd0,13973
11
+ deepagents/middleware/__init__.py,sha256=_OGIHcHZ2pRD0gzUBS7R48agwI6P7-FCBKBgjyaWlsg,303
12
+ deepagents/middleware/filesystem.py,sha256=8_W5XNDYMN37BQjbqMyUAVWYv2KmRP87xwwomQ37K1w,44568
13
+ deepagents/middleware/patch_tool_calls.py,sha256=PdNhxPaQqwnFkhEAZEE2kEzadTNAOO3_iJRA30WqpGE,1981
14
+ deepagents/middleware/subagents.py,sha256=JOvFBXT-wqy-7zWKFL4-76zI0cfD-2f1ALDUTJDZVuE,23886
15
+ deepagents-0.3.0.dist-info/METADATA,sha256=g2Xwexi4cMWi6GcCt-_sJGJCieGnOQWMNyMP_LuI45s,18790
16
+ deepagents-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ deepagents-0.3.0.dist-info/top_level.txt,sha256=drAzchOzPNePwpb3_pbPuvLuayXkN7SNqeIKMBWJoAo,11
18
+ deepagents-0.3.0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- deepagents/__init__.py,sha256=9BVNn4lfF5N8l2KY8Ttxi82zO609I-fGqoSIF7DAxiU,342
2
- deepagents/graph.py,sha256=c6ggWJIPaFOK2OCWxZdGEPDfuDvjdDuqHY06-bUiqPg,6379
3
- deepagents/backends/__init__.py,sha256=BOKu2cQ1OdMyO_l2rLqZQiXppYFmQbx7OIQb7WYwvZc,457
4
- deepagents/backends/composite.py,sha256=2BSyAurAt1FXV7iFyajzVaRZvjGkUPBybg7J8E6kRNE,9548
5
- deepagents/backends/filesystem.py,sha256=SsVDx__j_AARIwRzaDuokbxbkquJ_Lw3Qi7dLWaqRUs,18674
6
- deepagents/backends/protocol.py,sha256=Hi6u3MWIfMUGFWwnIFwvmwJbHYsx8IxeU2aaoP_9OMk,5831
7
- deepagents/backends/sandbox.py,sha256=JueMe_2cZcA359JIqIi8kDUkmdtevC4VbKHw-fBPOWs,10125
8
- deepagents/backends/state.py,sha256=ST_tUExPxArJaA3U8vc1dyzxuYl2BQH-HU7P0eu_Ty8,6518
9
- deepagents/backends/store.py,sha256=f2LVSl65Dg-BZl-cY3pl3RqrUJCBMBm2kuAzZEODwsE,13098
10
- deepagents/backends/utils.py,sha256=Iyk2jW-gfoLvMnz-W_2FRCoJW_j3r1zoumU9iww-jd0,13973
11
- deepagents/middleware/__init__.py,sha256=_OGIHcHZ2pRD0gzUBS7R48agwI6P7-FCBKBgjyaWlsg,303
12
- deepagents/middleware/filesystem.py,sha256=3PAetXqWy0i9bE6moM0FDZAEmjMm_M48B4AWWYl4Luk,37271
13
- deepagents/middleware/patch_tool_calls.py,sha256=PdNhxPaQqwnFkhEAZEE2kEzadTNAOO3_iJRA30WqpGE,1981
14
- deepagents/middleware/subagents.py,sha256=RbNpWLXC0Bhr0nUIs40whybNnzNkhxG9Fie7QKsICRk,23748
15
- deepagents-0.2.7.dist-info/METADATA,sha256=H5FgpjWX5qzV5uHcpm0ba4F1Jwtw_Kvj79U9mdUR3Os,18887
16
- deepagents-0.2.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- deepagents-0.2.7.dist-info/top_level.txt,sha256=drAzchOzPNePwpb3_pbPuvLuayXkN7SNqeIKMBWJoAo,11
18
- deepagents-0.2.7.dist-info/RECORD,,