kon-coding-agent 0.3.4__tar.gz → 0.3.5__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.5/.github/workflows/test.yml +33 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/.kon/skills/kon-release-publish/SKILL.md +16 -9
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/AGENTS.md +1 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/CHANGELOG.md +64 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/PKG-INFO +1 -1
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/pyproject.toml +1 -1
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/config.py +1 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/defaults/config.toml +3 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/base.py +1 -1
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/openai_completions.py +7 -1
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/openai_responses.py +3 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/session.py +144 -13
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/edit.py +1 -1
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/app.py +22 -21
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/chat.py +17 -2
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/commands.py +26 -72
- kon_coding_agent-0.3.5/src/kon/ui/export.py +693 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/floating_list.py +70 -8
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/session_ui.py +14 -52
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/widgets.py +116 -42
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/context/test_skills.py +1 -1
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_handoff.py +4 -6
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_launch_warnings.py +1 -1
- kon_coding_agent-0.3.5/tests/test_session_queries.py +61 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_session_resume.py +1 -5
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_edit_display.py +2 -2
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/uv.lock +1 -1
- kon_coding_agent-0.3.4/src/kon/ui/export.py +0 -330
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/.gitignore +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/.kon/skills/kon-tmux-test/SKILL.md +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/.kon/skills/kon-tmux-test/run-e2e-tests.sh +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/.kon/skills/kon-tmux-test/setup-test-project.sh +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/.python-version +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/LICENSE +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/README.md +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/docs/architecture-review.md +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/docs/images/kon-screenshot.png +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/docs/local-models.md +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/scripts/show_themes.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/async_utils.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/builtin_skills/init/SKILL.md +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/context/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/context/_xml.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/context/agent_mds.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/context/git.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/context/loader.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/context/skills.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/core/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/core/compaction.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/core/handoff.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/core/types.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/defaults/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/events.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/models.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/oauth/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/oauth/copilot.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/oauth/openai.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/anthropic.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/azure_ai_foundry.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/copilot.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/copilot_anthropic.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/github_copilot_headers.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/mock.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/openai_codex_responses.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/openai_compat.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/sanitize.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/loop.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/permissions.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/py.typed +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/themes.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/_read_image.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/_tool_utils.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/base.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/bash.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/find.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/grep.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/read.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/web_fetch.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/web_search.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools/write.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/tools_manager.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/turn.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/app_protocol.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/autocomplete.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/blocks.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/clipboard.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/formatting.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/input.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/path_complete.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/prompt_history.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/selection_mode.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/ui/styles.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/update_check.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/conftest.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/context/test_agents.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/llm/__init__.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/llm/test_anthropic_provider.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/llm/test_azure_ai_foundry_provider.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/llm/test_mock_provider.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/llm/test_openai_codex_provider_errors.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/llm/test_openai_oauth.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_agentic_loop.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_cli_auth_flags.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_cli_provider_resolution.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_compaction.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_config_binaries.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_config_error_fallback.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_config_injection.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_config_migration.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_handoff_link_interrupt.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_local_auth_config.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_model_provider_resolution.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_openai_compat.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_permissions.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_session_persistence.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_system_prompt.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_system_prompt_git_context.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_tools_manager.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_update_check.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/test_update_notice_behavior.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_diff.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_edit.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_read.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_read_image.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_read_image_integration.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_subprocess_cancellation.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/tools/test_write.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/ui/test_autocomplete.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/ui/test_floating_list.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/ui/test_input_handoff.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/ui/test_input_paste.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/tests/ui/test_prompt_history.py +0 -0
- {kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/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. **
|
|
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
|
-
|
|
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
|
-
|
|
51
|
+
5. **Commit**
|
|
46
52
|
- Commit message: `build: bump version to <version>`
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
6. **Tag**
|
|
49
55
|
- Annotated tag: `git tag -a v<version> -m "v<version> ..."`
|
|
50
|
-
- Include concise
|
|
56
|
+
- Include concise "changes since previous tag" bullets
|
|
51
57
|
|
|
52
|
-
|
|
58
|
+
7. **Push**
|
|
53
59
|
- `git push origin main`
|
|
54
60
|
- `git push origin v<version>`
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
8. **Build + verify artifacts**
|
|
57
63
|
- `rm -rf dist && uv build`
|
|
58
64
|
- `uv run python -m twine check dist/*`
|
|
59
65
|
|
|
60
|
-
|
|
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
|
-
|
|
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,70 @@ All notable changes to this project will be documented in this file.
|
|
|
6
6
|
|
|
7
7
|
- No changes yet.
|
|
8
8
|
|
|
9
|
+
## 0.3.5 - 2026-04-18
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Standalone session HTML export with self-contained styling.
|
|
14
|
+
- Configurable request timeout for API calls - @jspruit.
|
|
15
|
+
- GitHub CI tests for Python 3.12–3.13 - @sukhbinder.
|
|
16
|
+
- Width-aware popup lists and queue display.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Highlight color applied to the second column in floating lists.
|
|
21
|
+
- Batch scroll during streaming, cache query_one lookups, pause spinner timer when idle.
|
|
22
|
+
- Diff line length capped at 200 characters.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Persist thinking level in session header and change all defaults to high.
|
|
27
|
+
- Normalize OpenAI provider imports.
|
|
28
|
+
- Widen resume popup labels.
|
|
29
|
+
- Remove unused UI app import.
|
|
30
|
+
|
|
31
|
+
### Performance
|
|
32
|
+
|
|
33
|
+
- Added `gc.freeze()` and `PAUSE_GC_ON_SCROLL` to reduce GC stutters.
|
|
34
|
+
|
|
35
|
+
## 0.3.4 - 2026-04-10
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Fixed Windows UTF-8 encoding errors in file operations - @sukhbinder.
|
|
40
|
+
- Fixed local Gemma model thinking block compatibility.
|
|
41
|
+
- Removed duplicate force-include for builtin skills in build config.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- Updated local model documentation.
|
|
46
|
+
|
|
47
|
+
## 0.3.3 - 2026-04-08
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- Added queued agent steering between turns - @0xku.
|
|
52
|
+
- Added bundled `/init` slash command for project scaffolding - @0xku.
|
|
53
|
+
- Added help info for queue and steer queue commands.
|
|
54
|
+
- Added GLM-5.1 support for zai provider.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- Improved read tool directory listings.
|
|
59
|
+
- Updated README with steer queue documentation.
|
|
60
|
+
- Added `$` icon for bash, `%` for web tools, and `←` for edit tool.
|
|
61
|
+
- Used muted color for shortcut key hints in exit/delete prompts.
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- Let ESC interrupt retry backoff immediately - @0xku.
|
|
66
|
+
- Fixed OpenAI login stdin leak by removing orphaned thread - @Meltedd.
|
|
67
|
+
- Fixed OpenAI and Anthropic local compat with auth flags.
|
|
68
|
+
- Fixed interrupt handling before handoff thread switch.
|
|
69
|
+
- Fixed subprocess communication drain on cancellation/timeout.
|
|
70
|
+
- Added zipfile path traversal validation.
|
|
71
|
+
- Removed token throughput metrics.
|
|
72
|
+
|
|
9
73
|
## 0.3.2 - 2026-03-22
|
|
10
74
|
|
|
11
75
|
### Added
|
|
@@ -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.
|
|
@@ -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 = "
|
|
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"
|
{kon_coding_agent-0.3.4 → kon_coding_agent-0.3.5}/src/kon/llm/providers/openai_completions.py
RENAMED
|
@@ -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(
|
|
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
|
|
|
@@ -6,15 +6,18 @@ with a type field. The first line is always the session header.
|
|
|
6
6
|
|
|
7
7
|
Structure:
|
|
8
8
|
{"type": "header", "id": "...", "version": 1, "timestamp": "...",
|
|
9
|
-
"cwd": "...", "system_prompt": "..."}
|
|
9
|
+
"cwd": "...", "system_prompt": "...", "tools": ["read", "edit", ...]}
|
|
10
10
|
{"type": "message", "id": "...", "parent_id": "...", "timestamp": "...", "message": {...}}
|
|
11
11
|
{"type": "message", "id": "...", "parent_id": "...", "timestamp": "...", "message": {...}}
|
|
12
12
|
...
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
import json
|
|
16
18
|
import re
|
|
17
19
|
import uuid
|
|
20
|
+
from dataclasses import dataclass
|
|
18
21
|
from datetime import UTC, datetime
|
|
19
22
|
from pathlib import Path
|
|
20
23
|
from typing import Any, Literal
|
|
@@ -23,7 +26,15 @@ from pydantic import BaseModel
|
|
|
23
26
|
|
|
24
27
|
from kon import CONFIG_DIR_NAME
|
|
25
28
|
|
|
26
|
-
from .core.types import
|
|
29
|
+
from .core.types import (
|
|
30
|
+
AssistantMessage,
|
|
31
|
+
Message,
|
|
32
|
+
StopReason,
|
|
33
|
+
TextContent,
|
|
34
|
+
ToolCall,
|
|
35
|
+
ToolResultMessage,
|
|
36
|
+
UserMessage,
|
|
37
|
+
)
|
|
27
38
|
|
|
28
39
|
CURRENT_VERSION = 1
|
|
29
40
|
_SKILL_TRIGGER_HEADER_RE = re.compile(r"^\[([a-z0-9-]+)\]\s*$")
|
|
@@ -40,6 +51,8 @@ class SessionHeader(BaseModel):
|
|
|
40
51
|
timestamp: str
|
|
41
52
|
cwd: str
|
|
42
53
|
system_prompt: str | None = None
|
|
54
|
+
tools: list[str] | None = None
|
|
55
|
+
initial_thinking_level: str = "high"
|
|
43
56
|
|
|
44
57
|
|
|
45
58
|
class EntryBase(BaseModel):
|
|
@@ -107,6 +120,36 @@ class SessionInfo(BaseModel):
|
|
|
107
120
|
first_message: str
|
|
108
121
|
|
|
109
122
|
|
|
123
|
+
@dataclass(frozen=True)
|
|
124
|
+
class SessionTokenTotals:
|
|
125
|
+
input_tokens: int = 0
|
|
126
|
+
output_tokens: int = 0
|
|
127
|
+
context_tokens: int = 0
|
|
128
|
+
cache_read_tokens: int = 0
|
|
129
|
+
cache_write_tokens: int = 0
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def total_tokens(self) -> int:
|
|
133
|
+
return (
|
|
134
|
+
self.input_tokens
|
|
135
|
+
+ self.output_tokens
|
|
136
|
+
+ self.cache_read_tokens
|
|
137
|
+
+ self.cache_write_tokens
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass(frozen=True)
|
|
142
|
+
class SessionMessageCounts:
|
|
143
|
+
user_messages: int = 0
|
|
144
|
+
assistant_messages: int = 0
|
|
145
|
+
tool_calls: int = 0
|
|
146
|
+
tool_results: int = 0
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def total_messages(self) -> int:
|
|
150
|
+
return self.user_messages + self.assistant_messages
|
|
151
|
+
|
|
152
|
+
|
|
110
153
|
class Session:
|
|
111
154
|
"""
|
|
112
155
|
Manages conversation persistence as append-only JSONL.
|
|
@@ -148,7 +191,7 @@ class Session:
|
|
|
148
191
|
persist: bool = True,
|
|
149
192
|
initial_provider: str | None = None,
|
|
150
193
|
initial_model_id: str | None = None,
|
|
151
|
-
initial_thinking_level: str = "
|
|
194
|
+
initial_thinking_level: str = "high",
|
|
152
195
|
):
|
|
153
196
|
self._id = session_id
|
|
154
197
|
self._cwd = cwd
|
|
@@ -186,6 +229,14 @@ class Session:
|
|
|
186
229
|
def system_prompt(self) -> str | None:
|
|
187
230
|
return self._header.system_prompt if self._header else None
|
|
188
231
|
|
|
232
|
+
@property
|
|
233
|
+
def tools(self) -> list[str] | None:
|
|
234
|
+
return self._header.tools if self._header else None
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def created_at(self) -> str | None:
|
|
238
|
+
return self._header.timestamp if self._header else None
|
|
239
|
+
|
|
189
240
|
@property
|
|
190
241
|
def leaf_id(self) -> str | None:
|
|
191
242
|
return self._leaf_id
|
|
@@ -388,6 +439,72 @@ class Session:
|
|
|
388
439
|
|
|
389
440
|
return None
|
|
390
441
|
|
|
442
|
+
def token_totals(self) -> SessionTokenTotals:
|
|
443
|
+
input_tokens = 0
|
|
444
|
+
output_tokens = 0
|
|
445
|
+
cache_read_tokens = 0
|
|
446
|
+
cache_write_tokens = 0
|
|
447
|
+
context_tokens = 0
|
|
448
|
+
|
|
449
|
+
for entry in self._entries:
|
|
450
|
+
if isinstance(entry, MessageEntry) and isinstance(entry.message, AssistantMessage):
|
|
451
|
+
usage = entry.message.usage
|
|
452
|
+
if usage is None:
|
|
453
|
+
continue
|
|
454
|
+
input_tokens += usage.input_tokens
|
|
455
|
+
output_tokens += usage.output_tokens
|
|
456
|
+
cache_read_tokens += usage.cache_read_tokens
|
|
457
|
+
cache_write_tokens += usage.cache_write_tokens
|
|
458
|
+
context_tokens = (
|
|
459
|
+
usage.input_tokens
|
|
460
|
+
+ usage.output_tokens
|
|
461
|
+
+ usage.cache_read_tokens
|
|
462
|
+
+ usage.cache_write_tokens
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
return SessionTokenTotals(
|
|
466
|
+
input_tokens=input_tokens,
|
|
467
|
+
output_tokens=output_tokens,
|
|
468
|
+
context_tokens=context_tokens,
|
|
469
|
+
cache_read_tokens=cache_read_tokens,
|
|
470
|
+
cache_write_tokens=cache_write_tokens,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
def file_changes_summary(self) -> dict[str, tuple[int, int]]:
|
|
474
|
+
file_changes: dict[str, tuple[int, int]] = {}
|
|
475
|
+
for entry in self._entries:
|
|
476
|
+
if isinstance(entry, MessageEntry) and isinstance(entry.message, ToolResultMessage):
|
|
477
|
+
fc = entry.message.file_changes
|
|
478
|
+
if fc:
|
|
479
|
+
prev_added, prev_removed = file_changes.get(fc.path, (0, 0))
|
|
480
|
+
file_changes[fc.path] = (prev_added + fc.added, prev_removed + fc.removed)
|
|
481
|
+
return file_changes
|
|
482
|
+
|
|
483
|
+
def message_counts(self) -> SessionMessageCounts:
|
|
484
|
+
user_messages = 0
|
|
485
|
+
assistant_messages = 0
|
|
486
|
+
tool_calls = 0
|
|
487
|
+
tool_results = 0
|
|
488
|
+
|
|
489
|
+
for entry in self._entries:
|
|
490
|
+
if not isinstance(entry, MessageEntry):
|
|
491
|
+
continue
|
|
492
|
+
message = entry.message
|
|
493
|
+
if isinstance(message, UserMessage):
|
|
494
|
+
user_messages += 1
|
|
495
|
+
elif isinstance(message, AssistantMessage):
|
|
496
|
+
assistant_messages += 1
|
|
497
|
+
tool_calls += sum(1 for part in message.content if isinstance(part, ToolCall))
|
|
498
|
+
elif isinstance(message, ToolResultMessage):
|
|
499
|
+
tool_results += 1
|
|
500
|
+
|
|
501
|
+
return SessionMessageCounts(
|
|
502
|
+
user_messages=user_messages,
|
|
503
|
+
assistant_messages=assistant_messages,
|
|
504
|
+
tool_calls=tool_calls,
|
|
505
|
+
tool_results=tool_results,
|
|
506
|
+
)
|
|
507
|
+
|
|
391
508
|
@property
|
|
392
509
|
def name(self) -> str | None:
|
|
393
510
|
for entry in reversed(self._entries):
|
|
@@ -435,9 +552,10 @@ class Session:
|
|
|
435
552
|
persist: bool = True,
|
|
436
553
|
provider: str | None = None,
|
|
437
554
|
model_id: str | None = None,
|
|
438
|
-
thinking_level: str = "
|
|
555
|
+
thinking_level: str = "high",
|
|
439
556
|
system_prompt: str | None = None,
|
|
440
|
-
|
|
557
|
+
tools: list[str] | None = None,
|
|
558
|
+
) -> Session:
|
|
441
559
|
session_id = str(uuid.uuid4())
|
|
442
560
|
timestamp = _now_iso()
|
|
443
561
|
|
|
@@ -450,7 +568,12 @@ class Session:
|
|
|
450
568
|
initial_thinking_level=thinking_level,
|
|
451
569
|
)
|
|
452
570
|
session._header = SessionHeader(
|
|
453
|
-
id=session_id,
|
|
571
|
+
id=session_id,
|
|
572
|
+
timestamp=timestamp,
|
|
573
|
+
cwd=cwd,
|
|
574
|
+
system_prompt=system_prompt,
|
|
575
|
+
tools=tools,
|
|
576
|
+
initial_thinking_level=thinking_level,
|
|
454
577
|
)
|
|
455
578
|
|
|
456
579
|
if persist:
|
|
@@ -461,7 +584,7 @@ class Session:
|
|
|
461
584
|
return session
|
|
462
585
|
|
|
463
586
|
@classmethod
|
|
464
|
-
def load(cls, path: Path | str) ->
|
|
587
|
+
def load(cls, path: Path | str) -> Session:
|
|
465
588
|
path = Path(path)
|
|
466
589
|
if not path.exists():
|
|
467
590
|
raise FileNotFoundError(f"Session file not found: {path}")
|
|
@@ -500,7 +623,13 @@ class Session:
|
|
|
500
623
|
if not header:
|
|
501
624
|
raise ValueError(f"Invalid session file (no header): {path}")
|
|
502
625
|
|
|
503
|
-
session = cls(
|
|
626
|
+
session = cls(
|
|
627
|
+
session_id=header.id,
|
|
628
|
+
cwd=header.cwd,
|
|
629
|
+
session_file=path,
|
|
630
|
+
persist=True,
|
|
631
|
+
initial_thinking_level=header.initial_thinking_level,
|
|
632
|
+
)
|
|
504
633
|
session._header = header
|
|
505
634
|
session._entries = entries
|
|
506
635
|
session._by_id = {e.id: e for e in entries}
|
|
@@ -516,9 +645,9 @@ class Session:
|
|
|
516
645
|
cwd: str,
|
|
517
646
|
provider: str | None = None,
|
|
518
647
|
model_id: str | None = None,
|
|
519
|
-
thinking_level: str = "
|
|
648
|
+
thinking_level: str = "high",
|
|
520
649
|
system_prompt: str | None = None,
|
|
521
|
-
) ->
|
|
650
|
+
) -> Session:
|
|
522
651
|
sessions_dir = cls.get_sessions_dir(cwd)
|
|
523
652
|
|
|
524
653
|
jsonl_files = list(sessions_dir.glob("*.jsonl"))
|
|
@@ -535,7 +664,7 @@ class Session:
|
|
|
535
664
|
return cls.load(most_recent)
|
|
536
665
|
|
|
537
666
|
@classmethod
|
|
538
|
-
def continue_by_id(cls, cwd: str, session_id: str) ->
|
|
667
|
+
def continue_by_id(cls, cwd: str, session_id: str) -> Session:
|
|
539
668
|
normalized_id = session_id.strip().lower()
|
|
540
669
|
if not normalized_id:
|
|
541
670
|
raise ValueError("Session ID cannot be empty")
|
|
@@ -652,9 +781,10 @@ class Session:
|
|
|
652
781
|
cwd: str = ".",
|
|
653
782
|
provider: str | None = None,
|
|
654
783
|
model_id: str | None = None,
|
|
655
|
-
thinking_level: str = "
|
|
784
|
+
thinking_level: str = "high",
|
|
656
785
|
system_prompt: str | None = None,
|
|
657
|
-
|
|
786
|
+
tools: list[str] | None = None,
|
|
787
|
+
) -> Session:
|
|
658
788
|
return cls.create(
|
|
659
789
|
cwd,
|
|
660
790
|
persist=False,
|
|
@@ -662,4 +792,5 @@ class Session:
|
|
|
662
792
|
model_id=model_id,
|
|
663
793
|
thinking_level=thinking_level,
|
|
664
794
|
system_prompt=system_prompt,
|
|
795
|
+
tools=tools,
|
|
665
796
|
)
|
|
@@ -140,7 +140,7 @@ def format_diff_display(diff: str) -> str:
|
|
|
140
140
|
if not line:
|
|
141
141
|
continue
|
|
142
142
|
|
|
143
|
-
truncated = line[:
|
|
143
|
+
truncated = line[:200] + "..." if len(line) > 203 else line
|
|
144
144
|
escaped = truncated.replace("[", "\\[")
|
|
145
145
|
|
|
146
146
|
if line.startswith("-"):
|
|
@@ -60,7 +60,7 @@ from ..llm import (
|
|
|
60
60
|
resolve_provider_api_type,
|
|
61
61
|
)
|
|
62
62
|
from ..llm.base import AuthMode
|
|
63
|
-
from ..loop import Agent
|
|
63
|
+
from ..loop import Agent
|
|
64
64
|
from ..permissions import ApprovalResponse
|
|
65
65
|
from ..session import Session
|
|
66
66
|
from ..tools import DEFAULT_TOOLS, EXTRA_TOOLS, get_tool, get_tools
|
|
@@ -94,7 +94,7 @@ _CHANGELOG_URL = "https://github.com/0xku/kon/blob/main/CHANGELOG.md"
|
|
|
94
94
|
try:
|
|
95
95
|
VERSION = version(_PYPI_PACKAGE_NAME)
|
|
96
96
|
except PackageNotFoundError:
|
|
97
|
-
VERSION = "0.3.
|
|
97
|
+
VERSION = "0.3.5"
|
|
98
98
|
|
|
99
99
|
_COPILOT_API_TYPES: frozenset[ApiType] = frozenset(
|
|
100
100
|
{ApiType.GITHUB_COPILOT, ApiType.GITHUB_COPILOT_RESPONSES, ApiType.ANTHROPIC_COPILOT}
|
|
@@ -117,6 +117,7 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
117
117
|
CSS = get_styles()
|
|
118
118
|
TITLE = "kon"
|
|
119
119
|
VERSION = VERSION
|
|
120
|
+
PAUSE_GC_ON_SCROLL = True
|
|
120
121
|
|
|
121
122
|
BINDINGS: ClassVar[list] = [
|
|
122
123
|
("ctrl+c", "handle_ctrl_c", "Clear"),
|
|
@@ -324,7 +325,7 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
324
325
|
provider=self._model_provider,
|
|
325
326
|
model_id=self._model,
|
|
326
327
|
thinking_level=self._thinking_level,
|
|
327
|
-
system_prompt=
|
|
328
|
+
system_prompt=self._resolve_system_prompt(None),
|
|
328
329
|
)
|
|
329
330
|
except Exception as e:
|
|
330
331
|
self._add_launch_warning(str(e), severity="error")
|
|
@@ -375,7 +376,7 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
375
376
|
if self._provider:
|
|
376
377
|
valid_levels = self._provider.thinking_levels
|
|
377
378
|
if self._thinking_level not in valid_levels:
|
|
378
|
-
self._thinking_level = valid_levels[0] if valid_levels else "
|
|
379
|
+
self._thinking_level = valid_levels[0] if valid_levels else "high"
|
|
379
380
|
self._provider.set_thinking_level(self._thinking_level)
|
|
380
381
|
|
|
381
382
|
self._session_start_time = time.time()
|
|
@@ -388,13 +389,13 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
388
389
|
else (self._provider.name if self._provider else self._model_provider)
|
|
389
390
|
)
|
|
390
391
|
self._model_provider = model_provider
|
|
391
|
-
system_prompt = build_system_prompt(self._cwd, tools=self._tools)
|
|
392
392
|
self._session = Session.create(
|
|
393
393
|
self._cwd,
|
|
394
394
|
provider=model_provider,
|
|
395
395
|
model_id=self._model,
|
|
396
396
|
thinking_level=self._thinking_level,
|
|
397
|
-
system_prompt=
|
|
397
|
+
system_prompt=self._resolve_system_prompt(None),
|
|
398
|
+
tools=[t.name for t in self._tools],
|
|
398
399
|
)
|
|
399
400
|
if model_provider:
|
|
400
401
|
self._session.append_model_change(model_provider, self._model, base_url)
|
|
@@ -402,15 +403,12 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
402
403
|
# Create Agent once — it owns context + system prompt (stable across queries
|
|
403
404
|
# for prompt-prefix caching on llama-server and similar engines).
|
|
404
405
|
if self._provider is not None and self._session is not None:
|
|
405
|
-
system_prompt = self._session.system_prompt or build_system_prompt(
|
|
406
|
-
self._cwd, tools=self._tools
|
|
407
|
-
)
|
|
408
406
|
self._agent = Agent(
|
|
409
407
|
provider=self._provider,
|
|
410
408
|
tools=self._tools,
|
|
411
409
|
session=self._session,
|
|
412
410
|
cwd=self._cwd,
|
|
413
|
-
system_prompt=
|
|
411
|
+
system_prompt=self._resolve_system_prompt(self._session),
|
|
414
412
|
)
|
|
415
413
|
|
|
416
414
|
self._sync_slash_commands()
|
|
@@ -435,8 +433,6 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
435
433
|
self._flush_launch_warnings(chat)
|
|
436
434
|
|
|
437
435
|
info_bar = self.query_one("#info-bar", InfoBar)
|
|
438
|
-
if self._session:
|
|
439
|
-
info_bar.set_session_id(self._session.id[:8])
|
|
440
436
|
model_provider = (
|
|
441
437
|
model_info.provider
|
|
442
438
|
if model_info
|
|
@@ -453,11 +449,15 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
453
449
|
and self._session.entries
|
|
454
450
|
):
|
|
455
451
|
self._render_session_entries(self._session)
|
|
456
|
-
|
|
457
|
-
|
|
452
|
+
token_totals = self._session.token_totals()
|
|
453
|
+
info_bar.set_tokens(
|
|
454
|
+
token_totals.input_tokens,
|
|
455
|
+
token_totals.output_tokens,
|
|
456
|
+
token_totals.context_tokens,
|
|
457
|
+
token_totals.cache_read_tokens,
|
|
458
|
+
token_totals.cache_write_tokens,
|
|
458
459
|
)
|
|
459
|
-
info_bar.
|
|
460
|
-
info_bar.set_file_changes(self._calculate_session_file_changes(self._session))
|
|
460
|
+
info_bar.set_file_changes(self._session.file_changes_summary())
|
|
461
461
|
chat.add_info_message("Resumed session")
|
|
462
462
|
|
|
463
463
|
if self._provider and self._session:
|
|
@@ -467,6 +467,10 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
467
467
|
self._show_pending_update_notice_if_idle()
|
|
468
468
|
input_box.focus()
|
|
469
469
|
|
|
470
|
+
import gc
|
|
471
|
+
|
|
472
|
+
gc.freeze()
|
|
473
|
+
|
|
470
474
|
async def _collect_file_paths(self) -> None:
|
|
471
475
|
"""Collect file paths using glob (fallback when fd is unavailable)."""
|
|
472
476
|
patterns = [
|
|
@@ -853,15 +857,12 @@ class Kon(CommandsMixin, SessionUIMixin, App[None]):
|
|
|
853
857
|
return
|
|
854
858
|
|
|
855
859
|
if self._agent is None:
|
|
856
|
-
system_prompt = self._session.system_prompt or build_system_prompt(
|
|
857
|
-
self._cwd, tools=self._tools
|
|
858
|
-
)
|
|
859
860
|
self._agent = Agent(
|
|
860
861
|
provider=self._provider,
|
|
861
862
|
tools=self._tools,
|
|
862
863
|
session=self._session,
|
|
863
864
|
cwd=self._cwd,
|
|
864
|
-
system_prompt=
|
|
865
|
+
system_prompt=self._resolve_system_prompt(self._session),
|
|
865
866
|
)
|
|
866
867
|
|
|
867
868
|
current_prompt = prompt
|
|
@@ -1180,7 +1181,7 @@ def main():
|
|
|
1180
1181
|
|
|
1181
1182
|
if app._session:
|
|
1182
1183
|
session_id = app._session.id
|
|
1183
|
-
file_changes =
|
|
1184
|
+
file_changes = app._session.file_changes_summary() or None
|
|
1184
1185
|
if app._session_start_time is not None:
|
|
1185
1186
|
duration = time.time() - app._session_start_time
|
|
1186
1187
|
|