deepagents-cli 0.0.4__tar.gz → 0.0.5__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.
Potentially problematic release.
This version of deepagents-cli might be problematic. Click here for more details.
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/PKG-INFO +2 -2
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/agent.py +39 -28
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/commands.py +3 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/main.py +11 -2
- deepagents_cli-0.0.5/deepagents_cli/token_utils.py +63 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/ui.py +39 -5
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli.egg-info/PKG-INFO +2 -2
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli.egg-info/SOURCES.txt +1 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli.egg-info/requires.txt +1 -1
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/pyproject.toml +2 -2
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/README.md +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/cli.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/config.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/execution.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli.egg-info/dependency_links.txt +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli.egg-info/entry_points.txt +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/deepagents_cli.egg-info/top_level.txt +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/setup.cfg +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.4 → deepagents_cli-0.0.5}/tests/test_placeholder.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: Deepagents CLI
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: <4.0,>=3.11
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: deepagents==0.2.
|
|
8
|
+
Requires-Dist: deepagents==0.2.3
|
|
9
9
|
Requires-Dist: requests
|
|
10
10
|
Requires-Dist: rich>=13.0.0
|
|
11
11
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
@@ -79,35 +79,13 @@ def reset_agent(agent_name: str, source_agent: str = None):
|
|
|
79
79
|
console.print(f"Location: {agent_dir}\n", style=COLORS["dim"])
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
def
|
|
83
|
-
"""
|
|
84
|
-
shell_middleware = ResumableShellToolMiddleware(
|
|
85
|
-
workspace_root=os.getcwd(), execution_policy=HostExecutionPolicy()
|
|
86
|
-
)
|
|
82
|
+
def get_system_prompt() -> str:
|
|
83
|
+
"""Get the base system prompt for the agent.
|
|
87
84
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if not agent_md.exists():
|
|
93
|
-
source_content = get_default_coding_instructions()
|
|
94
|
-
agent_md.write_text(source_content)
|
|
95
|
-
|
|
96
|
-
# Long-term backend - rooted at agent directory
|
|
97
|
-
# This handles both /memories/ files and /agent.md
|
|
98
|
-
long_term_backend = FilesystemBackend(root_dir=agent_dir, virtual_mode=True)
|
|
99
|
-
|
|
100
|
-
# Composite backend: current working directory for default, agent directory for /memories/
|
|
101
|
-
backend = CompositeBackend(
|
|
102
|
-
default=FilesystemBackend(), routes={"/memories/": long_term_backend}
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
# Use the same backend for agent memory middleware
|
|
106
|
-
agent_middleware = [
|
|
107
|
-
AgentMemoryMiddleware(backend=long_term_backend, memory_path="/memories/"),
|
|
108
|
-
shell_middleware,
|
|
109
|
-
]
|
|
110
|
-
system_prompt = f"""### Current Working Directory
|
|
85
|
+
Returns:
|
|
86
|
+
The system prompt string (without agent.md content)
|
|
87
|
+
"""
|
|
88
|
+
return f"""### Current Working Directory
|
|
111
89
|
|
|
112
90
|
The filesystem backend is currently operating in: `{Path.cwd()}`
|
|
113
91
|
|
|
@@ -159,6 +137,39 @@ When using the write_todos tool:
|
|
|
159
137
|
|
|
160
138
|
The todo list is a planning tool - use it judiciously to avoid overwhelming the user with excessive task tracking."""
|
|
161
139
|
|
|
140
|
+
|
|
141
|
+
def create_agent_with_config(model, assistant_id: str, tools: list):
|
|
142
|
+
"""Create and configure an agent with the specified model and tools."""
|
|
143
|
+
shell_middleware = ResumableShellToolMiddleware(
|
|
144
|
+
workspace_root=os.getcwd(), execution_policy=HostExecutionPolicy()
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# For long-term memory, point to ~/.deepagents/AGENT_NAME/ with /memories/ prefix
|
|
148
|
+
agent_dir = Path.home() / ".deepagents" / assistant_id
|
|
149
|
+
agent_dir.mkdir(parents=True, exist_ok=True)
|
|
150
|
+
agent_md = agent_dir / "agent.md"
|
|
151
|
+
if not agent_md.exists():
|
|
152
|
+
source_content = get_default_coding_instructions()
|
|
153
|
+
agent_md.write_text(source_content)
|
|
154
|
+
|
|
155
|
+
# Long-term backend - rooted at agent directory
|
|
156
|
+
# This handles both /memories/ files and /agent.md
|
|
157
|
+
long_term_backend = FilesystemBackend(root_dir=agent_dir, virtual_mode=True)
|
|
158
|
+
|
|
159
|
+
# Composite backend: current working directory for default, agent directory for /memories/
|
|
160
|
+
backend = CompositeBackend(
|
|
161
|
+
default=FilesystemBackend(), routes={"/memories/": long_term_backend}
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Use the same backend for agent memory middleware
|
|
165
|
+
agent_middleware = [
|
|
166
|
+
AgentMemoryMiddleware(backend=long_term_backend, memory_path="/memories/"),
|
|
167
|
+
shell_middleware,
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
# Get the system prompt
|
|
171
|
+
system_prompt = get_system_prompt()
|
|
172
|
+
|
|
162
173
|
# Helper functions for formatting tool descriptions in HITL prompts
|
|
163
174
|
def format_write_file_description(tool_call: dict) -> str:
|
|
164
175
|
"""Format write_file tool call for approval prompt."""
|
|
@@ -20,6 +20,9 @@ def handle_command(command: str, agent, token_tracker: TokenTracker) -> str | bo
|
|
|
20
20
|
# Reset agent conversation state
|
|
21
21
|
agent.checkpointer = InMemorySaver()
|
|
22
22
|
|
|
23
|
+
# Reset token tracking to baseline
|
|
24
|
+
token_tracker.reset()
|
|
25
|
+
|
|
23
26
|
# Clear screen and show fresh UI
|
|
24
27
|
console.clear()
|
|
25
28
|
console.print(DEEP_AGENTS_ASCII, style=f"bold {COLORS['primary']}")
|
|
@@ -93,7 +93,7 @@ def parse_args():
|
|
|
93
93
|
return parser.parse_args()
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
async def simple_cli(agent, assistant_id: str | None, session_state):
|
|
96
|
+
async def simple_cli(agent, assistant_id: str | None, session_state, baseline_tokens: int = 0):
|
|
97
97
|
"""Main CLI loop."""
|
|
98
98
|
console.clear()
|
|
99
99
|
console.print(DEEP_AGENTS_ASCII, style=f"bold {COLORS['primary']}")
|
|
@@ -131,6 +131,7 @@ async def simple_cli(agent, assistant_id: str | None, session_state):
|
|
|
131
131
|
# Create prompt session and token tracker
|
|
132
132
|
session = create_prompt_session(assistant_id, session_state)
|
|
133
133
|
token_tracker = TokenTracker()
|
|
134
|
+
token_tracker.set_baseline(baseline_tokens)
|
|
134
135
|
|
|
135
136
|
while True:
|
|
136
137
|
try:
|
|
@@ -181,8 +182,16 @@ async def main(assistant_id: str, session_state):
|
|
|
181
182
|
|
|
182
183
|
agent = create_agent_with_config(model, assistant_id, tools)
|
|
183
184
|
|
|
185
|
+
# Calculate baseline token count for accurate token tracking
|
|
186
|
+
from .agent import get_system_prompt
|
|
187
|
+
from .token_utils import calculate_baseline_tokens
|
|
188
|
+
|
|
189
|
+
agent_dir = Path.home() / ".deepagents" / assistant_id
|
|
190
|
+
system_prompt = get_system_prompt()
|
|
191
|
+
baseline_tokens = calculate_baseline_tokens(model, agent_dir, system_prompt)
|
|
192
|
+
|
|
184
193
|
try:
|
|
185
|
-
await simple_cli(agent, assistant_id, session_state)
|
|
194
|
+
await simple_cli(agent, assistant_id, session_state, baseline_tokens)
|
|
186
195
|
except Exception as e:
|
|
187
196
|
console.print(f"\n[bold red]❌ Error:[/bold red] {e}\n")
|
|
188
197
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Utilities for accurate token counting using LangChain models."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from langchain_core.messages import SystemMessage
|
|
6
|
+
|
|
7
|
+
from .config import console
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def calculate_baseline_tokens(model, agent_dir: Path, system_prompt: str) -> int:
|
|
11
|
+
"""Calculate baseline context tokens using the model's official tokenizer.
|
|
12
|
+
|
|
13
|
+
This uses the model's get_num_tokens_from_messages() method to get
|
|
14
|
+
accurate token counts for the initial context (system prompt + agent.md).
|
|
15
|
+
|
|
16
|
+
Note: Tool definitions cannot be accurately counted before the first API call
|
|
17
|
+
due to LangChain limitations. They will be included in the total after the
|
|
18
|
+
first message is sent (~5,000 tokens).
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
model: LangChain model instance (ChatAnthropic or ChatOpenAI)
|
|
22
|
+
agent_dir: Path to agent directory containing agent.md
|
|
23
|
+
system_prompt: The base system prompt string
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Token count for system prompt + agent.md (tools not included)
|
|
27
|
+
"""
|
|
28
|
+
# Load agent.md content
|
|
29
|
+
agent_md_path = agent_dir / "agent.md"
|
|
30
|
+
agent_memory = ""
|
|
31
|
+
if agent_md_path.exists():
|
|
32
|
+
agent_memory = agent_md_path.read_text()
|
|
33
|
+
|
|
34
|
+
# Build the complete system prompt as it will be sent
|
|
35
|
+
# This mimics what AgentMemoryMiddleware.wrap_model_call() does
|
|
36
|
+
memory_section = f"<agent_memory>\n{agent_memory}\n</agent_memory>"
|
|
37
|
+
|
|
38
|
+
# Get the long-term memory system prompt
|
|
39
|
+
memory_system_prompt = get_memory_system_prompt()
|
|
40
|
+
|
|
41
|
+
# Combine all parts in the same order as the middleware
|
|
42
|
+
full_system_prompt = memory_section + "\n\n" + system_prompt + "\n\n" + memory_system_prompt
|
|
43
|
+
|
|
44
|
+
# Count tokens using the model's official method
|
|
45
|
+
messages = [SystemMessage(content=full_system_prompt)]
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
# Note: tools parameter is not supported by LangChain's token counting
|
|
49
|
+
# Tool tokens will be included in the API response after first message
|
|
50
|
+
token_count = model.get_num_tokens_from_messages(messages)
|
|
51
|
+
return token_count
|
|
52
|
+
except Exception as e:
|
|
53
|
+
# Fallback if token counting fails
|
|
54
|
+
console.print(f"[yellow]Warning: Could not calculate baseline tokens: {e}[/yellow]")
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_memory_system_prompt() -> str:
|
|
59
|
+
"""Get the long-term memory system prompt text."""
|
|
60
|
+
# Import from agent_memory middleware
|
|
61
|
+
from deepagents.middleware.agent_memory import LONGTERM_MEMORY_SYSTEM_PROMPT
|
|
62
|
+
|
|
63
|
+
return LONGTERM_MEMORY_SYSTEM_PROMPT.format(memory_path="/memories/")
|
|
@@ -165,7 +165,22 @@ class TokenTracker:
|
|
|
165
165
|
"""Track token usage across the conversation."""
|
|
166
166
|
|
|
167
167
|
def __init__(self):
|
|
168
|
-
self.
|
|
168
|
+
self.baseline_context = 0 # Baseline system context (system + agent.md + tools)
|
|
169
|
+
self.current_context = 0 # Total context including messages
|
|
170
|
+
self.last_output = 0
|
|
171
|
+
|
|
172
|
+
def set_baseline(self, tokens: int):
|
|
173
|
+
"""Set the baseline context token count.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
tokens: The baseline token count (system prompt + agent.md + tools)
|
|
177
|
+
"""
|
|
178
|
+
self.baseline_context = tokens
|
|
179
|
+
self.current_context = tokens
|
|
180
|
+
|
|
181
|
+
def reset(self):
|
|
182
|
+
"""Reset to baseline (for /clear command)."""
|
|
183
|
+
self.current_context = self.baseline_context
|
|
169
184
|
self.last_output = 0
|
|
170
185
|
|
|
171
186
|
def add(self, input_tokens: int, output_tokens: int):
|
|
@@ -183,12 +198,31 @@ class TokenTracker:
|
|
|
183
198
|
|
|
184
199
|
def display_session(self):
|
|
185
200
|
"""Display current context size."""
|
|
186
|
-
|
|
187
|
-
|
|
201
|
+
console.print("\n[bold]Token Usage:[/bold]", style=COLORS["primary"])
|
|
202
|
+
|
|
203
|
+
# Check if we've had any actual API calls yet (current > baseline means we have conversation)
|
|
204
|
+
has_conversation = self.current_context > self.baseline_context
|
|
205
|
+
|
|
206
|
+
if self.baseline_context > 0:
|
|
207
|
+
console.print(
|
|
208
|
+
f" Baseline: {self.baseline_context:,} tokens [dim](system + agent.md)[/dim]",
|
|
209
|
+
style=COLORS["dim"],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
if not has_conversation:
|
|
213
|
+
# Before first message - warn that tools aren't counted yet
|
|
214
|
+
console.print(
|
|
215
|
+
" [dim]Note: Tool definitions (~5k tokens) included after first message[/dim]"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
if has_conversation:
|
|
219
|
+
tools_and_conversation = self.current_context - self.baseline_context
|
|
188
220
|
console.print(
|
|
189
|
-
f"
|
|
221
|
+
f" Tools + conversation: {tools_and_conversation:,} tokens", style=COLORS["dim"]
|
|
190
222
|
)
|
|
191
|
-
|
|
223
|
+
|
|
224
|
+
console.print(f" Total: {self.current_context:,} tokens", style="bold " + COLORS["dim"])
|
|
225
|
+
console.print()
|
|
192
226
|
|
|
193
227
|
|
|
194
228
|
def render_todo_list(todos: list[dict]) -> None:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: Deepagents CLI
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: <4.0,>=3.11
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: deepagents==0.2.
|
|
8
|
+
Requires-Dist: deepagents==0.2.3
|
|
9
9
|
Requires-Dist: requests
|
|
10
10
|
Requires-Dist: rich>=13.0.0
|
|
11
11
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "deepagents-cli"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.5"
|
|
4
4
|
description = "Deepagents CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
7
7
|
requires-python = ">=3.11,<4.0"
|
|
8
8
|
dependencies = [
|
|
9
|
-
"deepagents==0.2.
|
|
9
|
+
"deepagents==0.2.3",
|
|
10
10
|
"requests",
|
|
11
11
|
"rich>=13.0.0",
|
|
12
12
|
"prompt-toolkit>=3.0.52",
|
|
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
|