kon-coding-agent 0.3.4__tar.gz → 0.3.6__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 (148) hide show
  1. kon_coding_agent-0.3.6/.github/workflows/test.yml +33 -0
  2. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/.kon/skills/kon-release-publish/SKILL.md +16 -9
  3. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/AGENTS.md +1 -0
  4. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/CHANGELOG.md +86 -0
  5. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/PKG-INFO +4 -8
  6. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/README.md +0 -6
  7. kon_coding_agent-0.3.6/docs/code-health-scan.md +144 -0
  8. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/pyproject.toml +9 -3
  9. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/config.py +10 -0
  10. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/defaults/config.toml +8 -0
  11. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/base.py +1 -1
  12. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/openai_codex_responses.py +21 -5
  13. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/openai_completions.py +7 -1
  14. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/openai_responses.py +3 -0
  15. kon_coding_agent-0.3.6/src/kon/notify.py +30 -0
  16. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/session.py +144 -13
  17. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/edit.py +1 -1
  18. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/find.py +1 -3
  19. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/grep.py +1 -3
  20. kon_coding_agent-0.3.6/src/kon/tools/web_fetch.py +160 -0
  21. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/turn.py +4 -6
  22. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/app.py +36 -21
  23. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/blocks.py +13 -6
  24. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/chat.py +83 -13
  25. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/commands.py +33 -90
  26. kon_coding_agent-0.3.6/src/kon/ui/export.py +693 -0
  27. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/floating_list.py +70 -8
  28. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/formatting.py +3 -0
  29. kon_coding_agent-0.3.6/src/kon/ui/latex.py +349 -0
  30. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/session_ui.py +14 -52
  31. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/styles.py +19 -3
  32. kon_coding_agent-0.3.6/src/kon/ui/welcome.py +85 -0
  33. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/widgets.py +116 -42
  34. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/context/test_skills.py +1 -1
  35. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_handoff.py +4 -6
  36. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_launch_warnings.py +1 -1
  37. kon_coding_agent-0.3.6/tests/test_notifications_config.py +64 -0
  38. kon_coding_agent-0.3.6/tests/test_notify.py +46 -0
  39. kon_coding_agent-0.3.6/tests/test_session_queries.py +61 -0
  40. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_session_resume.py +1 -5
  41. kon_coding_agent-0.3.6/tests/test_ui_notifications.py +32 -0
  42. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_edit_display.py +2 -2
  43. kon_coding_agent-0.3.6/tests/ui/test_latex.py +60 -0
  44. kon_coding_agent-0.3.6/tests/ui/test_styles.py +16 -0
  45. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/uv.lock +122 -222
  46. kon_coding_agent-0.3.4/src/kon/tools/web_fetch.py +0 -79
  47. kon_coding_agent-0.3.4/src/kon/ui/export.py +0 -330
  48. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/.gitignore +0 -0
  49. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/.kon/skills/kon-tmux-test/SKILL.md +0 -0
  50. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/.kon/skills/kon-tmux-test/run-e2e-tests.sh +0 -0
  51. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/.kon/skills/kon-tmux-test/setup-test-project.sh +0 -0
  52. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/.python-version +0 -0
  53. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/LICENSE +0 -0
  54. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/docs/architecture-review.md +0 -0
  55. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/docs/images/kon-screenshot.png +0 -0
  56. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/docs/local-models.md +0 -0
  57. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/scripts/show_themes.py +0 -0
  58. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/__init__.py +0 -0
  59. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/async_utils.py +0 -0
  60. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/builtin_skills/init/SKILL.md +0 -0
  61. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/context/__init__.py +0 -0
  62. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/context/_xml.py +0 -0
  63. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/context/agent_mds.py +0 -0
  64. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/context/git.py +0 -0
  65. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/context/loader.py +0 -0
  66. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/context/skills.py +0 -0
  67. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/core/__init__.py +0 -0
  68. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/core/compaction.py +0 -0
  69. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/core/handoff.py +0 -0
  70. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/core/types.py +0 -0
  71. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/defaults/__init__.py +0 -0
  72. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/events.py +0 -0
  73. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/__init__.py +0 -0
  74. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/models.py +0 -0
  75. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/oauth/__init__.py +0 -0
  76. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/oauth/copilot.py +0 -0
  77. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/oauth/openai.py +0 -0
  78. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/__init__.py +0 -0
  79. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/anthropic.py +0 -0
  80. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/azure_ai_foundry.py +0 -0
  81. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/copilot.py +0 -0
  82. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/copilot_anthropic.py +0 -0
  83. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/github_copilot_headers.py +0 -0
  84. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/mock.py +0 -0
  85. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/openai_compat.py +0 -0
  86. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/llm/providers/sanitize.py +0 -0
  87. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/loop.py +0 -0
  88. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/permissions.py +0 -0
  89. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/py.typed +0 -0
  90. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/themes.py +0 -0
  91. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/__init__.py +0 -0
  92. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/_read_image.py +0 -0
  93. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/_tool_utils.py +0 -0
  94. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/base.py +0 -0
  95. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/bash.py +0 -0
  96. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/read.py +0 -0
  97. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/web_search.py +0 -0
  98. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools/write.py +0 -0
  99. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/tools_manager.py +0 -0
  100. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/__init__.py +0 -0
  101. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/app_protocol.py +0 -0
  102. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/autocomplete.py +0 -0
  103. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/clipboard.py +0 -0
  104. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/input.py +0 -0
  105. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/path_complete.py +0 -0
  106. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/prompt_history.py +0 -0
  107. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/ui/selection_mode.py +0 -0
  108. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/src/kon/update_check.py +0 -0
  109. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/conftest.py +0 -0
  110. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/context/test_agents.py +0 -0
  111. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/llm/__init__.py +0 -0
  112. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/llm/test_anthropic_provider.py +0 -0
  113. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/llm/test_azure_ai_foundry_provider.py +0 -0
  114. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/llm/test_mock_provider.py +0 -0
  115. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/llm/test_openai_codex_provider_errors.py +0 -0
  116. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/llm/test_openai_oauth.py +0 -0
  117. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_agentic_loop.py +0 -0
  118. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_cli_auth_flags.py +0 -0
  119. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_cli_provider_resolution.py +0 -0
  120. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_compaction.py +0 -0
  121. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_config_binaries.py +0 -0
  122. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_config_error_fallback.py +0 -0
  123. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_config_injection.py +0 -0
  124. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_config_migration.py +0 -0
  125. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_handoff_link_interrupt.py +0 -0
  126. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_local_auth_config.py +0 -0
  127. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_model_provider_resolution.py +0 -0
  128. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_openai_compat.py +0 -0
  129. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_permissions.py +0 -0
  130. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_session_persistence.py +0 -0
  131. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_system_prompt.py +0 -0
  132. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_system_prompt_git_context.py +0 -0
  133. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_tools_manager.py +0 -0
  134. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_update_check.py +0 -0
  135. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/test_update_notice_behavior.py +0 -0
  136. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_diff.py +0 -0
  137. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_edit.py +0 -0
  138. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_read.py +0 -0
  139. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_read_image.py +0 -0
  140. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_read_image_integration.py +0 -0
  141. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_subprocess_cancellation.py +0 -0
  142. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/tools/test_write.py +0 -0
  143. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/ui/test_autocomplete.py +0 -0
  144. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/ui/test_floating_list.py +0 -0
  145. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/ui/test_input_handoff.py +0 -0
  146. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/ui/test_input_paste.py +0 -0
  147. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/ui/test_prompt_history.py +0 -0
  148. {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.6}/tests/ui/test_status_line.py +0 -0
