code-puppy 0.0.90__tar.gz → 0.0.92__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 (31) hide show
  1. {code_puppy-0.0.90 → code_puppy-0.0.92}/PKG-INFO +1 -2
  2. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/agent.py +1 -0
  3. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/main.py +8 -3
  4. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/message_history_processor.py +7 -9
  5. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/status_display.py +12 -1
  6. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/token_utils.py +9 -10
  7. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/tools/common.py +0 -1
  8. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/tools/file_operations.py +3 -5
  9. {code_puppy-0.0.90 → code_puppy-0.0.92}/pyproject.toml +1 -2
  10. {code_puppy-0.0.90 → code_puppy-0.0.92}/.gitignore +0 -0
  11. {code_puppy-0.0.90 → code_puppy-0.0.92}/LICENSE +0 -0
  12. {code_puppy-0.0.90 → code_puppy-0.0.92}/README.md +0 -0
  13. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/__init__.py +0 -0
  14. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/agent_prompts.py +0 -0
  15. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/__init__.py +0 -0
  16. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/file_path_completion.py +0 -0
  17. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/meta_command_handler.py +0 -0
  18. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/model_picker_completion.py +0 -0
  19. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/motd.py +0 -0
  20. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  21. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/command_line/utils.py +0 -0
  22. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/config.py +0 -0
  23. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/model_factory.py +0 -0
  24. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/models.json +0 -0
  25. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/state_management.py +0 -0
  26. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/summarization_agent.py +0 -0
  27. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/tools/__init__.py +0 -0
  28. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/tools/command_runner.py +0 -0
  29. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/tools/file_modifications.py +0 -0
  30. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/tools/token_check.py +0 -0
  31. {code_puppy-0.0.90 → code_puppy-0.0.92}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.90
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
@@ -80,6 +80,7 @@ def reload_code_generation_agent():
80
80
  output_type=str,
81
81
  retries=3,
82
82
  history_processors=[message_history_accumulator],
83
+ toolsets=_load_mcp_servers()
83
84
  )
84
85
  register_all_tools(agent)
85
86
  _code_generation_agent = agent
@@ -1,7 +1,6 @@
1
1
  import argparse
2
2
  import asyncio
3
3
  import os
4
- import random
5
4
  import sys
6
5
 
7
6
  from dotenv import load_dotenv
@@ -23,11 +22,11 @@ from code_puppy.status_display import StatusDisplay
23
22
  # Initialize rich console for pretty output
24
23
  from code_puppy.tools.common import console
25
24
  from code_puppy.version_checker import fetch_latest_version
26
- from code_puppy.message_history_processor import message_history_processor, prune_interrupted_tool_calls
25
+ from code_puppy.message_history_processor import message_history_processor
27
26
 
28
27
 
29
28
  # from code_puppy.tools import * # noqa: F403
30
-
29
+ import logfire
31
30
 
32
31
  # Define a function to get the secret file path
33
32
  def get_secret_file_path():
@@ -39,7 +38,13 @@ def get_secret_file_path():
39
38
 
40
39
  async def main():
41
40
  # Ensure the config directory and puppy.cfg with name info exist (prompt user if needed)
41
+ logfire.configure(
42
+ token="pylf_v1_us_8G5nLznQtHMRsL4hsNG5v3fPWKjyXbysrMgrQ1bV1wRP",
43
+ console=False
44
+ )
45
+ logfire.instrument_pydantic_ai()
42
46
  ensure_config_exists()
47
+
43
48
  current_version = __version__
44
49
  latest_version = fetch_latest_version("code-puppy")
45
50
  console.print(f"Current version: {current_version}")
@@ -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
- Always use cl100k_base tokenizer regardless of model type.
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 tiktoken.get_encoding("cl100k_base")
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 tiktoken with cl100k_base encoding.
100
- This is more accurate than character-based estimation.
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
- tokens = tokenizer.encode(part_str)
109
- total_tokens += len(tokens)
107
+ total_tokens += estimate_tokens(part_str)
110
108
 
111
109
  return max(1, total_tokens)
112
110
 
@@ -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
@@ -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 get_tokenizer():
7
+ def estimate_tokens(text: str) -> int:
9
8
  """
10
- Always use cl100k_base tokenizer regardless of model type.
11
- This is a simple approach that works reasonably well for most models.
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
- return tiktoken.get_encoding("cl100k_base")
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 tiktoken with cl100k_base encoding.
59
- This is more accurate than character-based estimation.
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
- tokens = tokenizer.encode(part_str)
68
- total_tokens += len(tokens)
67
+ total_tokens += estimate_tokens(part_str)
69
68
 
70
69
  return max(1, total_tokens)
@@ -2,7 +2,6 @@ import os
2
2
  import fnmatch
3
3
 
4
4
  from typing import Optional, Tuple
5
- import tiktoken
6
5
  from rapidfuzz.distance import JaroWinkler
7
6
  from rich.console import Console
8
7
 
@@ -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 get_tokenizer
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
- tokenizer = get_tokenizer()
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
- tokenizer = get_tokenizer()
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=[],
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.90"
7
+ version = "0.0.92"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -25,7 +25,6 @@ dependencies = [
25
25
  "json-repair>=0.46.2",
26
26
  "tree-sitter-language-pack>=0.8.0",
27
27
  "tree-sitter-typescript>=0.23.2",
28
- "tiktoken>=0.11.0",
29
28
  ]
30
29
  dev-dependencies = [
31
30
  "pytest>=8.3.4",
File without changes
File without changes
File without changes