patchpal 0.22.2__tar.gz → 0.22.4__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 (67) hide show
  1. {patchpal-0.22.2/patchpal.egg-info → patchpal-0.22.4}/PKG-INFO +2 -2
  2. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/__init__.py +1 -1
  3. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/agent/function_calling.py +8 -0
  4. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/cli/interactive.py +3 -1
  5. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/cli/sandbox.py +0 -3
  6. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/context.py +41 -18
  7. {patchpal-0.22.2 → patchpal-0.22.4/patchpal.egg-info}/PKG-INFO +2 -2
  8. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal.egg-info/requires.txt +1 -1
  9. {patchpal-0.22.2 → patchpal-0.22.4}/pyproject.toml +1 -1
  10. {patchpal-0.22.2 → patchpal-0.22.4}/LICENSE +0 -0
  11. {patchpal-0.22.2 → patchpal-0.22.4}/MANIFEST.in +0 -0
  12. {patchpal-0.22.2 → patchpal-0.22.4}/README.md +0 -0
  13. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/agent/__init__.py +0 -0
  14. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/agent/react.py +0 -0
  15. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/cli/__init__.py +0 -0
  16. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/cli/autopilot.py +0 -0
  17. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/cli/mcp.py +0 -0
  18. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/cli/streaming.py +0 -0
  19. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/config.py +0 -0
  20. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/permissions.py +0 -0
  21. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/prompts/react_prompt.md +0 -0
  22. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/prompts/system_prompt.md +0 -0
  23. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/skills.py +0 -0
  24. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/__init__.py +0 -0
  25. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/audit.py +0 -0
  26. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/code_analysis.py +0 -0
  27. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/common.py +0 -0
  28. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/definitions.py +0 -0
  29. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/file_reading.py +0 -0
  30. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/file_writing.py +0 -0
  31. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/find_tool.py +0 -0
  32. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/grep_tool.py +0 -0
  33. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/image_handler.py +0 -0
  34. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/mcp.py +0 -0
  35. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/repo_map.py +0 -0
  36. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/shell_tools.py +0 -0
  37. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/todo_tools.py +0 -0
  38. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/tool_schema.py +0 -0
  39. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/user_interaction.py +0 -0
  40. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal/tools/web_tools.py +0 -0
  41. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal.egg-info/SOURCES.txt +0 -0
  42. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal.egg-info/dependency_links.txt +0 -0
  43. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal.egg-info/entry_points.txt +0 -0
  44. {patchpal-0.22.2 → patchpal-0.22.4}/patchpal.egg-info/top_level.txt +0 -0
  45. {patchpal-0.22.2 → patchpal-0.22.4}/setup.cfg +0 -0
  46. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_agent.py +0 -0
  47. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_cli.py +0 -0
  48. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_config_dynamic.py +0 -0
  49. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_context.py +0 -0
  50. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_custom_tools.py +0 -0
  51. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_enabled_tools.py +0 -0
  52. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_find_tool.py +0 -0
  53. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_guardrails.py +0 -0
  54. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_image_blocking.py +0 -0
  55. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_maximum_security.py +0 -0
  56. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_mcp_config.py +0 -0
  57. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_memory.py +0 -0
  58. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_operational_safety.py +0 -0
  59. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_optional_tools.py +0 -0
  60. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_permissions.py +0 -0
  61. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_react.py +0 -0
  62. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_reasoning_content.py +0 -0
  63. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_repo_map.py +0 -0
  64. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_simplified_prompt.py +0 -0
  65. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_skills.py +0 -0
  66. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_streaming.py +0 -0
  67. {patchpal-0.22.2 → patchpal-0.22.4}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchpal
3
- Version: 0.22.2
3
+ Version: 0.22.4
4
4
  Summary: An agentic coding and automation assistant, supporting both local and cloud LLMs
5
5
  Author: PatchPal Contributors
6
6
  License-Expression: Apache-2.0
@@ -30,7 +30,7 @@ Requires-Dist: boto3
30
30
  Requires-Dist: pymupdf>=1.23.0
31
31
  Requires-Dist: python-docx>=1.0.0
32
32
  Requires-Dist: python-pptx>=0.6.0
33
- Requires-Dist: tree-sitter-language-pack>=0.3.0
33
+ Requires-Dist: tree-sitter-language-pack<1.0.0,>=0.3.0
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest>=7.0.0; extra == "dev"
36
36
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  """PatchPal - An open-source Claude Code clone implemented purely in Python."""
2
2
 
3
- __version__ = "0.22.2"
3
+ __version__ = "0.22.4"
4
4
 
5
5
  from patchpal.agent import create_agent, create_react_agent
6
6
  from patchpal.cli.autopilot import autopilot_loop
