kolega-code 0.26.2__tar.gz → 0.26.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 (360) hide show
  1. {kolega_code-0.26.2 → kolega_code-0.26.4}/CHANGELOG.md +34 -0
  2. {kolega_code-0.26.2 → kolega_code-0.26.4}/PKG-INFO +1 -1
  3. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/__init__.py +1 -1
  4. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/__init__.py +1 -1
  5. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/baseagent.py +14 -6
  6. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/browseragent.py +19 -2
  7. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/coder.py +2 -0
  8. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/context.py +2 -0
  9. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/planningagent.py +2 -0
  10. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_codebase_tool.py +121 -30
  11. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/terminal_tool.py +1 -0
  12. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/think_hard_tool.py +2 -0
  13. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch_tool.py +1 -0
  14. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tools.py +29 -5
  15. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/main.py +7 -0
  16. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/client.py +24 -0
  17. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/instrumented_client.py +4 -1
  18. kolega_code-0.26.4/kolega_code/llm/providers/deepseek_responses.py +66 -0
  19. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/deepseek.py +6 -1
  20. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/manager.py +49 -5
  21. kolega_code-0.26.4/kolega_code/tools/core.py +71 -0
  22. {kolega_code-0.26.2 → kolega_code-0.26.4}/pyproject.toml +8 -2
  23. kolega_code-0.26.2/kolega_code/tools/core.py +0 -33
  24. {kolega_code-0.26.2 → kolega_code-0.26.4}/.gitignore +0 -0
  25. {kolega_code-0.26.2 → kolega_code-0.26.4}/CONTRIBUTING.md +0 -0
  26. {kolega_code-0.26.2 → kolega_code-0.26.4}/LICENSE +0 -0
  27. {kolega_code-0.26.2 → kolega_code-0.26.4}/MIGRATION.md +0 -0
  28. {kolega_code-0.26.2 → kolega_code-0.26.4}/README.md +0 -0
  29. {kolega_code-0.26.2 → kolega_code-0.26.4}/RELEASING.md +0 -0
  30. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/LICENSE +0 -0
  31. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/manifest.json +0 -0
  32. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/deep-research/SKILL.md +0 -0
  33. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/deep-research/references/evidence-and-reporting.md +0 -0
  34. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/deep-research/references/gigacode-workflow.md +0 -0
  35. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/deep-research/scripts/deep-research.workflow +0 -0
  36. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/deep-research/scripts/materialize_report.py +0 -0
  37. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/LICENSE +0 -0
  38. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/SKILL.md +0 -0
  39. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/references/examples.md +0 -0
  40. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/references/limitations.md +0 -0
  41. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/references/operations.md +0 -0
  42. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/references/quality.md +0 -0
  43. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/requirements.txt +0 -0
  44. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/scripts/docx_tool.py +0 -0
  45. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/docx/scripts/smoke_test.py +0 -0
  46. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/humanizer/LICENSE +0 -0
  47. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/humanizer/SKILL.md +0 -0
  48. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/LICENSE +0 -0
  49. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/SKILL.md +0 -0
  50. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/references/examples.md +0 -0
  51. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/references/limitations.md +0 -0
  52. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/references/ocr.md +0 -0
  53. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/references/operations.md +0 -0
  54. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/references/quality.md +0 -0
  55. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/references/redaction.md +0 -0
  56. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/requirements-ocr-paddle.txt +0 -0
  57. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/requirements-ocr-surya.txt +0 -0
  58. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/requirements.txt +0 -0
  59. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/scripts/pdf_tool.py +0 -0
  60. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pdf/scripts/smoke_test.py +0 -0
  61. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/LICENSE +0 -0
  62. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/SKILL.md +0 -0
  63. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/references/examples.md +0 -0
  64. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/references/limitations.md +0 -0
  65. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/references/operations.md +0 -0
  66. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/requirements.txt +0 -0
  67. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/scripts/pptx_tool.py +0 -0
  68. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/pptx/scripts/smoke_test.py +0 -0
  69. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/review/SKILL.md +0 -0
  70. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/review/references/github-publishing.md +0 -0
  71. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/skill-authoring/SKILL.md +0 -0
  72. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/skill-authoring/references/review-checklist.md +0 -0
  73. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/LICENSE +0 -0
  74. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/SKILL.md +0 -0
  75. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/references/examples.md +0 -0
  76. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/references/limitations.md +0 -0
  77. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/references/operations.md +0 -0
  78. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/references/quality.md +0 -0
  79. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/requirements.txt +0 -0
  80. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/scripts/smoke_test.py +0 -0
  81. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/_bundled_skills/skills/xlsx/scripts/xlsx_tool.py +0 -0
  82. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/common.py +0 -0
  83. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/compression.py +0 -0
  84. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/conversation.py +0 -0
  85. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/custom_agents.py +0 -0
  86. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/edit_protocols.py +0 -0
  87. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/errors.py +0 -0
  88. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/__init__.py +0 -0
  89. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/bridge.py +0 -0
  90. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/bundle-requirements.in +0 -0
  91. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/bundle-requirements.txt +0 -0
  92. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/env.py +0 -0
  93. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/js_kernel.py +0 -0
  94. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/kernel.py +0 -0
  95. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/prelude.js +0 -0
  96. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/prelude.py +0 -0
  97. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/protocol.py +0 -0
  98. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/py_kernel.py +0 -0
  99. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/runner.js +0 -0
  100. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/eval/runner.py +0 -0
  101. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/generalagent.py +0 -0
  102. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/goal.py +0 -0
  103. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/investigationagent.py +0 -0
  104. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/model_routing.py +0 -0
  105. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/__init__.py +0 -0
  106. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/accounting.py +0 -0
  107. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/budget.py +0 -0
  108. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/context.py +0 -0
  109. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/errors.py +0 -0
  110. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/executor.py +0 -0
  111. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/guide.py +0 -0
  112. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/journal.py +0 -0
  113. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/runtime.py +0 -0
  114. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/orchestration/types.py +0 -0
  115. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_dump.py +0 -0
  116. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_overrides.py +0 -0
  117. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_provider.py +0 -0
  118. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/auxiliary/compression/summary.system.md +0 -0
  119. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/auxiliary/compression/summary.user.md.j2 +0 -0
  120. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/auxiliary/terminal/output_summary.system.md +0 -0
  121. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/auxiliary/terminal/safety.system.md +0 -0
  122. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/auxiliary/tools/think_hard.system.md +0 -0
  123. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/build_questions.md +0 -0
  124. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/current_plan_artifact.md.j2 +0 -0
  125. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/planning_questions.md +0 -0
  126. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/scratchpad.md.j2 +0 -0
  127. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/shared_task_list.md +0 -0
  128. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/shared_task_list_readonly.md +0 -0
  129. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/cli/worktree_control.md.j2 +0 -0
  130. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/extensions/skills/catalog.md.j2 +0 -0
  131. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/agents/browser.md.j2 +0 -0
  132. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/agents/coder_cli.md.j2 +0 -0
  133. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/agents/general.md.j2 +0 -0
  134. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/agents/investigation.md.j2 +0 -0
  135. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/agents/planning.md.j2 +0 -0
  136. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/agents_md_instructions.md +0 -0
  137. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/context_updates.md +0 -0
  138. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/environment_variables/workspace_env_vars.md +0 -0
  139. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/frontend_guidance.md +0 -0
  140. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/starter_templates/expo.md +0 -0
  141. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/starter_templates/html_website.md +0 -0
  142. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/starter_templates/mern_stack.md +0 -0
  143. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/system/includes/starter_templates/react_vite_shadcdn.md +0 -0
  144. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/user_tasks/cli/implement_plan.md.j2 +0 -0
  145. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompt_templates/user_tasks/cli/init_agents.md.j2 +0 -0
  146. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/prompts.py +0 -0
  147. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/agent_tool.py +0 -0
  148. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/base_tool.py +0 -0
  149. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/browser_tool.py +0 -0
  150. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/build_tool.py +0 -0
  151. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/codex_patch.py +0 -0
  152. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/edit_preview.py +0 -0
  153. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/edit_tool.py +0 -0
  154. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/eval_tool.py +0 -0
  155. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/glob_tool.py +0 -0
  156. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/hashline_v2.py +0 -0
  157. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/list_directory_tool.py +0 -0
  158. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/lsp_tool.py +0 -0
  159. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/memory_tool.py +0 -0
  160. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/read_file_tool.py +0 -0
  161. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/read_image_tool.py +0 -0
  162. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/__init__.py +0 -0
  163. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/base.py +0 -0
  164. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/duckduckgo.py +0 -0
  165. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/errors.py +0 -0
  166. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/firecrawl.py +0 -0
  167. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/models.py +0 -0
  168. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/searxng.py +0 -0
  169. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/search_backends/tavily.py +0 -0
  170. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/snapshot_tool.py +0 -0
  171. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/streaming_tool.py +0 -0
  172. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch/__init__.py +0 -0
  173. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch/answering.py +0 -0
  174. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch/documents.py +0 -0
  175. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch/extractors.py +0 -0
  176. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch/pipeline.py +0 -0
  177. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_fetch/retrieval.py +0 -0
  178. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/web_search_tool.py +0 -0
  179. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/tool_backend/workflow_tool.py +0 -0
  180. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/utils/commands.py +0 -0
  181. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/agent/volatile_context.py +0 -0
  182. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/auth/__init__.py +0 -0
  183. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/auth/_jwt.py +0 -0
  184. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/auth/chatgpt_oauth.py +0 -0
  185. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/auth/constants.py +0 -0
  186. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/auth/tokens.py +0 -0
  187. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/__init__.py +0 -0
  188. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/framing.py +0 -0
  189. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/installer.py +0 -0
  190. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/manager.py +0 -0
  191. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/multiplex.py +0 -0
  192. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/native_host.py +0 -0
  193. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/protocol.py +0 -0
  194. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/registry.py +0 -0
  195. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/browser_extension/runtime.py +0 -0
  196. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/__init__.py +0 -0
  197. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/app.py +0 -0
  198. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/browser_backend.py +0 -0
  199. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/clipboard_image.py +0 -0
  200. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/config.py +0 -0
  201. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/connection.py +0 -0
  202. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/cron.py +0 -0
  203. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/diagnostics.py +0 -0
  204. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/file_index.py +0 -0
  205. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/goal.py +0 -0
  206. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/loop.py +0 -0
  207. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/mentions.py +0 -0
  208. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/messages.py +0 -0
  209. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/model_catalog.py +0 -0
  210. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/model_connection.py +0 -0
  211. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/plan_artifacts.py +0 -0
  212. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/provider_registry.py +0 -0
  213. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/session_event_store.py +0 -0
  214. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/session_journal.py +0 -0
  215. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/session_store.py +0 -0
  216. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/settings.py +0 -0
  217. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/skills.py +0 -0
  218. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/slash_commands.py +0 -0
  219. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/theme.py +0 -0
  220. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/__init__.py +0 -0
  221. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/agent_runtime.py +0 -0
  222. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/app_base.py +0 -0
  223. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/changes_screen.py +0 -0
  224. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/command_handlers.py +0 -0
  225. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/constants.py +0 -0
  226. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/custom_model.py +0 -0
  227. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/loop_runtime.py +0 -0
  228. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/memory_screen.py +0 -0
  229. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/onboarding_screen.py +0 -0
  230. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/prompt_flows.py +0 -0
  231. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/session_diff.py +0 -0
  232. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/settings_panel.py +0 -0
  233. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/settings_screen.py +0 -0
  234. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/state.py +0 -0
  235. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/status_dashboard.py +0 -0
  236. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/styles.tcss +0 -0
  237. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/sub_agent_screen.py +0 -0
  238. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/terminal_display.py +0 -0
  239. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/transcript.py +0 -0
  240. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/tui/widgets.py +0 -0
  241. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/cli/updater.py +0 -0
  242. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/config.py +0 -0
  243. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/events.py +0 -0
  244. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/git_env.py +0 -0
  245. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/__init__.py +0 -0
  246. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/backends.py +0 -0
  247. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/config.py +0 -0
  248. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/dispatcher.py +0 -0
  249. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/events.py +0 -0
  250. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/matcher.py +0 -0
  251. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/hooks/outcome.py +0 -0
  252. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/exceptions.py +0 -0
  253. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/models.py +0 -0
  254. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/__init__.py +0 -0
  255. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/anthropic.py +0 -0
  256. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/base.py +0 -0
  257. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/chatgpt_oauth.py +0 -0
  258. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/google.py +0 -0
  259. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/models.py +0 -0
  260. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/openai.py +0 -0
  261. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/openai_responses.py +0 -0
  262. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/providers/responses_common.py +0 -0
  263. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/ratelimit.py +0 -0
  264. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/__init__.py +0 -0
  265. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/accessors.py +0 -0
  266. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/__init__.py +0 -0
  267. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/anthropic.py +0 -0
  268. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/dashscope.py +0 -0
  269. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/fireworks.py +0 -0
  270. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/google.py +0 -0
  271. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/kimi_coding.py +0 -0
  272. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/moonshot.py +0 -0
  273. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/ollama_cloud.py +0 -0
  274. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/openai.py +0 -0
  275. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/openai_chatgpt.py +0 -0
  276. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/openrouter.py +0 -0
  277. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/together.py +0 -0
  278. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/xai.py +0 -0
  279. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/catalog/zai.py +0 -0
  280. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/openrouter_catalog.py +0 -0
  281. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/thinking.py +0 -0
  282. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/specs/types.py +0 -0
  283. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/timeouts.py +0 -0
  284. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/llm/tool_execution_ids.py +0 -0
  285. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/local_state.py +0 -0
  286. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/__init__.py +0 -0
  287. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/config.py +0 -0
  288. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/oauth.py +0 -0
  289. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/service.py +0 -0
  290. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/state.py +0 -0
  291. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/tools.py +0 -0
  292. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/mcp/transport.py +0 -0
  293. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/__init__.py +0 -0
  294. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/identity.py +0 -0
  295. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/manifest.py +0 -0
  296. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/markdown.py +0 -0
  297. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/models.py +0 -0
  298. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/protocol.py +0 -0
  299. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/memory/registry.py +0 -0
  300. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/models/__init__.py +0 -0
  301. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/models/sandbox_terminal_state.py +0 -0
  302. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/permissions.py +0 -0
  303. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/runtime.py +0 -0
  304. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/README.md +0 -0
  305. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/__init__.py +0 -0
  306. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/async_filesystem.py +0 -0
  307. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/base.py +0 -0
  308. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/browser.py +0 -0
  309. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/event_loop.py +0 -0
  310. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/filesystem.py +0 -0
  311. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/local.py +0 -0
  312. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/serializer.py +0 -0
  313. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/terminal.py +0 -0
  314. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/sandbox/utils.py +0 -0
  315. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/scratchpad.py +0 -0
  316. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/security/__init__.py +0 -0
  317. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/security/secrets.py +0 -0
  318. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/base.py +0 -0
  319. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/browser.py +0 -0
  320. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/file_system.py +0 -0
  321. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/html.py +0 -0
  322. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/__init__.py +0 -0
  323. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/client.py +0 -0
  324. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/config.py +0 -0
  325. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/detector.py +0 -0
  326. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/diagnostics.py +0 -0
  327. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/edits.py +0 -0
  328. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/manager.py +0 -0
  329. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/registry.py +0 -0
  330. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/lsp/registry.yaml +0 -0
  331. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/snapshots.py +0 -0
  332. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/terminal.py +0 -0
  333. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/terminal_buffer.py +0 -0
  334. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/services/workspace_scan.py +0 -0
  335. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/__init__.py +0 -0
  336. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/control.py +0 -0
  337. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/inmemory.py +0 -0
  338. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/projection.py +0 -0
  339. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/recording.py +0 -0
  340. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/runtime.py +0 -0
  341. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/session/store.py +0 -0
  342. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/testing/__init__.py +0 -0
  343. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/testing/store_conformance.py +0 -0
  344. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/tools/__init__.py +0 -0
  345. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/tools/definitions.py +0 -0
  346. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/tools/registry.py +0 -0
  347. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/utils/__init__.py +0 -0
  348. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/utils/images.py +0 -0
  349. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/__init__.py +0 -0
  350. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/assets/fold.js +0 -0
  351. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/assets/player.css +0 -0
  352. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/assets/player.html +0 -0
  353. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/assets/player.js +0 -0
  354. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/bundle.py +0 -0
  355. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/hosting.py +0 -0
  356. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/redaction.py +0 -0
  357. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/server.py +0 -0
  358. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/singlefile.py +0 -0
  359. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/web/theme_css.py +0 -0
  360. {kolega_code-0.26.2 → kolega_code-0.26.4}/kolega_code/worktrees.py +0 -0
