langchain-trigger-server 0.1.14__tar.gz → 0.1.16__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.
Files changed (17) hide show
  1. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/PKG-INFO +1 -1
  2. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/app.py +24 -22
  3. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/core.py +3 -3
  4. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/database/interface.py +10 -0
  5. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/database/supabase.py +27 -0
  6. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/pyproject.toml +1 -1
  7. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/.github/workflows/release.yml +0 -0
  8. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/.vscode/settings.json +0 -0
  9. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/README.md +0 -0
  10. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/__init__.py +0 -0
  11. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/cron_manager.py +0 -0
  12. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/database/__init__.py +0 -0
  13. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/decorators.py +0 -0
  14. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/triggers/__init__.py +0 -0
  15. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/langchain_triggers/triggers/cron_trigger.py +0 -0
  16. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/test_framework.py +0 -0
  17. {langchain_trigger_server-0.1.14 → langchain_trigger_server-0.1.16}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain-trigger-server
3
- Version: 0.1.14
3
+ Version: 0.1.16
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
@@ -255,18 +255,18 @@ class TriggerServer:
255
255
  detail=f"Invalid payload for trigger: {str(e)}"
256
256
  )
257
257
 
258
- # Check for duplicate registration based on resource data
258
+ # Check for duplicate registration based on resource data within this user's scope
259
259
  resource_dict = registration_instance.model_dump()
260
- existing_registration = await self.database.find_registration_by_resource(
260
+ existing_registration = await self.database.find_user_registration_by_resource(
261
+ user_id=user_id,
261
262
  template_id=trigger.id,
262
263
  resource_data=resource_dict
263
264
  )
264
265
 
265
- # TODO(sam) figure out how to allow duplicates across users.....very unnatural constraint to have
266
266
  if existing_registration:
267
267
  raise HTTPException(
268
268
  status_code=400,
269
- detail=f"A registration with this configuration already exists for trigger type '{trigger.id}'. Registration ID: {existing_registration.get('id')}"
269
+ detail=f"You already have a registration with this configuration for trigger type '{trigger.id}'. Registration ID: {existing_registration.get('id')}"
270
270
  )
271
271
 
272
272
 
@@ -443,26 +443,28 @@ class TriggerServer:
443
443
  agent_links = await self.database.get_agents_for_trigger(registration_id)
444
444
 
445
445
  agents_invoked = 0
446
- for agent_link in agent_links:
447
- agent_id = agent_link if isinstance(agent_link, str) else agent_link.get("agent_id")
446
+ # Iterate through each message and invoke agents for each
447
+ for message in result.agent_messages:
448
+ for agent_link in agent_links:
449
+ agent_id = agent_link if isinstance(agent_link, str) else agent_link.get("agent_id")
448
450
 
449
- agent_input = {
450
- "messages": [
451
- {"role": "human", "content": result.agent_message}
452
- ]
453
- }
451
+ agent_input = {
452
+ "messages": [
453
+ {"role": "human", "content": message}
454
+ ]
455
+ }
454
456
 
455
- try:
456
- success = await self._invoke_agent(
457
- agent_id=agent_id,
458
- user_id=result.registration["user_id"],
459
- input_data=agent_input,
460
- )
461
- if success:
462
- agents_invoked += 1
463
- except Exception as e:
464
- logger.error(f"Error invoking agent {agent_id}: {e}", exc_info=True)
465
- logger.info(f"Processed trigger handler, invoked {agents_invoked} agents")
457
+ try:
458
+ success = await self._invoke_agent(
459
+ agent_id=agent_id,
460
+ user_id=result.registration["user_id"],
461
+ input_data=agent_input,
462
+ )
463
+ if success:
464
+ agents_invoked += 1
465
+ except Exception as e:
466
+ logger.error(f"Error invoking agent {agent_id}: {e}", exc_info=True)
467
+ logger.info(f"Processed trigger handler with {len(result.agent_messages)} messages, invoked {agents_invoked} agents")
466
468
 
467
469
  return {
468
470
  "success": True,
@@ -44,14 +44,14 @@ class AgentInvocationRequest(BaseModel):
44
44
  class TriggerHandlerResult(BaseModel):
45
45
  """Result returned by trigger handlers."""
46
46
  invoke_agent: bool = Field(default=True, description="Whether to invoke agents for this event")
47
- agent_message: Optional[str] = Field(default=None, description="String message to send to agents")
47
+ agent_messages: Optional[list[str]] = Field(default=None, description="List of messages to send to agents (one invocation per message)")
48
48
  response_body: Optional[Dict[str, Any]] = Field(default=None, description="Custom HTTP response body (when invoke_agent=False)")
49
49
  registration: Optional[Dict[str, Any]] = Field(default=None, description="Registration data (required when invoke_agent=True)")
50
50
 
51
51
  def model_post_init(self, __context) -> None:
52
52
  """Validate that required fields are provided based on invoke_agent."""
53
- if self.invoke_agent and not self.agent_message:
54
- raise ValueError("agent_message is required when invoke_agent=True")
53
+ if self.invoke_agent and not self.agent_messages:
54
+ raise ValueError("agent_messages is required when invoke_agent=True")
55
55
  if self.invoke_agent and not self.registration:
56
56
  raise ValueError("registration is required when invoke_agent=True")
57
57
  if not self.invoke_agent and not self.response_body:
@@ -67,6 +67,16 @@ class TriggerDatabaseInterface(ABC):
67
67
  """Find trigger registration by matching resource data."""
68
68
  pass
69
69
 
70
+ @abstractmethod
71
+ async def find_user_registration_by_resource(
72
+ self,
73
+ user_id: str,
74
+ template_id: str,
75
+ resource_data: Dict[str, Any]
76
+ ) -> Optional[Dict[str, Any]]:
77
+ """Find trigger registration by matching resource data for a specific user."""
78
+ pass
79
+
70
80
  @abstractmethod
71
81
  async def get_all_registrations(self, template_id: str) -> List[Dict[str, Any]]:
72
82
  """Get all registrations for a specific trigger template."""
@@ -250,6 +250,33 @@ class SupabaseTriggerDatabase(TriggerDatabaseInterface):
250
250
  logger.error(f"Error finding registration by resource: {e}")
251
251
  return None
252
252
 
253
+ async def find_user_registration_by_resource(
254
+ self,
255
+ user_id: str,
256
+ template_id: str,
257
+ resource_data: Dict[str, Any]
258
+ ) -> Optional[Dict[str, Any]]:
259
+ """Find trigger registration by matching resource data for a specific user."""
260
+ try:
261
+ # Build query to match against trigger_registrations with template_id and user_id filter
262
+ query = self.client.table("trigger_registrations").select(
263
+ "*, trigger_templates(id, name, description)"
264
+ ).eq("trigger_templates.id", template_id).eq("user_id", user_id)
265
+
266
+ # Add resource field matches
267
+ for field, value in resource_data.items():
268
+ query = query.eq(f"resource->>{field}", value)
269
+
270
+ response = query.execute()
271
+
272
+ if response.data:
273
+ return response.data[0] # Return first match
274
+ return None
275
+
276
+ except Exception as e:
277
+ logger.error(f"Error finding user registration by resource: {e}")
278
+ return None
279
+
253
280
  async def get_all_registrations(self, template_id: str) -> List[Dict[str, Any]]:
254
281
  """Get all registrations for a specific trigger template."""
255
282
  try:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "langchain-trigger-server"
7
- version = "0.1.14"
7
+ version = "0.1.16"
8
8
  description = "Generic event-driven triggers framework"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"