'use strict';

var chunkRUKCZLXN_cjs = require('./chunk-RUKCZLXN.cjs');
var chunk64ITUOXI_cjs = require('./chunk-64ITUOXI.cjs');

// src/server/handlers/responses.storage.ts
function isPlainObject(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
async function getAgentMemoryStore({
  agent,
  requestContext
}) {
  const memory = await agent.getMemory({ requestContext });
  if (!memory) {
    return null;
  }
  try {
    return await memory.storage.getStore("memory") ?? null;
  } catch {
    return null;
  }
}
function readResponseTurnRecordMetadata(message) {
  const mastraMetadata = isPlainObject(message.content?.metadata?.mastra) ? message.content.metadata.mastra : null;
  const responseMetadata = mastraMetadata && isPlainObject(mastraMetadata.response) ? mastraMetadata.response : null;
  if (!responseMetadata || typeof responseMetadata.agentId !== "string" || typeof responseMetadata.model !== "string" || typeof responseMetadata.createdAt !== "number" || responseMetadata.completedAt !== null && typeof responseMetadata.completedAt !== "number" || responseMetadata.instructions !== void 0 && typeof responseMetadata.instructions !== "string" || responseMetadata.text !== void 0 && (!isPlainObject(responseMetadata.text) || !isPlainObject(responseMetadata.text.format)) || responseMetadata.previousResponseId !== void 0 && typeof responseMetadata.previousResponseId !== "string" || !Array.isArray(responseMetadata.tools) || typeof responseMetadata.store !== "boolean" || !Array.isArray(responseMetadata.messageIds) || responseMetadata.outputItems !== void 0 && !Array.isArray(responseMetadata.outputItems)) {
    return null;
  }
  return {
    agentId: responseMetadata.agentId,
    model: responseMetadata.model,
    createdAt: responseMetadata.createdAt,
    completedAt: responseMetadata.completedAt,
    status: responseMetadata.status === "completed" ? "completed" : "incomplete",
    usage: responseMetadata.usage,
    instructions: responseMetadata.instructions,
    text: responseMetadata.text,
    previousResponseId: responseMetadata.previousResponseId,
    providerOptions: responseMetadata.providerOptions,
    tools: responseMetadata.tools,
    store: responseMetadata.store,
    messageIds: responseMetadata.messageIds.filter((value) => typeof value === "string"),
    outputItems: responseMetadata.outputItems
  };
}
function writeResponseTurnRecordMetadata(message, metadata) {
  const contentMetadata = isPlainObject(message.content?.metadata) ? message.content.metadata : {};
  const mastraMetadata = isPlainObject(contentMetadata.mastra) ? contentMetadata.mastra : {};
  return {
    ...message,
    content: {
      ...message.content,
      metadata: {
        ...contentMetadata,
        mastra: {
          ...mastraMetadata,
          response: metadata
        }
      }
    }
  };
}
async function findResponseTurnRecord({
  agent,
  responseId,
  requestContext
}) {
  const memoryStore = await getAgentMemoryStore({ agent, requestContext });
  if (!memoryStore) {
    return null;
  }
  const effectiveResourceId = chunkRUKCZLXN_cjs.getEffectiveResourceId(requestContext, void 0);
  const { messages: matchedMessages } = await memoryStore.listMessagesById({ messageIds: [responseId] });
  const message = matchedMessages[0];
  if (!message || message.role !== "assistant") {
    return null;
  }
  const metadata = readResponseTurnRecordMetadata(message);
  if (!metadata || metadata.agentId !== agent.id) {
    return null;
  }
  const thread = message.threadId ? await memoryStore.getThreadById({ threadId: message.threadId }) : null;
  if (!thread) {
    return null;
  }
  await chunkRUKCZLXN_cjs.validateThreadOwnership(thread, effectiveResourceId);
  const messageIds = metadata.messageIds.length > 0 ? metadata.messageIds : [message.id];
  const { messages: responseMessages } = await memoryStore.listMessagesById({ messageIds });
  const messagesById = new Map(responseMessages.map((storedMessage) => [storedMessage.id, storedMessage]));
  const orderedMessages = messageIds.map((messageId) => messagesById.get(messageId)).filter((storedMessage) => Boolean(storedMessage));
  return { metadata, message, messages: orderedMessages, thread, memoryStore };
}
async function findResponseTurnRecordAcrossAgents({
  mastra,
  responseId,
  requestContext
}) {
  if (!mastra) {
    return null;
  }
  const agents = Object.values(mastra.listAgents());
  for (const agent of agents) {
    const match = await findResponseTurnRecord({ agent, responseId, requestContext });
    if (match) {
      return match;
    }
  }
  return null;
}
async function findConversationThreadAcrossAgents({
  mastra,
  conversationId,
  requestContext
}) {
  if (!mastra) {
    return null;
  }
  const effectiveResourceId = chunkRUKCZLXN_cjs.getEffectiveResourceId(requestContext, void 0);
  const agents = Object.values(mastra.listAgents());
  for (const agent of agents) {
    const memoryStore = await getAgentMemoryStore({ agent, requestContext });
    if (!memoryStore) {
      continue;
    }
    const thread = await memoryStore.getThreadById({ threadId: conversationId });
    if (!thread) {
      continue;
    }
    await chunkRUKCZLXN_cjs.validateThreadOwnership(thread, effectiveResourceId);
    return { thread, memoryStore };
  }
  return null;
}
function createSyntheticResponseMessage({
  createdAt,
  responseId,
  text,
  threadContext
}) {
  return {
    id: responseId,
    role: "assistant",
    type: "text",
    createdAt: createdAt ?? /* @__PURE__ */ new Date(),
    threadId: threadContext.threadId,
    resourceId: threadContext.resourceId,
    content: {
      format: 2,
      parts: text ? [{ type: "text", text }] : []
    }
  };
}
function hasTextPart(message) {
  return Boolean(
    message.content?.parts?.some(
      (part) => isPlainObject(part) && part.type === "text" && typeof part.text === "string" && part.text.length > 0
    )
  );
}
function isEmptyAssistantMessage(message) {
  return message.role === "assistant" && Array.isArray(message.content?.parts) && message.content.parts.length === 0;
}
function hasToolInvocationPart(message) {
  return Boolean(
    message.content?.parts?.some(
      (part) => isPlainObject(part) && part.type === "tool-invocation" && isPlainObject(part.toolInvocation)
    )
  );
}
function getMessageText(message) {
  return message.content?.parts?.flatMap(
    (part) => isPlainObject(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
  ).join("") ?? "";
}
function getOutputMessageText(item) {
  return item.content.map((part) => part.text).join("");
}
function normalizeFallbackComparisonText(text) {
  return text.trim();
}
function matchesFallbackText(messageText, fallbackText) {
  return messageText === fallbackText || normalizeFallbackComparisonText(messageText) === normalizeFallbackComparisonText(fallbackText);
}
function hasMatchingAssistantText(messages, item) {
  const fallbackText = getOutputMessageText(item);
  return messages.some(
    (message) => message.role === "assistant" && hasTextPart(message) && matchesFallbackText(getMessageText(message), fallbackText)
  );
}
function shouldReplaceAssistantText(messageText, fallbackText) {
  const normalizedMessageText = normalizeFallbackComparisonText(messageText);
  const normalizedFallbackText = normalizeFallbackComparisonText(fallbackText);
  return normalizedFallbackText !== normalizedMessageText && (fallbackText.startsWith(messageText) || normalizedFallbackText.startsWith(normalizedMessageText));
}
function getAssistantMessageTexts(messages) {
  return messages.flatMap(
    (message) => message.role === "assistant" && hasTextPart(message) ? [getMessageText(message)] : []
  );
}
function shouldAddFallbackMessageText(messages, item) {
  const assistantTexts = getAssistantMessageTexts(messages);
  if (assistantTexts.length === 0) {
    return true;
  }
  const fallbackText = getOutputMessageText(item);
  return assistantTexts.every((messageText) => shouldReplaceAssistantText(messageText, fallbackText));
}
function shouldReplaceAssistantTextWithFallback({
  fallbackMessageTexts,
  message,
  textOnlyFallbackMessageTexts
}) {
  if (message.role !== "assistant" || !hasTextPart(message)) {
    return false;
  }
  const messageText = getMessageText(message);
  if (!messageText) {
    return false;
  }
  const comparisonTexts = hasToolInvocationPart(message) ? fallbackMessageTexts : textOnlyFallbackMessageTexts;
  return [...comparisonTexts].some((fallbackText) => shouldReplaceAssistantText(messageText, fallbackText));
}
function replaceAssistantTextWithFallback({
  fallbackMessageTexts,
  message,
  textOnlyFallbackMessageTexts
}) {
  if (!shouldReplaceAssistantTextWithFallback({ fallbackMessageTexts, message, textOnlyFallbackMessageTexts })) {
    return message;
  }
  const parts = message.content?.parts ?? [];
  const remainingParts = parts.filter((part) => !(isPlainObject(part) && part.type === "text"));
  return {
    ...message,
    content: {
      ...message.content,
      parts: remainingParts
    }
  };
}
function parseFunctionCallArguments(value) {
  try {
    return JSON.parse(value);
  } catch {
    return { __raw: value };
  }
}
function createSyntheticToolResultMessage({
  baseMessage,
  item,
  responseId,
  toolCall
}) {
  return {
    ...baseMessage,
    id: `${responseId}:tool-result:${item.call_id}`,
    role: "tool",
    type: "tool-result",
    content: {
      format: 2,
      parts: [
        {
          type: "tool-invocation",
          toolInvocation: {
            state: "result",
            toolCallId: item.call_id,
            toolName: toolCall?.toolName ?? "unknown",
            args: toolCall?.args ?? {},
            result: item.output
          }
        }
      ]
    }
  };
}
function toMastraDBMessage(message) {
  return message;
}
function createSyntheticMessagesFromOutputItems({
  contextOutputItems,
  outputItems,
  responseId,
  threadContext
}) {
  const toolContextItems = contextOutputItems ?? outputItems;
  const toolCallsById = new Map(
    toolContextItems.flatMap(
      (item) => item.type === "function_call" ? [[item.call_id, { args: parseFunctionCallArguments(item.arguments), toolName: item.name }]] : []
    )
  );
  const baseCreatedAt = Date.now();
  return outputItems.map((item, index) => {
    const baseMessage = {
      createdAt: new Date(baseCreatedAt + index),
      threadId: threadContext.threadId,
      resourceId: threadContext.resourceId
    };
    if (item.type === "function_call") {
      return {
        ...baseMessage,
        id: `${responseId}:tool-call:${item.call_id}`,
        role: "assistant",
        type: "tool-call",
        content: {
          format: 2,
          parts: [
            {
              type: "tool-invocation",
              toolInvocation: {
                state: "call",
                toolCallId: item.call_id,
                toolName: item.name,
                args: parseFunctionCallArguments(item.arguments)
              }
            }
          ]
        }
      };
    }
    if (item.type === "function_call_output") {
      const toolCall = toolCallsById.get(item.call_id);
      return toMastraDBMessage(createSyntheticToolResultMessage({ baseMessage, item, responseId, toolCall }));
    }
    return {
      ...baseMessage,
      id: item.id,
      role: "assistant",
      type: "text",
      content: {
        format: 2,
        parts: item.content.map((part) => ({ type: "text", text: part.text }))
      }
    };
  });
}
function getToolInvocationParts(message) {
  const parts = Array.isArray(message.content?.parts) ? message.content.parts : [];
  return parts.flatMap(
    (part) => isPlainObject(part) && part.type === "tool-invocation" && isPlainObject(part.toolInvocation) ? [part.toolInvocation] : []
  );
}
function getMissingFallbackOutputItems({
  fallbackOutputItems = [],
  messages
}) {
  if (!fallbackOutputItems.length) {
    return [];
  }
  const existingCallIds = /* @__PURE__ */ new Set();
  const existingResultCallIds = /* @__PURE__ */ new Set();
  for (const message of messages) {
    for (const toolInvocation of getToolInvocationParts(message)) {
      const toolCallId = typeof toolInvocation.toolCallId === "string" ? toolInvocation.toolCallId : null;
      if (!toolCallId) {
        continue;
      }
      if (message.role === "assistant" && (toolInvocation.args !== void 0 || toolInvocation.result === void 0)) {
        existingCallIds.add(toolCallId);
      }
      if (toolInvocation.result !== void 0) {
        existingResultCallIds.add(toolCallId);
      }
    }
  }
  return fallbackOutputItems.filter((item) => {
    if (item.type === "function_call") {
      return !existingCallIds.has(item.call_id);
    }
    if (item.type === "function_call_output") {
      return !existingResultCallIds.has(item.call_id);
    }
    if (item.type === "message") {
      if (!item.content.some((part) => part.text.length > 0) || hasMatchingAssistantText(messages, item)) {
        return false;
      }
      return shouldAddFallbackMessageText(messages, item);
    }
    return false;
  });
}
function getFallbackOutputIdForMessage(message, responseId, fallbackOutputIds) {
  for (const toolInvocation of getToolInvocationParts(message)) {
    const toolCallId = typeof toolInvocation.toolCallId === "string" ? toolInvocation.toolCallId : null;
    if (!toolCallId) {
      continue;
    }
    if (message.role === "assistant" && toolInvocation.args !== void 0) {
      return toolCallId;
    }
    if (toolInvocation.result !== void 0) {
      return `${toolCallId}:output`;
    }
  }
  if (message.role === "assistant" && hasTextPart(message)) {
    return fallbackOutputIds.has(message.id) ? message.id : responseId;
  }
  return null;
}
function sortMessagesByFallbackOutputOrder({
  fallbackOutputItems = [],
  messages,
  responseId
}) {
  if (!fallbackOutputItems.length) {
    return messages;
  }
  const outputOrder = new Map(fallbackOutputItems.map((item, index) => [item.id, index]));
  const fallbackOutputIds = new Set(outputOrder.keys());
  return messages.map((message, index) => ({
    index,
    message,
    outputIndex: outputOrder.get(getFallbackOutputIdForMessage(message, responseId, fallbackOutputIds) ?? "") ?? Number.MAX_SAFE_INTEGER
  })).sort((left, right) => left.outputIndex - right.outputIndex || left.index - right.index).map(({ message }) => message);
}
async function resolveResponseTurnMessagesForStorage({
  result,
  responseId,
  text,
  threadContext,
  fallbackOutputItems
}) {
  const response = await result.response;
  const responseMessages = response?.dbMessages?.length ? response.dbMessages : [];
  if (!threadContext) {
    return responseMessages;
  }
  if (responseMessages.length === 0) {
    if (fallbackOutputItems?.length) {
      const syntheticMessages = createSyntheticMessagesFromOutputItems({
        outputItems: fallbackOutputItems,
        responseId,
        threadContext
      });
      return text && !syntheticMessages.some((message) => message.role === "assistant" && hasTextPart(message)) ? [
        ...syntheticMessages,
        createSyntheticResponseMessage({
          createdAt: new Date(new Date(syntheticMessages.at(-1)?.createdAt ?? Date.now()).getTime() + 1),
          responseId,
          text,
          threadContext
        })
      ] : syntheticMessages;
    }
    return [createSyntheticResponseMessage({ responseId, text, threadContext })];
  }
  const missingFallbackItems = getMissingFallbackOutputItems({ fallbackOutputItems, messages: responseMessages });
  const missingFallbackMessageIds = new Set(
    missingFallbackItems.filter((item) => item.type === "message").map((item) => item.id)
  );
  const fallbackItemsWithMatchingAssistantText = (fallbackOutputItems ?? []).filter(
    (item) => item.type === "message" && hasMatchingAssistantText(responseMessages, item)
  );
  const textOnlyFallbackMessageTexts = new Set(
    fallbackItemsWithMatchingAssistantText.map(getOutputMessageText).filter(Boolean)
  );
  const fallbackMessageTexts = new Set(
    (fallbackOutputItems ?? []).filter((item) => item.type === "message").filter((item) => missingFallbackMessageIds.has(item.id) || fallbackItemsWithMatchingAssistantText.includes(item)).map(getOutputMessageText).filter(Boolean)
  );
  const baseMessages = fallbackMessageTexts.size ? responseMessages.map(
    (message) => replaceAssistantTextWithFallback({ fallbackMessageTexts, message, textOnlyFallbackMessageTexts })
  ) : responseMessages;
  const syntheticFallbackMessages = createSyntheticMessagesFromOutputItems({
    contextOutputItems: fallbackOutputItems ?? [],
    outputItems: missingFallbackItems,
    responseId,
    threadContext
  });
  const resolvedMessages = sortMessagesByFallbackOutputOrder({
    fallbackOutputItems,
    messages: [...baseMessages, ...syntheticFallbackMessages],
    responseId
  });
  if (text && !resolvedMessages.some((message) => message.role === "assistant" && hasTextPart(message))) {
    return [...resolvedMessages, createSyntheticResponseMessage({ responseId, text, threadContext })];
  }
  return resolvedMessages;
}
async function persistResponseTurnRecord({
  memoryStore,
  responseId,
  metadata,
  threadContext,
  messages
}) {
  if (!memoryStore) {
    throw new chunk64ITUOXI_cjs.HTTPException(500, { message: "Memory storage was not available while storing the response" });
  }
  const normalizedMessages = messages.map((message) => ({
    ...message,
    threadId: message.threadId ?? threadContext.threadId,
    resourceId: message.resourceId ?? threadContext.resourceId
  }));
  const lastAssistantIndex = [...normalizedMessages].map((message) => message.role).lastIndexOf("assistant");
  const responseAnchorIndex = [...normalizedMessages].map((message, index) => ({ index, message })).reverse().find(({ message }) => message.role === "assistant" && hasTextPart(message))?.index ?? lastAssistantIndex;
  const lastAssistantMessage = responseAnchorIndex >= 0 ? {
    ...normalizedMessages[responseAnchorIndex],
    id: responseId
  } : {
    id: responseId,
    role: "assistant",
    type: "text",
    createdAt: new Date(metadata.completedAt ? metadata.completedAt * 1e3 : Date.now()),
    threadId: threadContext.threadId,
    resourceId: threadContext.resourceId,
    content: {
      format: 2,
      parts: []
    }
  };
  if (responseAnchorIndex >= 0) {
    normalizedMessages[responseAnchorIndex] = lastAssistantMessage;
  } else {
    normalizedMessages.push(lastAssistantMessage);
  }
  const storedMessageIndex = responseAnchorIndex >= 0 ? responseAnchorIndex : normalizedMessages.length - 1;
  const droppedSupersededMessageIds = normalizedMessages.flatMap(
    (message, index) => index !== storedMessageIndex && isEmptyAssistantMessage(message) && messages[index]?.id ? [messages[index].id] : []
  );
  const staleMessageIds = responseAnchorIndex >= 0 && messages[responseAnchorIndex]?.id && messages[responseAnchorIndex]?.id !== responseId ? [messages[responseAnchorIndex].id] : [];
  const messagesToSave = normalizedMessages.filter(
    (message, index) => index === storedMessageIndex || !isEmptyAssistantMessage(message)
  );
  const storedMessage = writeResponseTurnRecordMetadata(lastAssistantMessage, {
    ...metadata,
    messageIds: messagesToSave.map((message) => message.id)
  });
  if (responseAnchorIndex >= 0) {
    normalizedMessages[responseAnchorIndex] = storedMessage;
  } else {
    normalizedMessages[normalizedMessages.length - 1] = storedMessage;
  }
  const savedMessages = normalizedMessages.filter(
    (message, index) => index === storedMessageIndex || !isEmptyAssistantMessage(message)
  );
  await memoryStore.saveMessages({ messages: savedMessages });
  const deleteMessageIds = [.../* @__PURE__ */ new Set([...staleMessageIds, ...droppedSupersededMessageIds])];
  if (deleteMessageIds.length > 0) {
    await memoryStore.deleteMessages(deleteMessageIds);
  }
}
async function deleteResponseTurnRecord({
  responseTurnRecord
}) {
  const messageIds = responseTurnRecord.messages.length > 0 ? responseTurnRecord.messages.map((message) => message.id) : [responseTurnRecord.message.id];
  await responseTurnRecord.memoryStore.deleteMessages(messageIds);
}

exports.deleteResponseTurnRecord = deleteResponseTurnRecord;
exports.findConversationThreadAcrossAgents = findConversationThreadAcrossAgents;
exports.findResponseTurnRecord = findResponseTurnRecord;
exports.findResponseTurnRecordAcrossAgents = findResponseTurnRecordAcrossAgents;
exports.getAgentMemoryStore = getAgentMemoryStore;
exports.persistResponseTurnRecord = persistResponseTurnRecord;
exports.resolveResponseTurnMessagesForStorage = resolveResponseTurnMessagesForStorage;
//# sourceMappingURL=chunk-7ASFLZZ6.cjs.map
//# sourceMappingURL=chunk-7ASFLZZ6.cjs.map