henchman-ai 0.1.15__tar.gz → 0.1.16__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 (387) hide show
  1. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/PKG-INFO +1 -1
  2. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/pyproject.toml +1 -1
  3. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/anthropic.py +99 -71
  4. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/version.py +1 -1
  5. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_anthropic_ratelimit.py +42 -2
  6. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/.github/copilot-instructions.md +0 -0
  7. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/.github/workflows/ci.yml +0 -0
  8. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/.github/workflows/docs.yml +0 -0
  9. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/.github/workflows/publish.yml +0 -0
  10. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/.gitignore +0 -0
  11. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/ALPHA_TEST_LOG.md +0 -0
  12. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/BETA_TESTING_ISSUES.md +0 -0
  13. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/BETA_TESTING_ISSUES2.md +0 -0
  14. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/BETA_TESTING_ISSUES3.md +0 -0
  15. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/CHANGELOG.md +0 -0
  16. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/CONTRIBUTING.md +0 -0
  17. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/LICENSE +0 -0
  18. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125050554038512/b0c5ce5844ad8acc/.rag.lock +0 -0
  19. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125050555035824/b0c5ce5844ad8acc/.rag.lock +0 -0
  20. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125050555125200/b0c5ce5844ad8acc/.rag.lock +0 -0
  21. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125051893219152/b0c5ce5844ad8acc/.rag.lock +0 -0
  22. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125080879298512/b0c5ce5844ad8acc/.rag.lock +0 -0
  23. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125080879878832/b0c5ce5844ad8acc/.rag.lock +0 -0
  24. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125080880913088/b0c5ce5844ad8acc/.rag.lock +0 -0
  25. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125081401798976/b0c5ce5844ad8acc/.rag.lock +0 -0
  26. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125246043105824/b0c5ce5844ad8acc/.rag.lock +0 -0
  27. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125246043924496/b0c5ce5844ad8acc/.rag.lock +0 -0
  28. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125246044001472/b0c5ce5844ad8acc/.rag.lock +0 -0
  29. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/125247627445840/b0c5ce5844ad8acc/.rag.lock +0 -0
  30. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/126367803948160/b0c5ce5844ad8acc/.rag.lock +0 -0
  31. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/126368206535376/b0c5ce5844ad8acc/.rag.lock +0 -0
  32. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/126368218825504/b0c5ce5844ad8acc/.rag.lock +0 -0
  33. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/126368326698240/b0c5ce5844ad8acc/.rag.lock +0 -0
  34. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/129118288064016/b0c5ce5844ad8acc/.rag.lock +0 -0
  35. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/129118289735760/b0c5ce5844ad8acc/.rag.lock +0 -0
  36. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/129118290807072/b0c5ce5844ad8acc/.rag.lock +0 -0
  37. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/129118485247328/b0c5ce5844ad8acc/.rag.lock +0 -0
  38. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131782863223120/b0c5ce5844ad8acc/.rag.lock +0 -0
  39. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131782952758032/b0c5ce5844ad8acc/.rag.lock +0 -0
  40. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131782953186608/b0c5ce5844ad8acc/.rag.lock +0 -0
  41. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131783467925184/b0c5ce5844ad8acc/.rag.lock +0 -0
  42. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131953655609296/b0c5ce5844ad8acc/.rag.lock +0 -0
  43. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131953656855104/b0c5ce5844ad8acc/.rag.lock +0 -0
  44. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131954146008512/b0c5ce5844ad8acc/.rag.lock +0 -0
  45. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/131954155550192/b0c5ce5844ad8acc/.rag.lock +0 -0
  46. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133226809006208/b0c5ce5844ad8acc/.rag.lock +0 -0
  47. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133226810375248/b0c5ce5844ad8acc/.rag.lock +0 -0
  48. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133226812410672/b0c5ce5844ad8acc/.rag.lock +0 -0
  49. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133227143444000/b0c5ce5844ad8acc/.rag.lock +0 -0
  50. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133999527639808/b0c5ce5844ad8acc/.rag.lock +0 -0
  51. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133999929687216/b0c5ce5844ad8acc/.rag.lock +0 -0
  52. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/133999955332368/b0c5ce5844ad8acc/.rag.lock +0 -0
  53. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134000027622176/b0c5ce5844ad8acc/.rag.lock +0 -0
  54. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134508512171968/b0c5ce5844ad8acc/.rag.lock +0 -0
  55. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134508512231200/b0c5ce5844ad8acc/.rag.lock +0 -0
  56. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134508512485616/b0c5ce5844ad8acc/.rag.lock +0 -0
  57. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134508855764000/b0c5ce5844ad8acc/.rag.lock +0 -0
  58. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134604944477792/b0c5ce5844ad8acc/.rag.lock +0 -0
  59. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134604945877536/b0c5ce5844ad8acc/.rag.lock +0 -0
  60. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134604946059776/b0c5ce5844ad8acc/.rag.lock +0 -0
  61. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134605456585744/b0c5ce5844ad8acc/.rag.lock +0 -0
  62. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134618534097648/b0c5ce5844ad8acc/.rag.lock +0 -0
  63. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134618535070656/b0c5ce5844ad8acc/.rag.lock +0 -0
  64. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134619942883056/b0c5ce5844ad8acc/.rag.lock +0 -0
  65. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134620110571280/b0c5ce5844ad8acc/.rag.lock +0 -0
  66. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134745693453872/b0c5ce5844ad8acc/.rag.lock +0 -0
  67. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134745694538112/b0c5ce5844ad8acc/.rag.lock +0 -0
  68. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134746088611312/b0c5ce5844ad8acc/.rag.lock +0 -0
  69. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/134746194079344/b0c5ce5844ad8acc/.rag.lock +0 -0
  70. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/138555538485184/b0c5ce5844ad8acc/.rag.lock +0 -0
  71. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/138555538874752/b0c5ce5844ad8acc/.rag.lock +0 -0
  72. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/138555539451408/b0c5ce5844ad8acc/.rag.lock +0 -0
  73. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/138556062045760/b0c5ce5844ad8acc/.rag.lock +0 -0
  74. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139088593563008/b0c5ce5844ad8acc/.rag.lock +0 -0
  75. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139088594086144/b0c5ce5844ad8acc/.rag.lock +0 -0
  76. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139088594201216/b0c5ce5844ad8acc/.rag.lock +0 -0
  77. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139088659820192/b0c5ce5844ad8acc/.rag.lock +0 -0
  78. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139391159286624/b0c5ce5844ad8acc/.rag.lock +0 -0
  79. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139391160298352/b0c5ce5844ad8acc/.rag.lock +0 -0
  80. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139391160361968/b0c5ce5844ad8acc/.rag.lock +0 -0
  81. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/139391778658240/b0c5ce5844ad8acc/.rag.lock +0 -0
  82. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140323476876816/b0c5ce5844ad8acc/.rag.lock +0 -0
  83. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140323493157376/b0c5ce5844ad8acc/.rag.lock +0 -0
  84. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140323629475472/b0c5ce5844ad8acc/.rag.lock +0 -0
  85. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140324020609984/b0c5ce5844ad8acc/.rag.lock +0 -0
  86. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140365102460192/b0c5ce5844ad8acc/.rag.lock +0 -0
  87. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140365132965952/b0c5ce5844ad8acc/.rag.lock +0 -0
  88. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140365156415680/b0c5ce5844ad8acc/.rag.lock +0 -0
  89. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/MagicMock/mock.rag.cache_dir/140365231305696/b0c5ce5844ad8acc/.rag.lock +0 -0
  90. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/PROJECT_PLAN.md +0 -0
  91. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/README.md +0 -0
  92. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/README_enhanced.md +0 -0
  93. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/RELEASE_CHECKLIST.md +0 -0
  94. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/TASK_COMPLETION_SUMMARY.md +0 -0
  95. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/debug_compaction.py +0 -0
  96. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/api.md +0 -0
  97. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/configuration.md +0 -0
  98. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/extensions.md +0 -0
  99. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/getting-started.md +0 -0
  100. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/index.md +0 -0
  101. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/mcp.md +0 -0
  102. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/providers.md +0 -0
  103. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/docs/tools.md +0 -0
  104. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/README.md +0 -0
  105. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/__init__.py +0 -0
  106. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/conftest.py +0 -0
  107. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/helpers.py +0 -0
  108. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/test_answer_vs_action.py +0 -0
  109. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/test_coding_tasks.py +0 -0
  110. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/test_edit_precision.py +0 -0
  111. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/test_skills_memory.py +0 -0
  112. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/evals/test_tool_selection.py +0 -0
  113. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/fix_repl.py +0 -0
  114. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/fix_repl_simple.py +0 -0
  115. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/mkdocs.yml +0 -0
  116. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/replace_method.py +0 -0
  117. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/reproduce_400_error.py +0 -0
  118. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/run_interactive_tests.py +0 -0
  119. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/scripts/build_docs.py +0 -0
  120. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/scripts/ci.sh +0 -0
  121. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/scripts/run_evals.sh +0 -0
  122. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/__init__.py +0 -0
  123. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/__main__.py +0 -0
  124. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/__init__.py +0 -0
  125. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/app.py +0 -0
  126. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/__init__.py +0 -0
  127. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/builtins.py +0 -0
  128. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/chat.py +0 -0
  129. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/extensions.py +0 -0
  130. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/mcp.py +0 -0
  131. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/model.py +0 -0
  132. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/plan.py +0 -0
  133. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/rag.py +0 -0
  134. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/skill.py +0 -0
  135. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/commands/unlimited.py +0 -0
  136. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/console.py +0 -0
  137. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/input.py +0 -0
  138. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/json_output.py +0 -0
  139. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/prompts.py +0 -0
  140. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/repl.py +0 -0
  141. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/repl.py.backup +0 -0
  142. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/cli/repl.py.backup2 +0 -0
  143. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/config/__init__.py +0 -0
  144. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/config/context.py +0 -0
  145. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/config/schema.py +0 -0
  146. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/config/settings.py +0 -0
  147. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/core/__init__.py +0 -0
  148. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/core/agent.py +0 -0
  149. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/core/agent.py.backup +0 -0
  150. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/core/events.py +0 -0
  151. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/core/session.py +0 -0
  152. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/core/turn.py +0 -0
  153. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/extensions/__init__.py +0 -0
  154. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/extensions/base.py +0 -0
  155. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/extensions/manager.py +0 -0
  156. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/mcp/__init__.py +0 -0
  157. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/mcp/client.py +0 -0
  158. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/mcp/config.py +0 -0
  159. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/mcp/manager.py +0 -0
  160. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/mcp/tool.py +0 -0
  161. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/__init__.py +0 -0
  162. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/base.py +0 -0
  163. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/deepseek.py +0 -0
  164. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/ollama.py +0 -0
  165. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/openai_compat.py +0 -0
  166. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/openai_compat.py.backup +0 -0
  167. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/providers/registry.py +0 -0
  168. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/__init__.py +0 -0
  169. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/chunker.py +0 -0
  170. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/concurrency.py +0 -0
  171. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/embedder.py +0 -0
  172. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/indexer.py +0 -0
  173. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/repo_id.py +0 -0
  174. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/store.py +0 -0
  175. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/rag/system.py +0 -0
  176. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/skills/__init__.py +0 -0
  177. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/skills/executor.py +0 -0
  178. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/skills/learner.py +0 -0
  179. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/skills/models.py +0 -0
  180. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/skills/store.py +0 -0
  181. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/__init__.py +0 -0
  182. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/base.py +0 -0
  183. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/__init__.py +0 -0
  184. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/ask_user.py +0 -0
  185. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/file_edit.py +0 -0
  186. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/file_read.py +0 -0
  187. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/file_write.py +0 -0
  188. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/glob_tool.py +0 -0
  189. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/grep.py +0 -0
  190. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/ls.py +0 -0
  191. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/rag_search.py +0 -0
  192. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/shell.py +0 -0
  193. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/web_fetch.py +0 -0
  194. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/builtins/web_search.py +0 -0
  195. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/tools/registry.py +0 -0
  196. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/utils/__init__.py +0 -0
  197. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/utils/compaction.py +0 -0
  198. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/utils/ratelimit.py +0 -0
  199. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/utils/retry.py +0 -0
  200. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/utils/tokens.py +0 -0
  201. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/src/henchman/utils/validation.py +0 -0
  202. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/test_compaction.py +0 -0
  203. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/test_compaction_fix.py +0 -0
  204. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/test_fixes.py +0 -0
  205. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/test_output.txt +0 -0
  206. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/test_run.py +0 -0
  207. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  208. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  209. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  210. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  211. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  212. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/manifest.json +0 -0
  213. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  214. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  215. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  216. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  217. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  218. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/manifest.json +0 -0
  219. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  220. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  221. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  222. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  223. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  224. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/manifest.json +0 -0
  225. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  226. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  227. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  228. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  229. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  230. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/manifest.json +0 -0
  231. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  232. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  233. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  234. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  235. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  236. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/manifest.json +0 -0
  237. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  238. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  239. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  240. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  241. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  242. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/manifest.json +0 -0
  243. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  244. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  245. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  246. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  247. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  248. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/manifest.json +0 -0
  249. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  250. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  251. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  252. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  253. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  254. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/manifest.json +0 -0
  255. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/__init__.py +0 -0
  256. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/__init__.py +0 -0
  257. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_model.py +0 -0
  258. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_model_integration.py +0 -0
  259. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_plan.py +0 -0
  260. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_plan_branch.py +0 -0
  261. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_session_resume_id.py +0 -0
  262. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_skill.py +0 -0
  263. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_skill_extended.py +0 -0
  264. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/commands/test_unlimited.py +0 -0
  265. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_app.py +0 -0
  266. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_app_extended.py +0 -0
  267. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_builtins.py +0 -0
  268. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_chat_command.py +0 -0
  269. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_cli_smoke.py +0 -0
  270. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_commands.py +0 -0
  271. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_commands_repro.py +0 -0
  272. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_console.py +0 -0
  273. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_console_confirm.py +0 -0
  274. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_enhanced_tool_display.py +0 -0
  275. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_input.py +0 -0
  276. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_input_bindings.py +0 -0
  277. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_interrupt.py +0 -0
  278. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_json_output.py +0 -0
  279. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_keyboard_fixes.py +0 -0
  280. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_keyboard_integration.py +0 -0
  281. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_keyboard_interrupt.py +0 -0
  282. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_keyboard_verification.py +0 -0
  283. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_loop_protection.py +0 -0
  284. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_mcp_command.py +0 -0
  285. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_repl.py +0 -0
  286. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_repl_attribute_fix.py +0 -0
  287. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_repl_startup_message.py +0 -0
  288. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/cli/test_repl_toolbar.py +0 -0
  289. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/config/__init__.py +0 -0
  290. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/config/test_context.py +0 -0
  291. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/config/test_schema.py +0 -0
  292. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/config/test_settings.py +0 -0
  293. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/conftest.py +0 -0
  294. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/__init__.py +0 -0
  295. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/test_automatic_compaction.py +0 -0
  296. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/test_events.py +0 -0
  297. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/test_session.py +0 -0
  298. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/test_session_manager.py +0 -0
  299. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/test_streaming_tool_calls.py +0 -0
  300. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/core/test_turn_state.py +0 -0
  301. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/e2e/test_context_safety.py +0 -0
  302. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/e2e/test_plan_mode_workflow.py +0 -0
  303. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/e2e/test_tool_fix.py +0 -0
  304. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/empty_message_validation/test_empty_messages.py +0 -0
  305. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/extensions/__init__.py +0 -0
  306. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/extensions/test_base.py +0 -0
  307. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/extensions/test_command.py +0 -0
  308. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/extensions/test_manager.py +0 -0
  309. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/integration/test_anthropic_functional.py +0 -0
  310. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/integration/test_context_limits.py +0 -0
  311. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/integration/test_tool_integration.py +0 -0
  312. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/mcp/__init__.py +0 -0
  313. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/mcp/test_client.py +0 -0
  314. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/mcp/test_config.py +0 -0
  315. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/mcp/test_manager.py +0 -0
  316. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/mcp/test_tool.py +0 -0
  317. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/__init__.py +0 -0
  318. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_413_error_handling.py +0 -0
  319. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_anthropic.py +0 -0
  320. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_anthropic_validation.py +0 -0
  321. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_base.py +0 -0
  322. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_deepseek.py +0 -0
  323. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_ollama.py +0 -0
  324. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_openai_compat.py +0 -0
  325. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/providers/test_registry.py +0 -0
  326. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/__init__.py +0 -0
  327. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_chunker.py +0 -0
  328. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_concurrency.py +0 -0
  329. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_concurrency_smoke.py +0 -0
  330. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_embedder.py +0 -0
  331. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_indexer.py +0 -0
  332. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_rag_command.py +0 -0
  333. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_rag_concurrency_integration.py +0 -0
  334. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_rag_search_tool.py +0 -0
  335. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_repo_id.py +0 -0
  336. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_store.py +0 -0
  337. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/rag/test_system.py +0 -0
  338. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/skills/test_executor.py +0 -0
  339. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/skills/test_learner.py +0 -0
  340. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/skills/test_markdown_skills.py +0 -0
  341. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/skills/test_models.py +0 -0
  342. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/skills/test_store.py +0 -0
  343. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/skills/test_store_extended.py +0 -0
  344. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/smoke/test_escape_key_behavior.py +0 -0
  345. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/smoke/test_large_file_handling.py +0 -0
  346. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/test_coverage_suite.py +0 -0
  347. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/test_main.py +0 -0
  348. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/test_version.py +0 -0
  349. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/__init__.py +0 -0
  350. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_ask_user_tool.py +0 -0
  351. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_base.py +0 -0
  352. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_directory_tools.py +0 -0
  353. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_file_tools.py +0 -0
  354. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_grep_tool.py +0 -0
  355. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_plan_mode_enforcement.py +0 -0
  356. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_registry.py +0 -0
  357. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_shell_advanced.py +0 -0
  358. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_shell_tool.py +0 -0
  359. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/tools/test_web_fetch_tool.py +0 -0
  360. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/INTERACTIVE_SESSION_TESTS.md +0 -0
  361. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/__init__.py +0 -0
  362. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/conftest.py +0 -0
  363. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_agent.py +0 -0
  364. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_compaction_llm.py +0 -0
  365. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_events.py +0 -0
  366. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_llm.py +0 -0
  367. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_mcp.py +0 -0
  368. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_plan_mode.py +0 -0
  369. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_repl_e2e.py +0 -0
  370. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_repl_integration.py +0 -0
  371. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_session.py +0 -0
  372. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_skills.py +0 -0
  373. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_slash_commands.py +0 -0
  374. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_tokens_llm.py +0 -0
  375. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_tool_calls.py +0 -0
  376. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/ui_integration/test_tool_integration.py +0 -0
  377. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_compaction.py +0 -0
  378. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_compaction_edge_cases.py +0 -0
  379. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_compaction_validation.py +0 -0
  380. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_multi_turn_tool_calls.py +0 -0
  381. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_protected_zone.py +0 -0
  382. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_retry.py +0 -0
  383. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_summarization.py +0 -0
  384. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_tiktoken_integration.py +0 -0
  385. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_token_counter_extended.py +0 -0
  386. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_tool_sequence_compaction.py +0 -0
  387. {henchman_ai-0.1.15 → henchman_ai-0.1.16}/tests/utils/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: henchman-ai
