kolega-code 0.26.6__tar.gz → 0.26.8__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 (373) hide show
  1. {kolega_code-0.26.6 → kolega_code-0.26.8}/CHANGELOG.md +77 -0
  2. {kolega_code-0.26.6 → kolega_code-0.26.8}/PKG-INFO +2 -1
  3. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/__init__.py +1 -1
  4. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/__init__.py +1 -1
  5. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/baseagent.py +215 -30
  6. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/browseragent.py +2 -0
  7. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/coder.py +2 -0
  8. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/common.py +10 -0
  9. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/compression.py +11 -8
  10. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/context.py +6 -0
  11. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/conversation.py +2 -0
  12. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/custom_agents.py +2 -0
  13. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/kernel.py +3 -2
  14. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/runner.js +11 -4
  15. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/generalagent.py +2 -0
  16. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/investigationagent.py +2 -0
  17. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/planningagent.py +2 -0
  18. kolega_code-0.26.8/kolega_code/agent/prompt_templates/auxiliary/agent_loop/silent_turn_exhausted.user.md +3 -0
  19. kolega_code-0.26.8/kolega_code/agent/prompt_templates/auxiliary/agent_loop/silent_turn_nudge.user.md.j2 +9 -0
  20. kolega_code-0.26.8/kolega_code/agent/prompt_templates/auxiliary/agent_loop/truncated_turn_nudge.user.md.j2 +9 -0
  21. kolega_code-0.26.8/kolega_code/agent/prompt_templates/extensions/cli/mode_switch_notice.md.j2 +23 -0
  22. kolega_code-0.26.8/kolega_code/agent/prompt_templates/system/agents/coder_ask.md.j2 +5 -0
  23. kolega_code-0.26.6/kolega_code/agent/prompt_templates/system/agents/coder_ask.md.j2 → kolega_code-0.26.8/kolega_code/agent/prompt_templates/system/agents/coder_base.md.j2 +75 -11
  24. kolega_code-0.26.8/kolega_code/agent/prompt_templates/system/agents/coder_cli.md.j2 +3 -0
  25. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompts.py +39 -1
  26. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/agent_tool.py +2 -0
  27. kolega_code-0.26.8/kolega_code/agent/tool_backend/network_status.py +90 -0
  28. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/__init__.py +2 -0
  29. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/duckduckgo.py +9 -2
  30. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/errors.py +8 -0
  31. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/firecrawl.py +3 -0
  32. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/searxng.py +6 -0
  33. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/tavily.py +6 -1
  34. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/terminal_tool.py +31 -18
  35. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/think_hard_tool.py +14 -10
  36. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch/pipeline.py +4 -1
  37. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch/retrieval.py +30 -1
  38. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch_tool.py +11 -3
  39. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_search_tool.py +11 -2
  40. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tools.py +36 -11
  41. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/app.py +107 -3
  42. kolega_code-0.26.8/kolega_code/cli/ask_output.py +92 -0
  43. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/main.py +70 -38
  44. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/messages.py +1 -0
  45. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/model_connection.py +26 -14
  46. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/session_store.py +13 -2
  47. kolega_code-0.26.8/kolega_code/cli/session_usage.py +289 -0
  48. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/agent_runtime.py +90 -63
  49. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/app_base.py +10 -1
  50. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/loop_runtime.py +9 -16
  51. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/memory_screen.py +25 -9
  52. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/onboarding_screen.py +1 -1
  53. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/session_diff.py +39 -6
  54. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/settings_panel.py +1 -1
  55. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/status_dashboard.py +42 -0
  56. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/styles.tcss +8 -0
  57. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/transcript.py +4 -4
  58. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/widgets.py +5 -1
  59. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/client.py +38 -2
  60. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/instrumented_client.py +13 -31
  61. kolega_code-0.26.8/kolega_code/llm/ledger.py +411 -0
  62. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/models.py +69 -21
  63. kolega_code-0.26.8/kolega_code/llm/providers/_token_encoding.py +44 -0
  64. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/anthropic.py +10 -6
  65. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/deepseek_responses.py +26 -1
  66. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/google.py +15 -4
  67. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/openai.py +61 -41
  68. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/responses_common.py +41 -9
  69. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/__init__.py +6 -0
  70. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/accessors.py +48 -0
  71. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/deepseek.py +17 -3
  72. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/fireworks.py +7 -2
  73. kolega_code-0.26.8/kolega_code/llm/usage.py +357 -0
  74. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/terminal.py +4 -3
  75. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/base.py +7 -5
  76. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/terminal.py +77 -14
  77. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/tools/core.py +24 -1
  78. kolega_code-0.26.8/kolega_code/tools/param_aliases.py +128 -0
  79. {kolega_code-0.26.6 → kolega_code-0.26.8}/pyproject.toml +5 -1
  80. kolega_code-0.26.6/kolega_code/agent/prompt_templates/system/agents/coder_cli.md.j2 +0 -133
  81. {kolega_code-0.26.6 → kolega_code-0.26.8}/.gitignore +0 -0
  82. {kolega_code-0.26.6 → kolega_code-0.26.8}/CONTRIBUTING.md +0 -0
  83. {kolega_code-0.26.6 → kolega_code-0.26.8}/LICENSE +0 -0
  84. {kolega_code-0.26.6 → kolega_code-0.26.8}/MIGRATION.md +0 -0
  85. {kolega_code-0.26.6 → kolega_code-0.26.8}/README.md +0 -0
  86. {kolega_code-0.26.6 → kolega_code-0.26.8}/RELEASING.md +0 -0
  87. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/LICENSE +0 -0
  88. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/manifest.json +0 -0
  89. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/deep-research/SKILL.md +0 -0
  90. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/deep-research/references/evidence-and-reporting.md +0 -0
  91. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/deep-research/references/gigacode-workflow.md +0 -0
  92. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/deep-research/scripts/deep-research.workflow +0 -0
  93. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/deep-research/scripts/materialize_report.py +0 -0
  94. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/LICENSE +0 -0
  95. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/SKILL.md +0 -0
  96. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/references/examples.md +0 -0
  97. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/references/limitations.md +0 -0
  98. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/references/operations.md +0 -0
  99. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/references/quality.md +0 -0
  100. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/requirements.txt +0 -0
  101. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/scripts/docx_tool.py +0 -0
  102. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/docx/scripts/smoke_test.py +0 -0
  103. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/humanizer/LICENSE +0 -0
  104. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/humanizer/SKILL.md +0 -0
  105. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/LICENSE +0 -0
  106. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/SKILL.md +0 -0
  107. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/references/examples.md +0 -0
  108. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/references/limitations.md +0 -0
  109. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/references/ocr.md +0 -0
  110. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/references/operations.md +0 -0
  111. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/references/quality.md +0 -0
  112. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/references/redaction.md +0 -0
  113. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/requirements-ocr-paddle.txt +0 -0
  114. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/requirements-ocr-surya.txt +0 -0
  115. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/requirements.txt +0 -0
  116. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/scripts/pdf_tool.py +0 -0
  117. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pdf/scripts/smoke_test.py +0 -0
  118. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/LICENSE +0 -0
  119. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/SKILL.md +0 -0
  120. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/references/examples.md +0 -0
  121. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/references/limitations.md +0 -0
  122. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/references/operations.md +0 -0
  123. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/requirements.txt +0 -0
  124. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/scripts/pptx_tool.py +0 -0
  125. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/pptx/scripts/smoke_test.py +0 -0
  126. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/review/SKILL.md +0 -0
  127. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/review/references/github-publishing.md +0 -0
  128. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/skill-authoring/SKILL.md +0 -0
  129. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/skill-authoring/references/review-checklist.md +0 -0
  130. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/LICENSE +0 -0
  131. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/SKILL.md +0 -0
  132. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/references/examples.md +0 -0
  133. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/references/limitations.md +0 -0
  134. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/references/operations.md +0 -0
  135. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/references/quality.md +0 -0
  136. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/requirements.txt +0 -0
  137. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/scripts/smoke_test.py +0 -0
  138. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/_bundled_skills/skills/xlsx/scripts/xlsx_tool.py +0 -0
  139. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/edit_protocols.py +0 -0
  140. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/errors.py +0 -0
  141. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/__init__.py +0 -0
  142. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/bridge.py +0 -0
  143. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/bundle-requirements.in +0 -0
  144. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/bundle-requirements.txt +0 -0
  145. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/env.py +0 -0
  146. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/js_kernel.py +0 -0
  147. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/prelude.js +0 -0
  148. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/prelude.py +0 -0
  149. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/protocol.py +0 -0
  150. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/py_kernel.py +0 -0
  151. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/eval/runner.py +0 -0
  152. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/goal.py +0 -0
  153. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/model_routing.py +0 -0
  154. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/__init__.py +0 -0
  155. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/accounting.py +0 -0
  156. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/budget.py +0 -0
  157. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/context.py +0 -0
  158. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/errors.py +0 -0
  159. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/executor.py +0 -0
  160. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/guide.py +0 -0
  161. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/journal.py +0 -0
  162. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/runtime.py +0 -0
  163. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/orchestration/types.py +0 -0
  164. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_dump.py +0 -0
  165. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_overrides.py +0 -0
  166. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_provider.py +0 -0
  167. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/auxiliary/compression/summary.system.md +0 -0
  168. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/auxiliary/compression/summary.user.md.j2 +0 -0
  169. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/auxiliary/terminal/output_summary.system.md +0 -0
  170. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/auxiliary/terminal/safety.system.md +0 -0
  171. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/auxiliary/tools/think_hard.system.md +0 -0
  172. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/build_questions.md +0 -0
  173. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/current_plan_artifact.md.j2 +0 -0
  174. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/planning_questions.md +0 -0
  175. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/scratchpad.md.j2 +0 -0
  176. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/shared_task_list.md +0 -0
  177. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/shared_task_list_readonly.md +0 -0
  178. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/cli/worktree_control.md.j2 +0 -0
  179. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/extensions/skills/catalog.md.j2 +0 -0
  180. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/agents/browser.md.j2 +0 -0
  181. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/agents/general.md.j2 +0 -0
  182. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/agents/investigation.md.j2 +0 -0
  183. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/agents/planning.md.j2 +0 -0
  184. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/agents_md_instructions.md +0 -0
  185. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/context_updates.md +0 -0
  186. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/environment_variables/workspace_env_vars.md +0 -0
  187. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/frontend_guidance.md +0 -0
  188. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/starter_templates/expo.md +0 -0
  189. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/starter_templates/html_website.md +0 -0
  190. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/starter_templates/mern_stack.md +0 -0
  191. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/system/includes/starter_templates/react_vite_shadcdn.md +0 -0
  192. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/user_tasks/cli/implement_plan.md.j2 +0 -0
  193. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/prompt_templates/user_tasks/cli/init_agents.md.j2 +0 -0
  194. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/base_tool.py +0 -0
  195. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/browser_tool.py +0 -0
  196. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/build_tool.py +0 -0
  197. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/codex_patch.py +0 -0
  198. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/edit_preview.py +0 -0
  199. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/edit_tool.py +0 -0
  200. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/eval_tool.py +0 -0
  201. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/glob_tool.py +0 -0
  202. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/hashline_v2.py +0 -0
  203. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/list_directory_tool.py +0 -0
  204. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/lsp_tool.py +0 -0
  205. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/memory_tool.py +0 -0
  206. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/read_file_tool.py +0 -0
  207. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/read_image_tool.py +0 -0
  208. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/base.py +0 -0
  209. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_backends/models.py +0 -0
  210. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/search_codebase_tool.py +0 -0
  211. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/snapshot_tool.py +0 -0
  212. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/streaming_tool.py +0 -0
  213. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch/__init__.py +0 -0
  214. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch/answering.py +0 -0
  215. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch/documents.py +0 -0
  216. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/web_fetch/extractors.py +0 -0
  217. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/tool_backend/workflow_tool.py +0 -0
  218. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/utils/commands.py +0 -0
  219. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/agent/volatile_context.py +0 -0
  220. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/auth/__init__.py +0 -0
  221. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/auth/_jwt.py +0 -0
  222. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/auth/chatgpt_oauth.py +0 -0
  223. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/auth/constants.py +0 -0
  224. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/auth/tokens.py +0 -0
  225. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/__init__.py +0 -0
  226. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/framing.py +0 -0
  227. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/installer.py +0 -0
  228. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/manager.py +0 -0
  229. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/multiplex.py +0 -0
  230. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/native_host.py +0 -0
  231. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/protocol.py +0 -0
  232. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/registry.py +0 -0
  233. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/browser_extension/runtime.py +0 -0
  234. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/__init__.py +0 -0
  235. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/browser_backend.py +0 -0
  236. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/clipboard_image.py +0 -0
  237. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/config.py +0 -0
  238. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/connection.py +0 -0
  239. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/cron.py +0 -0
  240. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/diagnostics.py +0 -0
  241. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/file_index.py +0 -0
  242. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/goal.py +0 -0
  243. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/loop.py +0 -0
  244. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/mentions.py +0 -0
  245. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/model_catalog.py +0 -0
  246. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/plan_artifacts.py +0 -0
  247. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/provider_registry.py +0 -0
  248. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/session_event_store.py +0 -0
  249. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/session_journal.py +0 -0
  250. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/settings.py +0 -0
  251. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/skills.py +0 -0
  252. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/slash_commands.py +0 -0
  253. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/theme.py +0 -0
  254. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/__init__.py +0 -0
  255. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/changes_screen.py +0 -0
  256. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/command_handlers.py +0 -0
  257. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/constants.py +0 -0
  258. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/custom_model.py +0 -0
  259. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/prompt_flows.py +0 -0
  260. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/settings_screen.py +0 -0
  261. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/state.py +0 -0
  262. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/sub_agent_screen.py +0 -0
  263. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/tui/terminal_display.py +0 -0
  264. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/cli/updater.py +0 -0
  265. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/config.py +0 -0
  266. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/events.py +0 -0
  267. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/git_env.py +0 -0
  268. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/__init__.py +0 -0
  269. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/backends.py +0 -0
  270. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/config.py +0 -0
  271. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/dispatcher.py +0 -0
  272. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/events.py +0 -0
  273. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/matcher.py +0 -0
  274. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/hooks/outcome.py +0 -0
  275. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/exceptions.py +0 -0
  276. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/__init__.py +0 -0
  277. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/base.py +0 -0
  278. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/chatgpt_oauth.py +0 -0
  279. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/models.py +0 -0
  280. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/providers/openai_responses.py +0 -0
  281. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/ratelimit.py +0 -0
  282. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/__init__.py +0 -0
  283. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/anthropic.py +0 -0
  284. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/dashscope.py +0 -0
  285. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/google.py +0 -0
  286. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/kimi_coding.py +0 -0
  287. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/moonshot.py +0 -0
  288. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/ollama_cloud.py +0 -0
  289. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/openai.py +0 -0
  290. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/openai_chatgpt.py +0 -0
  291. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/openrouter.py +0 -0
  292. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/together.py +0 -0
  293. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/xai.py +0 -0
  294. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/catalog/zai.py +0 -0
  295. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/openrouter_catalog.py +0 -0
  296. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/thinking.py +0 -0
  297. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/specs/types.py +0 -0
  298. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/timeouts.py +0 -0
  299. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/llm/tool_execution_ids.py +0 -0
  300. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/local_state.py +0 -0
  301. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/__init__.py +0 -0
  302. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/config.py +0 -0
  303. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/oauth.py +0 -0
  304. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/service.py +0 -0
  305. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/state.py +0 -0
  306. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/tools.py +0 -0
  307. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/mcp/transport.py +0 -0
  308. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/__init__.py +0 -0
  309. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/identity.py +0 -0
  310. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/manager.py +0 -0
  311. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/manifest.py +0 -0
  312. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/markdown.py +0 -0
  313. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/models.py +0 -0
  314. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/protocol.py +0 -0
  315. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/memory/registry.py +0 -0
  316. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/models/__init__.py +0 -0
  317. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/models/sandbox_terminal_state.py +0 -0
  318. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/permissions.py +0 -0
  319. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/runtime.py +0 -0
  320. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/README.md +0 -0
  321. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/__init__.py +0 -0
  322. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/async_filesystem.py +0 -0
  323. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/base.py +0 -0
  324. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/browser.py +0 -0
  325. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/event_loop.py +0 -0
  326. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/filesystem.py +0 -0
  327. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/local.py +0 -0
  328. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/serializer.py +0 -0
  329. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/sandbox/utils.py +0 -0
  330. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/scratchpad.py +0 -0
  331. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/security/__init__.py +0 -0
  332. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/security/secrets.py +0 -0
  333. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/browser.py +0 -0
  334. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/file_system.py +0 -0
  335. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/html.py +0 -0
  336. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/__init__.py +0 -0
  337. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/client.py +0 -0
  338. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/config.py +0 -0
  339. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/detector.py +0 -0
  340. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/diagnostics.py +0 -0
  341. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/edits.py +0 -0
  342. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/manager.py +0 -0
  343. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/registry.py +0 -0
  344. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/lsp/registry.yaml +0 -0
  345. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/snapshots.py +0 -0
  346. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/terminal_buffer.py +0 -0
  347. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/services/workspace_scan.py +0 -0
  348. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/__init__.py +0 -0
  349. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/control.py +0 -0
  350. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/inmemory.py +0 -0
  351. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/projection.py +0 -0
  352. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/recording.py +0 -0
  353. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/runtime.py +0 -0
  354. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/session/store.py +0 -0
  355. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/testing/__init__.py +0 -0
  356. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/testing/store_conformance.py +0 -0
  357. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/tools/__init__.py +0 -0
  358. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/tools/definitions.py +0 -0
  359. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/tools/registry.py +0 -0
  360. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/utils/__init__.py +0 -0
  361. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/utils/images.py +0 -0
  362. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/__init__.py +0 -0
  363. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/assets/fold.js +0 -0
  364. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/assets/player.css +0 -0
  365. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/assets/player.html +0 -0
  366. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/assets/player.js +0 -0
  367. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/bundle.py +0 -0
  368. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/hosting.py +0 -0
  369. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/redaction.py +0 -0
  370. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/server.py +0 -0
  371. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/singlefile.py +0 -0
  372. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/web/theme_css.py +0 -0
  373. {kolega_code-0.26.6 → kolega_code-0.26.8}/kolega_code/worktrees.py +0 -0
