langchain-trigger-server 0.1.9__tar.gz → 0.1.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.1.9 → langchain_trigger_server-0.1.10}/PKG-INFO +3 -1
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/__init__.py +2 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/app.py +13 -1
- langchain_trigger_server-0.1.10/langchain_triggers/cron_manager.py +259 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/database/supabase.py +1 -1
- langchain_trigger_server-0.1.10/langchain_triggers/triggers/__init__.py +7 -0
- langchain_trigger_server-0.1.10/langchain_triggers/triggers/cron_trigger.py +97 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/pyproject.toml +3 -1
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/.github/workflows/release.yml +0 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/README.md +0 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/core.py +0 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/database/__init__.py +0 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/database/interface.py +0 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/decorators.py +0 -0
- {langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/test_framework.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-trigger-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.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
|
|
@@ -16,6 +16,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
|
+
Requires-Dist: apscheduler>=3.10.0
|
|
20
|
+
Requires-Dist: croniter>=1.4.0
|
|
19
21
|
Requires-Dist: cryptography>=3.0.0
|
|
20
22
|
Requires-Dist: fastapi>=0.100.0
|
|
21
23
|
Requires-Dist: httpx>=0.24.0
|
{langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/__init__.py
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from .core import UserAuthInfo, TriggerRegistrationModel, TriggerHandlerResult, TriggerRegistrationResult
|
|
4
4
|
from .decorators import TriggerTemplate
|
|
5
5
|
from .app import TriggerServer
|
|
6
|
+
from .triggers.cron_trigger import cron_trigger
|
|
6
7
|
|
|
7
8
|
__version__ = "0.1.0"
|
|
8
9
|
|
|
@@ -13,4 +14,5 @@ __all__ = [
|
|
|
13
14
|
"TriggerRegistrationResult",
|
|
14
15
|
"TriggerTemplate",
|
|
15
16
|
"TriggerServer",
|
|
17
|
+
"cron_trigger",
|
|
16
18
|
]
|
{langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/app.py
RENAMED
|
@@ -14,6 +14,7 @@ from starlette.responses import Response
|
|
|
14
14
|
|
|
15
15
|
from .decorators import TriggerTemplate
|
|
16
16
|
from .database import create_database, TriggerDatabaseInterface
|
|
17
|
+
from .cron_manager import CronTriggerManager
|
|
17
18
|
|
|
18
19
|
logger = logging.getLogger(__name__)
|
|
19
20
|
|
|
@@ -103,16 +104,24 @@ class TriggerServer:
|
|
|
103
104
|
|
|
104
105
|
self.triggers: List[TriggerTemplate] = []
|
|
105
106
|
|
|
107
|
+
# Initialize CronTriggerManager
|
|
108
|
+
self.cron_manager = CronTriggerManager(self)
|
|
109
|
+
|
|
106
110
|
# Setup authentication middleware
|
|
107
111
|
self.app.add_middleware(AuthenticationMiddleware, auth_handler=auth_handler)
|
|
108
112
|
|
|
109
113
|
# Setup routes
|
|
110
114
|
self._setup_routes()
|
|
111
115
|
|
|
112
|
-
# Add startup
|
|
116
|
+
# Add startup and shutdown events
|
|
113
117
|
@self.app.on_event("startup")
|
|
114
118
|
async def startup_event():
|
|
115
119
|
await self.ensure_trigger_templates()
|
|
120
|
+
await self.cron_manager.start()
|
|
121
|
+
|
|
122
|
+
@self.app.on_event("shutdown")
|
|
123
|
+
async def shutdown_event():
|
|
124
|
+
await self.cron_manager.shutdown()
|
|
116
125
|
|
|
117
126
|
def add_trigger(self, trigger: TriggerTemplate) -> None:
|
|
118
127
|
"""Add a trigger template to the app."""
|
|
@@ -285,6 +294,9 @@ class TriggerServer:
|
|
|
285
294
|
if not registration:
|
|
286
295
|
raise HTTPException(status_code=500, detail="Failed to create trigger registration")
|
|
287
296
|
|
|
297
|
+
# Reload cron manager to pick up any new cron registrations
|
|
298
|
+
await self.cron_manager.reload_from_database()
|
|
299
|
+
|
|
288
300
|
# Return registration result
|
|
289
301
|
return {
|
|
290
302
|
"success": True,
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""Dynamic Cron Trigger Manager for scheduled agent execution."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Dict, Any, Optional
|
|
6
|
+
|
|
7
|
+
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
8
|
+
from apscheduler.triggers.cron import CronTrigger as APSCronTrigger
|
|
9
|
+
from croniter import croniter
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from langchain_triggers.core import TriggerHandlerResult
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CronJobExecution(BaseModel):
|
|
18
|
+
"""Model for tracking cron job execution history."""
|
|
19
|
+
|
|
20
|
+
registration_id: str
|
|
21
|
+
cron_pattern: str
|
|
22
|
+
scheduled_time: datetime
|
|
23
|
+
actual_start_time: datetime
|
|
24
|
+
completion_time: Optional[datetime] = None
|
|
25
|
+
status: str # "running", "completed", "failed"
|
|
26
|
+
error_message: Optional[str] = None
|
|
27
|
+
agents_invoked: int = 0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CronTriggerManager:
|
|
31
|
+
"""Manages dynamic cron job scheduling based on database registrations."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, trigger_server):
|
|
34
|
+
self.scheduler = AsyncIOScheduler(timezone='UTC')
|
|
35
|
+
self.trigger_server = trigger_server
|
|
36
|
+
self.active_jobs = {} # registration_id -> job_id mapping
|
|
37
|
+
self.execution_history = [] # Keep recent execution history
|
|
38
|
+
self.max_history = 1000
|
|
39
|
+
|
|
40
|
+
async def start(self):
|
|
41
|
+
"""Start scheduler and load existing cron registrations."""
|
|
42
|
+
try:
|
|
43
|
+
self.scheduler.start()
|
|
44
|
+
await self._load_existing_registrations()
|
|
45
|
+
logger.info("✓ CronTriggerManager started")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.error(f"Failed to start CronTriggerManager: {e}")
|
|
48
|
+
raise
|
|
49
|
+
|
|
50
|
+
async def shutdown(self):
|
|
51
|
+
"""Shutdown scheduler gracefully."""
|
|
52
|
+
try:
|
|
53
|
+
self.scheduler.shutdown(wait=True)
|
|
54
|
+
logger.info("✓ CronTriggerManager stopped")
|
|
55
|
+
except Exception as e:
|
|
56
|
+
logger.error(f"Error shutting down CronTriggerManager: {e}")
|
|
57
|
+
|
|
58
|
+
async def _load_existing_registrations(self):
|
|
59
|
+
"""Load all existing cron registrations from database and schedule them."""
|
|
60
|
+
try:
|
|
61
|
+
registrations = await self.trigger_server.database.get_all_registrations("cron-trigger")
|
|
62
|
+
|
|
63
|
+
scheduled_count = 0
|
|
64
|
+
for registration in registrations:
|
|
65
|
+
if registration.get("status") == "active":
|
|
66
|
+
try:
|
|
67
|
+
await self._schedule_cron_job(registration)
|
|
68
|
+
scheduled_count += 1
|
|
69
|
+
except Exception as e:
|
|
70
|
+
logger.error(f"Failed to schedule existing cron job {registration.get('id')}: {e}")
|
|
71
|
+
|
|
72
|
+
logger.info(f"Loaded {scheduled_count} existing cron registrations from {len(registrations)} total")
|
|
73
|
+
|
|
74
|
+
except Exception as e:
|
|
75
|
+
logger.error(f"Failed to load existing cron registrations: {e}")
|
|
76
|
+
|
|
77
|
+
async def reload_from_database(self):
|
|
78
|
+
"""Reload all cron registrations from database, replacing current schedules."""
|
|
79
|
+
try:
|
|
80
|
+
# Clear all current jobs
|
|
81
|
+
for registration_id in list(self.active_jobs.keys()):
|
|
82
|
+
await self._unschedule_cron_job(registration_id)
|
|
83
|
+
|
|
84
|
+
# Reload from database
|
|
85
|
+
await self._load_existing_registrations()
|
|
86
|
+
logger.info("✓ Reloaded cron jobs from database")
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error(f"Failed to reload cron jobs from database: {e}")
|
|
90
|
+
raise
|
|
91
|
+
|
|
92
|
+
async def on_registration_created(self, registration: Dict[str, Any]):
|
|
93
|
+
"""Called when a new cron registration is created."""
|
|
94
|
+
if registration.get("trigger_template_id") == "cron-trigger":
|
|
95
|
+
try:
|
|
96
|
+
await self._schedule_cron_job(registration)
|
|
97
|
+
logger.info(f"Scheduled new cron job for registration {registration['id']}")
|
|
98
|
+
except Exception as e:
|
|
99
|
+
logger.error(f"Failed to schedule new cron job {registration['id']}: {e}")
|
|
100
|
+
raise
|
|
101
|
+
|
|
102
|
+
async def on_registration_deleted(self, registration_id: str):
|
|
103
|
+
"""Called when a cron registration is deleted."""
|
|
104
|
+
try:
|
|
105
|
+
await self._unschedule_cron_job(registration_id)
|
|
106
|
+
logger.info(f"Unscheduled cron job for deleted registration {registration_id}")
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.error(f"Failed to unschedule cron job {registration_id}: {e}")
|
|
109
|
+
|
|
110
|
+
async def _schedule_cron_job(self, registration: Dict[str, Any]):
|
|
111
|
+
"""Add a cron job to the scheduler."""
|
|
112
|
+
registration_id = registration["id"]
|
|
113
|
+
resource_data = registration.get("resource", {})
|
|
114
|
+
crontab = resource_data.get("crontab", "")
|
|
115
|
+
|
|
116
|
+
if not crontab:
|
|
117
|
+
raise ValueError(f"No crontab pattern found in registration {registration_id}")
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
# Parse cron expression
|
|
121
|
+
cron_parts = crontab.strip().split()
|
|
122
|
+
if len(cron_parts) != 5:
|
|
123
|
+
raise ValueError(f"Invalid cron format: {crontab} (expected 5 parts)")
|
|
124
|
+
|
|
125
|
+
minute, hour, day, month, day_of_week = cron_parts
|
|
126
|
+
|
|
127
|
+
# Create APScheduler cron trigger
|
|
128
|
+
trigger = APSCronTrigger(
|
|
129
|
+
minute=minute,
|
|
130
|
+
hour=hour,
|
|
131
|
+
day=day,
|
|
132
|
+
month=month,
|
|
133
|
+
day_of_week=day_of_week,
|
|
134
|
+
timezone='UTC'
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Schedule the job
|
|
138
|
+
job = self.scheduler.add_job(
|
|
139
|
+
self._execute_cron_job_with_monitoring,
|
|
140
|
+
trigger=trigger,
|
|
141
|
+
args=[registration],
|
|
142
|
+
id=f"cron_{registration_id}",
|
|
143
|
+
name=f"Cron job for registration {registration_id}",
|
|
144
|
+
max_instances=1, # Prevent overlapping executions
|
|
145
|
+
replace_existing=True
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
self.active_jobs[registration_id] = job.id
|
|
149
|
+
logger.info(f"✓ Scheduled cron job: '{crontab}' for registration {registration_id}")
|
|
150
|
+
|
|
151
|
+
except Exception as e:
|
|
152
|
+
logger.error(f"Failed to schedule cron job for registration {registration_id}: {e}")
|
|
153
|
+
raise
|
|
154
|
+
|
|
155
|
+
async def _unschedule_cron_job(self, registration_id: str):
|
|
156
|
+
"""Remove a cron job from the scheduler."""
|
|
157
|
+
if registration_id in self.active_jobs:
|
|
158
|
+
job_id = self.active_jobs[registration_id]
|
|
159
|
+
try:
|
|
160
|
+
self.scheduler.remove_job(job_id)
|
|
161
|
+
del self.active_jobs[registration_id]
|
|
162
|
+
logger.info(f"✓ Unscheduled cron job for registration {registration_id}")
|
|
163
|
+
except Exception as e:
|
|
164
|
+
logger.error(f"Failed to unschedule cron job {job_id}: {e}")
|
|
165
|
+
raise
|
|
166
|
+
else:
|
|
167
|
+
logger.warning(f"Attempted to unschedule non-existent cron job {registration_id}")
|
|
168
|
+
|
|
169
|
+
async def _execute_cron_job_with_monitoring(self, registration: Dict[str, Any]):
|
|
170
|
+
"""Execute a scheduled cron job with full monitoring and error handling."""
|
|
171
|
+
registration_id = registration["id"]
|
|
172
|
+
cron_pattern = registration["resource"]["crontab"]
|
|
173
|
+
|
|
174
|
+
execution = CronJobExecution(
|
|
175
|
+
registration_id=registration_id,
|
|
176
|
+
cron_pattern=cron_pattern,
|
|
177
|
+
scheduled_time=datetime.utcnow(),
|
|
178
|
+
actual_start_time=datetime.utcnow(),
|
|
179
|
+
status="running"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
logger.info(f"🕐 Executing cron job {registration_id} with pattern '{cron_pattern}'")
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
agents_invoked = await self._execute_cron_job(registration)
|
|
186
|
+
execution.status = "completed"
|
|
187
|
+
execution.agents_invoked = agents_invoked
|
|
188
|
+
logger.info(f"✓ Cron job {registration_id} completed - invoked {agents_invoked} agents")
|
|
189
|
+
|
|
190
|
+
except Exception as e:
|
|
191
|
+
execution.status = "failed"
|
|
192
|
+
execution.error_message = str(e)
|
|
193
|
+
logger.error(f"✗ Cron job {registration_id} failed: {e}")
|
|
194
|
+
|
|
195
|
+
finally:
|
|
196
|
+
execution.completion_time = datetime.utcnow()
|
|
197
|
+
await self._record_execution(execution)
|
|
198
|
+
|
|
199
|
+
async def _execute_cron_job(self, registration: Dict[str, Any]) -> int:
|
|
200
|
+
"""Execute a scheduled cron job - invoke agents."""
|
|
201
|
+
registration_id = registration["id"]
|
|
202
|
+
user_id = registration["user_id"]
|
|
203
|
+
|
|
204
|
+
# Get agent links
|
|
205
|
+
agent_links = await self.trigger_server.database.get_agents_for_trigger(registration_id)
|
|
206
|
+
|
|
207
|
+
if not agent_links:
|
|
208
|
+
logger.warning(f"No agents linked to cron job {registration_id}")
|
|
209
|
+
return 0
|
|
210
|
+
|
|
211
|
+
agents_invoked = 0
|
|
212
|
+
for agent_link in agent_links:
|
|
213
|
+
agent_id = agent_link if isinstance(agent_link, str) else agent_link.get("agent_id")
|
|
214
|
+
|
|
215
|
+
agent_input = {
|
|
216
|
+
"messages": [
|
|
217
|
+
{"role": "human", "content": ""}
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
success = await self.trigger_server._invoke_agent(
|
|
223
|
+
agent_id=agent_id,
|
|
224
|
+
user_id=user_id,
|
|
225
|
+
input_data=agent_input,
|
|
226
|
+
)
|
|
227
|
+
if success:
|
|
228
|
+
agents_invoked += 1
|
|
229
|
+
logger.info(f"✓ Invoked agent {agent_id} for cron job {registration_id}")
|
|
230
|
+
|
|
231
|
+
except Exception as e:
|
|
232
|
+
logger.error(f"✗ Error invoking agent {agent_id} for cron job {registration_id}: {e}")
|
|
233
|
+
|
|
234
|
+
return agents_invoked
|
|
235
|
+
|
|
236
|
+
async def _record_execution(self, execution: CronJobExecution):
|
|
237
|
+
"""Record execution history (in memory for now)."""
|
|
238
|
+
self.execution_history.append(execution)
|
|
239
|
+
|
|
240
|
+
# Keep only recent executions
|
|
241
|
+
if len(self.execution_history) > self.max_history:
|
|
242
|
+
self.execution_history = self.execution_history[-self.max_history:]
|
|
243
|
+
|
|
244
|
+
def get_active_jobs(self) -> Dict[str, str]:
|
|
245
|
+
"""Get currently active cron jobs."""
|
|
246
|
+
return self.active_jobs.copy()
|
|
247
|
+
|
|
248
|
+
def get_execution_history(self, limit: int = 100) -> list[CronJobExecution]:
|
|
249
|
+
"""Get recent execution history."""
|
|
250
|
+
return self.execution_history[-limit:]
|
|
251
|
+
|
|
252
|
+
def get_job_status(self) -> Dict[str, Any]:
|
|
253
|
+
"""Get status information about the cron manager."""
|
|
254
|
+
return {
|
|
255
|
+
"active_jobs": len(self.active_jobs),
|
|
256
|
+
"scheduler_running": self.scheduler.running,
|
|
257
|
+
"total_executions": len(self.execution_history),
|
|
258
|
+
"active_job_ids": list(self.active_jobs.keys())
|
|
259
|
+
}
|
|
@@ -253,7 +253,7 @@ class SupabaseTriggerDatabase(TriggerDatabaseInterface):
|
|
|
253
253
|
try:
|
|
254
254
|
response = self.client.table("trigger_registrations").select(
|
|
255
255
|
"*, trigger_templates(id, name, description)"
|
|
256
|
-
).eq("
|
|
256
|
+
).eq("template_id", template_id).execute()
|
|
257
257
|
|
|
258
258
|
return response.data or []
|
|
259
259
|
except Exception as e:
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Cron-based trigger for scheduled agent execution."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
|
|
7
|
+
from croniter import croniter
|
|
8
|
+
from langchain_auth.client import Client
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
from langchain_triggers.core import (
|
|
12
|
+
TriggerRegistrationModel,
|
|
13
|
+
TriggerHandlerResult,
|
|
14
|
+
TriggerRegistrationResult,
|
|
15
|
+
)
|
|
16
|
+
from langchain_triggers.decorators import TriggerTemplate
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CronRegistration(TriggerRegistrationModel):
|
|
22
|
+
"""Registration model for cron triggers - just a crontab pattern."""
|
|
23
|
+
|
|
24
|
+
crontab: str = Field(
|
|
25
|
+
...,
|
|
26
|
+
description="Cron pattern (e.g., '0 9 * * MON-FRI', '*/15 * * * *')",
|
|
27
|
+
examples=["0 9 * * MON-FRI", "*/15 * * * *", "0 2 * * SUN"],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def cron_registration_handler(
|
|
32
|
+
user_id: str, auth_client: Client, registration: CronRegistration
|
|
33
|
+
) -> TriggerRegistrationResult:
|
|
34
|
+
"""Handle cron trigger registration - validates cron pattern and prepares for scheduling."""
|
|
35
|
+
logger.info(f"Cron registration request: {registration}")
|
|
36
|
+
|
|
37
|
+
cron_pattern = registration.crontab.strip()
|
|
38
|
+
|
|
39
|
+
# Validate cron pattern
|
|
40
|
+
try:
|
|
41
|
+
if not croniter.is_valid(cron_pattern):
|
|
42
|
+
return TriggerRegistrationResult(
|
|
43
|
+
create_registration=False,
|
|
44
|
+
response_body={
|
|
45
|
+
"success": False,
|
|
46
|
+
"error": "invalid_cron_pattern",
|
|
47
|
+
"message": f"Invalid cron pattern: '{cron_pattern}'"
|
|
48
|
+
},
|
|
49
|
+
status_code=400
|
|
50
|
+
)
|
|
51
|
+
except Exception as e:
|
|
52
|
+
return TriggerRegistrationResult(
|
|
53
|
+
create_registration=False,
|
|
54
|
+
response_body={
|
|
55
|
+
"success": False,
|
|
56
|
+
"error": "cron_validation_failed",
|
|
57
|
+
"message": f"Failed to validate cron pattern: {str(e)}"
|
|
58
|
+
},
|
|
59
|
+
status_code=400
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
logger.info(f"Successfully validated cron pattern: {cron_pattern}")
|
|
63
|
+
return TriggerRegistrationResult(
|
|
64
|
+
metadata={
|
|
65
|
+
"cron_pattern": cron_pattern,
|
|
66
|
+
"timezone": "UTC",
|
|
67
|
+
"created_at": datetime.utcnow().isoformat(),
|
|
68
|
+
"validated": True
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def cron_trigger_handler(
|
|
74
|
+
payload: Dict[str, Any],
|
|
75
|
+
query_params: Dict[str, str],
|
|
76
|
+
database,
|
|
77
|
+
auth_client: Client,
|
|
78
|
+
) -> TriggerHandlerResult:
|
|
79
|
+
"""Cron trigger handler - this should never be called via HTTP."""
|
|
80
|
+
logger.warning("Cron trigger handler called via HTTP - this shouldn't happen")
|
|
81
|
+
return TriggerHandlerResult(
|
|
82
|
+
invoke_agent=False,
|
|
83
|
+
response_body={
|
|
84
|
+
"success": False,
|
|
85
|
+
"message": "Cron triggers are executed by scheduler, not HTTP requests"
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
cron_trigger = TriggerTemplate(
|
|
91
|
+
id="cron-trigger",
|
|
92
|
+
name="Cron Scheduler",
|
|
93
|
+
description="Triggers agents on a cron schedule",
|
|
94
|
+
registration_model=CronRegistration,
|
|
95
|
+
registration_handler=cron_registration_handler,
|
|
96
|
+
trigger_handler=cron_trigger_handler,
|
|
97
|
+
)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "langchain-trigger-server"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.10"
|
|
8
8
|
description = "Generic event-driven triggers framework"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -33,6 +33,8 @@ dependencies = [
|
|
|
33
33
|
"langgraph-sdk>=0.2.6",
|
|
34
34
|
"supabase>=2.0.0",
|
|
35
35
|
"cryptography>=3.0.0",
|
|
36
|
+
"APScheduler>=3.10.0",
|
|
37
|
+
"croniter>=1.4.0",
|
|
36
38
|
]
|
|
37
39
|
|
|
38
40
|
[project.optional-dependencies]
|
{langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/.github/workflows/release.yml
RENAMED
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/core.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langchain_trigger_server-0.1.9 → langchain_trigger_server-0.1.10}/langchain_triggers/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|