ollama_chat 0.0.91 → 0.0.92
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 +38 -0
- data/lib/ollama_chat/chat.rb +4 -2
- data/lib/ollama_chat/commands.rb +15 -6
- data/lib/ollama_chat/favourites_management.rb +2 -2
- data/lib/ollama_chat/input_content.rb +1 -1
- data/lib/ollama_chat/model_handling.rb +4 -1
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +42 -2
- data/lib/ollama_chat/personae_management.rb +13 -11
- data/lib/ollama_chat/prompt_handling.rb +2 -2
- data/lib/ollama_chat/prompt_management.rb +50 -8
- data/lib/ollama_chat/rag_handling.rb +8 -2
- data/lib/ollama_chat/session_management.rb +1 -1
- data/lib/ollama_chat/state_selectors.rb +5 -1
- data/lib/ollama_chat/system_prompt_management.rb +18 -9
- data/lib/ollama_chat/tool_calling.rb +10 -2
- data/lib/ollama_chat/tools/retrieve_document_snippets.rb +52 -1
- data/lib/ollama_chat/version.rb +1 -1
- data/ollama_chat.gemspec +2 -2
- data/spec/ollama_chat/input_content_spec.rb +4 -1
- data/spec/ollama_chat/state_selectors_spec.rb +2 -1
- data/spec/ollama_chat/tools/retrieve_document_snippets_spec.rb +76 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65c990826623b9e3d8548c69bf01b715dd9597e451a5a4b480e4e09d48249113
|
|
4
|
+
data.tar.gz: bdf07bb49531d867d8be7b2cd8f2c5537867b9a2d297d939f123593952a77507
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ee0222c25f838f0c2436e71b9d9d8aa630fe45c58f7dc592c850e3dbe6b85ec0461883b05d735aab74c664fe8516ef13adecd33c18b0fd5b8571feba6827e65
|
|
7
|
+
data.tar.gz: a7ae3f192f4bead676495ee4053596fd5253e1394e5e2f1a5617f621d201e98d6dddd866c32b9d025a1b22cd3201fdf3be09a5399dab18c462c8bdc4d412b37f
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-06-19 v0.0.92
|
|
4
|
+
|
|
5
|
+
### New Features
|
|
6
|
+
|
|
7
|
+
- **LLM-Based Reranking**: Implemented reranking logic in the retrieval tool
|
|
8
|
+
via a new `rerank_records` method in
|
|
9
|
+
`lib/ollama_chat/tools/retrieve_document_snippets.rb`.
|
|
10
|
+
- Added a new `rerank` prompt template to `default_config.yml`.
|
|
11
|
+
- Refactored the `execute` method to utilize `flat_map` for better handling
|
|
12
|
+
of records without tags.
|
|
13
|
+
- **Prompt Suggestions**: Introduced a `/prompt suggest` subcommand in
|
|
14
|
+
`OllamaChat::Commands`.
|
|
15
|
+
- Implemented `suggest_prompts` and `prepare_conversation_history` within
|
|
16
|
+
`OllamaChat::PromptManagement`.
|
|
17
|
+
- Added `coding_suggest` and `roleplaying_suggest` templates to
|
|
18
|
+
`default_config.yml`.
|
|
19
|
+
|
|
20
|
+
### Improvements
|
|
21
|
+
|
|
22
|
+
- **CLI User Experience**: Enhanced CLI interactions by replacing generic
|
|
23
|
+
prompts with flavorful, context-aware messages across `ModelHandling`,
|
|
24
|
+
`RAGHandling`, `StateSelectors`, `SystemPromptManagement`,
|
|
25
|
+
`PersonaeManagement`, and `PromptManagement`.
|
|
26
|
+
- **Interaction Logic**: Expanded `choose_prompt` and `choose_system_prompt` to
|
|
27
|
+
support custom prompt messages and updated `choose_entry` signatures.
|
|
28
|
+
- **Observability**: Added info logging for prompt, model, and generation
|
|
29
|
+
details within `Chat#generate`.
|
|
30
|
+
- **Internal API**: Adjusted visibility in `lib/ollama_chat/chat.rb` and
|
|
31
|
+
`lib/ollama_chat/prompt_handling.rb` to allow tools access to core methods.
|
|
32
|
+
|
|
33
|
+
### Tests
|
|
34
|
+
|
|
35
|
+
- Updated `spec/ollama_chat/tools/retrieve_document_snippets_spec.rb` to cover
|
|
36
|
+
the new `rerank` parameter.
|
|
37
|
+
- Updated `spec/ollama_chat/input_content_spec.rb` and
|
|
38
|
+
`spec/ollama_chat/state_selectors_spec.rb` to align with updated
|
|
39
|
+
`choose_entry` signatures.
|
|
40
|
+
|
|
3
41
|
## 2026-06-17 v0.0.91
|
|
4
42
|
|
|
5
43
|
- Updated `lib/ollama_chat/commands.rb` to ensure the result of
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -228,8 +228,6 @@ class OllamaChat::Chat
|
|
|
228
228
|
@messages.system_name
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
-
private
|
|
232
|
-
|
|
233
231
|
# The generate method sends a prompt to the Ollama model and returns the
|
|
234
232
|
# result.
|
|
235
233
|
#
|
|
@@ -238,6 +236,8 @@ class OllamaChat::Chat
|
|
|
238
236
|
# @return [ Ollama::Response ] the response from the Ollama model
|
|
239
237
|
def generate(prompt:)
|
|
240
238
|
prepare_model(@model)
|
|
239
|
+
msg = "Using prompt #{prompt.inspect} for generation to #{@model.inspect}."
|
|
240
|
+
log(:info, msg)
|
|
241
241
|
ollama.generate(
|
|
242
242
|
model: @model,
|
|
243
243
|
prompt:,
|
|
@@ -247,6 +247,8 @@ class OllamaChat::Chat
|
|
|
247
247
|
)
|
|
248
248
|
end
|
|
249
249
|
|
|
250
|
+
private
|
|
251
|
+
|
|
250
252
|
# @return [Module] The module containing the database models.
|
|
251
253
|
def models
|
|
252
254
|
OllamaChat::Database::Models
|
data/lib/ollama_chat/commands.rb
CHANGED
|
@@ -163,7 +163,10 @@ module OllamaChat::Commands
|
|
|
163
163
|
when 'info'
|
|
164
164
|
info_system_prompt
|
|
165
165
|
when 'reset'
|
|
166
|
-
if prompt = choose_system_prompt
|
|
166
|
+
if prompt = choose_system_prompt(
|
|
167
|
+
prompt: 'Which system law needs to be restored to its origin? '
|
|
168
|
+
)
|
|
169
|
+
then
|
|
167
170
|
if reset_system_prompt_to_default(prompt.name)
|
|
168
171
|
STDOUT.puts "Reset system prompt #{bold{prompt.name}} to default."
|
|
169
172
|
else
|
|
@@ -405,12 +408,12 @@ module OllamaChat::Commands
|
|
|
405
408
|
|
|
406
409
|
command(
|
|
407
410
|
name: :prompt,
|
|
408
|
-
regexp: %r(^/prompt(\s+-e)?(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset))?(?:\s+(\S+))?$),
|
|
409
|
-
complete: [ 'prompt', %w[ edit info add delete list duplicate import export reset ] ],
|
|
411
|
+
regexp: %r(^/prompt(\s+-e)?(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset|suggest))?(?:\s+(\S+))?$),
|
|
412
|
+
complete: [ 'prompt', %w[ edit info add delete list duplicate import export reset suggest ] ],
|
|
410
413
|
optional: true,
|
|
411
414
|
help: <<~EOT,
|
|
412
415
|
Manage preset prompt templates or prefill the prompt (edit, info, add,
|
|
413
|
-
delete, list, duplicate, import, export, reset)
|
|
416
|
+
delete, list, duplicate, import, export, reset, suggest)
|
|
414
417
|
Options: -e to edit the next prompt instead of prefilling
|
|
415
418
|
EOT
|
|
416
419
|
) do |opts, subcommand, filename|
|
|
@@ -432,16 +435,22 @@ module OllamaChat::Commands
|
|
|
432
435
|
when 'info'
|
|
433
436
|
info_prompt
|
|
434
437
|
when 'reset'
|
|
435
|
-
if prompt = choose_prompt(
|
|
438
|
+
if prompt = choose_prompt(
|
|
439
|
+
default: true,
|
|
440
|
+
prompt: 'Which prompt needs to be restored to its origin? '
|
|
441
|
+
)
|
|
442
|
+
then
|
|
436
443
|
if reset_prompt_to_default(prompt.name)
|
|
437
444
|
STDOUT.puts "Reset prompt #{bold{prompt.name}} to default."
|
|
438
445
|
else
|
|
439
446
|
STDOUT.puts "No default value found for prompt #{bold{prompt.name}}."
|
|
440
447
|
end
|
|
441
448
|
end
|
|
449
|
+
when 'suggest'
|
|
450
|
+
prompt = suggest_prompts and next prompt
|
|
442
451
|
when nil
|
|
443
452
|
opts = go_command('e', opts)
|
|
444
|
-
if prompt = choose_prompt.full?(&:to_s)
|
|
453
|
+
if prompt = choose_prompt(prompt: 'Which template shall guide the next response? ').full?(&:to_s)
|
|
445
454
|
if opts[?e]
|
|
446
455
|
prompt = edit_text(prompt)
|
|
447
456
|
next prompt
|
|
@@ -51,7 +51,7 @@ module OllamaChat::FavouritesManagement
|
|
|
51
51
|
return
|
|
52
52
|
end
|
|
53
53
|
to_select.unshift('[EXIT]')
|
|
54
|
-
case chosen = choose_entry(to_select)
|
|
54
|
+
case chosen = choose_entry(to_select, prompt: 'Select an item to mark as favourite: ')
|
|
55
55
|
when '[EXIT]', nil
|
|
56
56
|
STDOUT.puts "Cancelled."
|
|
57
57
|
return
|
|
@@ -77,7 +77,7 @@ module OllamaChat::FavouritesManagement
|
|
|
77
77
|
to_select = models::Favourite.where(context: type).map(&:name)
|
|
78
78
|
to_select = all_things.select { to_select.member?(_1.value) }
|
|
79
79
|
to_select = [ '[EXIT]' ] + to_select
|
|
80
|
-
case chosen = choose_entry(to_select)
|
|
80
|
+
case chosen = choose_entry(to_select, prompt: 'Select a favourite to remove: ')
|
|
81
81
|
when '[EXIT]', nil
|
|
82
82
|
STDOUT.puts "Cancelled."
|
|
83
83
|
return
|
|
@@ -55,7 +55,7 @@ module OllamaChat::InputContent
|
|
|
55
55
|
files = patterns.flat_map { Pathname.glob(_1) }
|
|
56
56
|
files = files.reject { chosen&.member?(_1.expand_path) }.select { _1.file? }
|
|
57
57
|
files.unshift('[EXIT]')
|
|
58
|
-
case chosen_file = choose_entry(files)
|
|
58
|
+
case chosen_file = choose_entry(files, prompt: 'Select a file to import: ')
|
|
59
59
|
when '[EXIT]', nil
|
|
60
60
|
STDOUT.puts "Exiting chooser."
|
|
61
61
|
return
|
|
@@ -364,7 +364,10 @@ module OllamaChat::ModelHandling
|
|
|
364
364
|
if models.size == 1
|
|
365
365
|
models.first.value
|
|
366
366
|
elsif cli_model == ''
|
|
367
|
-
choose_entry(
|
|
367
|
+
choose_entry(
|
|
368
|
+
models,
|
|
369
|
+
prompt: "Which digital oracle shall we consult?"
|
|
370
|
+
)&.value || current_model
|
|
368
371
|
else
|
|
369
372
|
cli_model || current_model
|
|
370
373
|
end
|
|
@@ -24,7 +24,15 @@ infobar:
|
|
|
24
24
|
:frames: :braille181
|
|
25
25
|
:message: ✓
|
|
26
26
|
prompts:
|
|
27
|
-
embed:
|
|
27
|
+
embed: This source has been added to or updated in collection "%{collection}".
|
|
28
|
+
rerank: |
|
|
29
|
+
Query: %{query}
|
|
30
|
+
Candidates:
|
|
31
|
+
|
|
32
|
+
%{candidates}
|
|
33
|
+
|
|
34
|
+
Return only the indices of the most relevant snippets as a comma-separated
|
|
35
|
+
list (e.g., '0,2').
|
|
28
36
|
summarize: |
|
|
29
37
|
Generate an abstract summary of the content in this document using
|
|
30
38
|
%{words} words:
|
|
@@ -158,7 +166,39 @@ prompts:
|
|
|
158
166
|
Response content was
|
|
159
167
|
|
|
160
168
|
%{message_content}
|
|
161
|
-
session_title:
|
|
169
|
+
session_title: |
|
|
170
|
+
Create a title with a length of **less than %{length}** characters for this
|
|
171
|
+
conversation. Output only the title and nothing else:
|
|
172
|
+
|
|
173
|
+
%{content}
|
|
174
|
+
suggest_coding: |
|
|
175
|
+
Analyze the conversation history above. Generate exactly 3 distinct,
|
|
176
|
+
concise follow-up prompts that the user might want to ask next to further
|
|
177
|
+
their goal.
|
|
178
|
+
|
|
179
|
+
Criteria:
|
|
180
|
+
1. One prompt should dive deeper into the current technical implementation.
|
|
181
|
+
2. One prompt should challenge a potential edge case or optimization.
|
|
182
|
+
3. One prompt should suggest a logical next step or a broader architectural question.
|
|
183
|
+
|
|
184
|
+
Output only the text of these suggestions, separated by an empty line,
|
|
185
|
+
without any numbering, bullet points, or introductory text.
|
|
186
|
+
suggest_roleplaying: |
|
|
187
|
+
Analyze the conversation history and the current narrative state of this
|
|
188
|
+
roleplay/story. Generate exactly 3 distinct, concise prompts that the
|
|
189
|
+
user could use to respond as their character.
|
|
190
|
+
|
|
191
|
+
Criteria:
|
|
192
|
+
1. One prompt should be an active choice or bold action that pushes the
|
|
193
|
+
plot forward or creates tension.
|
|
194
|
+
2. One prompt should focus on character interaction, exploring emotional
|
|
195
|
+
depth, a social reaction, or a subtle nuance in dialogue.
|
|
196
|
+
3. One prompt should introduce a sudden complication, a risky gamble, or an
|
|
197
|
+
unexpected event. This prompt MUST explicitly include a suggested dice roll
|
|
198
|
+
(e.g., "Roll 1d20") to determine the success or failure of the action.
|
|
199
|
+
|
|
200
|
+
Output only the text of these suggestions, separated by an empty line,
|
|
201
|
+
without any numbering, bullet points, or introductory text.
|
|
162
202
|
system_prompts:
|
|
163
203
|
default: <%= OC::OLLAMA::CHAT::SYSTEM || "%{persona}\n\n%{runtime_info}".inspect %>
|
|
164
204
|
persona: |
|
|
@@ -91,7 +91,7 @@ module OllamaChat::PersonaeManagement
|
|
|
91
91
|
# @return [String, nil] The name of the persona that was set as default,
|
|
92
92
|
# or nil if the selection was cancelled or no persona was chosen.
|
|
93
93
|
def set_default_persona
|
|
94
|
-
if persona = choose_persona(none: true)
|
|
94
|
+
if persona = choose_persona(none: true, prompt: 'Who would you like to talk to today? ')
|
|
95
95
|
set_default_persona_name(persona)
|
|
96
96
|
end
|
|
97
97
|
end
|
|
@@ -214,7 +214,7 @@ module OllamaChat::PersonaeManagement
|
|
|
214
214
|
# @return [String] A JSON object with deletion status on success,
|
|
215
215
|
# or nil if persona was not selected or deletion was cancelled
|
|
216
216
|
def delete_persona
|
|
217
|
-
if persona = choose_persona
|
|
217
|
+
if persona = choose_persona(prompt: 'Which persona is no longer needed? ')
|
|
218
218
|
pathname = persona_name_to_pathname(persona)
|
|
219
219
|
backup_pathname = persona_backup_pathname(persona)
|
|
220
220
|
if pathname.exist?
|
|
@@ -245,7 +245,7 @@ module OllamaChat::PersonaeManagement
|
|
|
245
245
|
#
|
|
246
246
|
# @return [String, nil] persona name or nil if cancelled
|
|
247
247
|
def edit_persona
|
|
248
|
-
if persona = choose_persona
|
|
248
|
+
if persona = choose_persona(prompt: 'Which persona needs some polishing? ')
|
|
249
249
|
pathname = persona_name_to_pathname(persona)
|
|
250
250
|
old_content = pathname.read
|
|
251
251
|
if edit_file(pathname)
|
|
@@ -265,7 +265,7 @@ module OllamaChat::PersonaeManagement
|
|
|
265
265
|
# @return [String, nil] the filesystem path of the selected persona,
|
|
266
266
|
# or nil if the selection was cancelled.
|
|
267
267
|
def select_persona_path
|
|
268
|
-
persona = choose_persona or return
|
|
268
|
+
persona = choose_persona(prompt: "Which persona's path do you need? ") or return
|
|
269
269
|
path = persona_name_to_pathname(persona).to_s
|
|
270
270
|
perform_copy_to_clipboard(text: path, edit: false)
|
|
271
271
|
@prefill_prompt = path
|
|
@@ -279,7 +279,7 @@ module OllamaChat::PersonaeManagement
|
|
|
279
279
|
# location using `File.write`. This ensures a safe copy is preserved before
|
|
280
280
|
# any modifications are made to the original file.
|
|
281
281
|
def backup_persona
|
|
282
|
-
if persona = choose_persona
|
|
282
|
+
if persona = choose_persona(prompt: 'Which persona should be safely archived? ')
|
|
283
283
|
pathname = persona_name_to_pathname(persona)
|
|
284
284
|
old_content = pathname.read
|
|
285
285
|
backup_pathname = persona_backup_pathname(persona)
|
|
@@ -317,7 +317,7 @@ module OllamaChat::PersonaeManagement
|
|
|
317
317
|
#
|
|
318
318
|
# Shows the persona's profile using kramdown formatting with ansi parsing.
|
|
319
319
|
def info_persona
|
|
320
|
-
if persona = choose_persona
|
|
320
|
+
if persona = choose_persona(prompt: 'Who would you like to learn more about? ')
|
|
321
321
|
description = persona_description(persona) or return
|
|
322
322
|
use_pager do |output|
|
|
323
323
|
output.puts kramdown_ansi_parse(description)
|
|
@@ -374,9 +374,11 @@ module OllamaChat::PersonaeManagement
|
|
|
374
374
|
#
|
|
375
375
|
# @param chosen [Set, nil] Optional set of already selected personas
|
|
376
376
|
# @param none [Boolean] whether to include a '[NONE]' option in the list
|
|
377
|
+
# @param prompt [String] the prompt message to display when asking for input
|
|
378
|
+
# (default: 'Select a persona: ')
|
|
377
379
|
# @return [String, Symbol, nil] The selected persona name, :none, or nil if
|
|
378
380
|
# user exits
|
|
379
|
-
def choose_persona(chosen: nil, none: false)
|
|
381
|
+
def choose_persona(chosen: nil, none: false, prompt: 'Select a persona: ')
|
|
380
382
|
personae_list = available_personae_names.
|
|
381
383
|
reject { chosen&.member?(_1) }
|
|
382
384
|
if personae_list.empty?
|
|
@@ -385,7 +387,7 @@ module OllamaChat::PersonaeManagement
|
|
|
385
387
|
end
|
|
386
388
|
personae_list.unshift('[NONE]') if none
|
|
387
389
|
personae_list.unshift('[EXIT]')
|
|
388
|
-
case persona = choose_entry(personae_list)
|
|
390
|
+
case persona = choose_entry(personae_list, prompt:)
|
|
389
391
|
when '[EXIT]', nil
|
|
390
392
|
STDOUT.puts "Exiting chooser."
|
|
391
393
|
return
|
|
@@ -403,7 +405,7 @@ module OllamaChat::PersonaeManagement
|
|
|
403
405
|
def load_personae
|
|
404
406
|
chosen = Set[]
|
|
405
407
|
choose_with_state do
|
|
406
|
-
while persona = choose_persona(chosen: chosen)
|
|
408
|
+
while persona = choose_persona(chosen: chosen, prompt: 'Who else should join the conversation? ')
|
|
407
409
|
persona == :none and next
|
|
408
410
|
chosen << persona
|
|
409
411
|
end
|
|
@@ -532,7 +534,7 @@ module OllamaChat::PersonaeManagement
|
|
|
532
534
|
# @return [self, nil] returns self on success, or nil if the operation was
|
|
533
535
|
# cancelled during persona selection or name entry.
|
|
534
536
|
def duplicate_persona
|
|
535
|
-
persona = choose_persona or return
|
|
537
|
+
persona = choose_persona(prompt: 'Which persona shall serve as the blueprint? ') or return
|
|
536
538
|
pathname = persona_name_to_pathname(persona)
|
|
537
539
|
new_persona_name = determine_valid_new_name_for_persona('to ducplicate as') or return
|
|
538
540
|
new_pathname = persona_name_to_pathname(new_persona_name)
|
|
@@ -584,7 +586,7 @@ module OllamaChat::PersonaeManagement
|
|
|
584
586
|
# @return [self, nil] returns self if the export was successful, or nil if
|
|
585
587
|
# the process was cancelled during persona selection or filename entry.
|
|
586
588
|
def export_persona
|
|
587
|
-
persona = choose_persona or return
|
|
589
|
+
persona = choose_persona(prompt: 'Which persona are you taking with you? ') or return
|
|
588
590
|
pathname = persona_name_to_pathname(persona)
|
|
589
591
|
content = pathname.read
|
|
590
592
|
STDOUT.puts kramdown_ansi_parse(
|
|
@@ -14,8 +14,6 @@ module OllamaChat::PromptHandling
|
|
|
14
14
|
models::Prompt.where(context: 'system_prompt', name: name.to_s).first
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
private
|
|
18
|
-
|
|
19
17
|
# Retrieves a specific prompt by name from the 'prompt' context.
|
|
20
18
|
#
|
|
21
19
|
# @param name [String, Symbol] the name of the prompt to retrieve
|
|
@@ -25,6 +23,8 @@ module OllamaChat::PromptHandling
|
|
|
25
23
|
models::Prompt.where(context: 'prompt', name: name.to_s).first
|
|
26
24
|
end
|
|
27
25
|
|
|
26
|
+
private
|
|
27
|
+
|
|
28
28
|
# Iterates over all prompts in the 'prompt' context.
|
|
29
29
|
#
|
|
30
30
|
# @yield [prompt] yields each prompt model instance
|
|
@@ -26,13 +26,14 @@ module OllamaChat::PromptManagement
|
|
|
26
26
|
#
|
|
27
27
|
# @param default [Boolean, nil] filter for default prompts (true: only
|
|
28
28
|
# defaults, false: only non-defaults)
|
|
29
|
+
# @param prompt [String] the prompt message to display when asking for input
|
|
29
30
|
#
|
|
30
31
|
# @return [OllamaChat::Database::Models::Prompt, nil] the selected prompt
|
|
31
32
|
# model, or nil if the user chooses '[EXIT]' or cancels the selection.
|
|
32
|
-
def choose_prompt(default: nil)
|
|
33
|
+
def choose_prompt(default: nil, prompt: 'Select a prompt template: ')
|
|
33
34
|
prompts = all_prompts(default: default)
|
|
34
35
|
prompts.unshift('[EXIT]')
|
|
35
|
-
case chosen = choose_entry(prompts)
|
|
36
|
+
case chosen = choose_entry(prompts, prompt:)
|
|
36
37
|
when '[EXIT]', nil
|
|
37
38
|
STDOUT.puts "Exiting chooser."
|
|
38
39
|
return
|
|
@@ -45,7 +46,7 @@ module OllamaChat::PromptManagement
|
|
|
45
46
|
#
|
|
46
47
|
# @return [self, nil] the current context on success, or nil if cancelled
|
|
47
48
|
def info_prompt
|
|
48
|
-
if prompt = choose_prompt
|
|
49
|
+
if prompt = choose_prompt(prompt: 'Which blueprint would you like to inspect? ')
|
|
49
50
|
use_pager do |output|
|
|
50
51
|
output.puts kramdown_ansi_parse(<<~EOT)
|
|
51
52
|
# Prompt #{prompt.name}
|
|
@@ -98,7 +99,7 @@ module OllamaChat::PromptManagement
|
|
|
98
99
|
# Interactively selects an existing non-default prompt and deletes it after
|
|
99
100
|
# confirmation.
|
|
100
101
|
def choose_and_delete_prompt
|
|
101
|
-
prompt = choose_prompt(default: false) or return
|
|
102
|
+
prompt = choose_prompt(default: false, prompt: 'Which template has outlived its usefulness? ') or return
|
|
102
103
|
STDOUT.puts kramdown_ansi_parse(
|
|
103
104
|
prompt.to_s + "\n---"
|
|
104
105
|
)
|
|
@@ -114,7 +115,7 @@ module OllamaChat::PromptManagement
|
|
|
114
115
|
#
|
|
115
116
|
# @return [self, nil] the current context on success, or nil if cancelled
|
|
116
117
|
def choose_and_edit_prompt
|
|
117
|
-
prompt = choose_prompt or return
|
|
118
|
+
prompt = choose_prompt(prompt: 'Which spell needs some fine-tuning? ') or return
|
|
118
119
|
prompt.metadata['content'] = edit_text(prompt.metadata['content'].to_s)
|
|
119
120
|
prompt.save
|
|
120
121
|
self
|
|
@@ -132,7 +133,7 @@ module OllamaChat::PromptManagement
|
|
|
132
133
|
# @return [self, nil] the current context on success, or nil if the user
|
|
133
134
|
# cancelled the operation or no prompt was selected.
|
|
134
135
|
def duplicate_prompt
|
|
135
|
-
prompt = choose_prompt or return
|
|
136
|
+
prompt = choose_prompt(prompt: 'Which prompt shall be the basis for a new one? ') or return
|
|
136
137
|
STDOUT.puts kramdown_ansi_parse(
|
|
137
138
|
prompt.to_s + "\n---"
|
|
138
139
|
)
|
|
@@ -203,7 +204,7 @@ module OllamaChat::PromptManagement
|
|
|
203
204
|
# @return [self, nil] returns self if the export was successful, or nil if
|
|
204
205
|
# the process was cancelled during prompt selection or filename entry.
|
|
205
206
|
def export_prompt
|
|
206
|
-
prompt = choose_prompt or return
|
|
207
|
+
prompt = choose_prompt(prompt: 'Which template are you exporting to disk? ') or return
|
|
207
208
|
STDOUT.puts kramdown_ansi_parse(
|
|
208
209
|
prompt.to_s + "\n---"
|
|
209
210
|
)
|
|
@@ -213,6 +214,47 @@ module OllamaChat::PromptManagement
|
|
|
213
214
|
self
|
|
214
215
|
end
|
|
215
216
|
|
|
217
|
+
# Aggregates the current conversation history into a single string for
|
|
218
|
+
# context-aware generation.
|
|
219
|
+
#
|
|
220
|
+
# Each message is formatted as "Sender Name: Message Content",
|
|
221
|
+
# skipping messages that contain no content.
|
|
222
|
+
#
|
|
223
|
+
# @return [String] The flattened conversation history.
|
|
224
|
+
def prepare_conversation_history
|
|
225
|
+
messages.each_message.inject('') do |result, message|
|
|
226
|
+
message_content = message.content.full? or next result
|
|
227
|
+
sender_name = sender_name_displayed(message, template: false)
|
|
228
|
+
result << "%s: %s" % [ sender_name, message_content ]
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Interactively generates follow-up prompt suggestions based on the current
|
|
233
|
+
# session.
|
|
234
|
+
#
|
|
235
|
+
# This method prompts the user to select a suggestion strategy (e.g., coding
|
|
236
|
+
# or roleplaying), constructs a prompt containing the conversation history,
|
|
237
|
+
# and requests a generation from the AI model. The resulting suggestions
|
|
238
|
+
# are then opened in the editor for final refinement before being returned.
|
|
239
|
+
#
|
|
240
|
+
# @return [String, nil] The refined suggestion text, or nil if the process
|
|
241
|
+
# was cancelled.
|
|
242
|
+
def suggest_prompts
|
|
243
|
+
# Let the user pick a prompt template (e.g., suggest_coding, suggest_roleplaying)
|
|
244
|
+
instruction = choose_prompt(prompt: 'Which suggestion strategy shall we employ? ') or return
|
|
245
|
+
|
|
246
|
+
# Build the context by gathering all current conversation messages
|
|
247
|
+
history = prepare_conversation_history
|
|
248
|
+
full_prompt = "Conversation History:\n#{history}\n\n#{instruction}"
|
|
249
|
+
|
|
250
|
+
# Execute a silent generation call (doesn't add to history)
|
|
251
|
+
response = generate(prompt: full_prompt)
|
|
252
|
+
suggestions = response.response
|
|
253
|
+
|
|
254
|
+
# Pass the AI's suggestions through the editor for final refinement
|
|
255
|
+
edit_text(suggestions)
|
|
256
|
+
end
|
|
257
|
+
|
|
216
258
|
# Lists all prompt templates in the database, indicating which are defaults
|
|
217
259
|
# and showing a truncated preview of their content.
|
|
218
260
|
#
|
|
@@ -235,7 +277,7 @@ module OllamaChat::PromptManagement
|
|
|
235
277
|
# Resets a prompt's content to the default value defined in the configuration.
|
|
236
278
|
#
|
|
237
279
|
# @param name [String, Symbol] the name of the prompt to reset
|
|
238
|
-
# @return [Boolean] true if the prompt was reset, false if no default was found
|
|
280
|
+
# @return [Boolean, nil] true if the prompt was reset, false if no default was found
|
|
239
281
|
def reset_prompt_to_default(name)
|
|
240
282
|
if content = config.prompts[name.to_s]
|
|
241
283
|
store_prompt(name, content)
|
|
@@ -42,7 +42,10 @@ module OllamaChat::RAGHandling
|
|
|
42
42
|
choose_with_state do
|
|
43
43
|
loop do
|
|
44
44
|
tags = @documents.tags.to_a.unshift('[ALL]').unshift('[EXIT]')
|
|
45
|
-
tag = choose_entry(
|
|
45
|
+
tag = choose_entry(
|
|
46
|
+
tags,
|
|
47
|
+
prompt: 'What obsolete records are to be excised from the annals? '
|
|
48
|
+
)
|
|
46
49
|
case tag
|
|
47
50
|
when nil, '[EXIT]'
|
|
48
51
|
STDOUT.puts "Exiting chooser."
|
|
@@ -80,7 +83,10 @@ module OllamaChat::RAGHandling
|
|
|
80
83
|
collections = [ current_collection ] + @documents.collections.to_a
|
|
81
84
|
collections = collections.filter_map(&:to_s).uniq.sort
|
|
82
85
|
collections.unshift('[EXIT]').unshift('[NEW]')
|
|
83
|
-
collection = choose_entry(
|
|
86
|
+
collection = choose_entry(
|
|
87
|
+
collections,
|
|
88
|
+
prompt: 'Which archive of knowledge shall we delve into?'
|
|
89
|
+
) || current_collection
|
|
84
90
|
case collection&.to_s
|
|
85
91
|
when '[NEW]'
|
|
86
92
|
@documents.collection = ask?(
|
|
@@ -506,7 +506,7 @@ module OllamaChat::SessionManagement
|
|
|
506
506
|
else
|
|
507
507
|
offer_new_session and sessions.unshift(SearchUI::Wrapper.new('[new]', display: '[NEW]'))
|
|
508
508
|
sessions = sessions.unshift(SearchUI::Wrapper.new('[exit]', display: '[EXIT]'))
|
|
509
|
-
value = choose_entry(sessions)&.value
|
|
509
|
+
value = choose_entry(sessions, prompt: 'Select a chat session: ')&.value
|
|
510
510
|
if value == '[new]'
|
|
511
511
|
return new_session
|
|
512
512
|
end
|
|
@@ -90,7 +90,11 @@ module OllamaChat::StateSelectors
|
|
|
90
90
|
SearchUI::Wrapper.new(state, display:)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
chosen = choose_entry(
|
|
94
|
+
states,
|
|
95
|
+
prompt: 'Which operational paradigm should be engaged?'
|
|
96
|
+
)
|
|
97
|
+
case chosen
|
|
94
98
|
when '[EXIT]', nil
|
|
95
99
|
STDOUT.puts "Exiting chooser."
|
|
96
100
|
when
|
|
@@ -85,7 +85,10 @@ module OllamaChat::SystemPromptManagement
|
|
|
85
85
|
def change_system_prompt(default)
|
|
86
86
|
prompts = all_system_prompts
|
|
87
87
|
prompts.unshift('[MODEL DEFAULT]').unshift('[EXIT]')
|
|
88
|
-
chosen = choose_entry(
|
|
88
|
+
chosen = choose_entry(
|
|
89
|
+
prompts,
|
|
90
|
+
prompt: 'Which governing law shall we enact?'
|
|
91
|
+
)
|
|
89
92
|
system_prompt_name =
|
|
90
93
|
case chosen
|
|
91
94
|
when '[EXIT]'
|
|
@@ -105,11 +108,14 @@ module OllamaChat::SystemPromptManagement
|
|
|
105
108
|
|
|
106
109
|
# Presents an interactive menu to select a stored system prompt.
|
|
107
110
|
#
|
|
111
|
+
# @param prompt [String] the prompt message to display when asking for input
|
|
112
|
+
# (default: 'Select a system prompt: ')
|
|
113
|
+
#
|
|
108
114
|
# @return [Object, nil] the selected system prompt object, or nil if cancelled
|
|
109
|
-
def choose_system_prompt
|
|
115
|
+
def choose_system_prompt(prompt: 'Select a system prompt: ')
|
|
110
116
|
prompts = all_system_prompts
|
|
111
117
|
prompts.unshift('[EXIT]')
|
|
112
|
-
case chosen = choose_entry(prompts)
|
|
118
|
+
case chosen = choose_entry(prompts, prompt:)
|
|
113
119
|
when '[EXIT]', nil
|
|
114
120
|
STDOUT.puts "Exiting chooser."
|
|
115
121
|
return
|
|
@@ -122,7 +128,7 @@ module OllamaChat::SystemPromptManagement
|
|
|
122
128
|
#
|
|
123
129
|
# @return [self, nil] the current context on success, or nil if cancelled
|
|
124
130
|
def info_system_prompt
|
|
125
|
-
if system_prompt = choose_system_prompt
|
|
131
|
+
if system_prompt = choose_system_prompt(prompt: 'Which system law would you like to review? ')
|
|
126
132
|
use_pager do |output|
|
|
127
133
|
output.puts kramdown_ansi_parse(<<~EOT)
|
|
128
134
|
# System Prompt #{system_prompt.name}
|
|
@@ -163,7 +169,9 @@ module OllamaChat::SystemPromptManagement
|
|
|
163
169
|
#
|
|
164
170
|
# @return [self, nil] the current context on success, or nil if cancelled
|
|
165
171
|
def choose_and_edit_system_prompt
|
|
166
|
-
system_prompt = choose_system_prompt
|
|
172
|
+
system_prompt = choose_system_prompt(
|
|
173
|
+
prompt: 'Which system directive needs rewriting? '
|
|
174
|
+
) or return
|
|
167
175
|
system_prompt.metadata['content'] = edit_text(system_prompt.metadata['content'].to_s)
|
|
168
176
|
system_prompt.save
|
|
169
177
|
ask_to_set_current_system_prompt(system_prompt.name)
|
|
@@ -175,7 +183,7 @@ module OllamaChat::SystemPromptManagement
|
|
|
175
183
|
#
|
|
176
184
|
# @return [self, nil] the current context on success, or nil if cancelled
|
|
177
185
|
def choose_and_delete_system_prompt
|
|
178
|
-
system_prompt = choose_system_prompt or return
|
|
186
|
+
system_prompt = choose_system_prompt(prompt: 'Which old rule is now obsolete? ') or return
|
|
179
187
|
STDOUT.puts kramdown_ansi_parse(
|
|
180
188
|
system_prompt.to_s + "\n---"
|
|
181
189
|
)
|
|
@@ -218,7 +226,7 @@ module OllamaChat::SystemPromptManagement
|
|
|
218
226
|
# @return [self, nil] the current context on success, or nil if the user
|
|
219
227
|
# cancelled the operation or no system prompt was selected.
|
|
220
228
|
def duplicate_system_prompt
|
|
221
|
-
system_prompt = choose_system_prompt or return
|
|
229
|
+
system_prompt = choose_system_prompt(prompt: 'Which core logic shall be cloned? ') or return
|
|
222
230
|
STDOUT.puts kramdown_ansi_parse(
|
|
223
231
|
system_prompt.to_s + "\n---"
|
|
224
232
|
)
|
|
@@ -273,7 +281,7 @@ module OllamaChat::SystemPromptManagement
|
|
|
273
281
|
# @return [self, nil] returns self if the export was successful, or nil if
|
|
274
282
|
# the process was cancelled during system prompt selection or filename entry.
|
|
275
283
|
def export_system_prompt
|
|
276
|
-
prompt = choose_system_prompt or return
|
|
284
|
+
prompt = choose_system_prompt(prompt: 'Which system prompt are you archiving to disk? ') or return
|
|
277
285
|
STDOUT.puts kramdown_ansi_parse(
|
|
278
286
|
prompt.to_s + "\n---"
|
|
279
287
|
)
|
|
@@ -286,7 +294,8 @@ module OllamaChat::SystemPromptManagement
|
|
|
286
294
|
# Resets a system prompt's content to the default value defined in the configuration.
|
|
287
295
|
#
|
|
288
296
|
# @param name [String, Symbol] the name of the system prompt to reset
|
|
289
|
-
# @return [Boolean] true if the system prompt was reset, false if no
|
|
297
|
+
# @return [Boolean, nil] true if the system prompt was reset, false if no
|
|
298
|
+
# default was found
|
|
290
299
|
def reset_system_prompt_to_default(name)
|
|
291
300
|
if content = config.system_prompts[name.to_s]
|
|
292
301
|
store_system_prompt(name, content)
|
|
@@ -128,7 +128,11 @@ module OllamaChat::ToolCalling
|
|
|
128
128
|
loop do
|
|
129
129
|
select_tools = configured_tools - enabled_tools
|
|
130
130
|
select_tools = [ '[EXIT]' ] + select_tools
|
|
131
|
-
|
|
131
|
+
chosen = choose_entry(
|
|
132
|
+
select_tools,
|
|
133
|
+
prompt: 'Which capabilities should be granted to the model?'
|
|
134
|
+
)
|
|
135
|
+
case chosen
|
|
132
136
|
when '[EXIT]', nil
|
|
133
137
|
STDOUT.puts "Exiting chooser."
|
|
134
138
|
return
|
|
@@ -155,7 +159,11 @@ module OllamaChat::ToolCalling
|
|
|
155
159
|
loop do
|
|
156
160
|
select_tools = enabled_tools
|
|
157
161
|
select_tools = [ '[EXIT]' ] + select_tools
|
|
158
|
-
|
|
162
|
+
chosen = choose_entry(
|
|
163
|
+
select_tools,
|
|
164
|
+
prompt: 'Which capabilities should be granted to the model?'
|
|
165
|
+
)
|
|
166
|
+
case chosen
|
|
159
167
|
when '[EXIT]', nil
|
|
160
168
|
STDOUT.puts "Exiting chooser."
|
|
161
169
|
return
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
# the underlying document store.
|
|
19
19
|
class OllamaChat::Tools::RetrieveDocumentSnippets
|
|
20
20
|
include OllamaChat::Tools::Concern
|
|
21
|
+
include Kramdown::ANSI::Width
|
|
21
22
|
|
|
22
23
|
# @return [String] the registered name for this tool
|
|
23
24
|
def self.register_name = 'retrieve_document_snippets'
|
|
@@ -74,6 +75,10 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
|
|
|
74
75
|
text_count: Tool::Function::Parameters::Property.new(
|
|
75
76
|
type: 'integer',
|
|
76
77
|
description: 'The maximum number of snippets to return.'
|
|
78
|
+
),
|
|
79
|
+
rerank: Tool::Function::Parameters::Property.new(
|
|
80
|
+
type: 'boolean',
|
|
81
|
+
description: 'Rerank the returned records if true, (default: true)'
|
|
77
82
|
)
|
|
78
83
|
},
|
|
79
84
|
required: ['query']
|
|
@@ -102,6 +107,8 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
|
|
|
102
107
|
text_size = args.text_size.full? || chat.config.embedding.found_texts_size?
|
|
103
108
|
text_count = args.text_count.full? || chat.config.embedding.found_texts_count?
|
|
104
109
|
min_similarity = args.min_similarity.full?
|
|
110
|
+
rerank = args.rerank
|
|
111
|
+
rerank = true if rerank.nil?
|
|
105
112
|
|
|
106
113
|
old_collection = nil
|
|
107
114
|
|
|
@@ -112,14 +119,19 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
|
|
|
112
119
|
|
|
113
120
|
records = find_document_records(chat, query, tags, text_size, text_count, min_similarity)
|
|
114
121
|
|
|
122
|
+
if rerank && records.any?
|
|
123
|
+
records = rerank_records(chat, query, records)
|
|
124
|
+
end
|
|
125
|
+
|
|
115
126
|
message = records.map { |record|
|
|
116
127
|
link = if record.source =~ %r(\Ahttps?://)
|
|
117
128
|
record.source
|
|
118
129
|
else
|
|
119
130
|
'file://%s' % File.expand_path(record.source)
|
|
120
131
|
end
|
|
132
|
+
link && record.tags.any? or next
|
|
121
133
|
[ link, ?# + record.tags.first ]
|
|
122
|
-
}.
|
|
134
|
+
}.flat_map { |l, t| chat.hyperlink(l, t) }.join(' ')
|
|
123
135
|
|
|
124
136
|
{
|
|
125
137
|
prompt: 'Consider these snippets generated from retrieval when formulating your response!',
|
|
@@ -131,6 +143,12 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
|
|
|
131
143
|
}
|
|
132
144
|
end,
|
|
133
145
|
message:,
|
|
146
|
+
query:,
|
|
147
|
+
tags:,
|
|
148
|
+
min_similarity:,
|
|
149
|
+
text_size:,
|
|
150
|
+
text_count:,
|
|
151
|
+
rerank:,
|
|
134
152
|
}.to_json
|
|
135
153
|
rescue => e
|
|
136
154
|
{ error: e.class.name, message: e.message }.to_json
|
|
@@ -140,6 +158,39 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
|
|
|
140
158
|
|
|
141
159
|
private
|
|
142
160
|
|
|
161
|
+
# Uses the active chat model to filter records based on the query.
|
|
162
|
+
#
|
|
163
|
+
# @param chat [OllamaChat::Chat] the active chat instance
|
|
164
|
+
# @param query [String] the search query string
|
|
165
|
+
# @param records [Array<Documentrix::Utils::TagResult>] the initial set of
|
|
166
|
+
# found records
|
|
167
|
+
#
|
|
168
|
+
# @return [Array<Documentrix::Utils::TagResult>] the filtered array of
|
|
169
|
+
# records
|
|
170
|
+
#
|
|
171
|
+
# @raise [RuntimeError] if the 'rerank' prompt is missing from the
|
|
172
|
+
# configuration
|
|
173
|
+
def rerank_records(chat, query, records)
|
|
174
|
+
candidates = records.each_with_index.map { |r, i|
|
|
175
|
+
"[#{i}] #{truncate(r.text.strip, length: 300)}"
|
|
176
|
+
}.join("\n")
|
|
177
|
+
|
|
178
|
+
prompt = chat.prompt('rerank') or raise "missing prompt 'rerank'"
|
|
179
|
+
prompt = prompt.to_s % { query:, candidates: }
|
|
180
|
+
|
|
181
|
+
begin
|
|
182
|
+
# We use the active chat model to perform the surgical precision
|
|
183
|
+
# filtering
|
|
184
|
+
if response = chat.generate(prompt:)&.response.full?
|
|
185
|
+
indices = response.scan(/\d+/).map(&:to_i).select { |i| (0...records.size).include?(i) }
|
|
186
|
+
records = records.values_at(*indices) if indices.any?
|
|
187
|
+
end
|
|
188
|
+
rescue => e
|
|
189
|
+
chat.log(:error, "Attempted reranking, caught #{e.class} #{e}")
|
|
190
|
+
end
|
|
191
|
+
records
|
|
192
|
+
end
|
|
193
|
+
|
|
143
194
|
# The find_document_records method searches for document records matching the
|
|
144
195
|
# given query string.
|
|
145
196
|
#
|
data/lib/ollama_chat/version.rb
CHANGED
data/ollama_chat.gemspec
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: ollama_chat 0.0.
|
|
2
|
+
# stub: ollama_chat 0.0.92 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "ollama_chat".freeze
|
|
6
|
-
s.version = "0.0.
|
|
6
|
+
s.version = "0.0.92".freeze
|
|
7
7
|
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
9
9
|
s.require_paths = ["lib".freeze]
|
|
@@ -49,7 +49,10 @@ describe OllamaChat::InputContent do
|
|
|
49
49
|
|
|
50
50
|
# Mock the selection process
|
|
51
51
|
expect(chat).to receive(:choose_entry).
|
|
52
|
-
with(
|
|
52
|
+
with(
|
|
53
|
+
files.unshift('[EXIT]'),
|
|
54
|
+
prompt: 'Select a file to import: ',
|
|
55
|
+
).and_return(files[1])
|
|
53
56
|
|
|
54
57
|
result = chat.choose_filename('spec/assets/**/*.txt')
|
|
55
58
|
expect(result).to eq Pathname.new(files[1])
|
|
@@ -123,7 +123,8 @@ describe OllamaChat::StateSelectors::StateSelector do
|
|
|
123
123
|
it 'allows user to select a state from available options' do
|
|
124
124
|
# Mock the chooser to return a specific choice
|
|
125
125
|
expect(selector).to receive(:choose_entry).with(
|
|
126
|
-
%w[ [EXIT] enabled disabled low high ]
|
|
126
|
+
%w[ [EXIT] enabled disabled low high ],
|
|
127
|
+
prompt: 'Which operational paradigm should be engaged?'
|
|
127
128
|
).and_return(double(value: 'low'))
|
|
128
129
|
|
|
129
130
|
selector.choose
|
|
@@ -25,6 +25,7 @@ describe OllamaChat::Tools::RetrieveDocumentSnippets do
|
|
|
25
25
|
min_similarity: nil,
|
|
26
26
|
text_size: nil,
|
|
27
27
|
text_count: nil,
|
|
28
|
+
rerank: false,
|
|
28
29
|
)
|
|
29
30
|
)
|
|
30
31
|
)
|
|
@@ -68,6 +69,7 @@ describe OllamaChat::Tools::RetrieveDocumentSnippets do
|
|
|
68
69
|
min_similarity: nil,
|
|
69
70
|
text_size: nil,
|
|
70
71
|
text_count: nil,
|
|
72
|
+
rerank: false,
|
|
71
73
|
)
|
|
72
74
|
)
|
|
73
75
|
)
|
|
@@ -79,7 +81,7 @@ describe OllamaChat::Tools::RetrieveDocumentSnippets do
|
|
|
79
81
|
[
|
|
80
82
|
double(
|
|
81
83
|
'Record',
|
|
82
|
-
text: '
|
|
84
|
+
text: 'quintessential ruby',
|
|
83
85
|
source: 'foo',
|
|
84
86
|
tags: %w[ ruby expert ],
|
|
85
87
|
tags_set: [],
|
|
@@ -107,6 +109,7 @@ describe OllamaChat::Tools::RetrieveDocumentSnippets do
|
|
|
107
109
|
min_similarity: nil,
|
|
108
110
|
text_size: nil,
|
|
109
111
|
text_count: nil,
|
|
112
|
+
rerank: false,
|
|
110
113
|
)
|
|
111
114
|
)
|
|
112
115
|
)
|
|
@@ -141,6 +144,78 @@ describe OllamaChat::Tools::RetrieveDocumentSnippets do
|
|
|
141
144
|
expect(json.message).to eq('Empty query')
|
|
142
145
|
end
|
|
143
146
|
|
|
147
|
+
it 'performs reranking when rerank is true' do
|
|
148
|
+
tool_call = double(
|
|
149
|
+
'ToolCall',
|
|
150
|
+
function: double(
|
|
151
|
+
name: 'retrieve_document_snippets',
|
|
152
|
+
arguments: double(
|
|
153
|
+
query: 'Ruby array',
|
|
154
|
+
tags: nil,
|
|
155
|
+
collection: nil,
|
|
156
|
+
min_similarity: nil,
|
|
157
|
+
text_size: nil,
|
|
158
|
+
text_count: nil,
|
|
159
|
+
rerank: true,
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
records = [
|
|
165
|
+
double('Record', text: 'first', source: 's1', tags: [], tags_set: [], similarity: 0.1),
|
|
166
|
+
double('Record', text: 'second', source: 's2', tags: [], tags_set: [], similarity: 0.9)
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
tool = described_class.new
|
|
170
|
+
expect(tool).to receive(:find_document_records).and_return(records)
|
|
171
|
+
|
|
172
|
+
allow(chat).to receive(:prompt).with('rerank').and_return("template %{query} %{candidates}")
|
|
173
|
+
response_val = double('Response', response: double('FullResponse', full?: '1', response: '1'))
|
|
174
|
+
allow(chat).to receive(:generate).with(prompt: anything).and_return(response_val)
|
|
175
|
+
|
|
176
|
+
result = tool.execute(tool_call, chat:)
|
|
177
|
+
json = json_object(result)
|
|
178
|
+
|
|
179
|
+
expect(json.snippets.size).to eq 1
|
|
180
|
+
expect(json.snippets.first.text).to eq 'second'
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'performs reranking when rerank is nil (defaults to true)' do
|
|
184
|
+
tool_call = double(
|
|
185
|
+
'ToolCall',
|
|
186
|
+
function: double(
|
|
187
|
+
name: 'retrieve_document_snippets',
|
|
188
|
+
arguments: double(
|
|
189
|
+
query: 'Ruby array',
|
|
190
|
+
tags: nil,
|
|
191
|
+
collection: nil,
|
|
192
|
+
min_similarity: nil,
|
|
193
|
+
text_size: nil,
|
|
194
|
+
text_count: nil,
|
|
195
|
+
rerank: nil,
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
records = [
|
|
201
|
+
double('Record', text: 'first', source: 's1', tags: [], tags_set: [], similarity: 0.1),
|
|
202
|
+
double('Record', text: 'second', source: 's2', tags: [], tags_set: [], similarity: 0.9)
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
tool = described_class.new
|
|
206
|
+
expect(tool).to receive(:find_document_records).and_return(records)
|
|
207
|
+
|
|
208
|
+
allow(chat).to receive(:prompt).with('rerank').and_return("template %{query} %{candidates}")
|
|
209
|
+
response_val = double('Response', response: double('FullResponse', full?: '0', response: '0'))
|
|
210
|
+
allow(chat).to receive(:generate).with(prompt: anything).and_return(response_val)
|
|
211
|
+
|
|
212
|
+
result = tool.execute(tool_call, chat:)
|
|
213
|
+
json = json_object(result)
|
|
214
|
+
|
|
215
|
+
expect(json.snippets.size).to eq 1
|
|
216
|
+
expect(json.snippets.first.text).to eq 'first'
|
|
217
|
+
end
|
|
218
|
+
|
|
144
219
|
it 'can be converted to hash' do
|
|
145
220
|
expect(described_class.new.to_hash).to be_a(Hash)
|
|
146
221
|
end
|