{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/service-adapters/langchain/utils.ts"],"sourcesContent":["import {\n  ActionExecutionMessage,\n  Message,\n  ResultMessage,\n  TextMessage,\n} from \"../../graphql/types/converted\";\nimport {\n  AIMessage,\n  AIMessageChunk,\n  BaseMessage,\n  BaseMessageChunk,\n  HumanMessage,\n  SystemMessage,\n  ToolMessage,\n} from \"@langchain/core/messages\";\nimport { DynamicStructuredTool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { ActionInput } from \"../../graphql/inputs/action.input\";\nimport { LangChainReturnType } from \"./types\";\nimport { RuntimeEventSubject } from \"../events\";\nimport { randomId, convertJsonSchemaToZodSchema } from \"@copilotkit/shared\";\n\nexport function convertMessageToLangChainMessage(\n  message: Message,\n): BaseMessage {\n  if (message.isTextMessage()) {\n    if (message.role == \"user\") {\n      return new HumanMessage(message.content);\n    } else if (message.role == \"assistant\") {\n      return new AIMessage(message.content);\n    } else if (message.role === \"system\") {\n      return new SystemMessage(message.content);\n    }\n  } else if (message.isActionExecutionMessage()) {\n    return new AIMessage({\n      content: \"\",\n      tool_calls: [\n        {\n          id: message.id,\n          args: message.arguments,\n          name: message.name,\n        },\n      ],\n    });\n  } else if (message.isResultMessage()) {\n    return new ToolMessage({\n      content: message.result,\n      tool_call_id: message.actionExecutionId,\n    });\n  }\n}\n\nexport function convertActionInputToLangChainTool(\n  actionInput: ActionInput,\n): any {\n  return new DynamicStructuredTool({\n    ...actionInput,\n    name: actionInput.name,\n    description: actionInput.description,\n    schema: convertJsonSchemaToZodSchema(\n      JSON.parse(actionInput.jsonSchema),\n      true,\n    ) as z.ZodObject<any>,\n    func: async () => {\n      return \"\";\n    },\n  });\n}\n\ninterface StreamLangChainResponseParams {\n  result: LangChainReturnType;\n  eventStream$: RuntimeEventSubject;\n  actionExecution?: {\n    id: string;\n    name: string;\n    returnDirect?: boolean;\n  };\n}\n\nfunction getConstructorName(object: any): string {\n  if (\n    object &&\n    typeof object === \"object\" &&\n    object.constructor &&\n    object.constructor.name\n  ) {\n    return object.constructor.name;\n  }\n  return \"\";\n}\n\nfunction isAIMessage(message: any): message is AIMessage {\n  return Object.prototype.toString.call(message) === \"[object AIMessage]\";\n}\n\nfunction isAIMessageChunk(message: any): message is AIMessageChunk {\n  return Object.prototype.toString.call(message) === \"[object AIMessageChunk]\";\n}\n\nfunction isBaseMessageChunk(message: any): message is BaseMessageChunk {\n  return (\n    Object.prototype.toString.call(message) === \"[object BaseMessageChunk]\"\n  );\n}\n\nfunction maybeSendActionExecutionResultIsMessage(\n  eventStream$: RuntimeEventSubject,\n  actionExecution?: { id: string; name: string },\n) {\n  // language models need a result after the function call\n  // we simply let them know that we are sending a message\n  if (actionExecution) {\n    eventStream$.sendActionExecutionResult({\n      actionExecutionId: actionExecution.id,\n      actionName: actionExecution.name,\n      result: \"Sending a message\",\n    });\n  }\n}\n\nexport async function streamLangChainResponse({\n  result,\n  eventStream$,\n  actionExecution,\n}: StreamLangChainResponseParams) {\n  // We support several types of return values from LangChain functions:\n\n  // 1. string\n\n  if (typeof result === \"string\") {\n    if (!actionExecution || actionExecution?.returnDirect) {\n      // Just send one chunk with the string as the content.\n      eventStream$.sendActionExecutionResult({\n        actionExecutionId: actionExecution.id,\n        actionName: actionExecution.name,\n        result: result,\n      });\n      eventStream$.sendTextMessage(randomId(), result);\n    } else {\n      // Send as a result\n      eventStream$.sendActionExecutionResult({\n        actionExecutionId: actionExecution.id,\n        actionName: actionExecution.name,\n        result: result,\n      });\n    }\n  }\n\n  // 2. AIMessage\n  // Send the content and function call of the AIMessage as the content of the chunk.\n  else if (isAIMessage(result)) {\n    maybeSendActionExecutionResultIsMessage(eventStream$, actionExecution);\n\n    if (result.content) {\n      eventStream$.sendTextMessage(randomId(), result.content as string);\n    }\n    for (const toolCall of result.tool_calls) {\n      eventStream$.sendActionExecution({\n        actionExecutionId: toolCall.id || randomId(),\n        actionName: toolCall.name,\n        args: JSON.stringify(toolCall.args),\n      });\n    }\n  }\n\n  // 3. BaseMessageChunk\n  // Send the content and function call of the AIMessage as the content of the chunk.\n  else if (isBaseMessageChunk(result)) {\n    maybeSendActionExecutionResultIsMessage(eventStream$, actionExecution);\n\n    if (result.lc_kwargs?.content) {\n      eventStream$.sendTextMessage(randomId(), result.content as string);\n    }\n    if (result.lc_kwargs?.tool_calls) {\n      for (const toolCall of result.lc_kwargs?.tool_calls) {\n        eventStream$.sendActionExecution({\n          actionExecutionId: toolCall.id || randomId(),\n          actionName: toolCall.name,\n          args: JSON.stringify(toolCall.args),\n        });\n      }\n    }\n  }\n\n  // 4. IterableReadableStream\n  // Stream the result of the LangChain function.\n  else if (result && \"getReader\" in result) {\n    maybeSendActionExecutionResultIsMessage(eventStream$, actionExecution);\n\n    let reader = result.getReader();\n\n    let mode: \"function\" | \"message\" | null = null;\n    let currentMessageId: string;\n\n    const toolCallDetails = {\n      name: null,\n      id: null,\n      index: null,\n      prevIndex: null,\n    };\n\n    while (true) {\n      try {\n        const { done, value } = await reader.read();\n\n        let toolCallName: string | undefined = undefined;\n        let toolCallId: string | undefined = undefined;\n        let toolCallArgs: string | undefined = undefined;\n        let hasToolCall: boolean = false;\n        let content = \"\";\n        if (value && value.content) {\n          content = Array.isArray(value.content)\n            ? (((value.content[0] as any)?.text ?? \"\") as string)\n            : value.content;\n        }\n\n        if (isAIMessageChunk(value)) {\n          let chunk = value.tool_call_chunks?.[0];\n          toolCallArgs = chunk?.args;\n          hasToolCall = chunk != undefined;\n          if (chunk?.name) toolCallDetails.name = chunk.name;\n          // track different index on the same tool cool\n          if (chunk?.index != null) {\n            toolCallDetails.index = chunk.index; // 1\n            if (toolCallDetails.prevIndex == null)\n              toolCallDetails.prevIndex = chunk.index;\n          }\n          // Differentiate when calling the same tool but with different index\n          if (chunk?.id)\n            toolCallDetails.id =\n              chunk.index != null ? `${chunk.id}-idx-${chunk.index}` : chunk.id;\n\n          // Assign to internal variables that the entire script here knows how to work with\n          toolCallName = toolCallDetails.name;\n          toolCallId = toolCallDetails.id;\n        } else if (isBaseMessageChunk(value)) {\n          let chunk = value.additional_kwargs?.tool_calls?.[0];\n          toolCallName = chunk?.function?.name;\n          toolCallId = chunk?.id;\n          toolCallArgs = chunk?.function?.arguments;\n          hasToolCall = chunk?.function != undefined;\n        }\n\n        // When switching from message to function or vice versa,\n        // send the respective end event.\n        // If toolCallName is defined, it means a new tool call starts.\n        if (mode === \"message\" && (toolCallId || done)) {\n          mode = null;\n          eventStream$.sendTextMessageEnd({ messageId: currentMessageId });\n        } else if (mode === \"function\" && (!hasToolCall || done)) {\n          mode = null;\n          eventStream$.sendActionExecutionEnd({\n            actionExecutionId: toolCallId,\n          });\n        }\n\n        if (done) {\n          break;\n        }\n\n        // If we send a new message type, send the appropriate start event.\n        if (mode === null) {\n          if (hasToolCall && toolCallId && toolCallName) {\n            mode = \"function\";\n            eventStream$.sendActionExecutionStart({\n              actionExecutionId: toolCallId,\n              actionName: toolCallName,\n              parentMessageId: value.lc_kwargs?.id,\n            });\n          } else if (content) {\n            mode = \"message\";\n            currentMessageId = value.lc_kwargs?.id || randomId();\n            eventStream$.sendTextMessageStart({ messageId: currentMessageId });\n          }\n        }\n\n        // send the content events\n        if (mode === \"message\" && content) {\n          eventStream$.sendTextMessageContent({\n            messageId: currentMessageId,\n            content,\n          });\n        } else if (mode === \"function\" && toolCallArgs) {\n          // For calls of the same tool with different index, we seal last tool call and register a new one\n          if (toolCallDetails.index !== toolCallDetails.prevIndex) {\n            eventStream$.sendActionExecutionEnd({\n              actionExecutionId: toolCallId,\n            });\n            eventStream$.sendActionExecutionStart({\n              actionExecutionId: toolCallId,\n              actionName: toolCallName,\n              parentMessageId: value.lc_kwargs?.id,\n            });\n            toolCallDetails.prevIndex = toolCallDetails.index;\n          }\n          eventStream$.sendActionExecutionArgs({\n            actionExecutionId: toolCallId,\n            args: toolCallArgs,\n          });\n        }\n      } catch (error) {\n        console.error(\"Error reading from stream\", error);\n        break;\n      }\n    }\n  } else if (actionExecution) {\n    eventStream$.sendActionExecutionResult({\n      actionExecutionId: actionExecution.id,\n      actionName: actionExecution.name,\n      result: encodeResult(result),\n    });\n  }\n\n  // unsupported type\n  else {\n    throw new Error(\"Invalid return type from LangChain function.\");\n  }\n\n  eventStream$.complete();\n}\n\nfunction encodeResult(result: any): string {\n  if (result === undefined) {\n    return \"\";\n  } else if (typeof result === \"string\") {\n    return result;\n  } else {\n    return JSON.stringify(result);\n  }\n}\n"],"mappings":"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"}