langchain-trigger-server 0.2.8__tar.gz → 0.2.10__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.
Potentially problematic release.
This version of langchain-trigger-server might be problematic. Click here for more details.
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/PKG-INFO +1 -1
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/app.py +115 -16
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/cron_manager.py +5 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/pyproject.toml +1 -1
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/uv.lock +2 -2
- langchain_trigger_server-0.2.10/version_comparison.txt +1 -0
- langchain_trigger_server-0.2.8/version_comparison.txt +0 -1
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/actions/uv_setup/action.yml +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/_lint.yml +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/_test.yml +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/ci.yml +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/release.yml +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.gitignore +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/Makefile +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/README.md +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/__init__.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/auth/__init__.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/auth/slack_hmac.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/core.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/database/__init__.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/database/interface.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/database/supabase.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/decorators.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/triggers/__init__.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/triggers/cron_trigger.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/tests/__init__.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/tests/unit/__init__.py +0 -0
- {langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/tests/unit/test_trigger_server_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-trigger-server
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.10
|
|
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.8 → langchain_trigger_server-0.2.10}/langchain_triggers/app.py
RENAMED
|
@@ -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")
|
|
@@ -577,6 +594,14 @@ class TriggerServer:
|
|
|
577
594
|
) -> dict[str, Any]:
|
|
578
595
|
"""Handle an incoming request with a handler function."""
|
|
579
596
|
try:
|
|
597
|
+
logger.info(
|
|
598
|
+
"incoming_trigger_request method=%s path=%s trigger_id=%s provider=%s content_type=%s",
|
|
599
|
+
request.method,
|
|
600
|
+
request.url.path,
|
|
601
|
+
getattr(trigger, "id", "<unknown>"),
|
|
602
|
+
getattr(trigger, "provider", "<unknown>"),
|
|
603
|
+
request.headers.get("content-type", ""),
|
|
604
|
+
)
|
|
580
605
|
if request.method == "POST":
|
|
581
606
|
if request.headers.get("content-type", "").startswith(
|
|
582
607
|
"application/json"
|
|
@@ -584,15 +609,34 @@ class TriggerServer:
|
|
|
584
609
|
# Read body once for both auth and parsing
|
|
585
610
|
body_bytes = await request.body()
|
|
586
611
|
body_str = body_bytes.decode("utf-8")
|
|
612
|
+
logger.debug(
|
|
613
|
+
"request_body_read bytes=%s",
|
|
614
|
+
len(body_bytes) if body_bytes is not None else 0,
|
|
615
|
+
)
|
|
587
616
|
|
|
617
|
+
# TODO(sam/palash): We should not have API specific things in this framework repo. We should clean this up.
|
|
588
618
|
if self._is_slack_trigger(trigger):
|
|
619
|
+
logger.info(
|
|
620
|
+
"slack_request_detected trigger_id=%s verifying_signature=true",
|
|
621
|
+
getattr(trigger, "id", "<unknown>"),
|
|
622
|
+
)
|
|
589
623
|
await self._verify_slack_webhook_auth_with_body(
|
|
590
624
|
request, body_str
|
|
591
625
|
)
|
|
592
626
|
|
|
593
627
|
import json
|
|
594
628
|
|
|
595
|
-
|
|
629
|
+
try:
|
|
630
|
+
payload = json.loads(body_str)
|
|
631
|
+
except Exception as e:
|
|
632
|
+
logger.error("json_parse_error error=%s", e)
|
|
633
|
+
raise
|
|
634
|
+
logger.info(
|
|
635
|
+
"payload_parsed kind=json keys=%s",
|
|
636
|
+
sorted(payload.keys())
|
|
637
|
+
if isinstance(payload, dict)
|
|
638
|
+
else "<non-dict>",
|
|
639
|
+
)
|
|
596
640
|
|
|
597
641
|
if (
|
|
598
642
|
payload.get("type") == "url_verification"
|
|
@@ -604,22 +648,55 @@ class TriggerServer:
|
|
|
604
648
|
# Handle form data or other content types
|
|
605
649
|
body = await request.body()
|
|
606
650
|
payload = {"raw_body": body.decode("utf-8") if body else ""}
|
|
651
|
+
logger.info(
|
|
652
|
+
"payload_parsed kind=raw length=%s",
|
|
653
|
+
len(payload.get("raw_body", "")),
|
|
654
|
+
)
|
|
607
655
|
else:
|
|
608
656
|
payload = dict(request.query_params)
|
|
657
|
+
logger.info(
|
|
658
|
+
"payload_parsed kind=query keys=%s",
|
|
659
|
+
sorted(payload.keys()),
|
|
660
|
+
)
|
|
609
661
|
|
|
610
662
|
query_params = dict(request.query_params)
|
|
663
|
+
logger.info(
|
|
664
|
+
"invoking_trigger_handler trigger_id=%s provider=%s query_keys=%s",
|
|
665
|
+
getattr(trigger, "id", "<unknown>"),
|
|
666
|
+
getattr(trigger, "provider", "<unknown>"),
|
|
667
|
+
sorted(query_params.keys()),
|
|
668
|
+
)
|
|
611
669
|
result = await trigger.trigger_handler(
|
|
612
670
|
payload, query_params, self.database, self.langchain_auth_client
|
|
613
671
|
)
|
|
672
|
+
logger.info(
|
|
673
|
+
"trigger_handler_completed invoke_agent=%s messages=%s has_registration=%s",
|
|
674
|
+
getattr(result, "invoke_agent", None),
|
|
675
|
+
len(getattr(result, "agent_messages", []) or []),
|
|
676
|
+
bool(getattr(result, "registration", None)),
|
|
677
|
+
)
|
|
614
678
|
if not result.invoke_agent:
|
|
679
|
+
logger.info(
|
|
680
|
+
"no_agent_invocation trigger_id=%s returning_handler_response=true",
|
|
681
|
+
getattr(trigger, "id", "<unknown>"),
|
|
682
|
+
)
|
|
615
683
|
return result.response_body
|
|
616
684
|
|
|
617
685
|
registration_id = result.registration["id"]
|
|
618
686
|
agent_links = await self.database.get_agents_for_trigger(registration_id)
|
|
687
|
+
logger.info(
|
|
688
|
+
"agent_links_fetched registration_id=%s count=%s",
|
|
689
|
+
registration_id,
|
|
690
|
+
len(agent_links) if agent_links is not None else 0,
|
|
691
|
+
)
|
|
619
692
|
|
|
620
693
|
agents_invoked = 0
|
|
621
694
|
# Iterate through each message and invoke agents for each
|
|
622
695
|
for message in result.agent_messages:
|
|
696
|
+
logger.debug(
|
|
697
|
+
"processing_agent_message message_len=%s",
|
|
698
|
+
len(str(message)) if message is not None else 0,
|
|
699
|
+
)
|
|
623
700
|
for agent_link in agent_links:
|
|
624
701
|
agent_id = (
|
|
625
702
|
agent_link
|
|
@@ -629,17 +706,34 @@ class TriggerServer:
|
|
|
629
706
|
# Ensure agent_id and user_id are strings for JSON serialization
|
|
630
707
|
agent_id_str = str(agent_id)
|
|
631
708
|
user_id_str = str(result.registration["user_id"])
|
|
709
|
+
tenant_id_str = str(
|
|
710
|
+
result.registration.get("metadata", {})
|
|
711
|
+
.get("client_metadata", {})
|
|
712
|
+
.get("tenant_id")
|
|
713
|
+
)
|
|
632
714
|
|
|
633
715
|
agent_input = {"messages": [{"role": "human", "content": message}]}
|
|
634
716
|
|
|
635
717
|
try:
|
|
718
|
+
logger.info(
|
|
719
|
+
"invoking_agent assistant_id=%s user_id=%s tenant_id=%s",
|
|
720
|
+
agent_id_str,
|
|
721
|
+
user_id_str,
|
|
722
|
+
tenant_id_str,
|
|
723
|
+
)
|
|
636
724
|
success = await self._invoke_agent(
|
|
637
725
|
agent_id=agent_id_str,
|
|
638
726
|
user_id=user_id_str,
|
|
727
|
+
tenant_id=tenant_id_str,
|
|
639
728
|
input_data=agent_input,
|
|
640
729
|
)
|
|
641
730
|
if success:
|
|
642
731
|
agents_invoked += 1
|
|
732
|
+
logger.info(
|
|
733
|
+
"agent_invocation_success assistant_id=%s registration_id=%s",
|
|
734
|
+
agent_id_str,
|
|
735
|
+
registration_id,
|
|
736
|
+
)
|
|
643
737
|
except Exception as e:
|
|
644
738
|
logger.error(
|
|
645
739
|
f"Error invoking agent {agent_id_str}: {e}", exc_info=True
|
|
@@ -662,6 +756,7 @@ class TriggerServer:
|
|
|
662
756
|
self,
|
|
663
757
|
agent_id: str,
|
|
664
758
|
user_id: str,
|
|
759
|
+
tenant_id: str,
|
|
665
760
|
input_data: dict[str, Any],
|
|
666
761
|
) -> bool:
|
|
667
762
|
"""Invoke LangGraph agent using the SDK."""
|
|
@@ -671,20 +766,23 @@ class TriggerServer:
|
|
|
671
766
|
|
|
672
767
|
try:
|
|
673
768
|
headers = {
|
|
674
|
-
"x-
|
|
769
|
+
"x-api-key": "",
|
|
770
|
+
"x-auth-scheme": "langsmith-agent",
|
|
675
771
|
"x-user-id": user_id_str,
|
|
772
|
+
"x-tenant-id": tenant_id,
|
|
773
|
+
"x-service-key": get_x_service_jwt_token(
|
|
774
|
+
payload={
|
|
775
|
+
"tenant_id": tenant_id,
|
|
776
|
+
"user_id": user_id_str,
|
|
777
|
+
}
|
|
778
|
+
),
|
|
676
779
|
}
|
|
677
780
|
|
|
678
|
-
# Note: API key is already set in client initialization, no need to add to headers
|
|
679
|
-
if not self.langsmith_api_key:
|
|
680
|
-
logger.warning(
|
|
681
|
-
"No LANGSMITH_API_KEY available - authentication may fail"
|
|
682
|
-
)
|
|
683
|
-
|
|
684
781
|
thread = await self.langgraph_client.threads.create(
|
|
685
782
|
metadata={
|
|
686
783
|
"triggered_by": "langchain-triggers",
|
|
687
784
|
"user_id": user_id_str,
|
|
785
|
+
"tenant_id": tenant_id,
|
|
688
786
|
},
|
|
689
787
|
headers=headers,
|
|
690
788
|
)
|
|
@@ -697,6 +795,7 @@ class TriggerServer:
|
|
|
697
795
|
metadata={
|
|
698
796
|
"triggered_by": "langchain-triggers",
|
|
699
797
|
"user_id": user_id_str,
|
|
798
|
+
"tenant_id": tenant_id,
|
|
700
799
|
},
|
|
701
800
|
headers=headers,
|
|
702
801
|
)
|
|
@@ -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:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
version = 1
|
|
2
|
-
revision =
|
|
2
|
+
revision = 3
|
|
3
3
|
requires-python = ">=3.11"
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
@@ -393,7 +393,7 @@ wheels = [
|
|
|
393
393
|
|
|
394
394
|
[[package]]
|
|
395
395
|
name = "langchain-trigger-server"
|
|
396
|
-
version = "0.
|
|
396
|
+
version = "0.3"
|
|
397
397
|
source = { editable = "." }
|
|
398
398
|
dependencies = [
|
|
399
399
|
{ name = "apscheduler" },
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Current: 0.2.10, PyPI: 0.2.9, Should publish: True
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Current: 0.2.8, PyPI: 0.2.7, Should publish: True
|
|
File without changes
|
{langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/_lint.yml
RENAMED
|
File without changes
|
{langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/_test.yml
RENAMED
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/.github/workflows/release.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/core.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.2.8 → langchain_trigger_server-0.2.10}/langchain_triggers/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|