patchpal 0.22.3__tar.gz → 0.22.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.
Files changed (67) hide show
  1. {patchpal-0.22.3/patchpal.egg-info → patchpal-0.22.5}/PKG-INFO +1 -1
  2. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/__init__.py +1 -1
  3. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/agent/function_calling.py +4 -4
  4. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/context.py +21 -17
  5. {patchpal-0.22.3 → patchpal-0.22.5/patchpal.egg-info}/PKG-INFO +1 -1
  6. {patchpal-0.22.3 → patchpal-0.22.5}/LICENSE +0 -0
  7. {patchpal-0.22.3 → patchpal-0.22.5}/MANIFEST.in +0 -0
  8. {patchpal-0.22.3 → patchpal-0.22.5}/README.md +0 -0
  9. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/agent/__init__.py +0 -0
  10. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/agent/react.py +0 -0
  11. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/cli/__init__.py +0 -0
  12. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/cli/autopilot.py +0 -0
  13. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/cli/interactive.py +0 -0
  14. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/cli/mcp.py +0 -0
  15. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/cli/sandbox.py +0 -0
  16. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/cli/streaming.py +0 -0
  17. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/config.py +0 -0
  18. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/permissions.py +0 -0
  19. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/prompts/react_prompt.md +0 -0
  20. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/prompts/system_prompt.md +0 -0
  21. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/skills.py +0 -0
  22. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/__init__.py +0 -0
  23. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/audit.py +0 -0
  24. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/code_analysis.py +0 -0
  25. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/common.py +0 -0
  26. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/definitions.py +0 -0
  27. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/file_reading.py +0 -0
  28. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/file_writing.py +0 -0
  29. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/find_tool.py +0 -0
  30. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/grep_tool.py +0 -0
  31. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/image_handler.py +0 -0
  32. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/mcp.py +0 -0
  33. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/repo_map.py +0 -0
  34. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/shell_tools.py +0 -0
  35. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/todo_tools.py +0 -0
  36. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/tool_schema.py +0 -0
  37. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/user_interaction.py +0 -0
  38. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal/tools/web_tools.py +0 -0
  39. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal.egg-info/SOURCES.txt +0 -0
  40. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal.egg-info/dependency_links.txt +0 -0
  41. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal.egg-info/entry_points.txt +0 -0
  42. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal.egg-info/requires.txt +0 -0
  43. {patchpal-0.22.3 → patchpal-0.22.5}/patchpal.egg-info/top_level.txt +0 -0
  44. {patchpal-0.22.3 → patchpal-0.22.5}/pyproject.toml +0 -0
  45. {patchpal-0.22.3 → patchpal-0.22.5}/setup.cfg +0 -0
  46. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_agent.py +0 -0
  47. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_cli.py +0 -0
  48. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_config_dynamic.py +0 -0
  49. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_context.py +0 -0
  50. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_custom_tools.py +0 -0
  51. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_enabled_tools.py +0 -0
  52. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_find_tool.py +0 -0
  53. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_guardrails.py +0 -0
  54. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_image_blocking.py +0 -0
  55. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_maximum_security.py +0 -0
  56. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_mcp_config.py +0 -0
  57. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_memory.py +0 -0
  58. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_operational_safety.py +0 -0
  59. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_optional_tools.py +0 -0
  60. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_permissions.py +0 -0
  61. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_react.py +0 -0
  62. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_reasoning_content.py +0 -0
  63. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_repo_map.py +0 -0
  64. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_simplified_prompt.py +0 -0
  65. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_skills.py +0 -0
  66. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_streaming.py +0 -0
  67. {patchpal-0.22.3 → patchpal-0.22.5}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchpal
3
- Version: 0.22.3
3
+ Version: 0.22.5
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
@@ -1,6 +1,6 @@
1
1
  """PatchPal - An open-source Claude Code clone implemented purely in Python."""
2
2
 
3
- __version__ = "0.22.3"
3
+ __version__ = "0.22.5"
4
4
 
5
5
  from patchpal.agent import create_agent, create_react_agent
6
6
  from patchpal.cli.autopilot import autopilot_loop