@@ -479,6 +479,10 @@ class PatchPalAgent:
479
479
  self.cumulative_input_tokens = 0
480
480
  self.cumulative_output_tokens = 0
481
481
 
482
+ # Track last prompt tokens from most recent API response (includes cache operations)
483
+ # This is the ACTUAL token count sent to the API, used for accurate context management
484
+ self.last_prompt_tokens = None
485
+
482
486
  # Track cache-related tokens (for Anthropic/Bedrock models with prompt caching)
483
487
  self.cumulative_cache_creation_tokens = 0
484
488
  self.cumulative_cache_read_tokens = 0
@@ -953,6 +957,7 @@ It's currently empty (just the template). The file is automatically loaded at se
953
957
 
954
958
  # Check for compaction BEFORE starting work
955
959
  # This ensures we never compact mid-execution and lose tool results
960
+ # Always estimates current messages to avoid staleness issues (no actual_prompt_tokens)
956
961
  if self.enable_auto_compact and self.context_manager.needs_compaction(self.messages):
957
962
  self._perform_auto_compaction()
958
963
 
@@ -1100,7 +1105,10 @@ It's currently empty (just the template). The file is automatically loaded at se
1100
1105
  last_prompt_tokens = None # Track for reactive context management
1101
1106
  if hasattr(response, "usage") and response.usage:
1102
1107
  if hasattr(response.usage, "prompt_tokens"):
1108
+ # LiteLLM already includes cache operations in prompt_tokens for Anthropic/Bedrock
1109
+ # (see litellm/llms/anthropic/chat/transformation.py)
1103
1110
  last_prompt_tokens = response.usage.prompt_tokens
1111
+ self.last_prompt_tokens = last_prompt_tokens # Store for /status command
1104
1112
  self.cumulative_input_tokens += response.usage.prompt_tokens
1105
1113
  if hasattr(response.usage, "completion_tokens"):
1106
1114
  self.cumulative_output_tokens += response.usage.completion_tokens
@@ -670,7 +670,9 @@ Supported models: Any LiteLLM-supported model
670
670
 
671
671
  # Handle /status command - show context window usage
672
672
  if user_input.lower() in ["status", "/status"]:
673
- stats = agent.context_manager.get_usage_stats(agent.messages)
673
+ stats = agent.context_manager.get_usage_stats(
674
+ agent.messages, actual_prompt_tokens=agent.last_prompt_tokens
675
+ )
674
676
 
675
677
  print("\n" + "=" * 70)
676
678
  print("\033[1;36mContext Window Status\033[0m")
@@ -686,9 +686,6 @@ DESCRIPTION:
686
686
  - Pre-built image with patchpal installed (fast startup)
687
687
  - Auto-mounts ~/.patchpal for custom tools, config, and memory
688
688
  - Custom tools work automatically (from ~/.patchpal/tools/ and <repo>/.patchpal/tools/)
689
- - Auto-sets OLLAMA_CONTEXT_LENGTH for Ollama models:
690
- * 8192 for regular models (agents)
691
- * 32768 for reasoning models (gpt-oss, deepseek-r1, qwq, qwen)
692
689
 
693
690
  Recommended for autopilot mode and high-risk operations.
694
691
 
@@ -321,30 +321,31 @@ Be comprehensive but concise. The goal is to continue work seamlessly without lo
321
321
  ) -> bool:
322
322
  """Check if context window needs compaction.
323
323
 
324
- Supports both reactive (preferred) and proactive (fallback) approaches:
325
- - Reactive: Use actual_prompt_tokens from latest API response
326
- - Proactive: Estimate tokens if actual_prompt_tokens not available
327
-
328
- The reactive approach is preferred as it uses actual token counts from the LLM,
329
- avoiding the need for tiktoken or other estimation methods.
324
+ ALWAYS estimates current messages to avoid staleness issues when predicting
325
+ whether the NEXT API call will overflow. Using actual_prompt_tokens from a
326
+ previous call can cause false negatives when large messages are added between
327
+ the last API call and the compaction check.
328
+
329
+ Example of staleness bug (fixed):
330
+ - Previous API call: 120K tokens (60% usage)
331
+ - User pastes huge changelog: +90K tokens
332
+ - Total: 210K tokens (exceeds 200K limit)
333
+ - Bug: If we used actual_prompt_tokens=120K, we'd think we're at 60%
334
+ - Fix: Always re-estimate to see the 210K total
335
+
336
+ The actual_prompt_tokens parameter is kept for API compatibility but ignored
337
+ for compaction decisions. Use get_usage_stats() for display purposes where
338
+ actual tokens are appropriate (staleness OK for showing recent stats).
330
339
 
331
340
  Args:
332
341
  messages: Current message history
333
- actual_prompt_tokens: Optional actual prompt token count from latest API response
342
+ actual_prompt_tokens: IGNORED - kept for API compatibility only
334
343
 
335
344
  Returns:
336
345
  True if compaction is needed
337
346
  """
