asky-cli 0.1.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.
- asky_cli-0.1.6/.gitignore +12 -0
- asky_cli-0.1.6/DEVLOG.md +237 -0
- asky_cli-0.1.6/PKG-INFO +290 -0
- asky_cli-0.1.6/README.md +279 -0
- asky_cli-0.1.6/asky +7 -0
- asky_cli-0.1.6/assets/asearch_icon.png +0 -0
- asky_cli-0.1.6/assets/asearch_icon.xcf +0 -0
- asky_cli-0.1.6/pyproject.toml +28 -0
- asky_cli-0.1.6/src/asky/__init__.py +7 -0
- asky_cli-0.1.6/src/asky/__main__.py +6 -0
- asky_cli-0.1.6/src/asky/banner.py +123 -0
- asky_cli-0.1.6/src/asky/cli.py +506 -0
- asky_cli-0.1.6/src/asky/config.py +270 -0
- asky_cli-0.1.6/src/asky/config.toml +226 -0
- asky_cli-0.1.6/src/asky/html.py +62 -0
- asky_cli-0.1.6/src/asky/llm.py +378 -0
- asky_cli-0.1.6/src/asky/storage.py +157 -0
- asky_cli-0.1.6/src/asky/tools.py +314 -0
- asky_cli-0.1.6/tests/test_cli.py +318 -0
- asky_cli-0.1.6/tests/test_config.py +31 -0
- asky_cli-0.1.6/tests/test_custom_tools.py +95 -0
- asky_cli-0.1.6/tests/test_expansion.py +52 -0
- asky_cli-0.1.6/tests/test_html.py +64 -0
- asky_cli-0.1.6/tests/test_llm.py +245 -0
- asky_cli-0.1.6/tests/test_storage.py +137 -0
- asky_cli-0.1.6/tests/test_tools.py +232 -0
- asky_cli-0.1.6/uv.lock +340 -0
asky_cli-0.1.6/DEVLOG.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Development Log
|
|
2
|
+
|
|
3
|
+
## 2026-02-02
|
|
4
|
+
|
|
5
|
+
- **Fix**: Resolved **database bootstrapping failure** on first run.
|
|
6
|
+
- The CLI was attempting to count database records for the banner before the database was initialized.
|
|
7
|
+
- Moved `init_db()` to the beginning of `main()` in `cli.py`.
|
|
8
|
+
- Updated `tests/test_cli.py` to mock `get_db_record_count` in main flow tests to align with mocked `init_db`.
|
|
9
|
+
|
|
10
|
+
## 2026-02-02
|
|
11
|
+
|
|
12
|
+
- **Feat**: Enhanced CLI with a **shiny banner**.
|
|
13
|
+
- Renamed project from "asearch" to "asky".
|
|
14
|
+
- Added a cute icon.
|
|
15
|
+
- Added `get_banner` function to `banner.py` using `rich`.
|
|
16
|
+
- Integrated the banner into `cli.py` to show model details, summarizer details, search backend, and context limits in a rounded rectangle.
|
|
17
|
+
- **Expansion**: Reorganized the banner into a two-column layout to include **Default Model**, **Max Turns**, and **Database Record Count**.
|
|
18
|
+
- **Fix**: Adjusted banner styling to use `border_style="dim"` instead of a global `style="dim"`, ensuring icon and text colors remain vibrant.
|
|
19
|
+
- Ensured the banner is only shown for actual queries to maintain a clean interface for history and maintenance tasks.
|
|
20
|
+
|
|
21
|
+
- **Feat**: Introduced **configurable query summarization threshold**.
|
|
22
|
+
- Added `continue_query_threshold` (default: 160) to `[general]` section in `config.toml`.
|
|
23
|
+
- Exposed `CONTINUE_QUERY_THRESHOLD` in `config.py`.
|
|
24
|
+
- Updated `generate_summaries` in `llm.py` to only summarize queries exceeding this threshold.
|
|
25
|
+
- Updated `get_interaction_context` in `storage.py` to use the full query if it's below the threshold, even if a summary exists.
|
|
26
|
+
- Added unit tests to verify the threshold logic.
|
|
27
|
+
|
|
28
|
+
- **Feat**: Introduced **default context size setting** in the configuration.
|
|
29
|
+
- Added `default_context_size` (default: 4096) to `[general]` section in `config.toml`.
|
|
30
|
+
- Exposed `DEFAULT_CONTEXT_SIZE` in `config.py`.
|
|
31
|
+
- Updated `run_conversation_loop` in `llm.py` to use `DEFAULT_CONTEXT_SIZE` if not specified in model configuration.
|
|
32
|
+
- Added unit test in `test_config.py` to verify the setting.
|
|
33
|
+
|
|
34
|
+
- **Feat**: Implemented **token usage tracking and reporting**.
|
|
35
|
+
- Added `UsageTracker` class to `llm.py` to accumulate token counts per model alias.
|
|
36
|
+
- Updated `get_llm_msg` to print the number of tokens sent in each turn.
|
|
37
|
+
- Enhanced `get_llm_msg` to extract real usage data from API responses if available (falls back to naive `len // 4` count).
|
|
38
|
+
- Updated `run_conversation_loop` and `generate_summaries` to report usage through the tracker.
|
|
39
|
+
- Added a session summary report at the end of the query execution, showing separate usage for the main model and the summarization model.
|
|
40
|
+
- Updated unit tests to support the new tracking logic.
|
|
41
|
+
|
|
42
|
+
- **Fix**: Improved **rate limit handling and backoff robustness**.
|
|
43
|
+
- Increased `max_retries` from 5 to 10 in `llm.py`.
|
|
44
|
+
- Capped exponential backoff at 60 seconds to stay within API limit reset windows.
|
|
45
|
+
- Added support for respecting the `Retry-After` header from API responses (now handles decimal strings).
|
|
46
|
+
- Introduced a 1-second delay between sequential summarizations in `get_url_content` to reduce RPM (Requests Per Minute) pressure.
|
|
47
|
+
- Added unit tests to verify `Retry-After` handling and batch delay logic.
|
|
48
|
+
- **Fix**: Resolved issue where **failed URL fetches were marked as "read"**.
|
|
49
|
+
- Updated `execute_get_url_details` in `tools.py` to only append to `read_urls` after a successful request.
|
|
50
|
+
- **Fix**: Ensured `get_url_content` **respects the summarization flag** requested by the LLM.
|
|
51
|
+
- Previously, if the CLI was run without `-s`, the tool would ignore the LLM's own request for summaries and return full content.
|
|
52
|
+
- This often caused the next turn of the conversation to have a massive payload, triggering 429 rate limits on the LLM API itself.
|
|
53
|
+
- Now, `execute_get_url_content` uses `effective_summarize = args.get("summarize", summarize)`, correctly balancing user preference and LLM context management.
|
|
54
|
+
- **Fix**: Added **URL sanitization** to remove shell-escaped backslashes.
|
|
55
|
+
- Wikipedia and other servers often return 403 Forbidden for URLs containing literal backslashes (e.g., `\(`, `\)`).
|
|
56
|
+
- These backslashes are frequently added when a user pastes a URL into a shell without proper quoting.
|
|
57
|
+
- Added `_sanitize_url` and applied it to `fetch_single_url` and `execute_get_url_details`.
|
|
58
|
+
|
|
59
|
+
## 2026-02-01
|
|
60
|
+
|
|
61
|
+
- **Feat**: Switched to `argparse.RawTextHelpFormatter` to allow explicit newlines in CLI help text.
|
|
62
|
+
- **Feat**: Integrated **markdown rendering with `rich`**.
|
|
63
|
+
|
|
64
|
+
- Added `rich` to project dependencies.
|
|
65
|
+
- Implemented `is_markdown` detection in `llm.py`.
|
|
66
|
+
- Updated `run_conversation_loop` in `llm.py` and `print_answers` in `cli.py` to use `rich.markdown.Markdown` for rendering LLM output if markdown is detected.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## 2026-02-01
|
|
71
|
+
|
|
72
|
+
- **Refactor**: Consolidated `-f/--full` and `-s/--summarize` into a single `-s/--summarize` parameter.
|
|
73
|
+
- Removed `-f/--full` flag.
|
|
74
|
+
- Updated `-s/--summarize` to handle both URL content summarization and chat context summarization.
|
|
75
|
+
- Chat context now defaults to full content, and uses summaries only when `-s` is provided.
|
|
76
|
+
- Updated `cli.py` and consolidated tests in `test_cli.py`.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## 2026-02-01
|
|
80
|
+
|
|
81
|
+
- **Fix**: Added **configurable request timeout** for LLM API calls.
|
|
82
|
+
- Added `request_timeout` (default 60s) to `[general]` section in `config.toml`.
|
|
83
|
+
- Updated `get_llm_msg` in `llm.py` to use `REQUEST_TIMEOUT` from `config.py`.
|
|
84
|
+
- Broadened exception handling in `get_llm_msg` to catch and retry all `RequestException` errors (including timeouts).
|
|
85
|
+
- Verified with new unit test simulating connection timeouts and verifying retries.
|
|
86
|
+
|
|
87
|
+
## 2026-02-01
|
|
88
|
+
|
|
89
|
+
- **Refactor**: Removed **multi-threaded execution** from `get_url_content` tool.
|
|
90
|
+
- Replaced `ThreadPoolExecutor` with sequential execution to prevent rate limiting.
|
|
91
|
+
- Simplified `execute_get_url_content` logic.
|
|
92
|
+
- **Feat**: Made **summarization prompts configurable** via `config.toml` under `[prompts]` section.
|
|
93
|
+
- Added `summarize_query` and `summarize_answer` templates with `{QUERY_SUMMARY_MAX_CHARS}` and `{ANSWER_SUMMARY_MAX_CHARS}` placeholders.
|
|
94
|
+
- Updated `llm.py` to use these templates for internal summarization tasks.
|
|
95
|
+
|
|
96
|
+
- **Feat**: Made **User-Agent configurable** via `config.toml` under `[general]` section.
|
|
97
|
+
- Replaced hardcoded UA strings in `tools.py` with `USER_AGENT` constant.
|
|
98
|
+
- Introduced `llm_user_agent` for LLM requests in `llm.py`.
|
|
99
|
+
- Added support for loading both from configuration with sensible defaults.
|
|
100
|
+
- **Fix**: Made `tests/test_cli.py` independent of local configuration by patching `DEFAULT_MODEL` and `MODELS`.
|
|
101
|
+
|
|
102
|
+
- **Fix**: Added `User-Agent` header to all `requests` calls in `tools.py` to resolve **SearXNG 403 Forbidden** errors.
|
|
103
|
+
- **Feat**: Introduced **custom user-defined tool support**.
|
|
104
|
+
- Users can define tools in `config.toml` under `[tool.NAME]`.
|
|
105
|
+
- Supports command execution via `subprocess`.
|
|
106
|
+
- Arguments are automatically quoted (inner quotes removed and wrapped in double quotes).
|
|
107
|
+
- Supports placeholder replacement (e.g., `command = "ls {path}"`) or positional appending.
|
|
108
|
+
- Default `list_dir` tool added to `config.toml`.
|
|
109
|
+
- **Feat**: Added **clipboard support** via `/cp` slash command.
|
|
110
|
+
- Can be used anywhere in the query (not just at start).
|
|
111
|
+
- Integrates with `pyperclip`.
|
|
112
|
+
- **Feat**: Improved **prompt expansion** to be recursive and work anywhere in the query string.
|
|
113
|
+
- **Fix**: Made `tests/test_tools.py` independent of user's local configuration by explicitly patching `SEARCH_PROVIDER`.
|
|
114
|
+
- **Refactor**: Cleaned up CLI code, removed unused imports and fixed lint warnings.
|
|
115
|
+
- **Feat**: Introduced **Serper API** search provider support.
|
|
116
|
+
- Added `search_provider`, `serper_api_url`, and `serper_api_key_env` to `config.toml`.
|
|
117
|
+
- Refactored `execute_web_search` in `tools.py` to dispatch between `SearXNG` and `Serper`.
|
|
118
|
+
- Added full documentation comments for new configuration options.
|
|
119
|
+
- **Fix**: Resolved `AttributeError: 'Namespace' object has no attribute 'prompts'` in CLI tests caused by recent changes.
|
|
120
|
+
- **Refactor**: Moved configuration to `~/.config/asky/config.toml` (TOML format).
|
|
121
|
+
- **Feat**: Added `ConfigLoader` to `src/asky/config.py` to auto-generate default config on first run.
|
|
122
|
+
- **Feat**: Added support for defining API keys directly in `config.toml` or via environment variables (customizable names).
|
|
123
|
+
- **Refactor**: Removed `python-dotenv` dependency and `.env` file loading logic.
|
|
124
|
+
- **Refactor**: Relocated default history database to `~/.config/asky/history.db`. Path is configurable via `config.toml` or environment variable.
|
|
125
|
+
- **Refactor**: Decoupled API and Model definitions in `config.toml`. Now supports `[api.name]` sections used by `[models.name]`.
|
|
126
|
+
- **Feat**: Updated `config.py` to hydrate model configurations with API details (URLs, keys) automatically.
|
|
127
|
+
- **Refactor**: Removed direct `LMSTUDIO` constant usage in favor of data-driven configuration.
|
|
128
|
+
- **Test**: Verified new config schema with `pytest` and CLI execution (-v).
|
|
129
|
+
- **Test**: Verified config generation, loading, and API key precedence. Ran regression tests (50 passed).
|
|
130
|
+
- **Docs**: Added detailed explanatory comments to `src/asky/config.toml` explaining all sections and individual configuration fields.
|
|
131
|
+
|
|
132
|
+
### Dependency Cleanup
|
|
133
|
+
- Removed `liteLLM` dependency (simplified project, reduced bloat).
|
|
134
|
+
- Implemented naive token counting: `len(content) // 4`.
|
|
135
|
+
- Updated tests and matched `run_conversation_loop` tracking.
|
|
136
|
+
|
|
137
|
+
### Debug Flag
|
|
138
|
+
- Added `-v` / `--verbose` flag.
|
|
139
|
+
- Prints full configuration (models, constants) at startup.
|
|
140
|
+
- Prints LLM input previews (truncated) and tool usage status.
|
|
141
|
+
|
|
142
|
+
### Database Cleanup & Bug Fixes
|
|
143
|
+
- Added `--cleanup-db` (delete by ID/list/range/all)
|
|
144
|
+
- Fixed duplicate history output (`ask -H`)
|
|
145
|
+
- Fixed reverse ranges (e.g., `9-6`)
|
|
146
|
+
- Restored `-fs` / `--force-search`
|
|
147
|
+
|
|
148
|
+
### SQLite Conversation History
|
|
149
|
+
- Local SQLite storage (queries, answers, model)
|
|
150
|
+
- Added: `init_db`, `save_interaction`, `get_history`
|
|
151
|
+
- Flags:
|
|
152
|
+
- `-H/--history` view recent history
|
|
153
|
+
- `-c/--continue` load context by ID
|
|
154
|
+
- `-f/--full` load full content
|
|
155
|
+
- Numeric-only query → show past answers
|
|
156
|
+
- Conversation loop returns final answer for storage
|
|
157
|
+
- Added `force_search` logic to system prompt
|
|
158
|
+
|
|
159
|
+
### Documentation
|
|
160
|
+
- Updated `README.md` with "Key Features" and "How it Works" sections to provide a clearer overview of the tool's purpose and functionality.
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
## 2026-01-31
|
|
164
|
+
|
|
165
|
+
### Tools
|
|
166
|
+
- `get_url_content` → fetch + strip HTML (4000 char cap, error handling)
|
|
167
|
+
- `get_url_details` → content + links (Deep Dive, single-use)
|
|
168
|
+
- `get_date_time` → ISO timestamp
|
|
169
|
+
|
|
170
|
+
### HTML Processing
|
|
171
|
+
- `HTMLStripper` (stdlib `html.parser`)
|
|
172
|
+
- Skips `<script>/<style>`, extracts `<a>`
|
|
173
|
+
- Major noise reduction (~734k → ~21k chars)
|
|
174
|
+
|
|
175
|
+
### Tool Execution Engine
|
|
176
|
+
- Multi-turn loop for sequential tool calls
|
|
177
|
+
- Textual tool-call regex fixed (removed strict `$`)
|
|
178
|
+
- Batch URL fetching + concurrency (`ThreadPoolExecutor`)
|
|
179
|
+
- Single-use enforcement for heavy tools
|
|
180
|
+
- Max turns increased to 15
|
|
181
|
+
- Exponential backoff for `429` rate limits
|
|
182
|
+
|
|
183
|
+
### CLI & Config
|
|
184
|
+
- `argparse` integration
|
|
185
|
+
- `-m/--model` selection
|
|
186
|
+
- Unquoted queries supported (`nargs='+'`)
|
|
187
|
+
- Per-model config (`max_chars`, auth, base_url)
|
|
188
|
+
- `.env` support (`python-dotenv`, override enabled)
|
|
189
|
+
- API auth via `api_key_env` or direct `api_key`
|
|
190
|
+
- Added remote model examples (`gpt-4o`, Gemini)
|
|
191
|
+
- Removed hardcoded keys
|
|
192
|
+
|
|
193
|
+
### Modes
|
|
194
|
+
- `-d/--deep-research [N]` → enforce multiple searches (default 3)
|
|
195
|
+
- `-dd/--deep-dive` → recursive link exploration
|
|
196
|
+
- Prompt construction moved to helpers/constants
|
|
197
|
+
|
|
198
|
+
### Refactor & Cleanup
|
|
199
|
+
- Fully modular; ≤30 lines per function
|
|
200
|
+
- Type hints everywhere
|
|
201
|
+
- Removed debug prints / unused imports
|
|
202
|
+
- Safe import guard (`if __name__ == "__main__"`)
|
|
203
|
+
- `strip_think_tags` removes `<think>` blocks
|
|
204
|
+
|
|
205
|
+
### UX / Behavior
|
|
206
|
+
- Query timing with `perf_counter`
|
|
207
|
+
- Numeric-only queries auto-load history
|
|
208
|
+
- Improved system prompts for tool usage
|
|
209
|
+
- Direct SearXNG integration (removed `app.py` dependency)
|
|
210
|
+
|
|
211
|
+
### Misc
|
|
212
|
+
- Lint fixes
|
|
213
|
+
- Improved errors and stability
|
|
214
|
+
|
|
215
|
+
### Added Unit Tests
|
|
216
|
+
- Installed `pytest` and configured it for the project.
|
|
217
|
+
- Created comprehensive unit tests for core modules:
|
|
218
|
+
- `html.py`: HTML stripping and tag handling.
|
|
219
|
+
- `tools.py`: Web search, URL fetching, and date utilities (mocked network calls).
|
|
220
|
+
- `storage.py`: Database initialization, history storage, and cleanup (using temp DB).
|
|
221
|
+
- `config.py`: Configuration validation.
|
|
222
|
+
- `llm.py`: Helper functions and API call logic (mocked external APIs).
|
|
223
|
+
- Verified all tests pass with `uv run pytest`.
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
### Expanded Unit Coverage
|
|
227
|
+
- Created `tests/test_cli.py` to cover all CLI functionality including argument parsing, history display, and context loading.
|
|
228
|
+
- Updated `tests/test_llm.py` to test the core conversation loop (`run_conversation_loop`) and summarization logic (`generate_summaries`) using mocks.
|
|
229
|
+
- Updated `tests/test_tools.py` to test text summarization (`summarize_text`).
|
|
230
|
+
- Updated `tests/test_storage.py` to cover edge cases in database cleanup (e.g., reverse ranges).
|
|
231
|
+
- Achieved 100% pass rate for 47 unit tests.
|
|
232
|
+
- **Refactor**: Replaced dynamic configuration generation with a bundled `config.toml`. The default configuration file is now shipped with the package and copied to the user's config directory on first run.
|
|
233
|
+
- **Feat**: Enhanced `asky -c` (continue) to support relative history IDs. Users can now use `~1` (most recent), `~2` (second most recent), etc., instead of looking up exact database IDs.
|
|
234
|
+
- **Feat**: Added support for **Predefined Prompts**. Users can define reusable prompts in `config.toml` under `[user_prompts]` and invoke them via `/key` (e.g., `ask /wh Rotterdam`).
|
|
235
|
+
- **Feat**: Added `--prompts` / `-p` flag to list configured user prompts.
|
|
236
|
+
- **Change**: Renamed `--print-answer` short flag from `-p` to `-pa` to accommodate the new prompts flag.
|
|
237
|
+
|
asky_cli-0.1.6/PKG-INFO
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: asky-cli
|
|
3
|
+
Version: 0.1.6
|
|
4
|
+
Summary: AI-powered web search CLI with LLM tool-calling capabilities
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: pyperclip>=1.11.0
|
|
8
|
+
Requires-Dist: requests
|
|
9
|
+
Requires-Dist: rich
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<img src="assets/asearch_icon.png" alt="asky icon" width="200" align="right">
|
|
14
|
+
|
|
15
|
+
<font size="6">**asky**</font>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
AI-powered web search CLI with LLM tool-calling capabilities.
|
|
19
|
+
|
|
20
|
+
asky (can be invoked as `asky` or `ask`) is a powerful command-line interface that brings AI-powered search and research capabilities directly to your terminal. It uses LLMs and tools to synthesize answers from the web (or from files and apps you have on your computer).
|
|
21
|
+
## Key Features
|
|
22
|
+
|
|
23
|
+
- **Multi-Model Support**: Easily define and switch between various LLMs and providers that supports OpenAI compatible API.
|
|
24
|
+
- **Tool-Calling Integration**: Models can autonomously perform web searches (via SearXNG or Serper API), fetch URL content, and get current date/time to provide accurate, up-to-date answers.
|
|
25
|
+
- **Intelligent Content Fetching**: Automatically strips HTML noise (scripts, styles) to provide clean text context to the models.
|
|
26
|
+
- **Conversation History**: Maintains a local SQLite database of your queries and answers, allowing for context-aware follow-up questions.
|
|
27
|
+
- **Deep Research Mode**: Automatically performs multiple searches to provide comprehensive analysis of complex topics.
|
|
28
|
+
- **Deep Dive Mode**: Recursively explores links found on web pages for in-depth information gathering.
|
|
29
|
+
- **Predefined Prompts**: Save and quickly invoke common prompt patterns using simple slashes (e.g., `/gn` for get latest news from The Guardian).
|
|
30
|
+
- **Clipboard Integration**: Use `/cp` to expand the query with clipboard content.
|
|
31
|
+
- **Custom Tools**: Expose any CLI command as a tool for the LLM. Define your own commands and parameters in `config.toml`.
|
|
32
|
+
|
|
33
|
+
## How it Works
|
|
34
|
+
|
|
35
|
+
1. **User Query**: You provide a query to the `ask` command.
|
|
36
|
+
2. **Model Selection**: asky initializes the selected LLM based on your configuration.
|
|
37
|
+
3. **Tool Loop**: The LLM analyzes your query. If it needs real-world data, it calls integrated tools (like `web_search`).
|
|
38
|
+
4. **Context Synthesis**: asky fetches the data, cleans it, and feeds it back to the LLM. This process can repeat for up to 15 turns for complex research.
|
|
39
|
+
5. **Final Answer**: The LLM synthesizes all gathered information into a concise, formatted response.
|
|
40
|
+
6. **Persistence**: The interaction is saved to your local history for future reference.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install ask-cli
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or install from source:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -e .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
# Basic query
|
|
60
|
+
ask what is the weather in Berlin
|
|
61
|
+
|
|
62
|
+
# Continue from previous query (by ID)
|
|
63
|
+
ask -c 1 tell me more about that
|
|
64
|
+
|
|
65
|
+
# Continue from last query (relative ID)
|
|
66
|
+
ask -c~1 explain more
|
|
67
|
+
# OR
|
|
68
|
+
ask -c "~2" what about the one before that?
|
|
69
|
+
|
|
70
|
+
> [!NOTE]
|
|
71
|
+
> **Zsh Users**: When using `~` for relative IDs, you must either quote the value (e.g., `ask -c "~1"`) or place it immediately after the flag without a space (e.g., `ask -c~1`). If you use a space without quotes (e.g., `ask -c ~1`), zsh will attempt to expand it as a directory stack entry.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
➜ ~ ask -p
|
|
75
|
+
|
|
76
|
+
=== USER PROMPTS ===
|
|
77
|
+
/gn : Give me latest news from The Guardian, use https://www.theguardian.com/europe
|
|
78
|
+
/wh : how is weather in
|
|
79
|
+
====================
|
|
80
|
+
|
|
81
|
+
➜ ~ ask /wh delft
|
|
82
|
+
Dispatching tool call: web_search with args {'q': 'weather in Delft'}
|
|
83
|
+
Dispatching tool call: get_url_content with args {'urls': ...}
|
|
84
|
+
|
|
85
|
+
The weather in **Delft, South Holland, Netherlands** is currently **45°F and Cloudy with Showers in the Vicinity** (as of 4:20 pm CET).
|
|
86
|
+
|
|
87
|
+
Here is the forecast for today and the next couple of days:
|
|
88
|
+
|
|
89
|
+
...
|
|
90
|
+
|
|
91
|
+
Query completed in 3.88 seconds
|
|
92
|
+
|
|
93
|
+
--------------------------------------------------------------------------------
|
|
94
|
+
➜ ~ ask --help
|
|
95
|
+
usage: ask [-h] [-m {gf,glmair,glmflash,q34t,q34,lfm,q8,q30,onano,omini}] [-d [DEEP_RESEARCH]] [-dd] [-c CONTINUE_IDS] [-s] [-fs] [--cleanup-db [CLEANUP_DB]] [--all]
|
|
96
|
+
[-H [HISTORY]] [-pa PRINT_IDS] [-p] [-v]
|
|
97
|
+
[query ...]
|
|
98
|
+
|
|
99
|
+
Tool-calling CLI with model selection.
|
|
100
|
+
|
|
101
|
+
positional arguments:
|
|
102
|
+
query The query string
|
|
103
|
+
|
|
104
|
+
options:
|
|
105
|
+
-h, --help show this help message and exit
|
|
106
|
+
-m, --model {gf,glmair,glmflash,q34t,q34,lfm,q8,q30,onano,omini}
|
|
107
|
+
Select the model alias
|
|
108
|
+
-d, --deep-research [DEEP_RESEARCH]
|
|
109
|
+
Enable deep research mode (optional: specify min number of queries, default 5)
|
|
110
|
+
-dd, --deep-dive Enable deep dive mode (extracts links and encourages reading more pages from same domain)
|
|
111
|
+
-c, --continue-chat CONTINUE_IDS
|
|
112
|
+
Continue conversation with context from specific history IDs (comma-separated, e.g. '1,2').
|
|
113
|
+
-s, --summarize Enable summarize mode (summarizes URL content and uses summaries for chat context)
|
|
114
|
+
-fs, --force-search Force the model to use web search (default: False).
|
|
115
|
+
Helpful for avoiding hallucinations with small models
|
|
116
|
+
--cleanup-db [CLEANUP_DB]
|
|
117
|
+
Delete history records. usage: --cleanup-db [ID|ID-ID|ID,ID] or --cleanup-db --all
|
|
118
|
+
--all Used with --cleanup-db to delete ALL history.
|
|
119
|
+
-H, --history [HISTORY]
|
|
120
|
+
Show last N queries and answer summaries (default 10).
|
|
121
|
+
Use with --print-answer to print the full answer(s).
|
|
122
|
+
-pa, --print-answer PRINT_IDS
|
|
123
|
+
Print the answer(s) for specific history IDs (comma-separated).
|
|
124
|
+
-p, --prompts List all configured user prompts.
|
|
125
|
+
-v, --verbose Enable verbose output (prints config and LLM inputs).
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Deep research mode** (encourages model to perform multiple searches)
|
|
129
|
+
|
|
130
|
+
ask -d 5 comprehensive analysis of topic
|
|
131
|
+
|
|
132
|
+
**Deep dive mode** (encourages model to read multiple pages from same domain)
|
|
133
|
+
|
|
134
|
+
ask -dd https://example.com
|
|
135
|
+
|
|
136
|
+
**Use a specific model**
|
|
137
|
+
|
|
138
|
+
ask -m gf what is quantum computing
|
|
139
|
+
|
|
140
|
+
**Force web search**
|
|
141
|
+
|
|
142
|
+
ask -fs latest news on topic
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
**Pre-configured model definitions**
|
|
146
|
+
|
|
147
|
+
Followin model definitions ship with default config.toml, but you can add any number of models that are served with an OpenAI compatible API.
|
|
148
|
+
|
|
149
|
+
- `gf` - Google Gemini Flash (default)
|
|
150
|
+
- `lfm` - Liquid LFM 2.5
|
|
151
|
+
- `q8` - Qwen3 8B
|
|
152
|
+
- `q30` - Qwen3 30B
|
|
153
|
+
- `q34` - Qwen3 4B
|
|
154
|
+
- `q34t` - Qwen3 4B Thinking
|
|
155
|
+
|
|
156
|
+
## Custom Tools
|
|
157
|
+
|
|
158
|
+
You can define your own tools in `config.toml` that the LLM can use to interact with your local system. Each tool runs a CLI command and returns the output to the LLM.
|
|
159
|
+
|
|
160
|
+
Example configuration for a `list_dir` tool:
|
|
161
|
+
|
|
162
|
+
```toml
|
|
163
|
+
[tool.list_dir]
|
|
164
|
+
command = "ls"
|
|
165
|
+
description = "List the contents of a directory."
|
|
166
|
+
|
|
167
|
+
[tool.list_dir.parameters]
|
|
168
|
+
type = "object"
|
|
169
|
+
required = ["path"]
|
|
170
|
+
|
|
171
|
+
[tool.list_dir.parameters.properties.path]
|
|
172
|
+
type = "string"
|
|
173
|
+
default = "."
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Example configuration for a `grep_search` tool:
|
|
177
|
+
|
|
178
|
+
```toml
|
|
179
|
+
[tool.grep_search]
|
|
180
|
+
command = "grep -r {pattern} {path}"
|
|
181
|
+
description = "Search for a pattern in files recursively."
|
|
182
|
+
|
|
183
|
+
[tool.grep_search.parameters]
|
|
184
|
+
type = "object"
|
|
185
|
+
required = ["pattern"]
|
|
186
|
+
|
|
187
|
+
[tool.grep_search.parameters.properties.pattern]
|
|
188
|
+
type = "string"
|
|
189
|
+
description = "The regex pattern to search for."
|
|
190
|
+
|
|
191
|
+
[tool.grep_search.parameters.properties.path]
|
|
192
|
+
type = "string"
|
|
193
|
+
description = "The directory path to search in."
|
|
194
|
+
default = "."
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
> [!CAUTION]
|
|
198
|
+
> **Security Risk**: Custom tools execute commands using your system shell. While asky attempts to quote arguments safely, exposing powerful CLI tools to an LLM can be risky. Use this feature with caution.
|
|
199
|
+
|
|
200
|
+
### How it works:
|
|
201
|
+
- **Placeholders**: Use `{param_name}` in the `command` string to inject arguments. If no placeholders are found, arguments are appended to the command.
|
|
202
|
+
- **Quoting**: All arguments are automatically cleaned (inner double-quotes removed) and wrapped in double-quotes for safety.
|
|
203
|
+
- **Execution**: Commands are executed via terminal shell, allowing for advanced piping and redirection.
|
|
204
|
+
|
|
205
|
+
> [!TIP]
|
|
206
|
+
> **Performance Tip**: When using recursive tools like `grep`, consider excluding large directories like `.venv` or `node_modules` to avoid timeouts:
|
|
207
|
+
> `command = "grep -r --exclude-dir={.venv,node_modules} {pattern} {path}"`
|
|
208
|
+
|
|
209
|
+
> [!NOTE]
|
|
210
|
+
> **Optional Parameters**: If you define a parameter with a `default` value in `config.toml`, it will be automatically injected into your `command` if the LLM omits it.
|
|
211
|
+
|
|
212
|
+
## Configuration options
|
|
213
|
+
[See default configuration](./src/asky/config.toml)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
On first run, a default configuration file is created at `~/.config/asky/config.toml`. You can edit this file to configure models, API keys, and other settings.
|
|
217
|
+
|
|
218
|
+
### API Keys
|
|
219
|
+
You can set API keys in two ways:
|
|
220
|
+
1. **Environment Variables**: Set `GOOGLE_API_KEY` (or other configured env vars) in your shell.
|
|
221
|
+
2. **Config File**: Add keys directly to `[api.name]` sections in `config.toml`.
|
|
222
|
+
|
|
223
|
+
Example `config.toml`:
|
|
224
|
+
```toml
|
|
225
|
+
[general]
|
|
226
|
+
default_model = "gf"
|
|
227
|
+
|
|
228
|
+
[api.gemini]
|
|
229
|
+
api_key_env = "GOOGLE_API_KEY"
|
|
230
|
+
|
|
231
|
+
[api.lmstudio]
|
|
232
|
+
url = "http://localhost:1234/v1/chat/completions"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Verification
|
|
236
|
+
Run with `-v` to see the loaded configuration:
|
|
237
|
+
```bash
|
|
238
|
+
ask -v
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
## Web Search
|
|
243
|
+
|
|
244
|
+
asky works best with a web search tool. You can use SearXNG or Serper API.
|
|
245
|
+
|
|
246
|
+
### Serper API
|
|
247
|
+
Serper is a paid service, but gives 2500 requests for free.
|
|
248
|
+
|
|
249
|
+
### Install & configure SearXNG
|
|
250
|
+
SearXNG is free and open source, it's easy to set up with a single docker command.
|
|
251
|
+
|
|
252
|
+
Following command taken from [SearXNG docs](https://docs.searxng.org/admin/installation-docker.html#instancing).
|
|
253
|
+
```bash
|
|
254
|
+
docker pull docker.io/searxng/searxng:latest
|
|
255
|
+
|
|
256
|
+
# Create directories for configuration and persistent data
|
|
257
|
+
$ mkdir -p ./searxng/config/ ./searxng/data/
|
|
258
|
+
$ cd ./searxng/
|
|
259
|
+
|
|
260
|
+
# Run the container
|
|
261
|
+
$ docker run --name searxng -d \
|
|
262
|
+
-p 8888:8080 \
|
|
263
|
+
-v "./config/:/etc/searxng/" \
|
|
264
|
+
-v "./data/:/var/cache/searxng/" \
|
|
265
|
+
docker.io/searxng/searxng:latest
|
|
266
|
+
```
|
|
267
|
+
You need to add "-json" to the formats section of the default searxng config.yaml file.
|
|
268
|
+
```yaml
|
|
269
|
+
# remove format to deny access, use lower case.
|
|
270
|
+
# formats: [html, csv, json, rss]
|
|
271
|
+
formats:
|
|
272
|
+
- html
|
|
273
|
+
- json
|
|
274
|
+
```
|
|
275
|
+
Then restart the container.
|
|
276
|
+
```bash
|
|
277
|
+
docker restart searxng
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
## Requirements
|
|
283
|
+
|
|
284
|
+
- Python 3.10+
|
|
285
|
+
- Running SearXNG instance or Serper API key.
|
|
286
|
+
- LM Studio (for local models) or API keys for remote models
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
MIT
|