@@ -0,0 +1,33 @@
1
+ name: Test
2
+
3
+ on: [push, pull_request]
4
+
5
+ permissions:
6
+ contents: read
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.12","3.13", "3.14"]
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+ - name: Set up Python ${{ matrix.python-version }}
17
+ uses: actions/setup-python@v4
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+ cache: pip
21
+ cache-dependency-path: pyproject.toml
22
+ - name: Cache models
23
+ uses: actions/cache@v3
24
+ with:
25
+ path: ~/.cache
26
+ key: ${{ runner.os }}-torch-
27
+ - name: Install dependencies
28
+ run: |
29
+ pip install . --group dev
30
+ - name: Run tests
31
+ run: |
32
+ python -m pytest -s
33
+
@@ -33,38 +33,44 @@ Use this skill when the user asks to cut a new Kon version, tag it, publish to P
33
33
  - `git status --short --branch` must be clean (or confirm with user)
34
34
  - `git tag --list` and `git log --oneline <prev_tag>..HEAD` to summarize changes
35
35
 
36
- 2. **Version bump**
36
+ 2. **Update CHANGELOG.md**
37
+ - Replace the `## [Unreleased]` section's `- No changes yet.` with a new versioned heading: `## <version> - YYYY-MM-DD`
38
+ - Use `git log --oneline <prev_tag>..HEAD` to categorize changes into `### Added`, `### Changed`, `### Fixed` sections
39
+ - Credit external contributors with `- @username`
40
+ - Commit message: `docs: update changelog for <version>`
41
+
42
+ 3. **Version bump**
37
43
  - Update version in all 3 files above
