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

171 lines
4.9 KiB
Python
Raw Normal View History

"""
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