1+ using Discord ;
2+ using Estranged . Automation . Events ;
3+ using Microsoft . Extensions . AI ;
4+ using Microsoft . Extensions . Logging ;
5+ using System ;
6+ using System . Collections . Generic ;
7+ using System . Linq ;
8+ using System . Threading ;
9+ using System . Threading . Tasks ;
10+
11+ namespace Estranged . Automation . Responders
12+ {
13+ internal sealed class LlmResponder ( ILogger < OllamaResponder > logger , IChatClientFactory chatFactory ) : IResponder
14+ {
15+ private readonly ILogger < OllamaResponder > _logger = logger ;
16+ private readonly IChatClientFactory _chatFactory = chatFactory ;
17+ private string _urn ;
18+ private string _systemPrompt ;
19+
20+ public async Task ProcessMessage ( IMessage originalMessage , CancellationToken token )
21+ {
22+ if ( originalMessage . Author . Id != 269883106792701952 )
23+ {
24+ return ;
25+ }
26+
27+ if ( originalMessage . Channel . IsPublicChannel ( ) )
28+ {
29+ return ;
30+ }
31+
32+ var messageHistory = await originalMessage . GetFullConversation ( token ) ;
33+ if ( messageHistory . Any ( x => x . Channel != originalMessage . Channel ) )
34+ {
35+ _logger . LogWarning ( "Some of the message history is from other channels" ) ;
36+ return ;
37+ }
38+
39+ var initialMessage = messageHistory . Last ( ) ;
40+
41+ const string listModelTrigger = "llmlist " ;
42+ if ( initialMessage . Content . StartsWith ( listModelTrigger , StringComparison . InvariantCultureIgnoreCase ) )
43+ {
44+ var availableModels = await _chatFactory . GetModels ( initialMessage . Content [ listModelTrigger . Length ..] . Trim ( ) , token ) ;
45+ await initialMessage . Channel . SendMessageAsync ( $ "Available models:\n - { string . Join ( "\n - " , availableModels ) } ", options : token . ToRequestOptions ( ) ) ;
46+ return ;
47+ }
48+
49+ const string modelTrigger = "llmconf " ;
50+ if ( initialMessage . Content . StartsWith ( modelTrigger , StringComparison . InvariantCultureIgnoreCase ) )
51+ {
52+ var options = initialMessage . Content [ modelTrigger . Length ..] . Trim ( ) . Split ( "|" ) ;
53+ _urn = options [ 0 ] ;
54+ _systemPrompt = options [ 1 ] ;
55+ await initialMessage . Channel . SendMessageAsync ( $ "Configured LLM with URN: { _urn } ", options : token . ToRequestOptions ( ) ) ;
56+ return ;
57+ }
58+
59+ const string llmTrigger = "llm " ;
60+ if ( initialMessage . Content . StartsWith ( llmTrigger , StringComparison . InvariantCultureIgnoreCase ) )
61+ {
62+ var chatClient = _chatFactory . CreateClient ( _urn ) ;
63+ var latestMessage = messageHistory . First ( ) ;
64+
65+ using ( latestMessage . Channel . EnterTypingState ( ) )
66+ {
67+ IList < ChatMessage > chatMessages = MessageExtensions . BuildChatMessages ( messageHistory , llmTrigger . Length , initialMessage , _systemPrompt . Replace ( "{CurrentDate}" , $ "The current date is { DateTime . Now : D} ") ) ;
68+ await chatClient . StreamResponse ( latestMessage , chatMessages , new ( ) { AdditionalProperties = new AdditionalPropertiesDictionary { { "Think" , false } } } , token ) ;
69+ }
70+ return ;
71+ }
72+ }
73+ }
74+ }
0 commit comments