limbo-code 0.2__tar.gz → 0.2.1__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 (201) hide show
  1. {limbo_code-0.2 → limbo_code-0.2.1}/PKG-INFO +1 -1
  2. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/catalog.py +17 -2
  3. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_catalog.py +30 -1
  4. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/grill-with-docs/SKILL.md +0 -0
  5. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/grill-with-docs/agents/openai.yaml +0 -0
  6. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +0 -0
  7. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/improve-codebase-architecture/SKILL.md +0 -0
  8. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/improve-codebase-architecture/agents/openai.yaml +0 -0
  9. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/tdd/SKILL.md +0 -0
  10. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/tdd/agents/openai.yaml +0 -0
  11. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/tdd/mocking.md +0 -0
  12. {limbo_code-0.2 → limbo_code-0.2.1}/.agents/skills/tdd/tests.md +0 -0
  13. {limbo_code-0.2 → limbo_code-0.2.1}/.github/workflows/publish.yml +0 -0
  14. {limbo_code-0.2 → limbo_code-0.2.1}/.github/workflows/test.yml +0 -0
  15. {limbo_code-0.2 → limbo_code-0.2.1}/.gitignore +0 -0
  16. {limbo_code-0.2 → limbo_code-0.2.1}/AGENTS.md +0 -0
  17. {limbo_code-0.2 → limbo_code-0.2.1}/CONTEXT.md +0 -0
  18. {limbo_code-0.2 → limbo_code-0.2.1}/Makefile +0 -0
  19. {limbo_code-0.2 → limbo_code-0.2.1}/README.md +0 -0
  20. {limbo_code-0.2 → limbo_code-0.2.1}/design/bang-verification.md +0 -0
  21. {limbo_code-0.2 → limbo_code-0.2.1}/design/confirm_view.html +0 -0
  22. {limbo_code-0.2 → limbo_code-0.2.1}/design/limbo-ui-minimal.md +0 -0
  23. {limbo_code-0.2 → limbo_code-0.2.1}/design/limbo-ui-redesign.md +0 -0
  24. {limbo_code-0.2 → limbo_code-0.2.1}/design/prototype-minimal-confirm.png +0 -0
  25. {limbo_code-0.2 → limbo_code-0.2.1}/design/prototype-minimal.html +0 -0
  26. {limbo_code-0.2 → limbo_code-0.2.1}/design/prototype-minimal.png +0 -0
  27. {limbo_code-0.2 → limbo_code-0.2.1}/design/prototype.html +0 -0
  28. {limbo_code-0.2 → limbo_code-0.2.1}/design/prototype.png +0 -0
  29. {limbo_code-0.2 → limbo_code-0.2.1}/design/rfc-bang-command.md +0 -0
  30. {limbo_code-0.2 → limbo_code-0.2.1}/design/rfc-headless-cli.md +0 -0
  31. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/limbo-current-ui.png +0 -0
  32. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/limbo-new-ui.png +0 -0
  33. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-dark/1_idle.svg +0 -0
  34. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-dark/2_thinking_tool_running.svg +0 -0
  35. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-dark/3_tool_success.svg +0 -0
  36. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-dark/4_tool_error.svg +0 -0
  37. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-dark/5_llm_error.svg +0 -0
  38. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-dark/6_edit_diff.svg +0 -0
  39. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-light/1_idle.svg +0 -0
  40. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-light/2_thinking_tool_running.svg +0 -0
  41. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-light/3_tool_success.svg +0 -0
  42. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-light/4_tool_error.svg +0 -0
  43. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-light/5_llm_error.svg +0 -0
  44. {limbo_code-0.2 → limbo_code-0.2.1}/docs/assets/walkthrough/limbo-light/6_edit_diff.svg +0 -0
  45. {limbo_code-0.2 → limbo_code-0.2.1}/docs/session-management.md +0 -0
  46. {limbo_code-0.2 → limbo_code-0.2.1}/docs/skills.md +0 -0
  47. {limbo_code-0.2 → limbo_code-0.2.1}/docs/ui-redesign-proposal.md +0 -0
  48. {limbo_code-0.2 → limbo_code-0.2.1}/pyproject.toml +0 -0
  49. {limbo_code-0.2 → limbo_code-0.2.1}/scripts/check_contrast.py +0 -0
  50. {limbo_code-0.2 → limbo_code-0.2.1}/scripts/gen_banner.py +0 -0
  51. {limbo_code-0.2 → limbo_code-0.2.1}/scripts/scroll_bench.py +0 -0
  52. {limbo_code-0.2 → limbo_code-0.2.1}/scripts/ui_walkthrough.py +0 -0
  53. {limbo_code-0.2 → limbo_code-0.2.1}/skills-lock.json +0 -0
  54. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/__init__.py +0 -0
  55. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/__main__.py +0 -0
  56. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/agent.py +0 -0
  57. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/app.py +0 -0
  58. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/attachments.py +0 -0
  59. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/btw.py +0 -0
  60. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/code_mode.py +0 -0
  61. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/compaction.py +0 -0
  62. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/config.py +0 -0
  63. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/goal.py +0 -0
  64. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/headless.py +0 -0
  65. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/history.py +0 -0
  66. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/integrations/__init__.py +0 -0
  67. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/integrations/base.py +0 -0
  68. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/integrations/herdr.py +0 -0
  69. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/__init__.py +0 -0
  70. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/anthropic_client.py +0 -0
  71. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/client.py +0 -0
  72. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/factory.py +0 -0
  73. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/openai_client.py +0 -0
  74. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/responses_client.py +0 -0
  75. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/retry.py +0 -0
  76. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/scaffold.py +0 -0
  77. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/sse.py +0 -0
  78. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/llm/usage.py +0 -0
  79. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/model_switch.py +0 -0
  80. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/models.py +0 -0
  81. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/prompt.py +0 -0
  82. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/pump.py +0 -0
  83. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/sessions.py +0 -0
  84. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/skills.py +0 -0
  85. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/steer.py +0 -0
  86. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/__init__.py +0 -0
  87. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/base.py +0 -0
  88. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/bash.py +0 -0
  89. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/edit.py +0 -0
  90. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/find.py +0 -0
  91. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/grep.py +0 -0
  92. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/ignore.py +0 -0
  93. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/ls.py +0 -0
  94. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/mutation_queue.py +0 -0
  95. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/read.py +0 -0
  96. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/registry.py +0 -0
  97. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/run_code.py +0 -0
  98. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/tools/write.py +0 -0
  99. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/trace.py +0 -0
  100. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/__init__.py +0 -0
  101. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/app.py +0 -0
  102. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/app.tcss +0 -0
  103. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/banner.py +0 -0
  104. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/clipboard.py +0 -0
  105. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/commands.py +0 -0
  106. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/contrast.py +0 -0
  107. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/key_fixes.py +0 -0
  108. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/paste_store.py +0 -0
  109. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/path_input.py +0 -0
  110. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/__init__.py +0 -0
  111. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/btw.py +0 -0
  112. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/game2048.py +0 -0
  113. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/main.py +0 -0
  114. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/model_picker.py +0 -0
  115. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/session_picker.py +0 -0
  116. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/screens/verify_picker.py +0 -0
  117. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/syntax.py +0 -0
  118. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/theme.py +0 -0
  119. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/widgets/__init__.py +0 -0
  120. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/widgets/chat.py +0 -0
  121. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/widgets/command_menu.py +0 -0
  122. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/widgets/input.py +0 -0
  123. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/widgets/status_bar.py +0 -0
  124. {limbo_code-0.2 → limbo_code-0.2.1}/src/limbo/ui/widgets/tool_card.py +0 -0
  125. {limbo_code-0.2 → limbo_code-0.2.1}/tests/conftest.py +0 -0
  126. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_agent.py +0 -0
  127. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_anthropic_client.py +0 -0
  128. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_attachments.py +0 -0
  129. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_btw.py +0 -0
  130. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_cli.py +0 -0
  131. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_clipboard.py +0 -0
  132. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_code_mode.py +0 -0
  133. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_code_mode_agent.py +0 -0
  134. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_compaction.py +0 -0
  135. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_config.py +0 -0
  136. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_goal.py +0 -0
  137. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_headless.py +0 -0
  138. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_herdr.py +0 -0
  139. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_history.py +0 -0
  140. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_integration.py +0 -0
  141. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_integrations.py +0 -0
  142. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_interrupt.py +0 -0
  143. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_llm_client.py +0 -0
  144. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_llm_scaffold.py +0 -0
  145. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_model_switch.py +0 -0
  146. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_models.py +0 -0
  147. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_prompt.py +0 -0
  148. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_pump.py +0 -0
  149. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_responses_client.py +0 -0
  150. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_retry.py +0 -0
  151. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_sessions.py +0 -0
  152. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_skills.py +0 -0
  153. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_sse.py +0 -0
  154. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_steer.py +0 -0
  155. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_trace.py +0 -0
  156. {limbo_code-0.2 → limbo_code-0.2.1}/tests/test_usage.py +0 -0
  157. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_base.py +0 -0
  158. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_bash.py +0 -0
  159. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_edit.py +0 -0
  160. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_find.py +0 -0
  161. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_grep.py +0 -0
  162. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_ignore.py +0 -0
  163. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_ls.py +0 -0
  164. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_mutation_queue.py +0 -0
  165. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_read.py +0 -0
  166. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_registry.py +0 -0
  167. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_run_code.py +0 -0
  168. {limbo_code-0.2 → limbo_code-0.2.1}/tests/tools/test_write.py +0 -0
  169. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/__snapshots__/test_snapshots/test_snapshot_idle.raw +0 -0
  170. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/__snapshots__/test_snapshots/test_snapshot_session_picker.raw +0 -0
  171. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/__snapshots__/test_snapshots/test_snapshot_thinking_and_running_tool.raw +0 -0
  172. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/__snapshots__/test_snapshots/test_snapshot_tool_error_and_error_message.raw +0 -0
  173. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_app_smoke.py +0 -0
  174. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_bang_ui.py +0 -0
  175. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_btw_ui.py +0 -0
  176. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_code_mode_ui.py +0 -0
  177. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_command_menu.py +0 -0
  178. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_commands.py +0 -0
  179. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_compact_ui.py +0 -0
  180. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_contrast.py +0 -0
  181. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_copy.py +0 -0
  182. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_game2048.py +0 -0
  183. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_goal_ui.py +0 -0
  184. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_input_attachments.py +0 -0
  185. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_input_history.py +0 -0
  186. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_input_paste.py +0 -0
  187. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_interrupt_ui.py +0 -0
  188. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_key_fixes.py +0 -0
  189. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_main_screen.py +0 -0
  190. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_model_picker.py +0 -0
  191. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_paste_store.py +0 -0
  192. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_path_input.py +0 -0
  193. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_scroll_follow.py +0 -0
  194. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_sessions_ui.py +0 -0
  195. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_skills_ui.py +0 -0
  196. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_snapshots.py +0 -0
  197. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_startup_art.py +0 -0
  198. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_steer_ui.py +0 -0
  199. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_theme.py +0 -0
  200. {limbo_code-0.2 → limbo_code-0.2.1}/tests/ui/test_widgets.py +0 -0
  201. {limbo_code-0.2 → limbo_code-0.2.1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: limbo-code
3
- Version: 0.2
3
+ Version: 0.2.1
4
4
  Summary: A minimal terminal AI coding agent
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: httpx>=0.27
@@ -175,16 +175,19 @@ def _kimi_coding(
175
175
  *,
176
176
  context_window: int = 262_144,
177
177
  max_tokens: int = 32_768,
178
+ vision: bool = True,
178
179
  ) -> ModelSpec:
179
180
  # All Kimi For Coding models reason with Anthropic adaptive thinking
180
181
  # (thinking: {type: adaptive} + output_config.effort); thinking cannot
181
182
  # be disabled. Replayed thinking blocks may carry an empty signature.
183
+ # Every Kimi model is multimodal (accepts image input).
182
184
  return ModelSpec(
183
185
  id=model_id,
184
186
  provider=KIMI_CODING,
185
187
  context_window=context_window,
186
188
  max_tokens=max_tokens,
187
189
  reasoning=True,
190
+ vision=vision,
188
191
  thinking_format="anthropic-adaptive",
189
192
  thinking_levels={"low": "low", "high": "high", "max": "max"},
190
193
  thinking_can_disable=False,
@@ -197,7 +200,9 @@ def _moonshot(
197
200
  context_window: int = 262_144,
198
201
  max_tokens: int = 262_144,
199
202
  reasoning: bool = False,
200
- vision: bool = False,
203
+ # Every Kimi (Moonshot) model is multimodal: image input is supported
204
+ # across the family, so the helper defaults to vision-capable.
205
+ vision: bool = True,
201
206
  thinking_format: str | None = None,
202
207
  thinking_levels: dict[str, str] | None = None,
203
208
  thinking_can_disable: bool = True,
@@ -264,6 +269,16 @@ CATALOG: dict[str, ModelSpec] = {
264
269
  reasoning=True,
265
270
  thinking_format="deepseek",
266
271
  ),
272
+ # Vision-enabled experimental flash variant (accepts image input).
273
+ "deepseek-v4-flash-vision-exp": ModelSpec(
274
+ id="deepseek-v4-flash-vision-exp",
275
+ provider=DEEPSEEK,
276
+ context_window=1_000_000,
277
+ max_tokens=65_536,
278
+ reasoning=True,
279
+ vision=True,
280
+ thinking_format="deepseek",
281
+ ),
267
282
  # -- Kimi (Moonshot AI) -------------------------------------------------
268
283
  "kimi-k2-0711-preview": _moonshot(
269
284
  "kimi-k2-0711-preview", context_window=131_072, max_tokens=16_384
@@ -278,7 +293,7 @@ CATALOG: dict[str, ModelSpec] = {
278
293
  ),
279
294
  # Kimi K2.5 is Moonshot's multimodal generation (accepts image input).
280
295
  "kimi-k2.5": _moonshot(
281
- "kimi-k2.5", reasoning=True, thinking_format="deepseek", vision=True
296
+ "kimi-k2.5", reasoning=True, thinking_format="deepseek"
282
297
  ),
283
298
  "kimi-k2.6": _moonshot(
284
299
  "kimi-k2.6", reasoning=True, thinking_format="deepseek"
@@ -5,6 +5,7 @@ import pytest
5
5
  from limbo.config import Config, ProviderOverride
6
6
  from limbo.llm.anthropic_client import AnthropicMessagesClient
7
7
  from limbo.llm.catalog import (
8
+ CATALOG,
8
9
  DEEPSEEK,
9
10
  DEFAULT_BASE_URL,
10
11
  GENERIC_OPENAI,
@@ -298,13 +299,41 @@ def test_register_client_adds_dialect():
298
299
  def test_vision_defaults_to_false():
299
300
  # Text-only catalog entries stay non-vision (conservative default).
300
301
  assert resolve_model("deepseek-v4-flash").vision is False
301
- assert resolve_model("kimi-k3").vision is False
302
+ assert resolve_model("glm-5.2").vision is False
303
+
304
+
305
+ def test_deepseek_flash_vision_exp_is_vision_capable():
306
+ # Experimental flash variant: accepts image input, same spec as
307
+ # deepseek-v4-flash otherwise.
308
+ spec = resolve_model("deepseek-v4-flash-vision-exp")
309
+ assert spec.provider is DEEPSEEK
310
+ assert spec.vision is True
311
+ assert spec.reasoning is True
312
+ assert spec.thinking_format == "deepseek"
313
+
314
+
315
+ def test_all_kimi_models_are_vision_capable():
316
+ # Every Kimi model (Moonshot API + Kimi For Coding) is multimodal.
317
+ kimi_ids = {
318
+ m for m in CATALOG
319
+ if m.startswith("kimi-") or m in {"k3", "kimi-for-coding", "kimi-for-coding-highspeed"}
320
+ }
321
+ assert kimi_ids, "expected at least one Kimi model in the catalog"
322
+ for model_id in kimi_ids:
323
+ assert resolve_model(model_id).vision is True, model_id
302
324
 
303
325
 
304
326
  def test_kimi_k2_5_is_vision_capable():
305
327
  assert resolve_model("kimi-k2.5").vision is True
306
328
 
307
329
 
330
+ def test_kimi_k3_is_vision_capable():
331
+ # k3 (Kimi For Coding) and kimi-k3 (Moonshot) are the same multimodal
332
+ # model: both accept image input and must pass the vision gate.
333
+ assert resolve_model("kimi-k3").vision is True
334
+ assert resolve_model("k3").vision is True
335
+
336
+
308
337
  def test_unknown_model_vision_defaults_to_false():
309
338
  # GENERIC_OPENAI fallback: image attachments degrade to path references
310
339
  # rather than breaking an unrecognized endpoint with base64 payloads.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes