@leadbay/mcp 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.17.0 — 2026-05-29
|
|
4
|
+
|
|
5
|
+
- **Lens extension** (product#3654): two new composites that expose the
|
|
6
|
+
backend's agent-driven on-demand lens fill (backend#1844 / api-specs#205).
|
|
7
|
+
- `leadbay_extend_lens` (write, gated by `LEADBAY_MCP_WRITE=1`) —
|
|
8
|
+
`POST /lenses/{id}/extra_refill`. Translates the backend's 429
|
|
9
|
+
`quota_exceeded` / 409 `refresh_in_progress` / 400 `no_valid_seeds`
|
|
10
|
+
errors into routable `status` envelopes. On 429 the response carries
|
|
11
|
+
`quota.used_today` + `quota.resets_at` and a message instructing the
|
|
12
|
+
agent to surface three options to the user (smaller `extra_count` /
|
|
13
|
+
wait for reset / upgrade plan).
|
|
14
|
+
- `leadbay_seed_candidates` (read) — internal scaffolding for the
|
|
15
|
+
extend flow. Returns ranked candidate leads with rich signal
|
|
16
|
+
(description, sector, tags, qq_answers, engagement). The agent picks
|
|
17
|
+
3–5 seeds silently and chains to `extend_lens`; the user never
|
|
18
|
+
reviews the seed list.
|
|
19
|
+
- New prompt `leadbay_extend_my_lens` orchestrates the four-phase flow:
|
|
20
|
+
quota pre-check → silent seed pick → fire extend → react to status.
|
|
21
|
+
- `leadbay_account_status` description now mentions the per-org daily
|
|
22
|
+
`LENS_EXTRA_REFILL` quota — pre-check it before calling
|
|
23
|
+
`leadbay_extend_lens`.
|
|
24
|
+
|
|
25
|
+
## 0.16.2 — 2026-05-29
|
|
26
|
+
|
|
27
|
+
- **Tighter `_triggered_by` description on composite tools.** Live test of
|
|
28
|
+
0.16.1 showed Claude shipping the literal string `"user"` as
|
|
29
|
+
`_triggered_by` — technically non-empty, but useless for analytics. The
|
|
30
|
+
description now explicitly forbids single-word labels (`user`, `agent`,
|
|
31
|
+
`leads`, `request`, etc.), gives a GOOD/BAD example pair, and tells the
|
|
32
|
+
agent to pass `<no user message>` when it's acting without a fresh user
|
|
33
|
+
turn (memory recall, scheduled run, self-initiated retry) so the
|
|
34
|
+
agent-initiated path is auditable instead of falsely attributed.
|
|
35
|
+
|
|
36
|
+
## 0.16.1 — 2026-05-29
|
|
37
|
+
|
|
38
|
+
- **`_triggered_by` is now MANDATORY on every composite-file tool** (the 28
|
|
39
|
+
tools whose source lives under `packages/core/src/composite/`). Calls
|
|
40
|
+
without it are rejected pre-dispatch as `LAST_PROMPT_REQUIRED`. Granular
|
|
41
|
+
and agent-memory tools keep `_triggered_by` optional. Stronger
|
|
42
|
+
description text on the schema property tells the agent to quote
|
|
43
|
+
verbatim and strip secrets (`[REDACTED]`).
|
|
44
|
+
- **New PostHog event `mcp composite call`** with `last_prompt` attached
|
|
45
|
+
(the trimmed verbatim user quote). Fires on every composite-tool
|
|
46
|
+
invocation, success or error. Lives alongside the existing
|
|
47
|
+
`mcp tool called` event — no regression on the broader pipeline. Lets
|
|
48
|
+
dashboards filter user-language against composite outcomes without
|
|
49
|
+
the 60-70% null rate the optional-everywhere `triggered_by` field
|
|
50
|
+
carries on `mcp tool called`.
|
|
51
|
+
|
|
3
52
|
## 0.16.0 — 2026-05-28
|
|
4
53
|
|
|
5
54
|
- **OAuth login** (`leadbay-mcp login --oauth`): browser-based Authorization
|
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
COMPOSITE_FILE_TOOL_NAMES,
|
|
3
4
|
LeadbayClient,
|
|
4
5
|
agentMemoryTools,
|
|
5
6
|
compositeReadTools,
|
|
@@ -11,7 +12,7 @@ import {
|
|
|
11
12
|
granularWriteTools,
|
|
12
13
|
resolveAgentMemorySummary,
|
|
13
14
|
resolveRegion
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ASAKITU3.js";
|
|
15
16
|
|
|
16
17
|
// src/bin.ts
|
|
17
18
|
import { realpathSync } from "fs";
|
|
@@ -568,7 +569,9 @@ If the prompt's body and the tool's RENDERING appear to conflict, the tool's REN
|
|
|
568
569
|
|
|
569
570
|
|
|
570
571
|
# PHASE 1 \u2014 LAUNCH
|
|
571
|
-
Call \`leadbay_bulk_qualify_leads\` with \`count={{arg:count_or_default}}
|
|
572
|
+
Call \`leadbay_bulk_qualify_leads\` with \`count={{arg:count_or_default}}\` and \`wait_for_completion=true\` (synchronous mode \u2014 waits for results before returning).
|
|
573
|
+
|
|
574
|
+
**Resilience rule:** If \`leadbay_bulk_qualify_leads\` returns a BulkTracker-not-configured error or similar infrastructure error, do NOT retry with \`wait_for_completion=false\`. Instead, proceed directly to Phase 3 and call \`leadbay_pull_leads\` to surface the already-qualified leads in the current batch.
|
|
572
575
|
|
|
573
576
|
# PHASE 2 \u2014 POLL
|
|
574
577
|
While it polls, expect notifications / progress events showing per-lead transitions. Surface meaningful ones (e.g. "lead X just finished") to me as they arrive \u2014 one inline status sentence per check, never expanded into a card:
|
|
@@ -591,9 +594,13 @@ After the status line, propose the obvious refresh / progress-check / recovery a
|
|
|
591
594
|
|
|
592
595
|
When \`bulk_qualify_leads\` returns, surface results in two parts.
|
|
593
596
|
|
|
594
|
-
**Status line first** \u2014 one sentence
|
|
597
|
+
**Status line first** \u2014 one sentence in this exact format: "\u2713 N leads qualified \xB7 M still processing (lead IDs: X, Y, Z)". Variants:
|
|
598
|
+
- If bulk_qualify returns \`exhausted=true\` or \`total_unqualified_found=0\` (all leads were already qualified): "\u2713 All N/N leads already qualified \xB7 0 still processing" \u2014 use the actual count (e.g. "All 10/10 leads already qualified")
|
|
599
|
+
- If all newly qualified (none still pending): "\u2713 N leads qualified"
|
|
600
|
+
- If some still pending: "\u2713 N leads qualified \xB7 M still processing (lead IDs: X, Y, Z)"
|
|
601
|
+
- If all still processing: "\u2713 0 leads qualified \xB7 N still processing (lead IDs: X, Y, Z)"
|
|
595
602
|
|
|
596
|
-
**Then a refreshed table** \u2014
|
|
603
|
+
**Then a refreshed table** \u2014 call \`leadbay_pull_leads\` to fetch the current batch (this is always required \u2014 the qualification results do not include the full lead data needed to render the table). Use the same \`lensId\` and render using the canonical pull_leads layout:
|
|
597
604
|
|
|
598
605
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
599
606
|
|
|
@@ -965,6 +972,7 @@ day's batch", "let's prospect". Do NOT trigger on follow-up phrasings
|
|
|
965
972
|
("what should I follow up on", "before my trip") \u2014 those go to
|
|
966
973
|
\`leadbay_followup_check_in\`.
|
|
967
974
|
`, "arguments": [], "expected_calls": ["leadbay_account_status", "leadbay_pull_leads", "leadbay_research_lead_by_id", "leadbay_bulk_qualify_leads", "leadbay_enrich_contacts"], "failure_modes": ["Calls leadbay_report_outreach without explicit user authorization", "Surfaces fewer than 10 leads when more are available, or fails to top up via leadbay_qualify_top_n when the batch is short", `Replaces the canonical pull_leads table layout with prose per row (the per-tool RENDERING block is the structural contract; "Today's nudges" goes above it, not in place of it)`, "Skips the nudge paragraph entirely \u2014 the table alone is fine but adding the nudge is the value-add", "Skips deep research on promising leads (Phase 4) \u2014 the agent must call leadbay_research_lead_by_id on each, not just one", "Triggers contact enrichment without asking the user first (it consumes quota)", "Skips the STOP byproduct and proposes next actions on its own", 'Fires 10 parallel leadbay_research_lead_by_id calls and treats "stream closed" errors as terminal \u2014 must serialize and retry singletons', "Re-pulls leadbay_pull_leads without passing the captured lensId, allowing a backend lens shift to discard the Phase 2 batch", 'Treats a "Request timed out" from leadbay_bulk_qualify_leads as terminal instead of retrying with wait_for_completion:false + qualify_status polling', 'Triggers on a follow-up query (e.g., "leads I should follow up with") that should have routed to `leadbay_followup_check_in` \u2014 the two entry points are different data sources (Discover wishlist vs Monitor view) per \xA71.6'] },
|
|
975
|
+
leadbay_extend_my_lens: { "name": "leadbay_extend_my_lens", "short_description": "Add more leads to the current lens on demand \u2014 for users whose appetite\nexceeds the standard daily fill. The agent picks seeds silently from\nwhat's already on the lens, fires the extra refill, and surfaces the\nqueue confirmation. The user never reviews the seed list.\n", "arguments": [{ "name": "extra_count", "description": "How many extra leads to add. Optional. Omit to use the backend default.", "required": false }], "expected_calls": ["leadbay_account_status", "leadbay_seed_candidates", "leadbay_extend_lens", "leadbay_pull_leads"], "failure_modes": ["Surfaces the seed candidate list to the user instead of picking silently \u2014 the user asked for MORE LEADS, not a candidate review meeting", "Skips the seeded path and calls `leadbay_extend_lens` with no `seed_lead_ids`, losing the bias signal the recommender needs", "On 429, silently retries instead of surfacing the three options (smaller / wait / upgrade) via `ask_user_input_v0`", "Forgets to pre-check `LENS_EXTRA_REFILL` quota in `leadbay_account_status` and burns a wasted API call", "Skips the post-queue pull-leads suggestion, so the user doesn't see what just got added"] },
|
|
968
976
|
leadbay_followup_check_in: { "name": "leadbay_followup_check_in", "short_description": `Run the canonical follow-up check-in: surface KNOWN leads from the
|
|
969
977
|
Monitor view that need re-engagement today, ranked by AI urgency,
|
|
970
978
|
with the canonical pull_followups table layout. Trigger when the
|
|
@@ -992,6 +1000,7 @@ should I follow up on" to "I'll send via lemlist".
|
|
|
992
1000
|
var PROMPT_CATALOG_HEADER = `This server exposes the following workflow prompts via \`prompts/list\` and \`prompts/get\`. Some MCP clients render them as slash commands; if your client does not, you (the agent) should invoke them directly via \`prompts/get\` when the user's request matches one of the triggers described below.`;
|
|
993
1001
|
var PROMPT_CATALOG_BULLETS = {
|
|
994
1002
|
leadbay_daily_check_in: `- \`leadbay_daily_check_in\`: Run the canonical daily check-in: account state, fresh batch, triage top 10, deep-dive every promising one, offer contact enrichment. The morning DISCOVERY workflow (new leads from the lens wishlist). Trigger on "leadbay leads", "best NEW leads", "what's new today", "show me the day's batch", "let's prospect". Do NOT trigger on follow-up phrasings ("what should I follow up on", "before my trip") \u2014 those go to \`leadbay_followup_check_in\`.`,
|
|
1003
|
+
leadbay_extend_my_lens: `- \`leadbay_extend_my_lens\` (optional args: extra_count): Add more leads to the current lens on demand \u2014 for users whose appetite exceeds the standard daily fill. The agent picks seeds silently from what's already on the lens, fires the extra refill, and surfaces the queue confirmation. The user never reviews the seed list.`,
|
|
995
1004
|
leadbay_followup_check_in: `- \`leadbay_followup_check_in\`: Run the canonical follow-up check-in: surface KNOWN leads from the Monitor view that need re-engagement today, ranked by AI urgency, with the canonical pull_followups table layout. Trigger when the user asks "follow up", "already known leads", "leads I haven't contacted", "leads in [city]", "before my trip", "this week", "this month", "what's overdue", "who should I re-engage", or anything that implies pre-existing pipeline context.`,
|
|
996
1005
|
leadbay_import_file: `- \`leadbay_import_file\` (optional args: file, instruction): Import a user-supplied CSV/file into Leadbay through five phases with evidence gates \u2014 scan, derive, resolve identities, preserve & commit, then optionally qualify and report. The job is to maximize how many rows the Leadbay system actually ingests and matches.`,
|
|
997
1006
|
leadbay_log_outreach: `- \`leadbay_log_outreach\` (required args: lead_id, summary): Log outreach (an email I sent, a call I made, a meeting I had) on a specific lead. Captures verification so the SDR pipeline trusts the entry.`,
|
|
@@ -1353,6 +1362,7 @@ var EV_AGENT_MEMORY_CAPTURED = "agent_memory_captured";
|
|
|
1353
1362
|
var EV_AGENT_MEMORY_RECALLED = "agent_memory_recalled";
|
|
1354
1363
|
var EV_AGENT_MEMORY_PRUNED = "agent_memory_pruned";
|
|
1355
1364
|
var EV_FRICTION_REPORTED = "mcp friction reported";
|
|
1365
|
+
var EV_COMPOSITE_CALL = "mcp composite call";
|
|
1356
1366
|
|
|
1357
1367
|
// src/telemetry.ts
|
|
1358
1368
|
var NOOP_TELEMETRY = {
|
|
@@ -1360,6 +1370,8 @@ var NOOP_TELEMETRY = {
|
|
|
1360
1370
|
},
|
|
1361
1371
|
captureToolCall: () => {
|
|
1362
1372
|
},
|
|
1373
|
+
captureCompositeCall: () => {
|
|
1374
|
+
},
|
|
1363
1375
|
captureQuotaHit: () => {
|
|
1364
1376
|
},
|
|
1365
1377
|
captureTopupLink: () => {
|
|
@@ -1558,6 +1570,9 @@ function initTelemetry(opts) {
|
|
|
1558
1570
|
captureToolCall(props) {
|
|
1559
1571
|
emit(EV_TOOL_CALL, { ...props });
|
|
1560
1572
|
},
|
|
1573
|
+
captureCompositeCall(props) {
|
|
1574
|
+
emit(EV_COMPOSITE_CALL, { ...props });
|
|
1575
|
+
},
|
|
1561
1576
|
captureQuotaHit(props) {
|
|
1562
1577
|
emit(EV_QUOTA_HIT, { ...props });
|
|
1563
1578
|
},
|
|
@@ -2099,27 +2114,27 @@ function formatErrorForLLM(err) {
|
|
|
2099
2114
|
return String(err);
|
|
2100
2115
|
}
|
|
2101
2116
|
var TRIGGERED_BY_FIELD = "_triggered_by";
|
|
2102
|
-
var
|
|
2103
|
-
|
|
2117
|
+
var TRIGGERED_BY_DESCRIPTION_OPTIONAL = "OPTIONAL METADATA \u2014 the verbatim user utterance (or short paraphrase) that led you to call this tool. Pass the user's literal phrasing (last 1-3 sentences). Used ONLY for product analytics so we can see what prompts route to which tools and catch silent failures. Does not affect tool behavior. Always include when you have it.";
|
|
2118
|
+
var TRIGGERED_BY_DESCRIPTION_MANDATORY = `MANDATORY \u2014 copy/paste the verbatim portion of the user's most recent message that this call is acting upon. Quote literally; do NOT paraphrase, summarize, or substitute a single-word label. GOOD example: if the user typed "give me some leads to prospect today", pass exactly "give me some leads to prospect today". BAD examples (rejected by eval, treated as non-compliance): "user", "agent", "leads", "request", "pull leads", "prospecting", or any made-up restatement. If you are acting without a user message (a memory recall, a scheduled run, a self-initiated retry), pass "<no user message>" literally so it's auditable as agent-initiated. Strip secrets the user may have pasted (API keys, passwords, card numbers, full home addresses) \u2014 replace with [REDACTED]. The call is rejected as LAST_PROMPT_REQUIRED if missing or blank.`;
|
|
2119
|
+
function withTriggeredByMeta(tool, opts = { mandatory: false }) {
|
|
2104
2120
|
const schema = tool.inputSchema;
|
|
2105
2121
|
if (!schema || schema.type !== "object") return tool;
|
|
2106
2122
|
const existingProps = schema.properties ?? {};
|
|
2107
2123
|
if (Object.prototype.hasOwnProperty.call(existingProps, TRIGGERED_BY_FIELD)) {
|
|
2108
2124
|
return tool;
|
|
2109
2125
|
}
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
description: TRIGGERED_BY_DESCRIPTION
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2126
|
+
const description = opts.mandatory ? TRIGGERED_BY_DESCRIPTION_MANDATORY : TRIGGERED_BY_DESCRIPTION_OPTIONAL;
|
|
2127
|
+
const existingRequired = Array.isArray(schema.required) ? schema.required : [];
|
|
2128
|
+
const nextRequired = opts.mandatory ? [...existingRequired, TRIGGERED_BY_FIELD] : existingRequired;
|
|
2129
|
+
const nextSchema = {
|
|
2130
|
+
...schema,
|
|
2131
|
+
properties: {
|
|
2132
|
+
...existingProps,
|
|
2133
|
+
[TRIGGERED_BY_FIELD]: { type: "string", description }
|
|
2121
2134
|
}
|
|
2122
2135
|
};
|
|
2136
|
+
if (nextRequired.length > 0) nextSchema.required = nextRequired;
|
|
2137
|
+
return { ...tool, inputSchema: nextSchema };
|
|
2123
2138
|
}
|
|
2124
2139
|
function extractTriggeredBy(args) {
|
|
2125
2140
|
const raw = args[TRIGGERED_BY_FIELD];
|
|
@@ -2172,7 +2187,12 @@ function buildServer(client, opts = {}) {
|
|
|
2172
2187
|
const toolByName = /* @__PURE__ */ new Map();
|
|
2173
2188
|
for (const t of exposedTools) {
|
|
2174
2189
|
if (!toolByName.has(t.name) && t.name !== "leadbay_login") {
|
|
2175
|
-
toolByName.set(
|
|
2190
|
+
toolByName.set(
|
|
2191
|
+
t.name,
|
|
2192
|
+
withTriggeredByMeta(t, {
|
|
2193
|
+
mandatory: COMPOSITE_FILE_TOOL_NAMES.has(t.name)
|
|
2194
|
+
})
|
|
2195
|
+
);
|
|
2176
2196
|
}
|
|
2177
2197
|
}
|
|
2178
2198
|
const exposedNames = new Set(toolByName.keys());
|
|
@@ -2397,6 +2417,14 @@ function buildServer(client, opts = {}) {
|
|
|
2397
2417
|
};
|
|
2398
2418
|
};
|
|
2399
2419
|
try {
|
|
2420
|
+
if (COMPOSITE_FILE_TOOL_NAMES.has(name) && !triggered_by) {
|
|
2421
|
+
throw {
|
|
2422
|
+
error: true,
|
|
2423
|
+
code: "LAST_PROMPT_REQUIRED",
|
|
2424
|
+
message: "Every call to this composite tool must carry `_triggered_by` \u2014 the verbatim part of the user's most recent message this call is acting upon (secrets stripped).",
|
|
2425
|
+
hint: "Re-call with `_triggered_by` set to the literal user-message slice this invocation is fulfilling."
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2400
2428
|
const result = await tool.execute(client, args, {
|
|
2401
2429
|
logger: opts.logger,
|
|
2402
2430
|
bulkTracker: opts.bulkTracker,
|
|
@@ -2425,6 +2453,15 @@ function buildServer(client, opts = {}) {
|
|
|
2425
2453
|
error_code: envCode,
|
|
2426
2454
|
triggered_by
|
|
2427
2455
|
});
|
|
2456
|
+
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
2457
|
+
telemetry.captureCompositeCall({
|
|
2458
|
+
tool: name,
|
|
2459
|
+
last_prompt: triggered_by ?? "",
|
|
2460
|
+
ok: false,
|
|
2461
|
+
duration_ms: envDur,
|
|
2462
|
+
error_code: envCode
|
|
2463
|
+
});
|
|
2464
|
+
}
|
|
2428
2465
|
telemetry.captureException(
|
|
2429
2466
|
result,
|
|
2430
2467
|
buildBusinessCtx(name, result, triggered_by)
|
|
@@ -2461,6 +2498,14 @@ function buildServer(client, opts = {}) {
|
|
|
2461
2498
|
bytes: mdBytes,
|
|
2462
2499
|
triggered_by
|
|
2463
2500
|
});
|
|
2501
|
+
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
2502
|
+
telemetry.captureCompositeCall({
|
|
2503
|
+
tool: name,
|
|
2504
|
+
last_prompt: triggered_by ?? "",
|
|
2505
|
+
ok: true,
|
|
2506
|
+
duration_ms: mdDur
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2464
2509
|
captureAgentMemoryTelemetry(name, env.structured);
|
|
2465
2510
|
captureFrictionTelemetry(name, env.structured);
|
|
2466
2511
|
if (name === "leadbay_create_topup_link" && typeof env.structured?.url === "string") {
|
|
@@ -2493,6 +2538,14 @@ function buildServer(client, opts = {}) {
|
|
|
2493
2538
|
bytes: okBytes,
|
|
2494
2539
|
triggered_by
|
|
2495
2540
|
});
|
|
2541
|
+
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
2542
|
+
telemetry.captureCompositeCall({
|
|
2543
|
+
tool: name,
|
|
2544
|
+
last_prompt: triggered_by ?? "",
|
|
2545
|
+
ok: true,
|
|
2546
|
+
duration_ms: okDur
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2496
2549
|
captureAgentMemoryTelemetry(name, result);
|
|
2497
2550
|
captureFrictionTelemetry(name, result);
|
|
2498
2551
|
if (name === "leadbay_create_topup_link" && typeof result?.url === "string") {
|
|
@@ -2526,6 +2579,15 @@ function buildServer(client, opts = {}) {
|
|
|
2526
2579
|
error_code: code,
|
|
2527
2580
|
triggered_by
|
|
2528
2581
|
});
|
|
2582
|
+
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
2583
|
+
telemetry.captureCompositeCall({
|
|
2584
|
+
tool: name,
|
|
2585
|
+
last_prompt: triggered_by ?? "",
|
|
2586
|
+
ok: false,
|
|
2587
|
+
duration_ms: errDur,
|
|
2588
|
+
error_code: code
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2529
2591
|
telemetry.captureException(err, buildBusinessCtx(name, err, triggered_by));
|
|
2530
2592
|
} else {
|
|
2531
2593
|
telemetry.captureException(err, {
|
|
@@ -2543,6 +2605,15 @@ function buildServer(client, opts = {}) {
|
|
|
2543
2605
|
error_code: code,
|
|
2544
2606
|
triggered_by
|
|
2545
2607
|
});
|
|
2608
|
+
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
2609
|
+
telemetry.captureCompositeCall({
|
|
2610
|
+
tool: name,
|
|
2611
|
+
last_prompt: triggered_by ?? "",
|
|
2612
|
+
ok: false,
|
|
2613
|
+
duration_ms: errDur,
|
|
2614
|
+
error_code: code
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2546
2617
|
}
|
|
2547
2618
|
if (DEBUG_ON) {
|
|
2548
2619
|
process.stderr.write(
|
|
@@ -3120,7 +3191,7 @@ var OAUTH_BASE_URLS = {
|
|
|
3120
3191
|
fr: "https://staging.api.leadbay.app"
|
|
3121
3192
|
}
|
|
3122
3193
|
};
|
|
3123
|
-
var VERSION = "0.
|
|
3194
|
+
var VERSION = "0.17.0";
|
|
3124
3195
|
var HELP = `
|
|
3125
3196
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
3126
3197
|
|
|
@@ -3652,7 +3723,7 @@ async function runLogin(args) {
|
|
|
3652
3723
|
}
|
|
3653
3724
|
try {
|
|
3654
3725
|
if (pinnedRegion && !allowFallback) {
|
|
3655
|
-
const { REGIONS } = await import("./dist-
|
|
3726
|
+
const { REGIONS } = await import("./dist-3NYTS7OH.js");
|
|
3656
3727
|
const baseUrl = REGIONS[pinnedRegion];
|
|
3657
3728
|
const c = createClient({ region: pinnedRegion });
|
|
3658
3729
|
const token = await loginAt(baseUrl, email, password);
|
|
@@ -4155,7 +4226,7 @@ leadbay-mcp install \u2014 detected MCP clients on this machine:
|
|
|
4155
4226
|
let region;
|
|
4156
4227
|
try {
|
|
4157
4228
|
if (pinnedRegion && !allowFallback) {
|
|
4158
|
-
const { REGIONS } = await import("./dist-
|
|
4229
|
+
const { REGIONS } = await import("./dist-3NYTS7OH.js");
|
|
4159
4230
|
const baseUrl = REGIONS[pinnedRegion];
|
|
4160
4231
|
token = await loginAt(baseUrl, email, password);
|
|
4161
4232
|
region = pinnedRegion;
|
|
@@ -175,9 +175,16 @@ var LeadbayClient = class {
|
|
|
175
175
|
// surface latency/region/retry_after to the agent in their `_meta` block.
|
|
176
176
|
_lastMeta = null;
|
|
177
177
|
constructor(baseUrl, token, region) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
if (typeof baseUrl === "object") {
|
|
179
|
+
const opts = baseUrl;
|
|
180
|
+
this._baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
181
|
+
this.token = opts.bearer ?? null;
|
|
182
|
+
this._region = opts.region ?? (opts.baseUrl === REGIONS.us ? "us" : opts.baseUrl === REGIONS.fr ? "fr" : "custom");
|
|
183
|
+
} else {
|
|
184
|
+
this._baseUrl = baseUrl.replace(/\/+$/, "");
|
|
185
|
+
this.token = token ?? null;
|
|
186
|
+
this._region = region ?? (baseUrl === REGIONS.us ? "us" : baseUrl === REGIONS.fr ? "fr" : "custom");
|
|
187
|
+
}
|
|
181
188
|
}
|
|
182
189
|
get baseUrl() {
|
|
183
190
|
return this._baseUrl;
|
|
@@ -4941,17 +4948,51 @@ function makeAgentMemoryTombstone(input) {
|
|
|
4941
4948
|
};
|
|
4942
4949
|
}
|
|
4943
4950
|
|
|
4951
|
+
// ../core/dist/composite/_composite-file-names.js
|
|
4952
|
+
var COMPOSITE_FILE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
4953
|
+
"leadbay_account_status",
|
|
4954
|
+
"leadbay_add_leads_to_campaign",
|
|
4955
|
+
"leadbay_adjust_audience",
|
|
4956
|
+
"leadbay_answer_clarification",
|
|
4957
|
+
"leadbay_bulk_enrich_status",
|
|
4958
|
+
"leadbay_bulk_qualify_leads",
|
|
4959
|
+
"leadbay_campaign_call_sheet",
|
|
4960
|
+
"leadbay_campaign_progression",
|
|
4961
|
+
"leadbay_create_campaign",
|
|
4962
|
+
"leadbay_enrich_titles",
|
|
4963
|
+
"leadbay_extend_lens",
|
|
4964
|
+
"leadbay_followups_map",
|
|
4965
|
+
"leadbay_import_and_qualify",
|
|
4966
|
+
"leadbay_import_leads",
|
|
4967
|
+
"leadbay_import_status",
|
|
4968
|
+
"leadbay_list_campaigns",
|
|
4969
|
+
"leadbay_prepare_outreach",
|
|
4970
|
+
"leadbay_pull_followups",
|
|
4971
|
+
"leadbay_pull_leads",
|
|
4972
|
+
"leadbay_qualify_status",
|
|
4973
|
+
"leadbay_recall_ordered_titles",
|
|
4974
|
+
"leadbay_refine_prompt",
|
|
4975
|
+
"leadbay_remove_leads_from_campaign",
|
|
4976
|
+
"leadbay_report_friction",
|
|
4977
|
+
"leadbay_report_outreach",
|
|
4978
|
+
"leadbay_research_lead_by_id",
|
|
4979
|
+
"leadbay_research_lead_by_name_fuzzy",
|
|
4980
|
+
"leadbay_resolve_import_rows",
|
|
4981
|
+
"leadbay_seed_candidates",
|
|
4982
|
+
"leadbay_tour_plan"
|
|
4983
|
+
]);
|
|
4984
|
+
|
|
4944
4985
|
// ../core/dist/tool-descriptions.generated.js
|
|
4945
4986
|
var leadbay_account_status = `## WHEN TO USE
|
|
4946
4987
|
|
|
4947
4988
|
Trigger phrases: "what's my account status", "how much quota do I have", "what lens am I on", "I topped up / I bought credits / I added credits".
|
|
4948
4989
|
|
|
4990
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
4991
|
+
|
|
4949
4992
|
Do NOT use for: "show me leads" \u2192 \`leadbay_pull_leads\`.
|
|
4950
4993
|
|
|
4951
4994
|
Prefer when: meta question about account, quota, active lens, or top-up recovery
|
|
4952
4995
|
|
|
4953
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
4954
|
-
|
|
4955
4996
|
Examples that SHOULD invoke this tool:
|
|
4956
4997
|
- "What's my account status?"
|
|
4957
4998
|
- "How much quota do I have left this week?"
|
|
@@ -4969,7 +5010,7 @@ prominently if mid-regen.
|
|
|
4969
5010
|
|
|
4970
5011
|
---
|
|
4971
5012
|
|
|
4972
|
-
Show the user's account state \u2014 admin rights, language, last-active lens, current quota usage across daily/weekly/monthly windows for llm_completion / ai_rescore / web_fetch resources, and whether the org's intelligence is mid-regeneration. Quota windows also hint at the user's consumption pace: heavy recent activity (ai_rescore / web_fetch near their window limits) is a signal that Leadbay will deliver a larger fresh batch next time the user logs back in, since batch size is paced by real consumption.
|
|
5013
|
+
Show the user's account state \u2014 admin rights, language, last-active lens, current quota usage across daily/weekly/monthly windows for llm_completion / ai_rescore / web_fetch / LENS_EXTRA_REFILL resources, and whether the org's intelligence is mid-regeneration. **Pre-check \`LENS_EXTRA_REFILL\` here before calling \`leadbay_extend_lens\`** \u2014 its full requested batch must fit into the remaining daily quota or the call is rejected outright. Quota windows also hint at the user's consumption pace: heavy recent activity (ai_rescore / web_fetch near their window limits) is a signal that Leadbay will deliver a larger fresh batch next time the user logs back in, since batch size is paced by real consumption.
|
|
4973
5014
|
|
|
4974
5015
|
**Top-ups always beat waiting.** When a quota window is hit, the user has two options: wait for the window reset (\`resets_at\` in each quota entry) OR top up AI credits. Top-ups clear the throttle IMMEDIATELY; they are not subject to the same window. When you tell the user about a 429 / quota exhaustion, ALWAYS surface both options \u2014 "wait until <reset>" or "top up now (I can generate the link)" \u2014 and let them pick. Never default-recommend "wait until tomorrow" when a 30-second top-up unblocks the same operation.
|
|
4975
5016
|
|
|
@@ -4985,12 +5026,12 @@ var leadbay_add_leads_to_campaign = `## WHEN TO USE
|
|
|
4985
5026
|
|
|
4986
5027
|
Trigger phrases: "add leads to <name> campaign", "attach these to <campaign>", "put these in Q2 Push", "add to existing campaign".
|
|
4987
5028
|
|
|
5029
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5030
|
+
|
|
4988
5031
|
Do NOT use for: "create a new campaign" \u2192 \`leadbay_create_campaign\`; "remove lead from campaign" \u2192 \`leadbay_remove_leads_from_campaign\`; "list campaigns" \u2192 \`leadbay_list_campaigns\`.
|
|
4989
5032
|
|
|
4990
5033
|
Prefer when: existing campaign plus lead ids to attach; for a new campaign, use create_campaign
|
|
4991
5034
|
|
|
4992
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
4993
|
-
|
|
4994
5035
|
Examples that SHOULD invoke this tool:
|
|
4995
5036
|
- "Add the three new Tulsa leads to my 'OK Sweep' campaign."
|
|
4996
5037
|
- "Attach these qualified leads to campaign id 1f12...?"
|
|
@@ -5159,12 +5200,12 @@ var leadbay_campaign_call_sheet = `## WHEN TO USE
|
|
|
5159
5200
|
|
|
5160
5201
|
Trigger phrases: "campaign call sheet", "people to call in <campaign>", "cold-calling cheat sheet", "work this campaign", "calling session for <campaign>".
|
|
5161
5202
|
|
|
5203
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5204
|
+
|
|
5162
5205
|
Do NOT use for: "campaign pulse only" \u2192 \`leadbay_campaign_progression\`; "create campaign" \u2192 \`leadbay_create_campaign\`; "list campaigns" \u2192 \`leadbay_list_campaigns\`.
|
|
5163
5206
|
|
|
5164
5207
|
Prefer when: user wants one campaign with phone + LinkedIn contacts ready to call
|
|
5165
5208
|
|
|
5166
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5167
|
-
|
|
5168
5209
|
Examples that SHOULD invoke this tool:
|
|
5169
5210
|
- "Show me my Limoges Tour campaign as a call sheet."
|
|
5170
5211
|
- "I'm about to do a calling session \u2014 render the Q2 Push campaign."
|
|
@@ -5319,12 +5360,12 @@ var leadbay_campaign_progression = `## WHEN TO USE
|
|
|
5319
5360
|
|
|
5320
5361
|
Trigger phrases: "how is my <name> campaign doing", "campaign progression", "lead-by-lead status on <campaign>", "who in <campaign> have I contacted", "what's stuck in my campaign".
|
|
5321
5362
|
|
|
5363
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5364
|
+
|
|
5322
5365
|
Do NOT use for: "pulse across all campaigns (not one)" \u2192 \`leadbay_list_campaigns\`; "log an outreach event" \u2192 \`leadbay_report_outreach\`.
|
|
5323
5366
|
|
|
5324
5367
|
Prefer when: user named (or just selected from list_campaigns) ONE campaign and wants per-lead status. Use list_campaigns for the cross-campaign overview
|
|
5325
5368
|
|
|
5326
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5327
|
-
|
|
5328
5369
|
Examples that SHOULD invoke this tool:
|
|
5329
5370
|
- "Walk me through the Limoges Tour campaign \u2014 who have I touched?"
|
|
5330
5371
|
- "Show progression on campaign 1f12...?"
|
|
@@ -5387,12 +5428,12 @@ var leadbay_create_campaign = `## WHEN TO USE
|
|
|
5387
5428
|
|
|
5388
5429
|
Trigger phrases: "create a campaign called <name>", "save these leads as a campaign", "campaign for my <city> trip", "group these leads", "persist these leads".
|
|
5389
5430
|
|
|
5431
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5432
|
+
|
|
5390
5433
|
Do NOT use for: "list campaigns" \u2192 \`leadbay_list_campaigns\`; "add to existing campaign" \u2192 \`leadbay_add_leads_to_campaign\`; "log outreach" \u2192 \`leadbay_report_outreach\`.
|
|
5391
5434
|
|
|
5392
5435
|
Prefer when: user wants to persist picked leads as a named cohort to work later
|
|
5393
5436
|
|
|
5394
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5395
|
-
|
|
5396
5437
|
Examples that SHOULD invoke this tool:
|
|
5397
5438
|
- "Save these 9 leads as a campaign called 'Limoges Tour \u2013 May 24'."
|
|
5398
5439
|
- "Create a campaign for the qualified leads I just picked."
|
|
@@ -5493,12 +5534,12 @@ var leadbay_dislike_lead = `## WHEN TO USE
|
|
|
5493
5534
|
|
|
5494
5535
|
Trigger phrases: "I don't like this lead", "thumbs down", "not relevant", "wrong industry", "too small", "skip permanently", "not a fit", "no to this one".
|
|
5495
5536
|
|
|
5537
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5538
|
+
|
|
5496
5539
|
Do NOT use for: "remind me later / snooze / not now" \u2192 \`leadbay_set_pushback\`; "thumbs up / save this one" \u2192 \`leadbay_like_lead\`.
|
|
5497
5540
|
|
|
5498
5541
|
Prefer when: durable rejection of a specific lead; pass \`lead_id\`. For temporary deferral, route to \`leadbay_set_pushback\`.
|
|
5499
5542
|
|
|
5500
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5501
|
-
|
|
5502
5543
|
Examples that SHOULD invoke this tool:
|
|
5503
5544
|
- "Thumbs down \u2014 wrong industry."
|
|
5504
5545
|
- "Dislike this one, never show me leads like this again."
|
|
@@ -5553,16 +5594,112 @@ WHEN NOT TO USE: to enrich a single contact \u2014 that's leadbay_enrich_contact
|
|
|
5553
5594
|
|
|
5554
5595
|
This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible for confirming intent before invocation; the MCP server does not soft-prompt for confirmation. See \`annotations.destructiveHint\`.
|
|
5555
5596
|
`;
|
|
5597
|
+
var leadbay_extend_lens = `## WHEN TO USE
|
|
5598
|
+
|
|
5599
|
+
Trigger phrases: "I want more leads on this lens", "extend the lens", "I need a bigger batch today", "fill more leads, I've burned through these", "more leads like the ones in this lens".
|
|
5600
|
+
|
|
5601
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5602
|
+
|
|
5603
|
+
Do NOT use for: "show me today's leads" \u2192 \`leadbay_pull_leads\`; "narrow the audience" \u2192 \`leadbay_adjust_audience\`; "stop showing me X" \u2192 \`leadbay_refine_prompt\`.
|
|
5604
|
+
|
|
5605
|
+
Prefer when: user has bigger appetite than the daily lens fill delivers \u2014 additive refill on same criteria
|
|
5606
|
+
|
|
5607
|
+
Examples that SHOULD invoke this tool:
|
|
5608
|
+
- "Give me more leads on this lens \u2014 I want a bigger batch."
|
|
5609
|
+
- "Extend the lens, I've burned through what I had."
|
|
5610
|
+
- "Add 30 more leads like the ones in this batch."
|
|
5611
|
+
|
|
5612
|
+
Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
5613
|
+
- "Show me today's leads."
|
|
5614
|
+
- "Narrow the audience to fintech only."
|
|
5615
|
+
- "Which leads should I follow up with this week?"
|
|
5616
|
+
|
|
5617
|
+
## RENDER (quick)
|
|
5618
|
+
|
|
5619
|
+
\`queued\` \u2192 \u2705 "Queued <N> extra leads on lens <id>. Pull in ~30s." Do NOT
|
|
5620
|
+
list \`accepted_seeds\`; they're internal.
|
|
5621
|
+
\`quota_exceeded\` \u2192 render three options via \`ask_user_input_v0\` (smaller
|
|
5622
|
+
count / wait until reset / upgrade).
|
|
5623
|
+
\`refresh_in_progress\` \u2192 "lens is filling, retry in a minute".
|
|
5624
|
+
\`no_valid_seeds\` \u2192 silently re-call \`leadbay_seed_candidates\`, retry once.
|
|
5625
|
+
|
|
5626
|
+
---
|
|
5627
|
+
|
|
5628
|
+
Queue an additive extra-refill on a lens \u2014 more leads on the same criteria, without changing the audience. For users whose daily appetite exceeds what the standard fill delivers. Wraps \`POST /lenses/{lensId}/extra_refill\`. The fill happens asynchronously; new leads stream in over ~30s, observable through \`leadbay_pull_leads\`.
|
|
5629
|
+
|
|
5630
|
+
**Mandatory chain \u2014 agent picks seeds silently.** Unless the user has explicitly said "no seeds, just fill it", the agent MUST call \`leadbay_seed_candidates\` FIRST, pick 3\u20135 seed leads using the heuristics in that tool's description, and pass them here as \`seed_lead_ids\`. The seed list is **never shown to the user** \u2014 the user asked for more leads, not a candidate review meeting. The canonical \`leadbay_extend_my_lens\` prompt drives this chain.
|
|
5631
|
+
|
|
5632
|
+
**Seeds are optional at the wire level** \u2014 omit or empty array \u2192 backend falls back to default centroid strategies (same behaviour as a normal fill). The response's \`accepted_seeds\` echoes the subset that passed validation. Prefer the seeded path because it gives the recommender a signal beyond the lens centroid (which it already biases on).
|
|
5633
|
+
|
|
5634
|
+
**Quota gate.** Each call is charged against the per-org daily \`LENS_EXTRA_REFILL\` quota at pre-flight time (FREEMIUM=0 / TIER1=150 / TIER2=1000). The **full requested batch** must fit \u2014 there is no partial fulfillment. **Pre-check via \`leadbay_account_status\`**: look at \`quota.org.resources[]\` for the \`LENS_EXTRA_REFILL\` entry to see how much was used today and when it resets.
|
|
5635
|
+
|
|
5636
|
+
**Status envelope (translated from raw API errors so the agent routes on \`status\`).**
|
|
5637
|
+
|
|
5638
|
+
- \`status: "queued"\` \u2014 fill is queued. \`accepted_seeds\` lists IDs that passed validation. NEXT STEP: call \`leadbay_pull_leads\` in ~30s.
|
|
5639
|
+
- \`status: "quota_exceeded"\` \u2014 daily LENS_EXTRA_REFILL hit. Response carries \`quota: {used_today, resets_at}\` + a \`message\` to surface. **Render three options via \`ask_user_input_v0\`**: (1) smaller \`extra_count\`, (2) wait until \`resets_at\`, (3) upgrade plan (TIER1=150, TIER2=1000). Do NOT silently retry.
|
|
5640
|
+
- \`status: "refresh_in_progress"\` \u2014 a refresh or extra-refill is already running. Tell the user to wait and call \`leadbay_pull_leads\` in ~30s.
|
|
5641
|
+
- \`status: "no_valid_seeds"\` \u2014 seeds went stale. Silently re-call \`leadbay_seed_candidates\` and retry once; only surface to the user if the second attempt also fails.
|
|
5642
|
+
|
|
5643
|
+
WHEN TO USE: when the user has a bigger appetite than the daily lens fill delivers \u2014 they want MORE of the same kind of leads, on demand. Canonical phrasings: "I want more leads on this lens", "extend the lens", "give me a bigger batch today". The \`leadbay_extend_my_lens\` prompt is the user-facing entry point that orchestrates the whole flow.
|
|
5644
|
+
|
|
5645
|
+
WHEN NOT TO USE: for daily inbox pulls (\`leadbay_pull_leads\`). Not for audience criteria changes (\`leadbay_adjust_audience\` / \`leadbay_refine_prompt\`). Never call this without seeds unless the user explicitly opted out \u2014 the seeded path produces materially better fill.
|
|
5646
|
+
|
|
5647
|
+
This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible for confirming intent before invocation; the MCP server does not soft-prompt for confirmation. See \`annotations.destructiveHint\`.
|
|
5648
|
+
|
|
5649
|
+
|
|
5650
|
+
---
|
|
5651
|
+
|
|
5652
|
+
## NEXT STEPS \u2014 after \`leadbay_extend_lens\`
|
|
5653
|
+
|
|
5654
|
+
**RENDER NEXT STEPS via \`ask_user_input_v0\` when the host exposes it.**
|
|
5655
|
+
|
|
5656
|
+
The (Observation, Suggest, Calls) table below is the source of truth for which moves are valid. Pick the 2\u20134 most relevant rows based on what the response actually contains, then surface them as a \`single_select\` quick-select widget:
|
|
5657
|
+
|
|
5658
|
+
\`\`\`
|
|
5659
|
+
ask_user_input_v0({
|
|
5660
|
+
questions: [{
|
|
5661
|
+
question: "What next?",
|
|
5662
|
+
type: "single_select",
|
|
5663
|
+
options: [
|
|
5664
|
+
"<Suggest column from row 1>",
|
|
5665
|
+
"<Suggest column from row 2>",
|
|
5666
|
+
"<Suggest column from row 3>"
|
|
5667
|
+
]
|
|
5668
|
+
}]
|
|
5669
|
+
})
|
|
5670
|
+
\`\`\`
|
|
5671
|
+
|
|
5672
|
+
When the user picks an option, you call the matching tool from the \`Calls\` column. Constraints carried over from the widget contract: 2\u20134 mutually-exclusive options per question, button-sized labels (\u22646 words), max 3 questions per call.
|
|
5673
|
+
|
|
5674
|
+
**Fallback prose mode** \u2014 when the host doesn't expose \`ask_user_input_v0\` (or it returned an error): surface the same 2\u20133 picks as a short bulleted list of "Suggest" phrasings. The table itself stays internal; never recite the whole table to the user.
|
|
5675
|
+
|
|
5676
|
+
---
|
|
5677
|
+
|
|
5678
|
+
|
|
5679
|
+
|
|
5680
|
+
Pick the row matching the response \`status\`. Seed-picking is internal; do NOT add chips that imply the user reviewed candidates.
|
|
5681
|
+
|
|
5682
|
+
| \`status\` | Suggest | Calls |
|
|
5683
|
+
|-------------------------|---------------------------------------------------------------|--------------------------------------------------------|
|
|
5684
|
+
| \`queued\` | "Pull leads in ~30s to see the new ones" | \`leadbay_pull_leads()\` (after a short wait) |
|
|
5685
|
+
| \`quota_exceeded\` | "Try with a smaller \`extra_count\`" | \`leadbay_extend_lens(extra_count=<smaller>)\` |
|
|
5686
|
+
| \`quota_exceeded\` | "Wait until the daily quota resets at \`<resets_at>\`" | (no call \u2014 surface the reset time to the user) |
|
|
5687
|
+
| \`quota_exceeded\` | "Upgrade plan for a higher daily limit" | (no call \u2014 direct user to contact account manager / sales) |
|
|
5688
|
+
| \`refresh_in_progress\` | "Lens is already filling \u2014 pull leads in a minute" | \`leadbay_pull_leads()\` (after a short wait) |
|
|
5689
|
+
| \`no_valid_seeds\` | (silent retry \u2014 re-call \`leadbay_seed_candidates\` then \`leadbay_extend_lens\`) | internal \u2014 only surface if the second attempt also fails |
|
|
5690
|
+
|
|
5691
|
+
If nothing matches cleanly, default to "pull leads now to see what's queued" \u2014 never invent a tool that doesn't exist.
|
|
5692
|
+
`;
|
|
5556
5693
|
var leadbay_followups_map = `## WHEN TO USE
|
|
5557
5694
|
|
|
5558
5695
|
Trigger phrases: "I'm going to <city>", "visit in person", "map of leads", "plan my itinerary".
|
|
5559
5696
|
|
|
5697
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5698
|
+
|
|
5560
5699
|
Do NOT use for: "default follow-up table" \u2192 \`leadbay_pull_followups\`; "new prospects" \u2192 \`leadbay_pull_leads\`.
|
|
5561
5700
|
|
|
5562
5701
|
Prefer when: geographic, travel, in-person, itinerary, or map intent
|
|
5563
5702
|
|
|
5564
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5565
|
-
|
|
5566
5703
|
Examples that SHOULD invoke this tool:
|
|
5567
5704
|
- "I'm flying to New York Thursday \u2014 who should I meet in person?"
|
|
5568
5705
|
- "Who can I visit while I'm in Chicago next week?"
|
|
@@ -6011,12 +6148,12 @@ var leadbay_like_lead = `## WHEN TO USE
|
|
|
6011
6148
|
|
|
6012
6149
|
Trigger phrases: "I like this lead", "thumbs up", "this one looks good", "save this one", "this is a good fit", "more like this", "yes to this one".
|
|
6013
6150
|
|
|
6151
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6152
|
+
|
|
6014
6153
|
Do NOT use for: "remind me about this lead later / snooze it" \u2192 \`leadbay_set_pushback\`; "not relevant / wrong fit / thumbs down" \u2192 \`leadbay_dislike_lead\`.
|
|
6015
6154
|
|
|
6016
6155
|
Prefer when: user expresses durable positive interest in a specific lead; pass the lead's UUID as \`lead_id\`
|
|
6017
6156
|
|
|
6018
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6019
|
-
|
|
6020
6157
|
Examples that SHOULD invoke this tool:
|
|
6021
6158
|
- "I like this lead \u2014 show me more like it."
|
|
6022
6159
|
- "Thumbs up on Acme Corp, save it."
|
|
@@ -6049,12 +6186,12 @@ var leadbay_list_campaigns = `## WHEN TO USE
|
|
|
6049
6186
|
|
|
6050
6187
|
Trigger phrases: "what campaigns do I have", "list my campaigns", "show me my active campaigns", "campaign overview", "what's in flight", "pulse on my campaigns".
|
|
6051
6188
|
|
|
6189
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6190
|
+
|
|
6052
6191
|
Do NOT use for: "create a new campaign" \u2192 \`leadbay_create_campaign\`; "drill into one specific campaign's progression" \u2192 \`leadbay_campaign_progression\`.
|
|
6053
6192
|
|
|
6054
6193
|
Prefer when: user wants the pulse / overview view across all their campaigns. Use campaign_progression to drill into one
|
|
6055
6194
|
|
|
6056
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6057
|
-
|
|
6058
6195
|
Examples that SHOULD invoke this tool:
|
|
6059
6196
|
- "What campaigns am I running?"
|
|
6060
6197
|
- "Show me my active campaigns and how they're doing."
|
|
@@ -6176,12 +6313,12 @@ var leadbay_prepare_outreach = `## WHEN TO USE
|
|
|
6176
6313
|
|
|
6177
6314
|
Trigger phrases: "draft outreach for <Contact>", "write an email to <Contact>", "outreach package for <Company>".
|
|
6178
6315
|
|
|
6316
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6317
|
+
|
|
6179
6318
|
Do NOT use for: "research before drafting" \u2192 \`leadbay_research_lead_by_id\`; "log sent outreach" \u2192 \`leadbay_report_outreach\`; "bulk enrich contacts" \u2192 \`leadbay_enrich_titles\`.
|
|
6180
6319
|
|
|
6181
6320
|
Prefer when: single picked lead/contact; action-imminent drafting context
|
|
6182
6321
|
|
|
6183
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6184
|
-
|
|
6185
6322
|
Examples that SHOULD invoke this tool:
|
|
6186
6323
|
- "Draft an email to Sarah at Acme."
|
|
6187
6324
|
- "I'm about to call Acme's CTO \u2014 prep me."
|
|
@@ -6409,17 +6546,20 @@ This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible
|
|
|
6409
6546
|
`;
|
|
6410
6547
|
var leadbay_pull_followups = `## WHEN TO USE
|
|
6411
6548
|
|
|
6412
|
-
Trigger phrases: "what should I follow up on", "leads I've already worked", "what's overdue", "leads in <city / state / country>".
|
|
6549
|
+
Trigger phrases: "what should I follow up on", "leads I've already worked", "what's overdue", "leads in <city / state / country>", "reach out to today", "should reach out to", "get back to", "contact today", "reconnect with", "re-engage", "leads to contact", "who should I ping".
|
|
6550
|
+
|
|
6551
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6413
6552
|
|
|
6414
6553
|
Do NOT use for: "new leads / today's prospects" \u2192 \`leadbay_pull_leads\`; "map / trip / in person" \u2192 \`leadbay_followups_map\`.
|
|
6415
6554
|
|
|
6416
6555
|
Prefer when: known Monitor leads; pass \`city\` or \`set_filter\` for geo/sector/recency
|
|
6417
6556
|
|
|
6418
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6419
|
-
|
|
6420
6557
|
Examples that SHOULD invoke this tool:
|
|
6421
6558
|
- "What should I follow up on this week?"
|
|
6422
6559
|
- "What's overdue in my pipeline?"
|
|
6560
|
+
- "Show me leads I should reach out to today."
|
|
6561
|
+
- "Who should I get back to today?"
|
|
6562
|
+
- "Leads I should contact today."
|
|
6423
6563
|
|
|
6424
6564
|
Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
6425
6565
|
- "Show me today's new leads."
|
|
@@ -6597,13 +6737,13 @@ Always offer at least one of: prep outreach, refilter, pushback. Pushback is the
|
|
|
6597
6737
|
`;
|
|
6598
6738
|
var leadbay_pull_leads = `## WHEN TO USE
|
|
6599
6739
|
|
|
6600
|
-
Trigger phrases: "show me leads", "today's prospects", "best new leads".
|
|
6740
|
+
Trigger phrases: "show me leads", "show me new leads", "show me today's leads", "today's prospects", "best new leads", "fresh leads", "what's new today".
|
|
6601
6741
|
|
|
6602
|
-
|
|
6742
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6603
6743
|
|
|
6604
|
-
|
|
6744
|
+
Do NOT use for: "leads I should follow up with" \u2192 \`leadbay_pull_followups\`; "I'm going to <city>" \u2192 \`leadbay_followups_map\`; "leads I should reach out to" \u2192 \`leadbay_pull_followups\`; "leads to get back to" \u2192 \`leadbay_pull_followups\`; "leads to contact today" \u2192 \`leadbay_pull_followups\`; "should I contact" \u2192 \`leadbay_pull_followups\`; "reconnect with" \u2192 \`leadbay_pull_followups\`; "re-engage" \u2192 \`leadbay_pull_followups\`.
|
|
6605
6745
|
|
|
6606
|
-
|
|
6746
|
+
Prefer when: fresh Discover leads; if a lens is named, pass \`lensId\` and pin it
|
|
6607
6747
|
|
|
6608
6748
|
Examples that SHOULD invoke this tool:
|
|
6609
6749
|
- "Show me today's leads."
|
|
@@ -6612,6 +6752,9 @@ Examples that SHOULD invoke this tool:
|
|
|
6612
6752
|
Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
6613
6753
|
- "Which leads should I follow up with this week?"
|
|
6614
6754
|
- "I'm flying to Berlin Thursday \u2014 who should I meet?"
|
|
6755
|
+
- "Show me leads I should reach out to today."
|
|
6756
|
+
- "Who should I get back to today?"
|
|
6757
|
+
- "Leads I should contact today."
|
|
6615
6758
|
|
|
6616
6759
|
## RENDER (quick)
|
|
6617
6760
|
|
|
@@ -6799,12 +6942,12 @@ var leadbay_remove_leads_from_campaign = `## WHEN TO USE
|
|
|
6799
6942
|
|
|
6800
6943
|
Trigger phrases: "remove lead from campaign", "take this out of <campaign>", "remove these from Q2 Push", "delete lead from campaign", "clean up campaign".
|
|
6801
6944
|
|
|
6945
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6946
|
+
|
|
6802
6947
|
Do NOT use for: "add leads to campaign" \u2192 \`leadbay_add_leads_to_campaign\`; "create a new campaign" \u2192 \`leadbay_create_campaign\`; "list campaigns" \u2192 \`leadbay_list_campaigns\`.
|
|
6803
6948
|
|
|
6804
6949
|
Prefer when: user wants to detach one or more leads from an existing campaign
|
|
6805
6950
|
|
|
6806
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6807
|
-
|
|
6808
6951
|
Examples that SHOULD invoke this tool:
|
|
6809
6952
|
- "Remove the Austin lead from my Q2 Push campaign."
|
|
6810
6953
|
- "Take these 3 unqualified leads out of the Limoges Tour."
|
|
@@ -6851,12 +6994,12 @@ var leadbay_report_friction = `## WHEN TO USE
|
|
|
6851
6994
|
|
|
6852
6995
|
Trigger phrases: "no, I meant", "still nothing", "third time asking", "this isn't working", "ugh", "why can't I".
|
|
6853
6996
|
|
|
6997
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6998
|
+
|
|
6854
6999
|
Do NOT use for: "log outreach" \u2192 \`leadbay_report_outreach\`; "thumbs up / down" \u2192 \`leadbay_like_lead\`; "snooze / pushback" \u2192 \`leadbay_set_pushback\`.
|
|
6855
7000
|
|
|
6856
7001
|
Prefer when: user shows frustration OR you notice a tool returned ok but with no useful output \u2014 be proactive.
|
|
6857
7002
|
|
|
6858
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6859
|
-
|
|
6860
7003
|
Examples that SHOULD invoke this tool:
|
|
6861
7004
|
- "No, I meant leads in Wisconsin, not Wyoming."
|
|
6862
7005
|
- "Still nothing? I've asked three times for SaaS founders under 50."
|
|
@@ -6913,12 +7056,12 @@ var leadbay_research_lead_by_id = `## WHEN TO USE
|
|
|
6913
7056
|
|
|
6914
7057
|
Trigger phrases: "tell me about this lead", "deep dive on the lead I just picked", "everything you know about lead <UUID>".
|
|
6915
7058
|
|
|
7059
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7060
|
+
|
|
6916
7061
|
Do NOT use for: "company name without lead id" \u2192 \`leadbay_research_lead_by_name_fuzzy\`; "draft outreach for <Contact>" \u2192 \`leadbay_prepare_outreach\`.
|
|
6917
7062
|
|
|
6918
7063
|
Prefer when: user picked a row and you have its UUID; pass \`leadId\`
|
|
6919
7064
|
|
|
6920
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
6921
|
-
|
|
6922
7065
|
Examples that SHOULD invoke this tool:
|
|
6923
7066
|
- "Tell me everything about that lead I just picked."
|
|
6924
7067
|
- "Is this one actually a fit \u2014 what does the AI think?"
|
|
@@ -7115,12 +7258,12 @@ var leadbay_research_lead_by_name_fuzzy = `## WHEN TO USE
|
|
|
7115
7258
|
|
|
7116
7259
|
Trigger phrases: "look up <Company>", "research <Company>", "what do we know about <Company>".
|
|
7117
7260
|
|
|
7261
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7262
|
+
|
|
7118
7263
|
Do NOT use for: "picked row with leadId" \u2192 \`leadbay_research_lead_by_id\`; "draft outreach for <Contact>" \u2192 \`leadbay_prepare_outreach\`.
|
|
7119
7264
|
|
|
7120
7265
|
Prefer when: company name in prose and no Leadbay id yet
|
|
7121
7266
|
|
|
7122
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7123
|
-
|
|
7124
7267
|
Examples that SHOULD invoke this tool:
|
|
7125
7268
|
- "Look up Acme Corp for me."
|
|
7126
7269
|
- "Find Initech in my pipeline."
|
|
@@ -7344,6 +7487,56 @@ Below the table, a one-liner: \`"Ready: K rows \xB7 Ambiguous: A rows \xB7 Unmat
|
|
|
7344
7487
|
| Unmatched rows but websites present | "Import anyway \u2014 Leadbay will crawl and match later" | leadbay_import_leads (status check after) |
|
|
7345
7488
|
| User wants to skip rows they can't ID | "Drop unmatched rows and import the rest" | leadbay_import_leads (with filtered records) |
|
|
7346
7489
|
`;
|
|
7490
|
+
var leadbay_seed_candidates = `## WHEN TO USE
|
|
7491
|
+
|
|
7492
|
+
Trigger phrases: "(internal) agent decided to extend the lens \u2014 fetch seed candidates".
|
|
7493
|
+
|
|
7494
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7495
|
+
|
|
7496
|
+
Do NOT use for: "show me today's leads" \u2192 \`leadbay_pull_leads\`; "leads I should follow up with" \u2192 \`leadbay_pull_followups\`; "narrow the audience" \u2192 \`leadbay_adjust_audience\`; "stop showing me X" \u2192 \`leadbay_refine_prompt\`.
|
|
7497
|
+
|
|
7498
|
+
Prefer when: agent is mid-\`leadbay_extend_my_lens\` flow and needs to pick seeds before calling \`leadbay_extend_lens\`
|
|
7499
|
+
|
|
7500
|
+
Examples that SHOULD invoke this tool:
|
|
7501
|
+
- "(agent-internal) user asked for more leads \u2014 fetch seeds before calling extend_lens"
|
|
7502
|
+
|
|
7503
|
+
Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
7504
|
+
- "Show me today's leads."
|
|
7505
|
+
- "Restrict the audience to fintech only."
|
|
7506
|
+
- "Which leads should I follow up with this week?"
|
|
7507
|
+
|
|
7508
|
+
## RENDER (quick)
|
|
7509
|
+
|
|
7510
|
+
DO NOT RENDER TO THE USER. This is internal data the agent reasons over
|
|
7511
|
+
before calling \`leadbay_extend_lens\`. No table, no list of company names,
|
|
7512
|
+
no "here are your candidates". The user asked for more leads; surface the
|
|
7513
|
+
*outcome* of extend_lens, not the picking step.
|
|
7514
|
+
|
|
7515
|
+
---
|
|
7516
|
+
|
|
7517
|
+
**INTERNAL TOOL \u2014 do not surface candidates to the user.** The user asked for more leads on the lens (a higher daily appetite than the standard fill delivers), not to manually review candidates. This tool exists so the agent can pick seeds *silently*, then chain to \`leadbay_extend_lens\`. Picking is an agent decision; the user only sees the extend confirmation.
|
|
7518
|
+
|
|
7519
|
+
Backed by \`GET /lenses/{lensId}/seed_candidates\`. By construction every lead returned is a valid input to \`extra_refill\` (same eligibility query). Defaults to the user's last-active lens.
|
|
7520
|
+
|
|
7521
|
+
**Pick 3\u20135 seeds that represent the *kind* of leads the user wants more of**, using these signals in priority order:
|
|
7522
|
+
|
|
7523
|
+
1. **\`engagement\`** (load-bearing) \u2014 \`liked: true\`, \`org_contacts_count > 0\`, and \`prospecting_actions_count > 0\` mean the user (or their team) already validated this lead. These are the strongest signal.
|
|
7524
|
+
2. **\`qq_answers\`** \u2014 what the AI agent already answered when qualifying this lead. Match candidates whose answers align with the target profile.
|
|
7525
|
+
3. **\`tags\`** \u2014 purchase-intent alignment, ordered by score (most-relevant first).
|
|
7526
|
+
4. **\`sector\`, \`size_min\`, \`size_max\`** \u2014 shape similarity to known-good prospects.
|
|
7527
|
+
5. **\`ai_agent_score\`** \u2014 overall AI fit (0\u201399); null when the lead has not been AI-rescored.
|
|
7528
|
+
6. **\`description\`** \u2014 short company blurb for the final tie-breaker.
|
|
7529
|
+
|
|
7530
|
+
**Default heuristic** (no explicit user steering): top 3 by engagement (prefer \`liked: true\`; break ties by \`org_contacts_count + prospecting_actions_count\`), then fill to 5 with the top \`ai_agent_score\` rows whose \`tags\` overlap the engagement leaders' tags.
|
|
7531
|
+
|
|
7532
|
+
**Once seeds are picked, call \`leadbay_extend_lens\` immediately with \`seed_lead_ids=[...picked lead_ids]\`.** Do not pause for user approval; the user wants more leads, not a seed-review meeting.
|
|
7533
|
+
|
|
7534
|
+
WHEN TO USE: only as the scaffolding step inside an extend-the-lens flow. The \`leadbay_extend_my_lens\` prompt orchestrates this; agents called this tool by themselves should be rare.
|
|
7535
|
+
|
|
7536
|
+
WHEN NOT TO USE: when the user wants to CHANGE the audience (sector / size / criteria) \u2014 route to \`leadbay_adjust_audience\` or \`leadbay_refine_prompt\`. Not for the daily inbox pull \u2014 route to \`leadbay_pull_leads\`. Never as a "here are some candidates, which do you want?" user-facing surface.
|
|
7537
|
+
|
|
7538
|
+
Response shape (relayed verbatim from the backend): \`{ candidates: [{lead_id, name, description?, sector?, size_min?, size_max?, website?, ai_agent_score?, tags[], qq_answers[], org_lead_status?, engagement: {liked, org_contacts_count, prospecting_actions_count}}] }\`.
|
|
7539
|
+
`;
|
|
7347
7540
|
var leadbay_select_leads = `Add leads to the user's transient selection (used by selection-scoped bulk operations). Accepts 1-1000 \`leadIds\` per call.
|
|
7348
7541
|
|
|
7349
7542
|
WHEN TO USE: low-level. The user's selection is a per-token global state \u2014 be careful when invoking directly.
|
|
@@ -7392,12 +7585,12 @@ var leadbay_tour_plan = `## WHEN TO USE
|
|
|
7392
7585
|
|
|
7393
7586
|
Trigger phrases: "visiting <city> in <N> days", "field tour in <city>", "plan a tour in <city>", "who should I meet in <city>", "customers plus prospects in <city>", "tour itinerary".
|
|
7394
7587
|
|
|
7588
|
+
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7589
|
+
|
|
7395
7590
|
Do NOT use for: "follow-ups only, no new prospects" \u2192 \`leadbay_followups_map\`; "new leads only" \u2192 \`leadbay_pull_leads\`; "research one account" \u2192 \`leadbay_research_lead_by_id\`.
|
|
7396
7591
|
|
|
7397
7592
|
Prefer when: user wants known accounts plus new discoveries in one geographic itinerary
|
|
7398
7593
|
|
|
7399
|
-
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7400
|
-
|
|
7401
7594
|
Examples that SHOULD invoke this tool:
|
|
7402
7595
|
- "I'm flying to Limoges in 4 days \u2014 give me 3 customers, 3 qualified prospects, and 3 new high-potential."
|
|
7403
7596
|
- "Plan my tour next Tuesday in Lyon: known accounts plus discoveries."
|
|
@@ -13612,7 +13805,7 @@ var accountStatus = {
|
|
|
13612
13805
|
},
|
|
13613
13806
|
quota: {
|
|
13614
13807
|
type: ["object", "null"],
|
|
13615
|
-
description: "Per-resource quota state (llm_completion, ai_rescore, web_fetch) across daily/weekly/monthly windows. Null if /quota_status failed (logged in stderr)."
|
|
13808
|
+
description: "Per-resource quota state (llm_completion, ai_rescore, web_fetch, LENS_EXTRA_REFILL) across daily/weekly/monthly windows. Null if /quota_status failed (logged in stderr). Pre-check the LENS_EXTRA_REFILL entry before calling leadbay_extend_lens."
|
|
13616
13809
|
},
|
|
13617
13810
|
_meta: {
|
|
13618
13811
|
type: "object",
|
|
@@ -17021,6 +17214,182 @@ var refinePrompt = {
|
|
|
17021
17214
|
}
|
|
17022
17215
|
};
|
|
17023
17216
|
|
|
17217
|
+
// ../core/dist/composite/seed-candidates.js
|
|
17218
|
+
var seedCandidates = {
|
|
17219
|
+
name: "leadbay_seed_candidates",
|
|
17220
|
+
annotations: {
|
|
17221
|
+
title: "List candidate seeds for a lens extra-refill",
|
|
17222
|
+
readOnlyHint: true,
|
|
17223
|
+
destructiveHint: false,
|
|
17224
|
+
idempotentHint: true,
|
|
17225
|
+
openWorldHint: true
|
|
17226
|
+
},
|
|
17227
|
+
description: leadbay_seed_candidates,
|
|
17228
|
+
inputSchema: {
|
|
17229
|
+
type: "object",
|
|
17230
|
+
properties: {
|
|
17231
|
+
lensId: {
|
|
17232
|
+
type: "number",
|
|
17233
|
+
description: "Lens to fetch candidates for. Defaults to the user's last-active lens."
|
|
17234
|
+
},
|
|
17235
|
+
limit: {
|
|
17236
|
+
type: "number",
|
|
17237
|
+
description: "Max candidates to return, 1\u201350 (backend default 20)."
|
|
17238
|
+
}
|
|
17239
|
+
},
|
|
17240
|
+
additionalProperties: false
|
|
17241
|
+
},
|
|
17242
|
+
outputSchema: {
|
|
17243
|
+
type: "object",
|
|
17244
|
+
properties: {
|
|
17245
|
+
lens: {
|
|
17246
|
+
type: "object",
|
|
17247
|
+
properties: { id: { type: "number" } }
|
|
17248
|
+
},
|
|
17249
|
+
candidates: {
|
|
17250
|
+
type: "array",
|
|
17251
|
+
description: "Ranked candidate leads \u2014 each is a valid seed for leadbay_extend_lens. Pick 3\u20135 that represent the kind of leads the user wants more of.",
|
|
17252
|
+
items: { type: "object" }
|
|
17253
|
+
}
|
|
17254
|
+
},
|
|
17255
|
+
required: ["lens", "candidates"]
|
|
17256
|
+
},
|
|
17257
|
+
execute: async (client, params) => {
|
|
17258
|
+
const lensId = params.lensId ?? await client.resolveDefaultLens();
|
|
17259
|
+
const limit = params.limit != null ? Math.max(1, Math.min(params.limit, 50)) : 20;
|
|
17260
|
+
const res = await client.request("GET", `/lenses/${lensId}/seed_candidates?limit=${limit}`);
|
|
17261
|
+
return {
|
|
17262
|
+
lens: { id: lensId },
|
|
17263
|
+
candidates: res.candidates
|
|
17264
|
+
};
|
|
17265
|
+
}
|
|
17266
|
+
};
|
|
17267
|
+
|
|
17268
|
+
// ../core/dist/composite/extend-lens.js
|
|
17269
|
+
function httpStatus(err) {
|
|
17270
|
+
return err?._meta?.http_status;
|
|
17271
|
+
}
|
|
17272
|
+
async function readExtraRefillQuota(client) {
|
|
17273
|
+
try {
|
|
17274
|
+
const me = await client.resolveMe();
|
|
17275
|
+
const quota = await client.request("GET", `/organizations/${me.organization.id}/quota_status`);
|
|
17276
|
+
const entry = quota.org?.resources?.find((r) => r.resource_type === "LENS_EXTRA_REFILL");
|
|
17277
|
+
return {
|
|
17278
|
+
count: entry?.count ?? null,
|
|
17279
|
+
resets_at: entry?.resets_at ?? null
|
|
17280
|
+
};
|
|
17281
|
+
} catch {
|
|
17282
|
+
return { count: null, resets_at: null };
|
|
17283
|
+
}
|
|
17284
|
+
}
|
|
17285
|
+
var extendLens = {
|
|
17286
|
+
name: "leadbay_extend_lens",
|
|
17287
|
+
annotations: {
|
|
17288
|
+
title: "Extend a lens with additional leads (extra refill)",
|
|
17289
|
+
readOnlyHint: false,
|
|
17290
|
+
destructiveHint: false,
|
|
17291
|
+
idempotentHint: false,
|
|
17292
|
+
openWorldHint: true
|
|
17293
|
+
},
|
|
17294
|
+
description: leadbay_extend_lens,
|
|
17295
|
+
optional: true,
|
|
17296
|
+
// gated behind LEADBAY_MCP_WRITE=1 in MCP
|
|
17297
|
+
inputSchema: {
|
|
17298
|
+
type: "object",
|
|
17299
|
+
properties: {
|
|
17300
|
+
lensId: {
|
|
17301
|
+
type: "number",
|
|
17302
|
+
description: "Lens to extend. Defaults to the user's last-active lens."
|
|
17303
|
+
},
|
|
17304
|
+
seed_lead_ids: {
|
|
17305
|
+
type: "array",
|
|
17306
|
+
description: "Optional list of lead UUIDs from leadbay_seed_candidates to bias the recommender. Omit or empty array \u2192 default-strategy fallback (same behaviour as a normal fill).",
|
|
17307
|
+
items: { type: "string" }
|
|
17308
|
+
},
|
|
17309
|
+
extra_count: {
|
|
17310
|
+
type: "number",
|
|
17311
|
+
description: "How many extra leads to request. Omit to use the backend default. The full requested count must fit into the remaining daily LENS_EXTRA_REFILL quota \u2014 otherwise the call is rejected outright (status: quota_exceeded)."
|
|
17312
|
+
}
|
|
17313
|
+
},
|
|
17314
|
+
additionalProperties: false
|
|
17315
|
+
},
|
|
17316
|
+
outputSchema: {
|
|
17317
|
+
type: "object",
|
|
17318
|
+
properties: {
|
|
17319
|
+
status: {
|
|
17320
|
+
type: "string",
|
|
17321
|
+
description: "queued | quota_exceeded | refresh_in_progress | no_valid_seeds"
|
|
17322
|
+
},
|
|
17323
|
+
lens: {
|
|
17324
|
+
type: "object",
|
|
17325
|
+
properties: { id: { type: "number" } }
|
|
17326
|
+
},
|
|
17327
|
+
accepted_seeds: {
|
|
17328
|
+
type: "array",
|
|
17329
|
+
description: "Subset of seed_lead_ids that passed validation and will bias the fill. Empty when no seeds were submitted (default-strategies fallback). Present only on status=queued.",
|
|
17330
|
+
items: { type: "string" }
|
|
17331
|
+
},
|
|
17332
|
+
message: {
|
|
17333
|
+
type: "string",
|
|
17334
|
+
description: "Human-readable summary. On error statuses, this is the line to surface to the user."
|
|
17335
|
+
},
|
|
17336
|
+
quota: {
|
|
17337
|
+
type: "object",
|
|
17338
|
+
description: "Only present on status=quota_exceeded. Shows the org's daily LENS_EXTRA_REFILL state.",
|
|
17339
|
+
properties: {
|
|
17340
|
+
used_today: { type: ["number", "null"] },
|
|
17341
|
+
resets_at: { type: ["string", "null"] }
|
|
17342
|
+
}
|
|
17343
|
+
}
|
|
17344
|
+
},
|
|
17345
|
+
required: ["status", "lens"]
|
|
17346
|
+
},
|
|
17347
|
+
execute: async (client, params) => {
|
|
17348
|
+
const lensId = params.lensId ?? await client.resolveDefaultLens();
|
|
17349
|
+
const body = {
|
|
17350
|
+
seed_lead_ids: params.seed_lead_ids ?? []
|
|
17351
|
+
};
|
|
17352
|
+
if (params.extra_count != null) {
|
|
17353
|
+
body.extra_count = params.extra_count;
|
|
17354
|
+
}
|
|
17355
|
+
try {
|
|
17356
|
+
const res = await client.request("POST", `/lenses/${lensId}/extra_refill`, body);
|
|
17357
|
+
return {
|
|
17358
|
+
status: "queued",
|
|
17359
|
+
lens: { id: lensId },
|
|
17360
|
+
accepted_seeds: res.accepted_seeds,
|
|
17361
|
+
message: "Extra refill queued. Leads stream in asynchronously \u2014 call leadbay_pull_leads in ~30s to see them."
|
|
17362
|
+
};
|
|
17363
|
+
} catch (err) {
|
|
17364
|
+
const status = httpStatus(err);
|
|
17365
|
+
if (status === 429) {
|
|
17366
|
+
const q = await readExtraRefillQuota(client);
|
|
17367
|
+
return {
|
|
17368
|
+
status: "quota_exceeded",
|
|
17369
|
+
lens: { id: lensId },
|
|
17370
|
+
quota: { used_today: q.count, resets_at: q.resets_at },
|
|
17371
|
+
message: "Daily LENS_EXTRA_REFILL quota exhausted. Surface to user: (1) try a smaller extra_count, (2) wait for the daily reset" + (q.resets_at ? ` (resets at ${q.resets_at})` : "") + ", or (3) upgrade plan for a higher daily limit (TIER1=150, TIER2=1000)."
|
|
17372
|
+
};
|
|
17373
|
+
}
|
|
17374
|
+
if (status === 409) {
|
|
17375
|
+
return {
|
|
17376
|
+
status: "refresh_in_progress",
|
|
17377
|
+
lens: { id: lensId },
|
|
17378
|
+
message: "A refresh or extra-refill is already running on this lens. Wait, then call leadbay_pull_leads in ~30s."
|
|
17379
|
+
};
|
|
17380
|
+
}
|
|
17381
|
+
if (status === 400) {
|
|
17382
|
+
return {
|
|
17383
|
+
status: "no_valid_seeds",
|
|
17384
|
+
lens: { id: lensId },
|
|
17385
|
+
message: "Every submitted seed failed validation (likely stale \u2014 the lens shape may have changed). Refetch via leadbay_seed_candidates and retry."
|
|
17386
|
+
};
|
|
17387
|
+
}
|
|
17388
|
+
throw err;
|
|
17389
|
+
}
|
|
17390
|
+
}
|
|
17391
|
+
};
|
|
17392
|
+
|
|
17024
17393
|
// ../core/dist/composite/answer-clarification.js
|
|
17025
17394
|
var answerClarification = {
|
|
17026
17395
|
name: "leadbay_answer_clarification",
|
|
@@ -17604,6 +17973,9 @@ var compositeReadTools = [
|
|
|
17604
17973
|
qualifyStatus,
|
|
17605
17974
|
importStatus,
|
|
17606
17975
|
resolveImportRows,
|
|
17976
|
+
// seed-candidates is a read-only discovery surface for the extend flow.
|
|
17977
|
+
// Always exposed so the agent can show candidates even in read-only deployments.
|
|
17978
|
+
seedCandidates,
|
|
17607
17979
|
// listMappableFields is granular-shaped but the import composites depend on
|
|
17608
17980
|
// it for discoverability; expose it always-on so agents can find custom fields
|
|
17609
17981
|
// without needing LEADBAY_MCP_ADVANCED=1.
|
|
@@ -17647,7 +18019,10 @@ var compositeWriteTools = [
|
|
|
17647
18019
|
// Backend POST endpoints; gated behind LEADBAY_MCP_WRITE=1 in MCP.
|
|
17648
18020
|
createCampaign,
|
|
17649
18021
|
addLeadsToCampaign,
|
|
17650
|
-
removeLeadsFromCampaign
|
|
18022
|
+
removeLeadsFromCampaign,
|
|
18023
|
+
// Lens extend — agent-driven on-demand fill (additive). Gated behind
|
|
18024
|
+
// LEADBAY_MCP_WRITE=1. Subject to per-org daily LENS_EXTRA_REFILL quota.
|
|
18025
|
+
extendLens
|
|
17651
18026
|
];
|
|
17652
18027
|
var compositeTools = [
|
|
17653
18028
|
...compositeReadTools,
|
|
@@ -17689,6 +18064,7 @@ export {
|
|
|
17689
18064
|
withAgentMemoryMeta,
|
|
17690
18065
|
makeAgentMemoryEntry,
|
|
17691
18066
|
makeAgentMemoryTombstone,
|
|
18067
|
+
COMPOSITE_FILE_TOOL_NAMES,
|
|
17692
18068
|
login,
|
|
17693
18069
|
listLenses,
|
|
17694
18070
|
discoverLeads,
|
|
@@ -17769,6 +18145,8 @@ export {
|
|
|
17769
18145
|
bulkEnrichStatus,
|
|
17770
18146
|
adjustAudience,
|
|
17771
18147
|
refinePrompt,
|
|
18148
|
+
seedCandidates,
|
|
18149
|
+
extendLens,
|
|
17772
18150
|
answerClarification,
|
|
17773
18151
|
reportOutreach,
|
|
17774
18152
|
reportFriction,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
AgentMemoryScopeSchema,
|
|
7
7
|
AgentMemorySourceSchema,
|
|
8
8
|
AgentMemoryTombstoneSchema,
|
|
9
|
+
COMPOSITE_FILE_TOOL_NAMES,
|
|
9
10
|
InMemoryBulkStore,
|
|
10
11
|
LeadbayClient,
|
|
11
12
|
LocalBulkStore,
|
|
@@ -49,6 +50,7 @@ import {
|
|
|
49
50
|
enrichContacts,
|
|
50
51
|
enrichTitles,
|
|
51
52
|
ensureAgentMemorySummary,
|
|
53
|
+
extendLens,
|
|
52
54
|
followupsMap,
|
|
53
55
|
formatLoginError,
|
|
54
56
|
getClarification,
|
|
@@ -114,6 +116,7 @@ import {
|
|
|
114
116
|
resolveAgentMemorySummary,
|
|
115
117
|
resolveImportRows,
|
|
116
118
|
resolveRegion,
|
|
119
|
+
seedCandidates,
|
|
117
120
|
selectLeads,
|
|
118
121
|
setActiveLens,
|
|
119
122
|
setEpilogueStatus,
|
|
@@ -124,7 +127,7 @@ import {
|
|
|
124
127
|
updateLens,
|
|
125
128
|
updateLensFilter,
|
|
126
129
|
withAgentMemoryMeta
|
|
127
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-ASAKITU3.js";
|
|
128
131
|
export {
|
|
129
132
|
AgentMemoryCaptureInputSchema,
|
|
130
133
|
AgentMemoryEntrySchema,
|
|
@@ -132,6 +135,7 @@ export {
|
|
|
132
135
|
AgentMemoryScopeSchema,
|
|
133
136
|
AgentMemorySourceSchema,
|
|
134
137
|
AgentMemoryTombstoneSchema,
|
|
138
|
+
COMPOSITE_FILE_TOOL_NAMES,
|
|
135
139
|
InMemoryBulkStore,
|
|
136
140
|
LeadbayClient,
|
|
137
141
|
LocalBulkStore,
|
|
@@ -175,6 +179,7 @@ export {
|
|
|
175
179
|
enrichContacts,
|
|
176
180
|
enrichTitles,
|
|
177
181
|
ensureAgentMemorySummary,
|
|
182
|
+
extendLens,
|
|
178
183
|
followupsMap,
|
|
179
184
|
formatLoginError,
|
|
180
185
|
getClarification,
|
|
@@ -240,6 +245,7 @@ export {
|
|
|
240
245
|
resolveAgentMemorySummary,
|
|
241
246
|
resolveImportRows,
|
|
242
247
|
resolveRegion,
|
|
248
|
+
seedCandidates,
|
|
243
249
|
selectLeads,
|
|
244
250
|
setActiveLens,
|
|
245
251
|
setEpilogueStatus,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"mcpName": "io.github.leadbay/leadbay-mcp",
|
|
5
5
|
"description": "Model Context Protocol (MCP) server for Leadbay — AI lead discovery, qualification, and enrichment for Claude Desktop, Cursor, and Claude Code.",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@anthropic-ai/sdk": "^0.40.0",
|
|
35
|
-
"@leadbay/core": "workspace:*"
|
|
35
|
+
"@leadbay/core": "workspace:*",
|
|
36
|
+
"@leadbay/promptforge": "workspace:*"
|
|
36
37
|
},
|
|
37
38
|
"engines": {
|
|
38
39
|
"node": ">=22"
|