Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/rename-webhook-sources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@electric-ax/agents-runtime': patch
'@electric-ax/agents-server': patch
'@electric-ax/agents': patch
---

Rename agent-facing webhook subscription APIs from generic event source terminology to webhook source terminology. This is a breaking rename for the experimental webhook-source tools, runtime/server types, routes, manifest metadata, and wake payload names.
142 changes: 142 additions & 0 deletions docs/stratovolt-webhook-source-rename-followup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Stratovolt follow-up: webhook source rename

This Electric PR makes a breaking rename from the overly generic **event source** terminology to **webhook source** terminology for agent-visible webhook subscriptions.

After this PR is merged, Stratovolt/cloud needs a companion update before it can consume the new agents runtime/server APIs.

## Why this is needed

Stratovolt currently mirrors agent-visible webhook ingress metadata into the cloud agents server as **event source** contracts. The Electric API/types/tools are being renamed to **webhook source** equivalents, including:

- `EventSource*` → `WebhookSource*`
- `EventSourceCatalog` → `WebhookSourceCatalog`
- `sourceKey` → `webhookKey`
- `listEventSources()` → `listWebhookSources()`
- `getEventSource()` → `getWebhookSource()`
- `eventSources` tenant context option → `webhookSources`
- `ensureEventSourceWakeSource` → `ensureWebhookSourceWakeSource`
- `/_electric/event-sources` → `/_electric/webhook-sources`
- `/event-source-subscriptions/:id` → `/webhook-source-subscriptions/:id`
- `event-source:<id>` manifest keys → `webhook-source:<id>`
- `config.eventSource` → `config.webhookSource`
- `event_source_wake` → `webhook_source_wake`

We are intentionally **not** adding backwards compatibility aliases in Electric for the old names/routes/manifests.

## Stratovolt areas to update

The following references were found in `/Users/kylemathews/programs/stratovolt` and should be updated in the companion PR.

### Cloud agents server

Primary integration points:

- `packages/cloud-agents-server/src/event-source-registry.ts`
- Rename file/class if desired, e.g. `webhook-source-registry.ts` / `WebhookSourceRegistry`.
- Update imported agents types:
- `EventSourceBucket` → `WebhookSourceBucket`
- `EventSourceCatalog` → `WebhookSourceCatalog`
- `EventSourceContract` → `WebhookSourceContract`
- Update public methods:
- `listEventSources()` → `listWebhookSources()`
- `getEventSource()` → `getWebhookSource()`
- Update contract field projection:
- `sourceKey` → `webhookKey`
- Update logs from “event source shape” to “webhook source shape”.

- `packages/cloud-agents-server/src/app.ts`
- Tenant context currently passes:
- `eventSources: options.eventSourceRegistry.forService(...)`
- `ensureEventSourceWakeSource: ...`
- Update to:
- `webhookSources: options.webhookSourceRegistry.forService(...)`
- `ensureWebhookSourceWakeSource: ...`

- `packages/cloud-agents-server/src/main.ts`
- Rename registry import/instantiation if the registry file/class is renamed.
- Update config option names if changed.

- `packages/cloud-agents-server/src/config.ts`
- Consider renaming:
- `eventSourceShapeUrl` → `webhookSourceShapeUrl`
- env var `AGENTS_EVENT_SOURCE_SHAPE_URL` → `AGENTS_WEBHOOK_SOURCE_SHAPE_URL`

- `infra/cloud-agents-server/server.ts`
- Update environment variable wiring:
- `AGENTS_EVENT_SOURCE_SHAPE_URL` → `AGENTS_WEBHOOK_SOURCE_SHAPE_URL`

- `scripts/generate-dev-env.ts`
- Update generated dev env var:
- `AGENTS_EVENT_SOURCE_SHAPE_URL` → `AGENTS_WEBHOOK_SOURCE_SHAPE_URL`

### Admin API / contract

The Admin API exposes the webhook ingress catalog shape consumed by the cloud agents server.

- `packages/admin-api-contract/src/schemas/services.ts`
- Rename schema/types if we want public contract naming to match:
- `WebhookIngressEventSourceFilterConditionSchema`
- `WebhookIngressEventSourceFilterSchema`
- `WebhookIngressEventSourceFilter`
- Update contract field names from `sourceKey` to `webhookKey` if the API surface should match Electric.

- `packages/admin-api-contract/src/schemas/index.ts`
- Update exports for renamed schemas/types.