@@ -6,6 +6,83 @@ This project uses GitHub Releases for detailed generated release notes. This fil
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.26.8 - 2026-08-03
10
+
11
+ ### Added
12
+
13
+ - Completed model messages now carry normalized token usage across supported
14
+ providers. Session usage is persisted across resume, exported with provider
15
+ and model breakdowns, and shown in a dedicated Usage card on the Status tab.
16
+ - `kolega-code ask --json` now emits complete, replay-safe messages instead of
17
+ streaming prose chunks, including normalized usage and an explicit final
18
+ summary.
19
+ - Detached background terminal sessions now keep stdin open, so callers can
20
+ send multiple inputs to long-running processes with `write_stdin`.
21
+
22
+ ### Changed
23
+
24
+ - Build and ask agents now share stronger act-first and independent-verification
25
+ guidance. Silent reasoning-only turns are retried with escalating prompts,
26
+ and visible responses cut off at the output limit are asked to continue.
27
+ - Tool dispatch accepts common parameter aliases for `exec_command`, `eval`,
28
+ and `find_files_by_pattern`, while canonical arguments still take precedence.
29
+ - Turn status now appears immediately while checkpoints are prepared, and
30
+ session-diff baseline/checkpoint work is asynchronous and caches unchanged
31
+ files for faster turns.
32
+ - Switching between Plan and Build with existing history now gives the model a
33
+ hidden toolset-change notice so it does not attempt tools from the old mode.
34
+ - Web connection failures now distinguish unreachable hosts, TLS failures,
35
+ rate limits, and retryable errors, with guidance that reflects whether
36
+ outbound access is available.
37
+
38
+ ### Fixed
39
+
40
+ - Installing on an Intel Mac no longer fails with a `cryptography` source-build
41
+ error (`Failed to build cryptography==50.0.0` / missing OpenSSL). cryptography
42
+ 49+ stopped publishing Intel-mac wheels, so the installer tried to compile it
43
+ with Rust and OpenSSL; Intel Macs now install the last release that ships a
44
+ prebuilt universal2 wheel. Other platforms are unaffected.
45
+ - DeepSeek requests now always carry an explicit output-token cap (64000, on
46
+ every provider that serves DeepSeek models: first-party, Fireworks, Ollama
47
+ Cloud, OpenRouter). DeepSeek's real per-response ceiling is ~64k — far below
48
+ its published 384000 — and a server-enforced cutoff is reported as a clean
49
+ finish, so long reasoning runs were being truncated silently mid-word. An
50
+ explicit client cap is enforced and reported honestly, so truncation now
51
+ surfaces as a real `max_tokens` stop the agent loop can react to.
52
+ - The Responses API stream wrapper now captures the terminal
53
+ `response.incomplete` event, so a response truncated at `max_output_tokens`
54
+ reports stop reason `max_tokens` (and keeps its usage/billing metadata)
55
+ instead of looking like a clean `end_turn` with no usage.
56
+ - A reply cut off at the output-token limit mid-message is no longer delivered
57
+ as-is: the agent asks the model to continue (up to 3 escalating continuation
58
+ prompts, mirroring the silent-turn guard), and only finalizes with the
59
+ partial output if the reply is still truncated after that.
60
+ - The non-streaming chat `generate()` path now maps `finish_reason` (it lives
61
+ on the choice, not the message), so its responses carry a real stop reason
62
+ instead of `None`.
63
+ - Quitting while a question or approval is pending no longer raises a Textual
64
+ teardown traceback.
65
+ - JavaScript eval kernels no longer wait for orphaned cell timers during
66
+ shutdown.
67
+
68
+ ### Removed
69
+
70
+ - The `KOLEGA_CODE_OPENROUTER_MAX_TOKENS` environment variable. OpenRouter
71
+ requests still send no `max_tokens` by default (it acts as a routing filter
72
+ on the gateway), except DeepSeek models, which now always send the honest
73
+ clamped cap.
74
+
75
+ ## 0.26.7 - 2026-08-03
76
+
77
+ ### Fixed
78
+
79
+ - Local token counting no longer crashes on content that contains a tokenizer
80
+ special-token literal (for example `<|endoftext|>` or `<|im_start|>`, common in
81
+ ML/tokenizer files and chat-format prompts); those strings are now counted as
82
+ ordinary text instead of aborting the run.
83
+ - The Private Project Memory screen no longer crashes with an internal
84
+ "NoMatches" error when it is closed while still loading.
85
+
9
86
  ## 0.26.6 - 2026-08-03