3
- Version: 0.1.15
3
+ Version: 0.1.16
4
4
  Summary: A model-agnostic AI agent CLI - your AI henchman for the terminal
5
5
  Project-URL: Homepage, https://github.com/MGPowerlytics/henchman-ai
6
6
  Project-URL: Repository, https://github.com/MGPowerlytics/henchman-ai
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "henchman-ai"
7
- version = "0.1.15"
7
+ version = "0.1.16"
8
8
  description = "A model-agnostic AI agent CLI - your AI henchman for the terminal"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -4,12 +4,13 @@ This provider uses the Anthropic SDK to communicate with Claude models.
4
4
  Unlike OpenAI-compatible APIs, Anthropic has its own message format.
5
5
  """
6
6
 
7
+ import asyncio
7
8
  import json
8
9
  import os
9
10
  from collections.abc import AsyncIterator
10
11
  from typing import Any
11
12
 
12
- from anthropic import AsyncAnthropic
13
+ from anthropic import AsyncAnthropic, RateLimitError
13
14
 
14
15
  from henchman.providers.base import (
15
16
  FinishReason,
@@ -54,6 +55,7 @@ class AnthropicProvider(ModelProvider):
54
55
  model: str = "claude-sonnet-4-20250514",
55
56
  max_tokens: int = 8192,
56
57
  tokens_per_minute: int = 30000,
58
+ max_retries: int = 3,
57
59
  ) -> None:
58
60
  """Initialize the Anthropic provider.