- `packages/admin-api/src/lib/webhook-ingresses.ts`
- Currently projects database `source_key` to `sourceKey`.
- Update output to `webhookKey` if the shape/API is renamed.

- `packages/admin-api/src/routes/shapes/admin.ts`
- Shape alias currently uses `agent-event-sources`.
- Consider renaming to `agent-webhook-sources` and updating the description.
- If renaming the shape alias, update all consumers/tests/env vars accordingly.

- `migrations/049-add-agent-event-source-fields.sql`
- Existing migration name/comments mention event source terminology.
- Usually do **not** rewrite applied migrations, but future migrations/docs/comments should use webhook source terminology.

### Dashboard

User-facing dashboard copy and form state still use “event source” language.

- `packages/dashboard/src/routes/_dashboard/projects/$projectId/envs/$envId/svc/streams/$serviceId/webhooks/$endpointKey/edit.tsx`
- Rename form field/state if API changes:
- `sourceKey` → `webhookKey`
- Update copy: “event-source tools” → “webhook-source tools”.

- `packages/dashboard/src/components/webhooks/flow/BucketRouteSidePanel.tsx`
- Update copy: “What agents see when they discover this bucket as an event source.”

- `packages/dashboard/src/components/webhooks/flow/AgentSourcePanel.tsx`
- Update copy: “agent event-source discovery”.

- `packages/dashboard/src/components/webhooks/bucketTemplateFormState.ts`
- Update comment reference from `electric/packages/agents-runtime/src/event-sources.ts` to `webhook-sources.ts`.

### Tests

Update tests after renaming the cloud/admin/dashboard surfaces:

- `packages/cloud-agents-server/test/event-source-registry.test.ts`
- `packages/cloud-agents-server/test/app.test.ts`
- `packages/admin-api/test/routes/public/shapes.test.ts`
- `packages/admin-api/test/orpc/procedures/services/streams/webhook-ingresses.test.ts`

## Suggested approach

1. Wait until the Electric webhook-source rename PR is merged.
2. Update Stratovolt dependencies / workspace link to the merged Electric packages.
3. Rename the cloud registry and tenant context wiring to the new webhook-source API.
4. Decide whether the Admin API shape alias should also break from `agent-event-sources` to `agent-webhook-sources`.
- If yes, update env vars and tests together.
- If no, keep the shape alias as a cloud-internal compatibility detail but project rows into the new `WebhookSourceContract` shape for agents-server.
5. Update dashboard copy and form/API field names as appropriate.
6. Run targeted tests for:
- cloud agents server registry/app
- admin API webhook ingress shape
- dashboard webhook ingress editing

## Notes

Electric intentionally does not provide old route/type/manifest aliases for this rename. If Stratovolt has existing persisted dynamic subscriptions using `event-source:<id>` manifest keys, they should be considered disposable and recreated after rollout.
2 changes: 1 addition & 1 deletion packages/agents-runtime/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ output? }` summed across the run's steps at section-build time, and

### Patch Changes

- 833a1cb: Add agent event source contracts and dynamic event source subscription tools. Agents can list active, agent-visible webhook-backed event sources, subscribe entities to resolved bucket streams with explicit lifetimes, and persist those subscriptions as manifest-backed wake registrations. Bucket params are validated against the advertised `paramsSchema` before a subscription is accepted. Horton now receives these tools through the built-in agents runtime by default. Runtime-managed event source wakes now hydrate matching webhook rows into the agent trigger message so tool-created subscriptions include the event payload that caused the wake.
- 833a1cb: Add agent webhook source contracts and dynamic webhook source subscription tools. Agents can list active, agent-visible webhook-backed webhook sources, subscribe entities to resolved bucket streams with explicit lifetimes, and persist those subscriptions as manifest-backed wake registrations. Bucket params are validated against the advertised `paramsSchema` before a subscription is accepted. Horton now receives these tools through the built-in agents runtime by default. Runtime-managed webhook source wakes now hydrate matching webhook rows into the agent trigger message so tool-created subscriptions include the event payload that caused the wake.
- 833a1cb: Add `webhook(endpointKey, { bucket })` observation sources for webhook ingress streams, including deterministic stream path generation, event schema, default wake registration, and observe-time stream creation before preload.

## 0.3.3
Expand Down
14 changes: 7 additions & 7 deletions packages/agents-runtime/src/context-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { createContextTools } from './tools/context-tools'
import { CACHE_TIERS } from './types'
import { composeToolsWithProviders } from './tool-providers'
import { validateSlashCommandDefinitions } from './composer-input'
import type { HydratedEventSourceWake } from './event-sources'
import type { HydratedWebhookSourceWake } from './webhook-sources'
import type { ChangeEvent } from '@durable-streams/state'
import type { Sandbox } from './sandbox/types'
import type {
Expand Down Expand Up @@ -96,7 +96,7 @@ export interface HandlerContextConfig<TState extends StateProxy = StateProxy> {
payload?: unknown
}) => void | Promise<void>
) => void
hydratedEventSourceWake?: HydratedEventSourceWake | null
hydratedWebhookSourceWake?: HydratedWebhookSourceWake | null
doObserve: (
source: ObservationSource,
wake?: Wake
Expand Down Expand Up @@ -193,7 +193,7 @@ function getTriggerMessageText(
wakeEvent: WakeEvent,
events: Array<ChangeEvent>,
wakeOffset: string,
hydratedEventSourceWake?: HydratedEventSourceWake | null
hydratedWebhookSourceWake?: HydratedWebhookSourceWake | null
): string {
if (wakeEvent.type === `inbox`) {
let latestPayload: unknown = wakeEvent.payload
Expand Down Expand Up @@ -227,8 +227,8 @@ function getTriggerMessageText(
}

if (wakeEvent.type === `wake` && typeof wakeEvent.source === `string`) {
if (hydratedEventSourceWake) {
return asMessageText(hydratedEventSourceWake)
if (hydratedWebhookSourceWake) {
return asMessageText(hydratedWebhookSourceWake)
}

const cronPayload = getCronScheduleTriggerPayload(db, wakeEvent.source)
Expand Down Expand Up @@ -731,7 +731,7 @@ export function createHandlerContext<TState extends StateProxy = StateProxy>(
config.wakeEvent,
config.events,
config.wakeOffset,
config.hydratedEventSourceWake
config.hydratedWebhookSourceWake
)
const effectiveInput = input ?? messageText

Expand Down Expand Up @@ -770,7 +770,7 @@ export function createHandlerContext<TState extends StateProxy = StateProxy>(
const latestMessageRole = messages.at(-1)?.role
const runInput =
input !== undefined ||
config.hydratedEventSourceWake != null ||
config.hydratedWebhookSourceWake != null ||
latestMessageRole !== `user`
? effectiveInput
: undefined
Expand Down
18 changes: 9 additions & 9 deletions packages/agents-runtime/src/create-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import type {
import type { ChangeEvent } from '@durable-streams/state'
import type { DispatchPolicy } from './runtime-server-client'
import type {
EventSourceContract,
EventSourceSubscription,
EventSourceSubscriptionInput,
} from './event-sources'
WebhookSourceContract,
WebhookSourceSubscription,
WebhookSourceSubscriptionInput,
} from './webhook-sources'

export interface RuntimeRouterConfig {
/** Base URL of the durable streams server (e.g. http://localhost:4200) */
Expand Down Expand Up @@ -91,11 +91,11 @@ export interface RuntimeRouterConfig {
messageType?: string
}) => Promise<{ txid: string }>
deleteSchedule: (opts: { id: string }) => Promise<{ txid: string }>
listEventSources: () => Promise<Array<EventSourceContract>>
subscribeToEventSource: (
opts: EventSourceSubscriptionInput
) => Promise<{ txid: string; subscription: EventSourceSubscription }>
unsubscribeFromEventSource: (opts: {
listWebhookSources: () => Promise<Array<WebhookSourceContract>>
subscribeToWebhookSource: (
opts: WebhookSourceSubscriptionInput
) => Promise<{ txid: string; subscription: WebhookSourceSubscription }>
unsubscribeFromWebhookSource: (opts: {
id: string
}) => Promise<{ txid: string }>
}) => Array<AgentTool> | Promise<Array<AgentTool>>
Expand Down
44 changes: 22 additions & 22 deletions packages/agents-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,30 +259,30 @@ export type {
SendEntityMessageOptions,
} from './runtime-server-client'
export {
buildEventSourceManifestEntry,
buildHydratedEventSourceWake,
buildEventSourceSubscriptionId,
defaultEventSourceSubscriptionLifetime,
eventSourceWakeInfoFromManifests,
eventSourceSubscriptionManifestKey,
renderEventSourceBucketPath,
resolveEventSourceSubscription,
} from './event-sources'
buildWebhookSourceManifestEntry,
buildHydratedWebhookSourceWake,
buildWebhookSourceSubscriptionId,
defaultWebhookSourceSubscriptionLifetime,
webhookSourceWakeInfoFromManifests,
webhookSourceSubscriptionManifestKey,
renderWebhookSourceBucketPath,
resolveWebhookSourceSubscription,
} from './webhook-sources'
export type {
EventSourceBucket,
EventSourceContract,
EventSourceFilter,
EventSourceFilterCondition,
EventSourceStatus,
EventSourceSubscription,
EventSourceSubscriptionInput,
EventSourceType,
EventSourceWakeChange,
EventSourceWakeInfo,
HydratedEventSourceWake,
ResolvedEventSourceSubscription,
WebhookSourceBucket,
WebhookSourceContract,
WebhookSourceFilter,
WebhookSourceFilterCondition,
WebhookSourceStatus,
WebhookSourceSubscription,
WebhookSourceSubscriptionInput,
WebhookSourceType,
WebhookSourceWakeChange,
WebhookSourceWakeInfo,
HydratedWebhookSourceWake,
ResolvedWebhookSourceSubscription,
SubscriptionLifetime,
} from './event-sources'
} from './webhook-sources'
export { createAgentsClient } from './agents-client'
export type { AgentsClient, AgentsClientConfig } from './agents-client'

Expand Down
30 changes: 15 additions & 15 deletions packages/agents-runtime/src/process-wake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import { appendPathToUrl } from './url'
import { manifestChildKey } from './manifest-helpers'
import { ModelProviderError } from './model-provider-error'
import {
buildHydratedEventSourceWake,
eventSourceWakeInfoFromManifests,
} from './event-sources'
buildHydratedWebhookSourceWake,
webhookSourceWakeInfoFromManifests,
} from './webhook-sources'
import { webhookObservationCollections } from './observation-sources'
import type { HydratedEventSourceWake } from './event-sources'
import type { HydratedWebhookSourceWake } from './webhook-sources'
import { SandboxError } from './sandbox/types'
import type { Sandbox } from './sandbox/types'
import type {
Expand Down Expand Up @@ -1641,9 +1641,9 @@ export async function processWake(
})
setupCtx.restorePersistedSharedStateHandles()

const hydrateCurrentEventSourceWake =
async (): Promise<HydratedEventSourceWake | null> => {
const info = eventSourceWakeInfoFromManifests({
const hydrateCurrentWebhookSourceWake =
async (): Promise<HydratedWebhookSourceWake | null> => {
const info = webhookSourceWakeInfoFromManifests({
wakeEvent: currentWakeEvent,
manifests: db.collections.manifests.toArray,
})
Expand All @@ -1661,10 +1661,10 @@ export async function processWake(
)
const rows = (sourceDb.collections.events?.toArray ??
[]) as unknown as Array<WebhookEventRow>
return buildHydratedEventSourceWake(info, rows)
return buildHydratedWebhookSourceWake(info, rows)
} catch (error) {
log.warn(
`failed to hydrate event source wake source=${info.sourceUrl}: ${error instanceof Error ? error.message : String(error)}`
`failed to hydrate webhook source wake source=${info.sourceUrl}: ${error instanceof Error ? error.message : String(error)}`
)
return null
}
Expand Down Expand Up @@ -2077,14 +2077,14 @@ export async function processWake(
entityUrl,
...opts,
}),
listEventSources: () => serverClient.listEventSources(),
subscribeToEventSource: (opts) =>
serverClient.subscribeToEventSource({
listWebhookSources: () => serverClient.listWebhookSources(),
subscribeToWebhookSource: (opts) =>
serverClient.subscribeToWebhookSource({
entityUrl,
...opts,
}),
unsubscribeFromEventSource: (opts) =>
serverClient.unsubscribeFromEventSource({
unsubscribeFromWebhookSource: (opts) =>
serverClient.unsubscribeFromWebhookSource({
entityUrl,
...opts,
}),
Expand Down Expand Up @@ -2129,7 +2129,7 @@ export async function processWake(
registerSignalHandler: (handler) => {
activeSignalHandler = handler
},
hydratedEventSourceWake: await hydrateCurrentEventSourceWake(),
hydratedWebhookSourceWake: await hydrateCurrentWebhookSourceWake(),
doObserve,
doSpawn,
doFork,
Expand Down
Loading
Loading