chore: fix chat history

This commit is contained in:
Lluis Agusti
2025-12-16 19:11:21 +01:00
parent 7a57531063
commit ba003a5e18
2 changed files with 274 additions and 54 deletions

View File

@@ -3912,6 +3912,78 @@
}
}
},
"/api/store/admin/embeddings/stats": {
"get": {
"tags": ["v2", "admin", "store", "admin"],
"summary": "Get Embedding Statistics",
"description": "Get statistics about embedding coverage for store listings.\n\nReturns counts of total approved listings, listings with embeddings,\nlistings without embeddings, and coverage percentage.",
"operationId": "getV2Get embedding statistics",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": true,
"type": "object",
"title": "Response Getv2Get Embedding Statistics"
}
}
}
},
"401": {
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
}
},
"security": [{ "HTTPBearerJWT": [] }]
}
},
"/api/store/admin/embeddings/backfill": {
"post": {
"tags": ["v2", "admin", "store", "admin"],
"summary": "Backfill Missing Embeddings",
"description": "Trigger backfill of embeddings for approved listings that don't have them.\n\nArgs:\n batch_size: Number of embeddings to generate in one call (default 10)\n\nReturns:\n Dict with processed count, success count, failure count, and message",
"operationId": "postV2Backfill missing embeddings",
"security": [{ "HTTPBearerJWT": [] }],
"parameters": [
{
"name": "batch_size",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"default": 10,
"title": "Batch Size"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true,
"title": "Response Postv2Backfill Missing Embeddings"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
}
}
},
"401": {
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
}
}
}
},
"/api/credits/admin/add_credits": {
"post": {
"tags": ["v2", "admin", "credits", "admin"],
@@ -5443,6 +5515,112 @@
}
}
},
"/api/chat/onboarding/sessions": {
"post": {
"tags": ["v2", "chat", "chat"],
"summary": "Create Onboarding Session",
"description": "Create a new onboarding chat session.\n\nInitiates a new chat session specifically for user onboarding,\nusing a specialized prompt that guides users through their first\nexperience with AutoGPT.\n\nArgs:\n user_id: The optional authenticated user ID parsed from the JWT.\n\nReturns:\n CreateSessionResponse: Details of the created onboarding session.",
"operationId": "postV2CreateOnboardingSession",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateSessionResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
}
},
"security": [{ "HTTPBearerJWT": [] }]
}
},
"/api/chat/onboarding/sessions/{session_id}": {
"get": {
"tags": ["v2", "chat", "chat"],
"summary": "Get Onboarding Session",
"description": "Retrieve the details of an onboarding chat session.\n\nArgs:\n session_id: The unique identifier for the onboarding session.\n user_id: The optional authenticated user ID.\n\nReturns:\n SessionDetailResponse: Details for the requested session.",
"operationId": "getV2GetOnboardingSession",
"security": [{ "HTTPBearerJWT": [] }],
"parameters": [
{
"name": "session_id",
"in": "path",
"required": true,
"schema": { "type": "string", "title": "Session Id" }
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionDetailResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
}
}
},
"401": {
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
}
}
}
},
"/api/chat/onboarding/sessions/{session_id}/stream": {
"post": {
"tags": ["v2", "chat", "chat"],
"summary": "Stream Onboarding Chat",
"description": "Stream onboarding chat responses for a session.\n\nUses the specialized onboarding system prompt to guide new users\nthrough their first experience with AutoGPT. Streams AI responses\nin real time over Server-Sent Events (SSE).\n\nArgs:\n session_id: The onboarding session identifier.\n request: Request body containing message and optional context.\n user_id: Optional authenticated user ID.\n\nReturns:\n StreamingResponse: SSE-formatted response chunks.",
"operationId": "postV2StreamOnboardingChat",
"security": [{ "HTTPBearerJWT": [] }],
"parameters": [
{
"name": "session_id",
"in": "path",
"required": true,
"schema": { "type": "string", "title": "Session Id" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/StreamChatRequest" }
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": { "application/json": { "schema": {} } }
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
}
}
},
"401": {
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
}
}
}
},
"/api/chat/health": {
"get": {
"tags": ["v2", "chat", "chat"],

View File

@@ -32,70 +32,112 @@ export function useChatContainer({
const isStreaming = isStreamingInitiated || hasTextChunks;
const allMessages = useMemo(() => {
const processedInitialMessages = initialMessages
.filter((msg: Record<string, unknown>) => {
if (!isValidMessage(msg)) {
console.warn("Invalid message structure from backend:", msg);
return false;
const processedInitialMessages: ChatMessageData[] = [];
for (const msg of initialMessages) {
if (!isValidMessage(msg)) {
console.warn("Invalid message structure from backend:", msg);
continue;
}
let content = String(msg.content || "");
const role = String(msg.role || "assistant").toLowerCase();
const toolCalls = msg.tool_calls;
const timestamp = msg.timestamp
? new Date(msg.timestamp as string)
: undefined;
// Remove page context from user messages when loading existing sessions
if (role === "user") {
content = removePageContext(content);
// Skip user messages that become empty after removing page context
if (!content.trim()) {
continue;
}
const content = String(msg.content || "").trim();
const toolCalls = msg.tool_calls;
return (
content.length > 0 ||
(toolCalls && Array.isArray(toolCalls) && toolCalls.length > 0)
processedInitialMessages.push({
type: "message",
role: "user",
content,
timestamp,
});
continue;
}
// Handle tool messages
if (role === "tool") {
const toolResponse = parseToolResponse(
content,
(msg.tool_call_id as string) || "",
"unknown",
timestamp,
);
})
.map((msg: Record<string, unknown>) => {
let content = String(msg.content || "");
const role = String(msg.role || "assistant").toLowerCase();
const toolCalls = msg.tool_calls;
if (toolResponse) {
processedInitialMessages.push(toolResponse);
}
continue;
}
// Remove page context from user messages when loading existing sessions
if (role === "user") {
content = removePageContext(content);
// Skip user messages that become empty after removing page context
if (!content.trim()) {
return null;
// Handle assistant messages
if (role === "assistant") {
// Strip <thinking> tags from content
content = content
.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "")
.trim();
// If assistant has tool calls, create tool_call messages for each
if (toolCalls && isToolCallArray(toolCalls) && toolCalls.length > 0) {
for (const toolCall of toolCalls) {
try {
const args = JSON.parse(toolCall.function.arguments || "{}");
processedInitialMessages.push({
type: "tool_call",
toolId: toolCall.id,
toolName: toolCall.function.name,
arguments: args,
timestamp,
});
} catch (err) {
console.warn("Failed to parse tool call arguments:", err);
processedInitialMessages.push({
type: "tool_call",
toolId: toolCall.id,
toolName: toolCall.function.name,
arguments: {},
timestamp,
});
}
}
}
if (
role === "assistant" &&
toolCalls &&
isToolCallArray(toolCalls) &&
toolCalls.length > 0
) {
return null;
}
if (role === "tool") {
const timestamp = msg.timestamp
? new Date(msg.timestamp as string)
: undefined;
const toolResponse = parseToolResponse(
// Only add assistant message if there's content after stripping thinking tags
if (content.trim()) {
processedInitialMessages.push({
type: "message",
role: "assistant",
content,
timestamp,
});
}
} else if (content.trim()) {
// Assistant message without tool calls, but with content
processedInitialMessages.push({
type: "message",
role: "assistant",
content,
(msg.tool_call_id as string) || "",
"unknown",
timestamp,
);
if (!toolResponse) {
return null;
}
return toolResponse;
});
}
// Skip assistant messages with empty content (they're handled by tool calls)
if (role === "assistant" && !content.trim()) {
return null;
}
return {
continue;
}
// Handle other message types (system, etc.)
if (content.trim()) {
processedInitialMessages.push({
type: "message",
role: role as "user" | "assistant" | "system",
content,
timestamp: msg.timestamp
? new Date(msg.timestamp as string)
: undefined,
};
})
.filter((msg): msg is ChatMessageData => msg !== null);
timestamp,
});
}
}
return [...processedInitialMessages, ...messages];
}, [initialMessages, messages]);