Skip to content

Commit c493885

Browse files
authored
Merge pull request #1 from Bharani010/copilot/Implement persistent background agent execution with scheduling and event-driven triggers
Implement persistent background agent execution with scheduling and event-driven triggers
2 parents 2c25225 + 446668a commit c493885

20 files changed

Lines changed: 3192 additions & 0 deletions

File tree

docs/docs/API-Reference/api-background-agents.mdx

Lines changed: 441 additions & 0 deletions
Large diffs are not rendered by default.

docs/docs/Agents/background-agents.mdx

Lines changed: 523 additions & 0 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ dependencies = [
137137
"cuga==0.1.2",
138138
"agent-lifecycle-toolkit",
139139
"astrapy>=2.1.0,<3.0.0",
140+
"APScheduler>=3.10.4,<4.0.0",
140141
]
141142

142143

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""Add background agent tables
2+
3+
Revision ID: kcl7kwcp1upb
4+
Revises: 1b8b740a6fa3
5+
Create Date: 2025-01-03 00:00:00.000000
6+
7+
"""
8+
9+
from collections.abc import Sequence
10+
11+
import sqlalchemy as sa
12+
from alembic import op
13+
from sqlalchemy import Enum as SQLEnum
14+
15+
# revision identifiers, used by Alembic.
16+
revision: str = "kcl7kwcp1upb"
17+
down_revision: str | None = "1b8b740a6fa3"
18+
branch_labels: str | Sequence[str] | None = None
19+
depends_on: str | Sequence[str] | None = None
20+
21+
22+
def upgrade() -> None:
23+
"""Create background agent tables."""
24+
conn = op.get_bind()
25+
inspector = sa.inspect(conn) # type: ignore
26+
tables = inspector.get_table_names()
27+
28+
# Create trigger_type_enum
29+
trigger_type_enum = SQLEnum(
30+
"CRON", "INTERVAL", "DATE", "WEBHOOK", "EVENT",
31+
name="trigger_type_enum",
32+
)
33+
34+
# Create agent_status_enum
35+
agent_status_enum = SQLEnum(
36+
"ACTIVE", "PAUSED", "STOPPED", "ERROR",
37+
name="agent_status_enum",
38+
)
39+
40+
# Create backgroundagent table if it doesn't exist
41+
if "backgroundagent" not in tables:
42+
op.create_table(
43+
"backgroundagent",
44+
sa.Column("name", sa.String(), nullable=False),
45+
sa.Column("description", sa.Text(), nullable=True),
46+
sa.Column("flow_id", sa.UUID(), nullable=False),
47+
sa.Column("trigger_type", trigger_type_enum, nullable=False),
48+
sa.Column("trigger_config", sa.JSON(), nullable=True),
49+
sa.Column("input_config", sa.JSON(), nullable=True),
50+
sa.Column("status", agent_status_enum, nullable=False, server_default="STOPPED"),
51+
sa.Column("enabled", sa.Boolean(), nullable=True),
52+
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
53+
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
54+
sa.Column("last_run_at", sa.DateTime(timezone=True), nullable=True),
55+
sa.Column("next_run_at", sa.DateTime(timezone=True), nullable=True),
56+
sa.Column("id", sa.UUID(), nullable=False),
57+
sa.Column("user_id", sa.UUID(), nullable=False),
58+
sa.ForeignKeyConstraint(["flow_id"], ["flow.id"]),
59+
sa.ForeignKeyConstraint(["user_id"], ["user.id"]),
60+
sa.PrimaryKeyConstraint("id"),
61+
)
62+
op.create_index(op.f("ix_backgroundagent_flow_id"), "backgroundagent", ["flow_id"], unique=False)
63+
op.create_index(op.f("ix_backgroundagent_name"), "backgroundagent", ["name"], unique=False)
64+
op.create_index(op.f("ix_backgroundagent_user_id"), "backgroundagent", ["user_id"], unique=False)
65+
66+
# Create backgroundagentexecution table if it doesn't exist
67+
if "backgroundagentexecution" not in tables:
68+
op.create_table(
69+
"backgroundagentexecution",
70+
sa.Column("agent_id", sa.UUID(), nullable=False),
71+
sa.Column("started_at", sa.DateTime(timezone=True), nullable=False),
72+
sa.Column("completed_at", sa.DateTime(timezone=True), nullable=True),
73+
sa.Column("status", sa.String(), nullable=True),
74+
sa.Column("error_message", sa.Text(), nullable=True),
75+
sa.Column("result", sa.JSON(), nullable=True),
76+
sa.Column("trigger_source", sa.String(), nullable=True),
77+
sa.Column("id", sa.UUID(), nullable=False),
78+
sa.ForeignKeyConstraint(["agent_id"], ["backgroundagent.id"]),
79+
sa.PrimaryKeyConstraint("id"),
80+
)
81+
op.create_index(
82+
op.f("ix_backgroundagentexecution_agent_id"),
83+
"backgroundagentexecution",
84+
["agent_id"],
85+
unique=False,
86+
)
87+
88+
89+
def downgrade() -> None:
90+
"""Drop background agent tables."""
91+
conn = op.get_bind()
92+
inspector = sa.inspect(conn) # type: ignore
93+
tables = inspector.get_table_names()
94+
95+
# Drop backgroundagentexecution table if it exists
96+
if "backgroundagentexecution" in tables:
97+
op.drop_index(op.f("ix_backgroundagentexecution_agent_id"), table_name="backgroundagentexecution")
98+
op.drop_table("backgroundagentexecution")
99+
100+
# Drop backgroundagent table if it exists
101+
if "backgroundagent" in tables:
102+
op.drop_index(op.f("ix_backgroundagent_user_id"), table_name="backgroundagent")
103+
op.drop_index(op.f("ix_backgroundagent_name"), table_name="backgroundagent")
104+
op.drop_index(op.f("ix_backgroundagent_flow_id"), table_name="backgroundagent")
105+
op.drop_table("backgroundagent")
106+
107+
# Drop enums (PostgreSQL only)
108+
try:
109+
op.execute("DROP TYPE IF EXISTS agent_status_enum")
110+
op.execute("DROP TYPE IF EXISTS trigger_type_enum")
111+
except Exception: # noqa: S110, BLE001
112+
# Silently ignore for non-PostgreSQL databases
113+
pass

src/backend/base/langflow/api/router.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from langflow.api.v1 import (
55
api_key_router,
6+
background_agents_router,
67
chat_router,
78
endpoints_router,
89
files_router,
@@ -52,6 +53,7 @@
5253
router_v1.include_router(voice_mode_router)
5354
router_v1.include_router(mcp_projects_router)
5455
router_v1.include_router(openai_responses_router)
56+
router_v1.include_router(background_agents_router)
5557

5658
router_v2.include_router(files_router_v2)
5759
router_v2.include_router(mcp_router_v2)

src/backend/base/langflow/api/v1/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from langflow.api.v1.api_key import router as api_key_router
2+
from langflow.api.v1.background_agents import router as background_agents_router
23
from langflow.api.v1.chat import router as chat_router
34
from langflow.api.v1.endpoints import router as endpoints_router
45
from langflow.api.v1.files import router as files_router
@@ -20,6 +21,7 @@
2021

2122
__all__ = [
2223
"api_key_router",
24+
"background_agents_router",
2325
"chat_router",
2426
"endpoints_router",
2527
"files_router",

0 commit comments

Comments
 (0)