38
44
 
39
- 3. **Quality gates**
45
+ 4. **Quality gates**
40
46
  - `uv run ruff format .`
41
47
  - `uv run ruff check .`
42
48
  - `uv run pyright .`
43
49
  - `uv run pytest`
44
50
 
45
- 4. **Commit**
51
+ 5. **Commit**
46
52
  - Commit message: `build: bump version to <version>`
47
53
 
48
- 5. **Tag**
54
+ 6. **Tag**
49
55
  - Annotated tag: `git tag -a v<version> -m "v<version> ..."`
50
- - Include concise changes since previous tag bullets
56
+ - Include concise "changes since previous tag" bullets
51
57
 
52
- 6. **Push**
58
+ 7. **Push**
53
59
  - `git push origin main`
54
60
  - `git push origin v<version>`
55
61
 
56
- 7. **Build + verify artifacts**
62
+ 8. **Build + verify artifacts**
57
63
  - `rm -rf dist && uv build`
58
64
  - `uv run python -m twine check dist/*`
59
65
 
60
- 8. **Publish to PyPI**
66
+ 9. **Publish to PyPI**
61
67
  - Prefer token file if present (example `~/.pypi-token`):
62
68
  - `TWINE_USERNAME=__token__ TWINE_PASSWORD="$(< ~/.pypi-token)" uv run python -m twine upload dist/*`
63
69
  - Verify:
64
70
  - `https://pypi.org/project/kon-coding-agent/<version>/`
65
71
  - `https://pypi.org/pypi/kon-coding-agent/json` reports latest version
66
72
 
67
- 9. **Create GitHub release**
73
+ 10. **Create GitHub release**
68
74
  - If token exists at `~/.github-token`, call Releases API:
69
75
  - `POST /repos/<owner>/<repo>/releases` with:
70
76
  - `tag_name: v<version>`
@@ -83,6 +89,7 @@ Use this skill when the user asks to cut a new Kon version, tag it, publish to P
83
89
 
84
90
  ## Output checklist to report
85
91
 
92
+ - Changelog updated for `<version>`
86
93
  - Version bumped in all files
87
94
  - Checks passed
88
95
  - Commit hash
@@ -4,6 +4,7 @@
4
4
 
5
5
  - Don't add trivial docstrings. Only add docstrings when explaining complex functionality.
6
6
  - This project uses `uv`. Run `uv run ruff format .` after editing or creating any files.
7
+ - If generating and running a Python script, use `uv run python` instead of `python`.
7
8
 
8
9
  ## Testing
9
10
 
@@ -6,6 +6,92 @@ All notable changes to this project will be documented in this file.
6
6
 
7
7
  - No changes yet.
8
8
 
