ollama_chat 0.0.98 → 0.0.99
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 +41 -0
- data/lib/ollama_chat/chat.rb +15 -1
- data/lib/ollama_chat/commands.rb +8 -8
- data/lib/ollama_chat/message_list.rb +2 -2
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +156 -24
- data/lib/ollama_chat/personae_management.rb +2 -2
- data/lib/ollama_chat/prompt_management.rb +3 -3
- data/lib/ollama_chat/tools/copy_to_clipboard.rb +6 -15
- data/lib/ollama_chat/version.rb +1 -1
- data/ollama_chat.gemspec +2 -2
- data/spec/ollama_chat/chat_spec.rb +1 -1
- data/spec/ollama_chat/history_spec.rb +1 -1
- data/spec/ollama_chat/tools/copy_to_clipboard_spec.rb +13 -14
- data/spec/ollama_chat/tools/execute_ri_spec.rb +1 -1
- data/spec/ollama_chat/tools/get_url_spec.rb +7 -7
- 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: '0818076703ebd6e8d8babbe5898a6a0069863ce7cebf18658f70e8d4b5592c51'
|
|
4
|
+
data.tar.gz: 7e9f768d41bff3560c2d22ac20ace84da0b580b3b17f8f9d1ffd3522af5d8db1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4864950b3246106793b51ffe74e3ead6dad4683f1b9fcaf710bf7f672264c646dc90dacdbcef437725b725230b8d0b70938045729ca982c83845ebce41bb773d
|
|
7
|
+
data.tar.gz: 5b99426668efc34bbb89a17faf2dcf016c1a6ada4c69d44882ebb40bcb836907741f96b5fb66ee99ea75b78abbdd34069ddbc186d525acd015302bcea95e55a7
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-07-13 v0.0.99
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Command Handling & UX**
|
|
8
|
+
- Updated regexes for `/system`, `/session`, `/prompt`, `/conversation`,
|
|
9
|
+
`/character`, `/input`, `/pipe`, and `/output` in
|
|
10
|
+
`lib/ollama_chat/commands.rb` to prevent positional arguments from
|
|
11
|
+
starting with a hyphen.
|
|
12
|
+
- Enhanced warning messages in `lib/ollama_chat/message_list.rb` to include
|
|
13
|
+
explicit suggestions for `/drop` and `/regenerate`.
|
|
14
|
+
|
|
15
|
+
- **LLM & Prompt Management**
|
|
16
|
+
- Updated the `generate` method in `lib/ollama_chat/chat.rb` to capture
|
|
17
|
+
output in `content` and implemented conditional logging ( `:warn` for
|
|
18
|
+
empty results, `:info` otherwise).
|
|
19
|
+
- Added `.full? or return` guard clauses to `edit_text('')` and
|
|
20
|
+
`generate(prompt: full_prompt)` within
|
|
21
|
+
`lib/ollama_chat/prompt_management.rb`.
|
|
22
|
+
- Overhauled the `suggest_coding` prompt in `default_config.yml` to adopt a
|
|
23
|
+
Senior Software Architect and Technical Auditor persona.
|
|
24
|
+
- Overhauled the `suggest_roleplaying` prompt in `default_config.yml` to
|
|
25
|
+
adopt a Narrative Consultant and Game Master's Assistant persona.
|
|
26
|
+
|
|
27
|
+
- **Tools**
|
|
28
|
+
- Modified `OllamaChat::Tools::CopyToClipboard` to make the `text`
|
|
29
|
+
parameter required.
|
|
30
|
+
- Updated `lib/ollama_chat/tools/copy_to_clipboard.rb` to raise
|
|
31
|
+
`OllamaChat::ToolFunctionArgumentError` if `text` is missing and
|
|
32
|
+
simplified the success message.
|
|
33
|
+
|
|
34
|
+
- **Refactoring & Internal Improvements**
|
|
35
|
+
- Adopted Ruby shorthand for keyword arguments in:
|
|
36
|
+
- `set_default_persona_name` and `load_personae`
|
|
37
|
+
(`lib/ollama_chat/personae_management.rb`).
|
|
38
|
+
- `choose_prompt` via the `default` parameter
|
|
39
|
+
(`lib/ollama_chat/prompt_management.rb`).
|
|
40
|
+
- `OllamaChat::Chat` instantiation using `argv` in specs.
|
|
41
|
+
- The `topic` parameter in `spec/ollama_chat/tools/execute_ri_spec.rb`.
|
|
42
|
+
- The `url` parameter in `spec/ollama_chat/tools/get_url_spec.rb`.
|
|
43
|
+
|
|
3
44
|
## 2026-07-09 v0.0.98
|
|
4
45
|
|
|
5
46
|
### Added
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -255,7 +255,7 @@ class OllamaChat::Chat
|
|
|
255
255
|
),
|
|
256
256
|
]
|
|
257
257
|
|
|
258
|
-
ollama.chat(
|
|
258
|
+
content = ollama.chat(
|
|
259
259
|
model: @model,
|
|
260
260
|
messages: ,
|
|
261
261
|
options: model_options,
|
|
@@ -263,6 +263,20 @@ class OllamaChat::Chat
|
|
|
263
263
|
think: false,
|
|
264
264
|
tools:
|
|
265
265
|
)&.message&.content.to_s
|
|
266
|
+
|
|
267
|
+
if content.empty?
|
|
268
|
+
log(
|
|
269
|
+
:warn,
|
|
270
|
+
"Sent #{prompt.inspect} to LLM for generation, received no content!"
|
|
271
|
+
)
|
|
272
|
+
else
|
|
273
|
+
log(
|
|
274
|
+
:info,
|
|
275
|
+
"Sent #{prompt.inspect} to LLM for generation, received #{content.inspect}"
|
|
276
|
+
)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
content
|
|
266
280
|
end
|
|
267
281
|
|
|
268
282
|
private
|
data/lib/ollama_chat/commands.rb
CHANGED
|
@@ -170,7 +170,7 @@ module OllamaChat::Commands
|
|
|
170
170
|
|
|
171
171
|
command(
|
|
172
172
|
name: :system,
|
|
173
|
-
regexp: %r(^/system(?:\s+(change|info|edit|add|delete|list|duplicate|export|import|reset))?(?:\s+(
|
|
173
|
+
regexp: %r(^/system(?:\s+(change|info|edit|add|delete|list|duplicate|export|import|reset))?(?:\s+([^-].*))?$),
|
|
174
174
|
complete: [ 'system', %w[ change info edit add delete list duplicate export import reset ] ],
|
|
175
175
|
optional: true,
|
|
176
176
|
help: <<~EOT
|
|
@@ -285,7 +285,7 @@ module OllamaChat::Commands
|
|
|
285
285
|
|
|
286
286
|
command(
|
|
287
287
|
name: :session,
|
|
288
|
-
regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|summarize|delete|model options change|model options))?((?:\s+-(?:[sf]|p\s*\w+))*)(?:\s+(
|
|
288
|
+
regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|summarize|delete|model options change|model options))?((?:\s+-(?:[sf]|p\s*\w+))*)(?:\s+([^-].*))?$),
|
|
289
289
|
complete: [ 'session', %w[ change previous list new duplicate rename summarize delete model\ options\ change model\ options ] ],
|
|
290
290
|
optional: true,
|
|
291
291
|
options: "[-s|-f|-p profile]\n[name]",
|
|
@@ -490,7 +490,7 @@ module OllamaChat::Commands
|
|
|
490
490
|
|
|
491
491
|
command(
|
|
492
492
|
name: :prompt,
|
|
493
|
-
regexp: %r(^/prompt(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset|suggest|-e))?(\s+-e)?(?:\s+(
|
|
493
|
+
regexp: %r(^/prompt(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset|suggest|-e))?(\s+-e)?(?:\s+([^-].*))?$),
|
|
494
494
|
complete: [ 'prompt', %w[ edit info add delete list duplicate import export reset suggest ] ],
|
|
495
495
|
optional: true,
|
|
496
496
|
help: <<~EOT,
|
|
@@ -564,7 +564,7 @@ module OllamaChat::Commands
|
|
|
564
564
|
|
|
565
565
|
command(
|
|
566
566
|
name: :conversation,
|
|
567
|
-
regexp: %r(^/conversation\s+(save|load)((?:\s+-(?:[c]))*)\s+(
|
|
567
|
+
regexp: %r(^/conversation\s+(save|load)((?:\s+-(?:[c]))*)\s+([^-].*)$),
|
|
568
568
|
complete: [ 'conversation', %w[ save load ] ],
|
|
569
569
|
options: '[-c]',
|
|
570
570
|
help: <<~EOT
|
|
@@ -696,7 +696,7 @@ module OllamaChat::Commands
|
|
|
696
696
|
|
|
697
697
|
command(
|
|
698
698
|
name: :character,
|
|
699
|
-
regexp: %r(^/character(?:\s+(info|load|import))(?:\s+(
|
|
699
|
+
regexp: %r(^/character(?:\s+(info|load|import))(?:\s+([^-].+))?$),
|
|
700
700
|
complete: [ 'character', %w[ info load import ] ],
|
|
701
701
|
help: <<~EOT
|
|
702
702
|
Display character info, load or import a character
|
|
@@ -772,7 +772,7 @@ module OllamaChat::Commands
|
|
|
772
772
|
|
|
773
773
|
command(
|
|
774
774
|
name: :input,
|
|
775
|
-
regexp: %r(^/input(?:\s+(path|context|embedding|summary)(?:\s*(?=\z))?)?((?:\s+-(?:[apre]|c\s*\w+|w\s*\d+|t\s*[-\w\.]+(?:,[-\w\.]+)*))*)(?:\s+(
|
|
775
|
+
regexp: %r(^/input(?:\s+(path|context|embedding|summary)(?:\s*(?=\z))?)?((?:\s+-(?:[apre]|c\s*\w+|w\s*\d+|t\s*[-\w\.]+(?:,[-\w\.]+)*))*)(?:\s+([^-].*))?$),
|
|
776
776
|
optional: true,
|
|
777
777
|
complete: [ 'input', %w[ path context embedding summary ] ],
|
|
778
778
|
options: "[\n -w|-a|-p|-e|\n -c <collection>|\n -t <tags>\n]\n[arg…]",
|
|
@@ -891,7 +891,7 @@ module OllamaChat::Commands
|
|
|
891
891
|
|
|
892
892
|
command(
|
|
893
893
|
name: :pipe,
|
|
894
|
-
regexp: %r(^/pipe(\s+-e)?\s+(
|
|
894
|
+
regexp: %r(^/pipe(\s+-e)?\s+([^-].*)$),
|
|
895
895
|
options: 'path',
|
|
896
896
|
help: <<~EOT
|
|
897
897
|
Pipe the last response into another command's stdin.
|
|
@@ -918,7 +918,7 @@ module OllamaChat::Commands
|
|
|
918
918
|
|
|
919
919
|
command(
|
|
920
920
|
name: :output,
|
|
921
|
-
regexp: %r(^/output(\s+-e)?\s+(
|
|
921
|
+
regexp: %r(^/output(\s+-e)?\s+([^-].*)$),
|
|
922
922
|
options: '[-e] path',
|
|
923
923
|
help: <<~EOT
|
|
924
924
|
Save the last response to a file.
|
|
@@ -277,11 +277,11 @@ class OllamaChat::MessageList
|
|
|
277
277
|
)
|
|
278
278
|
msg = <<~EOT
|
|
279
279
|
|
|
280
|
-
⚠️ Last message is actually #{bold{'user message'}}, see:
|
|
280
|
+
⚠️ Last message is actually a #{bold{'user message'}}, see:
|
|
281
281
|
|
|
282
282
|
#{message_content}
|
|
283
283
|
|
|
284
|
-
You might want to drop it.
|
|
284
|
+
You might want to /drop it or /regenerate it.
|
|
285
285
|
EOT
|
|
286
286
|
output.puts msg
|
|
287
287
|
end
|
|
@@ -172,33 +172,165 @@ prompts:
|
|
|
172
172
|
|
|
173
173
|
%{content}
|
|
174
174
|
suggest_coding: |
|
|
175
|
-
|
|
176
|
-
concise follow-up prompts that the user might want to ask next to further
|
|
177
|
-
their goal.
|
|
175
|
+
## Context
|
|
178
176
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
You are acting as a Senior Software Architect and Technical Auditor. Your goal
|
|
178
|
+
is to analyze the conversation history between a developer and an AI to
|
|
179
|
+
identify technical blind spots, architectural risks, and optimization
|
|
180
|
+
opportunities. You do not just summarize; you challenge the current
|
|
181
|
+
implementation to ensure it is production-ready, scalable, and maintainable.
|
|
183
182
|
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
## Task
|
|
184
|
+
|
|
185
|
+
Analyze the provided Conversation History. Generate exactly 8 distinct, concise
|
|
186
|
+
follow-up prompts that the user could ask next to further their goal from a
|
|
187
|
+
professional engineering perspective.
|
|
188
|
+
|
|
189
|
+
Each prompt must map strictly to one of these categories:
|
|
190
|
+
|
|
191
|
+
1. **Technical Deep-Dive**: A tactical inquiry into the immediate
|
|
192
|
+
implementation details or logic flow.
|
|
193
|
+
2. **Edge Case/Optimization**: A stress test identifying where the logic
|
|
194
|
+
breaks, fails silently, or degrades in performance.
|
|
195
|
+
3. **Complexity & Scale**: An analysis of Big O, memory pressure, or
|
|
196
|
+
concurrency (e.g., "How does this behave under 100x load?").
|
|
197
|
+
4. **Maintainability & Debt**: An evaluation of clean code principles and
|
|
198
|
+
whether the current approach introduces future technical debt.
|
|
199
|
+
5. **Alternative Trade-offs**: A "Plan B" challenge suggesting a different
|
|
200
|
+
design pattern, library, or architectural approach.
|
|
201
|
+
6. **Verification & Testing**: A request for a programmatic verification
|
|
202
|
+
strategy (e.g., boundary value analysis or mocking dependencies).
|
|
203
|
+
7. **Knowledge Transfer & Documentation**: An inquiry about updating API
|
|
204
|
+
contracts, READMEs, or creating an Architectural Decision Record (ADR).
|
|
205
|
+
8. **Strategic Next Step**: A high-level roadmap question connecting this
|
|
206
|
+
tactical win to the broader system architecture.
|
|
207
|
+
|
|
208
|
+
## Constraints
|
|
209
|
+
|
|
210
|
+
- **Quantity**: Exactly 8 suggestions.
|
|
211
|
+
- **Tone**: Rigorous, auditing, and senior. Avoid passive phrasing ("Maybe you
|
|
212
|
+
could...") in favor of critical analysis ("This approach risks X; how do we
|
|
213
|
+
resolve it?").
|
|
214
|
+
- **Negative Constraints**:
|
|
215
|
+
- DO NOT use numbering or bullet points.
|
|
216
|
+
- DO NOT include introductory or concluding text.
|
|
217
|
+
- DO NOT suggest generic, superficial questions (e.g., "How does this
|
|
218
|
+
work?").
|
|
219
|
+
- **Conciseness**: Each prompt must be a single, punchy sentence.
|
|
220
|
+
|
|
221
|
+
## Few-Shot Examples
|
|
222
|
+
|
|
223
|
+
**Input:** [User and AI just implemented a Ruby method to parse a large JSON
|
|
224
|
+
file into a database]
|
|
225
|
+
|
|
226
|
+
**Output:**
|
|
227
|
+
|
|
228
|
+
Can we refactor the parser to use a stream-based approach instead of loading
|
|
229
|
+
the entire JSON into memory?
|
|
230
|
+
|
|
231
|
+
How does this implementation handle malformed JSON or missing keys in the
|
|
232
|
+
middle of a 2GB file without crashing the process?
|
|
233
|
+
|
|
234
|
+
What is the time complexity of the current insert logic, and can we implement
|
|
235
|
+
bulk inserts to reduce database round trips?
|
|
236
|
+
|
|
237
|
+
Does the current naming convention for these helper methods align with our
|
|
238
|
+
project's style guide, or are we introducing cognitive load for future
|
|
239
|
+
maintainers?
|
|
240
|
+
|
|
241
|
+
Would using a dedicated library like Oj provide significant performance gains
|
|
242
|
+
over the standard JSON implementation here?
|
|
243
|
+
|
|
244
|
+
What specific boundary cases should be covered in the RSpec suite to ensure the
|
|
245
|
+
parser doesn't truncate data on trailing whitespace?
|
|
246
|
+
|
|
247
|
+
Which sections of the API documentation need to be updated to reflect this
|
|
248
|
+
change in the data ingestion pipeline?
|
|
249
|
+
|
|
250
|
+
Now that parsing is solved, how does this integrate into our overall background
|
|
251
|
+
job queue and retry logic?
|
|
252
|
+
|
|
253
|
+
## Output Format
|
|
254
|
+
|
|
255
|
+
Output only the 8 suggestions as plain text, each separated by one empty line.
|
|
256
|
+
No other characters or formatting.
|
|
186
257
|
suggest_roleplaying: |
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
258
|
+
## Context
|
|
259
|
+
|
|
260
|
+
You are an expert Narrative Consultant and Game Master's Assistant. Your
|
|
261
|
+
purpose is to analyze a roleplay conversation history and provide high-value,
|
|
262
|
+
diverse action prompts that help a player overcome writer's block while
|
|
263
|
+
deepening the story.
|
|
264
|
+
|
|
265
|
+
## Task
|
|
266
|
+
|
|
267
|
+
Analyze the provided Conversation History and current narrative state. Generate
|
|
268
|
+
exactly 9 distinct, concise prompt suggestions that the user could use as their
|
|
269
|
+
character's next response.
|
|
270
|
+
|
|
271
|
+
Each suggestion must map to one of these specific categories:
|
|
272
|
+
|
|
273
|
+
1. Plot Driver: A bold action or choice that advances the plot or increases
|
|
274
|
+
tension.
|
|
275
|
+
2. Emotional Core: An interaction focusing on emotional depth, social nuance,
|
|
276
|
+
or psychological reaction.
|
|
277
|
+
3. World Insight: Investigating an object or detail in the environment. Include
|
|
278
|
+
a suggested dice roll (e.g., "Roll 1d20") if there is an inherent risk of
|
|
279
|
+
failure or a need for high skill.
|
|
280
|
+
4. Hidden Agenda: An action involving secrecy, deception, or private motives.
|
|
281
|
+
Include a suggested dice roll (e.g., "Roll 1d20") if the action risks
|
|
282
|
+
discovery.
|
|
283
|
+
5. Social Catalyst: A prompt that engages all characters currently present in
|
|
284
|
+
the scene to force group interaction.
|
|
285
|
+
6. High Stakes: A risky gamble or sudden complication. This MUST explicitly
|
|
286
|
+
include a suggested dice roll (e.g., "Roll 1d20").
|
|
287
|
+
7. Character Quirk: A response rooted in the character's specific flaws,
|
|
288
|
+
habits, or obsessions.
|
|
289
|
+
8. Meta-Pivot: An abrupt shift in scene direction via a revelation, surprising
|
|
290
|
+
admission, or sudden change of heart.
|
|
291
|
+
9. The Curveball: An unexpected external event or realization that forces an
|
|
292
|
+
immediate reaction.
|
|
293
|
+
|
|
294
|
+
## Constraints
|
|
295
|
+
|
|
296
|
+
- Generate exactly 9 suggestions.
|
|
297
|
+
- Each suggestion must be concise and punchy.
|
|
298
|
+
- Negative Constraints: Do not use numbering, bullet points, or
|
|
299
|
+
introductory/concluding text. Avoid generic clichés (e.g., "I can't believe
|
|
300
|
+
this" or "What do we do now?").
|
|
301
|
+
- Ensure the tone of the suggestions aligns with the established voice of the
|
|
302
|
+
characters in the history.
|
|
303
|
+
|
|
304
|
+
## Variables
|
|
305
|
+
|
|
306
|
+
- Conversation History: The provided log of messages between players and AI.
|
|
307
|
+
|
|
308
|
+
## Few-Shot Examples
|
|
309
|
+
|
|
310
|
+
Input: [Scene where a party is arguing in a rainy forest while being hunted]
|
|
311
|
+
Output:
|
|
312
|
+
Demand that everyone stop shouting and listen for the sound of footsteps in the brush.
|
|
313
|
+
|
|
314
|
+
Quietly admit to the party leader that you are terrified, leaning into their shoulder for support.
|
|
315
|
+
|
|
316
|
+
Examine the muddy tracks near the campfire to see if the hunters are human or something else. Roll 1d20.
|
|
317
|
+
|
|
318
|
+
Secretly slip the map out of the leader's pocket while they are distracted by the argument. Roll 1d20.
|
|
319
|
+
|
|
320
|
+
Raise your voice and challenge every single person present to state their true loyalty right now.
|
|
321
|
+
|
|
322
|
+
Attempt to leap across the ravine to flank the hunters, risking a fall into the rapids. Roll 1d20.
|
|
323
|
+
|
|
324
|
+
Obsessively polish your sword with a rag, ignoring the argument entirely until it is perfectly mirrored.
|
|
325
|
+
|
|
326
|
+
Suddenly reveal that you were actually sent here by the enemy as a double agent.
|
|
327
|
+
|
|
328
|
+
A sudden lightning strike hits a nearby tree, knocking everyone off balance and creating a deafening blast.
|
|
329
|
+
|
|
330
|
+
## Output Format
|
|
331
|
+
|
|
332
|
+
Output only the 9 suggestions as plain text, each separated by one empty line.
|
|
333
|
+
No other text.
|
|
202
334
|
system_prompts:
|
|
203
335
|
default: <%= OC::OLLAMA::CHAT::SYSTEM || "%{persona}\n\n%{runtime_info}".inspect %>
|
|
204
336
|
persona: |
|
|
@@ -73,7 +73,7 @@ module OllamaChat::PersonaeManagement
|
|
|
73
73
|
def set_default_persona_name(persona_name)
|
|
74
74
|
if persona_name.present? && persona_name != :none
|
|
75
75
|
@default_persona_name = Pathname.new(persona_name).basename.sub_ext('').to_path
|
|
76
|
-
@session.update(default_persona_name:
|
|
76
|
+
@session.update(default_persona_name:)
|
|
77
77
|
else
|
|
78
78
|
@session.update(default_persona_name: nil)
|
|
79
79
|
@default_persona_name = nil
|
|
@@ -403,7 +403,7 @@ module OllamaChat::PersonaeManagement
|
|
|
403
403
|
def load_personae
|
|
404
404
|
chosen = Set[]
|
|
405
405
|
choose_with_state do
|
|
406
|
-
while persona = choose_persona(chosen
|
|
406
|
+
while persona = choose_persona(chosen:, prompt: 'Who else should join the conversation? %s')
|
|
407
407
|
persona == :none and next
|
|
408
408
|
chosen << persona
|
|
409
409
|
end
|
|
@@ -31,7 +31,7 @@ module OllamaChat::PromptManagement
|
|
|
31
31
|
# @return [OllamaChat::Database::Models::Prompt, nil] the selected prompt
|
|
32
32
|
# model, or nil if the user chooses '[EXIT]' or cancels the selection.
|
|
33
33
|
def choose_prompt(default: nil, prompt: 'Select a prompt template: %s')
|
|
34
|
-
prompts = all_prompts(default:
|
|
34
|
+
prompts = all_prompts(default:)
|
|
35
35
|
prompts.unshift('[EXIT]')
|
|
36
36
|
case chosen = choose_entry(prompts, prompt:)
|
|
37
37
|
when '[EXIT]', nil
|
|
@@ -246,7 +246,7 @@ module OllamaChat::PromptManagement
|
|
|
246
246
|
instruction = nil
|
|
247
247
|
if edit
|
|
248
248
|
# Let the user write a suggestion instruction on the fly
|
|
249
|
-
instruction = edit_text('')
|
|
249
|
+
instruction = edit_text('').full? or return
|
|
250
250
|
else
|
|
251
251
|
# Let the user pick a prompt template (e.g., suggest_coding, suggest_roleplaying)
|
|
252
252
|
instruction = choose_prompt(prompt: 'Which suggestion strategy shall we employ? %s') or return
|
|
@@ -263,7 +263,7 @@ module OllamaChat::PromptManagement
|
|
|
263
263
|
EOT
|
|
264
264
|
|
|
265
265
|
# Execute a silent chat oneshot call (doesn't add to history)
|
|
266
|
-
suggestions = generate(prompt: full_prompt)
|
|
266
|
+
suggestions = generate(prompt: full_prompt).full? or return
|
|
267
267
|
|
|
268
268
|
# Pass the AI's suggestions through the editor for final refinement
|
|
269
269
|
edit_text(suggestions)
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
# A tool for copying
|
|
1
|
+
# A tool for copying a text to the clipboard.
|
|
2
2
|
#
|
|
3
3
|
# The executable used for the copy operation is read from the configuration
|
|
4
4
|
# under `copy.executable`. The default configuration ships with
|
|
5
5
|
# `ctc` – a small CLI that copies stdin to the system clipboard.
|
|
6
|
-
#
|
|
7
|
-
# The tool has no parameters; it simply grabs the most recent response
|
|
8
|
-
# from the chat instance and streams it to the executable.
|
|
9
6
|
class OllamaChat::Tools::CopyToClipboard
|
|
10
7
|
include OllamaChat::Tools::Concern
|
|
11
8
|
|
|
@@ -20,9 +17,8 @@ class OllamaChat::Tools::CopyToClipboard
|
|
|
20
17
|
function: Tool::Function.new(
|
|
21
18
|
name:,
|
|
22
19
|
description: <<~EOT,
|
|
23
|
-
Clipboard helper – Copies supplied string
|
|
24
|
-
|
|
25
|
-
output.
|
|
20
|
+
Clipboard helper – Copies supplied string into the OS clipboard,
|
|
21
|
+
enabling quick pasting elsewhere. No output.
|
|
26
22
|
EOT
|
|
27
23
|
parameters: Tool::Function::Parameters.new(
|
|
28
24
|
type: 'object',
|
|
@@ -36,7 +32,7 @@ class OllamaChat::Tools::CopyToClipboard
|
|
|
36
32
|
description: 'True if the copied text should be edited by the user, (default: false)'
|
|
37
33
|
)
|
|
38
34
|
},
|
|
39
|
-
required: []
|
|
35
|
+
required: %w[ text ]
|
|
40
36
|
)
|
|
41
37
|
)
|
|
42
38
|
)
|
|
@@ -51,17 +47,12 @@ class OllamaChat::Tools::CopyToClipboard
|
|
|
51
47
|
def execute(tool_call, **opts)
|
|
52
48
|
args = tool_call.function.arguments
|
|
53
49
|
edit = !!args.edit
|
|
54
|
-
text = args.text.full?
|
|
50
|
+
text = args.text.full? or raise OllamaChat::ToolFunctionArgumentError, 'no text given'
|
|
55
51
|
|
|
56
52
|
chat = opts[:chat]
|
|
57
53
|
chat.perform_copy_to_clipboard(text:, content: true, edit:)
|
|
58
54
|
|
|
59
|
-
message =
|
|
60
|
-
if text.nil?
|
|
61
|
-
"The last response has been successfully copied to the system clipboard."
|
|
62
|
-
else
|
|
63
|
-
"The provided text has been successfully copied to the system clipboard."
|
|
64
|
-
end
|
|
55
|
+
message = "The provided text has been successfully copied to the system clipboard."
|
|
65
56
|
|
|
66
57
|
{
|
|
67
58
|
success: true,
|
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.99 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.99".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]
|
|
@@ -17,7 +17,7 @@ describe OllamaChat::Tools::CopyToClipboard do
|
|
|
17
17
|
expect(described_class.new.to_hash).to be_a Hash
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
it '
|
|
20
|
+
it 'raises an error if no text is provided' do
|
|
21
21
|
tool_call = double(
|
|
22
22
|
'ToolCall',
|
|
23
23
|
function: double(
|
|
@@ -29,17 +29,13 @@ describe OllamaChat::Tools::CopyToClipboard do
|
|
|
29
29
|
)
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
# Test that perform_copy_to_clipboard is called with content: true
|
|
33
|
-
expect(chat).to receive(:perform_copy_to_clipboard).with(text: nil, content: true, edit: false)
|
|
34
|
-
|
|
35
32
|
result = described_class.new.execute(tool_call, chat:)
|
|
36
33
|
|
|
37
34
|
# Should return valid JSON
|
|
38
35
|
expect(result).to be_a(String)
|
|
39
36
|
json = json_object(result)
|
|
40
|
-
expect(json.error).to
|
|
41
|
-
expect(json.
|
|
42
|
-
expect(json.message).to eq 'The last response has been successfully copied to the system clipboard.'
|
|
37
|
+
expect(json.error).to eq 'OllamaChat::ToolFunctionArgumentError'
|
|
38
|
+
expect(json.message).to eq 'no text given'
|
|
43
39
|
end
|
|
44
40
|
|
|
45
41
|
it 'can copy custom text to the clipboard' do
|
|
@@ -70,19 +66,20 @@ describe OllamaChat::Tools::CopyToClipboard do
|
|
|
70
66
|
end
|
|
71
67
|
|
|
72
68
|
it 'can be executed with edit option' do
|
|
69
|
+
text = 'Text to edit'
|
|
73
70
|
tool_call = double(
|
|
74
71
|
'ToolCall',
|
|
75
72
|
function: double(
|
|
76
73
|
name: 'copy_to_clipboard',
|
|
77
74
|
arguments: double(
|
|
78
|
-
text:
|
|
75
|
+
text: ,
|
|
79
76
|
edit: true
|
|
80
77
|
)
|
|
81
78
|
)
|
|
82
79
|
)
|
|
83
80
|
|
|
84
81
|
# Test that perform_copy_to_clipboard is called with edit: true
|
|
85
|
-
expect(chat).to receive(:perform_copy_to_clipboard).with(text
|
|
82
|
+
expect(chat).to receive(:perform_copy_to_clipboard).with(text:, content: true, edit: true)
|
|
86
83
|
|
|
87
84
|
result = described_class.new.execute(tool_call, chat:)
|
|
88
85
|
|
|
@@ -91,23 +88,24 @@ describe OllamaChat::Tools::CopyToClipboard do
|
|
|
91
88
|
json = json_object(result)
|
|
92
89
|
expect(json.error).to be_nil
|
|
93
90
|
expect(json.success).to be true
|
|
94
|
-
expect(json.message).to eq 'The
|
|
91
|
+
expect(json.message).to eq 'The provided text has been successfully copied to the system clipboard.'
|
|
95
92
|
end
|
|
96
93
|
|
|
97
94
|
it 'can handle execution errors gracefully' do
|
|
95
|
+
text = 'Error triggering text'
|
|
98
96
|
tool_call = double(
|
|
99
97
|
'ToolCall',
|
|
100
98
|
function: double(
|
|
101
99
|
name: 'copy_to_clipboard',
|
|
102
100
|
arguments: double(
|
|
103
|
-
text:
|
|
101
|
+
text: ,
|
|
104
102
|
edit: nil
|
|
105
103
|
)
|
|
106
104
|
)
|
|
107
105
|
)
|
|
108
106
|
|
|
109
107
|
# Test that perform_copy_to_clipboard raises an error
|
|
110
|
-
expect(chat).to receive(:perform_copy_to_clipboard).with(text
|
|
108
|
+
expect(chat).to receive(:perform_copy_to_clipboard).with(text:, content: true, edit: false).
|
|
111
109
|
and_raise(OllamaChat::OllamaChatError, 'No response available to copy to the system clipboard.')
|
|
112
110
|
|
|
113
111
|
result = described_class.new.execute(tool_call, chat:)
|
|
@@ -120,19 +118,20 @@ describe OllamaChat::Tools::CopyToClipboard do
|
|
|
120
118
|
end
|
|
121
119
|
|
|
122
120
|
it 'can handle execution exceptions gracefully' do
|
|
121
|
+
text = 'Exception triggering text'
|
|
123
122
|
tool_call = double(
|
|
124
123
|
'ToolCall',
|
|
125
124
|
function: double(
|
|
126
125
|
name: 'copy_to_clipboard',
|
|
127
126
|
arguments: double(
|
|
128
|
-
text:
|
|
127
|
+
text: ,
|
|
129
128
|
edit: nil
|
|
130
129
|
)
|
|
131
130
|
)
|
|
132
131
|
)
|
|
133
132
|
|
|
134
133
|
# Test that perform_copy_to_clipboard raises an exception
|
|
135
|
-
expect(chat).to receive(:perform_copy_to_clipboard).with(text
|
|
134
|
+
expect(chat).to receive(:perform_copy_to_clipboard).with(text:, content: true, edit: false).
|
|
136
135
|
and_raise(RuntimeError, 'some kind of exception')
|
|
137
136
|
|
|
138
137
|
result = described_class.new.execute(tool_call, chat:)
|
|
@@ -104,7 +104,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
it 'handles the "ignoring" policy' do
|
|
107
|
-
args = double(url
|
|
107
|
+
args = double(url:, document_policy: 'ignoring')
|
|
108
108
|
tool_call = double(function: double(arguments: args))
|
|
109
109
|
|
|
110
110
|
result = described_class.new.execute(tool_call, chat:)
|
|
@@ -113,7 +113,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
113
113
|
end
|
|
114
114
|
|
|
115
115
|
it 'handles the "importing" policy' do
|
|
116
|
-
args = double(url
|
|
116
|
+
args = double(url:, document_policy: 'importing')
|
|
117
117
|
tool_call = double(function: double(arguments: args))
|
|
118
118
|
expect(chat).to receive(:import_source).with(source_io, URI.parse(url)).and_return('imported content')
|
|
119
119
|
|
|
@@ -123,7 +123,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
it 'handles the "embedding" policy' do
|
|
126
|
-
args = double(url
|
|
126
|
+
args = double(url:, document_policy: 'embedding')
|
|
127
127
|
tool_call = double(function: double(arguments: args))
|
|
128
128
|
expect(chat).to receive(:embed_source).with(source_io, URI.parse(url)).and_return('embedded content')
|
|
129
129
|
|
|
@@ -133,7 +133,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
it 'handles the "summarizing" policy' do
|
|
136
|
-
args = double(url
|
|
136
|
+
args = double(url:, document_policy: 'summarizing')
|
|
137
137
|
tool_call = double(function: double(arguments: args))
|
|
138
138
|
expect(chat).to receive(:summarize_source).with(source_io, URI.parse(url)).and_return('summarized content')
|
|
139
139
|
|
|
@@ -143,7 +143,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
it 'handles an invalid policy' do
|
|
146
|
-
args = double(url
|
|
146
|
+
args = double(url:, document_policy: 'chaos_mode')
|
|
147
147
|
tool_call = double(function: double(arguments: args))
|
|
148
148
|
|
|
149
149
|
result = described_class.new.execute(tool_call, chat:)
|
|
@@ -160,7 +160,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
160
160
|
allow(chat).to receive(:fetch_source).and_yield(source_io)
|
|
161
161
|
expect(chat).to receive(:add_image).with(chat.images, source_io, URI.parse(url))
|
|
162
162
|
|
|
163
|
-
args = double(url
|
|
163
|
+
args = double(url:, document_policy: 'ignoring')
|
|
164
164
|
tool_call = double(function: double(arguments: args))
|
|
165
165
|
|
|
166
166
|
result = described_class.new.execute(tool_call, chat:)
|
|
@@ -172,7 +172,7 @@ describe OllamaChat::Tools::GetURL do
|
|
|
172
172
|
source_io = double('SourceIO', content_type: double(media_type: 'video'))
|
|
173
173
|
allow(chat).to receive(:fetch_source).and_yield(source_io)
|
|
174
174
|
|
|
175
|
-
args = double(url
|
|
175
|
+
args = double(url:, document_policy: 'ignoring')
|
|
176
176
|
tool_call = double(function: double(arguments: args))
|
|
177
177
|
|
|
178
178
|
result = described_class.new.execute(tool_call, chat:)
|