mirror of
https://github.com/block/buzz.git
synced 2026-11-13 04:41:12 +00:00
Adds owner-only agent mentions, a relay setting,
`BUZZ_WORKFLOW_AGENT_MENTIONS`. Its values are `any`, the default and
today's behaviour, and `owner`. Any other value fails startup. With
`owner`, a workflow message can direct an agent only if the run's cause
and definition allow it. The setting is relay-wide.
**Recording what caused each run.** `workflow_runs` gets `cause_source`
and `cause_pubkey` columns. Migration `0087` adds them with named checks
marked `NOT VALID`, so it does not scan existing rows under its lock;
`0088` validates the checks separately. `create_workflow_run` now takes
a required `RunCause`, so every place that creates a run has to set one:
- **Event trigger:** the cause is the signer of the message, reaction or
diff. For a reaction, that is the reactor, not the author of the message
being reacted to.
- **Cron and interval schedules:** the cause is the timer.
- **Webhook:** the caller is unknown.
- **Manual trigger:** the cause is the invoking pubkey.
Rows written before this change have no cause. A stored source without
the pubkey it requires, or with one it forbids, is read as no cause.
**Deciding eligibility.** A run's messages may direct agents only when
all of these hold:
- the cause is a schedule, or an event or manual trigger whose pubkey is
the workflow owner's;
- every step of the definition that is running is `send_message` or
`delay`. This is an allowlist, so any other action, including one added
later, makes the definition ineligible, even when an `if:` skips that
step;
- the run did not resume after an approval.
Webhook runs and runs with no recorded cause are never eligible. The
executor decides this from `WorkflowConfig::agent_mentions`, and passes
`ActionSink::send_message` the owner's stored step text with a
`may_direct_agents` flag. The sink adds `buzz:workflow-mention` tags
only when the flag is set, and returns `SentMessage { event_id,
agent_mentions_withheld }`, which is true only when it left out a tag
that a member named in both the stored and rendered text would otherwise
have received. Webhook and manual runs start through `execute_run`, so
`execute_from_step` is used only to resume after an approval.
**The gate.** With `owner`, the relay adds `buzz:workflow-mention` only
to messages from eligible runs. Messages from other runs still post with
their plain `p` tags and still notify people. With `any`, mention tags
are added exactly as before.
**Making it visible.** When a `send_message` step leaves the tags out:
- its output in the run trace gets `"agent_mentions": {"withheld": true,
"reasons": [...]}`, listing each reason that applies: `cause` (not
started by the owner or a timer), `steps` (a step other than
`send_message` or `delay`), `resumed` (resumed after an approval). The
key is absent when nothing was withheld. The trace is what the app's run
history shows;
- the relay logs it at info level under the
`buzz_relay::workflow_agent_mentions` target (visible under the default
filter) with the community, workflow, run, step and reasons;
- the counter `buzz_workflow_agent_mentions_withheld_total` increases
once per reason, labelled `reason`.
**Discovery.** The NIP-11 document always carries
`"workflow_agent_mentions": "any" | "owner"`, so a missing field means
an older relay.
`NOSTR.md` now specifies `buzz:workflow-mention` for clients: what the
tag means, the checks an agent makes before acting, that a relay may
leave it out under a policy, and the NIP-11 `workflow_agent_mentions`
field. The relay policy itself is in the new operator guide,
`docs/operator-workflow-agent-mentions.md`: the setting and its values,
what counts as a run's cause for each trigger, which steps are allowed,
the trace key, the log and metric, the NIP-11 field, when to use
`owner`, rollout across pods, and what it doesn't cover. The
`TESTING.md` and `.env.example` entries link to it.
---------
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
30 lines
1.4 KiB
SQL
30 lines
1.4 KiB
SQL
-- ── Workflow runs ─────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE workflow_runs (
|
|
community_id UUID NOT NULL REFERENCES communities(id),
|
|
id UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
workflow_id UUID NOT NULL,
|
|
status run_status NOT NULL DEFAULT 'pending',
|
|
trigger_event_id BYTEA,
|
|
current_step INT NOT NULL DEFAULT 0,
|
|
execution_trace JSONB NOT NULL DEFAULT '[]',
|
|
trigger_context JSONB,
|
|
cause_source TEXT,
|
|
cause_pubkey BYTEA,
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
error_message TEXT,
|
|
error_code TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (community_id, id),
|
|
CONSTRAINT workflow_runs_cause_source_check
|
|
CHECK (cause_source IN ('event', 'schedule', 'webhook', 'manual')),
|
|
CONSTRAINT workflow_runs_cause_pubkey_check
|
|
CHECK (length(cause_pubkey) = 32),
|
|
FOREIGN KEY (community_id, workflow_id)
|
|
REFERENCES workflows (community_id, id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX idx_workflow_runs_workflow ON workflow_runs (community_id, workflow_id);
|
|
CREATE INDEX idx_workflow_runs_status ON workflow_runs (community_id, status);
|