Files
copilotkit__copilotkit/sdk-python/copilotkit/langchain.py
T

171 lines
4.9 KiB
Python

"""
LangChain specific utilities for CopilotKit
"""
import uuid
import json
from typing import List, Optional, Any, Union, Dict, Callable
import asyncio
from langchain_core.messages import (
HumanMessage,
SystemMessage,
BaseMessage,
AIMessage,
ToolMessage
)
from langchain_core.runnables import RunnableConfig
from langchain_core.callbacks.manager import adispatch_custom_event
from .types import Message, IntermediateStateConfig
def copilotkit_messages_to_langchain(
use_function_call: bool = False
) -> Callable[[List[Message]], List[BaseMessage]]:
"""
Convert CopilotKit messages to LangChain messages
"""
def _copilotkit_messages_to_langchain(messages: List[Message]) -> List[BaseMessage]:
result = []
for message in messages:
if "content" in message:
if message["role"] == "user":
result.append(HumanMessage(content=message["content"], id=message["id"]))
elif message["role"] == "system":
result.append(SystemMessage(content=message["content"], id=message["id"]))
elif message["role"] == "assistant":
result.append(AIMessage(content=message["content"], id=message["id"]))
elif "arguments" in message:
tool_call = {
"name": message["name"],
"args": message["arguments"],
"id": message["id"],
}
additional_kwargs = {
'function_call':{
'name': message["name"],
'arguments': json.dumps(message["arguments"]),
}
}
if not use_function_call:
ai_message = AIMessage(
id=message["id"],
content="",
tool_calls=[tool_call]
)
else:
ai_message = AIMessage(
id=message["id"],
content="",
additional_kwargs=additional_kwargs
)
result.append(ai_message)
elif "actionExecutionId" in message:
result.append(ToolMessage(
id=message["id"],
content=message["result"],
name=message["actionName"],
tool_call_id=message["actionExecutionId"]
))
return result
return _copilotkit_messages_to_langchain
def copilotkit_customize_config(
base_config: Optional[RunnableConfig] = None,
*,
emit_tool_calls: Optional[Union[bool, str, List[str]]] = None,
emit_messages: Optional[bool] = None,
emit_all: Optional[bool] = None,
emit_intermediate_state: Optional[List[IntermediateStateConfig]] = None
) -> RunnableConfig:
"""
Configure for LangChain for use in CopilotKit
"""
metadata = base_config.get("metadata", {}) if base_config else {}
if emit_all is True:
metadata["copilotkit:emit-tool-calls"] = True
metadata["copilotkit:emit-messages"] = True
else:
if emit_tool_calls is not None:
metadata["copilotkit:emit-tool-calls"] = emit_tool_calls
if emit_messages is not None:
metadata["copilotkit:emit-messages"] = emit_messages
if emit_intermediate_state:
metadata["copilotkit:emit-intermediate-state"] = emit_intermediate_state
base_config = base_config or {}
return {
**base_config,
"metadata": metadata
}
async def copilotkit_exit(config: RunnableConfig):
"""
Exit CopilotKit
"""
await adispatch_custom_event(
"copilotkit_exit",
{},
config=config,
)
await asyncio.sleep(0.02)
return True
async def copilotkit_emit_state(config: RunnableConfig, state: Any):
"""
Emit CopilotKit state
"""
await adispatch_custom_event(
"copilotkit_manually_emit_intermediate_state",
state,
config=config,
)
await asyncio.sleep(0.02)
return True
async def copilotkit_emit_message(config: RunnableConfig, message: str):
"""
Emit CopilotKit message
"""
await adispatch_custom_event(
"copilotkit_manually_emit_message",
{
"message": message,
"message_id": str(uuid.uuid4()),
"role": "assistant"
},
config=config,
)
await asyncio.sleep(0.02)
return True
async def copilotkit_emit_tool_call(config: RunnableConfig, *, name: str, args: Dict[str, Any]):
"""
Emit CopilotKit tool call
"""
await adispatch_custom_event(
"copilotkit_manually_emit_tool_call",
{
"name": name,
"args": args,
"id": str(uuid.uuid4())
},
config=config,
)
await asyncio.sleep(0.02)
return True