338
- # Reactive approach (preferred): use actual token counts from API response
339
- if actual_prompt_tokens is not None:
340
- # Add output reserve to account for response tokens
341
- total_tokens = actual_prompt_tokens + self.output_reserve
342
- usage_ratio = total_tokens / self.context_limit
343
- return usage_ratio >= self.COMPACT_THRESHOLD
344
-
345
- # Proactive approach (fallback): estimate tokens when API data not available
346
- # This uses character-based estimation (3 chars per token) which works
347
- # reliably without requiring tiktoken or network access
347
+ # ALWAYS estimate current messages - never use stale actual_prompt_tokens
348
+ # This ensures we detect large message additions that happen between API calls
348
349
  # Note: Dynamic date/time message adds ~30 tokens on each LLM call
349
350
  system_tokens = self.estimator.estimate_tokens(self.system_prompt)
350
351
  datetime_tokens = 30 # Approximate size of dynamic date/time message
@@ -355,15 +356,37 @@ Be comprehensive but concise. The goal is to continue work seamlessly without lo
355
356
  usage_ratio = total_tokens / self.context_limit
356
357
  return usage_ratio >= self.COMPACT_THRESHOLD
357
358
 
358
- def get_usage_stats(self, messages: List[Dict[str, Any]]) -> Dict[str, Any]:
359
+ def get_usage_stats(
360
+ self, messages: List[Dict[str, Any]], actual_prompt_tokens: int = None
361
+ ) -> Dict[str, Any]:
359
362
  """Get current context usage statistics.
360
363
 
361
364
  Args:
362
365
  messages: Current message history
366
+ actual_prompt_tokens: Optional actual prompt tokens from latest API response (includes cache operations)
363
367
 
364
368
  Returns:
365
369
  Dict with usage statistics
366
370
  """
371
+ # If we have actual prompt tokens from API (includes cache writes/reads), use those
372
+ if actual_prompt_tokens is not None:
373
+ total_tokens = actual_prompt_tokens + self.output_reserve
374
+ # For display purposes, estimate system vs message breakdown
375
+ system_tokens = self.estimator.estimate_tokens(self.system_prompt)
376
+ datetime_tokens = 30
377
+ message_tokens = actual_prompt_tokens - system_tokens - datetime_tokens
378
+
379
+ return {
380
+ "system_tokens": system_tokens + datetime_tokens,
381
+ "message_tokens": max(0, message_tokens), # Ensure non-negative
382
+ "output_reserve": self.output_reserve,
383
+ "total_tokens": total_tokens,
384
+ "context_limit": self.context_limit,
385
+ "usage_ratio": total_tokens / self.context_limit,
386
+ "usage_percent": int((total_tokens / self.context_limit) * 100),
387
+ }
388
+
389
+ # Fallback to estimation when actual tokens not available
367
390
  system_tokens = self.estimator.estimate_tokens(self.system_prompt)
368
391
  datetime_tokens = 30 # Approximate size of dynamic date/time message
369
392
  message_tokens = self.estimator.estimate_messages_tokens(messages)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchpal
3
- Version: 0.22.2
3
+ Version: 0.22.4
4
4
  Summary: An agentic coding and automation assistant, supporting both local and cloud LLMs
5
5
  Author: PatchPal Contributors
6
6
  License-Expression: Apache-2.0
@@ -30,7 +30,7 @@ Requires-Dist: boto3
30
30
  Requires-Dist: pymupdf>=1.23.0
31
31
  Requires-Dist: python-docx>=1.0.0
32
32
  Requires-Dist: python-pptx>=0.6.0
33
- Requires-Dist: tree-sitter-language-pack>=0.3.0
33
+ Requires-Dist: tree-sitter-language-pack<1.0.0,>=0.3.0
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest>=7.0.0; extra == "dev"
36
36
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
@@ -9,7 +9,7 @@ boto3
9
9
  pymupdf>=1.23.0
10
10
  python-docx>=1.0.0
11
11
  python-pptx>=0.6.0
12
- tree-sitter-language-pack>=0.3.0
12
+ tree-sitter-language-pack<1.0.0,>=0.3.0
13
13
 
14
14
  [dev]
15
15
  pytest>=7.0.0
@@ -36,7 +36,7 @@ dependencies = [
36
36
  "pymupdf>=1.23.0",
37
37
  "python-docx>=1.0.0",
38
38
  "python-pptx>=0.6.0",
39
- "tree-sitter-language-pack>=0.3.0",
39
+ "tree-sitter-language-pack>=0.3.0,<1.0.0",
40
40
  ]
41
41
 
42
42
  [project.optional-dependencies]
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