kon-coding-agent 0.3.7__tar.gz → 0.3.9__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.
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/AGENTS.md +4 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/CHANGELOG.md +66 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/PKG-INFO +17 -7
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/README.md +14 -5
- kon_coding_agent-0.3.9/docs/images/kon-screenshot.png +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/pyproject.toml +3 -2
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/config.py +27 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/core/types.py +5 -2
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/defaults/config.toml +10 -12
- kon_coding_agent-0.3.9/src/kon/git_branch.py +90 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/__init__.py +3 -19
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/base.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/models.py +19 -1
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/oauth/__init__.py +2 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/oauth/copilot.py +4 -0
- kon_coding_agent-0.3.9/src/kon/llm/providers/__init__.py +61 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/copilot.py +0 -4
- kon_coding_agent-0.3.9/src/kon/llm/providers/openai_codex_responses.py +509 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/openai_compat.py +1 -1
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/openai_completions.py +20 -2
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/loop.py +11 -4
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/runtime.py +62 -30
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/session.py +88 -16
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/themes.py +44 -13
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/base.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/bash.py +48 -37
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/edit.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/find.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/grep.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/read.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/web_fetch.py +113 -19
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/web_search.py +1 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/write.py +3 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/turn.py +28 -27
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/app.py +294 -50
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/app_protocol.py +1 -5
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/autocomplete.py +15 -17
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/blocks.py +136 -24
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/chat.py +104 -33
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/commands.py +143 -20
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/floating_list.py +24 -7
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/input.py +50 -3
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/selection_mode.py +2 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/session_ui.py +19 -20
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/styles.py +18 -2
- kon_coding_agent-0.3.9/src/kon/ui/terminal_image.py +34 -0
- kon_coding_agent-0.3.9/src/kon/ui/tool_output.py +34 -0
- kon_coding_agent-0.3.9/src/kon/ui/tree.py +437 -0
- kon_coding_agent-0.3.9/src/kon/ui/welcome.py +51 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/widgets.py +39 -24
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/llm/test_mock_provider.py +1 -1
- kon_coding_agent-0.3.9/tests/llm/test_openai_codex_provider_errors.py +371 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_agentic_loop.py +75 -2
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_compaction.py +1 -1
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_config_migration.py +51 -2
- kon_coding_agent-0.3.9/tests/test_git_branch.py +84 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_handoff.py +1 -1
- kon_coding_agent-0.3.9/tests/test_llm_lazy_imports.py +46 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_model_provider_resolution.py +7 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_openai_compat.py +32 -0
- kon_coding_agent-0.3.9/tests/test_runtime_switch_model.py +213 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_session_persistence.py +55 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_session_resume.py +1 -1
- kon_coding_agent-0.3.9/tests/test_session_tree.py +43 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_system_prompt.py +7 -1
- kon_coding_agent-0.3.9/tests/tools/test_bash_truncation.py +86 -0
- kon_coding_agent-0.3.9/tests/tools/test_web_fetch.py +139 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_autocomplete.py +6 -4
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_info_bar_permissions.py +14 -3
- kon_coding_agent-0.3.9/tests/ui/test_input_approval_submit.py +47 -0
- kon_coding_agent-0.3.9/tests/ui/test_input_cursor_theme.py +19 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_keybindings.py +3 -2
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_permissions_command.py +5 -5
- kon_coding_agent-0.3.9/tests/ui/test_queue_editing.py +154 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_shell_command_detection.py +39 -14
- kon_coding_agent-0.3.9/tests/ui/test_streaming_blocks.py +69 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_thinking_notifications_commands.py +6 -6
- kon_coding_agent-0.3.9/tests/ui/test_tool_output_expansion.py +67 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/uv.lock +277 -260
- kon_coding_agent-0.3.7/docs/architecture-review.md +0 -306
- kon_coding_agent-0.3.7/docs/code-health-scan.md +0 -144
- kon_coding_agent-0.3.7/docs/images/kon-screenshot.png +0 -0
- kon_coding_agent-0.3.7/micro +0 -0
- kon_coding_agent-0.3.7/src/kon/llm/providers/__init__.py +0 -57
- kon_coding_agent-0.3.7/src/kon/llm/providers/openai_codex_responses.py +0 -344
- kon_coding_agent-0.3.7/src/kon/ui/welcome.py +0 -85
- kon_coding_agent-0.3.7/tests/llm/test_openai_codex_provider_errors.py +0 -13
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.github/workflows/test.yml +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.gitignore +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.kon/skills/kon-release-publish/SKILL.md +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.kon/skills/kon-tmux-test/SKILL.md +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.kon/skills/kon-tmux-test/run-e2e-tests.sh +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.kon/skills/kon-tmux-test/setup-test-project.sh +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/.python-version +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/LICENSE +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/docs/e2e-test-coverage-review.md +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/docs/local-models.md +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/scripts/show_themes.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/async_utils.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/builtin_skills/init/SKILL.md +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/context/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/context/_xml.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/context/agent_mds.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/context/git.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/context/loader.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/context/skills.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/core/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/core/compaction.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/core/handoff.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/defaults/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/events.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/oauth/openai.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/anthropic.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/azure_ai_foundry.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/copilot_anthropic.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/github_copilot_headers.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/mock.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/openai_responses.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/llm/providers/sanitize.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/notify.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/permissions.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/py.typed +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/sounds/completion.wav +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/sounds/error.wav +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/sounds/permission.wav +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/_read_image.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools/_tool_utils.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/tools_manager.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/clipboard.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/export.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/formatting.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/latex.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/path_complete.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/ui/prompt_history.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/src/kon/update_check.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/conftest.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/context/test_agents.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/context/test_skills.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/llm/__init__.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/llm/test_anthropic_provider.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/llm/test_azure_ai_foundry_provider.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/llm/test_openai_oauth.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_cli_auth_flags.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_cli_provider_resolution.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_config_binaries.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_config_error_fallback.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_config_injection.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_handoff_link_interrupt.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_launch_warnings.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_local_auth_config.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_notifications_config.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_notify.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_permissions.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_session_queries.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_system_prompt_git_context.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_themes.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_tools_manager.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_ui_notifications.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_update_check.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/test_update_notice_behavior.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_diff.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_edit.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_edit_display.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_read.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_read_image.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_read_image_integration.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_subprocess_cancellation.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/tools/test_write.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_app_approval_keys.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_floating_list.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_info_bar_clicks.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_input_handoff.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_input_paste.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_input_shell_style.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_latex.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_permission_selection_status.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_prompt_history.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_status_line.py +0 -0
- {kon_coding_agent-0.3.7 → kon_coding_agent-0.3.9}/tests/ui/test_styles.py +0 -0
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
- Use `uv run python -m pytest` for testing in general; after edits/writes
|
|
12
12
|
- If the user asks for e2e tests then run the kon-tmux e2e test if available
|
|
13
13
|
|
|
14
|
+
## Skills
|
|
15
|
+
|
|
16
|
+
- Kon supports registering a skill as a slash command by setting `register_cmd: true` in the SKILL.md frontmatter. If a user asks for a "registered" skill, include this field.
|
|
17
|
+
|
|
14
18
|
## Committing code
|
|
15
19
|
|
|
16
20
|
- If the user tells you to commit code, look at all the changes and create multile commits if needed bsaed on logical groupings
|
|
@@ -6,6 +6,72 @@ All notable changes to this project will be documented in this file.
|
|
|
6
6
|
|
|
7
7
|
- No changes yet.
|
|
8
8
|
|
|
9
|
+
## 0.3.9 - 2026-05-20
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added inline image display from tool results in chat UI.
|
|
14
|
+
- Added tree view for handoff navigation.
|
|
15
|
+
- Added ability to edit queued messages.
|
|
16
|
+
- Added Kanagawa Dragon theme.
|
|
17
|
+
- Added lazy provider loading for faster startup - @Meltedd.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Swapped thinking block keybindings.
|
|
22
|
+
- Grouped preferences under settings.
|
|
23
|
+
- Refreshed startup resource display.
|
|
24
|
+
- Smoother streaming experience.
|
|
25
|
+
- Updated permission mode symbols — single tick for auto, stop icon for prompt.
|
|
26
|
+
- Lowercase slash command descriptions, `L` prefix for queue items.
|
|
27
|
+
- Updated README with ASCII art title, new screenshot, and refined styling.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Fixed Codex provider event handling, transport, and tracking - @Meltedd.
|
|
32
|
+
- Fixed tool expansion crash on startup - @0xku.
|
|
33
|
+
- Fixed Enter key not submitting permission prompts.
|
|
34
|
+
- Fixed manual shell output expand behavior.
|
|
35
|
+
- Fixed streaming cursor removal.
|
|
36
|
+
- Fixed tool output top padding missing blank line.
|
|
37
|
+
- Fixed tree selector display and empty tree state alignment.
|
|
38
|
+
- Fixed input cursor visibility in light themes.
|
|
39
|
+
- Fixed floating list popup styling.
|
|
40
|
+
- Fixed selected color alignment across themes and solarized-light dim color.
|
|
41
|
+
- Fixed legacy Shift+Enter mapping.
|
|
42
|
+
- Fixed Windows startup warning by delaying textual image import - @sukhbinder.
|
|
43
|
+
|
|
44
|
+
## 0.3.8 - 2026-05-08
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- Added DeepSeek provider support - @Kreijstal.
|
|
49
|
+
- Added Codex websocket streaming with SSE fallback.
|
|
50
|
+
- Added expandable tool output.
|
|
51
|
+
- Added session handoff tree display in the resume list.
|
|
52
|
+
- Added config migration v5→v6 to replace legacy system prompts with the current default.
|
|
53
|
+
- Added dynamic tool guidelines in the system prompt via `prompt_guidelines` on `BaseTool`.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Deduplicated tool prompt guidelines in the system prompt.
|
|
58
|
+
- Simplified prefix formatting in the session tree display.
|
|
59
|
+
- Added skills registration guidance to `AGENTS.md`.
|
|
60
|
+
- Removed old architectural review docs.
|
|
61
|
+
- Adjusted info bar pause icon spacing.
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- Fixed provider-specific OpenAI-compatible API key selection.
|
|
66
|
+
- Patched vulnerable dependencies - @Meltedd.
|
|
67
|
+
- Restored web fetch extraction compatibility with `html-to-markdown` 3.3.
|
|
68
|
+
- Handled `html-to-markdown` dict return types and raised the minimum supported version.
|
|
69
|
+
- Fixed info bar git branch refreshing.
|
|
70
|
+
- Marked GLM-5.1 as supporting native vision.
|
|
71
|
+
- Hardened `web_fetch` against SSRF - @Meltedd.
|
|
72
|
+
- Enforced output caps on shell-mode bash - @Meltedd.
|
|
73
|
+
- Used themed notice color for launch warning block borders.
|
|
74
|
+
|
|
9
75
|
## 0.3.7 - 2026-05-02
|
|
10
76
|
|
|
11
77
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kon-coding-agent
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Minimal coding agent
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -9,17 +9,22 @@ Requires-Dist: aiohttp>=3.13.3
|
|
|
9
9
|
Requires-Dist: anthropic>=0.79.0
|
|
10
10
|
Requires-Dist: curl-cffi>=0.15.0
|
|
11
11
|
Requires-Dist: ddgs>=9.0.0
|
|
12
|
-
Requires-Dist: html-to-markdown<3.
|
|
12
|
+
Requires-Dist: html-to-markdown<3.4.0,>=3.3.0
|
|
13
13
|
Requires-Dist: openai>=2.21.0
|
|
14
14
|
Requires-Dist: pillow>=12.1.1
|
|
15
15
|
Requires-Dist: pydantic>=2.12.5
|
|
16
16
|
Requires-Dist: readability-lxml>=0.8.4
|
|
17
17
|
Requires-Dist: rich>=14.3.2
|
|
18
|
+
Requires-Dist: textual-image[textual]>=0.12.0
|
|
18
19
|
Requires-Dist: textual>=8.0.0
|
|
19
20
|
Description-Content-Type: text/markdown
|
|
20
21
|
|
|
21
|
-
<
|
|
22
|
-
|
|
22
|
+
<pre align="center">
|
|
23
|
+
░█░█░█▀█░█▀█
|
|
24
|
+
░█▀▄░█░█░█░█
|
|
25
|
+
░▀░▀░▀▀▀░▀░▀
|
|
26
|
+
</pre>
|
|
27
|
+
<p align="center">Minimal coding agent harness</p>
|
|
23
28
|
<p align="center">
|
|
24
29
|
<a href="https://pypi.org/project/kon-coding-agent/"><img alt="PyPI" src="https://img.shields.io/pypi/v/kon-coding-agent?style=flat-square" /></a>
|
|
25
30
|
<a href="https://www.python.org/downloads/release/python-3120/"><img alt="Python" src="https://img.shields.io/badge/python-3.12%2B-blue?style=flat-square" /></a>
|
|
@@ -27,7 +32,7 @@ Description-Content-Type: text/markdown
|
|
|
27
32
|
</p>
|
|
28
33
|
|
|
29
34
|
<p align="center">
|
|
30
|
-
<img src="docs/images/kon-screenshot.png" alt="Kon terminal UI screenshot" width="
|
|
35
|
+
<img src="docs/images/kon-screenshot.png" alt="Kon terminal UI screenshot" width="700" />
|
|
31
36
|
</p>
|
|
32
37
|
|
|
33
38
|
Kon is a minimal coding agent focused on a tiny core prompt, a small built-in toolset, and project-specific context layered on top only when you want it. The default system prompt stays **under 270 tokens**, and even including the built-in tool descriptions and parameter schemas, the fixed harness stays at about **~1,000 tokens**. The core experience is built around just **6 default tools** plus **2 optional web tools**.
|
|
@@ -84,7 +89,7 @@ kon
|
|
|
84
89
|
|
|
85
90
|
```text
|
|
86
91
|
usage: kon [-h] [--model MODEL]
|
|
87
|
-
[--provider {azure-ai-foundry,github-copilot,openai,openai-codex,openai-responses,zhipu}]
|
|
92
|
+
[--provider {azure-ai-foundry,deepseek,github-copilot,openai,openai-codex,openai-responses,zhipu}]
|
|
88
93
|
[--api-key API_KEY] [--base-url BASE_URL] [--continue]
|
|
89
94
|
[--resume RESUME_SESSION] [--version]
|
|
90
95
|
[--extra-tools EXTRA_TOOLS]
|
|
@@ -94,7 +99,7 @@ Kon TUI
|
|
|
94
99
|
options:
|
|
95
100
|
-h, --help show this help message and exit
|
|
96
101
|
--model, -m MODEL Model to use
|
|
97
|
-
--provider, -p {azure-ai-foundry,github-copilot,openai,openai-codex,openai-responses,zhipu}
|
|
102
|
+
--provider, -p {azure-ai-foundry,deepseek,github-copilot,openai,openai-codex,openai-responses,zhipu}
|
|
98
103
|
Provider to use
|
|
99
104
|
--api-key, -k API_KEY
|
|
100
105
|
API key
|
|
@@ -482,6 +487,7 @@ Built-in provider support includes:
|
|
|
482
487
|
- **OpenAI Codex**
|
|
483
488
|
- **OpenAI Responses / OpenAI-compatible endpoints**
|
|
484
489
|
- **Azure AI Foundry**
|
|
490
|
+
- **DeepSeek**
|
|
485
491
|
- **ZhiPu**
|
|
486
492
|
|
|
487
493
|
Use `/model` in the TUI to switch between available configured models.
|
|
@@ -493,12 +499,16 @@ Kon supports both OAuth login flows and direct API-key configuration.
|
|
|
493
499
|
- **GitHub Copilot OAuth**: run `/login` and choose GitHub Copilot
|
|
494
500
|
- **OpenAI OAuth**: run `/login` and choose OpenAI
|
|
495
501
|
- **OpenAI-compatible providers**: use `OPENAI_API_KEY` or provider-specific equivalents
|
|
502
|
+
- OpenAI/default: `OPENAI_API_KEY` only
|
|
503
|
+
- DeepSeek: `DEEPSEEK_API_KEY` first, then `OPENAI_API_KEY`
|
|
504
|
+
- ZhiPu/ZAI: `ZAI_API_KEY` first, then `OPENAI_API_KEY`
|
|
496
505
|
- **Azure AI Foundry**: set `AZURE_AI_FOUNDRY_API_KEY` and `AZURE_AI_FOUNDRY_BASE_URL`
|
|
497
506
|
|
|
498
507
|
You can also pass credentials directly on launch:
|
|
499
508
|
|
|
500
509
|
```bash
|
|
501
510
|
kon --provider openai --model some-model --api-key "$OPENAI_API_KEY"
|
|
511
|
+
kon --provider deepseek --model deepseek-v4-flash
|
|
502
512
|
```
|
|
503
513
|
|
|
504
514
|
### Local models
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
1
|
+
<pre align="center">
|
|
2
|
+
░█░█░█▀█░█▀█
|
|
3
|
+
░█▀▄░█░█░█░█
|
|
4
|
+
░▀░▀░▀▀▀░▀░▀
|
|
5
|
+
</pre>
|
|
6
|
+
<p align="center">Minimal coding agent harness</p>
|
|
3
7
|
<p align="center">
|
|
4
8
|
<a href="https://pypi.org/project/kon-coding-agent/"><img alt="PyPI" src="https://img.shields.io/pypi/v/kon-coding-agent?style=flat-square" /></a>
|
|
5
9
|
<a href="https://www.python.org/downloads/release/python-3120/"><img alt="Python" src="https://img.shields.io/badge/python-3.12%2B-blue?style=flat-square" /></a>
|
|
@@ -7,7 +11,7 @@
|
|
|
7
11
|
</p>
|
|
8
12
|
|
|
9
13
|
<p align="center">
|
|
10
|
-
<img src="docs/images/kon-screenshot.png" alt="Kon terminal UI screenshot" width="
|
|
14
|
+
<img src="docs/images/kon-screenshot.png" alt="Kon terminal UI screenshot" width="700" />
|
|
11
15
|
</p>
|
|
12
16
|
|
|
13
17
|
Kon is a minimal coding agent focused on a tiny core prompt, a small built-in toolset, and project-specific context layered on top only when you want it. The default system prompt stays **under 270 tokens**, and even including the built-in tool descriptions and parameter schemas, the fixed harness stays at about **~1,000 tokens**. The core experience is built around just **6 default tools** plus **2 optional web tools**.
|
|
@@ -64,7 +68,7 @@ kon
|
|
|
64
68
|
|
|
65
69
|
```text
|
|
66
70
|
usage: kon [-h] [--model MODEL]
|
|
67
|
-
[--provider {azure-ai-foundry,github-copilot,openai,openai-codex,openai-responses,zhipu}]
|
|
71
|
+
[--provider {azure-ai-foundry,deepseek,github-copilot,openai,openai-codex,openai-responses,zhipu}]
|
|
68
72
|
[--api-key API_KEY] [--base-url BASE_URL] [--continue]
|
|
69
73
|
[--resume RESUME_SESSION] [--version]
|
|
70
74
|
[--extra-tools EXTRA_TOOLS]
|
|
@@ -74,7 +78,7 @@ Kon TUI
|
|
|
74
78
|
options:
|
|
75
79
|
-h, --help show this help message and exit
|
|
76
80
|
--model, -m MODEL Model to use
|
|
77
|
-
--provider, -p {azure-ai-foundry,github-copilot,openai,openai-codex,openai-responses,zhipu}
|
|
81
|
+
--provider, -p {azure-ai-foundry,deepseek,github-copilot,openai,openai-codex,openai-responses,zhipu}
|
|
78
82
|
Provider to use
|
|
79
83
|
--api-key, -k API_KEY
|
|
80
84
|
API key
|
|
@@ -462,6 +466,7 @@ Built-in provider support includes:
|
|
|
462
466
|
- **OpenAI Codex**
|
|
463
467
|
- **OpenAI Responses / OpenAI-compatible endpoints**
|
|
464
468
|
- **Azure AI Foundry**
|
|
469
|
+
- **DeepSeek**
|
|
465
470
|
- **ZhiPu**
|
|
466
471
|
|
|
467
472
|
Use `/model` in the TUI to switch between available configured models.
|
|
@@ -473,12 +478,16 @@ Kon supports both OAuth login flows and direct API-key configuration.
|
|
|
473
478
|
- **GitHub Copilot OAuth**: run `/login` and choose GitHub Copilot
|
|
474
479
|
- **OpenAI OAuth**: run `/login` and choose OpenAI
|
|
475
480
|
- **OpenAI-compatible providers**: use `OPENAI_API_KEY` or provider-specific equivalents
|
|
481
|
+
- OpenAI/default: `OPENAI_API_KEY` only
|
|
482
|
+
- DeepSeek: `DEEPSEEK_API_KEY` first, then `OPENAI_API_KEY`
|
|
483
|
+
- ZhiPu/ZAI: `ZAI_API_KEY` first, then `OPENAI_API_KEY`
|
|
476
484
|
- **Azure AI Foundry**: set `AZURE_AI_FOUNDRY_API_KEY` and `AZURE_AI_FOUNDRY_BASE_URL`
|
|
477
485
|
|
|
478
486
|
You can also pass credentials directly on launch:
|
|
479
487
|
|
|
480
488
|
```bash
|
|
481
489
|
kon --provider openai --model some-model --api-key "$OPENAI_API_KEY"
|
|
490
|
+
kon --provider deepseek --model deepseek-v4-flash
|
|
482
491
|
```
|
|
483
492
|
|
|
484
493
|
### Local models
|
|
Binary file
|
|
@@ -14,7 +14,7 @@ default = true
|
|
|
14
14
|
|
|
15
15
|
[project]
|
|
16
16
|
name = "kon-coding-agent"
|
|
17
|
-
version = "0.3.
|
|
17
|
+
version = "0.3.9"
|
|
18
18
|
description = "Minimal coding agent"
|
|
19
19
|
readme = "README.md"
|
|
20
20
|
requires-python = ">=3.12"
|
|
@@ -24,13 +24,14 @@ dependencies = [
|
|
|
24
24
|
"anthropic>=0.79.0",
|
|
25
25
|
"curl-cffi>=0.15.0",
|
|
26
26
|
"ddgs>=9.0.0",
|
|
27
|
-
"html-to-markdown>=3.
|
|
27
|
+
"html-to-markdown>=3.3.0,<3.4.0",
|
|
28
28
|
"openai>=2.21.0",
|
|
29
29
|
"pillow>=12.1.1",
|
|
30
30
|
"pydantic>=2.12.5",
|
|
31
31
|
"readability-lxml>=0.8.4",
|
|
32
32
|
"rich>=14.3.2",
|
|
33
33
|
"textual>=8.0.0",
|
|
34
|
+
"textual-image[textual]>=0.12.0",
|
|
34
35
|
]
|
|
35
36
|
|
|
36
37
|
[dependency-groups]
|
|
@@ -344,6 +344,29 @@ def _migrate_v4_to_v5(data: dict[str, Any]) -> dict[str, Any]:
|
|
|
344
344
|
return migrated
|
|
345
345
|
|
|
346
346
|
|
|
347
|
+
def _migrate_v5_to_v6(data: dict[str, Any]) -> dict[str, Any]:
|
|
348
|
+
migrated = Config._apply_legacy_key_shims(data)
|
|
349
|
+
llm = migrated.get("llm")
|
|
350
|
+
if not isinstance(llm, dict):
|
|
351
|
+
llm = {}
|
|
352
|
+
migrated["llm"] = llm
|
|
353
|
+
|
|
354
|
+
system_prompt = llm.get("system_prompt")
|
|
355
|
+
if not isinstance(system_prompt, dict):
|
|
356
|
+
system_prompt = {}
|
|
357
|
+
llm["system_prompt"] = system_prompt
|
|
358
|
+
|
|
359
|
+
system_prompt["content"] = _DEFAULT_CONFIG_DATA["llm"]["system_prompt"]["content"]
|
|
360
|
+
system_prompt["git_context"] = _DEFAULT_CONFIG_DATA["llm"]["system_prompt"]["git_context"]
|
|
361
|
+
|
|
362
|
+
meta = migrated.get("meta")
|
|
363
|
+
if not isinstance(meta, dict):
|
|
364
|
+
migrated["meta"] = {"config_version": 6}
|
|
365
|
+
else:
|
|
366
|
+
meta["config_version"] = 6
|
|
367
|
+
return migrated
|
|
368
|
+
|
|
369
|
+
|
|
347
370
|
def _migrate_config_data(data: dict[str, Any]) -> tuple[dict[str, Any], int, int, bool]:
|
|
348
371
|
original = deepcopy(data)
|
|
349
372
|
current_version = _get_config_version(original)
|
|
@@ -370,6 +393,10 @@ def _migrate_config_data(data: dict[str, Any]) -> tuple[dict[str, Any], int, int
|
|
|
370
393
|
migrated = _migrate_v4_to_v5(migrated)
|
|
371
394
|
current_version = 5
|
|
372
395
|
continue
|
|
396
|
+
if current_version == 5:
|
|
397
|
+
migrated = _migrate_v5_to_v6(migrated)
|
|
398
|
+
current_version = 6
|
|
399
|
+
continue
|
|
373
400
|
break
|
|
374
401
|
|
|
375
402
|
migrated_version = _get_config_version(migrated)
|
|
@@ -66,6 +66,7 @@ class ToolCallDelta(BaseModel):
|
|
|
66
66
|
type: Literal["tool_call_delta"] = "tool_call_delta"
|
|
67
67
|
index: int # Correlates with ToolCallStart.index
|
|
68
68
|
arguments_delta: str
|
|
69
|
+
replace: bool = False
|
|
69
70
|
|
|
70
71
|
|
|
71
72
|
class StreamDone(BaseModel):
|
|
@@ -129,7 +130,8 @@ class ToolResultMessage(BaseModel):
|
|
|
129
130
|
tool_name: str
|
|
130
131
|
content: list[TextContent | ImageContent]
|
|
131
132
|
ui_summary: str | None = None # One-line UI text rendered on tool header line
|
|
132
|
-
ui_details: str | None = None #
|
|
133
|
+
ui_details: str | None = None # Collapsed multiline UI text rendered below the header
|
|
134
|
+
ui_details_full: str | None = None # Expanded multiline UI text rendered below the header
|
|
133
135
|
is_error: bool = False
|
|
134
136
|
file_changes: FileChanges | None = None
|
|
135
137
|
|
|
@@ -165,7 +167,8 @@ class ToolResult(BaseModel):
|
|
|
165
167
|
result: str | None = None # Raw result (sent to LLM)
|
|
166
168
|
images: list[ImageContent] | None = None # Images to include in result
|
|
167
169
|
ui_summary: str | None = None # One-line result text appended to the tool header
|
|
168
|
-
ui_details: str | None = None #
|
|
170
|
+
ui_details: str | None = None # Collapsed multiline result body rendered below the header
|
|
171
|
+
ui_details_full: str | None = None # Expanded multiline result body rendered below the header
|
|
169
172
|
file_changes: FileChanges | None = None # Track +/- lines for edit/write tools
|
|
170
173
|
|
|
171
174
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[meta]
|
|
2
|
-
config_version =
|
|
2
|
+
config_version = 6
|
|
3
3
|
|
|
4
4
|
[llm]
|
|
5
5
|
default_provider = "openai-codex" # "zhipu", "github-copilot", "openai-codex"
|
|
@@ -32,17 +32,8 @@ content = """You are an expert coding assistant called Kon. You help users by re
|
|
|
32
32
|
- Be concise in your responses
|
|
33
33
|
- Show file paths clearly when working with files
|
|
34
34
|
- When summarizing your actions, output plain text directly DO NOT use cat or bash to display
|
|
35
|
-
- Kon session logs are JSONL files in ~/.kon/sessions;
|
|
36
|
-
|
|
37
|
-
# Tool usage
|
|
38
|
-
|
|
39
|
-
- Prefer specialized tools over bash for file operations:
|
|
40
|
-
- Use read to view files (NOT cat/head/tail)
|
|
41
|
-
- Use edit for precise changes (NOT sed/awk)
|
|
42
|
-
- Use write only for new files or complete rewrites (NOT echo >/cat <<EOF)
|
|
43
|
-
- Use grep to search file contents (NOT grep or rg via bash)
|
|
44
|
-
- Use find to search for files by name/glob (NOT find or ls via bash)
|
|
45
|
-
- Use bash for terminal operations (git, package managers, builds, tests, running scripts)"""
|
|
35
|
+
- Kon session logs are JSONL files in ~/.kon/sessions; If the user references recent sessions or a particular session, look there
|
|
36
|
+
- If the user mentions adding a new skill then look at https://github.com/0xku/kon/blob/main/README.md#skills"""
|
|
46
37
|
|
|
47
38
|
[compaction]
|
|
48
39
|
# What kon should do after compacting history on context overflow.
|
|
@@ -80,3 +71,10 @@ mode = "prompt" # "prompt" or "auto"
|
|
|
80
71
|
enabled = false
|
|
81
72
|
# Audio playback volume from 0.0 (muted) to 1.0 (full volume).
|
|
82
73
|
volume = 0.5
|
|
74
|
+
|
|
75
|
+
# Example: DeepSeek provider
|
|
76
|
+
# export DEEPSEEK_API_KEY="sk-your-api-key"
|
|
77
|
+
#
|
|
78
|
+
# Then set in [llm]:
|
|
79
|
+
# default_provider = "deepseek"
|
|
80
|
+
# default_model = "deepseek-v4-flash"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class GitPaths:
|
|
8
|
+
repo_dir: str
|
|
9
|
+
common_git_dir: str
|
|
10
|
+
head_path: str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def find_git_paths(cwd: str) -> GitPaths | None:
|
|
14
|
+
"""Find git metadata paths for regular repos and worktrees."""
|
|
15
|
+
directory = os.path.abspath(cwd)
|
|
16
|
+
while True:
|
|
17
|
+
git_path = os.path.join(directory, ".git")
|
|
18
|
+
if os.path.exists(git_path):
|
|
19
|
+
try:
|
|
20
|
+
if os.path.isfile(git_path):
|
|
21
|
+
with open(git_path, encoding="utf-8") as f:
|
|
22
|
+
content = f.read().strip()
|
|
23
|
+
if content.startswith("gitdir: "):
|
|
24
|
+
git_dir = os.path.abspath(
|
|
25
|
+
os.path.join(directory, content.removeprefix("gitdir: ").strip())
|
|
26
|
+
)
|
|
27
|
+
head_path = os.path.join(git_dir, "HEAD")
|
|
28
|
+
if not os.path.exists(head_path):
|
|
29
|
+
return None
|
|
30
|
+
common_dir_path = os.path.join(git_dir, "commondir")
|
|
31
|
+
if os.path.exists(common_dir_path):
|
|
32
|
+
with open(common_dir_path, encoding="utf-8") as f:
|
|
33
|
+
common_dir = f.read().strip()
|
|
34
|
+
common_git_dir = os.path.abspath(os.path.join(git_dir, common_dir))
|
|
35
|
+
else:
|
|
36
|
+
common_git_dir = git_dir
|
|
37
|
+
return GitPaths(directory, common_git_dir, head_path)
|
|
38
|
+
elif os.path.isdir(git_path):
|
|
39
|
+
head_path = os.path.join(git_path, "HEAD")
|
|
40
|
+
if not os.path.exists(head_path):
|
|
41
|
+
return None
|
|
42
|
+
return GitPaths(directory, git_path, head_path)
|
|
43
|
+
except OSError:
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
parent = os.path.dirname(directory)
|
|
47
|
+
if parent == directory:
|
|
48
|
+
return None
|
|
49
|
+
directory = parent
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _resolve_branch_with_git(repo_dir: str) -> str | None:
|
|
53
|
+
try:
|
|
54
|
+
result = subprocess.run(
|
|
55
|
+
["git", "--no-optional-locks", "symbolic-ref", "--quiet", "--short", "HEAD"],
|
|
56
|
+
cwd=repo_dir,
|
|
57
|
+
capture_output=True,
|
|
58
|
+
text=True,
|
|
59
|
+
timeout=1,
|
|
60
|
+
check=False,
|
|
61
|
+
)
|
|
62
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
if result.returncode != 0:
|
|
66
|
+
return None
|
|
67
|
+
branch = result.stdout.strip()
|
|
68
|
+
return branch or None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def resolve_git_branch(cwd: str) -> str:
|
|
72
|
+
"""Resolve current git branch, returning an empty string outside git repos."""
|
|
73
|
+
git_paths = find_git_paths(cwd)
|
|
74
|
+
if git_paths is None:
|
|
75
|
+
return ""
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
with open(git_paths.head_path, encoding="utf-8") as f:
|
|
79
|
+
content = f.read().strip()
|
|
80
|
+
except OSError:
|
|
81
|
+
return ""
|
|
82
|
+
|
|
83
|
+
prefix = "ref: refs/heads/"
|
|
84
|
+
if content.startswith(prefix):
|
|
85
|
+
branch = content.removeprefix(prefix)
|
|
86
|
+
if branch == ".invalid":
|
|
87
|
+
return _resolve_branch_with_git(git_paths.repo_dir) or "detached"
|
|
88
|
+
return branch
|
|
89
|
+
|
|
90
|
+
return "detached"
|
|
@@ -10,6 +10,7 @@ from .models import (
|
|
|
10
10
|
from .oauth import clear_credentials as clear_copilot_credentials
|
|
11
11
|
from .oauth import (
|
|
12
12
|
clear_openai_credentials,
|
|
13
|
+
is_copilot_logged_in,
|
|
13
14
|
is_openai_logged_in,
|
|
14
15
|
load_openai_credentials,
|
|
15
16
|
openai_login,
|
|
@@ -18,33 +19,15 @@ from .oauth import get_valid_openai_token as get_openai_token
|
|
|
18
19
|
from .oauth import get_valid_token as get_copilot_token
|
|
19
20
|
from .oauth import load_credentials as load_copilot_credentials
|
|
20
21
|
from .oauth import login as copilot_login
|
|
21
|
-
from .providers import
|
|
22
|
-
API_TYPE_TO_PROVIDER_CLASS,
|
|
23
|
-
PROVIDER_API_BY_NAME,
|
|
24
|
-
CopilotAnthropicProvider,
|
|
25
|
-
CopilotProvider,
|
|
26
|
-
CopilotResponsesProvider,
|
|
27
|
-
OpenAICodexResponsesProvider,
|
|
28
|
-
OpenAICompletionsProvider,
|
|
29
|
-
OpenAIResponsesProvider,
|
|
30
|
-
is_copilot_logged_in,
|
|
31
|
-
resolve_provider_api_type,
|
|
32
|
-
)
|
|
22
|
+
from .providers import PROVIDER_API_BY_NAME, get_provider_class, resolve_provider_api_type
|
|
33
23
|
|
|
34
24
|
__all__ = [
|
|
35
|
-
"API_TYPE_TO_PROVIDER_CLASS",
|
|
36
25
|
"DEFAULT_THINKING_LEVELS",
|
|
37
26
|
"PROVIDER_API_BY_NAME",
|
|
38
27
|
"ApiType",
|
|
39
28
|
"BaseProvider",
|
|
40
|
-
"CopilotAnthropicProvider",
|
|
41
|
-
"CopilotProvider",
|
|
42
|
-
"CopilotResponsesProvider",
|
|
43
29
|
"LLMStream",
|
|
44
30
|
"Model",
|
|
45
|
-
"OpenAICodexResponsesProvider",
|
|
46
|
-
"OpenAICompletionsProvider",
|
|
47
|
-
"OpenAIResponsesProvider",
|
|
48
31
|
"ProviderConfig",
|
|
49
32
|
"clear_copilot_credentials",
|
|
50
33
|
"clear_openai_credentials",
|
|
@@ -55,6 +38,7 @@ __all__ = [
|
|
|
55
38
|
"get_model",
|
|
56
39
|
"get_models_by_provider",
|
|
57
40
|
"get_openai_token",
|
|
41
|
+
"get_provider_class",
|
|
58
42
|
"is_copilot_logged_in",
|
|
59
43
|
"is_openai_logged_in",
|
|
60
44
|
"load_copilot_credentials",
|
|
@@ -53,9 +53,27 @@ MODELS: dict[str, Model] = {
|
|
|
53
53
|
api=ApiType.OPENAI_COMPLETIONS,
|
|
54
54
|
base_url="https://api.z.ai/api/coding/paas/v4",
|
|
55
55
|
max_tokens=8192,
|
|
56
|
+
supports_images=True,
|
|
57
|
+
supports_thinking=True,
|
|
58
|
+
),
|
|
59
|
+
# DeepSeek models (OpenAI-compatible Chat Completions API)
|
|
60
|
+
"deepseek-v4-flash": Model(
|
|
61
|
+
id="deepseek-v4-flash",
|
|
62
|
+
provider="deepseek",
|
|
63
|
+
api=ApiType.OPENAI_COMPLETIONS,
|
|
64
|
+
base_url="https://api.deepseek.com",
|
|
65
|
+
max_tokens=8192,
|
|
66
|
+
supports_images=False,
|
|
67
|
+
supports_thinking=True,
|
|
68
|
+
),
|
|
69
|
+
"deepseek-v4-pro": Model(
|
|
70
|
+
id="deepseek-v4-pro",
|
|
71
|
+
provider="deepseek",
|
|
72
|
+
api=ApiType.OPENAI_COMPLETIONS,
|
|
73
|
+
base_url="https://api.deepseek.com",
|
|
74
|
+
max_tokens=8192,
|
|
56
75
|
supports_images=False,
|
|
57
76
|
supports_thinking=True,
|
|
58
|
-
vision_model="glm-4v-flash",
|
|
59
77
|
),
|
|
60
78
|
# GitHub Copilot models - Claude (uses Anthropic Messages API for thinking support)
|
|
61
79
|
"claude-sonnet-4.6-copilot": Model(
|
|
@@ -5,6 +5,7 @@ from .copilot import (
|
|
|
5
5
|
get_base_url_from_token,
|
|
6
6
|
get_copilot_auth_path,
|
|
7
7
|
get_valid_token,
|
|
8
|
+
is_copilot_logged_in,
|
|
8
9
|
load_credentials,
|
|
9
10
|
login,
|
|
10
11
|
)
|
|
@@ -29,6 +30,7 @@ __all__ = [
|
|
|
29
30
|
"get_openai_auth_path",
|
|
30
31
|
"get_valid_openai_token",
|
|
31
32
|
"get_valid_token",
|
|
33
|
+
"is_copilot_logged_in",
|
|
32
34
|
"is_openai_logged_in",
|
|
33
35
|
"load_credentials",
|
|
34
36
|
"load_openai_credentials",
|
|
@@ -86,6 +86,10 @@ def clear_credentials() -> None:
|
|
|
86
86
|
path.unlink()
|
|
87
87
|
|
|
88
88
|
|
|
89
|
+
def is_copilot_logged_in() -> bool:
|
|
90
|
+
return load_credentials() is not None
|
|
91
|
+
|
|
92
|
+
|
|
89
93
|
def _get_urls(domain: str) -> dict[str, str]:
|
|
90
94
|
return {
|
|
91
95
|
"device_code": f"https://{domain}/login/device/code",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from ..base import BaseProvider
|
|
2
|
+
from ..models import ApiType
|
|
3
|
+
|
|
4
|
+
PROVIDER_API_BY_NAME: dict[str, ApiType] = {
|
|
5
|
+
"openai": ApiType.OPENAI_COMPLETIONS,
|
|
6
|
+
"zhipu": ApiType.OPENAI_COMPLETIONS,
|
|
7
|
+
"deepseek": ApiType.OPENAI_COMPLETIONS,
|
|
8
|
+
"github-copilot": ApiType.GITHUB_COPILOT,
|
|
9
|
+
"openai-responses": ApiType.OPENAI_RESPONSES,
|
|
10
|
+
"openai-codex": ApiType.OPENAI_CODEX_RESPONSES,
|
|
11
|
+
"azure-ai-foundry": ApiType.AZURE_AI_FOUNDRY,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_provider_api_type(provider: str | None) -> ApiType:
|
|
16
|
+
if provider is None:
|
|
17
|
+
return ApiType.OPENAI_COMPLETIONS
|
|
18
|
+
|
|
19
|
+
api_type = PROVIDER_API_BY_NAME.get(provider)
|
|
20
|
+
if api_type is None:
|
|
21
|
+
valid = ", ".join(sorted(PROVIDER_API_BY_NAME))
|
|
22
|
+
raise ValueError(f"Unknown provider '{provider}'. Valid providers: {valid}")
|
|
23
|
+
|
|
24
|
+
return api_type
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_provider_class(api_type: ApiType) -> type[BaseProvider]:
|
|
28
|
+
match api_type:
|
|
29
|
+
case ApiType.GITHUB_COPILOT:
|
|
30
|
+
from .copilot import CopilotProvider
|
|
31
|
+
|
|
32
|
+
return CopilotProvider
|
|
33
|
+
case ApiType.GITHUB_COPILOT_RESPONSES:
|
|
34
|
+
from .copilot import CopilotResponsesProvider
|
|
35
|
+
|
|
36
|
+
return CopilotResponsesProvider
|
|
37
|
+
case ApiType.OPENAI_RESPONSES:
|
|
38
|
+
from .openai_responses import OpenAIResponsesProvider
|
|
39
|
+
|
|
40
|
+
return OpenAIResponsesProvider
|
|
41
|
+
case ApiType.OPENAI_CODEX_RESPONSES:
|
|
42
|
+
from .openai_codex_responses import OpenAICodexResponsesProvider
|
|
43
|
+
|
|
44
|
+
return OpenAICodexResponsesProvider
|
|
45
|
+
case ApiType.ANTHROPIC_COPILOT:
|
|
46
|
+
from .copilot_anthropic import CopilotAnthropicProvider
|
|
47
|
+
|
|
48
|
+
return CopilotAnthropicProvider
|
|
49
|
+
case ApiType.AZURE_AI_FOUNDRY:
|
|
50
|
+
from .azure_ai_foundry import AzureAIFoundryProvider
|
|
51
|
+
|
|
52
|
+
return AzureAIFoundryProvider
|
|
53
|
+
case ApiType.OPENAI_COMPLETIONS:
|
|
54
|
+
from .openai_completions import OpenAICompletionsProvider
|
|
55
|
+
|
|
56
|
+
return OpenAICompletionsProvider
|
|
57
|
+
|
|
58
|
+
raise ValueError(f"Unsupported API type: {api_type.value}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
__all__ = ["PROVIDER_API_BY_NAME", "get_provider_class", "resolve_provider_api_type"]
|