@@ -741,6 +741,7 @@ It's currently empty (just the template). The file is automatically loaded at se
741
741
  response = litellm.completion(
742
742
  model=self.model_id,
743
743
  messages=messages,
744
+ max_tokens=32000, # Explicit output token limit for predictable context usage
744
745
  timeout=LLM_TIMEOUT,
745
746
  **self.litellm_kwargs,
746
747
  )
@@ -957,10 +958,8 @@ It's currently empty (just the template). The file is automatically loaded at se
957
958
 
958
959
  # Check for compaction BEFORE starting work
959
960
  # This ensures we never compact mid-execution and lose tool results
960
- # Use last_prompt_tokens from previous API call for accurate check (includes cache operations)
961
- if self.enable_auto_compact and self.context_manager.needs_compaction(
962
- self.messages, actual_prompt_tokens=self.last_prompt_tokens
963
- ):
961
+ # Always estimates current messages to avoid staleness issues (no actual_prompt_tokens)
962
+ if self.enable_auto_compact and self.context_manager.needs_compaction(self.messages):
964
963
  self._perform_auto_compaction()
965
964
 
966
965
  # Agent loop with interrupt handling
@@ -1080,6 +1079,7 @@ It's currently empty (just the template). The file is automatically loaded at se
1080
1079
  "messages": messages,
1081
1080
  "tools": tools,
1082
1081
  "tool_choice": "auto",
1082
+ "max_tokens": 32000, # Explicit output token limit for predictable context usage
1083
1083
  "timeout": LLM_TIMEOUT,
1084
1084
  "stream": stream,
1085
1085
  **self.litellm_kwargs,
@@ -257,7 +257,10 @@ Be comprehensive but concise. The goal is to continue work seamlessly without lo
257
257
  self.system_prompt = system_prompt
258
258
  self.estimator = TokenEstimator(model_id)
259
259
  self.context_limit = self._get_context_limit()
260
- self.output_reserve = 4_096 # Reserve tokens for model output
260
+ # Reserve 16% of context for output (min 4K, max 32K)
261
+ # This ensures older models like GPT-4 (8K) get 1.28K reserve
262
+ # while modern models get full 32K reserve
263
+ self.output_reserve = min(32_000, max(4_000, int(self.context_limit * 0.16)))
261
264
 
262
265
  def _get_context_limit(self) -> int:
263
266
  """Get context limit for model.
@@ -321,30 +324,31 @@ Be comprehensive but concise. The goal is to continue work seamlessly without lo
321
324
  ) -> bool:
322
325
  """Check if context window needs compaction.
323
326
 
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
+ ALWAYS estimates current messages to avoid staleness issues when predicting
328
+ whether the NEXT API call will overflow. Using actual_prompt_tokens from a
329
+ previous call can cause false negatives when large messages are added between
330
+ the last API call and the compaction check.
327
331
 
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.
332
+ Example of staleness bug (fixed):
333
+ - Previous API call: 120K tokens (60% usage)
334
+ - User pastes huge changelog: +90K tokens
335
+ - Total: 210K tokens (exceeds 200K limit)
336
+ - Bug: If we used actual_prompt_tokens=120K, we'd think we're at 60%
337
+ - Fix: Always re-estimate to see the 210K total
338
+
339
+ The actual_prompt_tokens parameter is kept for API compatibility but ignored
340
+ for compaction decisions. Use get_usage_stats() for display purposes where
341
+ actual tokens are appropriate (staleness OK for showing recent stats).
330
342
 
331
343
  Args:
332
344
  messages: Current message history
333
- actual_prompt_tokens: Optional actual prompt token count from latest API response
345
+ actual_prompt_tokens: IGNORED - kept for API compatibility only
334
346
 
335
347
  Returns:
336
348
  True if compaction is needed
337
349
  """
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
350
+ # ALWAYS estimate current messages - never use stale actual_prompt_tokens
351
+ # This ensures we detect large message additions that happen between API calls
348
352
  # Note: Dynamic date/time message adds ~30 tokens on each LLM call
349
353
  system_tokens = self.estimator.estimate_tokens(self.system_prompt)
350
354
  datetime_tokens = 30 # Approximate size of dynamic date/time message
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchpal
3
- Version: 0.22.3
3
+ Version: 0.22.5
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
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