ollama_chat 0.0.121 → 0.0.123
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.
- checksums.yaml +4 -4
- data/CHANGES.md +211 -0
- data/README.md +67 -11
- data/Rakefile +2 -2
- data/lib/ollama_chat/asr.rb +110 -0
- data/lib/ollama_chat/chat.rb +27 -4
- data/lib/ollama_chat/commands.rb +36 -26
- data/lib/ollama_chat/conversation.rb +3 -2
- data/lib/ollama_chat/database/models/session.rb +1 -1
- data/lib/ollama_chat/dialog.rb +6 -0
- data/lib/ollama_chat/http_handling.rb +25 -0
- data/lib/ollama_chat/information.rb +7 -1
- data/lib/ollama_chat/invidious.rb +162 -0
- data/lib/ollama_chat/kramdown_ansi.rb +22 -11
- data/lib/ollama_chat/model_handling.rb +23 -2
- data/lib/ollama_chat/oc.rb +53 -0
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +4 -1
- data/lib/ollama_chat/parsing.rb +54 -11
- data/lib/ollama_chat/personae_management.rb +1 -1
- data/lib/ollama_chat/prompt_management.rb +66 -2
- data/lib/ollama_chat/redis_cache.rb +1 -1
- data/lib/ollama_chat/say.rb +4 -0
- data/lib/ollama_chat/session_management.rb +28 -39
- data/lib/ollama_chat/source_fetching.rb +20 -11
- data/lib/ollama_chat/speaker.rb +70 -0
- data/lib/ollama_chat/state_selectors.rb +35 -11
- data/lib/ollama_chat/think_control.rb +39 -9
- data/lib/ollama_chat/tools/compute_bmi.rb +2 -2
- data/lib/ollama_chat/tools/execute_grep.rb +4 -0
- data/lib/ollama_chat/tools/generate_image.rb +5 -5
- data/lib/ollama_chat/tools/get_url.rb +29 -4
- data/lib/ollama_chat/tools/patch_file.rb +5 -1
- data/lib/ollama_chat/tts.rb +25 -22
- data/lib/ollama_chat/utils/audio_player.rb +1 -1
- data/lib/ollama_chat/utils/fetcher.rb +40 -10
- data/lib/ollama_chat/utils/png_metadata_extractor.rb +1 -0
- data/lib/ollama_chat/utils.rb +7 -7
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat.rb +2 -0
- data/ollama_chat.gemspec +7 -7
- data/spec/assets/linux.oga +0 -0
- data/spec/ollama_chat/asr_spec.rb +89 -0
- data/spec/ollama_chat/commands_spec.rb +122 -20
- data/spec/ollama_chat/conversation_spec.rb +1 -1
- data/spec/ollama_chat/http_handling_spec.rb +145 -0
- data/spec/ollama_chat/invidious_spec.rb +238 -0
- data/spec/ollama_chat/kramdown_ansi_spec.rb +60 -0
- data/spec/ollama_chat/message_list_spec.rb +1 -2
- data/spec/ollama_chat/model_handling_spec.rb +42 -0
- data/spec/ollama_chat/parsing_spec.rb +61 -2
- data/spec/ollama_chat/session_management_spec.rb +26 -15
- data/spec/ollama_chat/source_fetching_spec.rb +32 -0
- data/spec/ollama_chat/tools/directory_structure_spec.rb +1 -1
- data/spec/ollama_chat/tools/get_url_spec.rb +58 -19
- data/spec/ollama_chat/tts_spec.rb +11 -13
- data/spec/ollama_chat/utils/audio_player_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -1
- metadata +30 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2d0c5676e03433f245a21795872a9d7bd64357306ec691de3012195b5403bef
|
|
4
|
+
data.tar.gz: 933dca2b53647c523b9849d958cc1625106c97500caf2814bc731458a0e683f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4589b5f1cf689bb35bdf26c288e59f40b87ef926eaf7f91e187c3fa729958c9d042f784eb3bf9a4b6e64966c201312713c2e20607291c6aabc10d306cf4cf272
|
|
7
|
+
data.tar.gz: 19102c3d01a2ebb4bb14b8ea617b09a7e168d0175225024a490dc85e23b41ce3c7eba249d82cc671f5530da0090e945f8f6358d17ca7f6b7587a413002e27dc2
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,216 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-09-25 v0.0.123
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
* README section 5 documenting `/conversation compact`: token-aware
|
|
8
|
+
keep-recent budget, safe & retryable behavior, visible before/after
|
|
9
|
+
metrics, and iterative re-compaction.
|
|
10
|
+
* Three-step context escalation ladder in the README: `/conversation
|
|
11
|
+
compact` first, then `/conversation report` + `/clear` + `/input path`
|
|
12
|
+
as the preferred second step, and `/conversation clean` as the emergency
|
|
13
|
+
exit.
|
|
14
|
+
* `execute_shell` tool to the Filesystem row in the README, noted as running
|
|
15
|
+
shell commands as a last resort.
|
|
16
|
+
* `execute_jira_twg` tool to the Web/External row in the README for running
|
|
17
|
+
Jira CLI queries via `twg`.
|
|
18
|
+
* `lookup_group` tool to the Knowledge row in the README for retrieving prior
|
|
19
|
+
conversation groups by UUID.
|
|
20
|
+
* Speech Services (ASR) section documenting `OLLAMA_CHAT_ASR_URL`,
|
|
21
|
+
`OLLAMA_CHAT_ASR_CONVERT_COMMAND`, and `OLLAMA_CHAT_ASR_MODEL`.
|
|
22
|
+
* Audio Playback section documenting `OLLAMA_CHAT_AUDIO_PLAYER_CONFIG`.
|
|
23
|
+
* Invidious (YouTube Proxy) section documenting `OLLAMA_CHAT_INVIDIOUS_URL`,
|
|
24
|
+
`OLLAMA_CHAT_INVIDIOUS_COMPANION_KEY`, and
|
|
25
|
+
`OLLAMA_CHAT_INVIDIOUS_CAPTION_LANGUAGES`.
|
|
26
|
+
* `markdown:` keyword argument (default `true`) to
|
|
27
|
+
`kramdown_markdown_remove`; when `false`, skips the `kramdown_ansi_parse`
|
|
28
|
+
step while still removing emoji, ANSI, and box-drawing characters.
|
|
29
|
+
* Explanatory comment block to `eval_template` in
|
|
30
|
+
`lib/ollama_chat/tools/execute_grep.rb` clarifying that the `cmd` config
|
|
31
|
+
value is a Ruby string template whose `#{...}` interpolations are resolved
|
|
32
|
+
against the method's local parameters via `eval`.
|
|
33
|
+
* `cleaned` string prefix in `save_conversation` so the `STDOUT`/`STDERR`
|
|
34
|
+
confirmation messages read "Saved cleaned conversation to…" when `clean:
|
|
35
|
+
true` is passed.
|
|
36
|
+
* "Cancelled." message when the user skips saving in conversation report and
|
|
37
|
+
summarize flows.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
* Renamed `report_session` to `generate_conversation_report` to clarify it
|
|
42
|
+
only builds the report text.
|
|
43
|
+
* Reworked `report_conversation` to always display in the pager first, then
|
|
44
|
+
optionally save to a file; removed the `save:` keyword argument.
|
|
45
|
+
* Reworked `summarize_conversation` in `session_management.rb` to always
|
|
46
|
+
render via `use_pager` first, then optionally save via `ask_for_filename?`
|
|
47
|
+
and `should_overwrite?`.
|
|
48
|
+
* Removed the `save:` keyword argument from `summarize_conversation` and the
|
|
49
|
+
`-f` flag from the `/conversation` command dispatch in `commands.rb`.
|
|
50
|
+
* Tightened the `/conversation` regex from `(?:[sf]|c)` to `[sc]` and updated
|
|
51
|
+
the `options:` help text to drop `-f save`.
|
|
52
|
+
* Changed "Nothing to summarize!" and "Nothing to report!" output from
|
|
53
|
+
`STDERR` to `STDOUT`.
|
|
54
|
+
* `kramdown_markdown_remove` now strips `\p{Extended_Pictographic}` emoji
|
|
55
|
+
before any further processing, preventing TTS engines from vocalizing them.
|
|
56
|
+
* `kramdown_markdown_remove` in `lib/ollama_chat/kramdown_ansi.rb` now strips
|
|
57
|
+
Unicode box-drawing characters (`U+2500`..`U+257F`) that kramdown renders
|
|
58
|
+
as table borders, preventing TTS engines from stammering on them.
|
|
59
|
+
* Collapses resulting multi-space runs and strips leading/trailing whitespace
|
|
60
|
+
in `kramdown_markdown_remove`.
|
|
61
|
+
* Moved the `kramdown_markdown_remove` call from `flush_buffer` into
|
|
62
|
+
`enqueue_tts` in `lib/ollama_chat/tts.rb` so all enqueue paths are covered,
|
|
63
|
+
passing `markdown: @chat.markdown.on?`.
|
|
64
|
+
* `multipart_form_data` in `lib/ollama_chat/asr.rb` now returns a hash
|
|
65
|
+
containing only `headers:`, `expects:`, and `body:`, which are the actual
|
|
66
|
+
Excon request options, instead of merging `rest` (`model:`, `language:`)
|
|
67
|
+
into the returned options hash.
|
|
68
|
+
* Updated YARD documentation to reflect the new parameter and emoji stripping
|
|
69
|
+
behavior.
|
|
70
|
+
* Updated `spec/ollama_chat/asr_spec.rb` expectations from
|
|
71
|
+
`hash_including(model: ...)` / `hash_including(language: ...)` to
|
|
72
|
+
`hash_including(body: kind_of(String))` to match the new option shape.
|
|
73
|
+
* Updated `commands_spec.rb` to remove the obsolete `/conversation summarize
|
|
74
|
+
-f` and `/conversation report -f` specs and drop `save:` from expectations.
|
|
75
|
+
* Updated `session_management_spec.rb` for the new show-then-save flow,
|
|
76
|
+
`STDOUT` stream, and `Cancelled.` expectation.
|
|
77
|
+
* Updated the corresponding expectation in `conversation_spec.rb` to match
|
|
78
|
+
the new message text.
|
|
79
|
+
* Renamed former section 5 "Session Reports" to section 6 "Conversation
|
|
80
|
+
Reports" to match the actual command name.
|
|
81
|
+
* Updated Conversation Archiving section from `/session summarize` to
|
|
82
|
+
`/conversation summarize`, removed obsolete `-f` flag reference, and
|
|
83
|
+
described the show-then-save flow.
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
* Fixed `TTS_URL` to `OLLAMA_CHAT_TTS_URL` to match the actual env var name
|
|
87
|
+
in `oc.rb`.
|
|
88
|
+
* Wrapped `@prefix` with `Regexp.quote()` in `RedisCache#unpre` to ensure the
|
|
89
|
+
prefix is always matched as a literal string.
|
|
90
|
+
* Fixed typos in height validation error message.
|
|
91
|
+
|
|
92
|
+
### Removed
|
|
93
|
+
* `context_spook` from development dependencies in `Rakefile` and
|
|
94
|
+
`ollama_chat.gemspec`.
|
|
95
|
+
* The `-f` flag from the `/report` command in `commands.rb`.
|
|
96
|
+
|
|
97
|
+
## 2026-09-25 v0.0.122
|
|
98
|
+
|
|
99
|
+
## Features
|
|
100
|
+
|
|
101
|
+
* **Per-model thinking-state support**: Added support for per-model thinking
|
|
102
|
+
states via the `/api/show` endpoint.
|
|
103
|
+
* Replaced the `THINK_MODE_STATES` constant with a `think_mode_states`
|
|
104
|
+
method that reads `@model_metadata&.thinking&.full?(:values)` to return
|
|
105
|
+
a per-model subset, falling back to the full superset for
|
|
106
|
+
pre-**0.34.3** Ollama or non-thinking models.
|
|
107
|
+
* Added `normalize_think_state` helper to canonicalize boolean
|
|
108
|
+
(`true`/`false`) and string (`"low"`/`"high"`/`"max"`) thinking values.
|
|
109
|
+
* Added `:thinking` field to `ModelMetadata` data class.
|
|
110
|
+
* Implemented think-mode clamping in `use_model` to disable thinking for
|
|
111
|
+
non-thinking models or clamp to the model's default when the current
|
|
112
|
+
level is unavailable.
|
|
113
|
+
* Converted `DatabaseStateSelector` `states`/`off` to support `Proc` via
|
|
114
|
+
`ask_and_send_or_self(:call, @chat)`.
|
|
115
|
+
* Converted `think_mode` and `voices` selectors in
|
|
116
|
+
`setup_state_selectors` to lambda-based `states:`.
|
|
117
|
+
* Added `Thinking` display line to `info_model`.
|
|
118
|
+
* **Invidious YouTube captions**: Added `OllamaChat::Invidious` to fetch
|
|
119
|
+
video metadata and transcripts from an Invidious companion instance.
|
|
120
|
+
* Uses `POST /companion/youtubei/v1/player` for `videoDetails` and
|
|
121
|
+
`captionTracks`.
|
|
122
|
+
* Selects the best caption track by priority-ordered language regexes.
|
|
123
|
+
* Fetches timedtext XML and extracts `<text>` elements via `Nokogiri`,
|
|
124
|
+
decoding double-encoded HTML entities.
|
|
125
|
+
* Returns a formatted markdown header + transcript as a text IO.
|
|
126
|
+
* **Unified HTTP handling**: Added `HTTPHandling#request_url_response` to
|
|
127
|
+
consolidate `Excon.new` call sites, merging `http_options` (SSL, proxy)
|
|
128
|
+
with caller-supplied options.
|
|
129
|
+
* Updated `ASR.transcribe`, `TTS.voices`, `TTS#fetch_tts`,
|
|
130
|
+
`GenerateImage#post_url`, `GenerateImage#get_url`, `GetURL#execute`,
|
|
131
|
+
`Invidious.fetch_video_info`, and `SourceFetching#fetch_source` to
|
|
132
|
+
route through this method.
|
|
133
|
+
* Extracted audio/video MIME regex into `HAS_AUDIO` constant shared by
|
|
134
|
+
`parse_source` and the `get_url` tool.
|
|
135
|
+
* Split `Fetcher` `middlewares` into class-level `self.middlewares` and
|
|
136
|
+
instance delegate; added `RedirectFollower` to the default stack.
|
|
137
|
+
* Added `middlewares:` to streaming `excon` requests in `fetcher.rb`.
|
|
138
|
+
* **One-shot voice notification**: Added `OllamaChat::Speaker` concern
|
|
139
|
+
providing `speak(text, background:)` and `cancel_speaking`.
|
|
140
|
+
* `OllamaChat::TTS` and `OllamaChat::Say` now include
|
|
141
|
+
`OllamaChat::Speaker`.
|
|
142
|
+
* Added `Chat#speak` facade to resolve the configured voice handler.
|
|
143
|
+
* `Dialog#readline_prompt` and `Dialog#confirm?` now speak the prompt
|
|
144
|
+
with a 10-second delay.
|
|
145
|
+
* `Tools::PatchFile` announces "You can review the patch for the file …
|
|
146
|
+
now!" before opening `vimdiff`.
|
|
147
|
+
* `AudioPlayer#start` redirects `ffplay` stdout/stderr to `/dev/null`.
|
|
148
|
+
* **ASR transcription pipeline**: Added `OllamaChat::ASR` client for
|
|
149
|
+
audio/video transcription.
|
|
150
|
+
* Uploads audio/video as multipart form-data to the audio.cpp
|
|
151
|
+
`/v1/audio/transcriptions` endpoint.
|
|
152
|
+
* Converts video sources to 16 kHz mono PCM WAV via a configurable
|
|
153
|
+
`ffmpeg` command (`CONVERT_COMMAND`).
|
|
154
|
+
* Added `OC::OLLAMA::CHAT::ASR` config module with `URL`,
|
|
155
|
+
`CONVERT_COMMAND`, and `MODEL` settings.
|
|
156
|
+
* Extended `/input` command with `-l <language>` option.
|
|
157
|
+
* Routed `audio/*`, `video/*`, and specific `application/` MIME types
|
|
158
|
+
into `parse_audio`.
|
|
159
|
+
* Added `Fetcher::ResponseMetadata.as_text(text)` factory for synthetic
|
|
160
|
+
`text/plain` IO responses.
|
|
161
|
+
* Replaced hardcoded timeouts in `lib/ollama_chat/tts.rb` with values
|
|
162
|
+
from `config.timeouts`.
|
|
163
|
+
* **Audio/Video support in `get_url`**: Added `language` parameter to the
|
|
164
|
+
`get_url` tool definition for optional transcription hints.
|
|
165
|
+
* Pre-transcribes `audio/*` and `video/*` sources via `chat.parse_audio`
|
|
166
|
+
before content-type dispatch.
|
|
167
|
+
* Threads `language:` kwarg into `chat.import_source`.
|
|
168
|
+
* **Prompt management enhancements**:
|
|
169
|
+
* Added `reset_prompt_count` and `choose_and_reset_count` to
|
|
170
|
+
`lib/ollama_chat/prompt_management.rb`.
|
|
171
|
+
* Added `/prompt reset count` command.
|
|
172
|
+
* Added `count:` keyword argument to `choose_prompt` to increment
|
|
173
|
+
`metadata['use_count']`.
|
|
174
|
+
* Changed `all_prompts` sort to `use_count` descending, falling back to
|
|
175
|
+
name for tie-breaking.
|
|
176
|
+
* Added `-i` summary instruction flag to `/input` command to prompt for
|
|
177
|
+
an optional instruction.
|
|
178
|
+
* Added `instruction` parameter to `get_url` summarizing, threading it
|
|
179
|
+
through `summarize_source` and `summarize`.
|
|
180
|
+
* **Config-driven default persona**: Added `persona.default_name` to
|
|
181
|
+
`default_config.yml`.
|
|
182
|
+
* Updated `initial_persona_name` in `personae_management.rb` to fall back
|
|
183
|
+
to `config.persona&.default_name`.
|
|
184
|
+
|
|
185
|
+
## Improvements
|
|
186
|
+
|
|
187
|
+
* **CI and Dependencies**:
|
|
188
|
+
* Added `ffmpeg` to the CI Docker image.
|
|
189
|
+
* Added `nokogiri ~> 1.0` dependency.
|
|
190
|
+
* Bumped `tins ~> 1.58`.
|
|
191
|
+
* Added `require 'ollama_chat/utils/utf8_converter'` in
|
|
192
|
+
`png_metadata_extractor.rb`.
|
|
193
|
+
* Reorganized `require` statements in `lib/ollama_chat/utils.rb`
|
|
194
|
+
alphabetically.
|
|
195
|
+
* **Error Handling**:
|
|
196
|
+
* In `lib/ollama_chat/asr.rb`, capture the return value of `system` to
|
|
197
|
+
detect missing executables and print a clear "not found in PATH"
|
|
198
|
+
message.
|
|
199
|
+
* Extract executable name via `Shellwords.split(cmd).first` for error
|
|
200
|
+
messages.
|
|
201
|
+
* **Documentation**:
|
|
202
|
+
* Updated `ollama_chat` description in README to be more concise and
|
|
203
|
+
user-focused.
|
|
204
|
+
* Updated YARD in `session.rb`, `state_selectors.rb`, and
|
|
205
|
+
`think_control.rb` to reference `Chat#think_mode_states`.
|
|
206
|
+
|
|
207
|
+
## Bug Fixes
|
|
208
|
+
|
|
209
|
+
* **Pager Spec**: Changed `expect(Tins::Terminal).to receive(:lines)` to
|
|
210
|
+
`allow(Tins::Terminal).to receive(:lines)` in
|
|
211
|
+
`spec/ollama_chat/message_list_spec.rb` and removed the `skip 'no tty'`
|
|
212
|
+
guard.
|
|
213
|
+
|
|
3
214
|
## 2026-09-18 v0.0.121
|
|
4
215
|
|
|
5
216
|
* Added `**_kwargs` splat to `Say.voices` to prevent `ArgumentError` when the
|
data/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Description
|
|
4
4
|
|
|
5
|
-
**ollama_chat** is a chat client
|
|
6
|
-
server and
|
|
5
|
+
**ollama_chat** is a terminal chat client that connects to an Ollama
|
|
6
|
+
server and lets you converse with the LLMs it provides.
|
|
7
7
|
|
|
8
8
|
## Documentation
|
|
9
9
|
|
|
@@ -62,7 +62,7 @@ The following environment variables can be used to configure behavior:
|
|
|
62
62
|
- `OLLAMA_URL` - Base URL for Ollama server (default: `http://localhost:11434`)
|
|
63
63
|
- `OLLAMA_HOST` - Base hostname for Ollama server (default: `localhost:11434`)
|
|
64
64
|
- `OLLAMA_SEARXNG_URL` - SearxNG search endpoint URL
|
|
65
|
-
- `
|
|
65
|
+
- `OLLAMA_CHAT_TTS_URL` - Base URL for the [audio.cpp](https://github.com/0xshug0/audio.cpp) TTS server (default: `http://localhost:8880`)
|
|
66
66
|
|
|
67
67
|
#### Chat Settings
|
|
68
68
|
- `OLLAMA_CHAT_MODEL` - Default model to use (e.g., `llama3.1`)
|
|
@@ -75,6 +75,19 @@ The following environment variables can be used to configure behavior:
|
|
|
75
75
|
- `OLLAMA_CHAT_LOG_DATABASE` - Database log file path (default: `$XDG_STATE_HOME/database.log`)
|
|
76
76
|
- `OLLAMA_CHAT_LOG_TAIL_LINES` - Max lines to retain in log files (default: `10000`)
|
|
77
77
|
|
|
78
|
+
#### Speech Services (ASR)
|
|
79
|
+
- `OLLAMA_CHAT_ASR_URL` - Base URL for the ASR (Speech-to-Text) service (default: `http://localhost:8880`)
|
|
80
|
+
- `OLLAMA_CHAT_ASR_CONVERT_COMMAND` - Shell command template to convert video to 16 kHz mono PCM WAV; use `%{input}` / `%{output}` as placeholders (default: `ffmpeg -y -i %{input} -vn -acodec pcm_s16le -ar 16000 -ac 1 %{output}`)
|
|
81
|
+
- `OLLAMA_CHAT_ASR_MODEL` - ASR model identifier (default: `qwen3-asr-1.7b`)
|
|
82
|
+
|
|
83
|
+
#### Audio Playback
|
|
84
|
+
- `OLLAMA_CHAT_AUDIO_PLAYER_CONFIG` - JSON object with `command`, `frequency`, `bits`, `pause` keys controlling the ffplay-based TTS audio player
|
|
85
|
+
|
|
86
|
+
#### Invidious (YouTube Proxy)
|
|
87
|
+
- `OLLAMA_CHAT_INVIDIOUS_URL` - Base URL for an Invidious instance
|
|
88
|
+
- `OLLAMA_CHAT_INVIDIOUS_COMPANION_KEY` - Bearer token for the Invidious companion player API (required when `URL` is set)
|
|
89
|
+
- `OLLAMA_CHAT_INVIDIOUS_CAPTION_LANGUAGES` - JSON array of language-code regexes for caption selection priority (default: `["\\Aen\\z","\\Aen-","\\Ade\\z","\\Ade-"]`)
|
|
90
|
+
|
|
78
91
|
#### Tool Configuration
|
|
79
92
|
- `OLLAMA_CHAT_TOOLS_TEST_RUNNER` - Configured test runner for `run_tests` (default: `rspec`)
|
|
80
93
|
- `OLLAMA_CHAT_TOOLS_CTAGS_TOOL` - Path to the ctags tool
|
|
@@ -243,14 +256,57 @@ switch. The profile system allows you to manage "Live" vs "Saved" settings:
|
|
|
243
256
|
"bake" those live settings into a permanent profile using `options from
|
|
244
257
|
session`.
|
|
245
258
|
|
|
246
|
-
#### 4. Conversation Archiving (`/
|
|
259
|
+
#### 4. Conversation Archiving (`/conversation summarize`)
|
|
247
260
|
|
|
248
261
|
Turn your long-form brainstorming sessions into structured documents. The
|
|
249
|
-
`/
|
|
250
|
-
summary.
|
|
262
|
+
`/conversation summarize` command distills an entire conversation into a
|
|
263
|
+
concise summary, displayed in the pager first, then optionally saved.
|
|
251
264
|
* **Quick View**: Use `-s` for a one-sentence executive summary.
|
|
252
|
-
* **Archiving**:
|
|
253
|
-
Markdown file, creating an automatic journal
|
|
265
|
+
* **Archiving**: After the summary is displayed, you are prompted for a
|
|
266
|
+
filename to save it as a Markdown file, creating an automatic journal
|
|
267
|
+
of your project's evolution.
|
|
268
|
+
|
|
269
|
+
#### 5. Context Compaction (`/conversation compact`)
|
|
270
|
+
|
|
271
|
+
Long sessions inevitably fill up the model's context window. The
|
|
272
|
+
`/conversation compact` command summarizes older messages into a single
|
|
273
|
+
compact summary while preserving recent exchanges, freeing up space for
|
|
274
|
+
continued work.
|
|
275
|
+
|
|
276
|
+
* **Token-aware**: The keep-recent budget is derived from the active
|
|
277
|
+
model's context length, so it adapts automatically.
|
|
278
|
+
* **Safe & retryable**: If the LLM summarization fails, the message list
|
|
279
|
+
is left untouched and you can simply retry.
|
|
280
|
+
* **Visible metrics**: After compaction, a report shows summarized
|
|
281
|
+
message count, summary size, and context usage before/after.
|
|
282
|
+
* **Iterative**: Repeated compactions merge into the existing summary
|
|
283
|
+
rather than stacking multiple summary messages.
|
|
284
|
+
|
|
285
|
+
Run it whenever context usage climbs into the red zone (visible in the
|
|
286
|
+
runtime info gauge) — the model stays sharp and the conversation keeps
|
|
287
|
+
flowing.
|
|
288
|
+
|
|
289
|
+
If compaction alone isn't enough, a practical escalation ladder:
|
|
290
|
+
|
|
291
|
+
1. **`/conversation compact`** — summarize old messages, keep recent tail.
|
|
292
|
+
Try this first; it's the least destructive.
|
|
293
|
+
2. **`/conversation report`** → **`/clear`** → **`/input path
|
|
294
|
+
standup.md`** — generate a standup-style report, save it, clear
|
|
295
|
+
the messages, then feed the report back as context. Do this
|
|
296
|
+
before `clean`, because `clean` strips the tool output and
|
|
297
|
+
thinking that make a good report.
|
|
298
|
+
3. **`/conversation clean`** — strips tool results, images, and
|
|
299
|
+
thinking content from all messages. More radical, but the
|
|
300
|
+
conversation structure and text remain intact. The emergency
|
|
301
|
+
exit: if context is so stuffed that even a report can't fit,
|
|
302
|
+
`clean` carves out enough room for anything to work again.
|
|
303
|
+
|
|
304
|
+
#### 6. Conversation Reports (`/conversation report`)
|
|
305
|
+
|
|
306
|
+
Generate a structured report from your conversation using configurable
|
|
307
|
+
prompt templates. The report is displayed in the pager first, then
|
|
308
|
+
optionally saved to a file. Particularly useful for daily standup summaries
|
|
309
|
+
— run it at the end of the day and save the output for your team sync.
|
|
254
310
|
|
|
255
311
|
### Using a Persona
|
|
256
312
|
|
|
@@ -467,12 +523,12 @@ context, manipulate files, and retrieve external information.
|
|
|
467
523
|
|
|
468
524
|
| Category | Tools | Description |
|
|
469
525
|
| :--- | :--- | :--- |
|
|
470
|
-
| **Filesystem** | `read_file`, `write_file`, `patch_file`, `delete_file`, `move_file`, `directory_structure`, `execute_grep` | Read, write, and search files within allowed directories. |
|
|
526
|
+
| **Filesystem** | `read_file`, `write_file`, `patch_file`, `delete_file`, `move_file`, `directory_structure`, `execute_grep`, `execute_shell` | Read, write, and search files within allowed directories; run shell commands as a last resort. |
|
|
471
527
|
| **Ruby/Dev** | `resolve_tag`, `execute_ri`, `gem_path_lookup`, `run_tests`, `eval_ruby` | Introspect Ruby code, check documentation, and run test suites. |
|
|
472
|
-
| **Web/External** | `search_web`, `get_url`, `browse`, `get_rfc`, `get_cve`, `get_endoflife`, `get_ghr`, `get_jira_issue` | Access the internet, fetch specific URLs, and look up technical standards
|
|
528
|
+
| **Web/External** | `search_web`, `get_url`, `browse`, `get_rfc`, `get_cve`, `get_endoflife`, `get_ghr`, `get_jira_issue`, `execute_jira_twg` | Access the internet, fetch specific URLs, and look up technical standards; run Jira CLI queries via `twg`. |
|
|
473
529
|
| **System/Util** | `get_time`, `get_location`, `get_current_weather`, `generate_password`, `compute_bmi`, `roll_dice` | General utility functions for time, location, and simple calculations. |
|
|
474
530
|
| **Editor/Clip** | `copy_to_clipboard`, `paste_from_clipboard`, `paste_into_editor`, `open_file_in_editor` | Bridge the gap between the chat and the system clipboard or editor. |
|
|
475
|
-
| **Knowledge** | `search_knowledge`, `file_context` | Semantic search for specific snippets
|
|
531
|
+
| **Knowledge** | `search_knowledge`, `file_context`, `lookup_group` | Semantic search for specific snippets, broad retrieval of structured project context, or retrieving prior message groups by UUID. |
|
|
476
532
|
| **Multimodal** | `generate_image` | Generate images via a local ComfyUI server. |
|
|
477
533
|
|
|
478
534
|
***Note on Knowledge Tools**: Use `search_knowledge` for precise,
|
data/Rakefile
CHANGED
|
@@ -49,7 +49,7 @@ GemHadar do
|
|
|
49
49
|
dependency 'reverse_markdown', '~> 3.0'
|
|
50
50
|
dependency 'kramdown-ansi', '~> 0.5'
|
|
51
51
|
dependency 'complex_config', '~> 0.22', '>= 0.22.2'
|
|
52
|
-
dependency 'tins', '~> 1.
|
|
52
|
+
dependency 'tins', '~> 1.58'
|
|
53
53
|
dependency 'search_ui', '>= 0.2'
|
|
54
54
|
dependency 'amatch', '~> 0.4'
|
|
55
55
|
dependency 'pdf-reader', '~> 2.0'
|
|
@@ -61,13 +61,13 @@ GemHadar do
|
|
|
61
61
|
dependency 'rubyzip', '~> 3.0'
|
|
62
62
|
dependency 'sequel', '~> 5.0'
|
|
63
63
|
dependency 'file-tail', '~> 1.4'
|
|
64
|
+
dependency 'nokogiri', '~> 1.0'
|
|
64
65
|
development_dependency 'all_images', '~> 0.12'
|
|
65
66
|
development_dependency 'rspec', '~> 3.2'
|
|
66
67
|
development_dependency 'kramdown', '~> 2.0'
|
|
67
68
|
development_dependency 'webmock'
|
|
68
69
|
development_dependency 'debug'
|
|
69
70
|
development_dependency 'simplecov'
|
|
70
|
-
development_dependency 'context_spook'
|
|
71
71
|
development_dependency 'utils'
|
|
72
72
|
|
|
73
73
|
licenses << 'MIT'
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
# Standalone ASR (Speech-to-Text) transcription client for audio.cpp.
|
|
4
|
+
#
|
|
5
|
+
# Transcribes audio or video sources by uploading them as multipart
|
|
6
|
+
# form-data to the audio.cpp `/v1/audio/transcriptions` endpoint.
|
|
7
|
+
# Video sources are first converted to 16 kHz mono WAV via ffmpeg.
|
|
8
|
+
#
|
|
9
|
+
# @example Transcribing a WAV source
|
|
10
|
+
# text = OllamaChat::ASR.transcribe(source_io, chat:)
|
|
11
|
+
#
|
|
12
|
+
# @example Transcribing an MP4 video (ffmpeg extraction)
|
|
13
|
+
# text = OllamaChat::ASR.transcribe(source_io, chat:)
|
|
14
|
+
module OllamaChat
|
|
15
|
+
class ASR
|
|
16
|
+
class << self
|
|
17
|
+
# Transcribes audio/video content via the audio.cpp ASR endpoint.
|
|
18
|
+
#
|
|
19
|
+
# @param source_io [IO] the audio/video source stream
|
|
20
|
+
# (must respond to #content_type and be seekable)
|
|
21
|
+
# @param language [String, nil] optional language hint
|
|
22
|
+
# (e.g. "en", "de") passed as the `language` form field
|
|
23
|
+
# @param chat [OllamaChat::Chat] the chat instance (for HTTP middleware)
|
|
24
|
+
#
|
|
25
|
+
# @return [String, nil] the transcribed text, or nil on failure
|
|
26
|
+
def transcribe(source_io, chat:, language: nil)
|
|
27
|
+
asr_url = OC::OLLAMA::CHAT::ASR::URL
|
|
28
|
+
asr_model = OC::OLLAMA::CHAT::ASR::MODEL
|
|
29
|
+
input = Tempfile.new(['asr_in'])
|
|
30
|
+
wav = Tempfile.new(['asr', '.wav'])
|
|
31
|
+
begin
|
|
32
|
+
IO.copy_stream(source_io, input)
|
|
33
|
+
input.flush
|
|
34
|
+
|
|
35
|
+
cmd = OC::OLLAMA::CHAT::ASR::CONVERT_COMMAND % {
|
|
36
|
+
input: input.path, output: wav.path
|
|
37
|
+
}
|
|
38
|
+
executable = Shellwords.split(cmd).first
|
|
39
|
+
result = system(cmd, out: File::NULL, err: File::NULL)
|
|
40
|
+
if result.nil?
|
|
41
|
+
STDERR.puts "ASR: #{executable} not found in PATH."
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
unless File.size(wav.path) > 0
|
|
45
|
+
STDERR.puts "ASR: #{executable} produced no output."
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
url = "#{asr_url}/v1/audio/transcriptions"
|
|
50
|
+
form_data = multipart_form_data(wav.path, model: asr_model, language:)
|
|
51
|
+
chat.request_url_response(:post, url, **form_data) do |response|
|
|
52
|
+
return JSON.parse(response.body)['text']
|
|
53
|
+
end
|
|
54
|
+
ensure
|
|
55
|
+
input.close!
|
|
56
|
+
wav&.close!
|
|
57
|
+
end
|
|
58
|
+
rescue JSON::ParserError, Excon::Error => e
|
|
59
|
+
if response = e.ask_and_send(:response)
|
|
60
|
+
status = response.status
|
|
61
|
+
result = JSON.parse(response.body) rescue nil
|
|
62
|
+
end
|
|
63
|
+
chat.log(:error, e, data: { status:, result: })
|
|
64
|
+
STDERR.puts "ASR transcription failed: #{e.message}"
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Builds a multipart/form-data request body for the ASR endpoint.
|
|
71
|
+
#
|
|
72
|
+
# Constructs the wire format manually (boundary, text field parts,
|
|
73
|
+
# file part) so the result can be splatted directly into
|
|
74
|
+
# {HTTPHandling#request_url_response}.
|
|
75
|
+
#
|
|
76
|
+
# @param file_path [String] path to the WAV file to upload
|
|
77
|
+
# @param rest [Hash] additional form fields (e.g. `model:`,
|
|
78
|
+
# `language:`); `nil` values are omitted via `compact`
|
|
79
|
+
#
|
|
80
|
+
# @return [Hash] Excon-compatible options with `:headers`
|
|
81
|
+
# (Content-Type including the generated boundary), `:expects`
|
|
82
|
+
# (200), and `:body` (the assembled multipart string)
|
|
83
|
+
def multipart_form_data(file_path, **rest)
|
|
84
|
+
path = Pathname.new(file_path)
|
|
85
|
+
body = ''
|
|
86
|
+
boundary = SecureRandom.hex(8)
|
|
87
|
+
|
|
88
|
+
rest.compact.each do |field_name, field_value|
|
|
89
|
+
body << "--#{boundary}\r\n"
|
|
90
|
+
body << "Content-Disposition: form-data; name=\"#{field_name}\"\r\n\r\n"
|
|
91
|
+
body << "#{field_value}\r\n"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
body << "--#{boundary}" << Excon::CR_NL
|
|
95
|
+
body << %{Content-Disposition: form-data; name="file"; filename="#{path.basename}"} << Excon::CR_NL
|
|
96
|
+
body << 'Content-Type: audio/wav' << Excon::CR_NL
|
|
97
|
+
body << Excon::CR_NL
|
|
98
|
+
body << path.binread
|
|
99
|
+
body << Excon::CR_NL
|
|
100
|
+
body << "--#{boundary}--" << Excon::CR_NL
|
|
101
|
+
|
|
102
|
+
{
|
|
103
|
+
headers: { 'Content-Type' => %{multipart/form-data; boundary="#{boundary}"} },
|
|
104
|
+
expects: 200,
|
|
105
|
+
body: ,
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -162,15 +162,14 @@ class OllamaChat::Chat
|
|
|
162
162
|
# @return [OllamaChat::RedisCache, nil] the cache instance
|
|
163
163
|
attr_reader :cache
|
|
164
164
|
|
|
165
|
-
|
|
166
165
|
# Returns the voice handler class based on the configuration.
|
|
167
166
|
#
|
|
168
167
|
# This method resolves the voice handler class specified in the config.
|
|
169
|
-
# If running within RSpec, it returns
|
|
168
|
+
# If running within RSpec, it returns nil to avoid side effects.
|
|
170
169
|
#
|
|
171
|
-
# @return [Class,
|
|
170
|
+
# @return [Class, NilClass] the voice handler class or nil if in test mode
|
|
172
171
|
def voice_handler
|
|
173
|
-
defined?(RSpec) and return
|
|
172
|
+
defined?(RSpec) and return nil
|
|
174
173
|
case config.voice.handler
|
|
175
174
|
when 'OllamaChat::TTS'
|
|
176
175
|
OllamaChat::TTS
|
|
@@ -295,6 +294,30 @@ class OllamaChat::Chat
|
|
|
295
294
|
content
|
|
296
295
|
end
|
|
297
296
|
|
|
297
|
+
# Synthesizes and plays a short voice notification using the session's
|
|
298
|
+
# current voice.
|
|
299
|
+
#
|
|
300
|
+
# This is the chat-level facade for one-shot speech: it resolves the
|
|
301
|
+
# active voice, instantiates the configured voice handler, and delegates
|
|
302
|
+
# to its `#speak` method. It is a no-op when the voice switch is off,
|
|
303
|
+
# no voice is selected, or the handler lacks `#speak`.
|
|
304
|
+
#
|
|
305
|
+
# @param text [String] the text to speak
|
|
306
|
+
# @param background [Boolean, Integer] pass `true` for an immediate
|
|
307
|
+
# background thread, `false` for inline, or a numeric delay in
|
|
308
|
+
# seconds (e.g. `10`) to spawn a background thread that sleeps
|
|
309
|
+
# before speaking
|
|
310
|
+
#
|
|
311
|
+
# @return [OllamaChat::TTS, OllamaChat::Say, nil] the voice handler
|
|
312
|
+
# instance when a background thread was spawned (so callers can call
|
|
313
|
+
# `cancel_speaking`), or `nil` for inline playback or when voice is off
|
|
314
|
+
def speak(text, background: true)
|
|
315
|
+
voice.on? or return
|
|
316
|
+
voice = session.current_voice.full? or return
|
|
317
|
+
voice_handler.method_defined?(:speak) or return
|
|
318
|
+
voice_handler.new(chat: self, voice:).speak(text, background:)
|
|
319
|
+
end
|
|
320
|
+
|
|
298
321
|
# Returns a human-readable string representation of the Chat object,
|
|
299
322
|
# including the class name and the base URL.
|
|
300
323
|
#
|