10
87
 
11
88
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kolega-code
3
- Version: 0.26.6
3
+ Version: 0.26.8
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/
@@ -230,6 +230,7 @@ Classifier: Topic :: Utilities
230
230
  Requires-Python: >=3.11
231
231
  Requires-Dist: anthropic==0.101.0
232
232
  Requires-Dist: beautifulsoup4==4.14.3
233
+ Requires-Dist: cryptography==48.0.1; sys_platform == 'darwin' and platform_machine == 'x86_64'
233
234
  Requires-Dist: ddgs==9.14.4
234
235
  Requires-Dist: fastapi==0.139.2
235
236
  Requires-Dist: filelock==3.20.3
@@ -151,4 +151,4 @@ __all__ = [
151
151
  "parse_git_status_output",
152
152
  ]
153
153
 
154
- __version__ = "0.26.6"
154
+ __version__ = "0.26.8"
@@ -51,4 +51,4 @@ __all__ = [
51
51
  "ToolExtension",
52
52
  ]
53
53
 
54
- __version__ = "0.26.6"
54
+ __version__ = "0.26.8"
@@ -42,9 +42,15 @@ from kolega_code.llm.exceptions import (
42
42
  map_to_llm_error,
43
43
  )
44
44
  from kolega_code.llm.instrumented_client import get_output_tokens