@@ -6,6 +6,40 @@ This project uses GitHub Releases for detailed generated release notes. This fil
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.26.4 - 2026-08-02
10
+
11
+ ### Changed
12
+
13
+ - `deepseek-v4-flash` now connects over DeepSeek's **Responses API**
14
+ (`https://api.deepseek.com`) for its native tool-calling format and graded
15
+ reasoning effort. Every other DeepSeek model (including `deepseek-v4-pro`)
16
+ continues to use the OpenAI-compatible Chat Completions endpoint. This is a
17
+ per-model routing decision; no configuration change is required.
18
+
19
+ ## 0.26.3 - 2026-08-02
20
+
21
+ ### Added
22
+
23
+ - `kolega-code ask --no-memory-tools` disables the persistent project-memory
24
+ tools (read/list/write/edit/delete memory) and their prompt guidance for a
25
+ run — useful for headless or benchmark use where there is no durable memory
26
+ store.
27
+ - `search_codebase` accepts `path` to restrict the search to a subdirectory and
28
+ `max_results` to cap how many files are returned.
29
+
30
+ ### Changed
31
+
32
+ - `eval` now defaults `language` to `py`, so a call that omits the language runs
33
+ Python instead of failing.
34
+ - A tool call made with the wrong arguments now returns a clear message naming
35
+ the expected signature (for example `Usage: eval(code, language='py', …)`) and
36
+ no longer exposes internal class or method names.
37
+ - "Memory off" now has a single, consistent representation: a non-local host,
38
+ the new `--no-memory-tools` flag, and the memory toggle all behave the same
39
+ way, hiding both the memory tools and the memory prompt section.
40
+ - The browser agent's dispatch tool is now hidden when the model configured for
41
+ the browser agent cannot accept images, instead of failing only when invoked.
42
+
9
43
  ## 0.26.2 - 2026-07-31
