Skip to content

Platform-level relay reply: every agent converses over the relay by default #254

Description

@khaliqgant

Problem

Deployed agents can receive relay DMs today (persona relay.inbox: ['@self'] → cloud inbox_selectors → candidates → deliver → tick wakes the box), but they cannot reply over the relay. A relay DM from a local/peer agent wakes the target, but the answer goes to the wrong place:

  • @agentworkforce/delivery only knows 'slack' | 'telegram' targets (DeliveryClient.targets, resolveDeliveryTargets, onlyTargets, SlackRef/TelegramRef are all hardcoded to those two).
  • So an agent's relay Q&A branch (e.g. hn-monitor handleQaMessage(provider:'relay')) replies via the delivery package to Slack, never back to the relay sender. hn-monitor.parseRelayMessage even drops the sender.
  • There is no relaycast writeback provider in @relayfile/adapter-core (the catalog is external integrations only), and no handler-side relay-send primitive.

Net: "local agent ↔ deployed agent over the relay" doesn't round-trip. Patching each persona (hn-monitor, then inbox-buddy, then every future agent) is the wrong layer. Every agent should be on the relay and able to converse by default, with zero per-persona code.

Proposed design (workforce)

1. packages/delivery — add relaycast as a first-class target.

  • Widen the target union 'slack' | 'telegram''slack' | 'telegram' | 'relaycast' across DeliveryClient.targets, resolveDeliveryTargets(ctx), createDelivery(ctx, transports?, onlyTargets?), and add RelaycastRef alongside SlackRef/TelegramRef.
  • The relaycast transport posts via the relaycast API using RELAY_API_KEY + RELAY_WORKSPACE_ID (already injected into every box by packages/core launcher in cloud) to the inbound relay event's channel/threadId (carried on RelaycastMessageEvent@agent-relay/events).
  • resolveDeliveryTargets includes relaycast when the current run is handling a relay DM (origin-transport reply), so the existing "reply to origin transport" pattern in hn-monitor/inbox-buddy/joke-bot covers relay automatically — no persona changes.

2. packages/runtime — expose relay reply on ctx.

  • Add ctx.relay.reply(text) / ctx.relay.send(toAgent, text) sugar for agents that don't use the delivery package, backed by the same relaycast client.
  • Surface the inbound sender + channel/thread on the relay event so replies address the right DM/thread (today RelaycastMessageEvent carries channel/messageId but personas re-parse ad hoc and drop the sender).

3. (cross-repo) AgentWorkforce/cloud — relay-on by default.

  • Default inbox_selectors to ['@self'] for every deployed agent in translatePersonaRelayToInboxSelectors (packages/web/lib/proactive-runtime/inbox-selectors.ts), opt-out via relay.enabled:false, so addressability is the default rather than opt-in. (Receiving side; complements the reply primitive above.)

Migration / cleanup

  • Once delivery has the relaycast target, drop the per-persona Slack-fallback hack in agents repo hn-monitor relay branch; inbox-buddy/joke-bot inherit relay reply for free.

Acceptance

A local (broker-spawned) agent DMs a deployed agent (e.g. hn-monitor) over the relay and gets the answer back in the relay (full round-trip), with zero persona-specific relay code. Verified against a real workspace (rw_* on the cloud-configured relaycast gateway).

Context

Surfaced while wiring local-agent ↔ cloud-agent chat for the AgentWorkforce/agents personas (inbox-buddy/joke-bot/spotify/hn-monitor dual-transport unification). Relates to cloud inbox delivery (#2212) and the optional-integrations work (#252).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions