Skip to content

[feat] Add triggers (connections, subscriptions, schedules)#4749

Open
jp-agenta wants to merge 20 commits into
release/v0.104.1from
gateway-triggers-all
Open

[feat] Add triggers (connections, subscriptions, schedules)#4749
jp-agenta wants to merge 20 commits into
release/v0.104.1from
gateway-triggers-all

Conversation

@jp-agenta

@jp-agenta jp-agenta commented Jun 19, 2026

Copy link
Copy Markdown
Member

No description provided.

Inbound dual of webhooks: turn external provider events into Agenta workflow runs. Adds a shared routerless connections domain (core/gateway/connections), a triggers domain (event catalog, subscriptions, deliveries), a global Composio ingress endpoint with HMAC verification + async dispatch worker, and the web UI for catalog browse and subscription/delivery management. Includes design docs and unit/acceptance tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jun 19, 2026
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jun 22, 2026 2:26pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c721884d-c006-4c34-a36b-24e3e2c27e09

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR implements Gateway Triggers, a new first-class inbound event domain for Agenta. It extracts provider connection handling into a shared gateway_connections foundation, adds trigger subscriptions/schedules bound to workflows, includes webhook ingress with signature verification and async dispatch, refactors tools to use shared connections, renames webhook/automation terminology to webhook-specific naming, adds comprehensive design documentation and work-package planning, and includes frontend UI for browsing triggers, managing subscriptions and schedules, and viewing delivery history.

Changes