10
44
 
11
45
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kolega-code
3
- Version: 0.26.2
3
+ Version: 0.26.4
4
4
  Summary: Multi-agent coding in the terminal
5
5
  Project-URL: Homepage, https://kolega-ai.github.io/kolega-code/
6
6
  Project-URL: Documentation, https://kolega-ai.github.io/kolega-code/
@@ -151,4 +151,4 @@ __all__ = [
151
151
  "parse_git_status_output",
152
152
  ]
153
153
 
154
- __version__ = "0.26.2"
154
+ __version__ = "0.26.4"
@@ -51,4 +51,4 @@ __all__ = [
51
51
  "ToolExtension",
52
52
  ]
53
53
 
54
- __version__ = "0.26.2"
54
+ __version__ = "0.26.4"
@@ -170,6 +170,7 @@ class BaseAgent(LogMixin):
170
170
  custom_agent_catalog: Optional[Any] = None,
171
171
  memory_manager: Optional[Any] = None,
172
172
  memory_project_path: Optional[Path] = None,
173
+ memory_enabled: bool = True,
173
174
  ) -> None:
174
175
  """
175
176
  Initialize a new BaseAgent instance.
@@ -308,15 +309,21 @@ class BaseAgent(LogMixin):
308
309
  from kolega_code.memory import MemoryAccessScope
309
310
 
310
311
  self.memory_manager = self.memory_manager.with_scope(MemoryAccessScope.SUBAGENT)
311
- if self.memory_manager is None and not sub_agent and isinstance(self.filesystem, LocalFileSystem):
312
- # Keep non-local/sandbox hosts unchanged unless they inject a manager.
312
+ elif self.memory_manager is None and not sub_agent:
313
313
  from kolega_code.cli.session_store import default_state_dir
314
314
  from kolega_code.memory import ProjectMemoryManager
315
315
 
316
- self.memory_manager = ProjectMemoryManager(
317
- memory_project_path if memory_project_path is not None else self.project_path,
318
- default_state_dir(),
319
- )
316
+ project = memory_project_path if memory_project_path is not None else self.project_path
317
+ # "Memory off" has one representation everywhere: a present-but-disabled
318
+ # manager, never a None. Memory is live only for a local project with the
319
+ # per-run opt-out unset; a non-local/sandbox host (whose storage would be a
320
+ # local state dir, disconnected from the remote project) or an explicit
321
+ # `--no-memory-tools` opt-out gets an inert, storage-inert manager that
322
+ # writes nothing. Dispatched sub-agents inherit whichever it is.
323
+ if memory_enabled and isinstance(self.filesystem, LocalFileSystem):
324
+ self.memory_manager = ProjectMemoryManager(project, default_state_dir())
325
+ else:
326
+ self.memory_manager = ProjectMemoryManager.disabled(project, default_state_dir())
320
327
  self.context.services.memory_manager = self.memory_manager
321
328
  self._owns_memory_manager = True
322
329
 
@@ -1392,6 +1399,7 @@ class BaseAgent(LogMixin):
1392
1399
  client = LLMClient(
1393
1400
  provider=model_config.provider.value,
1394
1401
  api_key=self.config.get_api_key(model_config.provider) or "",
1402
+ model=model_config.model,
1395
1403
  max_retries=model_config.rate_limits.max_retries,
1396
1404
  requests_per_minute=model_config.rate_limits.requests_per_minute,
1397
1405
  tokens_per_minute=model_config.rate_limits.tokens_per_minute,
@@ -19,13 +19,30 @@ class BrowserAgent(BaseAgent):
19
19
 
20
20
  agent_name = "browser-agent"
21
21
 
22
+ @classmethod
23
+ def resolved_model_supports_vision(cls, config: AgentConfig) -> bool:
24
+ """True if the model resolved for the browser-agent role accepts image input.
25
+
26
+ The browser agent may run on its own ``agent_models`` override, so this is
27
+ deliberately keyed on the browser-agent's resolved model — not the main
28
+ coding model, which can differ in either direction.
29
+ """
30
+ model_config = config.model_config_for_agent(cls.agent_name)
31
+ provider = getattr(model_config.provider, "value", model_config.provider)
32
+ try:
33
+ return model_supports_vision(provider, model_config.model)
34
+ except ValueError:
35
+ # Unknown model → can't confirm image support → treat as no vision.
36
+ # This runs on every tool-list build, so it must never raise.
37
+ return False
38
+
22
39
  @classmethod
23
40
  def validate_model_capabilities(cls, config: AgentConfig) -> None:
24
41
  """Require the resolved browser-agent model to accept image input."""
42
+ if cls.resolved_model_supports_vision(config):
43
+ return
25
44
  model_config = config.model_config_for_agent(cls.agent_name)
26
45
  provider = getattr(model_config.provider, "value", model_config.provider)
27
- if model_supports_vision(provider, model_config.model):
28
- return
29
46
  raise ValueError(
30
47
  "BrowserAgent requires a vision-capable model, but "
31
48
  f"{provider}/{model_config.model} does not support image input. "
@@ -53,6 +53,7 @@ class CoderAgent(BaseAgent, LogMixin):
53
53
  custom_agent_catalog: Optional[Any] = None,
54
54
  memory_manager: Optional[Any] = None,
55
55
  memory_project_path: Optional[Path] = None,
56
+ memory_enabled: bool = True,
56
57
  ) -> None:
57
58
  """
