Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 702692cf0c | |||
| 51d1917a7b | |||
| 85f3400076 | |||
| a5cbe98f25 | |||
| 5b0e3a19f6 | |||
| e1d6b1eeb3 |
@@ -95,11 +95,11 @@ public class DashboardController(OpenClawGatewayClient gateway, ILogger<Dashboar
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sessionKey = string.IsNullOrWhiteSpace(request.SessionKey)
|
var agentId = string.IsNullOrWhiteSpace(request.AgentId)
|
||||||
? "iris"
|
? "iris"
|
||||||
: request.SessionKey.Trim();
|
: request.AgentId.Trim();
|
||||||
|
|
||||||
return await gateway.SendChatMessageAsync(sessionKey, request.Message.Trim());
|
return await gateway.SendChatMessageAsync(agentId, request.Message.Trim());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -119,7 +119,7 @@ public class DashboardController(OpenClawGatewayClient gateway, ILogger<Dashboar
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var key = string.IsNullOrWhiteSpace(sessionKey) ? "iris" : sessionKey.Trim();
|
var key = string.IsNullOrWhiteSpace(sessionKey) ? "agent:iris:main" : sessionKey.Trim();
|
||||||
var messages = await gateway.GetSessionHistoryAsync(key, Math.Clamp(limit, 1, 200), Math.Max(0, offset));
|
var messages = await gateway.GetSessionHistoryAsync(key, Math.Clamp(limit, 1, 200), Math.Max(0, offset));
|
||||||
|
|
||||||
// Filter: only user and assistant messages (exclude tool/system)
|
// Filter: only user and assistant messages (exclude tool/system)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public sealed record MessageEntry(
|
|||||||
|
|
||||||
public sealed record ChatRequest(
|
public sealed record ChatRequest(
|
||||||
string Message,
|
string Message,
|
||||||
string? SessionKey
|
string? AgentId
|
||||||
);
|
);
|
||||||
|
|
||||||
public sealed record ChatResponse(
|
public sealed record ChatResponse(
|
||||||
|
|||||||
@@ -145,24 +145,49 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await InvokeToolAsync("sessions_history", new { sessionKey, limit, offset });
|
var result = await InvokeToolAsync("sessions_history", new {
|
||||||
|
sessionKey, limit, offset,
|
||||||
|
includeTools = false
|
||||||
|
});
|
||||||
if (result is null) return new List<MessageEntry>();
|
if (result is null) return new List<MessageEntry>();
|
||||||
|
|
||||||
var messages = new List<MessageEntry>();
|
// sessions_history returns { details: { messages: [...] } }
|
||||||
var array = result as JsonArray ?? result.AsArray();
|
var messageArray = result["details"]?["messages"] as JsonArray;
|
||||||
if (array is null) return messages;
|
if (messageArray is null) return new List<MessageEntry>();
|
||||||
|
|
||||||
foreach (var msg in array)
|
var messages = new List<MessageEntry>();
|
||||||
|
foreach (var msg in messageArray.Cast<JsonNode?>())
|
||||||
{
|
{
|
||||||
if (msg is null) continue;
|
if (msg is null) continue;
|
||||||
var role = msg["role"]?.GetValue<string>() ?? "";
|
var role = msg["role"]?.GetValue<string>() ?? "";
|
||||||
var content = msg["content"]?.GetValue<string>() ?? "";
|
// Skip non-user/assistant roles
|
||||||
|
if (role is not ("user" or "assistant")) continue;
|
||||||
|
|
||||||
|
// Content is an array of blocks: [{type: "text"/"thinking", text: "..."}]
|
||||||
|
// Extract only pure text blocks, skip thinking-only messages
|
||||||
|
var contentBlocks = msg["content"] as JsonArray;
|
||||||
|
if (contentBlocks is null) continue;
|
||||||
|
|
||||||
|
var visibleTexts = new List<string>();
|
||||||
|
foreach (var block in contentBlocks.Cast<JsonNode?>())
|
||||||
|
{
|
||||||
|
if (block is null) continue;
|
||||||
|
var type = block["type"]?.GetValue<string>() ?? "";
|
||||||
|
var text = block["text"]?.GetValue<string>() ?? "";
|
||||||
|
if (type == "text" && !string.IsNullOrWhiteSpace(text))
|
||||||
|
visibleTexts.Add(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
var visibleContent = string.Join(" ", visibleTexts).Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(visibleContent)) continue;
|
||||||
|
|
||||||
|
// Skip system-only replies
|
||||||
|
if (visibleContent is "REPLY_SKIP" or "ANNOUNCE_SKIP") continue;
|
||||||
|
|
||||||
var timestamp = msg["timestamp"]?.GetValue<string>()
|
var timestamp = msg["timestamp"]?.GetValue<string>()
|
||||||
?? msg["ts"]?.GetValue<string>()
|
|
||||||
?? msg["createdAt"]?.GetValue<string>()
|
|
||||||
?? DateTimeOffset.UtcNow.ToString("o");
|
?? DateTimeOffset.UtcNow.ToString("o");
|
||||||
|
|
||||||
messages.Add(new MessageEntry(role, content, timestamp));
|
messages.Add(new MessageEntry(role, visibleContent, timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
return messages;
|
return messages;
|
||||||
@@ -173,18 +198,21 @@ public sealed class OpenClawGatewayClient(HttpClient httpClient, IConfiguration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ChatResponse> SendChatMessageAsync(string sessionKey, string message)
|
public async Task<ChatResponse> SendChatMessageAsync(string agentId, string message)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await InvokeToolAsync("sessions_send", new { sessionKey, message });
|
var result = await InvokeToolAsync("sessions_send", new { agentId, message });
|
||||||
if (result is null) return new ChatResponse(false, null, "Gateway nicht erreichbar");
|
if (result is null) return new ChatResponse(false, null, "Gateway nicht erreichbar");
|
||||||
|
|
||||||
var ok = result["ok"]?.GetValue<bool>() ?? false;
|
// sessions_send reply is in details.reply or content[0].text
|
||||||
var reply = result["reply"]?.GetValue<string>()
|
var details = result["details"];
|
||||||
|
var ok = (details?["status"]?.GetValue<string>() ?? result["status"]?.GetValue<string>()) == "ok";
|
||||||
|
var reply = details?["reply"]?.GetValue<string>()
|
||||||
|
?? result["reply"]?.GetValue<string>()
|
||||||
?? result["response"]?.GetValue<string>()
|
?? result["response"]?.GetValue<string>()
|
||||||
?? result["content"]?[0]?["text"]?.GetValue<string>();
|
?? result["content"]?[0]?["text"]?.GetValue<string>();
|
||||||
var error = result["error"]?.GetValue<string>();
|
var error = details?["error"]?.GetValue<string>() ?? result["error"]?.GetValue<string>();
|
||||||
|
|
||||||
return new ChatResponse(ok, reply, error);
|
return new ChatResponse(ok, reply, error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -280,12 +280,19 @@ async function fetchChatMessages(): Promise<void> {
|
|||||||
const res = await apiFetch('/api/dashboard/chat/messages?limit=50')
|
const res = await apiFetch('/api/dashboard/chat/messages?limit=50')
|
||||||
if (!res.ok) return
|
if (!res.ok) return
|
||||||
const data: DashboardChatMessage[] = await res.json()
|
const data: DashboardChatMessage[] = await res.json()
|
||||||
chatMessages.value = data.map((msg, idx) => ({
|
// Merge instead of replace — only add messages not already present
|
||||||
id: `msg-${idx}`,
|
const existingTexts = new Set(chatMessages.value.map(m => m.text))
|
||||||
sender: msg.role === 'assistant' ? 'iris' : 'user',
|
const existingTimestamps = new Set(chatMessages.value.map(m => m.timestamp))
|
||||||
text: msg.content,
|
for (const msg of data) {
|
||||||
timestamp: new Date(msg.timestamp).getTime(),
|
const msgTime = new Date(msg.timestamp).getTime()
|
||||||
}))
|
if (existingTexts.has(msg.content) && existingTimestamps.has(msgTime)) continue
|
||||||
|
chatMessages.value.push({
|
||||||
|
id: `msg-${msgTime}-${msg.role}`,
|
||||||
|
sender: msg.role === 'assistant' ? 'iris' : 'user',
|
||||||
|
text: msg.content,
|
||||||
|
timestamp: msgTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// API unreachable – keep current values
|
// API unreachable – keep current values
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user