@seldonframe/mcp 1.51.0 → 1.53.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/package.json +1 -1
- package/src/tools.js +169 -112
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seldonframe/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.53.0",
|
|
4
4
|
"mcpName": "io.github.seldonframe/seldonframe-mcp",
|
|
5
5
|
"description": "Open-source GoHighLevel alternative for agencies. 146+ MCP tools that let Claude Code spin up white-labeled client workspaces — CRM, booking, intake forms, landing pages, AI chatbot, and pre-wired agent archetypes (speed-to-lead, missed-call-text-back, review-requester) — in minutes. AGPL-3.0.",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|
package/src/tools.js
CHANGED
|
@@ -60,11 +60,9 @@ export const TOOLS = [
|
|
|
60
60
|
{
|
|
61
61
|
name: "create_full_workspace",
|
|
62
62
|
description:
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"MANDATORY FOLLOW-UP: After this returns `status: 'ready'`, ask the operator verbatim 'What email should I use for your account? This is where you'll get your login link and notifications.' Then call `finalize_workspace({ workspace_id, email })`. The admin dashboard URL is ONLY created by finalize_workspace — it does not exist in this response (so there's nothing for you to display prematurely). " +
|
|
67
|
-
"Example: create_full_workspace({ business_name: 'Summit Air Comfort', city: 'Phoenix', state: 'AZ', phone: '(480) 555-2100', services: ['AC repair', 'heating installation', 'duct cleaning'], business_description: 'Residential and commercial HVAC in Phoenix', review_count: 950, review_rating: 4.7, trust_signals: ['licensed', 'bonded', 'insured'], emergency_service: true, same_day: true, service_area: ['Scottsdale', 'Tempe', 'Mesa'] })",
|
|
63
|
+
"Atomic workspace creation from pre-extracted business facts. Equivalent to create_workspace_v2 but single-call (no block-by-block iteration). Used as the follow-up after `create_workspace_from_url` for cases where the operator wants the workspace produced in one shot rather than block-iterated. " +
|
|
64
|
+
"Example: create_full_workspace({ business_name: 'Summit Air Comfort', city: 'Phoenix', state: 'AZ', phone: '(480) 555-2100', services: ['AC repair', 'heating installation', 'duct cleaning'], business_description: 'Residential and commercial HVAC in Phoenix', review_count: 950, review_rating: 4.7, trust_signals: ['licensed', 'bonded', 'insured'], emergency_service: true, same_day: true, service_area: ['Scottsdale', 'Tempe', 'Mesa'] }). " +
|
|
65
|
+
"MANDATORY FOLLOW-UP: same as create_workspace_v2 — after this returns `status: 'ready'`, ask 'What email should I use for your account?' and call finalize_workspace({ workspace_id, email }).",
|
|
68
66
|
inputSchema: obj(
|
|
69
67
|
{
|
|
70
68
|
business_name: str("Business display name (e.g. 'Summit Air Comfort')."),
|
|
@@ -101,19 +99,8 @@ export const TOOLS = [
|
|
|
101
99
|
},
|
|
102
100
|
email: str("Optional contact email surfaced in the landing footer (NOT the operator's account email — that comes via finalize_workspace)."),
|
|
103
101
|
address: str("Optional business address."),
|
|
104
|
-
// v1.48 — schema-level routing guard. The model MUST pass `true`
|
|
105
|
-
// to confirm no URL was available. When the operator's input
|
|
106
|
-
// contains a URL, this assertion is false (don't lie); use
|
|
107
|
-
// `create_workspace_from_url` instead. This makes the routing
|
|
108
|
-
// a hard schema constraint, not just description prose.
|
|
109
|
-
confirmed_no_url_available: {
|
|
110
|
-
type: "boolean",
|
|
111
|
-
enum: [true],
|
|
112
|
-
description:
|
|
113
|
-
"MUST be `true`. Set to true ONLY if the operator did NOT provide a website URL (e.g. they pasted Google Maps text or typed structured fields). If a URL IS available, use `create_workspace_from_url` instead — do NOT lie here. The schema rejects calls without this confirmation.",
|
|
114
|
-
},
|
|
115
102
|
},
|
|
116
|
-
["business_name", "city", "state", "phone", "services", "business_description"
|
|
103
|
+
["business_name", "city", "state", "phone", "services", "business_description"]
|
|
117
104
|
),
|
|
118
105
|
handler: async (args) => {
|
|
119
106
|
const firstEver = isFirstEverCall();
|
|
@@ -489,33 +476,22 @@ export const TOOLS = [
|
|
|
489
476
|
{
|
|
490
477
|
name: "create_workspace_from_url",
|
|
491
478
|
description:
|
|
492
|
-
"
|
|
493
|
-
"
|
|
494
|
-
"
|
|
495
|
-
"
|
|
496
|
-
"DOES NOT GENERATE A LANDING PAGE BY DEFAULT — agency clients typically already have their own website (the URL the operator passed). The chatbot ships as an embed snippet (`chatbot_embed_snippet` in the response) which the agency pastes onto the client's existing site. " +
|
|
497
|
-
"If you ALSO need a SeldonFrame-hosted landing page (only when the client has no site of their own), call `generate_landing_page({ workspace_id })` AFTER this returns — it's a separate ~30-60s opt-in step. " +
|
|
498
|
-
"DO NOT use create_workspace_v2 or create_full_workspace when a URL is available. Those tools require PRE-EXTRACTED structured fields (business_name, services[], phone) and will produce INFERIOR results for URL input because they skip the URL crawler, the FAQ extractor, and the auto-chatbot build. " +
|
|
499
|
-
"DO NOT manually WebFetch the URL first — the SeldonFrame backend's soul-compiler is already wired to scrape + extract. Forwarding pre-fetched HTML wastes a round-trip and bypasses the FAQ-from-URL pipeline. " +
|
|
500
|
-
"Eval gate: chatbot must pass ≥10 of 11 safety + behavior scenarios to ship 'live'. White-label-ready under partner-agency attachment. " +
|
|
501
|
-
"Returns: workspace + agent + chatbot_embed_snippet + faq_summary. MANDATORY FOLLOW-UP: ask the operator verbatim 'What email should I use for your account?' then call finalize_workspace({ workspace_id, email }) — the admin dashboard URL is ONLY created by finalize_workspace. " +
|
|
502
|
-
"⭐ WHEN RENDERING THE RESPONSE BACK TO THE OPERATOR: lead with `primary_deliverable.embed_snippet` + `primary_deliverable.paste_instruction`. The chatbot embed snippet is the agency's HEADLINE deliverable — the agency pastes it onto their CLIENT'S existing website (e.g. dallasplumbing.com), not onto a SeldonFrame-hosted page. DO NOT lead the response summary with 'Public URLs' or a `*.app.seldonframe.com` subdomain. When `include_landing_page: false` (the default for URL flow), there is NO SeldonFrame-hosted landing page — the subdomain is for previewing the chatbot only; don't promote it as a deliverable.",
|
|
479
|
+
"Entry point for URL-based workspace creation. Returns instructions Claude follows: WebFetch the URL, optionally WebFetch up to 2 priority sub-pages (e.g. /about, /services, /contact, /pricing), extract structured business facts, ask the operator for any required field that can't be determined, then call `create_workspace_v2` with the result. " +
|
|
480
|
+
"THIS TOOL DOES NOT CREATE A WORKSPACE — it returns the playbook. The workspace is created by the follow-up `create_workspace_v2` call (then per-block: get_block_skill + persist_block + complete_workspace_v2 + finalize_workspace). " +
|
|
481
|
+
"When operator provides ANY of: 'http://', 'https://', a domain (.com/.io/.net/.co/.app/.dev/.us etc), or 'create workspace for <URL>' — call this tool. Do NOT manually WebFetch first; the instructions returned by this tool tell you exactly what to fetch and in what order. " +
|
|
482
|
+
"MANDATORY FOLLOW-UP: After create_workspace_v2 returns 'ready' and all blocks land via persist_block + complete_workspace_v2, ask the operator 'What email should I use for your account?' and call finalize_workspace({ workspace_id, email }).",
|
|
503
483
|
inputSchema: obj(
|
|
504
484
|
{
|
|
505
|
-
url: str("Business website URL, e.g. https://
|
|
485
|
+
url: str("Business website URL the operator provided, e.g. https://quigleyac.com"),
|
|
506
486
|
},
|
|
507
487
|
["url"]
|
|
508
488
|
),
|
|
509
489
|
handler: async (args) =>
|
|
510
|
-
api(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
include_landing_page: false,
|
|
516
|
-
},
|
|
517
|
-
allow_anonymous: true,
|
|
518
|
-
}),
|
|
490
|
+
api(
|
|
491
|
+
"GET",
|
|
492
|
+
`/workspace/extract-instructions?url=${encodeURIComponent(args.url)}`,
|
|
493
|
+
{ allow_anonymous: true }
|
|
494
|
+
),
|
|
519
495
|
},
|
|
520
496
|
// v1.47 — explicit opt-in landing-page generator. create_workspace_from_url
|
|
521
497
|
// defaults to NO landing page (the client already has their own site);
|
|
@@ -828,7 +804,8 @@ export const TOOLS = [
|
|
|
828
804
|
"ONE-CALL CLOSING WRAPPER for the workspace creation flow. Bundles email collection (welcome email + lead capture via collect_operator_email) AND produces the final operator-facing summary (live URLs, what's configured, admin link). " +
|
|
829
805
|
"Call this as the LAST step of every workspace creation. After create_workspace returns, ask the user 'What email should I use for your account? This is where you'll get your login link and any notifications.' Then call this tool with the email they give you. Returns a `summary` string Claude Code should paraphrase verbatim to the operator. " +
|
|
830
806
|
"Use this instead of calling collect_operator_email directly when you want a single tool call to close the loop. Skipping this is the same as skipping email collection — leaves the operator with a one-shot URL and no recovery path. " +
|
|
831
|
-
"Example: finalize_workspace({ email: 'max@precisionplumbing.com', name: 'Max' })"
|
|
807
|
+
"Example: finalize_workspace({ email: 'max@precisionplumbing.com', name: 'Max' }). " +
|
|
808
|
+
"The summary is agency-voice: addresses the operator AS an agency delivering for their SMB client, not as the workspace owner. When relaying to the operator, preserve the 'your client' framing throughout — don't rewrite to 'your workspace'.",
|
|
832
809
|
inputSchema: obj(
|
|
833
810
|
{
|
|
834
811
|
email: str("Operator email — used as the welcome email recipient AND as the unique key for the SeldonFrame CRM lead."),
|
|
@@ -861,6 +838,10 @@ export const TOOLS = [
|
|
|
861
838
|
const publicUrls = snapshot?.public_urls ?? {};
|
|
862
839
|
const slug = snapshot?.workspace?.slug ?? null;
|
|
863
840
|
const wsName = snapshot?.workspace?.name ?? "Your workspace";
|
|
841
|
+
const chatbot = snapshot?.chatbot ?? null;
|
|
842
|
+
const tier = snapshot?.tier ?? null;
|
|
843
|
+
const bookingInfo = snapshot?.booking ?? null;
|
|
844
|
+
const intakeInfo = snapshot?.intake ?? null;
|
|
864
845
|
if (!publicUrls.home || !publicUrls.book || !publicUrls.intake) {
|
|
865
846
|
throw new Error(
|
|
866
847
|
"Snapshot did not return public_urls (home/book/intake). Re-check the workspace.",
|
|
@@ -924,65 +905,144 @@ export const TOOLS = [
|
|
|
924
905
|
: null;
|
|
925
906
|
const pipelineStages = personality?.pipeline?.stages ?? [];
|
|
926
907
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
?
|
|
932
|
-
:
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
908
|
+
// 2026-05-15 — Agency-voice product moment summary. See spec
|
|
909
|
+
// docs/superpowers/specs/2026-05-15-agency-output-product-moment-design.md
|
|
910
|
+
const intakeSpecialNote =
|
|
911
|
+
personality?.vertical === "hvac" || personality?.vertical === "plumbing"
|
|
912
|
+
? "emergency-line fallback"
|
|
913
|
+
: "structured lead-qualification";
|
|
914
|
+
|
|
915
|
+
const tierLabel = tier?.current_tier_label ?? "Free";
|
|
916
|
+
const isPaid =
|
|
917
|
+
tier?.current_tier === "growth" || tier?.current_tier === "scale";
|
|
918
|
+
const isScale = tier?.current_tier === "scale";
|
|
919
|
+
|
|
920
|
+
const intakeFieldCount = intakeInfo?.field_count ?? 0;
|
|
921
|
+
const intakeTitle = intakeInfo?.title ?? "lead qualification";
|
|
922
|
+
|
|
923
|
+
const lines = [];
|
|
924
|
+
|
|
925
|
+
// Header
|
|
926
|
+
lines.push(`✅ ${wsName} — client OS shipped.`);
|
|
927
|
+
lines.push("");
|
|
928
|
+
lines.push("Your client's stack is wired and live:");
|
|
929
|
+
lines.push("");
|
|
930
|
+
|
|
931
|
+
// Public site
|
|
932
|
+
lines.push("🌐 Public site (paste a screenshot in your Slack)");
|
|
933
|
+
lines.push(` ${publicUrls.home}`);
|
|
934
|
+
lines.push("");
|
|
935
|
+
|
|
936
|
+
// Chatbot
|
|
937
|
+
if (chatbot && chatbot.embed_snippet) {
|
|
938
|
+
lines.push("🤖 AI chatbot — paste on the client's existing site (before </body>):");
|
|
939
|
+
lines.push(` ${chatbot.embed_snippet}`);
|
|
940
|
+
lines.push(
|
|
941
|
+
` In ${String(chatbot.status).toUpperCase()} mode. Powered by your Claude Code key (swap in settings).`,
|
|
942
|
+
);
|
|
943
|
+
lines.push(
|
|
944
|
+
` Publish live: publish_agent({ agent_id: "${chatbot.agent_id}", status: "live" })`,
|
|
945
|
+
);
|
|
946
|
+
} else {
|
|
947
|
+
lines.push("🤖 AI chatbot — scaffold pending. Retry:");
|
|
948
|
+
lines.push(` create_agent({ archetype: "website-chatbot", channel: "web_chat" })`);
|
|
949
|
+
}
|
|
950
|
+
lines.push("");
|
|
951
|
+
|
|
952
|
+
// Booking
|
|
953
|
+
lines.push("📋 Booking page (client's customers self-serve appointments)");
|
|
954
|
+
lines.push(` ${publicUrls.book}`);
|
|
955
|
+
lines.push("");
|
|
956
|
+
|
|
957
|
+
// Intake
|
|
958
|
+
lines.push(`📝 Intake form (${intakeFieldCount}-question ${intakeTitle})`);
|
|
959
|
+
lines.push(` ${publicUrls.intake}`);
|
|
960
|
+
lines.push("");
|
|
961
|
+
|
|
962
|
+
// Admin
|
|
963
|
+
lines.push("🔐 Your admin (CRM, pipeline, leads, deals)");
|
|
964
|
+
lines.push(` ${adminUrl}`);
|
|
965
|
+
lines.push("");
|
|
966
|
+
|
|
967
|
+
// Client portal
|
|
968
|
+
if (tier?.client_portal_url) {
|
|
969
|
+
lines.push("👥 Client portal (your client logs in here to see their leads + bookings)");
|
|
970
|
+
lines.push(` ${tier.client_portal_url}`);
|
|
971
|
+
if (isPaid) {
|
|
972
|
+
lines.push(` ✅ Active. Forward this URL to your client; they log in via magic email.`);
|
|
973
|
+
} else {
|
|
974
|
+
lines.push(` 🔒 Growth tier ($29/mo) unlocks this for your client. Preview it`);
|
|
975
|
+
lines.push(` yourself at the URL above right now.`);
|
|
976
|
+
}
|
|
977
|
+
lines.push("");
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// What's wired
|
|
981
|
+
lines.push("What's wired:");
|
|
944
982
|
if (personalityLabel) {
|
|
945
|
-
|
|
983
|
+
const stageCount = pipelineStages.length;
|
|
984
|
+
lines.push(` • ${personalityLabel} personality • ${stageCount}-stage CRM pipeline`);
|
|
946
985
|
}
|
|
947
|
-
if (
|
|
948
|
-
|
|
949
|
-
.
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
986
|
+
if (bookingInfo) {
|
|
987
|
+
lines.push(
|
|
988
|
+
` • ${bookingInfo.hours_summary} bookings, ${bookingInfo.duration_minutes}-min slots`,
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
if (intakeInfo) {
|
|
992
|
+
lines.push(` • ${intakeFieldCount}-question intake with ${intakeSpecialNote}`);
|
|
993
|
+
}
|
|
994
|
+
if (chatbot) {
|
|
995
|
+
lines.push(` • AI chatbot trained on the homepage (FAQ scaffold ready to refine)`);
|
|
953
996
|
}
|
|
954
|
-
lines.push(` • Booking page, intake form, CRM, AI agents — all live`);
|
|
955
997
|
lines.push(
|
|
956
998
|
emailSent
|
|
957
|
-
? `
|
|
958
|
-
: `
|
|
999
|
+
? ` • Welcome email + admin link sent to ${a.email}`
|
|
1000
|
+
: ` • Welcome email NOT yet sent (rerun finalize_workspace to retry)`,
|
|
959
1001
|
);
|
|
960
|
-
// v1.34.0 — Brief, optional next-step menu surfaced AFTER the
|
|
961
|
-
// operator's site is live. We don't lecture; we just list what's
|
|
962
|
-
// available. Claude Code reads this and decides whether to mention
|
|
963
|
-
// any of it based on the conversation vibe (e.g. user says
|
|
964
|
-
// "perfect, ship it" → skip; user says "can it look more
|
|
965
|
-
// impressive?" → call apply_motion_preset).
|
|
966
1002
|
lines.push("");
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
lines.push(
|
|
970
|
-
lines.push(`
|
|
971
|
-
lines.push(`
|
|
1003
|
+
|
|
1004
|
+
// What you can prompt next (5 agency-meaningful examples)
|
|
1005
|
+
lines.push("What you can prompt next:");
|
|
1006
|
+
lines.push(` • "Refine the chatbot FAQ from the site" → update_website_chatbot`);
|
|
1007
|
+
lines.push(` • "Add SMS missed-call-text-back automation" → install_archetype`);
|
|
1008
|
+
lines.push(` • "Customize the hero with the client's brand voice" → customize_block`);
|
|
1009
|
+
lines.push(` • "Wire Google Calendar so bookings sync" → connect_integration`);
|
|
1010
|
+
lines.push(` • "Add a Spanish version of the landing page" → clone_workspace + translate`);
|
|
1011
|
+
lines.push("");
|
|
1012
|
+
|
|
1013
|
+
// Tier ladder (omit on Scale tier)
|
|
1014
|
+
if (!isScale) {
|
|
1015
|
+
lines.push(`Tier ladder (you're on ${tierLabel}):`);
|
|
1016
|
+
lines.push(` Free → 1 client workspace, everything above wired`);
|
|
1017
|
+
lines.push(` Growth $29/mo → 3 workspaces, client portal goes live, custom domain`);
|
|
1018
|
+
lines.push(` (e.g. crm.youragency.com), SMS/email automations`);
|
|
1019
|
+
lines.push(` Scale $99/mo → unlimited workspaces, full white-label, reseller pricing`);
|
|
1020
|
+
lines.push("");
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// Closer
|
|
1024
|
+
lines.push("Forward your client this admin link when ready. Or stay here and iterate.");
|
|
1025
|
+
|
|
972
1026
|
const summary = lines.join("\n");
|
|
973
1027
|
|
|
974
1028
|
return {
|
|
975
1029
|
ok: emailSent || leadRecorded,
|
|
976
1030
|
summary,
|
|
977
|
-
workspace: {
|
|
978
|
-
id: workspaceId,
|
|
979
|
-
name: wsName,
|
|
980
|
-
slug,
|
|
981
|
-
},
|
|
1031
|
+
workspace: { id: workspaceId, name: wsName, slug },
|
|
982
1032
|
website_url: publicUrls.home,
|
|
983
1033
|
booking_url: publicUrls.book,
|
|
984
1034
|
intake_url: publicUrls.intake,
|
|
985
1035
|
admin_url: adminUrl,
|
|
1036
|
+
// NEW (2026-05-15): chatbot + tier surfacing
|
|
1037
|
+
chatbot_agent_id: chatbot?.agent_id ?? null,
|
|
1038
|
+
chatbot_embed_url: chatbot?.embed_url ?? null,
|
|
1039
|
+
chatbot_embed_snippet: chatbot?.embed_snippet ?? null,
|
|
1040
|
+
chatbot_status: chatbot?.status ?? null,
|
|
1041
|
+
client_portal_url: tier?.client_portal_url ?? null,
|
|
1042
|
+
client_portal_status: tier?.client_portal_status ?? null,
|
|
1043
|
+
current_tier: tier?.current_tier ?? "free",
|
|
1044
|
+
tier_features: tier?.tier_features ?? null,
|
|
1045
|
+
// Existing email/lead fields
|
|
986
1046
|
email_sent: emailSent,
|
|
987
1047
|
email_error: emailError,
|
|
988
1048
|
lead_recorded: leadRecorded,
|
|
@@ -990,28 +1050,37 @@ export const TOOLS = [
|
|
|
990
1050
|
lead_error: leadError,
|
|
991
1051
|
personality: personalityLabel,
|
|
992
1052
|
pipeline_stages: pipelineStages.map((s) => s?.name).filter(Boolean),
|
|
993
|
-
//
|
|
994
|
-
// without parsing the human-facing summary string.
|
|
1053
|
+
// 2026-05-15 — agency-meaningful next-step examples
|
|
995
1054
|
next_steps_available: [
|
|
996
1055
|
{
|
|
997
|
-
action: "
|
|
998
|
-
when: "operator
|
|
999
|
-
example:
|
|
1056
|
+
action: "publish_agent",
|
|
1057
|
+
when: "operator has reviewed the chatbot and is ready to take it live for the client's website",
|
|
1058
|
+
example: `publish_agent({ agent_id: "${chatbot?.agent_id ?? "ag_..."}", status: "live" })`,
|
|
1000
1059
|
},
|
|
1001
1060
|
{
|
|
1002
|
-
action: "
|
|
1003
|
-
when: "operator
|
|
1004
|
-
example:
|
|
1061
|
+
action: "update_website_chatbot",
|
|
1062
|
+
when: "operator wants to refine the chatbot's FAQ before publishing",
|
|
1063
|
+
example: `update_website_chatbot({ workspace_id, faq: [{ q: '...', a: '...' }] })`,
|
|
1005
1064
|
},
|
|
1006
1065
|
{
|
|
1007
|
-
action: "
|
|
1008
|
-
when: "operator
|
|
1009
|
-
example:
|
|
1066
|
+
action: "install_archetype",
|
|
1067
|
+
when: "operator wants to wire pre-built automations (missed-call-text-back, speed-to-lead, review-requester)",
|
|
1068
|
+
example: `install_archetype({ archetype: "missed-call-text-back" })`,
|
|
1010
1069
|
},
|
|
1011
1070
|
{
|
|
1012
|
-
action: "
|
|
1013
|
-
when: "operator wants to
|
|
1014
|
-
example:
|
|
1071
|
+
action: "customize_block",
|
|
1072
|
+
when: "operator wants to refine landing-page hero / services / FAQ with brand voice",
|
|
1073
|
+
example: `customize_block({ workspace_id, block_name: "hero", prompt: "make this feel more premium" })`,
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
action: "connect_integration",
|
|
1077
|
+
when: "operator wants Google Calendar sync, Stripe payments, Twilio SMS",
|
|
1078
|
+
example: `connect_integration({ workspace_id, provider: "google_calendar" })`,
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
action: "configure_llm_provider",
|
|
1082
|
+
when: "operator wants to swap from the default Claude Code key to a different Anthropic key",
|
|
1083
|
+
example: `configure_llm_provider({ workspace_id, provider: "anthropic", api_key: "sk-ant-..." })`,
|
|
1015
1084
|
},
|
|
1016
1085
|
],
|
|
1017
1086
|
};
|
|
@@ -3018,11 +3087,9 @@ export const TOOLS = [
|
|
|
3018
3087
|
{
|
|
3019
3088
|
name: "create_workspace_v2",
|
|
3020
3089
|
description:
|
|
3021
|
-
"
|
|
3022
|
-
"
|
|
3023
|
-
"
|
|
3024
|
-
"MANDATORY FOLLOW-UP: After this returns `status: 'ready'` AND after all blocks land via persist_block + complete_workspace_v2, ask the operator verbatim 'What email should I use for your account?' Then call finalize_workspace({ workspace_id, email }). The admin dashboard URL is created by finalize_workspace, not here. " +
|
|
3025
|
-
"Why v2: v1 generated all copy server-side from a hardcoded personality system, which produced layer-mismatch bugs every time a new niche was tested. v2 puts the LLM in your context (the IDE agent), reads from one SKILL.md per block, and the generated copy is naturally niche-aware. The operator can later say 'change the hero' and you customize it via persist_block with a customization payload.",
|
|
3090
|
+
"Create a workspace from pre-extracted business facts. Used as the follow-up call after `create_workspace_from_url` returns extraction instructions, OR directly when the operator provides structured info (no URL). " +
|
|
3091
|
+
"Flow: 1) call this tool with the business facts; 2) for each block in `v2.recommended_blocks`, call get_block_skill(name) and use your LLM to generate props matching the SKILL.md prompt + schema; 3) call persist_block({ workspace_id, block_name, generation_prompt, props }) for each; 4) call complete_workspace_v2({ workspace_id }). " +
|
|
3092
|
+
"MANDATORY FOLLOW-UP: After this returns `status: 'ready'` AND after all blocks land via persist_block + complete_workspace_v2, ask the operator verbatim 'What email should I use for your account?' Then call finalize_workspace({ workspace_id, email }). The admin dashboard URL is created by finalize_workspace, not here.",
|
|
3026
3093
|
inputSchema: obj(
|
|
3027
3094
|
{
|
|
3028
3095
|
business_name: str("Business display name."),
|
|
@@ -3046,18 +3113,8 @@ export const TOOLS = [
|
|
|
3046
3113
|
service_area: { type: "array", items: { type: "string" } },
|
|
3047
3114
|
email: str("Optional contact email surfaced in the landing footer (NOT the operator's account email)."),
|
|
3048
3115
|
address: str("Optional business address."),
|
|
3049
|
-
// v1.48 — schema-level routing guard (same as create_full_workspace).
|
|
3050
|
-
// Forces the model to acknowledge no URL was available, preventing
|
|
3051
|
-
// accidental routing to v2 when create_workspace_from_url is the
|
|
3052
|
-
// correct path.
|
|
3053
|
-
confirmed_no_url_available: {
|
|
3054
|
-
type: "boolean",
|
|
3055
|
-
enum: [true],
|
|
3056
|
-
description:
|
|
3057
|
-
"MUST be `true`. Set to true ONLY if the operator did NOT provide a website URL. If a URL IS available, use `create_workspace_from_url` instead — do NOT lie here.",
|
|
3058
|
-
},
|
|
3059
3116
|
},
|
|
3060
|
-
["business_name", "city", "state", "phone", "services", "business_description"
|
|
3117
|
+
["business_name", "city", "state", "phone", "services", "business_description"],
|
|
3061
3118
|
),
|
|
3062
3119
|
handler: async (args) => {
|
|
3063
3120
|
const firstEver = isFirstEverCall();
|