Cohort / File(s) Summary
Shared connections extraction
api/oss/databases/postgres/migrations/core_oss/versions/oss000000002_rename_tool_connections_to_gateway_connections.py, api/oss/src/core/gateway/connections/*, api/oss/src/dbs/postgres/gateway/connections/*, api/oss/src/core/tools/dtos.py, api/oss/src/core/tools/interfaces.py, api/oss/src/core/tools/service.py, api/oss/src/core/tools/providers/composio/adapter.py
Migrate tool_connections to gateway_connections table. Extract connection persistence, service layer, DAO, interfaces, Composio adapter into shared core/gateway/connections domain. Refactor tools to delegate connection lifecycle to ConnectionsService. Remove connection DTOs from tools domain.
Shared catalog service
api/oss/src/core/gateway/catalog/*, api/oss/src/core/tools/dtos.py
Add new CatalogGatewayInterface and CatalogService for shared provider/integration browsing. Extract catalog DTOs to gateway/catalog. Repoint tools catalog queries to use shared service. Add Composio catalog adapter.
Triggers core domain
api/oss/src/core/triggers/*
Add complete triggers domain: DTOs (subscriptions, schedules, deliveries, events), exceptions, DAO/service interfaces, registries. Define trigger flags, context fields, max retries constant. Implement service orchestration for catalog, connections, subscriptions, schedules, deliveries, webhook registration, signature verification.
Triggers persistence
api/oss/databases/postgres/migrations/core_oss/versions/oss00000000{3,4}*.py, api/oss/src/dbs/postgres/triggers/*
Add Alembic migrations for trigger_subscriptions, trigger_schedules, trigger_deliveries tables with composite PKs, partial indexes, XOR constraints. Define DBE models, DAO with subscription/schedule/delivery CRUD, active-schedule queries, deduplication logic, and mapping functions.
Triggers router and models
api/oss/src/apis/fastapi/triggers/router.py, api/oss/src/apis/fastapi/triggers/models.py
Add FastAPI router with 20+ endpoints for catalog (providers/integrations/events), connections, subscriptions, schedules, deliveries, ingress webhook. Define Pydantic request/response models. Include signature verification, error handling, permission gating, caching for catalog. Mount webhook ingress, subscription lifecycle, schedule refresh endpoints.
Triggers worker and dispatch
api/oss/src/tasks/asyncio/triggers/dispatcher.py, api/oss/src/tasks/taskiq/triggers/worker.py, api/entrypoints/worker_triggers.py, api/entrypoints/dispatcher_composio.py, api/oss/src/core/triggers/utils.py
Add TriggersDispatcher for matching events to subscriptions/schedules, invoking workflows, and writing delivery records. Implement TriggersWorker registering TaskIQ tasks for subscription and schedule dispatch. Add worker entrypoint with Redis broker, Postgres DAO/service setup. Add Composio event bridge tunnel for local webhook testing.
Triggers entrypoint wiring
api/entrypoints/routers.py
Wire triggers domain: DAO, service, adapter registry, dispatch broker, worker. Start Redis broker on lifespan. Register webhook subscription on Composio startup. Mount trigger routes. Close Composio connections on shutdown.
Webhook activation flags
api/oss/src/core/webhooks/types.py, api/oss/src/core/webhooks/service.py, api/oss/src/apis/fastapi/webhooks/router.py, api/oss/src/dbs/postgres/webhooks/mappings.py, api/oss/src/tasks/asyncio/webhooks/dispatcher.py, api/oss/databases/postgres/migrations/core_oss/versions/oss000000004_add_webhook_subscription_flags.py, api/oss/tests/pytest/acceptance/webhooks/test_webhooks_basics.py
Add WebhookSubscriptionFlags with is_active field to webhooks. Add migration to backfill and index by active status. Implement set_subscription_active service method and /start/stop routes. Gate webhook dispatch by is_active flag. Add acceptance tests for play/pause behavior.
Trigger scheduling and cron
api/oss/src/crons/triggers.sh, api/oss/src/crons/triggers.txt, api/pyproject.toml, api/oss/tests/pytest/acceptance/triggers/test_triggers_schedules.py
Add cron scripts to invoke schedule refresh endpoint every minute. Add croniter dependency for cron validation. Define schedule CRUD with cron validation via croniter. Add acceptance tests for schedule lifecycle, cron validation, active/pause toggling.
Triggers permissions (EE)
api/ee/src/core/access/permissions/types.py
Add VIEW_TRIGGERS, EDIT_TRIGGERS, RUN_TRIGGERS permissions to EE permission catalog. Map to VIEWER, ANNOTATOR, EDITOR roles respectively.
Frontend: gateway-trigger entities
web/packages/agenta-entities/src/gatewayTrigger/*
Add complete frontend entity layer: Zod-based type definitions, API HTTP wrappers with axios, Jotai atoms/hooks for catalog, connections, subscriptions, schedules, deliveries, drawer state. Include cursor-based pagination, search support, delivery dedup tracking.
Frontend: gateway-trigger UI
web/packages/agenta-entity-ui/src/gatewayTrigger/*
Add three drawer components: TriggerCatalogDrawer for browsing integrations/events, TriggerConnectDrawer for OAuth authorization, TriggerSubscriptionDrawer for creating/editing subscriptions with schema form, TriggerDeliveriesDrawer for audit logs. Include trigger events list, subscription list, schedule list pages with CRUD and start/stop controls.
Frontend: settings UI
web/oss/src/components/pages/settings/Triggers/*, web/oss/src/components/Sidebar/SettingsSidebar.tsx, web/oss/src/pages/.../settings/index.tsx
Add Triggers settings tab with sections for connections (browser/provider list), subscriptions (CRUD + start/stop), schedules (CRUD + start/stop), deliveries audit view. Wire drawer state and action handlers. Add Lightning icon and sidebar menu entry.
Frontend: gateway-tool renaming
web/packages/agenta-entities/src/gatewayTool/*, web/packages/agenta-entity-ui/src/gatewayTool/*, web/oss/src/components/.../Tools/*, web/oss/src/components/DrillInView/OSSdrillInUIProvider.tsx, web/oss/src/components/Playground/.../GatewayToolsPanel.tsx
Rename all gateway-tool entity exports and hooks from non-prefixed (fetchProviders, useCatalogIntegrations) to tool* variants (fetchToolProviders, useToolCatalogIntegrations). Update all consumers to use new names, including drawer atoms and query families. Trigger and tools share connection queries via invalidateConnections cache invalidation.
Frontend: webhook renaming
web/oss/src/services/webhooks/types.ts, web/oss/src/state/webhooks/*, web/oss/src/components/Webhooks/*, web/oss/src/styles/globals.css, web/_reference/agenta-sdk/src/types.ts
Rename AutomationProviderWebhookProvider, automation form types to webhook form types. Rename atom names from automation to webhook. Rename schema constants and UI component exports (AutomationFieldRendererWebhookFieldRenderer, AutomationLogsTabWebhookLogsTab). Update cache keys and drawer state. Update CSS table selectors from .automations-table to .webhooks-table.
Resolver promotion to SDK
sdks/python/agenta/sdk/utils/resolvers.py, api/oss/src/core/webhooks/delivery.py, api/oss/tests/pytest/unit/webhooks/test_webhooks_tasks.py, sdks/python/oss/tests/pytest/unit/test_resolvers.py
Move resolve_payload_fields from webhooks module to SDK as resolve_target_fields with MAX_RESOLVE_DEPTH. Update webhooks delivery to call SDK resolver. Update test imports and patch targets. Add comprehensive resolver unit tests.
Composio error handling
api/oss/src/core/gateway/providers/composio/errors.py, api/oss/src/apis/fastapi/tools/router.py
Add composio_error_detail formatter for Composio HTTP errors. Extend handle_adapter_exceptions decorator to map ProviderNotFoundError to 404, upstream 5xx to 502, other AdapterError to 424.
Database and auth
api/oss/src/middlewares/auth.py, api/oss/utils/env.py
Add trigger ingress endpoints to public auth allowlist. Add COMPOSIO_WEBHOOK_TARGET and COMPOSIO_WEBHOOK_URL env vars to ComposioConfig.
Tests: acceptance
api/oss/tests/pytest/acceptance/triggers/*.py, api/ee/tests/pytest/acceptance/triggers/*.py, api/ee/tests/pytest/acceptance/tools/test_tools_connections.py, api/oss/tests/pytest/acceptance/tools/test_tools_connections.py, api/oss/tests/pytest/acceptance/webhooks/test_webhooks_basics.py
Add acceptance test suites for triggers catalog, subscriptions, deliveries, connections, ingress signature verification, deduplication. Add webhook start/stop tests. Add cross-surface visibility tests for shared connections. Gate live-API tests on COMPOSIO_API_KEY.
Tests: unit
api/oss/tests/pytest/unit/triggers/test_triggers_dispatcher.py, api/oss/tests/pytest/unit/triggers/test_triggers_signature.py, sdks/python/oss/tests/pytest/unit/test_resolvers.py, api/oss/tests/pytest/unit/services/test_db_manager.py, api/oss/tests/pytest/unit/models/test_lifecycle_conventions.py, api/pytest.ini, web/packages/agenta-entities/tests/unit/gatewayTriggerApi.test.ts
Add dispatcher unit tests for inactive/invalid entities, deduplication, workflow failures. Add HMAC signature verification tests with secret refresh retry. Add resolver recursion/depth/error tests. Update workspace-selection test to ignore owner role. Register gateway connections DBEs in lifecycle tests. Add pytest deprecation filter. Add frontend API boundary validation tests.
Tests: manual
api/oss/tests/manual/triggers/try_composio_triggers.py
Add manual test script for Composio trigger catalog, instances, subscriptions, event watching, webhook management, and secret convergence under concurrent load.
Docker and runtime
hosting/docker-compose/*/docker-compose*.yml, hosting/docker-compose/run.sh, api/ee/docker/Dockerfile.*, api/oss/docker/Dockerfile.*
Add worker-triggers service to dev/production compose stacks. Add optional Composio tunnel service (with-tunnel profile). Add triggers.sh/triggers.txt cron scripts to Dockerfiles. Update run.sh to support --no-tunnel option and default WITH_TUNNEL=true.
Design and planning
AGENTS.md, docs/designs/gateway-triggers/*
Expand AGENTS.md with GitButler but push/absorb rules, lane-scoped commit semantics, stacked-edits handling, PR-base configuration, and local dev loop (load-env, deploy, py-run-tests, Postgres setup, ephemeral account creation). Add comprehensive design docs: proposal, research, mimics/contrasts, plan, gap analysis, mapping, work lanes runbook, and 6+ work-package specs/status plus schedules extension docs and orchestration guide.
Miscellaneous
web/packages/agenta-entities/package.json, web/packages/agenta-entity-ui/package.json, web/oss/src/components/pages/settings/APIKeys/APIKeys.tsx, web/packages/agenta-entities/src/index.ts
Add gatewayTrigger subpath exports to entity/entity-ui packages. Update API key button label. Update subpath import comments in index files.

Sequence Diagram(s)

sequenceDiagram
  participant Composio as Composio<br/>(Provider)
  participant Ingress as TriggersRouter<br/>(HTTP Ingress)
  participant Worker as TriggersWorker<br/>(TaskIQ)
  participant Dispatcher as TriggersDispatcher<br/>(Asyncio)
  participant Workflows as WorkflowsService<br/>(Invocation)
  participant DAO as TriggersDAO<br/>(Persistence)

  Composio->>Ingress: POST /triggers/composio/events/<br/>(signed event envelope)
  
  Ingress->>Ingress: verify HMAC signature
  Ingress->>Ingress: extract metadata.trigger_id
  
  Ingress->>Worker: enqueue(trigger_id, event_id, event)
  Ingress-->>Composio: 202 Accepted
  
  Worker->>DAO: get_project_and_subscription_by_trigger_id
  DAO-->>Worker: (project_id, subscription)
  
  Worker->>Dispatcher: dispatch(project_id, entity, event_id, event)
  
  Dispatcher->>Dispatcher: check entity.flags.is_active
  Dispatcher->>Dispatcher: dedup_seen(event_id)
  Dispatcher->>Workflows: invoke_workflow(...)
  
  Workflows-->>Dispatcher: response (status, outputs)
  
  Dispatcher->>DAO: write_delivery(TriggerDeliveryCreate)
  DAO-->>Dispatcher: delivery persisted
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • Agenta-AI/agenta#4338: This PR also refactors gateway-tools exports to use tool* naming and updates consumer hooks/atoms to match the renamed entity layer.
  • Agenta-AI/agenta#4543: This PR builds upon the AGENTS.md restructuring from #4543, further expanding GitButler workflow guidance and local dev loop documentation.
  • Agenta-AI/agenta#4748: This PR also updates the get_default_workspace_id test in test_db_manager.py to change expected behavior regarding role prioritization.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.90% which is insufficient. The required threshold is 60.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The pull request lacks an author-provided description but includes detailed objectives that explain the changeset comprehensively. Add a pull request description that briefly summarizes the changes and their purpose, referencing the provided PR objectives.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title '[feat] Add triggers (connections, subscriptions, schedules)' directly summarizes the main feature being added—a comprehensive triggers system with three core components (connections, subscriptions, schedules). It is specific, concise, and clearly communicates the primary change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gateway-triggers-all

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-production-55d1.up.railway.app/w
Project agenta-oss-pr-4749
Image tag pr-4749-699ac3a
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-06-22T14:37:36.022Z

get_default_workspace_id no longer prefers owner-role (multi-org: an invitee owns their own empty personal workspace). Assert oldest membership wins regardless of role.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…g in tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
api/ee/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py (1)

182-227: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guarantee connection cleanup even on test failure.

If any assertion fails before Line 226, the connection cleanup is skipped, which can leak external/provider state and make later acceptance runs flaky. Move cleanup to a finally block and assert the delete response.

Suggested fix
 def test_create_list_disable_delete_keeps_connection(self, triggers_api):
     connection_id = self._create_connection(triggers_api)
-
-    create = triggers_api(
-        "POST",
-        "/triggers/subscriptions/",
-        json={
-            "subscription": {
-                "name": f"sub-{uuid4().hex[:8]}",
-                "connection_id": connection_id,
-                "data": {
-                    "event_key": "GITHUB_STAR_ADDED_EVENT",
-                    "trigger_config": {},
-                    "inputs_fields": {"repo": "$.event.data.repository"},
-                    "references": {"workflow": {"slug": "triage"}},
-                },
-            }
-        },
-    )
-    assert create.status_code == 200, create.text
-    sub = create.json()["subscription"]
-    subscription_id = sub["id"]
-    assert sub["connection_id"] == connection_id
-    assert sub["data"]["ti_id"] is not None
-
-    listing = triggers_api("GET", "/triggers/subscriptions/").json()
-    assert any(s["id"] == subscription_id for s in listing["subscriptions"])
-
-    revoke = triggers_api(
-        "POST", f"/triggers/subscriptions/{subscription_id}/revoke"
-    )
-    assert revoke.status_code == 200, revoke.text
-    assert revoke.json()["subscription"]["enabled"] is False
-
-    delete = triggers_api("DELETE", f"/triggers/subscriptions/{subscription_id}")
-    assert delete.status_code == 204
-
-    fetch = triggers_api("GET", f"/triggers/subscriptions/{subscription_id}")
-    assert fetch.status_code == 404
-
-    # C7: deleting the subscription must NOT delete/revoke the connection.
-    conn = triggers_api("GET", f"/tools/connections/{connection_id}")
-    assert conn.status_code == 200, conn.text
-
-    triggers_api("DELETE", f"/tools/connections/{connection_id}")
+    try:
+        create = triggers_api(
+            "POST",
+            "/triggers/subscriptions/",
+            json={
+                "subscription": {
+                    "name": f"sub-{uuid4().hex[:8]}",
+                    "connection_id": connection_id,
+                    "data": {
+                        "event_key": "GITHUB_STAR_ADDED_EVENT",
+                        "trigger_config": {},
+                        "inputs_fields": {"repo": "$.event.data.repository"},
+                        "references": {"workflow": {"slug": "triage"}},
+                    },
+                }
+            },
+        )
+        assert create.status_code == 200, create.text
+        sub = create.json()["subscription"]
+        subscription_id = sub["id"]
+        assert sub["connection_id"] == connection_id
+        assert sub["data"]["ti_id"] is not None
+
+        listing = triggers_api("GET", "/triggers/subscriptions/").json()
+        assert any(s["id"] == subscription_id for s in listing["subscriptions"])
+
+        revoke = triggers_api("POST", f"/triggers/subscriptions/{subscription_id}/revoke")
+        assert revoke.status_code == 200, revoke.text
+        assert revoke.json()["subscription"]["enabled"] is False
+
+        delete = triggers_api("DELETE", f"/triggers/subscriptions/{subscription_id}")
+        assert delete.status_code == 204
+
+        fetch = triggers_api("GET", f"/triggers/subscriptions/{subscription_id}")
+        assert fetch.status_code == 404
+
+        conn = triggers_api("GET", f"/tools/connections/{connection_id}")
+        assert conn.status_code == 200, conn.text
+    finally:
+        cleanup = triggers_api("DELETE", f"/tools/connections/{connection_id}")
+        assert cleanup.status_code == 204, cleanup.text
api/oss/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py (1)

108-156: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make lifecycle cleanup unconditional.

Cleanup at Line 155 only runs on the happy path. A mid-test failure leaves shared connection state behind, which can pollute subsequent acceptance runs. Move deletion to finally and assert cleanup success.

Suggested fix
 def test_create_list_disable_delete_keeps_connection(self, authed_api):
     connection_id = self._create_connection(authed_api)
-
-    # CREATE — binds the event to a workflow reference on the shared connection
-    create = authed_api(
-        "POST",
-        "/triggers/subscriptions/",
-        json={
-            "subscription": {
-                "name": f"sub-{uuid4().hex[:8]}",
-                "connection_id": connection_id,
-                "data": {
-                    "event_key": "GITHUB_STAR_ADDED_EVENT",
-                    "trigger_config": {},
-                    "inputs_fields": {"repo": "$.event.data.repository"},
-                    "references": {"workflow": {"slug": "triage"}},
-                },
-            }
-        },
-    )
-    assert create.status_code == 200, create.text
-    sub = create.json()["subscription"]
-    subscription_id = sub["id"]
-    assert sub["connection_id"] == connection_id
-    assert sub["data"]["ti_id"] is not None
-    assert sub["enabled"] is True
-
-    # LIST
-    listing = authed_api("GET", "/triggers/subscriptions/").json()
-    assert any(s["id"] == subscription_id for s in listing["subscriptions"])
-
-    # DISABLE (revoke the subscription, not the connection)
-    revoke = authed_api("POST", f"/triggers/subscriptions/{subscription_id}/revoke")
-    assert revoke.status_code == 200, revoke.text
-    assert revoke.json()["subscription"]["enabled"] is False
-
-    # DELETE
-    delete = authed_api("DELETE", f"/triggers/subscriptions/{subscription_id}")
-    assert delete.status_code == 204
-
-    fetch = authed_api("GET", f"/triggers/subscriptions/{subscription_id}")
-    assert fetch.status_code == 404
-
-    # C7: deleting the subscription must NOT delete/revoke the connection.
-    conn = authed_api("GET", f"/tools/connections/{connection_id}")
-    assert conn.status_code == 200, conn.text
-
-    authed_api("DELETE", f"/tools/connections/{connection_id}")
+    try:
+        create = authed_api(
+            "POST",
+            "/triggers/subscriptions/",
+            json={
+                "subscription": {
+                    "name": f"sub-{uuid4().hex[:8]}",
+                    "connection_id": connection_id,
+                    "data": {
+                        "event_key": "GITHUB_STAR_ADDED_EVENT",
+                        "trigger_config": {},
+                        "inputs_fields": {"repo": "$.event.data.repository"},
+                        "references": {"workflow": {"slug": "triage"}},
+                    },
+                }
+            },
+        )
+        assert create.status_code == 200, create.text
+        sub = create.json()["subscription"]
+        subscription_id = sub["id"]
+        assert sub["connection_id"] == connection_id
+        assert sub["data"]["ti_id"] is not None
+        assert sub["enabled"] is True
+
+        listing = authed_api("GET", "/triggers/subscriptions/").json()
+        assert any(s["id"] == subscription_id for s in listing["subscriptions"])
+
+        revoke = authed_api("POST", f"/triggers/subscriptions/{subscription_id}/revoke")
+        assert revoke.status_code == 200, revoke.text
+        assert revoke.json()["subscription"]["enabled"] is False
+
+        delete = authed_api("DELETE", f"/triggers/subscriptions/{subscription_id}")
+        assert delete.status_code == 204
+
+        fetch = authed_api("GET", f"/triggers/subscriptions/{subscription_id}")
+        assert fetch.status_code == 404
+
+        conn = authed_api("GET", f"/tools/connections/{connection_id}")
+        assert conn.status_code == 200, conn.text
+    finally:
+        cleanup = authed_api("DELETE", f"/tools/connections/{connection_id}")
+        assert cleanup.status_code == 204, cleanup.text
docs/designs/gateway-triggers/proposal.md (1)

285-289: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the empty quoted line.

The blank > line before the next heading trips MD028 and will keep docs lint failing.

As per the markdownlint hint, this blockquote needs to stay contiguous.

🛠️ Proposed fix
 > **Consequence — cross-domain revoke.** Because `ca_*` is shared, revoking it affects
 > both tools actions and trigger subscriptions on it. Lean: revoke-for-everyone + show
 > usage; deleting a subscription must not revoke the connection. Connect once, used
 > everywhere — the inverse of the connect-twice cost that rejected option B carried.
->
 
 ### The workflow dispatch seam

Source: Linters/SAST tools

🟡 Minor comments (16)
web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerSubscriptions.ts-54-58 (1)

54-58: ⚠️ Potential issue | 🟡 Minor

Gate loading state for empty connectionId to match the pattern in useTriggerDeliveries.

Line 57 exposes loading while the query is disabled. When connectionId is empty, the query is disabled (enabled: !!connectionId at line 42) but isLoading still reflects query.isPending. Apply the same gating pattern used in useTriggerDeliveries to return false when the query is disabled:

Suggested fix
     return {
         subscriptions,
         count: query.data?.count ?? 0,
-        isLoading: query.isPending,
+        isLoading: connectionId ? query.isPending : false,
         error: query.error,
     }
 }
web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerConnections.ts-60-64 (1)

60-64: ⚠️ Potential issue | 🟡 Minor

Gate loading state when integrationKey is empty.

Line 63 can surface a loading state even when the query is intentionally disabled (line 48). Mirror the useTriggerDeliveries hook pattern and gate isLoading by the input key.

Suggested fix
 export const useTriggerIntegrationConnections = (integrationKey: string) => {
     const query = useAtomValue(triggerIntegrationConnectionsAtomFamily(integrationKey))

     const connections = useMemo<TriggerConnection[]>(
         () => query.data?.connections ?? [],
         [query.data?.connections],
     )

     return {
         connections,
         count: query.data?.count ?? 0,
-        isLoading: query.isPending,
+        isLoading: integrationKey ? query.isPending : false,
         error: query.error,
     }
 }
web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerEvent.ts-32-35 (1)

32-35: ⚠️ Potential issue | 🟡 Minor

Make isLoading conditional on both required keys.

Line 34 should be gated by integrationKey and eventKey so consumers don't get a loading signal when the query is disabled due to missing prerequisites.

Suggested fix
     return {
         event: query.data?.event ?? null,
-        isLoading: query.isPending,
+        isLoading: integrationKey && eventKey ? query.isPending : false,
         error: query.error,
     }
 }
web/oss/src/components/pages/settings/Triggers/components/GatewaySubscriptionsSection.tsx-248-248 (1)

248-248: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid non-unique rowKey fallback.

Line 248 can return "", which can produce duplicate keys and unstable row identity when multiple records miss these fields.

Suggested fix
-                    rowKey={(record) => record.id ?? record.slug ?? record.data?.event_key ?? ""}
+                    rowKey={(record) =>
+                        record.id ??
+                        record.slug ??
+                        `${record.connection_id ?? "unknown"}:${record.data?.event_key ?? "unknown"}:${record.created_at ?? "unknown"}`
+                    }
web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerSubscriptionDrawer.tsx-97-100 (1)

97-100: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Edit prefill uses raw workflow revision ID as UI label

Line 99 sets workflowLabel to the revision ID, so edit mode can display an opaque ID instead of the workflow display name/version format used elsewhere.

As per coding guidelines, display workflow names via workflowMolecule.selectors.artifactName(entityId) and use the prescribed label rules for workflow/variant naming.

Source: Coding guidelines

web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerDeliveriesDrawer.tsx-51-55 (1)

51-55: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Status tag color ignores the status-code fallback

Line 51 already falls back to status.code, but Line 54 colors using status.type only. Code-only statuses can display the wrong semantic color.

Suggested fix
-const type = record.status?.type ?? record.status?.code
+const type = record.status?.type ?? record.status?.code
 return (
     <Tooltip title={record.status?.message ?? undefined}>
-        <Tag color={statusColor(record.status?.type)}>{type ?? "unknown"}</Tag>
+        <Tag color={statusColor(type)}>{type ?? "unknown"}</Tag>
     </Tooltip>
 )
web/oss/src/components/pages/settings/Triggers/components/GatewayTriggersSection.tsx-56-57 (1)

56-57: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Name column can render blank for valid rows

Line 56 falls back to slug, but if both name and slug are absent the cell is empty. Add integration_key as final fallback so every row remains identifiable.

Suggested fix
-<Typography.Text>{record.name || record.slug}</Typography.Text>
+<Typography.Text>{record.name || record.slug || record.integration_key}</Typography.Text>
web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerSubscriptionDrawer.tsx-138-146 (1)

138-146: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject non-object JSON for inputs_fields

Line 140 accepts any valid JSON (including arrays/primitives), but inputs_fields is expected to be an object map. This can produce contract failures downstream.

Suggested fix
 let inputsFields: Record<string, unknown> = {}
 try {
-    inputsFields = inputsText.trim() ? JSON.parse(inputsText) : {}
+    const parsed = inputsText.trim() ? JSON.parse(inputsText) : {}
+    if (parsed === null || Array.isArray(parsed) || typeof parsed !== "object") {
+        throw new Error("Inputs mapping must be a JSON object")
+    }
+    inputsFields = parsed as Record<string, unknown>
     setInputsError(null)
 } catch {
     setInputsError("Invalid JSON")
     message.error("inputs mapping is not valid JSON")
     return
 }
api/oss/src/core/gateway/connections/dtos.py-112-118 (1)

112-118: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use enum typing for ConnectionRequest.auth_scheme to keep validation consistent.

ConnectionCreateData.auth_scheme is enum-validated, but ConnectionRequest.auth_scheme is a plain str, which lets invalid schemes bypass early validation and fail later in adapter calls.

🔧 Proposed fix
 class ConnectionRequest(BaseModel):
@@
-    auth_scheme: Optional[str] = None
+    auth_scheme: Optional[ConnectionAuthScheme] = None
api/oss/src/apis/fastapi/triggers/router.py-376-377 (1)

376-377: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate limit at the API boundary.

Line 376 allows invalid values (e.g., 0 or negative), which can propagate upstream and surface as adapter failures instead of a clean client validation error.

Suggested fix
-        limit: Optional[int] = Query(default=None),
+        limit: Optional[int] = Query(default=None, ge=1, le=1000),
docs/designs/gateway-triggers/wp/WP4-specs.md-20-25 (1)

20-25: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update WP4 ACK semantics from 200 to 202.

Line 22 and Line 54 document 200 for no-op/unset-secret, but this PR’s ingress contract is 202 Accepted. Keeping 200 here creates avoidable contract drift.

Suggested doc fix
-- HMAC-SHA256 verify over `{id}.{ts}.{body}` with `COMPOSIO_WEBHOOK_SECRET`; 401 bad sig;
-  200 no-op when secret unset; add `COMPOSIO_WEBHOOK_SECRET` to `env`.
+- HMAC-SHA256 verify over `{id}.{ts}.{body}` with `COMPOSIO_WEBHOOK_SECRET`; 401 bad sig;
+  202 no-op when secret unset; add `COMPOSIO_WEBHOOK_SECRET` to `env`.
@@
-- Forged signature → 401; unset secret → 200 no-op.
+- Forged signature → 401; unset secret → 202 no-op.

Also applies to: 54-55

docs/designs/gateway-triggers/wp/WP4-status.md-7-25 (1)

7-25: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Refresh WP4 status to match implemented work.

The document still marks WP4 as NOT STARTED, but this stack includes ingress, dispatch runtime, worker wiring, and tests. This stale status will confuse follow-on planning.

docs/designs/gateway-triggers/wp/WP0-status.md-15-18 (1)

15-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align the connection path spelling.

This status file still uses the flat core/connections / dbs/postgres/connections names, but the spec and implementation cohort use the gateway/ subpaths. Keeping both spellings will send the next lane to the wrong package.

Based on the stack context, this PR already uses core/gateway/connections/ and dbs/postgres/gateway/connections/.

🛠️ Suggested alignment
- [x] `core/connections/` service + DAO interface + `ConnectionsService` + `ConnectionsGatewayInterface`
+ [x] `core/gateway/connections/` service + DAO interface + `ConnectionsService` + `ConnectionsGatewayInterface`

- [x] `dbs/postgres/connections/` DBE + DAO + mappings
+ [x] `dbs/postgres/gateway/connections/` DBE + DAO + mappings

Also applies to: 50-59

docs/designs/gateway-triggers/wp/WL-runbook.md-128-154 (1)

128-154: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Label the markdown example fence.

The unlabeled fence trips MD040; md is sufficient here.

As per the markdownlint hint, the docs PR body example needs a language tag.

🛠️ Proposed fix
-```
+```md

Source: Linters/SAST tools

docs/designs/gateway-triggers/wp/WP1-status.md-41-42 (1)

41-42: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Permission note conflicts with the WP1 frozen contract.

This says no VIEW_TRIGGERS and reuses VIEW_TOOLS, but WP1 specs freeze the opposite rule. Please reconcile this to avoid implementer confusion on authorization behavior.

docs/designs/gateway-triggers/wp/WP2-specs.md-29-33 (1)

29-33: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Frozen resolver return type is too narrow.

The spec locks -> dict, but current trigger dispatch logic already handles scalar/non-dict results from resolve_target_fields. Please widen the contract wording to avoid future mismatches.

🧹 Nitpick comments (9)
web/packages/agenta-entities/src/gatewayTrigger/api/client.ts (1)

5-19: ⚡ Quick win

Trim block comments to “why”-only notes.

These docblocks narrate implementation details (“what”) across many lines; please reduce to terse invariant-level comments only, or rely on naming/extraction.

As per coding guidelines, “Keep AI-generated in-code comments minimal; comment only the non-obvious why, never the what.”

Source: Coding guidelines

web/packages/agenta-entities/src/gatewayTrigger/api/api.ts (1)

1-12: ⚡ Quick win

Reduce explanatory prose comments in this module.

The section/header comments mostly restate behavior; please keep only short “why” notes where needed.

As per coding guidelines, comments should be minimal and explain non-obvious rationale, not implementation narration.

Also applies to: 42-42, 111-111, 133-133, 243-243

Source: Coding guidelines

web/packages/agenta-entities/tests/unit/gatewayTriggerApi.test.ts (1)

1-14: ⚡ Quick win

Shorten the top-of-file comment block.

Please keep only the non-obvious invariant/intent and drop step-by-step prose.

As per coding guidelines, comments should be terse and explain “why,” not narrate “what.”

Source: Coding guidelines

web/packages/agenta-entity-ui/src/gatewayTrigger/index.ts (1)

1-8: ⚡ Quick win

Condense the module docblock to a one-liner (or remove).

Current block explains behavior in detail; this can be inferred from exports and naming.

As per coding guidelines, keep in-code comments minimal and focused on subtle “why” context only.

Source: Coding guidelines

web/packages/agenta-entities/src/gatewayTrigger/core/types.ts (1)

1-15: ⚡ Quick win

Trim non-obvious-comment blocks to terse intent notes only.

These large narrative blocks describe what and migration context; please reduce to minimal “why” comments (or rely on symbol names/module docs) to match repo standards.

As per coding guidelines, “Keep AI-generated in-code comments minimal; comment only the non-obvious why … never the what.”

Also applies to: 90-95, 134-140, 235-239

Source: Coding guidelines

web/packages/agenta-entities/src/gatewayTrigger/hooks/useCatalogEvents.ts (1)

14-16: ⚡ Quick win

Unify catalog-search atom ownership to avoid split state.

eventsSearchAtom here overlaps conceptually with eventSearchAtom in state/atoms.ts; keeping two similarly named atoms for the same concern invites accidental desync across consumers. Prefer exporting one shared atom from a single module and reusing it here.

api/oss/tests/pytest/acceptance/triggers/test_triggers_ingress.py (1)

151-163: ⚡ Quick win

Make the dedup assertion deterministic and cleanup-safe.

Line 151 currently allows a false positive (<= 1) when the async dispatcher hasn’t written any row yet. Poll for completion (bounded) and then assert exactly one delivery; also run cleanup in finally with response checks.

Proposed test hardening
+from time import sleep
@@
-        # The dispatch is async; the dedup guard means at most one delivery row
-        # exists for this (subscription, event_id).
-        deliveries = authed_api(
-            "POST",
-            "/triggers/deliveries/query",
-            json={
-                "delivery": {"subscription_id": subscription_id, "event_id": event_id}
-            },
-        ).json()["deliveries"]
-        assert len(deliveries) <= 1
-
-        authed_api("DELETE", f"/triggers/subscriptions/{subscription_id}")
-        authed_api("DELETE", f"/tools/connections/{connection_id}")
+        try:
+            deliveries = []
+            for _ in range(20):
+                query = authed_api(
+                    "POST",
+                    "/triggers/deliveries/query",
+                    json={
+                        "delivery": {"subscription_id": subscription_id, "event_id": event_id}
+                    },
+                )
+                assert query.status_code == 200, query.text
+                deliveries = query.json()["deliveries"]
+                if deliveries:
+                    break
+                sleep(0.25)
+
+            assert len(deliveries) == 1
+        finally:
+            delete_sub = authed_api("DELETE", f"/triggers/subscriptions/{subscription_id}")
+            assert delete_sub.status_code in (200, 204), delete_sub.text
+            delete_conn = authed_api("DELETE", f"/tools/connections/{connection_id}")
+            assert delete_conn.status_code in (200, 204), delete_conn.text
api/oss/tests/pytest/unit/triggers/test_triggers_dispatcher.py (1)

129-149: ⚡ Quick win

Add coverage for the raised-exception branch in dispatch.

Current tests validate non-200 responses, but not the invoke_workflow exception path that should write a failed delivery and re-raise.

Suggested additional unit test
+import pytest
@@
 async def test_workflow_non_200_writes_failed_delivery():
@@
     assert delivery.status.code == "500"
+
+
+async def test_workflow_exception_writes_failed_delivery_and_reraises():
+    project_id = uuid4()
+    reference = Reference(slug="wf-1")
+    subscription = _make_subscription(references={"workflow": reference})
+    dao = _make_dao(resolved=(project_id, subscription))
+
+    workflows = MagicMock()
+    workflows.invoke_workflow = AsyncMock(side_effect=RuntimeError("boom"))
+    dispatcher = TriggersDispatcher(triggers_dao=dao, workflows_service=workflows)
+
+    with pytest.raises(RuntimeError, match="boom"):
+        await dispatcher.dispatch(trigger_id="ti_1", event_id="e1", event=_EVENT)
+
+    dao.write_delivery.assert_awaited_once()
+    delivery = dao.write_delivery.await_args.kwargs["delivery"]
+    assert delivery.status.code == "500"
api/oss/src/tasks/asyncio/triggers/dispatcher.py (1)

1-9: ⚡ Quick win

Trim narrative comments to “why-only” comments.

Several comments/docstrings here narrate behavior rather than a non-obvious invariant. Please reduce these to terse “why” notes (or rely on naming/extraction).

As per coding guidelines, "Keep AI-generated in-code comments minimal; comment only the non-obvious why ... never the what."

Also applies to: 109-130

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bb4b1c2d-a35f-4d60-ab97-8083ce9d0008

📥 Commits

Reviewing files that changed from the base of the PR and between a97e608 and f606d7a.

📒 Files selected for processing (125)
  • AGENTS.md
  • api/ee/src/core/access/permissions/types.py
  • api/ee/tests/pytest/acceptance/tools/__init__.py
  • api/ee/tests/pytest/acceptance/tools/test_tools_connections.py
  • api/ee/tests/pytest/acceptance/triggers/__init__.py
  • api/ee/tests/pytest/acceptance/triggers/test_triggers_catalog.py
  • api/ee/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py
  • api/entrypoints/routers.py
  • api/entrypoints/worker_triggers.py
  • api/oss/databases/postgres/migrations/core_oss/versions/oss000000002_rename_tool_connections_to_gateway_connections.py
  • api/oss/databases/postgres/migrations/core_oss/versions/oss000000003_add_trigger_subscriptions_and_deliveries.py
  • api/oss/src/apis/fastapi/tools/models.py
  • api/oss/src/apis/fastapi/tools/router.py
  • api/oss/src/apis/fastapi/triggers/__init__.py
  • api/oss/src/apis/fastapi/triggers/models.py
  • api/oss/src/apis/fastapi/triggers/router.py
  • api/oss/src/core/gateway/__init__.py
  • api/oss/src/core/gateway/connections/__init__.py
  • api/oss/src/core/gateway/connections/dtos.py
  • api/oss/src/core/gateway/connections/exceptions.py
  • api/oss/src/core/gateway/connections/interfaces.py
  • api/oss/src/core/gateway/connections/providers/__init__.py
  • api/oss/src/core/gateway/connections/providers/composio/__init__.py
  • api/oss/src/core/gateway/connections/providers/composio/adapter.py
  • api/oss/src/core/gateway/connections/registry.py
  • api/oss/src/core/gateway/connections/service.py
  • api/oss/src/core/gateway/connections/utils.py
  • api/oss/src/core/tools/dtos.py
  • api/oss/src/core/tools/interfaces.py
  • api/oss/src/core/tools/providers/composio/adapter.py
  • api/oss/src/core/tools/service.py
  • api/oss/src/core/triggers/__init__.py
  • api/oss/src/core/triggers/dtos.py
  • api/oss/src/core/triggers/exceptions.py
  • api/oss/src/core/triggers/interfaces.py
  • api/oss/src/core/triggers/providers/__init__.py
  • api/oss/src/core/triggers/providers/composio/__init__.py
  • api/oss/src/core/triggers/providers/composio/adapter.py
  • api/oss/src/core/triggers/providers/composio/catalog.py
  • api/oss/src/core/triggers/registry.py
  • api/oss/src/core/triggers/service.py
  • api/oss/src/core/webhooks/delivery.py
  • api/oss/src/dbs/postgres/gateway/__init__.py
  • api/oss/src/dbs/postgres/gateway/connections/__init__.py
  • api/oss/src/dbs/postgres/gateway/connections/dao.py
  • api/oss/src/dbs/postgres/gateway/connections/dbes.py
  • api/oss/src/dbs/postgres/gateway/connections/mappings.py
  • api/oss/src/dbs/postgres/triggers/__init__.py
  • api/oss/src/dbs/postgres/triggers/dao.py
  • api/oss/src/dbs/postgres/triggers/dbas.py
  • api/oss/src/dbs/postgres/triggers/dbes.py
  • api/oss/src/dbs/postgres/triggers/mappings.py
  • api/oss/src/middlewares/auth.py
  • api/oss/src/tasks/asyncio/triggers/__init__.py
  • api/oss/src/tasks/asyncio/triggers/dispatcher.py
  • api/oss/src/tasks/taskiq/triggers/__init__.py
  • api/oss/src/tasks/taskiq/triggers/worker.py
  • api/oss/src/utils/env.py
  • api/oss/tests/pytest/acceptance/tools/test_tools_connections.py
  • api/oss/tests/pytest/acceptance/triggers/__init__.py
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_catalog.py
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_ingress.py
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py
  • api/oss/tests/pytest/unit/models/test_lifecycle_conventions.py
  • api/oss/tests/pytest/unit/triggers/__init__.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_dispatcher.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_signature.py
  • api/oss/tests/pytest/unit/webhooks/test_webhooks_tasks.py
  • docs/designs/gateway-triggers/gap.md
  • docs/designs/gateway-triggers/mapping.md
  • docs/designs/gateway-triggers/mimics.md
  • docs/designs/gateway-triggers/plan.md
  • docs/designs/gateway-triggers/proposal.md
  • docs/designs/gateway-triggers/research.md
  • docs/designs/gateway-triggers/wp/WL-runbook.md
  • docs/designs/gateway-triggers/wp/WP0-specs.md
  • docs/designs/gateway-triggers/wp/WP0-status.md
  • docs/designs/gateway-triggers/wp/WP1-specs.md
  • docs/designs/gateway-triggers/wp/WP1-status.md
  • docs/designs/gateway-triggers/wp/WP2-specs.md
  • docs/designs/gateway-triggers/wp/WP2-status.md
  • docs/designs/gateway-triggers/wp/WP3-specs.md
  • docs/designs/gateway-triggers/wp/WP3-status.md
  • docs/designs/gateway-triggers/wp/WP4-specs.md
  • docs/designs/gateway-triggers/wp/WP4-status.md
  • docs/designs/gateway-triggers/wp/WP5-specs.md
  • docs/designs/gateway-triggers/wp/WP5-status.md
  • docs/designs/gateway-triggers/wp/WP6-specs.md
  • docs/designs/gateway-triggers/wp/WP6-status.md
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • sdks/python/agenta/sdk/utils/resolvers.py
  • sdks/python/oss/tests/pytest/unit/test_resolvers.py
  • web/oss/src/components/Sidebar/SettingsSidebar.tsx
  • web/oss/src/components/pages/settings/Triggers/Triggers.tsx
  • web/oss/src/components/pages/settings/Triggers/components/GatewaySubscriptionsSection.tsx
  • web/oss/src/components/pages/settings/Triggers/components/GatewayTriggersSection.tsx
  • web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx
  • web/packages/agenta-entities/package.json
  • web/packages/agenta-entities/src/gatewayTrigger/api/api.ts
  • web/packages/agenta-entities/src/gatewayTrigger/api/client.ts
  • web/packages/agenta-entities/src/gatewayTrigger/api/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/core/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/core/types.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useCatalogEvents.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerConnections.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerDeliveries.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerEvent.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerSubscription.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerSubscriptions.ts
  • web/packages/agenta-entities/src/gatewayTrigger/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/state/atoms.ts
  • web/packages/agenta-entities/src/gatewayTrigger/state/index.ts
  • web/packages/agenta-entities/tests/unit/gatewayTriggerApi.test.ts
  • web/packages/agenta-entity-ui/package.json
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerDeliveriesDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerEventsDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerSubscriptionDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/index.ts
💤 Files with no reviewable changes (1)
  • api/oss/src/core/tools/dtos.py

Comment thread api/oss/src/apis/fastapi/triggers/router.py Outdated
Comment thread api/oss/src/apis/fastapi/triggers/router.py Outdated
Comment thread api/oss/src/core/gateway/connections/interfaces.py Outdated
Comment thread api/oss/src/core/triggers/service.py
Comment thread api/oss/src/core/triggers/service.py
Comment thread api/oss/src/dbs/postgres/gateway/connections/dao.py Outdated
Comment thread api/oss/src/dbs/postgres/triggers/dao.py Outdated
Comment thread api/oss/src/dbs/postgres/triggers/mappings.py Outdated
Comment thread api/oss/src/tasks/asyncio/triggers/dispatcher.py
Comment thread web/packages/agenta-entities/src/gatewayTrigger/api/client.ts
Normalize the inbound provider envelope in the dispatcher into a stable
context (event.attributes + synthetic trigger_id/trigger_type/timestamp/
created_at), parallel to webhooks' event context. Resolve and complete the
bound workflow reference on subscription create/edit (the /deploy pattern) so
a variant id is resolved to a runnable revision. Align the drawer's mapping
suggestions + live preview to the same normalized shape.

Update trigger tests to the new shape and always-verify ingress; gate the
create-roundtrip acceptance tests on an ACTIVE connected account.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread api/oss/tests/manual/triggers/try_composio_triggers.py Dismissed
Comment thread api/oss/tests/manual/triggers/try_composio_triggers.py Dismissed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
web/packages/agenta-entity-ui/src/gatewayTool/drawers/ConnectDrawer.tsx (1)

80-90: ⚠️ Potential issue | 🔴 Critical

Drawer mutation flow misses trigger cache invalidation.

After createToolConnection, both mutation paths (lines 90 and 119) call invalidateConnections() which only invalidates tool caches. Because connections are shared between tools and triggers (stored in the same gateway_connections rows), the trigger connection queries remain stale. Compare with TriggerConnectDrawer, which correctly invalidates both surfaces.

Suggested fix
 const invalidateConnections = useCallback(() => {
     queryClient.invalidateQueries({queryKey: ["tools", "connections"]})
     queryClient.invalidateQueries({queryKey: ["tools", "catalog"]})
+    queryClient.invalidateQueries({queryKey: ["triggers", "connections"]})
 }, [])
web/oss/src/components/pages/settings/Tools/hooks/useToolsConnections.ts (1)

22-35: ⚠️ Potential issue | 🟠 Major

Invalidate trigger connection cache on tool-side mutations.

The invalidate() callback (lines 22–35) and its use in handleCreate (line 56–58), handleDelete, and handleRefresh only invalidate ["tools", ...] keys. Since tools and triggers share the same gateway_connections rows, trigger screens can display stale connection state after these mutations until an unrelated refetch occurs. Other files in the codebase (useToolConnectionActions.ts, useTriggerConnectionActions.ts) correctly invalidate both surfaces.

Suggested fix
 const invalidate = useCallback(() => {
     queryClient.invalidateQueries({
         queryKey: ["tools", "connections"],
     })
+    queryClient.invalidateQueries({
+        queryKey: ["triggers", "connections"],
+    })
 }, [integrationKey])
web/oss/src/styles/globals.css (1)

384-443: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

webhooks-table CSS rules appear disconnected from the rendered table.

These selectors only apply when the table (or an ancestor) has webhooks-table, but the provided Webhooks.tsx table markup doesn’t set that class. The column-width rules likely won’t take effect.

Suggested fix outside this file
-            <Table
+            <Table
+                className="webhooks-table"
                 columns={columns}
                 dataSource={webhooks ?? []}
                 loading={isLoading}
                 rowKey="id"
api/oss/src/apis/fastapi/triggers/router.py (1)

111-117: ⚠️ Potential issue | 🟠 Major

Support both /composio/events and /composio/events/ to prevent POST redirect failures.

FastAPI's default redirect_slashes=True issues HTTP 307 redirects when requests don't match the defined route's trailing-slash format. For POST webhook ingestion, some providers do not properly resend the request body after a 307 redirect, causing lost events.

Suggested fix
         self.router.add_api_route(
             "/composio/events/",
             self.ingest_composio_event,
             methods=["POST"],
             operation_id="ingest_composio_event",
             response_model=TriggerEventAck,
             status_code=status.HTTP_202_ACCEPTED,
         )
+        self.router.add_api_route(
+            "/composio/events",
+            self.ingest_composio_event,
+            methods=["POST"],
+            include_in_schema=False,
+        )
🧹 Nitpick comments (9)
api/ee/tests/pytest/acceptance/triggers/test_triggers_connections.py (1)

29-33: ⚡ Quick win

Use the shared API env object instead of os.getenv here.

This file introduces direct env access at Line 29; in API code/tests we should read config from the shared env object to keep config handling centralized.

Suggested change
-import os
+from oss.src.utils.env import env
...
-_COMPOSIO_ENABLED = bool(os.getenv("COMPOSIO_API_KEY"))
+_COMPOSIO_ENABLED = bool(env.composio.api_key)

As per coding guidelines: api/**/*.py: “Add new API environment variables to api/oss/src/utils/env.py and consume them via the shared env object instead of calling os.getenv(...) directly”.

