copilotkit 0.1.77__tar.gz → 0.1.78a0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/PKG-INFO +1 -1
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/copilotkit_lg_middleware.py +96 -1
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/pyproject.toml +1 -1
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/README.md +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/__init__.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/action.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/agent.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/crewai/__init__.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/crewai/copilotkit_integration.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/crewai/crewai_agent.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/crewai/crewai_sdk.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/exc.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/html.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/integrations/__init__.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/integrations/fastapi.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/langchain.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/langgraph.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/langgraph_agent.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/langgraph_agui_agent.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/logging.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/parameter.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/protocol.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/runloop.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/sdk.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/types.py +0 -0
- {copilotkit-0.1.77 → copilotkit-0.1.78a0}/copilotkit/utils.py +0 -0
|
@@ -14,9 +14,10 @@ Example:
|
|
|
14
14
|
)
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
+
import json
|
|
17
18
|
from typing import Any, Callable, Awaitable, ClassVar, List
|
|
18
19
|
|
|
19
|
-
from langchain_core.messages import AIMessage
|
|
20
|
+
from langchain_core.messages import AIMessage, SystemMessage
|
|
20
21
|
from langchain.agents.middleware import (
|
|
21
22
|
AgentMiddleware,
|
|
22
23
|
AgentState,
|
|
@@ -75,6 +76,100 @@ class CopilotKitMiddleware(AgentMiddleware[StateSchema, Any]):
|
|
|
75
76
|
|
|
76
77
|
return await handler(request.override(tools=merged_tools))
|
|
77
78
|
|
|
79
|
+
# Inject app context before agent runs
|
|
80
|
+
def before_agent(
|
|
81
|
+
self,
|
|
82
|
+
state: StateSchema,
|
|
83
|
+
runtime: Runtime[Any],
|
|
84
|
+
) -> dict[str, Any] | None:
|
|
85
|
+
messages = state.get("messages", [])
|
|
86
|
+
|
|
87
|
+
if not messages:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
# Get app context from state or runtime
|
|
91
|
+
copilotkit_state = state.get("copilotkit", {})
|
|
92
|
+
app_context = copilotkit_state.get("context") or getattr(runtime, "context", None)
|
|
93
|
+
|
|
94
|
+
# Check if app_context is missing or empty
|
|
95
|
+
if not app_context:
|
|
96
|
+
return None
|
|
97
|
+
if isinstance(app_context, str) and app_context.strip() == "":
|
|
98
|
+
return None
|
|
99
|
+
if isinstance(app_context, dict) and len(app_context) == 0:
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
# Create the context content
|
|
103
|
+
if isinstance(app_context, str):
|
|
104
|
+
context_content = app_context
|
|
105
|
+
else:
|
|
106
|
+
context_content = json.dumps(app_context, indent=2)
|
|
107
|
+
|
|
108
|
+
context_message_content = f"App Context:\n{context_content}"
|
|
109
|
+
context_message_prefix = "App Context:\n"
|
|
110
|
+
|
|
111
|
+
# Helper to get message content as string
|
|
112
|
+
def get_content_string(msg: Any) -> str | None:
|
|
113
|
+
content = getattr(msg, "content", None)
|
|
114
|
+
if isinstance(content, str):
|
|
115
|
+
return content
|
|
116
|
+
if isinstance(content, list) and content and isinstance(content[0], dict):
|
|
117
|
+
return content[0].get("text")
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
# Find the first system/developer message (not our context message)
|
|
121
|
+
# to determine where to insert our context message (right after it)
|
|
122
|
+
first_system_index = -1
|
|
123
|
+
|
|
124
|
+
for i, msg in enumerate(messages):
|
|
125
|
+
msg_type = getattr(msg, "type", None)
|
|
126
|
+
if msg_type in ("system", "developer"):
|
|
127
|
+
content = get_content_string(msg)
|
|
128
|
+
# Skip if this is our own context message
|
|
129
|
+
if content and content.startswith(context_message_prefix):
|
|
130
|
+
continue
|
|
131
|
+
first_system_index = i
|
|
132
|
+
break
|
|
133
|
+
|
|
134
|
+
# Check if our context message already exists
|
|
135
|
+
existing_context_index = -1
|
|
136
|
+
for i, msg in enumerate(messages):
|
|
137
|
+
msg_type = getattr(msg, "type", None)
|
|
138
|
+
if msg_type in ("system", "developer"):
|
|
139
|
+
content = get_content_string(msg)
|
|
140
|
+
if content and content.startswith(context_message_prefix):
|
|
141
|
+
existing_context_index = i
|
|
142
|
+
break
|
|
143
|
+
|
|
144
|
+
# Create the context message
|
|
145
|
+
context_message = SystemMessage(content=context_message_content)
|
|
146
|
+
|
|
147
|
+
if existing_context_index != -1:
|
|
148
|
+
# Replace existing context message
|
|
149
|
+
updated_messages = list(messages)
|
|
150
|
+
updated_messages[existing_context_index] = context_message
|
|
151
|
+
else:
|
|
152
|
+
# Insert after the first system message, or at position 0 if no system message
|
|
153
|
+
insert_index = first_system_index + 1 if first_system_index != -1 else 0
|
|
154
|
+
updated_messages = [
|
|
155
|
+
*messages[:insert_index],
|
|
156
|
+
context_message,
|
|
157
|
+
*messages[insert_index:],
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
**state,
|
|
162
|
+
"messages": updated_messages,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async def abefore_agent(
|
|
166
|
+
self,
|
|
167
|
+
state: StateSchema,
|
|
168
|
+
runtime: Runtime[Any],
|
|
169
|
+
) -> dict[str, Any] | None:
|
|
170
|
+
# Delegate to sync implementation
|
|
171
|
+
return self.before_agent(state, runtime)
|
|
172
|
+
|
|
78
173
|
# Intercept frontend tool calls after model returns, before ToolNode executes
|
|
79
174
|
def after_model(
|
|
80
175
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|