45
+ from kolega_code.llm.ledger import HISTORY_ORIGIN, LlmCallOrigin, helper_origin, llm_call_origin
45
46
  from kolega_code.llm.models import ImageBlock, Message, MessageHistory, TextBlock, ToolCall, ToolResult
46
47
  from kolega_code.llm.providers.models import TokenCount
47
- from kolega_code.llm.specs import get_model_specs, supports_vision as model_supports_vision
48
+ from kolega_code.llm.specs import (
49
+ deepseek_output_token_cap,
50
+ get_model_specs,
51
+ is_deepseek_model,
52
+ supports_vision as model_supports_vision,
53
+ )
48
54
  from kolega_code.permissions import (
49
55
  PermissionDecision,
50
56
  PermissionMode,
@@ -133,6 +139,25 @@ class BaseAgent(LogMixin):
133
139
  # Cap on how many times a Stop hook may force the agent to keep working in one
134
140
  # turn, so a misbehaving "don't stop until X" hook cannot loop forever.
135
141
  MAX_STOP_HOOK_OVERRIDES = 5
142
+ # Cap on consecutive re-prompts after a "silent turn": the model ended its
143
+ # turn with no tool call and no visible text (empty or reasoning-only).
144
+ # Finalizing such a turn reports nothing — in non-interactive modes that
145
+ # reads as success with empty output — so the loop nudges the model to act
146
+ # instead, and after the cap terminates the turn and surfaces the failure.
147
+ # Runtime half of the coder_base.md.j2 invariant ("Thinking is invisible
148
+ # and changes nothing on its own").
149
+ MAX_SILENT_TURN_NUDGES = 3
150
+ # Cap on consecutive continuation prompts after a truncated turn: the model
151
+ # hit the output-token limit mid-reply (honest "max_tokens" stop, visible
152
+ # text, no tool call). Unlike a silent turn there IS partial content, so
153
+ # exhausting the cap finalizes the turn with what was produced instead of
154
+ # reporting no result.
155
+ MAX_TRUNCATED_TURN_NUDGES = 3
156
+ # A DeepSeek response whose output lands within this many tokens of the wire
157
+ # output cap without an honest "max_tokens" stop was likely truncated
158
+ # server-side: DeepSeek reports its own cutoff as a clean finish (probed
159
+ # 2026-08-03; see DEEPSEEK_WIRE_OUTPUT_CAP in llm/specs/accessors.py).
160
+ DEEPSEEK_OUTPUT_CAP_SLACK = 1024
136
161
  long_content_tool_calls = ["write"]
137
162
  max_tool_result_chars_in_history = 100_000
138
163
  skill_content_pattern = re.compile(r'<skill_content name="[^"]+">')
@@ -163,6 +188,7 @@ class BaseAgent(LogMixin):
163
188
  permission_callback: Optional[Any] = None,
164
189
  usage_recorder: Optional[Any] = None,
165
190
  sub_agent_recorder: Optional[Any] = None,
191
+ usage_ledger: Optional[Any] = None,
166
192
  session_recorder: Optional[Any] = None,
167
193
  hook_dispatcher: Optional[HookDispatcher] = None,
168
194
  context: Optional[AgentContext] = None,
@@ -241,6 +267,7 @@ class BaseAgent(LogMixin):
241
267
  user_email=user_email,
242
268
  usage_recorder=usage_recorder,
243
269
  sub_agent_recorder=sub_agent_recorder,
270
+ usage_ledger=usage_ledger,
244
271
  ),