59
61
 
@@ -62,10 +64,12 @@ class AnthropicProvider(ModelProvider):
62
64
  model: Default model to use.
63
65
  max_tokens: Maximum tokens in response.
64
66
  tokens_per_minute: Maximum tokens per minute (rate limit).
67
+ max_retries: Maximum number of retries for rate limits.
65
68
  """
66
69
  self.api_key = api_key or os.getenv("ANTHROPIC_API_KEY", "")
67
70
  self.default_model = model
68
71
  self.max_tokens = max_tokens
72
+ self.max_retries = max_retries
69
73
  self._client = AsyncAnthropic(api_key=self.api_key or "placeholder")
70
74
  self._rate_limiter = AsyncRateLimiter(tokens_per_minute)
71
75
 
@@ -194,10 +198,6 @@ class AnthropicProvider(ModelProvider):
194
198
  if not (message.content or '').strip():
195
199
  raise ValueError(f"Message with role '{message.role}' cannot have empty content")
196
200
 
197
- # Rate limiting: wait for capacity based on input tokens
198
- input_tokens = TokenCounter.count_messages(messages, model=self.default_model)
199
- await self._rate_limiter.wait_for_capacity(input_tokens)
200
-
201
201
  system_prompt, formatted_messages = self._format_messages(messages)
202
202
 
203
203
  params: dict[str, Any] = {
@@ -213,71 +213,99 @@ class AnthropicProvider(ModelProvider):
213
213
  if tools:
214
214
  params["tools"] = [self._format_tool(t) for t in tools]
215
215
 
216
- total_output_tokens = 0
217
- async with self._client.messages.stream(**params) as stream:
218
- pending_tool_calls: dict[str, dict[str, Any]] = {}
219
- current_tool_id: str | None = None
220
-
221
- async for event in stream:
222
- content: str | None = None
223
- thinking: str | None = None
224
- tool_calls: list[ToolCall] | None = None
225
- finish_reason: FinishReason | None = None
226
-
227
- if event.type == "content_block_start":
228
- block = event.content_block
229
- if block.type == "tool_use":
230
- current_tool_id = block.id
231
- pending_tool_calls[block.id] = {
232
- "id": block.id,
233
- "name": block.name,
234
- "arguments": "",
235
- }
236
-
237
- elif event.type == "content_block_delta":
238
- delta = event.delta
239
- if delta.type == "text_delta":
240
- content = delta.text
241
- total_output_tokens += TokenCounter.count_text(content, model=self.default_model)
242
- elif delta.type == "thinking_delta":
243
- thinking = delta.thinking
244
- total_output_tokens += TokenCounter.count_text(thinking, model=self.default_model)
245
- elif delta.type == "input_json_delta" and current_tool_id:
246
- pending_tool_calls[current_tool_id]["arguments"] += delta.partial_json
247
- # Note: we don't count JSON tokens precisely here as they come in,
248
- # but we could count the delta text.
249
- total_output_tokens += TokenCounter.count_text(delta.partial_json, model=self.default_model)
250
-
251
- elif event.type == "content_block_stop":
252
- current_tool_id = None
253
-
254
- elif event.type == "message_delta":
255
- finish_reason = self._parse_finish_reason(event.delta.stop_reason)
256
-
257
- # Emit completed tool calls
258
- if finish_reason == FinishReason.TOOL_CALLS and pending_tool_calls:
259
- tool_calls = []
260
- for tc_data in pending_tool_calls.values():
261
- try:
262
- arguments = json.loads(tc_data["arguments"]) if tc_data["arguments"] else {}
263
- except json.JSONDecodeError:
264
- arguments = {}
265
- tool_calls.append(
266
- ToolCall(
267
- id=tc_data["id"],
268
- name=tc_data["name"],
269
- arguments=arguments,
270
- )
216
+ input_tokens = TokenCounter.count_messages(messages, model=self.default_model)
217
+ retries = 0
218
+ while True:
219
+ try:
220
+ # Rate limiting: wait for capacity based on input tokens
221
+ await self._rate_limiter.wait_for_capacity(input_tokens)
222
+
223
+ total_output_tokens = 0
224
+ async with self._client.messages.stream(**params) as stream:
225
+ pending_tool_calls: dict[str, dict[str, Any]] = {}
226
+ current_tool_id: str | None = None
227
+
228
+ async for event in stream:
229
+ content: str | None = None
230
+ thinking: str | None = None
231
+ tool_calls: list[ToolCall] | None = None
232
+ finish_reason: FinishReason | None = None
233
+
234
+ if event.type == "content_block_start":
235
+ block = event.content_block
236
+ if block.type == "tool_use":
237
+ current_tool_id = block.id
238
+ pending_tool_calls[block.id] = {
239
+ "id": block.id,
240
+ "name": block.name,
241
+ "arguments": "",
242
+ }
243
+
244
+ elif event.type == "content_block_delta":
245
+ delta = event.delta
246
+ if delta.type == "text_delta":
247
+ content = delta.text
248
+ total_output_tokens += TokenCounter.count_text(content, model=self.default_model)
249
+ elif delta.type == "thinking_delta":
250
+ thinking = delta.thinking
251
+ total_output_tokens += TokenCounter.count_text(thinking, model=self.default_model)
252
+ elif delta.type == "input_json_delta" and current_tool_id:
253
+ pending_tool_calls[current_tool_id]["arguments"] += delta.partial_json
254
+ # Note: we don't count JSON tokens precisely here as they come in,
255
+ # but we could count the delta text.
256
+ total_output_tokens += TokenCounter.count_text(delta.partial_json, model=self.default_model)
257
+
258
+ elif event.type == "content_block_stop":
259
+ current_tool_id = None
260
+
261
+ elif event.type == "message_delta":
262
+ finish_reason = self._parse_finish_reason(event.delta.stop_reason)
263
+
264
+ # Emit completed tool calls
265
+ if finish_reason == FinishReason.TOOL_CALLS and pending_tool_calls:
266
+ tool_calls = []
267
+ for tc_data in pending_tool_calls.values():
268
+ try:
269
+ arguments = json.loads(tc_data["arguments"]) if tc_data["arguments"] else {}
270
+ except json.JSONDecodeError:
271
+ arguments = {}
272
+ tool_calls.append(
273
+ ToolCall(
274
+ id=tc_data["id"],
275
+ name=tc_data["name"],
276
+ arguments=arguments,
277
+ )
278
+ )
279
+
280
+ # Only yield if we have meaningful content
281
+ if content is not None or thinking is not None or tool_calls or finish_reason:
282
+ yield StreamChunk(
283
+ content=content,
284
+ tool_calls=tool_calls,
285
+ finish_reason=finish_reason,
286
+ thinking=thinking,
271
287
  )
272
288
 
273
- # Only yield if we have meaningful content
274
- if content is not None or thinking is not None or tool_calls or finish_reason:
275
- yield StreamChunk(
276
- content=content,
277
- tool_calls=tool_calls,
278
- finish_reason=finish_reason,
279
- thinking=thinking,
280
- )
281
-
282
- # Record final usage
283
- await self._rate_limiter.add_usage(input_tokens + total_output_tokens)
289
+ # Record final usage
290
+ await self._rate_limiter.add_usage(input_tokens + total_output_tokens)
291
+ break # Success, exit retry loop
292
+
293
+ except RateLimitError as e:
294
+ retries += 1
295
+ if retries > self.max_retries:
296
+ raise
297
+
298
+ # Hit rate limit, wait and retry
299
+ # Extract wait time from headers if available, otherwise use exponential backoff
300
+ wait_time = 5.0 * (2 ** (retries - 1)) # Default backoff
301
+
302
+ # Log to console if possible
303
+ from rich.console import Console
304
+ Console().print(f"[yellow]Rate limit reached (429). Retrying in {wait_time:.1f}s... (Attempt {retries}/{self.max_retries})[/yellow]")
305
+
306
+ await asyncio.sleep(wait_time)
307
+ # After sleeping, we loop back and try again.
308
+ # The rate limiter's wait_for_capacity will be called again if we move it inside the loop,
309
+ # but we already called it once. However, Anthropic says we are OVER the limit,
310
+ # so we should probably record that usage or just wait.
311
+ # Let's move the wait_for_capacity INSIDE the retry loop.
@@ -1,6 +1,6 @@
1
1
  """Version information for Henchman-AI."""
2
2
 
3
- VERSION_TUPLE = (0, 1, 15)
3
+ VERSION_TUPLE = (0, 1, 16)
4
4
  VERSION = ".".join(str(v) for v in VERSION_TUPLE)
5
5
 
6
6
  __all__ = ["VERSION", "VERSION_TUPLE"]
@@ -5,8 +5,8 @@ import time
5
5
  import pytest
6
6
  from unittest.mock import MagicMock, patch, AsyncMock
7
7
 
8
- from henchman.providers.anthropic import AnthropicProvider
9
- from henchman.providers.base import Message
8
+ from henchman.providers.anthropic import AnthropicProvider, RateLimitError
9
+ from henchman.providers.base import Message, StreamChunk, FinishReason
10
10
 
11
11
 
12
12
  @pytest.mark.asyncio
@@ -74,3 +74,43 @@ async def test_anthropic_rate_limiting_delays():
74
74
  pass
75
75
 
76
76
  assert mock_sleep.called
77
+
78
+
79
+ @pytest.mark.asyncio
80
+ async def test_anthropic_rate_limit_retry():
81
+ """Test that AnthropicProvider retries on RateLimitError."""
82
+ limit = 100
83
+ messages = [Message(role="user", content="Hello")]
84
+
85
+ with patch('henchman.providers.anthropic.AsyncAnthropic') as mock_anthropic:
86
+ mock_client = MagicMock()
87
+ mock_anthropic.return_value = mock_client
88
+
89
+ provider = AnthropicProvider(api_key="test", tokens_per_minute=limit, max_retries=2)
90
+
91
+ # Setup mock stream for successful call
92
+ mock_stream = AsyncMock()
93
+
94
+ async def mock_aiter():
95
+ yield MagicMock(type="content_block_delta", delta=MagicMock(type="text_delta", text="Success"))
96
+ yield MagicMock(type="message_delta", delta=MagicMock(stop_reason="end_turn"))
97
+
98
+ mock_stream.__aenter__.return_value = mock_aiter()
99
+
100
+ # First call fails, second succeeds
101
+ # Anthropic SDK RateLimitError needs a message and response
102
+ error_response = MagicMock()
103
+ error_response.status_code = 429
104
+ rate_limit_error = RateLimitError(message="Rate limit hit", response=error_response, body={})
105
+
106
+ mock_client.messages.stream.side_effect = [rate_limit_error, mock_stream]
107
+
108
+ with patch('asyncio.sleep', new_callable=AsyncMock) as mock_sleep:
109
+ chunks = []
110
+ async for chunk in provider.chat_completion_stream(messages):
111
+ chunks.append(chunk)
112
+
113
+ assert mock_client.messages.stream.call_count == 2
114
+ assert mock_sleep.call_count == 1
115
+ assert any(c.content == "Success" for c in chunks)
116
+ assert any(c.finish_reason == FinishReason.STOP for c in chunks)
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