kagi-cli 0.1.0__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.
- kagi_cli-0.1.0/.github/workflows/release.yml +79 -0
- kagi_cli-0.1.0/.gitignore +10 -0
- kagi_cli-0.1.0/.python-version +1 -0
- kagi_cli-0.1.0/API.md +0 -0
- kagi_cli-0.1.0/CONVENTIONS.md +120 -0
- kagi_cli-0.1.0/PKG-INFO +92 -0
- kagi_cli-0.1.0/README.md +80 -0
- kagi_cli-0.1.0/TESTING.md +139 -0
- kagi_cli-0.1.0/flake.lock +27 -0
- kagi_cli-0.1.0/flake.nix +37 -0
- kagi_cli-0.1.0/kagi_client/__init__.py +67 -0
- kagi_cli-0.1.0/kagi_client/assistant.py +185 -0
- kagi_cli-0.1.0/kagi_client/auth.py +56 -0
- kagi_cli-0.1.0/kagi_client/cli.py +505 -0
- kagi_cli-0.1.0/kagi_client/client.py +127 -0
- kagi_cli-0.1.0/kagi_client/errors.py +30 -0
- kagi_cli-0.1.0/kagi_client/formatters.py +243 -0
- kagi_cli-0.1.0/kagi_client/models.py +185 -0
- kagi_cli-0.1.0/kagi_client/proofread.py +162 -0
- kagi_cli-0.1.0/kagi_client/search.py +238 -0
- kagi_cli-0.1.0/kagi_client/streams.py +104 -0
- kagi_cli-0.1.0/kagi_client/summarizer.py +135 -0
- kagi_cli-0.1.0/main.py +32 -0
- kagi_cli-0.1.0/pyproject.toml +41 -0
- kagi_cli-0.1.0/tests/__init__.py +0 -0
- kagi_cli-0.1.0/tests/conftest.py +54 -0
- kagi_cli-0.1.0/tests/integration/__init__.py +0 -0
- kagi_cli-0.1.0/tests/integration/test_client.py +139 -0
- kagi_cli-0.1.0/tests/unit/__init__.py +0 -0
- kagi_cli-0.1.0/tests/unit/test_assistant.py +91 -0
- kagi_cli-0.1.0/tests/unit/test_auth.py +120 -0
- kagi_cli-0.1.0/tests/unit/test_cli.py +850 -0
- kagi_cli-0.1.0/tests/unit/test_errors.py +67 -0
- kagi_cli-0.1.0/tests/unit/test_formatters.py +459 -0
- kagi_cli-0.1.0/tests/unit/test_models.py +278 -0
- kagi_cli-0.1.0/tests/unit/test_proofread.py +110 -0
- kagi_cli-0.1.0/tests/unit/test_search.py +182 -0
- kagi_cli-0.1.0/tests/unit/test_streams.py +131 -0
- kagi_cli-0.1.0/tests/unit/test_summarizer.py +99 -0
- kagi_cli-0.1.0/uv.lock +317 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build distributions
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Setup Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
|
|
25
|
+
- name: Build package
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip build
|
|
28
|
+
python -m build
|
|
29
|
+
|
|
30
|
+
- name: Upload build artifacts
|
|
31
|
+
uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: python-package-distributions
|
|
34
|
+
path: dist/
|
|
35
|
+
|
|
36
|
+
github-release:
|
|
37
|
+
name: Attach packages to GitHub Release
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: build
|
|
40
|
+
permissions:
|
|
41
|
+
contents: write
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Download build artifacts
|
|
45
|
+
uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: python-package-distributions
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Create or update release and upload assets
|
|
51
|
+
uses: softprops/action-gh-release@v2
|
|
52
|
+
with:
|
|
53
|
+
files: dist/*
|
|
54
|
+
generate_release_notes: true
|
|
55
|
+
|
|
56
|
+
pypi-publish:
|
|
57
|
+
name: Publish to PyPI (Trusted Publishing)
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
needs: build
|
|
60
|
+
permissions:
|
|
61
|
+
id-token: write
|
|
62
|
+
|
|
63
|
+
# Configure this environment in GitHub settings and connect it in PyPI
|
|
64
|
+
# as a Trusted Publisher for this repository/workflow.
|
|
65
|
+
environment:
|
|
66
|
+
name: pypi
|
|
67
|
+
url: https://pypi.org/project/kagi-cli/
|
|
68
|
+
|
|
69
|
+
steps:
|
|
70
|
+
- name: Download build artifacts
|
|
71
|
+
uses: actions/download-artifact@v4
|
|
72
|
+
with:
|
|
73
|
+
name: python-package-distributions
|
|
74
|
+
path: dist/
|
|
75
|
+
|
|
76
|
+
- name: Publish distribution to PyPI
|
|
77
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
78
|
+
with:
|
|
79
|
+
packages-dir: dist/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
kagi_cli-0.1.0/API.md
ADDED
|
Binary file
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Coding Conventions
|
|
2
|
+
|
|
3
|
+
## 1. Guiding Principles
|
|
4
|
+
|
|
5
|
+
Our primary goal is to build a robust, maintainable, code base.
|
|
6
|
+
|
|
7
|
+
Key principles:
|
|
8
|
+
|
|
9
|
+
* **Clarity over Cleverness:** Code should be easy to read and understand
|
|
10
|
+
* **Explicit over Implicit:** Be clear about intentions and dependencies
|
|
11
|
+
* **Consistency:** Follow established patterns within the project
|
|
12
|
+
* **Single Responsibility Principle:** Each module, class, or function should have one clear purpose
|
|
13
|
+
* **Loose Coupling, High Cohesion:** Modules should be independent but related components within a module should be grouped
|
|
14
|
+
* **Testability:** Write code that is inherently easy to unit and integration test
|
|
15
|
+
* **Pythonic:** Embrace PEP 8 and the Zen of Python (`import this`)
|
|
16
|
+
|
|
17
|
+
## 2. General Python Conventions
|
|
18
|
+
|
|
19
|
+
* **PEP 8 Compliance:** Adhere strictly to PEP 8
|
|
20
|
+
* Use `ruff format` for auto-formatting to ensure consistent style
|
|
21
|
+
* Line length limit is **88 characters** (ruff's default)
|
|
22
|
+
* **Python Version:** Target **Python 3.11+**. Utilize modern features like union types (`X | Y`)
|
|
23
|
+
* **No Mutable Default Arguments:** Avoid using mutable objects as default arguments
|
|
24
|
+
* **Bad:** `def foo(items=[])`
|
|
25
|
+
* **Good:** `def foo(items: list | None = None): if items is None: items = []`
|
|
26
|
+
|
|
27
|
+
## 3. Naming Conventions
|
|
28
|
+
|
|
29
|
+
* **Packages/Directories:** `snake_case` (e.g., `api`, `claude_sdk`, `auth`)
|
|
30
|
+
* **Modules:** `snake_case` (e.g., `manager.py`, `client.py`)
|
|
31
|
+
* **Classes:** `CamelCase` (e.g., `OpenAIAdapter`, `ServiceContainer`)
|
|
32
|
+
* **Abstract Base Classes:** Suffix with `ABC` or `Protocol`
|
|
33
|
+
* **Pydantic Models:** `CamelCase` (e.g., `MessageCreateParams`)
|
|
34
|
+
* **Functions/Methods/Variables:** `snake_case` (e.g., `handle_request`, `get_access_token`)
|
|
35
|
+
* **Constants:** `UPPER_SNAKE_CASE` (e.g., `DEFAULT_PORT`, `API_VERSION`)
|
|
36
|
+
* **Private Members:** `_single_leading_underscore` for internal use
|
|
37
|
+
|
|
38
|
+
## 4. Imports
|
|
39
|
+
|
|
40
|
+
* **Ordering:** Standard library → Third-party → First-party → Relative
|
|
41
|
+
* **Absolute Imports Preferred:** Use absolute imports for modules within the project
|
|
42
|
+
* **`__all__` in `__init__.py`:** Define to explicitly expose public API
|
|
43
|
+
|
|
44
|
+
## 5. Typing
|
|
45
|
+
|
|
46
|
+
Type hints are mandatory for clarity and maintainability:
|
|
47
|
+
|
|
48
|
+
* **All Function Signatures:** Type-hint all parameters and return values, avoid `Any`
|
|
49
|
+
* **Class Attributes:** Use type hints, especially for Pydantic models
|
|
50
|
+
* **Union Types:** Use `Type | None` for optional values (Python 3.11+)
|
|
51
|
+
* **Type Aliases:** Define in `core/types.py` for complex types
|
|
52
|
+
* **Generics:** Use `Generic[T]` for classes/functions that operate on multiple types
|
|
53
|
+
|
|
54
|
+
## 7. Error Handling
|
|
55
|
+
|
|
56
|
+
* **Custom Exceptions:** Inherit from `kagicli.errors.BaseError`
|
|
57
|
+
* **Catch Specific Exceptions:** Never use bare `except:`
|
|
58
|
+
* **Chain Exceptions:** Use `raise NewError(...) from original`
|
|
59
|
+
|
|
60
|
+
## 8. Asynchronous Programming
|
|
61
|
+
|
|
62
|
+
* **`async`/`await`:** Use consistently for all I/O operations
|
|
63
|
+
* **Libraries:** Prefer `httpx` for HTTP, `asyncio` for concurrency
|
|
64
|
+
* **No Blocking Code:** Never use blocking I/O in async functions
|
|
65
|
+
|
|
66
|
+
## 9. Testing
|
|
67
|
+
|
|
68
|
+
* **Framework:** `pytest` with `pytest-asyncio`
|
|
69
|
+
* **Architecture:** Streamlined after aggressive refactoring (606 tests, was 786)
|
|
70
|
+
* **Structure:** Clean separation with proper boundaries:
|
|
71
|
+
* `tests/unit/` - Fast, isolated unit tests (mock at service boundaries only)
|
|
72
|
+
* `tests/integration/` - Cross-component interaction tests (core)
|
|
73
|
+
* **Markers:** Use `@pytest.mark.unit`, `@pytest.mark.integration`, `@pytest.mark.network`, `@pytest.mark.slow`
|
|
74
|
+
* **Fixtures:** Essential fixtures only in `conftest.py` (515 lines, was 1117)
|
|
75
|
+
* **Mocking:** External services only - no internal component mocking
|
|
76
|
+
* **Type Safety:** All test functions must have `-> None` return type
|
|
77
|
+
* **Coverage:** High coverage on critical paths with real component testing
|
|
78
|
+
|
|
79
|
+
## 10. Configuration
|
|
80
|
+
|
|
81
|
+
* **Pydantic Settings:** All config in `config/settings.py`
|
|
82
|
+
* **Environment Variables:** Use `__` for nesting
|
|
83
|
+
* **Priority:** CLI args → Environment → TOML files → Defaults
|
|
84
|
+
|
|
85
|
+
## 11. Security
|
|
86
|
+
|
|
87
|
+
* **Input Validation:** All API inputs validated with Pydantic
|
|
88
|
+
* **No Secrets in Code:** Use environment variables
|
|
89
|
+
|
|
90
|
+
## 12. Tooling
|
|
91
|
+
|
|
92
|
+
Core tools enforced via pre-commit and CI:
|
|
93
|
+
|
|
94
|
+
* **Package Manager:** `uv` (via Makefile only)
|
|
95
|
+
* **Formatter:** `ruff format`
|
|
96
|
+
* **Linter:** `ruff check`
|
|
97
|
+
* **Type Checker:** `mypy`
|
|
98
|
+
* **Test Runner:** `pytest`
|
|
99
|
+
* **Dev Scripts:** helper scripts under `scripts/` for local testing and debugging
|
|
100
|
+
|
|
101
|
+
## 13. Development Workflow
|
|
102
|
+
|
|
103
|
+
### Required Before Commits
|
|
104
|
+
```bash
|
|
105
|
+
make pre-commit # Comprehensive checks + auto-fixes
|
|
106
|
+
make test # Run tests with coverage
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 14. Documentation
|
|
110
|
+
|
|
111
|
+
* **Docstrings:** Required for all public APIs (Google style)
|
|
112
|
+
* **Comments:** Explain *why*, not *what*
|
|
113
|
+
* **TODO/FIXME:** Use consistently with explanations
|
|
114
|
+
|
|
115
|
+
## 15. Git Workflow
|
|
116
|
+
|
|
117
|
+
* **Commits:** Follow Conventional Commits (feat:, fix:, docs:, etc.)
|
|
118
|
+
* **Branches:** Use feature branches (`feature/`, `fix/`, `docs/`)
|
|
119
|
+
* **No `git add .`:** Only stage specific files
|
|
120
|
+
|
kagi_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kagi-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: httpx>=0.28.1
|
|
7
|
+
Requires-Dist: pygments>=2.19.2
|
|
8
|
+
Requires-Dist: pyjwt>=2.10.1
|
|
9
|
+
Requires-Dist: rich>=13.0
|
|
10
|
+
Requires-Dist: typer>=0.15
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# kagi-cli-py
|
|
14
|
+
|
|
15
|
+
Python CLI and client for Kagi services.
|
|
16
|
+
|
|
17
|
+
PyPI package name: `kagi-cli`
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- `proofread`: improve text quality
|
|
22
|
+
- `summarize`: summarize URLs
|
|
23
|
+
- `ask`: query Kagi Assistant
|
|
24
|
+
- `search`: run Kagi search queries
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Python 3.12+
|
|
29
|
+
- A valid `KAGI_SESSION` value from your Kagi session link
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uv sync
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Install and run from PyPI
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Run without installing globally
|
|
41
|
+
uvx --from kagi-cli kagi --help
|
|
42
|
+
pipx run --spec kagi-cli kagi --help
|
|
43
|
+
|
|
44
|
+
# Install globally with pipx
|
|
45
|
+
pipx install kagi-cli
|
|
46
|
+
kagi --help
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Authentication
|
|
50
|
+
|
|
51
|
+
Set `KAGI_SESSION` from your Kagi session link before using the CLI:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export KAGI_SESSION="your_session_value_from_link"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## CLI usage
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Show help
|
|
61
|
+
uv run kagi --help
|
|
62
|
+
|
|
63
|
+
# Show version (git tag when available)
|
|
64
|
+
uv run kagi --version
|
|
65
|
+
|
|
66
|
+
# Proofread text
|
|
67
|
+
uv run kagi proofread "Ths is a tset."
|
|
68
|
+
|
|
69
|
+
# Summarize a URL
|
|
70
|
+
uv run kagi summarize "https://example.com"
|
|
71
|
+
|
|
72
|
+
# Ask assistant
|
|
73
|
+
uv run kagi ask "What is 2+2?"
|
|
74
|
+
|
|
75
|
+
# Search
|
|
76
|
+
uv run kagi search "python async"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Output formats
|
|
80
|
+
|
|
81
|
+
Commands support:
|
|
82
|
+
|
|
83
|
+
- `--format console` (default)
|
|
84
|
+
- `--format json`
|
|
85
|
+
- `--format md`
|
|
86
|
+
- `--format csv`
|
|
87
|
+
|
|
88
|
+
## Run tests
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
uv run pytest -q
|
|
92
|
+
```
|
kagi_cli-0.1.0/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# kagi-cli-py
|
|
2
|
+
|
|
3
|
+
Python CLI and client for Kagi services.
|
|
4
|
+
|
|
5
|
+
PyPI package name: `kagi-cli`
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- `proofread`: improve text quality
|
|
10
|
+
- `summarize`: summarize URLs
|
|
11
|
+
- `ask`: query Kagi Assistant
|
|
12
|
+
- `search`: run Kagi search queries
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Python 3.12+
|
|
17
|
+
- A valid `KAGI_SESSION` value from your Kagi session link
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv sync
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Install and run from PyPI
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Run without installing globally
|
|
29
|
+
uvx --from kagi-cli kagi --help
|
|
30
|
+
pipx run --spec kagi-cli kagi --help
|
|
31
|
+
|
|
32
|
+
# Install globally with pipx
|
|
33
|
+
pipx install kagi-cli
|
|
34
|
+
kagi --help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Authentication
|
|
38
|
+
|
|
39
|
+
Set `KAGI_SESSION` from your Kagi session link before using the CLI:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
export KAGI_SESSION="your_session_value_from_link"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## CLI usage
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Show help
|
|
49
|
+
uv run kagi --help
|
|
50
|
+
|
|
51
|
+
# Show version (git tag when available)
|
|
52
|
+
uv run kagi --version
|
|
53
|
+
|
|
54
|
+
# Proofread text
|
|
55
|
+
uv run kagi proofread "Ths is a tset."
|
|
56
|
+
|
|
57
|
+
# Summarize a URL
|
|
58
|
+
uv run kagi summarize "https://example.com"
|
|
59
|
+
|
|
60
|
+
# Ask assistant
|
|
61
|
+
uv run kagi ask "What is 2+2?"
|
|
62
|
+
|
|
63
|
+
# Search
|
|
64
|
+
uv run kagi search "python async"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Output formats
|
|
68
|
+
|
|
69
|
+
Commands support:
|
|
70
|
+
|
|
71
|
+
- `--format console` (default)
|
|
72
|
+
- `--format json`
|
|
73
|
+
- `--format md`
|
|
74
|
+
- `--format csv`
|
|
75
|
+
|
|
76
|
+
## Run tests
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv run pytest -q
|
|
80
|
+
```
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Streamlined Testing Guide
|
|
2
|
+
|
|
3
|
+
## Philosophy
|
|
4
|
+
|
|
5
|
+
After aggressive refactoring and architecture realignment, our testing philosophy is:
|
|
6
|
+
- **Clean boundaries**: Unit tests for isolated components, integration tests for cross-component behavior
|
|
7
|
+
- **Fast execution**: Unit tests run in milliseconds, mypy completes in seconds
|
|
8
|
+
- **Modern patterns**: Type-safe fixtures, clear separation of concerns
|
|
9
|
+
- **Minimal mocking**: Only mock external services, test real internal behavior
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Run all tests
|
|
15
|
+
make test
|
|
16
|
+
|
|
17
|
+
# Run specific test categories
|
|
18
|
+
pytest tests/unit/auth/ # Authentication tests
|
|
19
|
+
pytest tests/unit/config/ # Config tests
|
|
20
|
+
pytest tests/integration/ # Cross-component integration tests (core)
|
|
21
|
+
|
|
22
|
+
# Run with coverage
|
|
23
|
+
make test-coverage
|
|
24
|
+
|
|
25
|
+
# Type checking and quality (now sub-second)
|
|
26
|
+
make typecheck
|
|
27
|
+
make pre-commit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## Writing Tests
|
|
32
|
+
|
|
33
|
+
### Clean Architecture Principles
|
|
34
|
+
|
|
35
|
+
**Unit Tests** (tests/unit/):
|
|
36
|
+
- Mock at **service boundaries only** - never mock internal components
|
|
37
|
+
- Test **pure functions and single components** in isolation
|
|
38
|
+
- **No timing dependencies** - all asyncio.sleep() removed
|
|
39
|
+
- **No database operations** - moved to integration tests
|
|
40
|
+
|
|
41
|
+
**Integration Tests** (tests/integration/):
|
|
42
|
+
- Test **cross-component interactions** with minimal mocking
|
|
43
|
+
- Include **HTTP client testing **
|
|
44
|
+
- Test **async coordination when needed**
|
|
45
|
+
- Validate configuration end-to-end
|
|
46
|
+
|
|
47
|
+
### Mocking Strategy (Simplified)
|
|
48
|
+
|
|
49
|
+
- **External APIs only**
|
|
50
|
+
- **Internal services**: Use real implementations with dependency injection
|
|
51
|
+
- **Configuration**: Use test settings objects, not mocks
|
|
52
|
+
- **No mock explosion**
|
|
53
|
+
|
|
54
|
+
## Type Safety and Code Quality
|
|
55
|
+
|
|
56
|
+
**REQUIREMENT**: All test files MUST pass type checking and linting. This is not optional.
|
|
57
|
+
|
|
58
|
+
### Type Safety Requirements
|
|
59
|
+
|
|
60
|
+
1. **All test files MUST pass mypy type checking** - No `Any` types unless absolutely necessary
|
|
61
|
+
2. **All test files MUST pass ruff formatting and linting** - Code must be properly formatted
|
|
62
|
+
3. **Add proper type hints to all test functions and fixtures** - Include return types and parameter types
|
|
63
|
+
4. **Import necessary types** - Use `from typing import` for type annotations
|
|
64
|
+
|
|
65
|
+
### Required Type Annotations
|
|
66
|
+
|
|
67
|
+
- **Test functions**: Must have `-> None` return type annotation
|
|
68
|
+
- **Fixtures**: Must have proper return type hints
|
|
69
|
+
- **Parameters**: Must have type hints where not inferred from fixtures
|
|
70
|
+
- **Variables**: Add type hints for complex objects when not obvious
|
|
71
|
+
|
|
72
|
+
## Architecture Overview
|
|
73
|
+
|
|
74
|
+
### Essential Fixtures
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
## Test Markers
|
|
78
|
+
|
|
79
|
+
- `@pytest.mark.unit` - Fast unit tests (default)
|
|
80
|
+
- `@pytest.mark.integration` - Cross-component integration tests
|
|
81
|
+
- `@pytest.mark.network` - Tests requiring network access (external APIs)
|
|
82
|
+
- `@pytest.mark.slow` - Tests that take longer than 1 second (avoid if possible)
|
|
83
|
+
|
|
84
|
+
## Best Practices
|
|
85
|
+
|
|
86
|
+
1. **Clean boundaries** - Unit tests mock at service boundaries only
|
|
87
|
+
2. **Fast execution** - Unit tests run in milliseconds, no timing dependencies
|
|
88
|
+
3. **Type safety** - All fixtures properly typed, mypy compliant
|
|
89
|
+
4. **Real components** - Test actual internal behavior, not mocked responses
|
|
90
|
+
5. **Performance-optimized patterns** - Use session-scoped fixtures for expensive operations
|
|
91
|
+
6. **Modern async patterns** - `@pytest.mark.asyncio(loop_scope="session")` for integration tests
|
|
92
|
+
7. **No overengineering** - Removed 180+ tests, 3000+ lines of complexity
|
|
93
|
+
|
|
94
|
+
### Performance Guidelines
|
|
95
|
+
|
|
96
|
+
#### When to Use Session-Scoped Fixtures
|
|
97
|
+
- **Plugin integration tests** - Plugin initialization is expensive
|
|
98
|
+
- **Database/external service tests** - Connection setup overhead
|
|
99
|
+
- **Complex app configuration** - Multiple services, middleware stacks
|
|
100
|
+
- **Consistent test state needed** - Tests require same app configuration
|
|
101
|
+
|
|
102
|
+
#### When to Use Factory Patterns
|
|
103
|
+
- **Dynamic configurations** - Each test needs different plugin settings
|
|
104
|
+
- **Isolation required** - Tests might interfere with shared state
|
|
105
|
+
- **Simple setup** - Minimal overhead for app creation
|
|
106
|
+
|
|
107
|
+
#### Logging Performance Tips
|
|
108
|
+
- **Use `ERROR` level** - Minimal logging for faster test execution
|
|
109
|
+
- **Disable JSON logs** - `json_logs=False` for better performance
|
|
110
|
+
- **Manual setup required** - Call `setup_logging()` explicitly in test environment
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Running Tests
|
|
114
|
+
|
|
115
|
+
### Make Commands
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
make test # Run all tests with coverage except network, slow
|
|
119
|
+
make test-coverage # With coverage report
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Direct pytest
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pytest -v # Verbose output
|
|
126
|
+
pytest -k "test_auth" # Run matching tests
|
|
127
|
+
pytest --lf # Run last failed
|
|
128
|
+
pytest -x # Stop on first failure
|
|
129
|
+
pytest -s -v # No capture, verbose
|
|
130
|
+
pytest --pdb # Debug on failure
|
|
131
|
+
pytest -m unit # Unit tests only
|
|
132
|
+
pytest -m integration # Integration tests only
|
|
133
|
+
pytest -m slow # Slow tests only
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Migration from Old Architecture
|
|
137
|
+
|
|
138
|
+
**All existing test patterns still work** - but new tests should use the performance-optimized patterns:
|
|
139
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nodes": {
|
|
3
|
+
"nixpkgs": {
|
|
4
|
+
"locked": {
|
|
5
|
+
"lastModified": 1735563628,
|
|
6
|
+
"narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=",
|
|
7
|
+
"owner": "NixOS",
|
|
8
|
+
"repo": "nixpkgs",
|
|
9
|
+
"rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798",
|
|
10
|
+
"type": "github"
|
|
11
|
+
},
|
|
12
|
+
"original": {
|
|
13
|
+
"owner": "NixOS",
|
|
14
|
+
"ref": "nixos-24.05",
|
|
15
|
+
"repo": "nixpkgs",
|
|
16
|
+
"type": "github"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"root": {
|
|
20
|
+
"inputs": {
|
|
21
|
+
"nixpkgs": "nixpkgs"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"root": "root",
|
|
26
|
+
"version": 7
|
|
27
|
+
}
|
kagi_cli-0.1.0/flake.nix
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
description = "Kagi development flake";
|
|
3
|
+
|
|
4
|
+
inputs = {
|
|
5
|
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
outputs = { self, nixpkgs }:
|
|
9
|
+
let
|
|
10
|
+
systems = [
|
|
11
|
+
"x86_64-linux"
|
|
12
|
+
"aarch64-linux"
|
|
13
|
+
"x86_64-darwin"
|
|
14
|
+
"aarch64-darwin"
|
|
15
|
+
];
|
|
16
|
+
forEachSystem = nixpkgs.lib.genAttrs systems;
|
|
17
|
+
in {
|
|
18
|
+
devShells = forEachSystem (system:
|
|
19
|
+
let
|
|
20
|
+
pkgs = import nixpkgs { inherit system; };
|
|
21
|
+
in {
|
|
22
|
+
default = pkgs.mkShell {
|
|
23
|
+
packages = with pkgs; [
|
|
24
|
+
python312
|
|
25
|
+
uv
|
|
26
|
+
zsh
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
shellHook = ''
|
|
30
|
+
# Keep uv-managed virtual environments local to this repo and align with nix python.
|
|
31
|
+
export UV_PROJECT_ENV=".venv"
|
|
32
|
+
export UV_PYTHON="${pkgs.python312}/bin/python3"
|
|
33
|
+
'';
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from kagi_client.assistant import AssistantClient
|
|
2
|
+
from kagi_client.auth import KagiAuth
|
|
3
|
+
from kagi_client.client import KagiClient
|
|
4
|
+
from kagi_client.errors import (
|
|
5
|
+
APIError,
|
|
6
|
+
AuthError,
|
|
7
|
+
KagiError,
|
|
8
|
+
StreamParseError,
|
|
9
|
+
TokenExpiredError,
|
|
10
|
+
)
|
|
11
|
+
from kagi_client.formatters import OutputFormat
|
|
12
|
+
from kagi_client.models import (
|
|
13
|
+
AssistantMessage,
|
|
14
|
+
AssistantResult,
|
|
15
|
+
AssistantThread,
|
|
16
|
+
AuthResponse,
|
|
17
|
+
DetectedLanguage,
|
|
18
|
+
DomainInfo,
|
|
19
|
+
ProofreadAnalysis,
|
|
20
|
+
ProofreadResult,
|
|
21
|
+
ResponseMetadata,
|
|
22
|
+
SearchInfo,
|
|
23
|
+
SearchItem,
|
|
24
|
+
SearchResult,
|
|
25
|
+
SummaryResult,
|
|
26
|
+
SummaryUpdate,
|
|
27
|
+
TokenPayload,
|
|
28
|
+
ToneAnalysis,
|
|
29
|
+
WordStats,
|
|
30
|
+
WritingStatistics,
|
|
31
|
+
)
|
|
32
|
+
from kagi_client.proofread import ProofreadClient
|
|
33
|
+
from kagi_client.search import SearchClient
|
|
34
|
+
from kagi_client.summarizer import SummarizerClient
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"APIError",
|
|
38
|
+
"AssistantClient",
|
|
39
|
+
"AssistantMessage",
|
|
40
|
+
"AssistantResult",
|
|
41
|
+
"AssistantThread",
|
|
42
|
+
"AuthError",
|
|
43
|
+
"AuthResponse",
|
|
44
|
+
"DetectedLanguage",
|
|
45
|
+
"DomainInfo",
|
|
46
|
+
"KagiAuth",
|
|
47
|
+
"KagiClient",
|
|
48
|
+
"KagiError",
|
|
49
|
+
"OutputFormat",
|
|
50
|
+
"ProofreadAnalysis",
|
|
51
|
+
"ProofreadClient",
|
|
52
|
+
"ProofreadResult",
|
|
53
|
+
"ResponseMetadata",
|
|
54
|
+
"SearchClient",
|
|
55
|
+
"SearchInfo",
|
|
56
|
+
"SearchItem",
|
|
57
|
+
"SearchResult",
|
|
58
|
+
"StreamParseError",
|
|
59
|
+
"SummarizerClient",
|
|
60
|
+
"SummaryResult",
|
|
61
|
+
"SummaryUpdate",
|
|
62
|
+
"TokenExpiredError",
|
|
63
|
+
"TokenPayload",
|
|
64
|
+
"ToneAnalysis",
|
|
65
|
+
"WordStats",
|
|
66
|
+
"WritingStatistics",
|
|
67
|
+
]
|