🐛 Fix some issues in AI agent

This commit is contained in:
2025-10-26 12:24:41 +08:00
parent 92cd6b5f7e
commit 4347281fcd
3 changed files with 54 additions and 16 deletions

View File

@@ -129,6 +129,30 @@ All endpoints require authentication through the current user session. Sequence
The POST endpoint returns a stream of assistant responses using Server-Sent Events format. Clients should handle the streaming response and display messages incrementally. The POST endpoint returns a stream of assistant responses using Server-Sent Events format. Clients should handle the streaming response and display messages incrementally.
### Streaming Message Format
The streaming response sends several types of JSON messages:
- **Text messages**: `{"type": "text", "data": "..." }`
- **Function calls**: `{"type": "function_call", "data": {...} }` (when AI uses tools)
- **Topic updates**: `{"type": "topic", "data": "..." }` (sent at end if topic was generated)
- **Thought completion**: `{"type": "thought", "data": {...} }` (sent at end with saved thought details)
All streaming chunks during generation use the SSE event format:
```
data: {"type": "...", "data": ...}
```
Final messages (topic and thought) use custom event types:
```
topic: {"type": "topic", "data": "..."}
thought: {"type": "thought", "data": {...}}
```
Clients should parse these JSON messages and handle different types appropriately, such as displaying text in real-time and processing tool calls.
## Implementation Notes ## Implementation Notes
- Built with ASP.NET Core and Semantic Kernel - Built with ASP.NET Core and Semantic Kernel

View File

@@ -58,7 +58,7 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
"When you talk to user, you can add some modal particles and emoticons to your response to be cute, but prevent use a lot of emojis." + "When you talk to user, you can add some modal particles and emoticons to your response to be cute, but prevent use a lot of emojis." +
"Your father (creator) is @littlesheep. (prefer calling him 父亲 in chinese)\n" + "Your father (creator) is @littlesheep. (prefer calling him 父亲 in chinese)\n" +
"\n" + "\n" +
"The ID on the Solar Network is UUID, so mostly hard to read, so do not show ID to user unless user ask to do so or necessary.\n"+ "The ID on the Solar Network is UUID, so mostly hard to read, so do not show ID to user unless user ask to do so or necessary.\n" +
"\n" + "\n" +
"Your aim is to helping solving questions for the users on the Solar Network.\n" + "Your aim is to helping solving questions for the users on the Solar Network.\n" +
"And the Solar Network is the social network platform you live on.\n" + "And the Solar Network is the social network platform you live on.\n" +
@@ -105,16 +105,29 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
kernel: kernel kernel: kernel
)) ))
{ {
// Write each chunk to the HTTP response as SSE // Process each item in the chunk for detailed streaming
var data = chunk.ToString(); foreach (var item in chunk.Items)
accumulatedContent.Append(data); {
if (string.IsNullOrEmpty(data)) continue; var messageJson = item switch
{
StreamingTextContent textContent =>
JsonSerializer.Serialize(new { type = "text", data = textContent.Text ?? "" }),
StreamingFunctionCallUpdateContent functionCall =>
JsonSerializer.Serialize(new { type = "function_call", data = functionCall }),
_ =>
JsonSerializer.Serialize(new { type = "unknown", data = item })
};
var bytes = Encoding.UTF8.GetBytes(data); // Write a structured JSON message to the HTTP response as SSE
await Response.Body.WriteAsync(bytes); var messageBytes = Encoding.UTF8.GetBytes($"data: {messageJson}\n\n");
await Response.Body.WriteAsync(messageBytes, 0, messageBytes.Length);
await Response.Body.FlushAsync(); await Response.Body.FlushAsync();
} }
// Accumulate content for saving (only text content)
accumulatedContent.Append(chunk.Content ?? "");
}
// Save assistant thought // Save assistant thought
var savedThought = var savedThought =
await service.SaveThoughtAsync(sequence, accumulatedContent.ToString(), ThinkingThoughtRole.Assistant); await service.SaveThoughtAsync(sequence, accumulatedContent.ToString(), ThinkingThoughtRole.Assistant);
@@ -122,15 +135,16 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
// Write the topic if it was newly set, then the thought object as JSON to the stream // Write the topic if it was newly set, then the thought object as JSON to the stream
using (var streamBuilder = new MemoryStream()) using (var streamBuilder = new MemoryStream())
{ {
await streamBuilder.WriteAsync("\n\ndata: "u8.ToArray()); await streamBuilder.WriteAsync("\n\n"u8.ToArray());
if (topic != null) if (topic != null)
{ {
var topicJson = JsonSerializer.Serialize(new { type = "topic", data = sequence.Topic ?? "" }); var topicJson = JsonSerializer.Serialize(new { type = "topic", data = sequence.Topic ?? "" });
await streamBuilder.WriteAsync(Encoding.UTF8.GetBytes($"{topicJson}\n\n")); await streamBuilder.WriteAsync(Encoding.UTF8.GetBytes($"topic: {topicJson}\n\n"));
} }
var thoughtJson = JsonSerializer.Serialize(new { type = "thought", data = savedThought }, GrpcTypeHelper.SerializerOptions); var thoughtJson = JsonSerializer.Serialize(new { type = "thought", data = savedThought },
await streamBuilder.WriteAsync(Encoding.UTF8.GetBytes($"data: {thoughtJson}\n\n")); GrpcTypeHelper.SerializerOptions);
await streamBuilder.WriteAsync(Encoding.UTF8.GetBytes($"thought: {thoughtJson}\n\n"));
var outputBytes = streamBuilder.ToArray(); var outputBytes = streamBuilder.ToArray();
await Response.Body.WriteAsync(outputBytes); await Response.Body.WriteAsync(outputBytes);
await Response.Body.FlushAsync(); await Response.Body.FlushAsync();

View File

@@ -98,7 +98,7 @@ public class ThoughtProvider
string? afterIso = null, string? afterIso = null,
string? beforeIso = null, string? beforeIso = null,
bool includeReplies = false, bool includeReplies = false,
int? pinned = null, string? pinned = null,
bool onlyMedia = false, bool onlyMedia = false,
bool shuffle = false bool shuffle = false
) => ) =>
@@ -112,7 +112,7 @@ public class ThoughtProvider
OrderBy = orderBy, OrderBy = orderBy,
Query = query, Query = query,
IncludeReplies = includeReplies, IncludeReplies = includeReplies,
Pinned = pinned.HasValue ? (PostPinMode)pinned : default, Pinned = !string.IsNullOrEmpty(pinned) && int.TryParse(pinned, out int p) ? (PostPinMode)p : default,
OnlyMedia = onlyMedia, OnlyMedia = onlyMedia,
Shuffle = shuffle Shuffle = shuffle
}; };