Source: Coding guidelines

web/oss/src/components/Webhooks/WebhookDrawer.tsx (1)

58-67: ⚡ Quick win

Reuse a shared provider-detection helper instead of duplicating URL heuristics.

This edit path derives provider with inline hostname checks; the same concern is already handled elsewhere via shared helper logic. Consolidating avoids drift between pages.

hosting/docker-compose/ee/docker-compose.gh.local.yml (1)

516-545: 💤 Low value

Consider caching pip packages for faster container restarts.

The composio service runs pip install on every container start, which adds latency on restarts. For a dev-only tunnel service with restart: always, this is acceptable but could be optimized by building a custom image or using a volume-cached pip directory.

api/oss/src/core/triggers/utils.py (1)

45-68: 💤 Low value

Consider returning cached value on Composio failure instead of None.

When force_refresh=False and the cache is empty, if Composio fails (line 57-59), the method returns None. However, if there's a stale/expired cache entry that was evicted, users get no secret. Consider a fallback strategy or ensure callers handle None gracefully.

web/oss/src/services/webhooks/types.ts (1)

22-43: ⚡ Quick win

Split API payload types from draft form-state types.

WebhookFormValues currently models payload-style fields (event_types), while form consumers use draft fields (events, header_list), which is why downstream code needs as any. Define a dedicated draft type and use it in form-preview helpers to restore type safety.