58
59
  Initialize a new CoderAgent instance.
@@ -117,6 +118,7 @@ class CoderAgent(BaseAgent, LogMixin):
117
118
  custom_agent_catalog=custom_agent_catalog,
118
119
  memory_manager=memory_manager,
119
120
  memory_project_path=memory_project_path,
121
+ memory_enabled=memory_enabled,
120
122
  )
121
123
 
122
124
  # Configure tool collection with custom coder agent tools
@@ -109,6 +109,7 @@ class AgentContext:
109
109
  return InstrumentedLLMClient(
110
110
  provider=model_config.provider,
111
111
  api_key=self.config.get_api_key(model_config.provider) or "",
112
+ model=model_config.model,
112
113
  max_retries=model_config.rate_limits.max_retries,
113
114
  requests_per_minute=model_config.rate_limits.requests_per_minute,
114
115
  tokens_per_minute=model_config.rate_limits.tokens_per_minute,
@@ -126,6 +127,7 @@ class AgentContext:
126
127
  return LLMClient(
127
128
  provider=model_config.provider,
128
129
  api_key=self.config.get_api_key(model_config.provider) or "",
130
+ model=model_config.model,
129
131
  max_retries=model_config.rate_limits.max_retries,
130
132
  requests_per_minute=model_config.rate_limits.requests_per_minute,
131
133
  tokens_per_minute=model_config.rate_limits.tokens_per_minute,
@@ -47,6 +47,7 @@ class PlanningAgent(BaseAgent):
47
47
  max_iterations: Optional[int] = None,
48
48
  custom_agent_catalog: Optional[Any] = None,
49
49
  memory_manager: Optional[Any] = None,
50
+ memory_enabled: bool = True,
50
51
  ) -> None:
51
52
  if custom_agent_catalog is not None:
52
53
  custom_agent_catalog = custom_agent_catalog.for_mode("plan")
@@ -81,6 +82,7 @@ class PlanningAgent(BaseAgent):
81
82
  max_iterations=max_iterations,
82
83
  custom_agent_catalog=custom_agent_catalog,
83
84
  memory_manager=memory_manager,
85
+ memory_enabled=memory_enabled,
84
86
  )
