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.
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/PKG-INFO +1 -1
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/app.py +51 -9
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/cron_manager.py +15 -14
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/database/__init__.py +1 -1
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/triggers/cron_trigger.py +4 -1
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/pyproject.toml +1 -1
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/.github/workflows/release.yml +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/.vscode/settings.json +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/README.md +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/__init__.py +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/core.py +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/database/interface.py +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/database/supabase.py +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/decorators.py +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/triggers/__init__.py +0 -0
- {langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/test_framework.py +0 -0
- {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
|
+
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
|
-
|
|
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
|
{langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/cron_manager.py
RENAMED
|
@@ -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(
|
|
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") ==
|
|
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.
|
|
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
|
|
203
|
-
"""Execute a
|
|
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
|
|
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=
|
|
94
|
+
id=CRON_TRIGGER_ID,
|
|
92
95
|
name="Cron Scheduler",
|
|
93
96
|
provider="Cron",
|
|
94
97
|
description="Triggers agents on a cron schedule",
|
{langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/.github/workflows/release.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/__init__.py
RENAMED
|
File without changes
|
{langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/core.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.2.3 → langchain_trigger_server-0.2.4}/langchain_triggers/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|