Skip to content

Commit 0cbc77f

Browse files
authored
Merge pull request #273 from awaescher/feature/improve-thinking
Improve thinking support on Chats
2 parents a5553d2 + 1794223 commit 0cbc77f

File tree

6 files changed

+58
-6
lines changed

6 files changed

+58
-6
lines changed

demo/Demos/ChatConsole.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public override async Task Run()
2323
AnsiConsole.MarkupLine($"You are talking to [{AccentTextColor}]{Ollama.SelectedModel}[/] now.");
2424
WriteChatInstructionHint();
2525

26-
var chat = new Chat(Ollama, systemPrompt);
26+
var chat = new Chat(Ollama, systemPrompt) { Think = Think };
27+
chat.OnThink = (thoughts) => AnsiConsole.MarkupInterpolated($"[{AiThinkTextColor}]{thoughts}[/]");
2728

2829
string message;
2930

@@ -38,6 +39,14 @@ public override async Task Run()
3839
break;
3940
}
4041

42+
if (message.Equals(TOGGLETHINK_COMMAND, StringComparison.OrdinalIgnoreCase))
43+
{
44+
ToggleThink();
45+
keepChatting = true;
46+
chat.Think = Think;
47+
continue;
48+
}
49+
4150
if (message.Equals(START_NEW_COMMAND, StringComparison.OrdinalIgnoreCase))
4251
{
4352
keepChatting = true;

demo/Demos/ImageChatConsole.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public override async Task Run()
2525
AnsiConsole.MarkupLine($"[{HintTextColor}]To send an image, simply enter its full filename like \"[{AccentTextColor}]c:/image.jpg[/]\"[/]");
2626
WriteChatInstructionHint();
2727

28-
var chat = new Chat(Ollama, systemPrompt);
28+
var chat = new Chat(Ollama, systemPrompt) { Think = Think };
29+
chat.OnThink = (thoughts) => AnsiConsole.MarkupInterpolated($"[{AiThinkTextColor}]{thoughts}[/]");
2930

3031
string message;
3132

@@ -40,6 +41,14 @@ public override async Task Run()
4041
break;
4142
}
4243

44+
if (message.Equals(TOGGLETHINK_COMMAND, StringComparison.OrdinalIgnoreCase))
45+
{
46+
ToggleThink();
47+
keepChatting = true;
48+
chat.Think = Think;
49+
continue;
50+
}
51+
4352
if (message.Equals(START_NEW_COMMAND, StringComparison.OrdinalIgnoreCase))
4453
{
4554
keepChatting = true;

demo/Demos/ToolConsole.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ public override async Task Run()
3838
}
3939
AnsiConsole.MarkupLine($"[{HintTextColor}]Enter [{AccentTextColor}]{LIST_TOOLS_COMMAND}[/] to list all available tools.[/]");
4040

41-
var chat = new Chat(Ollama, systemPrompt);
41+
var chat = new Chat(Ollama, systemPrompt) { Think = Think };
42+
chat.OnThink = (thoughts) => AnsiConsole.MarkupInterpolated($"[{AiThinkTextColor}]{thoughts}[/]");
4243

4344
string message;
4445

@@ -53,6 +54,14 @@ public override async Task Run()
5354
break;
5455
}
5556

57+
if (message.Equals(TOGGLETHINK_COMMAND, StringComparison.OrdinalIgnoreCase))
58+
{
59+
ToggleThink();
60+
keepChatting = true;
61+
chat.Think = Think;
62+
continue;
63+
}
64+
5665
if (message.Equals(START_NEW_COMMAND, StringComparison.OrdinalIgnoreCase))
5766
{
5867
keepChatting = true;

demo/OllamaConsole.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@ public abstract class OllamaConsole(IOllamaApiClient ollama)
1919
public static string ErrorTextColor { get; } = "red";
2020

2121
public static string AiTextColor { get; } = "cyan";
22+
public static string AiThinkTextColor { get; } = "magenta";
2223

2324
public static string START_NEW_COMMAND { get; } = "/new";
2425
public static string USE_MCP_SERVER_COMMAND { get; } = "/mcp";
2526
public static string LIST_TOOLS_COMMAND { get; } = "/tools";
2627

2728
public static string EXIT_COMMAND { get; } = "/exit";
2829

30+
public static string TOGGLETHINK_COMMAND { get; } = "/togglethink";
31+
2932
public IOllamaApiClient Ollama { get; } = ollama ?? throw new ArgumentNullException(nameof(ollama));
3033

34+
public bool? Think { get; private set; }
35+
3136
public abstract Task Run();
3237

3338
public static string ReadInput(string prompt = "", string additionalInformation = "")
@@ -69,6 +74,14 @@ protected void WriteChatInstructionHint()
6974
{
7075
AnsiConsole.MarkupLine($"[{HintTextColor}]Enter [{AccentTextColor}]{START_NEW_COMMAND}[/] to start over or [{AccentTextColor}]{EXIT_COMMAND}[/] to leave.[/]");
7176
AnsiConsole.MarkupLine($"[{HintTextColor}]Begin with [{AccentTextColor}]{Markup.Escape(MULTILINE_OPEN.ToString())}[/] to start multiline input. Sumbmit it by ending with [{AccentTextColor}]{Markup.Escape(MULTILINE_CLOSE.ToString())}[/].[/]");
77+
AnsiConsole.MarkupLine($"[{HintTextColor}]Think mode is [{AccentTextColor}]{Think?.ToString().ToLower() ?? "(null)"}[/]. Type [{AccentTextColor}]{TOGGLETHINK_COMMAND}[/] to change.[/]");
78+
}
79+
80+
internal void ToggleThink()
81+
{
82+
// null -> false -> true -> null -> ...
83+
Think = Think == null ? false : (Think == false ? true : (Think == true ? null : false));
84+
AnsiConsole.MarkupLine($"[{HintTextColor}]Think mode is [{AccentTextColor}]{Think?.ToString().ToLower() ?? "(null)"}[/].[/]");
7285
}
7386

7487
protected async Task<string> SelectModel(string prompt, string additionalInformation = "")

src/OllamaSharp/Chat.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ public class Chat
6969
/// </summary>
7070
public bool? Think { get; set; }
7171

72+
73+
/// <summary>
74+
/// Gets or sets an action that is called when the AI model is thinking and Think is set to true.
75+
/// </summary>
76+
public Action<string>? OnThink { get; set; }
77+
7278
/// <summary>
7379
/// Initializes a new instance of the <see cref="Chat"/> class.
7480
/// This basic constructor sets up the chat without a predefined system prompt.
@@ -424,7 +430,12 @@ public async IAsyncEnumerable<string> SendAsAsync(ChatRole role, string message,
424430

425431
messageBuilder.Append(answer);
426432

427-
yield return answer.Message.Content ?? string.Empty;
433+
// yield the message content or call the delegate to handle thinking
434+
var isThinking = Think == true && !string.IsNullOrEmpty(answer.Message.Thinking);
435+
if (isThinking)
436+
OnThink?.Invoke(answer.Message.Thinking!);
437+
else
438+
yield return answer.Message.Content ?? string.Empty;
428439
}
429440

430441
if (messageBuilder.HasValue)

src/OllamaSharp/Models/Chat/MessageBuilder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace OllamaSharp.Models.Chat;
88
public class MessageBuilder
99
{
1010
private readonly StringBuilder _contentBuilder = new();
11+
private readonly StringBuilder _thinkContentBuilder = new();
1112
private List<string> _images = [];
1213
private List<Message.ToolCall> _toolCalls = [];
1314

@@ -44,6 +45,7 @@ public void Append(ChatResponseStream? chunk)
4445
return;
4546

4647
_contentBuilder.Append(chunk.Message.Content ?? "");
48+
_thinkContentBuilder.Append(chunk.Message.Thinking ?? "");
4749
Role = chunk.Message.Role;
4850

4951
_images.AddRangeIfNotNull(chunk.Message.Images);
@@ -81,8 +83,7 @@ public void Append(ChatResponseStream? chunk)
8183
/// Console.WriteLine(finalMessage.Role); // Output: Assistant
8284
/// </code>
8385
/// </example>
84-
public Message ToMessage() =>
85-
new() { Content = _contentBuilder.ToString(), Images = _images.ToArray(), Role = Role, ToolCalls = _toolCalls };
86+
public Message ToMessage() => new() { Content = _contentBuilder.ToString(), Thinking = _thinkContentBuilder.ToString(), Images = _images.ToArray(), Role = Role, ToolCalls = _toolCalls };
8687

8788

8889
/// <summary>

0 commit comments

Comments
 (0)