85
87
 
86
88
  self._completed_plan: Optional[str] = None
@@ -22,6 +22,8 @@ _RC_MARKER = "__KOLEGA_RG_RC"
22
22
 
23
23
  # Display caps (shared by every engine via the single formatter).
24
24
  _MAX_FILES = 128
25
+ # Ceiling for a caller-supplied ``max_results`` so a huge request can't flood context.
26
+ _MAX_FILES_CEILING = 512
25
27
  _MAX_LINES_PER_FILE = 5
26
28
  _MAX_LINE_LENGTH = 200
27
29
  _MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
@@ -46,6 +48,10 @@ class _EngineUnavailable(Exception):
46
48
  flag, non-regex error) so the caller falls back to the next engine tier."""
47
49
 
48
50
 
51
+ class _InvalidSearchPath(Exception):
52
+ """A caller-supplied ``path`` that escapes the project or isn't a directory."""
53
+
54
+
49
55
  class _SearchTimedOut(Exception):
50
56
  """Raised when an otherwise valid search exceeds its execution budget."""
51
57
 
@@ -147,6 +153,31 @@ class SearchCodebaseTool(BaseTool):
147
153
  excluded.update(_BROAD_ROOT_EXCLUDE_DIRS)
148
154
  return excluded
149
155
 
156
+ def _resolve_search_target(self, path: Optional[str]) -> str:
157
+ """Validate a caller-supplied ``path`` and return a project-relative search
158
+ root (``.`` for the whole project). Rejects absolute paths, parent escapes,
159
+ and non-directories so the search can never wander outside the project."""
160
+ if not path or path.strip() in ("", ".", "./"):
161
+ return "."
162
+ candidate = Path(path.strip())
163
+ if candidate.is_absolute() or ".." in candidate.parts:
164
+ raise _InvalidSearchPath(f"path must be a relative directory inside the project, got '{path}'")
165
+ rel = candidate.as_posix().strip("/")
166
+ if not rel:
167
+ return "."
168
+ try:
169
+ exists = self.filesystem.exists(rel)
170
+ is_dir = exists and self.filesystem.is_dir(rel)
171
+ except Exception:
172
+ # If the filesystem can't answer (e.g. an exotic sandbox), let the
173
+ # engine handle the path rather than blocking a legitimate search.
174
+ return rel
175
+ if not exists:
176
+ raise _InvalidSearchPath(f"path '{path}' was not found in the project")
177
+ if not is_dir:
178
+ raise _InvalidSearchPath(f"path '{path}' is not a directory; use file_pattern to filter files")
179
+ return rel
180
+
150
181
  async def search_codebase(
151
182
  self,
152
183
  pattern: str,
@@ -154,6 +185,8 @@ class SearchCodebaseTool(BaseTool):
154
185
  case_sensitive: bool = False,
155
186
  literal: bool = False,
156
187
  *,
188
+ path: Optional[str] = None,
189
+ max_results: int = _MAX_FILES,
157
190
  line_formatter: Optional[Callable[[int, str], str]] = None,
158
191
  ) -> str:
