langchain-trigger-server 0.2.8__py3-none-any.whl → 0.2.10__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain-trigger-server
3
- Version: 0.2.8
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
@@ -1,7 +1,7 @@
1
1
  langchain_triggers/__init__.py,sha256=WoW9LC_FJRs42mLWq2iuM-jjPow2Rue50q2zm56Oul0,536
2
- langchain_triggers/app.py,sha256=_PWD8qB4wE98OCkIGeC4mx2D1TUrFW50Rm2z1kMXhTU,34532
2
+ langchain_triggers/app.py,sha256=rVl_Yc2n0bz37mPb3E1MnPG2bCXH-bZkuuleaQIII8U,38569
3
3
  langchain_triggers/core.py,sha256=_CNZRyj78yCHG8FACwhCmZ0zvRoWls924OIFYMOC27Q,3772
4
- langchain_triggers/cron_manager.py,sha256=RYtaco1mMYRI0BnB-u9NKoI55mTinn485h8HwWNoxJU,10268
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.8.dist-info/METADATA,sha256=_RdZIPeGJI6fGKsJUXtaAekSj4gXd9SY-jGDp9l2qYk,1486
14
- langchain_trigger_server-0.2.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- langchain_trigger_server-0.2.8.dist-info/RECORD,,
13
+ langchain_trigger_server-0.2.10.dist-info/METADATA,sha256=EcKCDT6DqADexKESf7YhP8mMkZImpBDRaGHnvl4XAdU,1487
14
+ langchain_trigger_server-0.2.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ langchain_trigger_server-0.2.10.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")
@@ -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
- payload = json.loads(body_str)
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-auth-scheme": "agent-builder-trigger",
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: