code-puppy 0.0.91__py3-none-any.whl → 0.0.92__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.
- code_puppy/main.py +4 -1
- code_puppy/message_history_processor.py +7 -9
- code_puppy/status_display.py +12 -1
- code_puppy/token_utils.py +9 -10
- code_puppy/tools/common.py +0 -1
- code_puppy/tools/file_operations.py +3 -5
- {code_puppy-0.0.91.dist-info → code_puppy-0.0.92.dist-info}/METADATA +1 -2
- {code_puppy-0.0.91.dist-info → code_puppy-0.0.92.dist-info}/RECORD +12 -12
- {code_puppy-0.0.91.data → code_puppy-0.0.92.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.91.dist-info → code_puppy-0.0.92.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.91.dist-info → code_puppy-0.0.92.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.91.dist-info → code_puppy-0.0.92.dist-info}/licenses/LICENSE +0 -0
code_puppy/main.py
CHANGED
|
@@ -38,7 +38,10 @@ def get_secret_file_path():
|
|
|
38
38
|
|
|
39
39
|
async def main():
|
|
40
40
|
# Ensure the config directory and puppy.cfg with name info exist (prompt user if needed)
|
|
41
|
-
logfire.configure(
|
|
41
|
+
logfire.configure(
|
|
42
|
+
token="pylf_v1_us_8G5nLznQtHMRsL4hsNG5v3fPWKjyXbysrMgrQ1bV1wRP",
|
|
43
|
+
console=False
|
|
44
|
+
)
|
|
42
45
|
logfire.instrument_pydantic_ai()
|
|
43
46
|
ensure_config_exists()
|
|
44
47
|
|
|
@@ -4,7 +4,6 @@ import os
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
import pydantic
|
|
7
|
-
import tiktoken
|
|
8
7
|
from pydantic_ai.messages import (
|
|
9
8
|
ModelMessage,
|
|
10
9
|
TextPart,
|
|
@@ -16,6 +15,7 @@ from pydantic_ai.messages import (
|
|
|
16
15
|
from code_puppy.tools.common import console
|
|
17
16
|
from code_puppy.model_factory import ModelFactory
|
|
18
17
|
from code_puppy.config import get_model_name
|
|
18
|
+
from code_puppy.token_utils import estimate_tokens
|
|
19
19
|
|
|
20
20
|
# Import the status display to get token rate info
|
|
21
21
|
try:
|
|
@@ -46,12 +46,12 @@ except ImportError:
|
|
|
46
46
|
return None
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
# Dummy function for backward compatibility
|
|
49
50
|
def get_tokenizer_for_model(model_name: str):
|
|
50
51
|
"""
|
|
51
|
-
|
|
52
|
-
This is a simple approach that works reasonably well for most models.
|
|
52
|
+
Dummy function that returns None since we're now using len/4 heuristic.
|
|
53
53
|
"""
|
|
54
|
-
return
|
|
54
|
+
return None
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
def stringify_message_part(part) -> str:
|
|
@@ -96,17 +96,15 @@ def stringify_message_part(part) -> str:
|
|
|
96
96
|
|
|
97
97
|
def estimate_tokens_for_message(message: ModelMessage) -> int:
|
|
98
98
|
"""
|
|
99
|
-
Estimate the number of tokens in a message using
|
|
100
|
-
This is
|
|
99
|
+
Estimate the number of tokens in a message using the len/4 heuristic.
|
|
100
|
+
This is a simple approximation that works reasonably well for most text.
|
|
101
101
|
"""
|
|
102
|
-
tokenizer = get_tokenizer_for_model(get_model_name())
|
|
103
102
|
total_tokens = 0
|
|
104
103
|
|
|
105
104
|
for part in message.parts:
|
|
106
105
|
part_str = stringify_message_part(part)
|
|
107
106
|
if part_str:
|
|
108
|
-
|
|
109
|
-
total_tokens += len(tokens)
|
|
107
|
+
total_tokens += estimate_tokens(part_str)
|
|
110
108
|
|
|
111
109
|
return max(1, total_tokens)
|
|
112
110
|
|
code_puppy/status_display.py
CHANGED
|
@@ -104,9 +104,13 @@ class StatusDisplay:
|
|
|
104
104
|
|
|
105
105
|
def update_token_count(self, tokens: int) -> None:
|
|
106
106
|
"""Update the token count and recalculate the rate"""
|
|
107
|
+
# Reset timing if this is the first update of a new task
|
|
107
108
|
if self.start_time is None:
|
|
108
109
|
self.start_time = time.time()
|
|
109
110
|
self.last_update_time = self.start_time
|
|
111
|
+
# Reset token counters for new task
|
|
112
|
+
self.last_token_count = 0
|
|
113
|
+
self.current_rate = 0.0
|
|
110
114
|
|
|
111
115
|
# Allow for incremental updates (common for streaming) or absolute updates
|
|
112
116
|
if tokens > self.token_count or tokens < 0:
|
|
@@ -204,6 +208,13 @@ class StatusDisplay:
|
|
|
204
208
|
avg_rate = self.token_count / elapsed if elapsed > 0 else 0
|
|
205
209
|
self.console.print(f"[dim]Completed: {self.token_count} tokens in {elapsed:.1f}s ({avg_rate:.1f} t/s avg)[/dim]")
|
|
206
210
|
|
|
207
|
-
# Reset
|
|
211
|
+
# Reset state
|
|
208
212
|
self.start_time = None
|
|
209
213
|
self.token_count = 0
|
|
214
|
+
self.last_update_time = None
|
|
215
|
+
self.last_token_count = 0
|
|
216
|
+
self.current_rate = 0
|
|
217
|
+
|
|
218
|
+
# Reset global rate to 0 to avoid affecting subsequent tasks
|
|
219
|
+
global CURRENT_TOKEN_RATE
|
|
220
|
+
CURRENT_TOKEN_RATE = 0.0
|
code_puppy/token_utils.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import tiktoken
|
|
3
2
|
|
|
4
3
|
import pydantic
|
|
5
4
|
from pydantic_ai.messages import ModelMessage
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
def
|
|
7
|
+
def estimate_tokens(text: str) -> int:
|
|
9
8
|
"""
|
|
10
|
-
|
|
11
|
-
This is a simple
|
|
9
|
+
Estimate the number of tokens using the len/4 heuristic.
|
|
10
|
+
This is a simple approximation that works reasonably well for most text.
|
|
12
11
|
"""
|
|
13
|
-
|
|
12
|
+
if not text:
|
|
13
|
+
return 0
|
|
14
|
+
return max(1, len(text) // 4)
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def stringify_message_part(part) -> str:
|
|
@@ -55,16 +56,14 @@ def stringify_message_part(part) -> str:
|
|
|
55
56
|
|
|
56
57
|
def estimate_tokens_for_message(message: ModelMessage) -> int:
|
|
57
58
|
"""
|
|
58
|
-
Estimate the number of tokens in a message using
|
|
59
|
-
This is
|
|
59
|
+
Estimate the number of tokens in a message using the len/4 heuristic.
|
|
60
|
+
This is a simple approximation that works reasonably well for most text.
|
|
60
61
|
"""
|
|
61
|
-
tokenizer = get_tokenizer()
|
|
62
62
|
total_tokens = 0
|
|
63
63
|
|
|
64
64
|
for part in message.parts:
|
|
65
65
|
part_str = stringify_message_part(part)
|
|
66
66
|
if part_str:
|
|
67
|
-
|
|
68
|
-
total_tokens += len(tokens)
|
|
67
|
+
total_tokens += estimate_tokens(part_str)
|
|
69
68
|
|
|
70
69
|
return max(1, total_tokens)
|
code_puppy/tools/common.py
CHANGED
|
@@ -7,7 +7,7 @@ from pydantic import BaseModel, conint
|
|
|
7
7
|
from pydantic_ai import RunContext
|
|
8
8
|
|
|
9
9
|
from code_puppy.tools.common import console
|
|
10
|
-
from code_puppy.token_utils import
|
|
10
|
+
from code_puppy.token_utils import estimate_tokens
|
|
11
11
|
from code_puppy.tools.token_check import token_guard
|
|
12
12
|
# ---------------------------------------------------------------------------
|
|
13
13
|
# Module-level helper functions (exposed for unit tests _and_ used as tools)
|
|
@@ -218,8 +218,7 @@ def _read_file(context: RunContext, file_path: str, start_line: int | None = Non
|
|
|
218
218
|
# Read the entire file
|
|
219
219
|
content = f.read()
|
|
220
220
|
|
|
221
|
-
|
|
222
|
-
num_tokens = len(tokenizer.encode(content))
|
|
221
|
+
num_tokens = estimate_tokens(content)
|
|
223
222
|
if num_tokens > 10000:
|
|
224
223
|
raise ValueError("The file is massive, greater than 10,000 tokens which is dangerous to read entirely. Please read this file in chunks.")
|
|
225
224
|
token_guard(num_tokens)
|
|
@@ -313,8 +312,7 @@ def list_files(
|
|
|
313
312
|
context: RunContext, directory: str = ".", recursive: bool = True
|
|
314
313
|
) -> ListFileOutput:
|
|
315
314
|
list_files_output = _list_files(context, directory, recursive)
|
|
316
|
-
|
|
317
|
-
num_tokens = len(tokenizer.encode(list_files_output.model_dump_json()))
|
|
315
|
+
num_tokens = estimate_tokens(list_files_output.model_dump_json())
|
|
318
316
|
if num_tokens > 10000:
|
|
319
317
|
return ListFileOutput(
|
|
320
318
|
files=[],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-puppy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.92
|
|
4
4
|
Summary: Code generation agent
|
|
5
5
|
Author: Michael Pfaffenberger
|
|
6
6
|
License: MIT
|
|
@@ -27,7 +27,6 @@ Requires-Dist: python-dotenv>=1.0.0
|
|
|
27
27
|
Requires-Dist: rapidfuzz>=3.13.0
|
|
28
28
|
Requires-Dist: rich>=13.4.2
|
|
29
29
|
Requires-Dist: ruff>=0.11.11
|
|
30
|
-
Requires-Dist: tiktoken>=0.11.0
|
|
31
30
|
Requires-Dist: tree-sitter-language-pack>=0.8.0
|
|
32
31
|
Requires-Dist: tree-sitter-typescript>=0.23.2
|
|
33
32
|
Description-Content-Type: text/markdown
|
|
@@ -2,14 +2,14 @@ code_puppy/__init__.py,sha256=CWH46ZAmJRmHAbOiAhG07OrWYEcEt4yvDTkZU341Wag,169
|
|
|
2
2
|
code_puppy/agent.py,sha256=Hwlblm9Om4qZPOur28auxBkdJRAA9Kz-36YPQg7i3SI,3321
|
|
3
3
|
code_puppy/agent_prompts.py,sha256=t3-lqDKrDxCKxFa_va4Suze9BT-JOu1dh9iGiAVNFO4,6828
|
|
4
4
|
code_puppy/config.py,sha256=r5nw5ChOP8xd_K5yo8U5OtO2gy2bFhARiyNtDp1JrwQ,5013
|
|
5
|
-
code_puppy/main.py,sha256=
|
|
6
|
-
code_puppy/message_history_processor.py,sha256
|
|
5
|
+
code_puppy/main.py,sha256=4ru_POVn6_QylecnJ12aNi95mi0bZ4A6P1Ujzn_YD4k,21220
|
|
6
|
+
code_puppy/message_history_processor.py,sha256=-bdtufnxMNrX9JLY6dgmxGxjgy4sutTjA_SCKGnEaaA,9931
|
|
7
7
|
code_puppy/model_factory.py,sha256=HXuFHNkVjkCcorAd3ScFmSvBILO932UTq6OmNAqisT8,10898
|
|
8
8
|
code_puppy/models.json,sha256=jr0-LW87aJS79GosVwoZdHeeq5eflPzgdPoMbcqpVA8,2728
|
|
9
9
|
code_puppy/state_management.py,sha256=JkTkmq6f9rl_RHPDoBqJvbAzgaMsIkJf-k38ragItIo,1692
|
|
10
|
-
code_puppy/status_display.py,sha256=
|
|
10
|
+
code_puppy/status_display.py,sha256=P4FVtbzdGQs11UDz4ZlWKOpuNYLQ8ILANi2NlMyjKp8,8413
|
|
11
11
|
code_puppy/summarization_agent.py,sha256=jHUQe6iYJsMT0ywEwO7CrhUIKEamO5imhAsDwvNuvow,2684
|
|
12
|
-
code_puppy/token_utils.py,sha256=
|
|
12
|
+
code_puppy/token_utils.py,sha256=c3mD-7VSvkybP9J4kptyrq_jushtzaKUTj6qj2ddqZA,2070
|
|
13
13
|
code_puppy/version_checker.py,sha256=aRGulzuY4C4CdFvU1rITduyL-1xTFsn4GiD1uSfOl_Y,396
|
|
14
14
|
code_puppy/command_line/__init__.py,sha256=y7WeRemfYppk8KVbCGeAIiTuiOszIURCDjOMZv_YRmU,45
|
|
15
15
|
code_puppy/command_line/file_path_completion.py,sha256=gw8NpIxa6GOpczUJRyh7VNZwoXKKn-yvCqit7h2y6Gg,2931
|
|
@@ -20,13 +20,13 @@ code_puppy/command_line/prompt_toolkit_completion.py,sha256=De_grHDPOvCRph-HDOGC
|
|
|
20
20
|
code_puppy/command_line/utils.py,sha256=7eyxDHjPjPB9wGDJQQcXV_zOsGdYsFgI0SGCetVmTqE,1251
|
|
21
21
|
code_puppy/tools/__init__.py,sha256=WTHYIfRk2KMmk6o45TELpbB3GIiAm8s7GmfJ7Zy_tww,503
|
|
22
22
|
code_puppy/tools/command_runner.py,sha256=9UWCSPpuEndaPx8Ecc8TRsn3rMHNd2AqerirvYPGRIw,14358
|
|
23
|
-
code_puppy/tools/common.py,sha256=
|
|
23
|
+
code_puppy/tools/common.py,sha256=fQL5ub2HgAo_s8RCeQFYwmALgrPfkUi35Q0InK4_7lE,3249
|
|
24
24
|
code_puppy/tools/file_modifications.py,sha256=BzQrGEacS2NZr2ru9N30x_Qd70JDudBKOAPO1XjBohg,13861
|
|
25
|
-
code_puppy/tools/file_operations.py,sha256=
|
|
25
|
+
code_puppy/tools/file_operations.py,sha256=htrdURR1mBqBUja1mAHLlySwFN6xNHeGdYbg5eLiOug,13533
|
|
26
26
|
code_puppy/tools/token_check.py,sha256=F3eygdI8fgb6dfCrSkGw_OLI7cb_Kpa5ILft4BQ7hvY,525
|
|
27
|
-
code_puppy-0.0.
|
|
28
|
-
code_puppy-0.0.
|
|
29
|
-
code_puppy-0.0.
|
|
30
|
-
code_puppy-0.0.
|
|
31
|
-
code_puppy-0.0.
|
|
32
|
-
code_puppy-0.0.
|
|
27
|
+
code_puppy-0.0.92.data/data/code_puppy/models.json,sha256=jr0-LW87aJS79GosVwoZdHeeq5eflPzgdPoMbcqpVA8,2728
|
|
28
|
+
code_puppy-0.0.92.dist-info/METADATA,sha256=gBLvPgAiTg5Ut7rMaBA_wiyVV3pGDe8yBy-TrUJDuRk,6319
|
|
29
|
+
code_puppy-0.0.92.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
30
|
+
code_puppy-0.0.92.dist-info/entry_points.txt,sha256=d8YkBvIUxF-dHNJAj-x4fPEqizbY5d_TwvYpc01U5kw,58
|
|
31
|
+
code_puppy-0.0.92.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
|
|
32
|
+
code_puppy-0.0.92.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|