159
192
  """
@@ -170,9 +203,11 @@ class SearchCodebaseTool(BaseTool):
170
203
  file_pattern: Optional glob to filter which files to search (default: all files)
171
204
  case_sensitive: Whether the search is case-sensitive (default: False)
172
205
  literal: Treat the pattern as plain text instead of a regular expression (default: False)
206
+ path: Optional directory (relative to the project root) to restrict the search to; searches the whole project when omitted
207
+ max_results: Maximum number of matching files to return (default 128, capped at 512)
173
208
 
174
209
  Returns:
175
- Markdown formatted list of files and matches, limited to 128 results
210
+ Markdown formatted list of files and matches, capped at ``max_results`` files
176
211
 
177
212
  Raises:
178
213
  Exception: If any error occurs during the search operation
@@ -198,10 +233,16 @@ class SearchCodebaseTool(BaseTool):
198
233
  await self.log_error(error_msg, sender=self.caller.agent_name)
199
234
  return f"Error: {error_msg}"
200
235
 
236
+ limit = max(1, min(int(max_results), _MAX_FILES_CEILING))
237
+ try:
238
+ search_target = self._resolve_search_target(path)
239
+ except _InvalidSearchPath as exc:
240
+ return f"Error: {exc}"
241
+
201
242
  # Run the first available engine; fall back down the tiers on failure.
202
243
  for runner in await self._engine_chain():
203
244
  try:
204
- run = await runner(pattern, file_pattern, case_sensitive, literal, regex)
245
+ run = await runner(pattern, file_pattern, case_sensitive, literal, regex, search_target, limit)
205
246
  except _EngineUnavailable:
206
247
  continue
207
248
  except _SearchTimedOut:
@@ -213,7 +254,7 @@ class SearchCodebaseTool(BaseTool):
213
254
  f"elapsed={run.elapsed_seconds:.2f}s)",
214
255
  sender=self.caller.agent_name,
215
256
  )
216
- return self._format_results(run, pattern, line_formatter=line_formatter)
257
+ return self._format_results(run, pattern, limit=limit, line_formatter=line_formatter)
217
258
 
218
259
  # The Python tier never raises _EngineUnavailable, so this is unreachable.
219
260
  return f"No matches found for pattern '{pattern}'"
@@ -266,7 +307,9 @@ class SearchCodebaseTool(BaseTool):
266
307
  # ripgrep engine
267
308
  # ------------------------------------------------------------------
268
309
 
269
- def _rg_args(self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool) -> List[str]:
310
+ def _rg_args(
311
+ self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, search_target: str = "."
312
+ ) -> List[str]:
270
313
  args = [
271
314
  "--json",
272
315
  "--no-config",
@@ -297,17 +340,25 @@ class SearchCodebaseTool(BaseTool):
297
340
  if file_pattern != "*":
298
341
  glob = file_pattern if "/" not in file_pattern else f"**/{file_pattern}"
299
342
  args += ["-g", glob]
300
- # Pattern as its own argv element (after -e) and an explicit search path so
301
- # ripgrep never reads stdin in a headless context.
302
- args += ["-e", pattern, "."]
343
+ # Pattern as its own argv element (after -e) and an explicit search path
344
+ # (the whole tree, or the caller's ``path`` subtree) so ripgrep never reads
345
+ # stdin in a headless context.
346
+ args += ["-e", pattern, search_target]
303
347
  return args
304
348
 
305
349
  async def _run_rg_local(
306
- self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, regex
350
+ self,
351
+ pattern: str,
352
+ file_pattern: str,
353
+ case_sensitive: bool,
354
+ literal: bool,
355
+ regex,
356
+ search_target: str = ".",
357
+ limit: int = _MAX_FILES,
307
358
  ) -> SearchRun:
308
359
  if shutil.which("rg") is None:
309
360
  raise _EngineUnavailable()
310
- args = self._rg_args(pattern, file_pattern, case_sensitive, literal)
361
+ args = self._rg_args(pattern, file_pattern, case_sensitive, literal, search_target)
311
362
  env = {**os.environ, "RIPGREP_CONFIG_FILE": ""}
312
363
  try:
313
364
  proc = await asyncio.create_subprocess_exec(
@@ -329,9 +380,16 @@ class SearchCodebaseTool(BaseTool):
329
380
  return SearchRun(self._parse_rg_json(stdout.decode("utf-8", "replace")))
330
381
 
331
382
  async def _run_rg_sandbox(
332
- self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, regex
383
+ self,
384
+ pattern: str,
385
+ file_pattern: str,
386
+ case_sensitive: bool,
387
+ literal: bool,
388
+ regex,
389
+ search_target: str = ".",
390
+ limit: int = _MAX_FILES,
333
391
  ) -> SearchRun:
334
- args = self._rg_args(pattern, file_pattern, case_sensitive, literal)
392
+ args = self._rg_args(pattern, file_pattern, case_sensitive, literal, search_target)
335
393
  cmd = "RIPGREP_CONFIG_FILE= rg " + " ".join(shlex.quote(a) for a in args)
336
394
  full_cmd = f"cd {shlex.quote(self._fs_root)} && {cmd} ; echo {_RC_MARKER}=$?"
337
395
  try:
@@ -390,7 +448,9 @@ class SearchCodebaseTool(BaseTool):
390
448
  # grep engine
391
449
  # ------------------------------------------------------------------
392
450
 
393
- def _grep_argv(self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool) -> List[str]:
451
+ def _grep_argv(
452
+ self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, search_target: str = "."
453
+ ) -> List[str]:
394
454
  argv = ["grep", "-r", "-n", "--binary-files=without-match"]
395
455
  if not case_sensitive:
396
456
  argv.append("-i")
@@ -403,16 +463,24 @@ class SearchCodebaseTool(BaseTool):
403
463
  argv.append("--exclude-dir=.*")
404
464
  for ext in sorted(self.BINARY_EXTENSIONS):
405
465
  argv.append(f"--exclude=*{ext}")
406
- # -e guards a pattern that starts with '-'; '.' is the search root.
407
- argv += ["-e", pattern, "."]
466
+ # -e guards a pattern that starts with '-'; search_target is the search
467
+ # root (the whole tree, or the caller's ``path`` subtree).
468
+ argv += ["-e", pattern, search_target]
408
469
  return argv
409
470
 
410
471
  async def _run_grep_local(
411
- self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, regex
472
+ self,
473
+ pattern: str,
474
+ file_pattern: str,
475
+ case_sensitive: bool,
476
+ literal: bool,
477
+ regex,
478
+ search_target: str = ".",
479
+ limit: int = _MAX_FILES,
412
480
  ) -> SearchRun:
413
481
  if shutil.which("grep") is None:
414
482
  raise _EngineUnavailable()
415
- argv = self._grep_argv(pattern, file_pattern, case_sensitive, literal)
483
+ argv = self._grep_argv(pattern, file_pattern, case_sensitive, literal, search_target)
416
484
  try:
417
485
  proc = await asyncio.create_subprocess_exec(
418
486
  *argv,
@@ -431,9 +499,16 @@ class SearchCodebaseTool(BaseTool):
431
499
  return SearchRun(self._drop_oversize_local(records))
432
500
 
433
501
  async def _run_grep_sandbox(
434
- self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, regex
502
+ self,
503
+ pattern: str,
504
+ file_pattern: str,
505
+ case_sensitive: bool,
506
+ literal: bool,
507
+ regex,
508
+ search_target: str = ".",
509
+ limit: int = _MAX_FILES,
435
510
  ) -> SearchRun:
436
- argv = self._grep_argv(pattern, file_pattern, case_sensitive, literal)
511
+ argv = self._grep_argv(pattern, file_pattern, case_sensitive, literal, search_target)
437
512
  cmd = " ".join(shlex.quote(a) for a in argv)
438
513
  full_cmd = f"cd {shlex.quote(self._fs_root)} && {cmd} ; echo {_RC_MARKER}=$?"
439
514
  try:
@@ -524,15 +599,23 @@ class SearchCodebaseTool(BaseTool):
524
599
  # ------------------------------------------------------------------
525
600
 
526
601
  async def _run_python(
527
- self, pattern: str, file_pattern: str, case_sensitive: bool, literal: bool, regex
602
+ self,
603
+ pattern: str,
604
+ file_pattern: str,
605
+ case_sensitive: bool,
606
+ literal: bool,
607
+ regex,
608
+ search_target: str = ".",
609
+ limit: int = _MAX_FILES,
528
610
  ) -> SearchRun:
529
611
  if hasattr(self.filesystem, "sandbox"):
530
- return await self._run_python_sandbox_fallback(file_pattern, regex)
612
+ return await self._run_python_sandbox_fallback(file_pattern, regex, search_target, limit)
531
613
 
532
614
  normalized_pattern = "**/*" if file_pattern == "*" else f"**/{file_pattern}"
533
615
  self._load_gitignore_patterns()
616
+ scan_root = Path(self._fs_root) if search_target == "." else Path(self._fs_root) / search_target
534
617
  scan = await scan_workspace(
535
- Path(self._fs_root),
618
+ scan_root,
536
619
  pattern=normalized_pattern,
537
620
  include_files=True,
538
621
  include_directories=False,
@@ -543,9 +626,9 @@ class SearchCodebaseTool(BaseTool):
543
626
  ignore_spec=getattr(self, "_gitignore_spec", None),
544
627
  limits=ScanLimits(timeout_seconds=_SCAN_TIMEOUT_SECONDS, max_entries=_SCAN_MAX_ENTRIES),
545
628
  )
546
- return await self._search_scanned_files(scan, regex)
629
+ return await self._search_scanned_files(scan, regex, limit)
547
630
 
548
- async def _search_scanned_files(self, scan: ScanOutcome, regex) -> SearchRun:
631
+ async def _search_scanned_files(self, scan: ScanOutcome, regex, limit: int = _MAX_FILES) -> SearchRun:
549
632
  cancel_event = threading.Event()
550
633
  started = time.monotonic()
551
634
  remaining = max(0.01, _SEARCH_TIMEOUT_SECONDS - scan.elapsed_seconds)
@@ -570,7 +653,7 @@ class SearchCodebaseTool(BaseTool):
570
653
  if regex.search(line):
571
654
  records.append((norm, line_num, line))
572
655
  matched_files.add(norm)
573
- if len(matched_files) > _MAX_FILES:
656
+ if len(matched_files) > limit:
574
657
  return SearchRun(
575
658
  records,
576
659
  False,
@@ -598,28 +681,37 @@ class SearchCodebaseTool(BaseTool):
598
681
  task.cancel()
599
682
  return SearchRun([], False, "deadline", scan.visited_entries, _SEARCH_TIMEOUT_SECONDS)
600
683
 
601
- async def _run_python_sandbox_fallback(self, file_pattern: str, regex) -> SearchRun:
684
+ async def _run_python_sandbox_fallback(
685
+ self, file_pattern: str, regex, search_target: str = ".", limit: int = _MAX_FILES
686
+ ) -> SearchRun:
602
687
  """Keep the legacy remote-files fallback off-loop and time bounded."""
603
688
  cancel_event = threading.Event()
604
689
  started = time.monotonic()
690
+ prefix = "" if search_target == "." else search_target.rstrip("/") + "/"
605
691
 
606
692
  def search() -> SearchRun:
607
693
  records: List[Record] = []
694
+ matched_files: set[str] = set()
608
695
  for file_path, file_size in self._get_files_batch_sync(file_pattern):
609
696
  if cancel_event.is_set() or time.monotonic() - started >= _SEARCH_TIMEOUT_SECONDS:
610
697
  return SearchRun(records, False, "deadline", elapsed_seconds=time.monotonic() - started)
611
698
  if file_size > _MAX_FILE_SIZE or self._is_likely_binary_by_extension(file_path):
612
699
  continue
700
+ norm = self._normalize_path(file_path)
701
+ if prefix and not norm.startswith(prefix):
702
+ continue
613
703
  try:
614
704
  content = self.filesystem.read_text(file_path)
615
705
  if "\x00" in content[:1024]:
616
706
  continue
617
707
  except Exception:
618
708
  continue
619
- norm = self._normalize_path(file_path)
620
709
  for line_num, line in enumerate(content.splitlines(), start=1):
621
710
  if regex.search(line):
622
711
  records.append((norm, line_num, line))
712
+ matched_files.add(norm)
713
+ if len(matched_files) > limit:
714
+ return SearchRun(records, False, "result_limit", elapsed_seconds=time.monotonic() - started)
623
715
  return SearchRun(records, elapsed_seconds=time.monotonic() - started)
624
716
 
625
717
  task = asyncio.create_task(asyncio.to_thread(search))
@@ -643,6 +735,7 @@ class SearchCodebaseTool(BaseTool):
643
735
  run: SearchRun,
644
736
  original_pattern: str,
645
737
  *,
738
+ limit: int = _MAX_FILES,
646
739
  line_formatter: Optional[Callable[[int, str], str]] = None,
647
740
  ) -> str:
648
741
  """Group records by file (first-seen order), apply the display caps, and
