Skip to content

v1.7.0

Choose a tag to compare

@jiashuoz jiashuoz released this 08 Aug 22:34
749fbea

Backward compatible with 1.6.0 on the wire — nothing in this release removes an
operation, field, or enum value, and every API addition is additive or opt-in.
Two behavior changes are deliberate and customer-visible, and one of them
changes an email address your filters may match on — read "Behavior changes"
before upgrading.
Three migrations: two metadata-only ALTER TABLEs with NULL
defaults and one CREATE INDEX — see "Upgrading".

Behavior changes

Each of these changes an outcome that 1.6.0 produced.

  • Operational email now comes from approvals@ and webhooks@, not
    hitl-noreply@.
    HITL approval notifications previously sent from
    hitl-noreply@<your from_domain>; they now send from approvals@, and the
    new webhook health mail sends from webhooks@. If you filter, route, or
    allowlist on the old address — including bounce rules and mail-server
    allowlists — those rules stop matching. The senders are deliberately distinct
    so a time-boxed approval stays filterable apart from routine webhook mail;
    setting notifications.from_address collapses both into one identity.

  • Operational email now carries a working Reply-To. Previously HITL
    approval mail set Reply-To to its own sender on the platform relay domain,
    which has no mailbox — a reply went nowhere. When notifications.reply_to is
    configured, both notification kinds now direct replies to that address; unset
    preserves the previous behavior exactly, so a deployment that configures
    nothing is unchanged.

  • e2a now emails webhook owners when their endpoint is failing. Two new
    emails: an early warning when deliveries start failing, and a notice
    when e2a auto-disables an endpoint. Accounts with webhooks will receive mail
    they have not received before. The auto-disable thresholds themselves are
    unchanged (10 terminal failures in 72h with none succeeding); the warning is
    new and fires on attempt-level failures within minutes, long before the
    breaker can see them.

  • Deliveries parked against a disabled webhook now terminate. Previously a
    delivery whose webhook was disabled snoozed hourly with no ceiling, sitting in
    pending until its 90-day expiry. It is now capped at 24 snoozes (~24h) and
    then written terminal with last_error = "webhook disabled". Re-enabling
    within that window still drains the queue as before; after it, events remain
    replayable via POST /v1/events/{id}/redeliver for the 30-day retention.

New

  • Message filtering — filter on listMessages (beta). A boolean
    expression language derived from AIP-160 over label, from, subject and
    created. Operators : = != < <= > >= with AND / OR / NOT and
    parentheses; whitespace is an implicit AND and binds looser than OR.
    It composes with (ANDs) the existing flat filters rather than replacing
    them, so direction, labels, since and friends keep working alongside it.
    Capped at 500 characters. Pagination is cursor-stable under a filter.
    Available across the API, both SDKs, the CLI and MCP. The parameter is
    filter, not q
    — it was renamed during development and some intermediate
    commit messages still say q. Unknown fields and malformed expressions return
    400 invalid_filter with the column position of the error.

  • Delivery metrics (beta). GET /v1/metrics and
    GET /v1/agents/{email}/metrics, aggregated from the message lifecycle
    ledger, plus a /metrics dashboard page, e2a metrics in the CLI, and
    get_agent_metrics / get_account_metrics in MCP. No migration — the
    aggregate rides existing indexes. Three semantics worth knowing before you
    build on it: messages join a window by their own created_at (so recent days
    keep settling for up to 72h as feedback arrives), headline numbers use message
    grain rather than observation grain, and a rate with a zero denominator is
    null — never 0, which would be indistinguishable from total failure.

  • Webhook enable/disable in the dashboard. The webhooks list and detail
    pages can now toggle an endpoint, including re-enabling one e2a disabled. The
    detail page previously told you to use the API.

  • auto_disabled_reason on the webhook view. The concrete cause e2a
    captured when it disabled an endpoint (for example HTTP 404), so the reason
    is visible without reading delivery history. Additive and optional; treat the
    value as an open set.

Fixed

  • MCP delete_agent honours permanent purge, matching REST. Previously the
    MCP tool could only trash an agent, leaving message bodies stored and counting
    against usage.storage_bytes until the retention window elapsed. (#847)

  • The webhook breaker no longer counts e2a's own failures. Terminal errors
    attributable to e2a (expired before delivery, internal load/resolve errors)
    previously counted toward the auto-disable threshold and could be quoted back
    to the customer as the reason their endpoint was disabled. They are now
    excluded from the breaker, the warning, the captured reason, and the email.

  • The auto-disable sweep is now bounded per tick, so a systemic failure on
    e2a's side cannot mass-disable and mass-mail the customer base in one pass.

Upgrading

Migrations (three, applied automatically on startup):

  • 096_webhooks_health_notify.sql — two nullable columns on webhooks
    (metadata-only)
  • 097_webhooks_reenabled_at.sql — one nullable column on webhooks
    (metadata-only)
  • 098_wsd_created_at_idx.sql — an index on webhook_subscriber_deliveries
    supporting the health sweeps

Configuration (all optional; unset preserves 1.6.0 behavior):

  • notifications.from_address — overrides both notification senders with a
    single address
  • notifications.reply_to — adds a Reply-To to notification mail. Set this
    if your from_domain is relay-only with no mailbox behind it, or replies
    from customers will go nowhere.

Client packages — publish in this order, as the CLI depends on the SDK:
@e2a/sdke2a (PyPI) → @e2a/cli.

New telemetry: e2a_webhook_notify_total{kind,outcome} counts notification
sends. A sustained outcome="permanent" rate means the path that reports broken
webhooks is itself broken — worth an alert.