22using Microsoft . Extensions . Options ;
33using Azure ;
44using Azure . AI . Agents . Persistent ;
5- using chatui . Models ;
65using chatui . Configuration ;
76
87namespace chatui . Controllers ;
@@ -19,41 +18,48 @@ public class ChatController(
1918 private readonly IOptionsMonitor < ChatApiOptions > _options = options ;
2019 private readonly ILogger < ChatController > _logger = logger ;
2120
22- [ HttpPost ]
23- public async Task < IActionResult > Completions ( [ FromBody ] string prompt )
21+ // TODO: [security] Do not trust client to provide threadId. Instead map current user to their active threadid in your application's own state store.
22+ // Without this security control in place, a user can inject messages into another user's thread.
23+ [ HttpPost ( "{threadId}" ) ]
24+ public async Task < IActionResult > Completions ( [ FromRoute ] string threadId , [ FromBody ] string prompt )
2425 {
2526 if ( string . IsNullOrWhiteSpace ( prompt ) )
2627 throw new ArgumentException ( "Prompt cannot be null, empty, or whitespace." , nameof ( prompt ) ) ;
2728
2829 _logger . LogDebug ( "Prompt received {Prompt}" , prompt ) ;
2930 var _config = _options . CurrentValue ;
3031
31- // TODO: Reuse chat context.
32- PersistentAgentThread thread = await _client . Threads . CreateThreadAsync ( ) ;
33-
3432 PersistentThreadMessage message = await _client . Messages . CreateMessageAsync (
35- thread . Id ,
33+ threadId ,
3634 MessageRole . User ,
3735 prompt ) ;
3836
39- ThreadRun run = await _client . Runs . CreateRunAsync ( thread . Id , _config . AIAgentId ) ;
37+ ThreadRun run = await _client . Runs . CreateRunAsync ( threadId , _config . AIAgentId ) ;
4038
4139 while ( run . Status == RunStatus . Queued || run . Status == RunStatus . InProgress || run . Status == RunStatus . RequiresAction )
4240 {
4341 await Task . Delay ( TimeSpan . FromMilliseconds ( 500 ) ) ;
44- run = ( await _client . Runs . GetRunAsync ( thread . Id , run . Id ) ) . Value ;
42+ run = ( await _client . Runs . GetRunAsync ( threadId , run . Id ) ) . Value ;
4543 }
4644
47- Pageable < PersistentThreadMessage > messages = _client . Messages . GetMessages (
48- threadId : thread . Id , order : ListSortOrder . Ascending ) ;
45+ Pageable < PersistentThreadMessage > messages = _client . Messages . GetMessages (
46+ threadId : threadId , order : ListSortOrder . Ascending ) ;
4947
50- var fullText = string . Concat (
48+ var fullText =
5149 messages
5250 . Where ( m => m . Role == MessageRole . Agent )
5351 . SelectMany ( m => m . ContentItems . OfType < MessageTextContent > ( ) )
54- . Select ( c => c . Text )
55- ) ;
52+ . Last ( ) . Text ;
53+
54+ return Ok ( new { data = fullText } ) ;
55+ }
56+
57+ [ HttpPost ]
58+ public async Task < IActionResult > Threads ( )
59+ {
60+ // TODO [performance efficiency] Delay creating a thread until the first user message arrives.
61+ PersistentAgentThread thread = await _client . Threads . CreateThreadAsync ( ) ;
5662
57- return Ok ( new HttpChatResponse ( true , fullText ) ) ;
63+ return Ok ( new { id = thread . Id } ) ;
5864 }
5965}
0 commit comments