langchain-trigger-server 0.2.3__tar.gz → 0.2.4__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.

Files changed (17) hide show
  1. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/PKG-INFO +1 -1
  2. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/app.py +51 -9
  3. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/cron_manager.py +15 -14
  4. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/database/__init__.py +1 -1
  5. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/triggers/cron_trigger.py +4 -1
  6. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/pyproject.toml +1 -1
  7. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/.github/workflows/release.yml +0 -0
  8. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/.vscode/settings.json +0 -0
  9. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/README.md +0 -0
  10. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/__init__.py +0 -0
  11. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/core.py +0 -0
  12. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/database/interface.py +0 -0
  13. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/database/supabase.py +0 -0
  14. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/decorators.py +0 -0
  15. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/triggers/__init__.py +0 -0
  16. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/test_framework.py +0 -0
  17. {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain-trigger-server
3
- Version: 0.2.3
3
+ Version: 0.2.4
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
@@ -15,6 +15,7 @@ from starlette.responses import Response
15
15
  from .decorators import TriggerTemplate
16
16
  from .database import create_database, TriggerDatabaseInterface
17
17
  from .cron_manager import CronTriggerManager
18
+ from .triggers.cron_trigger import CRON_TRIGGER_ID
18
19
 
19
20
  logger = logging.getLogger(__name__)
20
21
 
@@ -71,17 +72,27 @@ class TriggerServer:
71
72
  def __init__(
72
73
  self,
73
74
  auth_handler: Callable,
75
+ database: Optional[TriggerDatabaseInterface] = None,
76
+ database_type: Optional[str] = "supabase",
77
+ **database_kwargs: Any,
74
78
  ):
75
79
  # Configure uvicorn logging to use consistent formatting
76
80
  self._configure_uvicorn_logging()
77
-
81
+
78
82
  self.app = FastAPI(
79
83
  title="Triggers Server",
80
84
  description="Event-driven triggers framework",
81
85
  version="0.1.0"
82
86
  )
83
-
84
- self.database = create_database()
87
+
88
+ # Configure database: allow either instance injection or factory creation
89
+ # Defaults to Supabase for backward compatibility
90
+ if database and database_type != "supabase":
91
+ raise ValueError("Provide either 'database' or 'database_type', not both")
92
+ if database is not None:
93
+ self.database = database
94
+ else:
95
+ self.database = create_database(database_type, **database_kwargs)
85
96
  self.auth_handler = auth_handler
86
97
 
87
98
  # LangGraph configuration
@@ -406,21 +417,21 @@ class TriggerServer:
406
417
  """Remove an agent from a trigger registration."""
407
418
  try:
408
419
  user_id = current_user["identity"]
409
-
420
+
410
421
  # Verify the trigger registration exists and belongs to the user
411
422
  registration = await self.database.get_trigger_registration(registration_id, user_id)
412
423
  if not registration:
413
424
  raise HTTPException(status_code=404, detail="Trigger registration not found or access denied")
414
-
425
+
415
426
  # Unlink the agent from the trigger
416
427
  success = await self.database.unlink_agent_from_trigger(
417
428
  agent_id=agent_id,
418
429
  registration_id=registration_id
419
430
  )
420
-
431
+
421
432
  if not success:
422
433
  raise HTTPException(status_code=500, detail="Failed to unlink agent from trigger")
423
-
434
+
424
435
  return {
425
436
  "success": True,
426
437
  "message": f"Successfully unlinked agent {agent_id} from trigger {registration_id}",
@@ -429,12 +440,43 @@ class TriggerServer:
429
440
  "agent_id": agent_id
430
441
  }
431
442
  }
432
-
443
+
433
444
  except HTTPException:
434
445
  raise
435
446
  except Exception as e:
436
447
  logger.error(f"Error unlinking agent from trigger: {e}")
437
448
  raise HTTPException(status_code=500, detail=str(e))
449
+
450
+ @self.app.post("/api/triggers/registrations/{registration_id}/execute")
451
+ async def api_execute_trigger_now(registration_id: str, current_user: Dict[str, Any] = Depends(get_current_user)) -> Dict[str, Any]:
452
+ """Manually execute a cron trigger registration immediately."""
453
+ try:
454
+ user_id = current_user["identity"]
455
+
456
+ # Verify the trigger registration exists and belongs to the user
457
+ registration = await self.database.get_trigger_registration(registration_id, user_id)
458
+ if not registration:
459
+ raise HTTPException(status_code=404, detail="Trigger registration not found or access denied")
460
+
461
+ # Get the template to check if it's a cron trigger
462
+ template_id = registration.get("template_id")
463
+ if template_id != CRON_TRIGGER_ID:
464
+ raise HTTPException(status_code=400, detail="Manual execution is only supported for cron triggers")
465
+
466
+ # Execute the cron trigger using the cron manager
467
+ agents_invoked = await self.cron_manager.execute_cron_job(registration)
468
+
469
+ return {
470
+ "success": True,
471
+ "message": f"Manually executed cron trigger {registration_id}",
472
+ "agents_invoked": agents_invoked
473
+ }
474
+
475
+ except HTTPException:
476
+ raise
477
+ except Exception as e:
478
+ logger.error(f"Error executing trigger: {e}")
479
+ raise HTTPException(status_code=500, detail=str(e))
438
480
 
439
481
 
440
482
  async def _handle_request(
@@ -552,4 +594,4 @@ class TriggerServer:
552
594
 
553
595
  def get_app(self) -> FastAPI:
554
596
  """Get the FastAPI app instance."""
555
- return self.app
597
+ return self.app
@@ -10,6 +10,7 @@ from croniter import croniter
10
10
  from pydantic import BaseModel
11
11
 
12
12
  from langchain_triggers.core import TriggerHandlerResult
13
+ from langchain_triggers.triggers.cron_trigger import CRON_TRIGGER_ID
13
14
 
14
15
  logger = logging.getLogger(__name__)
15
16
 
@@ -58,7 +59,7 @@ class CronTriggerManager:
58
59
  async def _load_existing_registrations(self):
59
60
  """Load all existing cron registrations from database and schedule them."""
60
61
  try:
61
- registrations = await self.trigger_server.database.get_all_registrations("cron-trigger")
62
+ registrations = await self.trigger_server.database.get_all_registrations(CRON_TRIGGER_ID)
62
63
 
63
64
  scheduled_count = 0
64
65
  for registration in registrations:
@@ -91,7 +92,7 @@ class CronTriggerManager:
91
92
 
92
93
  async def on_registration_created(self, registration: Dict[str, Any]):
93
94
  """Called when a new cron registration is created."""
94
- if registration.get("trigger_template_id") == "cron-trigger":
95
+ if registration.get("trigger_template_id") == CRON_TRIGGER_ID:
95
96
  try:
96
97
  await self._schedule_cron_job(registration)
97
98
  logger.info(f"Scheduled new cron job for registration {registration['id']}")
@@ -183,15 +184,15 @@ class CronTriggerManager:
183
184
  )
184
185
 
185
186
  logger.info(f"Executing cron job {registration_id} with pattern '{cron_pattern}'")
186
-
187
+
187
188
  try:
188
- agents_invoked = await self._execute_cron_job(registration)
189
+ agents_invoked = await self.execute_cron_job(registration)
189
190
  execution.status = "completed"
190
191
  execution.agents_invoked = agents_invoked
191
192
  logger.info(f"✓ Cron job {registration_id} completed - invoked {agents_invoked} agents")
192
-
193
+
193
194
  except Exception as e:
194
- execution.status = "failed"
195
+ execution.status = "failed"
195
196
  execution.error_message = str(e)
196
197
  logger.error(f"✗ Cron job {registration_id} failed: {e}")
197
198
 
@@ -199,11 +200,11 @@ class CronTriggerManager:
199
200
  execution.completion_time = datetime.utcnow()
200
201
  await self._record_execution(execution)
201
202
 
202
- async def _execute_cron_job(self, registration: Dict[str, Any]) -> int:
203
- """Execute a scheduled cron job - invoke agents."""
203
+ async def execute_cron_job(self, registration: Dict[str, Any]) -> int:
204
+ """Execute a cron job - invoke agents. Can be called manually or by scheduler."""
204
205
  registration_id = registration["id"]
205
206
  user_id = registration["user_id"]
206
-
207
+
207
208
  # Get agent links
208
209
  logger.info(f"Querying database for agents linked to cron job {registration_id}")
209
210
  agent_links = await self.trigger_server.database.get_agents_for_trigger(registration_id)
@@ -216,16 +217,16 @@ class CronTriggerManager:
216
217
  agents_invoked = 0
217
218
  for agent_link in agent_links:
218
219
  agent_id = agent_link if isinstance(agent_link, str) else agent_link.get("agent_id")
219
-
220
+
220
221
  current_time = datetime.utcnow()
221
222
  current_time_str = current_time.strftime("%A, %B %d, %Y at %H:%M UTC")
222
-
223
+
223
224
  agent_input = {
224
225
  "messages": [
225
226
  {"role": "human", "content": f"ACTION: triggering cron from langchain-trigger-server\nCURRENT TIME: {current_time_str}"}
226
227
  ]
227
228
  }
228
-
229
+
229
230
  try:
230
231
  success = await self.trigger_server._invoke_agent(
231
232
  agent_id=agent_id,
@@ -235,10 +236,10 @@ class CronTriggerManager:
235
236
  if success:
236
237
  agents_invoked += 1
237
238
  logger.info(f"✓ Invoked agent {agent_id} for cron job {registration_id}")
238
-
239
+
239
240
  except Exception as e:
240
241
  logger.error(f"✗ Error invoking agent {agent_id} for cron job {registration_id}: {e}")
241
-
242
+
242
243
  return agents_invoked
243
244
 
244
245
  async def _record_execution(self, execution: CronJobExecution):
@@ -4,7 +4,7 @@ from .interface import TriggerDatabaseInterface
4
4
  from .supabase import SupabaseTriggerDatabase
5
5
 
6
6
 
7
- def create_database(database_type: str = "supabase", **kwargs) -> TriggerDatabaseInterface:
7
+ def create_database(database_type: str, **kwargs) -> TriggerDatabaseInterface:
8
8
  """Factory function to create database implementation."""
9
9
 
10
10
  if database_type == "supabase":
@@ -17,6 +17,9 @@ from langchain_triggers.decorators import TriggerTemplate
17
17
 
18
18
  logger = logging.getLogger(__name__)
19
19
 
20
+ # Global constant for cron trigger ID
21
+ CRON_TRIGGER_ID = "cron-trigger"
22
+
20
23
 
21
24
  class CronRegistration(TriggerRegistrationModel):
22
25
  """Registration model for cron triggers - just a crontab pattern."""
@@ -88,7 +91,7 @@ async def cron_trigger_handler(
88
91
 
89
92
 
90
93
  cron_trigger = TriggerTemplate(
91
- id="cron-trigger",
94
+ id=CRON_TRIGGER_ID,
92
95
  name="Cron Scheduler",
93
96
  provider="Cron",
94
97
  description="Triggers agents on a cron schedule",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "langchain-trigger-server"
7
- version = "0.2.3"
7
+ version = "0.2.4"
8
8
  description = "Generic event-driven triggers framework"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"