UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

1 lines 14.3 kB
{"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 = 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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"}