langchain-trigger-server 0.2.7__py3-none-any.whl → 0.2.9__py3-none-any.whl
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.
Potentially problematic release.
This version of langchain-trigger-server might be problematic. Click here for more details.
- {langchain_trigger_server-0.2.7.dist-info → langchain_trigger_server-0.2.9.dist-info}/METADATA +1 -1
- {langchain_trigger_server-0.2.7.dist-info → langchain_trigger_server-0.2.9.dist-info}/RECORD +6 -6
- langchain_triggers/app.py +51 -16
- langchain_triggers/core.py +7 -0
- langchain_triggers/cron_manager.py +5 -0
- {langchain_trigger_server-0.2.7.dist-info → langchain_trigger_server-0.2.9.dist-info}/WHEEL +0 -0
{langchain_trigger_server-0.2.7.dist-info → langchain_trigger_server-0.2.9.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-trigger-server
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Generic event-driven triggers framework
|
|
5
5
|
Project-URL: Homepage, https://github.com/langchain-ai/open-agent-platform
|
|
6
6
|
Project-URL: Repository, https://github.com/langchain-ai/open-agent-platform
|
{langchain_trigger_server-0.2.7.dist-info → langchain_trigger_server-0.2.9.dist-info}/RECORD
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
langchain_triggers/__init__.py,sha256=WoW9LC_FJRs42mLWq2iuM-jjPow2Rue50q2zm56Oul0,536
|
|
2
|
-
langchain_triggers/app.py,sha256=
|
|
3
|
-
langchain_triggers/core.py,sha256=
|
|
4
|
-
langchain_triggers/cron_manager.py,sha256=
|
|
2
|
+
langchain_triggers/app.py,sha256=MARlj82Ena79n0MG23m-Vu9w6YDQWqp0Ao24TuEKTzs,35325
|
|
3
|
+
langchain_triggers/core.py,sha256=_CNZRyj78yCHG8FACwhCmZ0zvRoWls924OIFYMOC27Q,3772
|
|
4
|
+
langchain_triggers/cron_manager.py,sha256=ISo-P2gw7eQ6y7xWQOfojqcJr_K-zagZt9Ocy8nX0fw,10477
|
|
5
5
|
langchain_triggers/decorators.py,sha256=zsfgf171qkEDdIiSn8LUr--3dz6bxBBKZO6dpRM2ILs,3711
|
|
6
6
|
langchain_triggers/auth/__init__.py,sha256=RtDKuBoKYuyHzLNpKr74cmALO0PhHlWO9Ho7k3CUYFE,349
|
|
7
7
|
langchain_triggers/auth/slack_hmac.py,sha256=kiwjhTXITgQvLAtEcOv8BnnWJRJcxaQ9dXkQm3JJDQ4,2948
|
|
@@ -10,6 +10,6 @@ langchain_triggers/database/interface.py,sha256=jpADOOwcBQo1ZichgiZVaOvfZqEqVVo8
|
|
|
10
10
|
langchain_triggers/database/supabase.py,sha256=zi_75GbqRvzzlXd5EgfYof4h6vHWOLS4I1759wvY9kQ,17009
|
|
11
11
|
langchain_triggers/triggers/__init__.py,sha256=Uw1544gxzN4XDRn2RzpZ5EAG6EAF38ZYQtVvlciEsMs,146
|
|
12
12
|
langchain_triggers/triggers/cron_trigger.py,sha256=SeWz_ETBCBO1_r96tzTZgsvn4BdF4yMKabygjmHoGwY,3174
|
|
13
|
-
langchain_trigger_server-0.2.
|
|
14
|
-
langchain_trigger_server-0.2.
|
|
15
|
-
langchain_trigger_server-0.2.
|
|
13
|
+
langchain_trigger_server-0.2.9.dist-info/METADATA,sha256=8ER3hixfKxyvOIn308bFj64yjZkscTxotQRkah3pS60,1486
|
|
14
|
+
langchain_trigger_server-0.2.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
15
|
+
langchain_trigger_server-0.2.9.dist-info/RECORD,,
|
langchain_triggers/app.py
CHANGED
|
@@ -5,8 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
7
|
from collections.abc import Callable
|
|
8
|
+
from datetime import UTC, datetime, timedelta
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
11
|
+
import jwt
|
|
10
12
|
from fastapi import Depends, FastAPI, HTTPException, Request
|
|
11
13
|
from langchain_auth.client import Client
|
|
12
14
|
from langgraph_sdk import get_client
|
|
@@ -27,6 +29,28 @@ from .triggers.cron_trigger import CRON_TRIGGER_ID
|
|
|
27
29
|
logger = logging.getLogger(__name__)
|
|
28
30
|
|
|
29
31
|
|
|
32
|
+
def get_x_service_jwt_token(
|
|
33
|
+
payload: dict[str, Any] | None = None, expiration_seconds: int = 60 * 60
|
|
34
|
+
) -> str:
|
|
35
|
+
exp_datetime = datetime.now(tz=UTC) + timedelta(seconds=expiration_seconds)
|
|
36
|
+
exp = int(exp_datetime.timestamp())
|
|
37
|
+
|
|
38
|
+
payload = payload or {}
|
|
39
|
+
payload = {
|
|
40
|
+
"sub": "unspecified",
|
|
41
|
+
"exp": exp,
|
|
42
|
+
**payload,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
secret = os.environ["X_SERVICE_AUTH_JWT_SECRET"]
|
|
46
|
+
|
|
47
|
+
return jwt.encode(
|
|
48
|
+
payload,
|
|
49
|
+
secret,
|
|
50
|
+
algorithm="HS256",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
30
54
|
class AuthenticationMiddleware(BaseHTTPMiddleware):
|
|
31
55
|
"""Middleware to handle authentication for API endpoints."""
|
|
32
56
|
|
|
@@ -106,7 +130,6 @@ class TriggerServer:
|
|
|
106
130
|
|
|
107
131
|
# LangGraph configuration
|
|
108
132
|
self.langgraph_api_url = os.getenv("LANGGRAPH_API_URL")
|
|
109
|
-
self.langsmith_api_key = os.getenv("LANGCHAIN_API_KEY")
|
|
110
133
|
self.trigger_server_auth_api_url = os.getenv("TRIGGER_SERVER_HOST_API_URL")
|
|
111
134
|
|
|
112
135
|
if not self.langgraph_api_url:
|
|
@@ -115,16 +138,10 @@ class TriggerServer:
|
|
|
115
138
|
self.langgraph_api_url = self.langgraph_api_url.rstrip("/")
|
|
116
139
|
|
|
117
140
|
# Initialize LangGraph SDK client
|
|
118
|
-
self.langgraph_client = get_client(
|
|
119
|
-
url=self.langgraph_api_url, api_key=self.langsmith_api_key
|
|
120
|
-
)
|
|
141
|
+
self.langgraph_client = get_client(url=self.langgraph_api_url, api_key=None)
|
|
121
142
|
logger.info(
|
|
122
143
|
f"✓ LangGraph client initialized with URL: {self.langgraph_api_url}"
|
|
123
144
|
)
|
|
124
|
-
if self.langsmith_api_key:
|
|
125
|
-
logger.info("✓ LangGraph client initialized with API key.")
|
|
126
|
-
else:
|
|
127
|
-
logger.warning("⚠ LangGraph client initialized without API key")
|
|
128
145
|
|
|
129
146
|
# Initialize LangChain auth client
|
|
130
147
|
langchain_api_key = os.getenv("LANGCHAIN_API_KEY")
|
|
@@ -323,6 +340,7 @@ class TriggerServer:
|
|
|
323
340
|
raise HTTPException(
|
|
324
341
|
status_code=400, detail=f"Unknown trigger type: {trigger_id}"
|
|
325
342
|
)
|
|
343
|
+
client_metadata = payload.pop("metadata", None)
|
|
326
344
|
|
|
327
345
|
# Parse payload into registration model first
|
|
328
346
|
try:
|
|
@@ -368,11 +386,16 @@ class TriggerServer:
|
|
|
368
386
|
|
|
369
387
|
resource_dict = registration_instance.model_dump()
|
|
370
388
|
|
|
389
|
+
merged_metadata = {}
|
|
390
|
+
if client_metadata:
|
|
391
|
+
merged_metadata["client_metadata"] = client_metadata
|
|
392
|
+
merged_metadata.update(result.metadata)
|
|
393
|
+
|
|
371
394
|
registration = await self.database.create_trigger_registration(
|
|
372
395
|
user_id=user_id,
|
|
373
396
|
template_id=trigger.id,
|
|
374
397
|
resource=resource_dict,
|
|
375
|
-
metadata=
|
|
398
|
+
metadata=merged_metadata,
|
|
376
399
|
)
|
|
377
400
|
|
|
378
401
|
if not registration:
|
|
@@ -579,6 +602,7 @@ class TriggerServer:
|
|
|
579
602
|
body_bytes = await request.body()
|
|
580
603
|
body_str = body_bytes.decode("utf-8")
|
|
581
604
|
|
|
605
|
+
# TODO(sam/palash): We should not have API specific things in this framework repo. We should clean this up.
|
|
582
606
|
if self._is_slack_trigger(trigger):
|
|
583
607
|
await self._verify_slack_webhook_auth_with_body(
|
|
584
608
|
request, body_str
|
|
@@ -623,6 +647,11 @@ class TriggerServer:
|
|
|
623
647
|
# Ensure agent_id and user_id are strings for JSON serialization
|
|
624
648
|
agent_id_str = str(agent_id)
|
|
625
649
|
user_id_str = str(result.registration["user_id"])
|
|
650
|
+
tenant_id_str = str(
|
|
651
|
+
result.registration.get("metadata", {})
|
|
652
|
+
.get("client_metadata", {})
|
|
653
|
+
.get("tenant_id")
|
|
654
|
+
)
|
|
626
655
|
|
|
627
656
|
agent_input = {"messages": [{"role": "human", "content": message}]}
|
|
628
657
|
|
|
@@ -630,6 +659,7 @@ class TriggerServer:
|
|
|
630
659
|
success = await self._invoke_agent(
|
|
631
660
|
agent_id=agent_id_str,
|
|
632
661
|
user_id=user_id_str,
|
|
662
|
+
tenant_id=tenant_id_str,
|
|
633
663
|
input_data=agent_input,
|
|
634
664
|
)
|
|
635
665
|
if success:
|
|
@@ -656,6 +686,7 @@ class TriggerServer:
|
|
|
656
686
|
self,
|
|
657
687
|
agent_id: str,
|
|
658
688
|
user_id: str,
|
|
689
|
+
tenant_id: str,
|
|
659
690
|
input_data: dict[str, Any],
|
|
660
691
|
) -> bool:
|
|
661
692
|
"""Invoke LangGraph agent using the SDK."""
|
|
@@ -665,20 +696,23 @@ class TriggerServer:
|
|
|
665
696
|
|
|
666
697
|
try:
|
|
667
698
|
headers = {
|
|
668
|
-
"x-
|
|
699
|
+
"x-api-key": "",
|
|
700
|
+
"x-auth-scheme": "langsmith-agent",
|
|
669
701
|
"x-user-id": user_id_str,
|
|
702
|
+
"x-tenant-id": tenant_id,
|
|
703
|
+
"x-service-key": get_x_service_jwt_token(
|
|
704
|
+
payload={
|
|
705
|
+
"tenant_id": tenant_id,
|
|
706
|
+
"user_id": user_id_str,
|
|
707
|
+
}
|
|
708
|
+
),
|
|
670
709
|
}
|
|
671
710
|
|
|
672
|
-
# Note: API key is already set in client initialization, no need to add to headers
|
|
673
|
-
if not self.langsmith_api_key:
|
|
674
|
-
logger.warning(
|
|
675
|
-
"No LANGSMITH_API_KEY available - authentication may fail"
|
|
676
|
-
)
|
|
677
|
-
|
|
678
711
|
thread = await self.langgraph_client.threads.create(
|
|
679
712
|
metadata={
|
|
680
713
|
"triggered_by": "langchain-triggers",
|
|
681
714
|
"user_id": user_id_str,
|
|
715
|
+
"tenant_id": tenant_id,
|
|
682
716
|
},
|
|
683
717
|
headers=headers,
|
|
684
718
|
)
|
|
@@ -691,6 +725,7 @@ class TriggerServer:
|
|
|
691
725
|
metadata={
|
|
692
726
|
"triggered_by": "langchain-triggers",
|
|
693
727
|
"user_id": user_id_str,
|
|
728
|
+
"tenant_id": tenant_id,
|
|
694
729
|
},
|
|
695
730
|
headers=headers,
|
|
696
731
|
)
|
langchain_triggers/core.py
CHANGED
|
@@ -88,6 +88,13 @@ class TriggerRegistrationResult(BaseModel):
|
|
|
88
88
|
"""Validate that required fields are provided based on create_registration."""
|
|
89
89
|
if self.create_registration and not self.metadata:
|
|
90
90
|
self.metadata = {} # Allow empty metadata for create_registration=True
|
|
91
|
+
|
|
92
|
+
if "client_metadata" in self.metadata:
|
|
93
|
+
raise ValueError(
|
|
94
|
+
"The 'client_metadata' key is reserved for client-provided metadata. "
|
|
95
|
+
"Registration handlers must not use this key in their metadata."
|
|
96
|
+
)
|
|
97
|
+
|
|
91
98
|
if not self.create_registration and (
|
|
92
99
|
not self.response_body or not self.status_code
|
|
93
100
|
):
|
|
@@ -202,6 +202,9 @@ class CronTriggerManager:
|
|
|
202
202
|
"""Execute a cron job - invoke agents. Can be called manually or by scheduler."""
|
|
203
203
|
registration_id = registration["id"]
|
|
204
204
|
user_id = registration["user_id"]
|
|
205
|
+
tenant_id = (
|
|
206
|
+
registration.get("metadata", {}).get("client_metadata", {}).get("tenant_id")
|
|
207
|
+
)
|
|
205
208
|
|
|
206
209
|
# Get agent links
|
|
207
210
|
agent_links = await self.trigger_server.database.get_agents_for_trigger(
|
|
@@ -222,6 +225,7 @@ class CronTriggerManager:
|
|
|
222
225
|
# Ensure agent_id and user_id are strings for JSON serialization
|
|
223
226
|
agent_id_str = str(agent_id)
|
|
224
227
|
user_id_str = str(user_id)
|
|
228
|
+
tenant_id_str = str(tenant_id)
|
|
225
229
|
|
|
226
230
|
current_time = datetime.utcnow()
|
|
227
231
|
current_time_str = current_time.strftime("%A, %B %d, %Y at %H:%M UTC")
|
|
@@ -239,6 +243,7 @@ class CronTriggerManager:
|
|
|
239
243
|
success = await self.trigger_server._invoke_agent(
|
|
240
244
|
agent_id=agent_id_str,
|
|
241
245
|
user_id=user_id_str,
|
|
246
|
+
tenant_id=tenant_id_str,
|
|
242
247
|
input_data=agent_input,
|
|
243
248
|
)
|
|
244
249
|
if success:
|
|
File without changes
|