@@ -652,7 +745,7 @@ class SearchCodebaseTool(BaseTool):
652
745
  for path, line_num, raw in run.records:
653
746
  if path in files:
654
747
  files[path].append((line_num, raw))
655
- elif len(files) < _MAX_FILES:
748
+ elif len(files) < limit:
656
749
  files[path] = [(line_num, raw)]
657
750
  else:
658
751
  limit_hit = True
@@ -690,9 +783,7 @@ class SearchCodebaseTool(BaseTool):
690
783
 
691
784
  output = f"# Search Results for '{original_pattern}'\n\n"
692
785
  if limit_hit or run.stop_reason == "result_limit":
693
- output += (
694
- f"⚠️ **Note:** Showing only the first {_MAX_FILES} results. There are more matches in the codebase.\n\n"
695
- )
786
+ output += f"⚠️ **Note:** Showing only the first {limit} results. There are more matches in the codebase.\n\n"
696
787
  elif not run.complete:
697
788
  output += (
698
789
  f"⚠️ **Incomplete search:** stopped because of {run.stop_reason or 'a search limit'}. "
@@ -76,6 +76,7 @@ class TerminalTool(BaseTool):
76
76
  client = LLMClient(
77
77
  provider=provider.value,
78
78
  api_key=api_key or "",
79
+ model=self.config.fast_config.model,
79
80
  max_retries=rate_limits.max_retries,
80
81
  requests_per_minute=rate_limits.requests_per_minute,
81
82
  tokens_per_minute=rate_limits.tokens_per_minute,
@@ -37,6 +37,7 @@ class ThinkHardTool(StreamingTool):
37
37
  client = InstrumentedLLMClient(
38
38
  provider=provider.value,
39
39
  api_key=api_key or "",
40
+ model=self.config.thinking_config.model,
40
41
  max_retries=rate_limits.max_retries,
41
42
  requests_per_minute=rate_limits.requests_per_minute,
42
43
  tokens_per_minute=rate_limits.tokens_per_minute,
@@ -54,6 +55,7 @@ class ThinkHardTool(StreamingTool):
54
55
  client = LLMClient(
55
56
  provider=provider.value,
56
57
  api_key=api_key or "",
58
+ model=self.config.thinking_config.model,
57
59
  max_retries=rate_limits.max_retries,
58
60
  requests_per_minute=rate_limits.requests_per_minute,
59
61
  tokens_per_minute=rate_limits.tokens_per_minute,
@@ -142,6 +142,7 @@ class WebFetchTool(StreamingTool):
142
142
  client_kwargs = {
143
143
  "provider": provider.value,
144
144
  "api_key": self.config.get_api_key(provider),
145
+ "model": self.config.fast_config.model,
145
146
  "max_retries": rate_limits.max_retries,
146
147
  "requests_per_minute": rate_limits.requests_per_minute,
147
148
  "tokens_per_minute": rate_limits.tokens_per_minute,
@@ -2003,8 +2003,8 @@ class ToolCollection(LogMixin):
2003
2003
 
2004
2004
  async def eval(
2005
2005
  self,
2006
- language: str,
2007
2006
  code: str,
2007
+ language: str = "py",
2008
2008
  title: Optional[str] = None,
2009
2009
  timeout: Optional[float] = None,
2010
2010
  reset: bool = False,
@@ -2034,8 +2034,8 @@ class ToolCollection(LogMixin):
2034
2034
  Top-level await works; declarations inside await-wrapped cells do NOT persist — use setGlobal(name, value) for cross-cell state there. Redeclaring an existing top-level name errors: assign without redeclaring, or pass reset=true.
2035
2035
 
2036
2036
  Args:
2037
- language: "py" for the persistent Python kernel, "js" for the persistent JavaScript kernel (js needs bun or node >= 18 on PATH).
2038
2037
  code: code to run in this eval call, verbatim. Top-level await is fine.
2038
+ language: which kernel to run in; defaults to "py" (the persistent Python kernel). Pass "js" for the persistent JavaScript kernel (needs bun or node >= 18 on PATH).
2039
2039
  title: short label for this step shown in the transcript (e.g. "load csv", "chart by region").
2040
2040
  timeout: timeout for this cell in seconds; 0 disables it. Default 120, max 600.
2041
2041
  reset: wipe this language's kernel before running (fresh state). The other language is untouched.
@@ -2199,7 +2199,13 @@ class ToolCollection(LogMixin):
2199
2199
  return await self.memory_tool.delete_memory(path)
2200
2200
 
2201
2201
  async def search_codebase(
2202
- self, pattern: str, file_pattern: str = "*", case_sensitive: bool = False, literal: bool = False
2202
+ self,
2203
+ pattern: str,
2204
+ file_pattern: str = "*",
2205
+ case_sensitive: bool = False,
2206
+ literal: bool = False,
2207
+ path: Optional[str] = None,
2208
+ max_results: int = 128,
2203
2209
  ) -> str:
2204
2210
  """
2205
2211
  Search the codebase for lines matching a regular expression (grep/ripgrep).
@@ -2210,14 +2216,19 @@ class ToolCollection(LogMixin):
2210
2216
  `^ $`, quantifiers `* + ? {n,m}`, groups `(...)`). Set `literal=True` to match
2211
2217
  the pattern as plain text instead (e.g. to find `arr[0]` or `a||b` verbatim).
2212
2218
 
2219
+ Narrow a search with `path` (search only within a subdirectory) and
2220
+ `max_results` (cap the number of files returned).
2221
+
2213
2222
  Args:
2214
2223
  pattern: The regular expression to search for (use `literal=True` to match it as plain text)
2215
- file_pattern: Optional glob to filter which files to search (default: all files)
2224
+ file_pattern: Glob to filter which files to search by name, e.g. `*.py` (default: all files)
2216
2225
  case_sensitive: Whether the search is case-sensitive (default: False)
2217
2226
  literal: Treat the pattern as plain text instead of a regular expression (default: False)
2227
+ path: Directory (relative to the project root) to search within; searches the whole project when omitted
2228
+ max_results: Maximum number of matching files to return (default 128, capped at 512)
2218
2229
 
2219
2230
  Returns:
2220
- Markdown formatted list of files and matches, limited to 128 results
2231
+ Markdown formatted list of files and matches, capped at `max_results` files
2221
2232
 
2222
2233
  Raises:
2223
2234
  Exception: If any error occurs during the search operation
@@ -2236,6 +2247,8 @@ class ToolCollection(LogMixin):
2236
2247
  "file_pattern": file_pattern,
2237
2248
  "case_sensitive": case_sensitive,
2238
2249
  "literal": literal,
2250
+ "path": path,
2251
+ "max_results": max_results,
2239
2252
  }
2240
2253
  if formatter is not None:
2241
2254
  kwargs["line_formatter"] = formatter
@@ -2680,6 +2693,17 @@ class ToolCollection(LogMixin):
2680
2693
  if method_name == "read_image":
2681
2694
  return bool(getattr(self.caller, "supports_vision", False))
2682
2695
 
2696
+ # Vision gate: dispatching the browser agent only works when the model
2697
+ # resolved for the browser-agent role accepts images (it reads page
2698
+ # screenshots). That model may differ from the main one, so gate on it —
2699
+ # not caller.supports_vision — rather than offer a call that can only
2700
+ # fail at dispatch.
2701
+ if method_name == "dispatch_browser_agent":
2702
+ from kolega_code.agent.browseragent import BrowserAgent
2703
+
2704
+ if not BrowserAgent.resolved_model_supports_vision(self.config):
2705
+ return False
2706
+
2683
2707
  # Settings gate: eval can be disabled host-wide (AgentConfig.eval_enabled).
2684
2708
  # Strict `is False` so Mock configs in tests keep the default (enabled).
2685
2709
  if method_name == "eval" and getattr(self.config, "eval_enabled", True) is False: