limbo-code 0.2__tar.gz → 0.2.2__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.
- {limbo_code-0.2 → limbo_code-0.2.2}/PKG-INFO +1 -1
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/catalog.py +17 -2
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/app.tcss +2 -1
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/banner.py +24 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/contrast.py +4 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/theme.py +8 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/widgets/chat.py +11 -2
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_catalog.py +30 -1
- limbo_code-0.2.2/tests/ui/__snapshots__/test_snapshots/test_snapshot_thinking_and_running_tool.raw +175 -0
- limbo_code-0.2.2/tests/ui/__snapshots__/test_snapshots/test_snapshot_tool_error_and_error_message.raw +176 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_startup_art.py +4 -1
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_theme.py +2 -0
- limbo_code-0.2/tests/ui/__snapshots__/test_snapshots/test_snapshot_thinking_and_running_tool.raw +0 -174
- limbo_code-0.2/tests/ui/__snapshots__/test_snapshots/test_snapshot_tool_error_and_error_message.raw +0 -175
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/grill-with-docs/SKILL.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/grill-with-docs/agents/openai.yaml +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/improve-codebase-architecture/SKILL.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/improve-codebase-architecture/agents/openai.yaml +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/tdd/SKILL.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/tdd/agents/openai.yaml +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/tdd/mocking.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.agents/skills/tdd/tests.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.github/workflows/publish.yml +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.github/workflows/test.yml +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/.gitignore +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/AGENTS.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/CONTEXT.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/Makefile +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/README.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/bang-verification.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/confirm_view.html +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/limbo-ui-minimal.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/limbo-ui-redesign.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/prototype-minimal-confirm.png +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/prototype-minimal.html +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/prototype-minimal.png +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/prototype.html +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/prototype.png +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/rfc-bang-command.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/design/rfc-headless-cli.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/limbo-current-ui.png +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/limbo-new-ui.png +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-dark/1_idle.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-dark/2_thinking_tool_running.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-dark/3_tool_success.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-dark/4_tool_error.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-dark/5_llm_error.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-dark/6_edit_diff.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-light/1_idle.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-light/2_thinking_tool_running.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-light/3_tool_success.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-light/4_tool_error.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-light/5_llm_error.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/assets/walkthrough/limbo-light/6_edit_diff.svg +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/session-management.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/skills.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/docs/ui-redesign-proposal.md +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/pyproject.toml +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/scripts/check_contrast.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/scripts/gen_banner.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/scripts/scroll_bench.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/scripts/ui_walkthrough.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/skills-lock.json +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/__main__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/agent.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/app.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/attachments.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/btw.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/code_mode.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/compaction.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/config.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/goal.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/headless.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/history.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/integrations/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/integrations/base.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/integrations/herdr.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/anthropic_client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/factory.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/openai_client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/responses_client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/retry.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/scaffold.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/sse.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/llm/usage.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/model_switch.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/models.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/prompt.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/pump.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/sessions.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/skills.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/steer.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/base.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/bash.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/edit.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/find.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/grep.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/ignore.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/ls.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/mutation_queue.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/read.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/registry.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/run_code.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/tools/write.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/trace.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/app.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/clipboard.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/commands.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/key_fixes.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/paste_store.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/path_input.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/btw.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/game2048.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/main.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/model_picker.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/session_picker.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/screens/verify_picker.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/syntax.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/widgets/__init__.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/widgets/command_menu.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/widgets/input.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/widgets/status_bar.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/src/limbo/ui/widgets/tool_card.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/conftest.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_agent.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_anthropic_client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_attachments.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_btw.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_cli.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_clipboard.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_code_mode.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_code_mode_agent.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_compaction.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_config.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_goal.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_headless.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_herdr.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_history.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_integration.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_integrations.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_interrupt.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_llm_client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_llm_scaffold.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_model_switch.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_models.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_prompt.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_pump.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_responses_client.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_retry.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_sessions.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_skills.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_sse.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_steer.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_trace.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/test_usage.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_base.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_bash.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_edit.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_find.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_grep.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_ignore.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_ls.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_mutation_queue.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_read.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_registry.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_run_code.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/tools/test_write.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/__snapshots__/test_snapshots/test_snapshot_idle.raw +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/__snapshots__/test_snapshots/test_snapshot_session_picker.raw +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_app_smoke.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_bang_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_btw_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_code_mode_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_command_menu.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_commands.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_compact_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_contrast.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_copy.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_game2048.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_goal_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_input_attachments.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_input_history.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_input_paste.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_interrupt_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_key_fixes.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_main_screen.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_model_picker.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_paste_store.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_path_input.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_scroll_follow.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_sessions_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_skills_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_snapshots.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_steer_ui.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/tests/ui/test_widgets.py +0 -0
- {limbo_code-0.2 → limbo_code-0.2.2}/uv.lock +0 -0
|
@@ -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
|
-
|
|
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"
|
|
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"
|
|
@@ -115,3 +115,27 @@ def startup_art_text() -> Text:
|
|
|
115
115
|
elif cb is not None:
|
|
116
116
|
text.append(LOWER, style=_rgb(cb))
|
|
117
117
|
return text
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def user_icon() -> Text:
|
|
121
|
+
"""A compact single-row mascot icon for user messages (LIM-16 v1.1).
|
|
122
|
+
|
|
123
|
+
Half-block compression of the mascot: red shirt on top, yellow pants
|
|
124
|
+
below, dark outline on the sides. One terminal row tall so it lines up
|
|
125
|
+
with the message text ("same size as the font") while keeping the
|
|
126
|
+
brand colors. Prepended before the ``❯`` user-message marker.
|
|
127
|
+
|
|
128
|
+
``DRRRD`` / ``DYYYD`` -> 2 px rows condensed into 1 terminal row via
|
|
129
|
+
``▀`` (top pixel as foreground, bottom pixel as background).
|
|
130
|
+
"""
|
|
131
|
+
top = "DRRRD"
|
|
132
|
+
bottom = "DYYYD"
|
|
133
|
+
text = Text()
|
|
134
|
+
for ct_key, cb_key in zip(top, bottom):
|
|
135
|
+
ct = _PALETTE[ct_key]
|
|
136
|
+
cb = _PALETTE[cb_key]
|
|
137
|
+
if ct == cb:
|
|
138
|
+
text.append(FULL, style=_rgb(ct))
|
|
139
|
+
else:
|
|
140
|
+
text.append(UPPER, style=f"{_rgb(ct)} on {_rgb(cb)}")
|
|
141
|
+
return text
|
|
@@ -33,6 +33,7 @@ _FOREGROUNDS = (
|
|
|
33
33
|
"error",
|
|
34
34
|
"diff-added",
|
|
35
35
|
"diff-removed",
|
|
36
|
+
"user-message-fg",
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
# §6.3 规范中实际使用的「文字 on 背景」组合(低于 4.5 即 FAIL)。
|
|
@@ -56,6 +57,8 @@ USED_PAIRS = frozenset(
|
|
|
56
57
|
# F1:edit diff 的真实渲染路径(pygments Inserted/Deleted on diff 底)
|
|
57
58
|
("diff-added", "diff-added-bg"),
|
|
58
59
|
("diff-removed", "diff-removed-bg"),
|
|
60
|
+
# 用户消息蓝染底上的文字(新语义色,与 agent 中性前景区分)
|
|
61
|
+
("user-message-fg", "user-message-bg"),
|
|
59
62
|
}
|
|
60
63
|
)
|
|
61
64
|
|
|
@@ -64,6 +67,7 @@ _EXTRA_PAIRS = (
|
|
|
64
67
|
("error-bright", "error-bg"),
|
|
65
68
|
("diff-added", "diff-added-bg"),
|
|
66
69
|
("diff-removed", "diff-removed-bg"),
|
|
70
|
+
("user-message-fg", "user-message-bg"), # 用户消息蓝染底文字
|
|
67
71
|
)
|
|
68
72
|
|
|
69
73
|
|
|
@@ -39,6 +39,10 @@ LIMBO_DARK = Theme(
|
|
|
39
39
|
"text-tertiary": "#7F85A0",
|
|
40
40
|
"border-subtle": "#2C3044",
|
|
41
41
|
"border-default": "#3A3F57",
|
|
42
|
+
# 用户消息专属蓝:蓝染底 + 蓝字,与 agent 中性前景拉开辨识度
|
|
43
|
+
# (user-fg on user-bg = 7.26:1,on chat-bg = 7.91:1)
|
|
44
|
+
"user-message-bg": "#202744",
|
|
45
|
+
"user-message-fg": "#96B9EA",
|
|
42
46
|
# 错误底块上的文字专用(on error-bg = 4.91:1)
|
|
43
47
|
"error-bright": "#F06661",
|
|
44
48
|
"error-bg": "#342026",
|
|
@@ -69,6 +73,10 @@ LIMBO_LIGHT = Theme(
|
|
|
69
73
|
"text-tertiary": "#6B7186",
|
|
70
74
|
"border-subtle": "#D8DCE8",
|
|
71
75
|
"border-default": "#C4CADD",
|
|
76
|
+
# 用户消息专属蓝:淡蓝底 + 深蓝字,与 agent 中性前景拉开辨识度
|
|
77
|
+
# (user-fg on user-bg = 6.69:1,on chat-bg = 8.78:1)
|
|
78
|
+
"user-message-bg": "#DCE6F5",
|
|
79
|
+
"user-message-fg": "#1F4E86",
|
|
72
80
|
"error-bright": "#A93230",
|
|
73
81
|
"error-bg": "#F3D6D6",
|
|
74
82
|
"diff-added": "#256B41",
|
|
@@ -27,6 +27,7 @@ from textual.css.query import NoMatches
|
|
|
27
27
|
from textual.widgets import Markdown, Static
|
|
28
28
|
|
|
29
29
|
from limbo.models import Attachment
|
|
30
|
+
from limbo.ui.banner import user_icon
|
|
30
31
|
from limbo.ui.widgets.tool_card import ToolCard
|
|
31
32
|
|
|
32
33
|
# How many message widgets stay mounted in the DOM. Older ones are pruned
|
|
@@ -144,7 +145,11 @@ class QueuedMessage(Vertical):
|
|
|
144
145
|
def compose(self) -> ComposeResult:
|
|
145
146
|
if self.state == "cancelled":
|
|
146
147
|
self.add_class("cancelled")
|
|
147
|
-
yield Static(
|
|
148
|
+
yield Static(
|
|
149
|
+
user_icon() + Text(" ") + Text(f"❯ {self._text}"),
|
|
150
|
+
classes="user-message",
|
|
151
|
+
markup=False,
|
|
152
|
+
)
|
|
148
153
|
if self._attachments:
|
|
149
154
|
chips = []
|
|
150
155
|
for attachment in self._attachments:
|
|
@@ -310,7 +315,11 @@ class ChatWidget(VerticalScroll):
|
|
|
310
315
|
) -> None:
|
|
311
316
|
self._current_assistant = None
|
|
312
317
|
self._close_thinking()
|
|
313
|
-
msg = Static(
|
|
318
|
+
msg = Static(
|
|
319
|
+
user_icon() + Text(" ") + Text(f"❯ {text}"),
|
|
320
|
+
classes="user-message",
|
|
321
|
+
markup=False,
|
|
322
|
+
)
|
|
314
323
|
self.messages.append(msg)
|
|
315
324
|
self._mount_and_scroll(msg)
|
|
316
325
|
if attachments:
|
|
@@ -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("
|
|
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.
|