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.
- deepagents/backends/composite.py +321 -9
- deepagents/backends/filesystem.py +90 -23
- deepagents/backends/protocol.py +289 -27
- deepagents/backends/sandbox.py +24 -5
- deepagents/backends/state.py +6 -10
- deepagents/backends/store.py +72 -8
- deepagents/graph.py +18 -4
- deepagents/middleware/filesystem.py +209 -27
- deepagents/middleware/subagents.py +4 -2
- {deepagents-0.2.7.dist-info → deepagents-0.3.0.dist-info}/METADATA +5 -8
- deepagents-0.3.0.dist-info/RECORD +18 -0
- deepagents-0.2.7.dist-info/RECORD +0 -18
- {deepagents-0.2.7.dist-info → deepagents-0.3.0.dist-info}/WHEEL +0 -0
- {deepagents-0.2.7.dist-info → deepagents-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -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,
|
|
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 `~`)
|
|
111
|
-
|
|
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
|
-
|
|
316
|
-
|
|
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
|
-
|
|
333
|
+
paths = [fi.get("path", "") for fi in infos]
|
|
334
|
+
result = truncate_if_too_long(paths)
|
|
335
|
+
return str(result)
|
|
321
336
|
|
|
322
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
460
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
15
|
-
Requires-Dist: langchain<2.0.0,>=1.0
|
|
16
|
-
Requires-Dist: langchain-core<2.0.0,>=1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|