9
+ ## 0.3.6 - 2026-04-23
10
+
11
+ ### Added
12
+
13
+ - Configurable terminal bell notifications on response completion.
14
+ - Render LaTeX math as Unicode in markdown output - @toojays.
15
+ - Style approval popup with button-like controls and panel background.
16
+ - Permission popup title card and improved UI formatting.
17
+
18
+ ### Changed
19
+
20
+ - Improved UI for approval popup.
21
+ - Reduce LaTeX preprocessing overhead.
22
+ - Improved Codex SSE error extraction and retry on transient errors.
23
+
24
+ ### Fixed
25
+
26
+ - Rewrite web_fetch to bypass bot-detection, preserve indentation, and harden against SSRF - @Meltedd (#28, #29).
27
+ - Remove unused turn streaming state.
28
+ - Remove unused tool imports.
29
+ - Remove empty blocks.
30
+
31
+ ## 0.3.5 - 2026-04-18
32
+
33
+ ### Added
34
+
35
+ - Standalone session HTML export with self-contained styling.
36
+ - Configurable request timeout for API calls - @jspruit.
37
+ - GitHub CI tests for Python 3.12–3.13 - @sukhbinder.
38
+ - Width-aware popup lists and queue display.
39
+
40
+ ### Changed
41
+
42
+ - Highlight color applied to the second column in floating lists.
43
+ - Batch scroll during streaming, cache query_one lookups, pause spinner timer when idle.
44
+ - Diff line length capped at 200 characters.
45
+
46
+ ### Fixed
47
+
48
+ - Persist thinking level in session header and change all defaults to high.
49
+ - Normalize OpenAI provider imports.
50
+ - Widen resume popup labels.
51
+ - Remove unused UI app import.
52
+
53
+ ### Performance
54
+
55
+ - Added `gc.freeze()` and `PAUSE_GC_ON_SCROLL` to reduce GC stutters.
56
+
57
+ ## 0.3.4 - 2026-04-10
58
+
59
+ ### Fixed
60
+
61
+ - Fixed Windows UTF-8 encoding errors in file operations - @sukhbinder.
62
+ - Fixed local Gemma model thinking block compatibility.
63
+ - Removed duplicate force-include for builtin skills in build config.
64
+
65
+ ### Changed
66
+
67
+ - Updated local model documentation.
68
+
69
+ ## 0.3.3 - 2026-04-08
70
+
71
+ ### Added
72
+
73
+ - Added queued agent steering between turns - @0xku.
74
+ - Added bundled `/init` slash command for project scaffolding - @0xku.
75
+ - Added help info for queue and steer queue commands.
76
+ - Added GLM-5.1 support for zai provider.
77
+
78
+ ### Changed
79
+
80
+ - Improved read tool directory listings.
81
+ - Updated README with steer queue documentation.
82
+ - Added `$` icon for bash, `%` for web tools, and `←` for edit tool.
83
+ - Used muted color for shortcut key hints in exit/delete prompts.
84
+
85
+ ### Fixed
86
+
87
+ - Let ESC interrupt retry backoff immediately - @0xku.
88
+ - Fixed OpenAI login stdin leak by removing orphaned thread - @Meltedd.
89
+ - Fixed OpenAI and Anthropic local compat with auth flags.
90
+ - Fixed interrupt handling before handoff thread switch.
91
+ - Fixed subprocess communication drain on cancellation/timeout.
92
+ - Added zipfile path traversal validation.
93
+ - Removed token throughput metrics.
94
+
9
95
  ## 0.3.2 - 2026-03-22
10
96
 
11
97
  ### Added
@@ -1,19 +1,21 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kon-coding-agent
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Minimal coding agent
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
7
7
  Requires-Dist: aiofiles>=25.1.0
8
8
  Requires-Dist: aiohttp>=3.13.3
9
9
  Requires-Dist: anthropic>=0.79.0
10
+ Requires-Dist: curl-cffi>=0.15.0
10
11
  Requires-Dist: ddgs>=9.0.0
12
+ Requires-Dist: html-to-markdown>=3.1.0
11
13
  Requires-Dist: openai>=2.21.0
12
14
  Requires-Dist: pillow>=12.1.1
13
15
  Requires-Dist: pydantic>=2.12.5
16
+ Requires-Dist: readability-lxml>=0.8.4
14
17
  Requires-Dist: rich>=14.3.2
15
18
  Requires-Dist: textual>=8.0.0
16
- Requires-Dist: trafilatura>=2.0.0
17
19
  Description-Content-Type: text/markdown
18
20
 
19
21
  <h1 align="center">Kon</h1>
@@ -475,12 +477,6 @@ If `fd` or `rg` are missing, Kon can download them automatically.
475
477
 
476
478
  ---
477
479
 
478
- ## Documentation
479
-
480
- - [Local models](docs/local-models.md) - Running Kon with local OpenAI-compatible models, plus tested setups and example commands.
481
-
482
- ---
483
-
484
480
  ## Acknowledgements
485
481
 
486
482
  - Kon takes significant inspiration from [pi coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent), especially around philosophy and UI direction.
@@ -457,12 +457,6 @@ If `fd` or `rg` are missing, Kon can download them automatically.
457
457
 
458
458
  ---
459
459
 
460
- ## Documentation
461
-
462
- - [Local models](docs/local-models.md) - Running Kon with local OpenAI-compatible models, plus tested setups and example commands.
463
-
464
- ---
465
-
466
460
  ## Acknowledgements
467
461
 
468
462
  - Kon takes significant inspiration from [pi coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent), especially around philosophy and UI direction.
@@ -0,0 +1,144 @@
1
+ # Code Health Scan: Additional Notable Issues
2
+
3
+ This note captures only the additional issues found in a fresh repo scan that are **not** the same as the already-known architectural concerns in `docs/architecture-review.md`.
4
+
5
+ The baseline conclusion from the earlier review still stands:
6
+
7
+ - the core runtime is strong
8
+ - the TUI still owns too much runtime/session orchestration
9
+ - the large controller/runtime-manager refactor is deferred for now
10
+
11
+ This document is intentionally narrower. It records only the standout issue and the smaller cleanup opportunities found in the current repo state after the recent cleanup pass.
12
+
13
+ ## Overall verdict
14
+
15
+ Aside from the already-documented UI/runtime orchestration boundary issue, the repo looks to be in decent shape overall.
16
+
17
+ Notable signals:
18
+
19
+ - test suite passed cleanly
20
+ - pyright passed cleanly
21
+ - only a few lint issues remained
22
+
23
+ So this is **not** a case where the repo appears to have multiple additional architectural problems lurking elsewhere. The main new thing worth tracking is a state-consistency problem around provider/model transitions, plus a few smaller cleanup items.
24
+
25
+ ## Major issue
26
+
27
+ ### Provider/model transition paths are not transactional
28
+
29
+ The main additional issue is that some provider/model/session transition flows update app state before it is certain that the replacement provider/runtime state can be constructed successfully.
30
+
31
+ Relevant files:
32
+
33
+ - `src/kon/ui/commands.py`
34
+ - `src/kon/ui/session_ui.py`
35
+
36
+ ### Where it shows up
37
+
38
+ #### `src/kon/ui/commands.py::_select_model`
39
+
40
+ This path updates:
41
+
42
+ - `self._model`
43
+ - `self._model_provider`
44
+
45
+ before provider recreation is guaranteed to succeed.
46
+
47
+ If `_create_provider(...)` fails, the UI reports the error, but some selected-model state may already have been changed while the active provider/agent runtime is still using the old provider instance.
48
+
49
+ #### `src/kon/ui/session_ui.py::_load_session`
50
+
51
+ This path loads session metadata and updates model/provider-related state while also trying to reconcile the active provider.
52
+
53
+ If provider recreation fails during session load, the code reports the error, but can still leave partially updated state behind:
54
+
55
+ - loaded session state may now be active
56
+ - selected model/provider values may reflect the resumed session
57
+ - the provider instance may still be the old one or only partially reconfigured
58
+
59
+ ### Why this matters
60
+
61
+ This is not a large-architecture problem, but it is a real correctness risk.
62
+
63
+ It can produce subtle mismatches between:
64
+
65
+ - selected model/provider UI state
66
+ - active provider config
67
+ - agent runtime state
68
+ - resumed session metadata
69
+
70
+ Those failures are harder to reason about than a simple hard error because the app can continue running in a partially updated state.
71
+
72
+ ### Suggested direction
73
+
74
+ Without doing the large architecture refactor, the safer short-term fix would be to make these transitions more atomic:
75
+
76
+ 1. compute the target model/provider/session state first
77
+ 2. build or validate the replacement provider first
78
+ 3. only commit the new state to `self._model`, `self._model_provider`, `self._provider`, `self._session`, and `self._agent` after success
79
+ 4. otherwise leave the old runtime state untouched
80
+
81
+ Even a small helper that stages the new state before assignment would reduce the sync-risk significantly.
82
+
83
+ ## Small cleanup opportunities
84
+
85
+ ### 1. `CompactionEntry.first_kept_entry_id` is currently misleading
86
+
87
+ Relevant file:
88
+
89
+ - `src/kon/session.py`
90
+
91
+ `CompactionEntry` stores `first_kept_entry_id`, and comments imply that the compacted view depends on it.
92
+
93
+ However, `Session.messages` currently reconstructs the compacted view by:
94
+
95
+ - finding the last compaction entry
96
+ - inserting the synthetic summary pair
97
+ - including message entries after the compaction entry itself
98
+
99
+ It does **not** currently use `first_kept_entry_id` to decide what to retain.
100
+
101
+ This is not a functional bug in current usage because existing callers/tests append compaction entries in a way that still makes the behavior correct. But the data model and implementation intent are slightly out of sync, which makes the field more confusing than helpful right now.
102
+
103
+ Small fix options:
104
+
105
+ - actually use `first_kept_entry_id` in `Session.messages`, or
106
+ - simplify the field/comment contract if the compaction-entry position is the real source of truth
107
+
108
+ ### 2. System-prompt fallback logic is still duplicated across UI mixins
109
+
110
+ Relevant files:
111
+
112
+ - `src/kon/ui/commands.py`
113
+ - `src/kon/ui/session_ui.py`
114
+
115
+ Both files define the same `_resolve_system_prompt(...)` helper:
116
+
117
+ - use persisted `session.system_prompt` when available
118
+ - otherwise rebuild with `build_system_prompt(...)`
119
+
120
+ This is a small issue, not a major design problem, but it means the recent centralization is still only partial. If the fallback behavior changes again, both copies will need to stay in sync.
121
+
122
+ Small fix option:
123
+
124
+ - move the helper to one shared non-duplicated location used by both mixins/app paths
125
+
126
+ ### 3. Lint cleanup remains in a few tool modules
127
+
128
+ Relevant files:
129
+
130
+ - `src/kon/tools/find.py`
131
+ - `src/kon/tools/grep.py`
132
+ - `src/kon/tools/web_fetch.py`
133
+
134
+ Current lint output shows unused imports of `truncate_text` in these files.
135
+
136
+ This is only a hygiene issue, but it is a useful signal that a full lint pass likely did not happen after some recent edits.
137
+
138
+ ## Final assessment
139
+
140
+ The repo looks fine overall.
141
+
142
+ Aside from the already-known concerns in `docs/architecture-review.md`, the only additional issue that really stands out is the non-transactional provider/model/session transition behavior.
143
+
144
+ The other findings are small cleanup opportunities rather than signs of deeper architectural trouble.
@@ -14,7 +14,7 @@ default = true
14
14
 
15
15
  [project]
16
16
  name = "kon-coding-agent"
17
- version = "0.3.4"
17
+ version = "0.3.6"
18
18
  description = "Minimal coding agent"
19
19
  readme = "README.md"
20
20
  requires-python = ">=3.12"
@@ -22,13 +22,15 @@ dependencies = [
22
22
  "aiofiles>=25.1.0",
23
23
  "aiohttp>=3.13.3",
24
24
  "anthropic>=0.79.0",
25
+ "curl-cffi>=0.15.0",
26
+ "ddgs>=9.0.0",
27
+ "html-to-markdown>=3.1.0",
25
28
  "openai>=2.21.0",
26
29
  "pillow>=12.1.1",
27
30
  "pydantic>=2.12.5",
31
+ "readability-lxml>=0.8.4",
28
32
  "rich>=14.3.2",
29
33
  "textual>=8.0.0",
30
- "ddgs>=9.0.0",
31
- "trafilatura>=2.0.0",
32
34
  ]
33
35
 
34
36
  [dependency-groups]
@@ -60,6 +62,10 @@ select = [
60
62
  "RUF", # ruff-specific rules
61
63
  ]
62
64
 
65
+ [tool.ruff.lint.per-file-ignores]
66
+ "src/kon/ui/latex.py" = ["RUF001"]
67
+ "tests/ui/test_latex.py" = ["RUF001"]
68
+
63
69
  [tool.ruff.lint.isort]
64
70
  split-on-trailing-comma = false
65
71
 
@@ -76,6 +76,7 @@ class LLMConfig(BaseModel):
76
76
  default_thinking_level: str
77
77
  system_prompt: SystemPromptConfig
78
78
  tool_call_idle_timeout_seconds: float = 180
79
+ request_timeout_seconds: float = 600
79
80
  auth: AuthConfig = AuthConfig()
80
81
 
81
82
 
@@ -97,6 +98,10 @@ class ToolsConfig(BaseModel):
97
98
  extra: list[str] = []
98
99
 
99
100
 
101
+ class NotificationsConfig(BaseModel):
102
+ enabled: bool = False
103
+
104
+
100
105
  class ConfigSchema(BaseModel):
101
106
  meta: MetaConfig
102
107
  llm: LLMConfig
@@ -105,6 +110,7 @@ class ConfigSchema(BaseModel):
105
110
  agent: AgentConfig
106
111
  tools: ToolsConfig = ToolsConfig()
107
112
  permissions: PermissionsConfig
113
+ notifications: NotificationsConfig = NotificationsConfig()
108
114
 
109
115
 
110
116
  # =================================================================================================
@@ -193,6 +199,10 @@ class Config:
193
199
  def tools(self) -> ToolsConfig:
194
200
  return self._parsed.tools
195
201
 
202
+ @property
203
+ def notifications(self) -> NotificationsConfig:
204
+ return self._parsed.notifications
205
+
196
206
  @property
197
207
  def binaries(self) -> _BinariesConfig:
198
208
  return _BinariesConfig(AVAILABLE_BINARIES)
@@ -11,6 +11,9 @@ default_thinking_level = "high"
11
11
  # Abort a tool call if it stays idle for this long during a turn.
12
12
  # Helps prevent stalled tool executions from hanging the agent loop.
13
13
  tool_call_idle_timeout_seconds = 180
14
+ # HTTP request timeout for LLM API calls (in seconds).
15
+ # Local models (e.g. llama.cpp) may need a higher value for long compaction requests.
16
+ request_timeout_seconds = 600
14
17
 
15
18
  [llm.auth]
16
19
  # Auth policy for OpenAI-compatible and Anthropic-compatible endpoints.
@@ -70,3 +73,8 @@ collapse_thinking = true
70
73
  # "prompt" asks before edits/writes and other mutating actions.
71
74
  # "auto" allows tool calls without approval prompts.
72
75
  mode = "prompt" # "prompt" or "auto"
76
+
77
+ [notifications]
78
+ # Ring the terminal bell when kon finishes a task or waits for tool approval.
79
+ # Disabled by default.
80
+ enabled = false
@@ -77,7 +77,7 @@ class ProviderConfig:
77
77
  model: str = ""
78
78
  max_tokens: int = 8192
79
79
  temperature: float | None = None
80
- thinking_level: str = "medium"
80
+ thinking_level: str = "high"
81
81
  provider: str | None = None
82
82
  session_id: str | None = None
83
83
  openai_compat_auth_mode: AuthMode = "auto"
@@ -279,11 +279,26 @@ class OpenAICodexResponsesProvider(BaseProvider):
279
279
  yield StreamDone(stop_reason=stop_reason)
280
280
  return
281
281
 
282
- elif event_type in {"response.failed", "error"}:
282
+ elif event_type == "error":
283
+ code = event.get("code")
283
284
  message = event.get("message")
284
- if not isinstance(message, str):
285
- message = "Codex response failed"
286
- yield StreamError(error=message)
285
+ if isinstance(message, str) and message:
286
+ yield StreamError(error=f"Codex error: {message}")
287
+ elif isinstance(code, str) and code:
288
+ yield StreamError(error=f"Codex error: {code}")
289
+ else:
290
+ yield StreamError(error=f"Codex error: {json.dumps(event)}")
291
+ return
292
+
293
+ elif event_type == "response.failed":
294
+ response_obj = event.get("response")
295
+ msg = None
296
+ if isinstance(response_obj, dict):
297
+ err = response_obj.get("error")
298
+ if isinstance(err, dict):
299
+ msg = err.get("message")
300
+ err_msg = msg if isinstance(msg, str) and msg else "Codex response failed"
301
+ yield StreamError(error=err_msg)
287
302
  return
288
303
  finally:
289
304
  await session.close()
@@ -321,7 +336,8 @@ class OpenAICodexResponsesProvider(BaseProvider):
321
336
  return StopReason.STOP
322
337
 
323
338
  def should_retry_for_error(self, error: Exception) -> bool:
324
- return False
339
+ msg = str(error).lower()
340
+ return any(kw in msg for kw in ("429", "rate_limit", "server_error", "502", "503", "504"))
325
341
 
326
342
 
327
343
  def is_openai_logged_in() -> bool:
@@ -10,6 +10,8 @@ from openai.types.chat import (
10
10
  ChatCompletionToolParam,
11
11
  )
12
12
 
13
+ from kon import config as kon_config
14
+
13
15
  from ...core.types import (
14
16
  AssistantMessage,
15
17
  ImageContent,
@@ -99,7 +101,11 @@ class OpenAICompletionsProvider(BaseProvider):
99
101
  "Set OPENAI_API_KEY or ZAI_API_KEY environment variable, "
100
102
  'or configure llm.auth.openai_compat = "auto"/"none" for local endpoints.'
101
103
  )
102
- self._client = AsyncOpenAI(api_key=api_key, base_url=config.base_url)
104
+ self._client = AsyncOpenAI(
105
+ api_key=api_key,
106
+ base_url=config.base_url,
107
+ timeout=kon_config.llm.request_timeout_seconds,
108
+ )
103
109
  self._compat = _detect_compat(
104
110
  config.provider or "", config.base_url or "", config.model or ""
105
111
  )
@@ -4,6 +4,8 @@ from typing import Any
4
4
 
5
5
  from openai import APIStatusError, AsyncOpenAI, RateLimitError
6
6
 
7
+ from kon import config as kon_config
8
+
7
9
  from ...core.types import (
8
10
  AssistantMessage,
9
11
  ImageContent,
@@ -51,6 +53,7 @@ class OpenAIResponsesProvider(BaseProvider):
51
53
  api_key=self.config.api_key,
52
54
  base_url=self.config.base_url,
53
55
  default_headers=self._headers,
56
+ timeout=kon_config.llm.request_timeout_seconds,
54
57
  )
55
58
  return self._client
56
59
 
@@ -0,0 +1,30 @@
1
+ import os
2
+ import time
3
+
4
+ _BELL_DEBOUNCE_S = 0.5
5
+ _last_bell_time: float = 0.0
6
+
7
+
8
+ def _raw_write(data: bytes) -> None:
9
+ try:
10
+ fd = os.open("/dev/tty", os.O_WRONLY | os.O_NOCTTY)
11
+ try:
12
+ os.write(fd, data)
13
+ finally:
14
+ os.close(fd)
15
+ except OSError:
16
+ os.write(2, data)
17
+
18
+
19
+ def _bell() -> None:
20
+ global _last_bell_time
21
+ now = time.monotonic()
22
+ if now - _last_bell_time < _BELL_DEBOUNCE_S:
23
+ return
24
+ _last_bell_time = now
25
+ _raw_write(b"\a")
26
+
27
+
28
+ def notify(title: str, message: str) -> None:
29
+ del title, message
30
+ _bell()