{"version":3,"sources":["../../../src/runtimes/external-store/external-message-converter.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport { ThreadMessageConverter } from \"./ThreadMessageConverter\";\nimport {\n  getExternalStoreMessage,\n  symbolInnerMessage,\n} from \"./getExternalStoreMessage\";\nimport { fromThreadMessageLike, ThreadMessageLike } from \"./ThreadMessageLike\";\nimport { getAutoStatus, isAutoStatus } from \"./auto-status\";\nimport { ToolCallContentPart } from \"../../types\";\n\nexport namespace useExternalMessageConverter {\n  export type Message =\n    | ThreadMessageLike\n    | {\n        role: \"tool\";\n        toolCallId: string;\n        toolName?: string | undefined;\n        result: any;\n      };\n\n  export type Callback<T> = (message: T) => Message | Message[];\n}\n\ntype CallbackResult<T> = {\n  input: T;\n  outputs: useExternalMessageConverter.Message[];\n};\n\ntype ChunkResult<T> = {\n  inputs: T[];\n  outputs: useExternalMessageConverter.Message[];\n};\n\nconst joinExternalMessages = (\n  messages: useExternalMessageConverter.Message[],\n): ThreadMessageLike => {\n  const assistantMessage: ThreadMessageLike & { content: any[] } = {\n    role: \"assistant\",\n    content: [],\n  };\n  for (const output of messages) {\n    if (output.role === \"tool\") {\n      const toolCallIdx = assistantMessage.content.findIndex(\n        (c) => c.type === \"tool-call\" && c.toolCallId === output.toolCallId,\n      );\n      if (toolCallIdx !== -1) {\n        const toolCall = assistantMessage.content[\n          toolCallIdx\n        ]! as ToolCallContentPart;\n        if (output.toolName) {\n          if (toolCall.toolName !== output.toolName)\n            throw new Error(\n              `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}`,\n            );\n        }\n        assistantMessage.content[toolCallIdx] = {\n          ...toolCall,\n          result: output.result,\n        };\n      } else {\n        throw new Error(\n          `Tool call ${output.toolCallId} ${output.toolName} not found in assistant message`,\n        );\n      }\n    } else {\n      const role = output.role;\n      switch (role) {\n        case \"system\":\n        case \"user\":\n          return output;\n        case \"assistant\":\n          if (assistantMessage.content.length === 0) {\n            assistantMessage.id = output.id;\n            assistantMessage.createdAt ??= output.createdAt;\n            assistantMessage.status ??= output.status;\n            // TODO keep this in sync\n          }\n          assistantMessage.content.push(...output.content);\n          break;\n        default: {\n          const unsupportedRole: never = role;\n          throw new Error(`Unknown message role: ${unsupportedRole}`);\n        }\n      }\n    }\n  }\n  return assistantMessage;\n};\n\nconst chunkExternalMessages = <T,>(callbackResults: CallbackResult<T>[]) => {\n  const results: ChunkResult<T>[] = [];\n  let isAssistant = false;\n  let inputs: T[] = [];\n  let outputs: useExternalMessageConverter.Message[] = [];\n\n  const flush = () => {\n    if (outputs.length) {\n      results.push({\n        inputs,\n        outputs,\n      });\n    }\n    inputs = [];\n    outputs = [];\n  };\n\n  for (const callbackResult of callbackResults) {\n    for (const output of callbackResult.outputs) {\n      if (!isAssistant || output.role === \"user\" || output.role === \"system\") {\n        flush();\n      }\n      isAssistant = output.role === \"assistant\" || output.role === \"tool\";\n\n      if (inputs.at(-1) !== callbackResult.input) {\n        inputs.push(callbackResult.input);\n      }\n      outputs.push(output);\n    }\n  }\n  flush();\n  return results;\n};\n\nexport const useExternalMessageConverter = <T extends WeakKey>({\n  callback,\n  messages,\n  isRunning,\n}: {\n  callback: useExternalMessageConverter.Callback<T>;\n  messages: T[];\n  isRunning: boolean;\n}) => {\n  const state = useMemo(\n    () => ({\n      callback,\n      callbackCache: new WeakMap<T, CallbackResult<T>>(),\n      chunkCache: new WeakMap<\n        useExternalMessageConverter.Message,\n        ChunkResult<T>\n      >(),\n      converterCache: new ThreadMessageConverter(),\n    }),\n    [callback],\n  );\n\n  return useMemo(() => {\n    const callbackResults: CallbackResult<T>[] = [];\n    for (const message of messages) {\n      let result = state.callbackCache.get(message);\n      if (!result) {\n        const output = state.callback(message);\n        const outputs = Array.isArray(output) ? output : [output];\n        result = { input: message, outputs };\n        state.callbackCache.set(message, result);\n      }\n      callbackResults.push(result);\n    }\n\n    const chunks = chunkExternalMessages(callbackResults).map((m) => {\n      const key = m.outputs[0];\n      if (!key) return m;\n\n      const cached = state.chunkCache.get(key);\n      if (cached && shallowArrayEqual(cached.outputs, m.outputs)) return cached;\n      state.chunkCache.set(key, m);\n      return m;\n    });\n\n    return state.converterCache.convertMessages(\n      chunks,\n      (cache, message, idx) => {\n        const isLast = idx === chunks.length - 1;\n        const autoStatus = getAutoStatus(isLast, isRunning);\n\n        if (\n          cache &&\n          (cache.role !== \"assistant\" ||\n            !isAutoStatus(cache.status) ||\n            cache.status === autoStatus)\n        ) {\n          const inputs = getExternalStoreMessage(cache) as T[];\n          if (shallowArrayEqual(inputs, message.inputs)) {\n            return cache;\n          }\n        }\n\n        const newMessage = fromThreadMessageLike(\n          joinExternalMessages(message.outputs),\n          idx.toString(),\n          autoStatus,\n        );\n        (newMessage as any)[symbolInnerMessage] = message.inputs;\n        return newMessage;\n      },\n    );\n  }, [state, messages, isRunning]);\n};\n\nconst shallowArrayEqual = (a: unknown[], b: unknown[]) => {\n  if (a.length !== b.length) return false;\n  for (let i = 0; i < a.length; i++) {\n    if (a[i] !== b[i]) return false;\n  }\n  return true;\n};\n"],"mappings":"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","names":[]}