245
272
  agent_mode=agent_mode,
246
273
  prompt_provider=prompt_provider,
@@ -301,6 +328,7 @@ class BaseAgent(LogMixin):
301
328
  self.hook_dispatcher = context.hook_dispatcher or NO_OP_DISPATCHER
302
329
  self.usage_recorder = context.telemetry.usage_recorder
303
330
  self.sub_agent_recorder = context.telemetry.sub_agent_recorder
331
+ self.usage_ledger = context.telemetry.usage_ledger
304
332
  self.session_recorder = None if sub_agent else session_recorder
305
333
  self.custom_agent_catalog = custom_agent_catalog
306
334
  self.memory_manager = context.services.memory_manager
@@ -416,6 +444,18 @@ class BaseAgent(LogMixin):
416
444
  self.model_context_length = model_specs["context_length"]
417
445
  self.model_completion_tokens = model_specs["max_completion_tokens"]
418
446
  self.model_default_temperature = model_specs.get("default_temperature", 1.0)
447
+ # The clamped cap DeepSeek requests carry on the wire (None for other
448
+ # models). Used to flag probable silent server-side truncation — see the
449
+ # at-ceiling warning in process_message_stream.
450
+ self.deepseek_wire_output_cap = (
451
+ deepseek_output_token_cap(
452
+ self.primary_model_config.provider,
453
+ self.primary_model_config.model,
454
+ self.model_completion_tokens,
455
+ )
456
+ if is_deepseek_model(self.primary_model_config.model)
457
+ else None
458
+ )
419
459
  # Whether this agent's primary model can accept image input. Read by the
420
460
  # ToolCollection read_image tool gate (so non-vision models never see the
421
461
  # tool) and used by _unsupported_attachment_message to reject image
@@ -492,6 +532,15 @@ class BaseAgent(LogMixin):
492
532
  """
493
533
  self.conversation.append_assistant(message)
494
534
 
535
+ async def _record_context_user_message(self, text: str) -> None:
536
+ """Journal and append a runtime-injected user message (not typed by the user)."""
537
+ if self.session_recorder is not None:
538
+ await asyncio.to_thread(
539
+ self.session_recorder.record_context_message,
540
+ Message(role="user", content=[TextBlock(text=text)]),
541
+ )
542
+ self.append_user_message([TextBlock(text=text)])
543
+
495
544
  def extend_history(self, messages: List[Message]) -> None:
496
545
  """
497
546
  Safely extend history with multiple messages, validating the sequence.
@@ -1051,11 +1100,14 @@ class BaseAgent(LogMixin):
1051
1100
  try:
1052
1101
  registry = self.tool_collection.registry()
1053
1102
  if tool_name not in registry:
1054
- error_message = f"Tool '{tool_name}' is not available in this mode."
1055
- await self.log_error(error_message, sender=self.agent_name)
1103
+ short_message = f"Tool '{tool_name}' is not available in this mode."
1104
+ # The model gets the available-tool list so it can self-correct;
1105
+ # the transcript row keeps the short form.
1106
+ error_message = f"{short_message} Available tools: {', '.join(sorted(registry.names()))}."
1107
+ await self.log_error(short_message, sender=self.agent_name)
1056
1108
  await self.send_chat_message(
1057
1109
  message_type="tool_error",
1058
- content=error_message,
1110
+ content=short_message,
1059
1111
  is_streaming=False,
1060
1112
  tool_description=tool_name,
1061
1113
  tool_call_id=tool_execution_id,
@@ -1379,6 +1431,27 @@ class BaseAgent(LogMixin):
1379
1431
  async def _log_hook_message(self, message: str) -> None:
1380
1432
  await self.log_warning(message, sender=self.agent_name)
1381
1433
 
1434
+ def _main_loop_origin(self) -> LlmCallOrigin:
1435
+ """Attribution for this agent's main-loop LLM calls.
1436
+
1437
+ HISTORY marks exactly the responses the session recorder journals as
1438
+ ``assistant.message`` (the same ``session_recorder is not None``
1439
+ condition guards ``record_assistant``), so the persistence sink skips
1440
+ them and no response is ever journaled twice.
1441
+ """
1442
+ if self.session_recorder is not None:
1443
+ return HISTORY_ORIGIN
1444
+ if self.sub_agent:
1445
+ context = getattr(self, "sub_agent_context", None) or {}
1446
+ return LlmCallOrigin(
1447
+ kind="sub_agent",
1448
+ agent_name=self.agent_name,
1449
+ agent_id=context.get("agent_id"),
1450
+ parent_tool_call_id=context.get("parent_tool_call_id") or getattr(self, "parent_tool_call_id", None),
1451
+ depth=context.get("depth"),
1452
+ )
1453
+ return LlmCallOrigin(kind="primary", agent_name=self.agent_name)
1454
+
1382
1455
  async def _run_hook_prompt(self, prompt_text: str, model_hint: Optional[str]) -> str:
1383
1456
  """Run a `prompt` hook: a single completion on a chosen model slot.
1384
1457
 
@@ -1404,14 +1477,16 @@ class BaseAgent(LogMixin):
1404
1477
  requests_per_minute=model_config.rate_limits.requests_per_minute,
1405
1478
  tokens_per_minute=model_config.rate_limits.tokens_per_minute,
1406
1479
  token_manager=self.config.get_chatgpt_token_manager(),
1480
+ usage_ledger=self.usage_ledger,
1407
1481
  )
1408
- response = await client.generate(
1409
- model=model_config.model,
1410
- max_completion_tokens=512,
1411
- system=Message(role="system", content=[TextBlock(text=HOOK_DECISION_SYSTEM_PROMPT)]),
1412
- messages=MessageHistory([Message(role="user", content=[TextBlock(text=prompt_text)])]),
1413
- temperature=0.0,
1414
- )
1482
+ with llm_call_origin(helper_origin("hook_prompt")):
1483
+ response = await client.generate(
1484
+ model=model_config.model,
1485
+ max_completion_tokens=512,
1486
+ system=Message(role="system", content=[TextBlock(text=HOOK_DECISION_SYSTEM_PROMPT)]),
1487
+ messages=MessageHistory([Message(role="user", content=[TextBlock(text=prompt_text)])]),
1488
+ temperature=0.0,
1489
+ )
1415
1490
  return response.get_text_content() or ""
1416
1491
 
1417
1492
  async def _run_hook_agent(self, task: str) -> str:
@@ -1712,6 +1787,17 @@ class BaseAgent(LogMixin):
1712
1787
  """Return the agent's final report: the text of the last message in history."""
1713
1788
  return self.history[-1].get_text_content()
1714
1789
 
1790
+ @staticmethod
1791
+ def _is_silent_turn(message: Message) -> bool:
1792
+ """True when an assistant message has no tool calls and no visible text.
1793
+
1794
+ ThinkingBlock carries ``.thinking`` rather than ``.text``, so a
1795
+ reasoning-only message reads as empty here. Evaluate the streamed
1796
+ message, not history: Conversation.append_assistant replaces empty
1797
+ content with a placeholder TextBlock.
1798
+ """
1799
+ return not message.tool_calls and not message.get_text_content().strip()
1800
+
1715
1801
  async def _deliver_queued_user_inputs(self) -> None:
1716
1802
  """Append user inputs drained from the host while the current turn is running."""
1717
1803
  if self.queued_input_provider is None:
@@ -1911,6 +1997,8 @@ class BaseAgent(LogMixin):
1911
1997
 
1912
1998
  stop_reason = None
1913
1999
  stop_overrides = 0
2000
+ silent_turn_nudges = 0
2001
+ truncated_turn_nudges = 0
1914
2002
  iterations = 0
1915
2003
  while stop_reason not in ["end_turn", "max_tokens", "stop_sequence"]:
1916
2004
  iterations += 1
@@ -1994,18 +2082,19 @@ class BaseAgent(LogMixin):
1994
2082
  # provider is ``async def``, so the call is always a coroutine that we
1995
2083
  # await into the context manager. Cast to the coroutine form for the type
1996
2084
  # checker rather than awaiting the union directly.
1997
- stream_cm = await cast(
1998
- Coroutine[Any, Any, AbstractAsyncContextManager[Any]],
1999
- self.llm.stream(
2000
- system=self.system_prompt,
2001
- max_completion_tokens=self.model_completion_tokens,
2002
- temperature=self.model_default_temperature,
2003
- messages=fixed_history,
2004
- model=self.primary_model_config.model,
2005
- tools=self.tool_collection.get_tool_list(),
2006
- thinking=self.primary_model_config.thinking_effort,
2007
- ),
2008
- )
2085
+ with llm_call_origin(self._main_loop_origin()):
2086
+ stream_cm = await cast(
2087
+ Coroutine[Any, Any, AbstractAsyncContextManager[Any]],
2088
+ self.llm.stream(
2089
+ system=self.system_prompt,
2090
+ max_completion_tokens=self.model_completion_tokens,
2091
+ temperature=self.model_default_temperature,
2092
+ messages=fixed_history,
2093
+ model=self.primary_model_config.model,
2094
+ tools=self.tool_collection.get_tool_list(),
2095
+ thinking=self.primary_model_config.thinking_effort,
2096
+ ),
2097
+ )
2009
2098
  async with stream_cm as stream:
2010
2099
  async for event in stream:
2011
2100
  if event.type == "text":
@@ -2049,10 +2138,11 @@ class BaseAgent(LogMixin):
2049
2138
  assistant_message = await stream.get_final_message()
2050
2139
  self._normalize_freeform_tool_calls(assistant_message)
2051
2140
  assistant_message.usage_metadata["edit_protocol"] = self.edit_protocol.value
2052
- self.total_tokens_used += get_output_tokens(
2141
+ response_output_tokens = get_output_tokens(
2053
2142
  assistant_message.usage_metadata,
2054
2143
  self.primary_model_config.provider.value,
2055
2144
  )
2145
+ self.total_tokens_used += response_output_tokens
2056
2146
  if self._accounting_reservation is not None:
2057
2147
  self._accounting_reservation.report_total(self.total_tokens_used)
2058
2148
  stop_reason = assistant_message.stop_reason
@@ -2063,6 +2153,23 @@ class BaseAgent(LogMixin):
2063
2153
  elapsed_s=round(time.monotonic() - _req_start, 2),
2064
2154
  stop_reason=stop_reason,
2065
2155
  )
2156
+ # DeepSeek reports a SERVER-side output cutoff as a clean finish;
2157
+ # the clamped wire cap should always fire first as an honest
2158
+ # "max_tokens" stop. A response landing at/near the cap without
2159
+ # one was likely truncated silently — surface it in the
2160
+ # trajectory (log_message event) since the stop reason cannot be
2161
+ # recovered.
2162
+ if (
2163
+ self.deepseek_wire_output_cap is not None
2164
+ and stop_reason != "max_tokens"
2165
+ and response_output_tokens >= self.deepseek_wire_output_cap - self.DEEPSEEK_OUTPUT_CAP_SLACK
2166
+ ):
2167
+ await self.log_warning(
2168
+ f"DeepSeek response used {response_output_tokens} output tokens — at or near "
2169
+ f"the {self.deepseek_wire_output_cap}-token output cap — but reported "
2170
+ f"stop_reason={stop_reason!r}; the output was likely truncated server-side.",
2171
+ sender=self.agent_name,
2172
+ )
2066
2173
 
2067
2174
  if self.session_recorder is not None:
2068
2175
  await asyncio.to_thread(self.session_recorder.record_assistant, assistant_message)
@@ -2070,6 +2177,15 @@ class BaseAgent(LogMixin):
2070
2177
  # A clean stream resets the transient-failure budget, so the cap measures
2071
2178
  # only consecutive failures, not lifetime failures across the turn.
2072
2179
  self._consecutive_llm_retries = 0
2180
+ # Likewise, a response with a tool call or visible text resets the
2181
+ # silent-turn budget: the cap measures only consecutive silence.
2182
+ if not self._is_silent_turn(assistant_message):
2183
+ silent_turn_nudges = 0
2184
+ # And any response that was not cut off at the output limit
2185
+ # resets the truncation budget: the cap measures only
2186
+ # consecutive truncations.
2187
+ if stop_reason != "max_tokens":
2188
+ truncated_turn_nudges = 0
2073
2189
 
2074
2190
  if thinking_started or current_thinking:
2075
2191
  yield {"type": "thinking", "content": current_thinking, "complete": True, "uuid": thinking_uuid}
@@ -2123,18 +2239,87 @@ class BaseAgent(LogMixin):
2123
2239
  # host UI so the next model request sees them.
2124
2240
  await self._deliver_queued_user_inputs()
2125
2241
 
2242
+ # Silent-turn guard: the model ended this iteration with no tool
2243
+ # call and no visible text (reasoning-only or empty). Finalizing
2244
+ # would report nothing, so re-prompt with an escalating reminder;
2245
+ # after the cap, terminate the turn and surface the failure. Runs
2246
+ # before the Stop hook: a nudged iteration is not a turn end, and
2247
+ # clearing stop_reason makes the stop-hook block skip itself.
2248
+ if stop_reason in ["end_turn", "max_tokens", "stop_sequence"] and self._is_silent_turn(
2249
+ assistant_message
2250
+ ):
2251
+ from .prompts import SILENT_TURN_EXHAUSTED_NOTICE, build_silent_turn_nudge
2252
+
2253
+ if silent_turn_nudges < self.MAX_SILENT_TURN_NUDGES:
2254
+ silent_turn_nudges += 1
2255
+ await self.emitter.llm_status(
2256
+ "info",
2257
+ "Model returned no output — asking it to act "
2258
+ f"({silent_turn_nudges}/{self.MAX_SILENT_TURN_NUDGES})…",
2259
+ )
2260
+ await self._record_context_user_message(build_silent_turn_nudge(silent_turn_nudges))
2261
+ stop_reason = None
2262
+ else:
2263
+ await self.log_warning(
2264
+ f"Model ended {self.MAX_SILENT_TURN_NUDGES + 1} consecutive responses with "
2265
+ "no tool call and no visible output; terminating the turn.",
2266
+ sender=self.agent_name,
2267
+ )
2268
+ await self.emitter.llm_status(
2269
+ "warning",
2270
+ "Model returned no output after repeated reminders — ending the turn with no result.",
2271
+ )
2272
+ await self._record_context_user_message(SILENT_TURN_EXHAUSTED_NOTICE)
2273
+ yield {
2274
+ "type": "response",
2275
+ "content": (
2276
+ "[no output] The model ended its turn with no tool call and no visible "
2277
+ f"message {self.MAX_SILENT_TURN_NUDGES + 1} times in a row despite "
2278
+ "reminders. The turn was terminated without a result."
2279
+ ),
2280
+ "complete": True,
2281
+ "uuid": str(uuid.uuid4()),
2282
+ }
2283
+ break
2284
+
2285
+ # Truncated-turn guard: an honest "max_tokens" stop with visible
2286
+ # text and no tool call means the reply was cut off mid-message
2287
+ # (the silent-turn guard above owns the no-visible-output case
2288
+ # and cleared stop_reason if it fired). Finalizing would deliver
2289
+ # a partial answer, so ask the model to continue; after the cap,
2290
+ # finalize with the partial output — unlike a silent turn there
2291
+ # IS content worth delivering.
2292
+ if stop_reason == "max_tokens" and not assistant_message.tool_calls:
2293
+ from .prompts import build_truncated_turn_nudge
2294
+
2295
+ if truncated_turn_nudges < self.MAX_TRUNCATED_TURN_NUDGES:
2296
+ truncated_turn_nudges += 1
2297
+ await self.emitter.llm_status(
2298
+ "info",
2299
+ "Response hit the output limit — asking the model to continue "
2300
+ f"({truncated_turn_nudges}/{self.MAX_TRUNCATED_TURN_NUDGES})…",
2301
+ )
2302
+ await self._record_context_user_message(build_truncated_turn_nudge(truncated_turn_nudges))
2303
+ stop_reason = None
2304
+ else:
2305
+ await self.log_warning(
2306
+ f"Model hit the output-token limit {self.MAX_TRUNCATED_TURN_NUDGES + 1} times "
2307
+ "in a row; finalizing the turn with the partial output.",
2308
+ sender=self.agent_name,
2309
+ )
2310
+ await self.emitter.llm_status(
2311
+ "warning",
2312
+ "Response still truncated after repeated continuation prompts — "
2313
+ "delivering the partial output.",
2314
+ )
2315
+
2126
2316
  # Stop hooks (main agent only). On a natural turn end, a hook may
2127
2317
  # keep the agent working by blocking the stop and returning a reason.
2128
2318
  if stop_reason in ["end_turn", "max_tokens", "stop_sequence"] and not self.sub_agent:
2129
2319
  keep_working = await self._fire_stop_hook(stop_reason)
2130
2320
  if keep_working is not None and stop_overrides < self.MAX_STOP_HOOK_OVERRIDES:
2131
2321
  stop_overrides += 1
2132
- if self.session_recorder is not None:
2133
- await asyncio.to_thread(
2134
- self.session_recorder.record_context_message,
2135
- Message(role="user", content=[TextBlock(text=keep_working)]),
2136
- )
2137
- self.append_user_message([TextBlock(text=keep_working)])
2322
+ await self._record_context_user_message(keep_working)
2138
2323
  stop_reason = None
2139
2324
 
2140
2325
  except Exception as ex:
@@ -74,6 +74,7 @@ class BrowserAgent(BaseAgent):
74
74
  permission_mode: Optional[Any] = None,
75
75
  permission_callback: Optional[Any] = None,
76
76
  usage_recorder: Optional[Any] = None,
77
+ usage_ledger: Optional[Any] = None,
77
78
  sub_agent_recorder: Optional[Any] = None,
78
79
  hook_dispatcher: Optional[Any] = None,
79
80
  max_iterations: Optional[int] = None,
@@ -130,6 +131,7 @@ class BrowserAgent(BaseAgent):
130
131
  permission_mode=permission_mode,
131
132
  permission_callback=permission_callback,
132
133
  usage_recorder=usage_recorder,
134
+ usage_ledger=usage_ledger,
133
135
  sub_agent_recorder=sub_agent_recorder,
134
136
  hook_dispatcher=hook_dispatcher,
135
137
  max_iterations=max_iterations,
@@ -46,6 +46,7 @@ class CoderAgent(BaseAgent, LogMixin):
46
46
  permission_mode: Optional[Any] = None,
47
47
  permission_callback: Optional[Any] = None,
48
48
  usage_recorder: Optional[Any] = None,
49
+ usage_ledger: Optional[Any] = None,
49
50
  sub_agent_recorder: Optional[Any] = None,
50
51
  session_recorder: Optional[Any] = None,
51
52
  hook_dispatcher: Optional[Any] = None,
@@ -111,6 +112,7 @@ class CoderAgent(BaseAgent, LogMixin):
111
112
  permission_mode=permission_mode,
112
113
  permission_callback=permission_callback,
113
114
  usage_recorder=usage_recorder,
115
+ usage_ledger=usage_ledger,
114
116
  sub_agent_recorder=sub_agent_recorder,
115
117
  session_recorder=session_recorder,
116
118
  hook_dispatcher=hook_dispatcher,
@@ -49,3 +49,13 @@ class LogMixin:
49
49
  """
50
50
  log_event = AgentEvent(event_type="log_message", sender=sender, content={"text": message, "level": "warning"})
51
51
  await self.connection_manager.broadcast_event(log_event, self.workspace_id, self.thread_id)
52
+
53
+ async def log_debug(self, message: str, sender: str = "agent") -> None:
54
+ """
55
+ Log a debug-level message to the logs panel.
56
+
57
+ Args:
58
+ message: The debug message to log
59
+ """
60
+ log_event = AgentEvent(event_type="log_message", sender=sender, content={"text": message, "level": "debug"})
61
+ await self.connection_manager.broadcast_event(log_event, self.workspace_id, self.thread_id)
@@ -5,6 +5,7 @@ from dataclasses import dataclass
5
5
  from typing import Awaitable, Callable, Optional
6
6
 
7
7
  from .conversation import Conversation
8
+ from kolega_code.llm.ledger import helper_origin, llm_call_origin
8
9
  from kolega_code.llm.models import Message, MessageHistory, TextBlock
9
10
  from .prompts import (
10
11
  build_compression_summary_user_prompt,
@@ -109,14 +110,16 @@ class HistoryCompressor:
109
110
  # Stream and drain rather than calling generate(): the Anthropic SDK
110
111
  # rejects non-streaming requests whose max_tokens is large enough to risk
111
112
  # a >10-minute response, which the model's full completion budget triggers.
112
- async with await llm.stream(
113
- messages=messages,
114
- system=system_message,
115
- temperature=temperature,
116
- model=model,
117
- max_completion_tokens=self.SUMMARY_MAX_TOKENS,
118
- thinking=thinking,
119
- ) as stream:
113
+ with llm_call_origin(helper_origin("compression")):
114
+ stream_cm = await llm.stream(
115
+ messages=messages,
116
+ system=system_message,
117
+ temperature=temperature,
118
+ model=model,
119
+ max_completion_tokens=self.SUMMARY_MAX_TOKENS,
120
+ thinking=thinking,
121
+ )
122
+ async with stream_cm as stream:
120
123
  async for _event in stream:
121
124
  pass
122
125
  response = await stream.get_final_message()
@@ -75,6 +75,10 @@ class Telemetry:
75
75
  user_email: Optional[str] = None
76
76
  usage_recorder: Optional[Any] = None
77
77
  sub_agent_recorder: Optional[Any] = None
78
+ # Process-wide runtime usage accounting (kolega_code/llm/ledger.py). Unlike
79
+ # the recorders above it does not require Langfuse: it reaches the plain
80
+ # LLMClient too.
81
+ usage_ledger: Optional[Any] = None
78
82
 
79
83
 
80
84
  @dataclass
@@ -122,6 +126,7 @@ class AgentContext:
122
126
  user_email=self.telemetry.user_email,
123
127
  usage_recorder=self.telemetry.usage_recorder,
124
128
  token_manager=self.config.get_chatgpt_token_manager(),
129
+ usage_ledger=self.telemetry.usage_ledger,
125
130
  )
126
131
 
127
132
  return LLMClient(
@@ -132,4 +137,5 @@ class AgentContext:
132
137
  requests_per_minute=model_config.rate_limits.requests_per_minute,
133
138
  tokens_per_minute=model_config.rate_limits.tokens_per_minute,
134
139
  token_manager=self.config.get_chatgpt_token_manager(),
140
+ usage_ledger=self.telemetry.usage_ledger,
135
141
  )
@@ -163,6 +163,7 @@ def _message_with_content(message: Message, content: List[Any]) -> Message:
163
163
  stop_reason=message.stop_reason,
164
164
  tool_calls=tool_calls,
165
165
  usage_metadata=message.usage_metadata,
166
+ usage=message.usage,
166
167
  )
167
168
 
168
169
 
@@ -699,6 +700,7 @@ class Conversation:
699
700
  stop_reason=message.stop_reason,
700
701
  tool_calls=message.tool_calls,
701
702
  usage_metadata=message.usage_metadata,
703
+ usage=message.usage,
702
704
  )
703
705
 
704
706
  self.history.append(message)
@@ -384,6 +384,7 @@ class CustomAgent(BaseAgent):
384
384
  permission_mode: Optional[Any] = None,
385
385
  permission_callback: Optional[Any] = None,
386
386
  usage_recorder: Optional[Any] = None,
387
+ usage_ledger: Optional[Any] = None,
387
388
  sub_agent_recorder: Optional[Any] = None,
388
389
  hook_dispatcher: Optional[Any] = None,
389
390
  max_iterations: Optional[int] = None,
@@ -419,6 +420,7 @@ class CustomAgent(BaseAgent):
419
420
  permission_mode=permission_mode,
420
421
  permission_callback=permission_callback,
421
422
  usage_recorder=usage_recorder,
423
+ usage_ledger=usage_ledger,
422
424
  sub_agent_recorder=sub_agent_recorder,
423
425
  hook_dispatcher=hook_dispatcher,
424
426
  max_iterations=definition.max_iterations if definition.max_iterations is not None else max_iterations,
@@ -184,8 +184,9 @@ class BaseKernel:
184
184
  try:
185
185
  if proc.stdin is not None:
186
186
  proc.stdin.write(encode_frame({"type": "exit"}))
187
- await proc.stdin.wait_closed()
188
- except (BrokenPipeError, ConnectionError, RuntimeError):
187
+ proc.stdin.close()
188
+ await asyncio.wait_for(proc.stdin.wait_closed(), timeout=timeout)
189
+ except (BrokenPipeError, ConnectionError, RuntimeError, asyncio.TimeoutError):
189
190
  pass
190
191
  try:
191
192
  await asyncio.wait_for(proc.wait(), timeout=timeout)