Skip to content
Merged
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
12 changes: 8 additions & 4 deletions examples/lobu-crm/funnel-digest.reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
* Runs after the weekly Monday-9am window completes. `ctx.extracted_data` is
* whatever the watcher's `extraction_schema` produced — funnel snapshot, top
* action, stale leads, etc. We:
* 1. persist the digest as a `funnel_digest` event linked to every lead the
* watcher knows about, so the next digest can compare stage_counts
* week-over-week without re-running classification; and
* 1. persist the digest as a `summary` event (tagged `metadata.kind:
* "funnel_digest"`) linked to every lead the watcher knows about, so the
* next digest can compare stage_counts week-over-week without re-running
* classification; and
* 2. push it to the team via `client.notifications.send` — which fans out to
* the org's active bot connections (the #leads Slack connection) and the
* in-app inbox. `watcher_source` attributes it to this window.
Expand Down Expand Up @@ -43,8 +44,11 @@ export default async (
// CRM data and discoverable from any lead the watcher already touches.
entity_ids: ctx.entities.map((e) => e.id),
content,
semantic_type: "funnel_digest",
// `semantic_type` must be a registered event kind; "summary" fits a digest.
// The domain label lives in metadata so it stays queryable.
semantic_type: "summary",
metadata: {
kind: "funnel_digest",
window_id: ctx.window.id,
watcher_slug: ctx.watcher.slug,
stage_counts: data.stage_counts ?? {},
Expand Down
10 changes: 7 additions & 3 deletions examples/lobu-crm/inbound-triage.reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
* Reaction for the `inbound-triage` watcher.
*
* Fires every 2h after the watcher LLM extracts new and enriched leads from
* GitHub/X/HN signals. Persists a `lead_interaction` event per run so the next
* digest can count them, and — when the run is notable — pushes the recommended
* GitHub/X/HN signals. Persists an `observation` event (tagged `metadata.kind:
* "lead_interaction"`) per run so the next digest can count them, and — when
* the run is notable — pushes the recommended
Comment on lines +5 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Header comment overstates when triage events are persisted.

The function returns before client.knowledge.save when data.notable is false or recommended_actions is empty, so it does not persist an observation “per run.” Reword this comment to match the actual gate; otherwise the next-digest counting semantics are misleading.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/lobu-crm/inbound-triage.reaction.ts` around lines 5 - 7, Header
comment incorrectly claims an observation is persisted "per run" even though the
code returns early when data.notable is false or recommended_actions is empty;
update the comment to reflect the actual gate. Edit the header above the
reaction function to say that an observation (metadata.kind: "lead_interaction")
is only saved when the function reaches the client.knowledge.save call (i.e.,
when data.notable is truthy and recommended_actions is non-empty), and not on
every invocation, and mention the early return behavior that prevents saving.

* actions to the team via `client.notifications.send` (fans out to the #leads
* Slack connection + the in-app inbox).
*/
Expand Down Expand Up @@ -38,8 +39,11 @@ export default async (
await client.knowledge.save({
entity_ids: ctx.entities.map((e) => e.id),
content: summary,
semantic_type: "lead_interaction",
// `semantic_type` must be a registered event kind; "observation" fits a
// triage note. The domain label lives in metadata so it stays queryable.
semantic_type: "observation",
metadata: {
kind: "lead_interaction",
window_id: ctx.window.id,
new_lead_count: data.new_leads?.length ?? 0,
action_count: actions.length,
Expand Down
Loading