Proposed direction
 interface WebhookFormValuesBase<P extends WebhookProvider = WebhookProvider> {
     provider: P
     name?: string
     event_types?: WebhookEventType[]
 }

+export interface WebhookDraftFields {
+    events?: WebhookEventType[]
+    header_list?: {key: string; value: string}[]
+}
+
 export interface WebhookConfigFormValues extends WebhookFormValuesBase<"webhook"> {
     url?: string
     headers?: Record<string, string>
     auth_mode?: "signature" | "authorization"
     auth_value?: string
 }

 export interface GitHubFormValues extends WebhookFormValuesBase<"github"> {
     github_sub_type?: GitHubDispatchType
     github_repo?: string
     github_pat?: string
     github_workflow?: string
     github_branch?: string
 }

 export type WebhookFormValues = WebhookConfigFormValues | GitHubFormValues
+export type WebhookDraftFormValues =
+    | (WebhookConfigFormValues & WebhookDraftFields)
+    | (GitHubFormValues & WebhookDraftFields)

Then type form-preview paths with WebhookDraftFormValues instead of WebhookFormValues.

web/packages/agenta-entities/src/gatewayTrigger/api/client.ts (1)

30-36: ⚡ Quick win

Trim this block comment to a one-line “why” note (or remove it).

The current comment narrates behavior that is already clear from the function body, which adds maintenance noise.

As per coding guidelines, “Keep AI-generated in-code comments minimal; comment only the non-obvious why … never the what.”

Source: Coding guidelines

api/oss/src/apis/fastapi/triggers/router.py (1)

136-159: 🏗️ Heavy lift

Use POST /query for searchable catalog list endpoints.

The new searchable/filterable catalog lists are exposed via GET query params; the router guideline requires query-style filtering via POST /query payload endpoints.

As per coding guidelines, “api/oss/src/apis/fastapi/**/router.py: Use POST /query for filtering/search with payload support.”

Also applies to: 603-614, 727-736

Source: Coding guidelines

api/entrypoints/dispatcher_composio.py (1)

70-70: 💤 Low value

httpx.Client is never closed.

The forward client is created but never explicitly closed. Since this script runs indefinitely, it's not a functional issue, but for resource hygiene consider using a context manager or calling forward.close() on exit. However, given this is a dev-only script that blocks forever on wait_forever(), this is acceptable as-is.

web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerCatalogDrawer.tsx (1)

426-444: 💤 Low value

Event cards are hoverable but not actionable.

The event Card has hoverable prop but no onClick handler. If clicking an event should do something (e.g., show event details or select it for subscription), add the handler. If cards are purely informational, consider removing hoverable to avoid misleading UX affordance.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c857f25-e2d7-4af9-b561-b325285e1c10

📥 Commits

Reviewing files that changed from the base of the PR and between 338939c and ce43b26.

📒 Files selected for processing (116)
  • api/ee/tests/pytest/acceptance/triggers/test_triggers_connections.py
  • api/ee/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py
  • api/entrypoints/dispatcher_composio.py
  • api/entrypoints/routers.py
  • api/oss/src/apis/fastapi/tools/router.py
  • api/oss/src/apis/fastapi/triggers/models.py
  • api/oss/src/apis/fastapi/triggers/router.py
  • api/oss/src/core/gateway/catalog/__init__.py
  • api/oss/src/core/gateway/catalog/dtos.py
  • api/oss/src/core/gateway/catalog/interfaces.py
  • api/oss/src/core/gateway/catalog/providers/__init__.py
  • api/oss/src/core/gateway/catalog/providers/composio/__init__.py
  • api/oss/src/core/gateway/catalog/providers/composio/adapter.py
  • api/oss/src/core/gateway/catalog/registry.py
  • api/oss/src/core/gateway/catalog/service.py
  • api/oss/src/core/gateway/connections/providers/composio/adapter.py
  • api/oss/src/core/gateway/providers/__init__.py
  • api/oss/src/core/gateway/providers/composio/__init__.py
  • api/oss/src/core/gateway/providers/composio/errors.py
  • api/oss/src/core/tools/dtos.py
  • api/oss/src/core/tools/providers/composio/adapter.py
  • api/oss/src/core/tools/service.py
  • api/oss/src/core/triggers/dtos.py
  • api/oss/src/core/triggers/interfaces.py
  • api/oss/src/core/triggers/providers/composio/adapter.py
  • api/oss/src/core/triggers/service.py
  • api/oss/src/core/triggers/utils.py
  • api/oss/src/middlewares/auth.py
  • api/oss/src/tasks/asyncio/triggers/dispatcher.py
  • api/oss/src/utils/env.py
  • api/oss/tests/manual/triggers/try_composio_triggers.py
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_connections.py
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_ingress.py
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_dispatcher.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_signature.py
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/run.sh
  • web/_reference/agenta-sdk/src/types.ts
  • web/oss/src/components/DrillInView/OSSdrillInUIProvider.tsx
  • web/oss/src/components/Playground/Components/PlaygroundVariantConfigPrompt/assets/GatewayToolsPanel.tsx
  • web/oss/src/components/Sidebar/SettingsSidebar.tsx
  • web/oss/src/components/Webhooks/Modals/DeleteWebhookModal.tsx
  • web/oss/src/components/Webhooks/Modals/SecretRevealModal.tsx
  • web/oss/src/components/Webhooks/RequestPreview.tsx
  • web/oss/src/components/Webhooks/WebhookDrawer.tsx
  • web/oss/src/components/Webhooks/WebhookFieldRenderer.tsx
  • web/oss/src/components/Webhooks/WebhookLogsTab.tsx
  • web/oss/src/components/Webhooks/assets/constants.ts
  • web/oss/src/components/Webhooks/assets/types.ts
  • web/oss/src/components/Webhooks/utils/buildPreviewRequest.ts
  • web/oss/src/components/Webhooks/utils/buildSubscription.ts
  • web/oss/src/components/Webhooks/utils/handleTestResult.ts
  • web/oss/src/components/Webhooks/widgets/AdvanceConfigWidget.tsx
  • web/oss/src/components/Webhooks/widgets/DispatchAlertWidget.tsx
  • web/oss/src/components/Webhooks/widgets/HeaderListWidget.tsx
  • web/oss/src/components/pages/settings/APIKeys/APIKeys.tsx
  • web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx
  • web/oss/src/components/pages/settings/Tools/hooks/useIntegrationDetail.ts
  • web/oss/src/components/pages/settings/Tools/hooks/useToolsConnections.ts
  • web/oss/src/components/pages/settings/Tools/hooks/useToolsIntegrations.ts
  • web/oss/src/components/pages/settings/Triggers/components/GatewaySubscriptionsSection.tsx
  • web/oss/src/components/pages/settings/Triggers/components/GatewayTriggersSection.tsx
  • web/oss/src/components/pages/settings/Webhooks/Webhooks.tsx
  • web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx
  • web/oss/src/services/webhooks/api.ts
  • web/oss/src/services/webhooks/types.ts
  • web/oss/src/state/automations/state.ts
  • web/oss/src/state/webhooks/atoms.ts
  • web/oss/src/state/webhooks/state.ts
  • web/oss/src/styles/globals.css
  • web/packages/agenta-entities/src/gatewayTool/api/api.ts
  • web/packages/agenta-entities/src/gatewayTool/api/index.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/index.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolActionDetail.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolCatalogActions.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolCatalogIntegrations.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolConnectionActions.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolConnectionQuery.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolConnectionsQuery.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolIntegrationConnections.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolIntegrationDetail.ts
  • web/packages/agenta-entities/src/gatewayTool/index.ts
  • web/packages/agenta-entities/src/gatewayTool/state/atoms.ts
  • web/packages/agenta-entities/src/gatewayTool/state/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/api/api.ts
  • web/packages/agenta-entities/src/gatewayTrigger/api/client.ts
  • web/packages/agenta-entities/src/gatewayTrigger/api/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/core/types.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerCatalogEvents.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerCatalogIntegrations.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerConnectionActions.ts
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerEvent.ts
  • web/packages/agenta-entities/src/gatewayTrigger/index.ts
  • web/packages/agenta-entities/src/gatewayTrigger/state/atoms.ts
  • web/packages/agenta-entities/src/gatewayTrigger/state/index.ts
  • web/packages/agenta-entities/src/index.ts
  • web/packages/agenta-entity-ui/src/gatewayTool/components/SchemaForm.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/CatalogDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/ConnectDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/ConnectionManagerDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/ToolExecutionDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerCatalogDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerConnectDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerDeliveriesDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerEventsDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerSubscriptionDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTrigger/index.ts
  • web/tests/tests/fixtures/base.fixture/providerHelpers/index.ts
💤 Files with no reviewable changes (1)
  • web/oss/src/state/automations/state.ts
✅ Files skipped from review due to trivial changes (5)
  • api/oss/src/core/gateway/catalog/providers/composio/init.py
  • web/packages/agenta-entity-ui/src/gatewayTool/components/SchemaForm.tsx
  • web/_reference/agenta-sdk/src/types.ts
  • web/packages/agenta-entities/src/index.ts
  • web/oss/src/components/pages/settings/APIKeys/APIKeys.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
  • api/oss/src/middlewares/auth.py
  • web/packages/agenta-entities/src/gatewayTrigger/state/atoms.ts
  • web/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerDeliveriesDrawer.tsx
  • api/oss/src/core/triggers/interfaces.py
  • web/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerEvent.ts
  • web/oss/src/components/pages/settings/Triggers/components/GatewaySubscriptionsSection.tsx
  • api/oss/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py
  • api/entrypoints/routers.py
  • api/ee/tests/pytest/acceptance/triggers/test_triggers_subscriptions.py
  • web/oss/src/components/Sidebar/SettingsSidebar.tsx
  • api/oss/src/tasks/asyncio/triggers/dispatcher.py

Comment thread api/oss/src/core/gateway/catalog/interfaces.py Outdated
Comment thread api/oss/src/core/gateway/catalog/registry.py Outdated
Comment thread api/oss/src/core/gateway/catalog/service.py Outdated
Comment thread api/oss/src/core/triggers/providers/composio/adapter.py
Comment thread api/oss/tests/pytest/acceptance/triggers/test_triggers_ingress.py
Comment thread hosting/docker-compose/oss/docker-compose.gh.yml
Resolve the bound reference via the canonical
WorkflowsService.retrieve_workflow_revision (handles application/evaluator/
workflow + environment families) and rebuild the completed family with
build_retrieval_info, so invoke_workflow finds the service uri. Raise
TriggerReferenceInvalid when it cannot resolve. Skip soft-deleted
subscriptions in the ti_* resolver. FE: scope the picker to application
workflows and send the reference family by its true kind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ggers, schedules, webhooks

Add trigger schedules: a cron-expression analogue to trigger subscriptions that
fires the same dispatch path on each matching minute tick. Promote ti_id to a
top-level indexed column, type subscription/schedule/webhook flags, and add
/start and /stop play/pause routes (is_active) across all three domains, with
is_valid reserved for third-party connection sync on subscriptions.

- core/triggers: TriggerSchedule* DTOs, schedule CRUD + croniter validation,
  refresh_schedules fire gate, entity-agnostic dispatcher
- db: fold schedules + ti_id column + generalized deliveries into oss000000003;
  data-only oss000000004 backfills webhook flags.is_active
- cron: crons/triggers.{sh,txt} wired into oss+ee compose and all oss/ee x dev/gh Dockerfiles
- web: schedule drawer + list section, ActiveToggle, schedule atoms/hooks
- tests: schedule + webhook play/pause acceptance, dispatcher is_valid unit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@junaway junaway changed the title [feat] Gateway triggers: Composio event ingress, subscriptions, and UI [feat] Add triggers Jun 22, 2026
@junaway junaway changed the title [feat] Add triggers [feat] Add triggers (connections, subscriptions, schedules) Jun 22, 2026
…nature to hex

The dispatcher refactor added a required triggers_dao kwarg to TriggersWorker
but worker_triggers.py was missed, crash-looping the worker (ingress 202 but
nothing drained the queue). Live events also confirmed Composio signs lowercase
hex, so the diagnostic dual hex/base64 accept is collapsed to hex-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…39 os.getenv

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…grade, F37 skip, F40 dup-flags

- F5: make triggers_dao/connections_service/workflows_service required (drop Optional)
- F16: extract selector-preview to pure core/selectorPreview.ts + 12 web unit tests
- F17: add schedule cron fire-gate unit tests (_validate_schedule + refresh_schedules)
- F18: try/finally cleanup in six connection/subscription lifecycle tests
- F20: symmetric oss000000004 downgrade (strip only backfill-created flags)
- F37: skip ingress dedup test when webhook secret unresolvable (no 401 flake)
- F40: remove duplicate flags key breaking @agenta/entities tsc build
- F2 verified not fail-open; F13/F24/F39 dispositioned wontfix

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jp-agenta and others added 2 commits June 22, 2026 13:06
Adds the generated Python (agenta_client/triggers/*, trigger_* types) and
TypeScript (agenta-api-client triggers resource, Trigger*/Connection*/Catalog*
types) clients for the gateway-triggers surface; renames the tool-scoped
connection/provider/auth enums to the shared Connection*/Catalog* names and
drops the obsolete Tool* variants.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rsion

global-setup now reads the backend's /auth/discover response and promotes the
'auto' auth mode to the method the deployment actually serves: 'email:password'
(local dev / no SMTP — direct signup, no email verification) vs 'email:otp'
(SMTP/SendGrid enabled). Local dev no longer demands Testmail/OTP wiring.

run-tests excludes the agenta-web-tests workspace from the vitest layer pass so
its test:acceptance script doesn't recurse into the playwright runner. Re-enable
multi-worker by dropping the temporary workers:1 pin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jp-agenta and others added 2 commits June 22, 2026 13:24
The gateway-triggers feature runs a dedicated queue consumer
(entrypoints.worker_triggers) alongside the schedule-ticking cron. It was
wired into every docker-compose variant but missing from the Helm chart, so
Helm-deployed clusters ingest+enqueue trigger events (and tick schedules via
the baked crontab) but have nothing consuming the queue — no delivery ever
fires. This is the F38 worker-wiring gap, permanent on Kubernetes.

Adds worker-triggers-deployment.yaml modeled on worker-webhooks (same image,
commonEnv, init containers, NewRelic command branch, pgrep liveness probe),
the agenta.workerTriggers.enabled/.replicas helpers, and the workerTriggers
knob in both values examples. Defaults enabled with replicas:1; toggle off
via workerTriggers.enabled=false. Verified with helm template + helm lint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…* names

The fern regen renamed the shared gateway enums/DTOs from Tool*-prefixed to the
backend's sub-domain names (ConnectionAuthScheme/ConnectionProviderKind/
ConnectionCreateData/ConnectionStatus) and dropped the Tool* variants, breaking
the @agenta/entities build (TS2694/TS2724) in gatewayTool/core/types.ts. Point
the four package-local Tool* aliases at the new names; the aliases keep the
gatewayTool package's public surface stable. Verified: @agenta/entities builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…schema leak

The tools/triggers domains subclass the shared gateway Connection/Catalog DTOs
so their public surface is Tool*/Trigger*-named (per the design comments in each
dtos.py). But the subclasses were empty (`pass`), so every inherited leaf type
still resolved to its gateway name in the OpenAPI schema and leaked into the
generated clients: ConnectionProviderKind/ConnectionStatus/ConnectionCreateData/
ConnectionAuthScheme (via Connection/ConnectionCreate) and CatalogProviderKind/
CatalogAuthScheme (via CatalogProvider/CatalogIntegration). The domains even
redefined Tool/TriggerProviderKind and ToolAuthScheme but never referenced them.

Override the leaked fields so each domain fully shadows the gateway leaves:
- ToolConnection/TriggerConnection: provider_key + status -> domain-named
- Tool/TriggerConnectionCreate: provider_key + data -> domain-named
- add Tool/TriggerConnectionStatus, Tool/TriggerConnectionCreateData subclasses
- add TriggerAuthScheme; point catalog provider.key/integration.auth_schemes at
  the domain enums

Verified against the live /openapi.json: zero bare Connection*/Catalog* names
remain; all connection/catalog schema types are Tool*/Trigger*-prefixed.
Regenerated both clients (gateway leaf types deleted, domain types added) and
re-pointed the gatewayTool/core/types.ts aliases back to the honest Tool* names.
py-run-tests --api (1876) + --sdk (1007) green; web --ui unit+integration green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@junaway junaway changed the base branch from main to release/v0.104.1 June 22, 2026 12:00
@junaway junaway marked this pull request as ready for review June 22, 2026 12:01
Copilot AI review requested due to automatic review settings June 22, 2026 12:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend feature size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants