@sentientui/mcp 0.23.0 → 0.24.1
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/AGENTS.md +1 -1
- package/README.md +1 -1
- package/dist/{chunk-P3XRXJKT.js → chunk-G6WGJ7A5.js} +78 -14
- package/dist/index.cjs +78 -14
- package/dist/index.js +1 -1
- package/dist/lib.cjs +79 -15
- package/dist/lib.js +2 -2
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -56,7 +56,7 @@ Every write tool changes what real visitors see or what the project accepts —
|
|
|
56
56
|
| `get_funnel_report` | read | Step-by-step funnel drop-off |
|
|
57
57
|
| `list_guardrail_events` | read | Every variant still paused by a guardrail; `days` narrows to recent pauses |
|
|
58
58
|
| `get_persona_breakdown` | read | Cluster distribution + avg reliability per cluster (all retained sessions, not windowed) |
|
|
59
|
-
| `get_stage_breakdown` | read | E-commerce funnel stages: stage mix (observed vs hinted), arrival channel x stage,
|
|
59
|
+
| `get_stage_breakdown` | read | E-commerce funnel stages: stage mix (observed vs hinted), arrival channel x stage, stage moves between visits, tested holdout lift per first-visit context and channel (the headline lift's always-valid test, all-time, alpha split over 23 series), versions per context with evidence (windowed, observational) |
|
|
60
60
|
| `get_layout_stats` | read | Per-persona layout order + bandit pulls/reward (cumulative state, not windowed) |
|
|
61
61
|
| `get_insights` | read | Ranked measured findings (tier + sample, low-sample flagged; `limit`, default 10) + (Growth) AI narrations, which are unmeasured |
|
|
62
62
|
| `refresh_insights` | write | Async trigger — wait ~15s then call `get_insights`. Starter+ and an editor/admin role |
|
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ A demo token is provisioned automatically — 10 calls/month, read-only (write t
|
|
|
107
107
|
| `get_funnel_report` | read | Step-by-step funnel drop-off |
|
|
108
108
|
| `list_guardrail_events` | read | Every variant currently paused by a guardrail (pass `days` to see only pauses from the last N days) |
|
|
109
109
|
| `get_persona_breakdown` | read | Visitor clusters with session counts and reliability (all retained sessions) |
|
|
110
|
-
| `get_stage_breakdown` | read | E-commerce funnel stages: stage mix, arrival channel x stage, holdout per context and versions per context (windowed, observational) |
|
|
110
|
+
| `get_stage_breakdown` | read | E-commerce funnel stages: stage mix, arrival channel x stage, stage moves between visits, tested holdout lift per first-visit context and channel (all-time), and versions per context (windowed, observational) |
|
|
111
111
|
| `get_layout_stats` | read | Per-persona section order with bandit pulls and reward (cumulative state) |
|
|
112
112
|
| `get_insights` | read | Ranked measured findings with their sample (low samples flagged), plus AI narrations marked unmeasured |
|
|
113
113
|
| `refresh_insights` | write | Regenerate AI insights — needs Starter or higher and an editor/admin role (a paid model call); advisor recommendations are Growth+ |
|
|
@@ -1241,7 +1241,36 @@ function registerPersonaTools(server, client) {
|
|
|
1241
1241
|
// src/tools/stages.ts
|
|
1242
1242
|
import { z as z6 } from "zod";
|
|
1243
1243
|
var pct = (v) => v == null ? "n/a (too few sessions)" : `${(v * 100).toFixed(1)}%`;
|
|
1244
|
-
var
|
|
1244
|
+
var counts = z6.object({ visitors: z6.number(), conversions: z6.number() });
|
|
1245
|
+
var segmentLift = z6.object({
|
|
1246
|
+
key: z6.string(),
|
|
1247
|
+
kind: z6.string().describe("stage | arrival | channel"),
|
|
1248
|
+
evidence: z6.string().describe("collecting | awaiting_conversions | not_significant | significant_positive | significant_negative"),
|
|
1249
|
+
testStarted: z6.boolean().describe("False until the series has 100 visitors per side and 10 conversions (its test scale is then fixed)"),
|
|
1250
|
+
liftPct: z6.number().nullable().describe("Relative lift %, null while collecting / awaiting conversions"),
|
|
1251
|
+
diffInterval: z6.object({ lower: z6.number(), upper: z6.number() }).nullable().describe("Always-valid range on the absolute rate difference (fractions)"),
|
|
1252
|
+
pValue: z6.number().nullable(),
|
|
1253
|
+
rates: z6.object({ adapted: z6.number(), control: z6.number() }).nullable(),
|
|
1254
|
+
adapted: counts,
|
|
1255
|
+
control: counts,
|
|
1256
|
+
epochs: z6.number()
|
|
1257
|
+
});
|
|
1258
|
+
function liftWords(l, minPerArm) {
|
|
1259
|
+
const n = `adapted ${l.adapted.visitors} / control ${l.control.visitors} visitors`;
|
|
1260
|
+
switch (l.evidence) {
|
|
1261
|
+
case "collecting":
|
|
1262
|
+
return `early \u2014 ${n}; a number shows at ${minPerArm} per side`;
|
|
1263
|
+
case "awaiting_conversions":
|
|
1264
|
+
return `early \u2014 ${n}; waiting on control-group conversions`;
|
|
1265
|
+
case "not_significant":
|
|
1266
|
+
return `not proven yet${l.liftPct != null ? ` (${l.liftPct > 0 ? "+" : ""}${l.liftPct}%, could be chance)` : ""}${l.testStarted ? "" : " \u2014 test not started"} \u2014 ${n}`;
|
|
1267
|
+
case "significant_positive":
|
|
1268
|
+
case "significant_negative":
|
|
1269
|
+
return `tested: ${l.liftPct != null && l.liftPct > 0 ? "+" : ""}${l.liftPct}% conversion${l.evidence === "significant_negative" ? " (worse)" : ""}${l.diffInterval ? `, range ${(l.diffInterval.lower * 100).toFixed(2)} to ${(l.diffInterval.upper * 100).toFixed(2)} pts` : ""} \u2014 ${n}`;
|
|
1270
|
+
default:
|
|
1271
|
+
return n;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1245
1274
|
function registerStageTools(server, client) {
|
|
1246
1275
|
server.registerTool(
|
|
1247
1276
|
"get_stage_breakdown",
|
|
@@ -1250,7 +1279,7 @@ function registerStageTools(server, client) {
|
|
|
1250
1279
|
// Mirrors GET /projects/:id/stage-report. Says OBSERVATIONAL in the
|
|
1251
1280
|
// description because nothing serves on stage yet: an agent must not
|
|
1252
1281
|
// read a per-context arm result as "stage-based serving would win".
|
|
1253
|
-
description:
|
|
1282
|
+
description: `E-commerce projects: where visitors are in buying (new, browsing, carted, customer, lapsed) \u2014 share of human sessions per stage (each session counted once, at its latest recorded stage; hinted = set by a tagged campaign, not observed history), arrival channel x stage with conversion, how visitors moved between stages from one visit to the next, the TESTED holdout lift per first-visit context and per first-visit arrival channel (the same always-valid test as the headline lift, all-time, alpha split over all 23 possible series; "collecting" and "awaiting_conversions" are early, not results), and each region's versions per context judged against the original with the per-audience evidence rule. OBSERVATIONAL: nothing is served by stage yet; the per-context results are what stage-based serving would have to beat. Defaults to the last 30 days; pass range or from/to. Returns enabled:false when the project does not record stages.` + UNTRUSTED_FIELDS_NOTE,
|
|
1254
1283
|
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("30d")),
|
|
1255
1284
|
outputSchema: {
|
|
1256
1285
|
enabled: z6.boolean().describe("False when the project does not record funnel stages (settings.stage absent)"),
|
|
@@ -1263,11 +1292,29 @@ function registerStageTools(server, client) {
|
|
|
1263
1292
|
contexts: z6.array(z6.object({
|
|
1264
1293
|
context: z6.string(),
|
|
1265
1294
|
kind: z6.string().describe("stage | arrival"),
|
|
1266
|
-
sessions: z6.number()
|
|
1267
|
-
treated: side,
|
|
1268
|
-
holdout: side,
|
|
1269
|
-
rawLiftPct: z6.number().nullable().describe("Raw relative difference, %; null until both arms have 100 sessions. Observational.")
|
|
1295
|
+
sessions: z6.number()
|
|
1270
1296
|
})),
|
|
1297
|
+
holdoutLift: z6.object({
|
|
1298
|
+
basis: z6.string().describe("'first_visit': visitors grouped by their first visit's context/channel"),
|
|
1299
|
+
allTime: z6.boolean().describe("True: the window does not apply to the lift"),
|
|
1300
|
+
goal: z6.string(),
|
|
1301
|
+
alpha: z6.number().describe("Per-series alpha after the correction"),
|
|
1302
|
+
family: z6.number(),
|
|
1303
|
+
minPerArm: z6.number(),
|
|
1304
|
+
units: z6.number(),
|
|
1305
|
+
unclassified: z6.number().describe("Exposed visitors with no first-visit record (exposed before recording began)"),
|
|
1306
|
+
contexts: z6.array(segmentLift),
|
|
1307
|
+
channels: z6.array(segmentLift)
|
|
1308
|
+
}).nullable().optional(),
|
|
1309
|
+
transitions: z6.object({
|
|
1310
|
+
pairs: z6.number().describe("Consecutive recorded visits in the window"),
|
|
1311
|
+
visitors: z6.number(),
|
|
1312
|
+
rows: z6.array(z6.object({
|
|
1313
|
+
from: z6.string(),
|
|
1314
|
+
nextVisits: z6.number(),
|
|
1315
|
+
to: z6.array(z6.object({ stage: z6.string(), visits: z6.number(), visitors: z6.number(), share: z6.number().describe("0-1") }))
|
|
1316
|
+
}))
|
|
1317
|
+
}).optional(),
|
|
1271
1318
|
arms: z6.array(z6.object({
|
|
1272
1319
|
slotId: z6.string(),
|
|
1273
1320
|
slotName: z6.string(),
|
|
@@ -1285,6 +1332,7 @@ function registerStageTools(server, client) {
|
|
|
1285
1332
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
1286
1333
|
},
|
|
1287
1334
|
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
1335
|
+
var _a;
|
|
1288
1336
|
const id = encodeURIComponent(projectId);
|
|
1289
1337
|
const r = await client.get(`/projects/${id}/stage-report${rangeQuery({ range, from, to })}`);
|
|
1290
1338
|
const structuredContent = {
|
|
@@ -1296,6 +1344,8 @@ function registerStageTools(server, client) {
|
|
|
1296
1344
|
channels: r.channels,
|
|
1297
1345
|
arrivals: r.arrivals,
|
|
1298
1346
|
contexts: r.contexts,
|
|
1347
|
+
holdoutLift: (_a = r.holdoutLift) != null ? _a : null,
|
|
1348
|
+
transitions: r.transitions,
|
|
1299
1349
|
arms: r.arms,
|
|
1300
1350
|
window: r.window
|
|
1301
1351
|
};
|
|
@@ -1320,11 +1370,24 @@ function registerStageTools(server, client) {
|
|
|
1320
1370
|
...r.stages.map((s) => `- ${s.stage}: ${s.sessions} (${(s.share * 100).toFixed(1)}%)${s.hinted ? `, ${s.hinted} hinted` : ""}`),
|
|
1321
1371
|
"",
|
|
1322
1372
|
"Arrival channel x stage (conversion):",
|
|
1323
|
-
...r.arrivals.map((a) => `- ${a.channel} / ${a.stage}: ${a.sessions} sessions, ${pct(a.conversionRate)}`)
|
|
1324
|
-
"",
|
|
1325
|
-
"Holdout vs treated per context (raw rates, no significance test):",
|
|
1326
|
-
...r.contexts.filter((c) => c.sessions > 0).map((c) => `- ${c.context}: treated ${pct(c.treated.conversionRate)} (n=${c.treated.sessions}), holdout ${pct(c.holdout.conversionRate)} (n=${c.holdout.sessions})${c.rawLiftPct != null ? `, raw difference ${c.rawLiftPct > 0 ? "+" : ""}${c.rawLiftPct}%` : ""}`)
|
|
1373
|
+
...r.arrivals.map((a) => `- ${a.channel} / ${a.stage}: ${a.sessions} sessions, ${pct(a.conversionRate)}`)
|
|
1327
1374
|
];
|
|
1375
|
+
const t = r.transitions;
|
|
1376
|
+
if (t && t.rows.length > 0) {
|
|
1377
|
+
lines.push("", `Stage moves between visits (${t.pairs} next visits from ${t.visitors} returning visitors in the window):`);
|
|
1378
|
+
for (const row of t.rows) {
|
|
1379
|
+
lines.push(`- from ${row.from} (${row.nextVisits} next visits): ${row.to.map((x) => `${x.stage} ${(x.share * 100).toFixed(0)}%`).join(", ")}`);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
const h = r.holdoutLift;
|
|
1383
|
+
if (h && (h.contexts.length > 0 || h.channels.length > 0)) {
|
|
1384
|
+
lines.push(
|
|
1385
|
+
"",
|
|
1386
|
+
`Holdout lift by first-visit context and channel (tested, all-time \u2014 the window does not apply; alpha ${h.alpha.toPrecision(2)} per series over ${h.family}; ${h.unclassified} of ${h.units} visitors predate recording and are not in any row):`,
|
|
1387
|
+
...h.contexts.map((l) => `- context ${l.key}: ${liftWords(l, h.minPerArm)}`),
|
|
1388
|
+
...h.channels.map((l) => `- channel ${l.key}: ${liftWords(l, h.minPerArm)}`)
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1328
1391
|
if (r.arms.length > 0) {
|
|
1329
1392
|
lines.push("", "Versions per context (what stage-based serving would have to beat):");
|
|
1330
1393
|
for (const a of r.arms) {
|
|
@@ -1841,7 +1904,7 @@ function registerVariantWriteTools(server, client) {
|
|
|
1841
1904
|
"create_variant",
|
|
1842
1905
|
{
|
|
1843
1906
|
title: "Create managed variant",
|
|
1844
|
-
description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Works on every plan with an editor/admin login or the project's sk_ server key (anonymous demo tokens are read-only). The variant is created as a DRAFT \u2014 it serves no traffic until activated with update_variant (status 'active'). Confirm the text with the user before calling.",
|
|
1907
|
+
description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Works on every plan with an editor/admin login or the project's sk_ server key (anonymous demo tokens are read-only). The variant is created as a DRAFT \u2014 it serves no traffic until activated with update_variant (status 'active'). Confirm the text with the user before calling. On a component that has moved to the shared track, the text is added to the component's versions instead (still a draft until activated), and text is required there (an empty create is refused); the call and its result are otherwise the same.",
|
|
1845
1908
|
inputSchema: {
|
|
1846
1909
|
projectId: projectIdSchema,
|
|
1847
1910
|
componentId: z11.string().min(1).max(200).describe("The component ID to add a variant to"),
|
|
@@ -1960,7 +2023,7 @@ function registerVariantWriteTools(server, client) {
|
|
|
1960
2023
|
"update_variant",
|
|
1961
2024
|
{
|
|
1962
2025
|
title: "Update managed variant",
|
|
1963
|
-
description: "Edit a NO-CODE managed variant (one created with create_variant or in the dashboard): its display name, its text, or its status \u2014 'active' starts serving it to visitors, 'draft' takes it back out of rotation. Code-native variants cannot be edited here (change the code). Overwriting text or activating changes what live visitors see, so CONFIRM with the user first. Omit a field to leave it unchanged.",
|
|
2026
|
+
description: "Edit a NO-CODE managed variant (one created with create_variant or in the dashboard): its display name, its text, or its status \u2014 'active' starts serving it to visitors, 'draft' takes it back out of rotation. Code-native variants cannot be edited here (change the code). Overwriting text or activating changes what live visitors see, so CONFIRM with the user first. Omit a field to leave it unchanged. On a component that has moved to the shared track (one experiment with its versions), the text is edited on that component's version instead; the call and its result are the same.",
|
|
1964
2027
|
inputSchema: {
|
|
1965
2028
|
projectId: projectIdSchema,
|
|
1966
2029
|
componentId: z11.string().min(1).max(200).describe("The component ID"),
|
|
@@ -2629,7 +2692,8 @@ and then, in the same tag after the ';', runs the inline pre-paint script; then
|
|
|
2629
2692
|
loader. The pre-paint script reads window.sentient when it runs, so sharing the tag is safe. It
|
|
2630
2693
|
is optional but recommended \u2014 the loader is deferred, so on a return visit the page can paint
|
|
2631
2694
|
its original state before the loader runs; the inline script applies the last served decision
|
|
2632
|
-
from the visitor's own device first, with no network call and no cloak
|
|
2695
|
+
from the visitor's own device first, with no network call and no page-wide cloak (it briefly hides
|
|
2696
|
+
only published components, and only for a visitor who just clicked an ad or email). Get the exact bytes from
|
|
2633
2697
|
the dashboard's Install page, or from renderSnippetInstall({ config }) in
|
|
2634
2698
|
'@sentientui/snippet/install' (renderSnippetPrePaintScript() for the script alone).
|
|
2635
2699
|
|
|
@@ -3126,7 +3190,7 @@ function registerCellTools(server, client) {
|
|
|
3126
3190
|
}
|
|
3127
3191
|
|
|
3128
3192
|
// src/server.ts
|
|
3129
|
-
var PKG_VERSION = true ? "0.
|
|
3193
|
+
var PKG_VERSION = true ? "0.24.1" : "0.0.0-dev";
|
|
3130
3194
|
function createMcpServer(client) {
|
|
3131
3195
|
const server = new McpServer(
|
|
3132
3196
|
{
|
package/dist/index.cjs
CHANGED
|
@@ -1245,7 +1245,36 @@ function registerPersonaTools(server, client) {
|
|
|
1245
1245
|
// src/tools/stages.ts
|
|
1246
1246
|
var import_zod6 = require("zod");
|
|
1247
1247
|
var pct = (v) => v == null ? "n/a (too few sessions)" : `${(v * 100).toFixed(1)}%`;
|
|
1248
|
-
var
|
|
1248
|
+
var counts = import_zod6.z.object({ visitors: import_zod6.z.number(), conversions: import_zod6.z.number() });
|
|
1249
|
+
var segmentLift = import_zod6.z.object({
|
|
1250
|
+
key: import_zod6.z.string(),
|
|
1251
|
+
kind: import_zod6.z.string().describe("stage | arrival | channel"),
|
|
1252
|
+
evidence: import_zod6.z.string().describe("collecting | awaiting_conversions | not_significant | significant_positive | significant_negative"),
|
|
1253
|
+
testStarted: import_zod6.z.boolean().describe("False until the series has 100 visitors per side and 10 conversions (its test scale is then fixed)"),
|
|
1254
|
+
liftPct: import_zod6.z.number().nullable().describe("Relative lift %, null while collecting / awaiting conversions"),
|
|
1255
|
+
diffInterval: import_zod6.z.object({ lower: import_zod6.z.number(), upper: import_zod6.z.number() }).nullable().describe("Always-valid range on the absolute rate difference (fractions)"),
|
|
1256
|
+
pValue: import_zod6.z.number().nullable(),
|
|
1257
|
+
rates: import_zod6.z.object({ adapted: import_zod6.z.number(), control: import_zod6.z.number() }).nullable(),
|
|
1258
|
+
adapted: counts,
|
|
1259
|
+
control: counts,
|
|
1260
|
+
epochs: import_zod6.z.number()
|
|
1261
|
+
});
|
|
1262
|
+
function liftWords(l, minPerArm) {
|
|
1263
|
+
const n = `adapted ${l.adapted.visitors} / control ${l.control.visitors} visitors`;
|
|
1264
|
+
switch (l.evidence) {
|
|
1265
|
+
case "collecting":
|
|
1266
|
+
return `early \u2014 ${n}; a number shows at ${minPerArm} per side`;
|
|
1267
|
+
case "awaiting_conversions":
|
|
1268
|
+
return `early \u2014 ${n}; waiting on control-group conversions`;
|
|
1269
|
+
case "not_significant":
|
|
1270
|
+
return `not proven yet${l.liftPct != null ? ` (${l.liftPct > 0 ? "+" : ""}${l.liftPct}%, could be chance)` : ""}${l.testStarted ? "" : " \u2014 test not started"} \u2014 ${n}`;
|
|
1271
|
+
case "significant_positive":
|
|
1272
|
+
case "significant_negative":
|
|
1273
|
+
return `tested: ${l.liftPct != null && l.liftPct > 0 ? "+" : ""}${l.liftPct}% conversion${l.evidence === "significant_negative" ? " (worse)" : ""}${l.diffInterval ? `, range ${(l.diffInterval.lower * 100).toFixed(2)} to ${(l.diffInterval.upper * 100).toFixed(2)} pts` : ""} \u2014 ${n}`;
|
|
1274
|
+
default:
|
|
1275
|
+
return n;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1249
1278
|
function registerStageTools(server, client) {
|
|
1250
1279
|
server.registerTool(
|
|
1251
1280
|
"get_stage_breakdown",
|
|
@@ -1254,7 +1283,7 @@ function registerStageTools(server, client) {
|
|
|
1254
1283
|
// Mirrors GET /projects/:id/stage-report. Says OBSERVATIONAL in the
|
|
1255
1284
|
// description because nothing serves on stage yet: an agent must not
|
|
1256
1285
|
// read a per-context arm result as "stage-based serving would win".
|
|
1257
|
-
description:
|
|
1286
|
+
description: `E-commerce projects: where visitors are in buying (new, browsing, carted, customer, lapsed) \u2014 share of human sessions per stage (each session counted once, at its latest recorded stage; hinted = set by a tagged campaign, not observed history), arrival channel x stage with conversion, how visitors moved between stages from one visit to the next, the TESTED holdout lift per first-visit context and per first-visit arrival channel (the same always-valid test as the headline lift, all-time, alpha split over all 23 possible series; "collecting" and "awaiting_conversions" are early, not results), and each region's versions per context judged against the original with the per-audience evidence rule. OBSERVATIONAL: nothing is served by stage yet; the per-context results are what stage-based serving would have to beat. Defaults to the last 30 days; pass range or from/to. Returns enabled:false when the project does not record stages.` + UNTRUSTED_FIELDS_NOTE,
|
|
1258
1287
|
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("30d")),
|
|
1259
1288
|
outputSchema: {
|
|
1260
1289
|
enabled: import_zod6.z.boolean().describe("False when the project does not record funnel stages (settings.stage absent)"),
|
|
@@ -1267,11 +1296,29 @@ function registerStageTools(server, client) {
|
|
|
1267
1296
|
contexts: import_zod6.z.array(import_zod6.z.object({
|
|
1268
1297
|
context: import_zod6.z.string(),
|
|
1269
1298
|
kind: import_zod6.z.string().describe("stage | arrival"),
|
|
1270
|
-
sessions: import_zod6.z.number()
|
|
1271
|
-
treated: side,
|
|
1272
|
-
holdout: side,
|
|
1273
|
-
rawLiftPct: import_zod6.z.number().nullable().describe("Raw relative difference, %; null until both arms have 100 sessions. Observational.")
|
|
1299
|
+
sessions: import_zod6.z.number()
|
|
1274
1300
|
})),
|
|
1301
|
+
holdoutLift: import_zod6.z.object({
|
|
1302
|
+
basis: import_zod6.z.string().describe("'first_visit': visitors grouped by their first visit's context/channel"),
|
|
1303
|
+
allTime: import_zod6.z.boolean().describe("True: the window does not apply to the lift"),
|
|
1304
|
+
goal: import_zod6.z.string(),
|
|
1305
|
+
alpha: import_zod6.z.number().describe("Per-series alpha after the correction"),
|
|
1306
|
+
family: import_zod6.z.number(),
|
|
1307
|
+
minPerArm: import_zod6.z.number(),
|
|
1308
|
+
units: import_zod6.z.number(),
|
|
1309
|
+
unclassified: import_zod6.z.number().describe("Exposed visitors with no first-visit record (exposed before recording began)"),
|
|
1310
|
+
contexts: import_zod6.z.array(segmentLift),
|
|
1311
|
+
channels: import_zod6.z.array(segmentLift)
|
|
1312
|
+
}).nullable().optional(),
|
|
1313
|
+
transitions: import_zod6.z.object({
|
|
1314
|
+
pairs: import_zod6.z.number().describe("Consecutive recorded visits in the window"),
|
|
1315
|
+
visitors: import_zod6.z.number(),
|
|
1316
|
+
rows: import_zod6.z.array(import_zod6.z.object({
|
|
1317
|
+
from: import_zod6.z.string(),
|
|
1318
|
+
nextVisits: import_zod6.z.number(),
|
|
1319
|
+
to: import_zod6.z.array(import_zod6.z.object({ stage: import_zod6.z.string(), visits: import_zod6.z.number(), visitors: import_zod6.z.number(), share: import_zod6.z.number().describe("0-1") }))
|
|
1320
|
+
}))
|
|
1321
|
+
}).optional(),
|
|
1275
1322
|
arms: import_zod6.z.array(import_zod6.z.object({
|
|
1276
1323
|
slotId: import_zod6.z.string(),
|
|
1277
1324
|
slotName: import_zod6.z.string(),
|
|
@@ -1289,6 +1336,7 @@ function registerStageTools(server, client) {
|
|
|
1289
1336
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
1290
1337
|
},
|
|
1291
1338
|
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
1339
|
+
var _a2;
|
|
1292
1340
|
const id = encodeURIComponent(projectId);
|
|
1293
1341
|
const r = await client.get(`/projects/${id}/stage-report${rangeQuery({ range, from, to })}`);
|
|
1294
1342
|
const structuredContent = {
|
|
@@ -1300,6 +1348,8 @@ function registerStageTools(server, client) {
|
|
|
1300
1348
|
channels: r.channels,
|
|
1301
1349
|
arrivals: r.arrivals,
|
|
1302
1350
|
contexts: r.contexts,
|
|
1351
|
+
holdoutLift: (_a2 = r.holdoutLift) != null ? _a2 : null,
|
|
1352
|
+
transitions: r.transitions,
|
|
1303
1353
|
arms: r.arms,
|
|
1304
1354
|
window: r.window
|
|
1305
1355
|
};
|
|
@@ -1324,11 +1374,24 @@ function registerStageTools(server, client) {
|
|
|
1324
1374
|
...r.stages.map((s) => `- ${s.stage}: ${s.sessions} (${(s.share * 100).toFixed(1)}%)${s.hinted ? `, ${s.hinted} hinted` : ""}`),
|
|
1325
1375
|
"",
|
|
1326
1376
|
"Arrival channel x stage (conversion):",
|
|
1327
|
-
...r.arrivals.map((a) => `- ${a.channel} / ${a.stage}: ${a.sessions} sessions, ${pct(a.conversionRate)}`)
|
|
1328
|
-
"",
|
|
1329
|
-
"Holdout vs treated per context (raw rates, no significance test):",
|
|
1330
|
-
...r.contexts.filter((c) => c.sessions > 0).map((c) => `- ${c.context}: treated ${pct(c.treated.conversionRate)} (n=${c.treated.sessions}), holdout ${pct(c.holdout.conversionRate)} (n=${c.holdout.sessions})${c.rawLiftPct != null ? `, raw difference ${c.rawLiftPct > 0 ? "+" : ""}${c.rawLiftPct}%` : ""}`)
|
|
1377
|
+
...r.arrivals.map((a) => `- ${a.channel} / ${a.stage}: ${a.sessions} sessions, ${pct(a.conversionRate)}`)
|
|
1331
1378
|
];
|
|
1379
|
+
const t = r.transitions;
|
|
1380
|
+
if (t && t.rows.length > 0) {
|
|
1381
|
+
lines.push("", `Stage moves between visits (${t.pairs} next visits from ${t.visitors} returning visitors in the window):`);
|
|
1382
|
+
for (const row of t.rows) {
|
|
1383
|
+
lines.push(`- from ${row.from} (${row.nextVisits} next visits): ${row.to.map((x) => `${x.stage} ${(x.share * 100).toFixed(0)}%`).join(", ")}`);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
const h = r.holdoutLift;
|
|
1387
|
+
if (h && (h.contexts.length > 0 || h.channels.length > 0)) {
|
|
1388
|
+
lines.push(
|
|
1389
|
+
"",
|
|
1390
|
+
`Holdout lift by first-visit context and channel (tested, all-time \u2014 the window does not apply; alpha ${h.alpha.toPrecision(2)} per series over ${h.family}; ${h.unclassified} of ${h.units} visitors predate recording and are not in any row):`,
|
|
1391
|
+
...h.contexts.map((l) => `- context ${l.key}: ${liftWords(l, h.minPerArm)}`),
|
|
1392
|
+
...h.channels.map((l) => `- channel ${l.key}: ${liftWords(l, h.minPerArm)}`)
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1332
1395
|
if (r.arms.length > 0) {
|
|
1333
1396
|
lines.push("", "Versions per context (what stage-based serving would have to beat):");
|
|
1334
1397
|
for (const a of r.arms) {
|
|
@@ -1845,7 +1908,7 @@ function registerVariantWriteTools(server, client) {
|
|
|
1845
1908
|
"create_variant",
|
|
1846
1909
|
{
|
|
1847
1910
|
title: "Create managed variant",
|
|
1848
|
-
description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Works on every plan with an editor/admin login or the project's sk_ server key (anonymous demo tokens are read-only). The variant is created as a DRAFT \u2014 it serves no traffic until activated with update_variant (status 'active'). Confirm the text with the user before calling.",
|
|
1911
|
+
description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Works on every plan with an editor/admin login or the project's sk_ server key (anonymous demo tokens are read-only). The variant is created as a DRAFT \u2014 it serves no traffic until activated with update_variant (status 'active'). Confirm the text with the user before calling. On a component that has moved to the shared track, the text is added to the component's versions instead (still a draft until activated), and text is required there (an empty create is refused); the call and its result are otherwise the same.",
|
|
1849
1912
|
inputSchema: {
|
|
1850
1913
|
projectId: projectIdSchema,
|
|
1851
1914
|
componentId: import_zod11.z.string().min(1).max(200).describe("The component ID to add a variant to"),
|
|
@@ -1964,7 +2027,7 @@ function registerVariantWriteTools(server, client) {
|
|
|
1964
2027
|
"update_variant",
|
|
1965
2028
|
{
|
|
1966
2029
|
title: "Update managed variant",
|
|
1967
|
-
description: "Edit a NO-CODE managed variant (one created with create_variant or in the dashboard): its display name, its text, or its status \u2014 'active' starts serving it to visitors, 'draft' takes it back out of rotation. Code-native variants cannot be edited here (change the code). Overwriting text or activating changes what live visitors see, so CONFIRM with the user first. Omit a field to leave it unchanged.",
|
|
2030
|
+
description: "Edit a NO-CODE managed variant (one created with create_variant or in the dashboard): its display name, its text, or its status \u2014 'active' starts serving it to visitors, 'draft' takes it back out of rotation. Code-native variants cannot be edited here (change the code). Overwriting text or activating changes what live visitors see, so CONFIRM with the user first. Omit a field to leave it unchanged. On a component that has moved to the shared track (one experiment with its versions), the text is edited on that component's version instead; the call and its result are the same.",
|
|
1968
2031
|
inputSchema: {
|
|
1969
2032
|
projectId: projectIdSchema,
|
|
1970
2033
|
componentId: import_zod11.z.string().min(1).max(200).describe("The component ID"),
|
|
@@ -2633,7 +2696,8 @@ and then, in the same tag after the ';', runs the inline pre-paint script; then
|
|
|
2633
2696
|
loader. The pre-paint script reads window.sentient when it runs, so sharing the tag is safe. It
|
|
2634
2697
|
is optional but recommended \u2014 the loader is deferred, so on a return visit the page can paint
|
|
2635
2698
|
its original state before the loader runs; the inline script applies the last served decision
|
|
2636
|
-
from the visitor's own device first, with no network call and no cloak
|
|
2699
|
+
from the visitor's own device first, with no network call and no page-wide cloak (it briefly hides
|
|
2700
|
+
only published components, and only for a visitor who just clicked an ad or email). Get the exact bytes from
|
|
2637
2701
|
the dashboard's Install page, or from renderSnippetInstall({ config }) in
|
|
2638
2702
|
'@sentientui/snippet/install' (renderSnippetPrePaintScript() for the script alone).
|
|
2639
2703
|
|
|
@@ -3130,7 +3194,7 @@ function registerCellTools(server, client) {
|
|
|
3130
3194
|
}
|
|
3131
3195
|
|
|
3132
3196
|
// src/server.ts
|
|
3133
|
-
var PKG_VERSION = true ? "0.
|
|
3197
|
+
var PKG_VERSION = true ? "0.24.1" : "0.0.0-dev";
|
|
3134
3198
|
function createMcpServer(client) {
|
|
3135
3199
|
const server = new import_mcp.McpServer(
|
|
3136
3200
|
{
|
package/dist/index.js
CHANGED
package/dist/lib.cjs
CHANGED
|
@@ -1271,7 +1271,36 @@ function registerPersonaTools(server, client) {
|
|
|
1271
1271
|
// src/tools/stages.ts
|
|
1272
1272
|
var import_zod6 = require("zod");
|
|
1273
1273
|
var pct = (v) => v == null ? "n/a (too few sessions)" : `${(v * 100).toFixed(1)}%`;
|
|
1274
|
-
var
|
|
1274
|
+
var counts = import_zod6.z.object({ visitors: import_zod6.z.number(), conversions: import_zod6.z.number() });
|
|
1275
|
+
var segmentLift = import_zod6.z.object({
|
|
1276
|
+
key: import_zod6.z.string(),
|
|
1277
|
+
kind: import_zod6.z.string().describe("stage | arrival | channel"),
|
|
1278
|
+
evidence: import_zod6.z.string().describe("collecting | awaiting_conversions | not_significant | significant_positive | significant_negative"),
|
|
1279
|
+
testStarted: import_zod6.z.boolean().describe("False until the series has 100 visitors per side and 10 conversions (its test scale is then fixed)"),
|
|
1280
|
+
liftPct: import_zod6.z.number().nullable().describe("Relative lift %, null while collecting / awaiting conversions"),
|
|
1281
|
+
diffInterval: import_zod6.z.object({ lower: import_zod6.z.number(), upper: import_zod6.z.number() }).nullable().describe("Always-valid range on the absolute rate difference (fractions)"),
|
|
1282
|
+
pValue: import_zod6.z.number().nullable(),
|
|
1283
|
+
rates: import_zod6.z.object({ adapted: import_zod6.z.number(), control: import_zod6.z.number() }).nullable(),
|
|
1284
|
+
adapted: counts,
|
|
1285
|
+
control: counts,
|
|
1286
|
+
epochs: import_zod6.z.number()
|
|
1287
|
+
});
|
|
1288
|
+
function liftWords(l, minPerArm) {
|
|
1289
|
+
const n = `adapted ${l.adapted.visitors} / control ${l.control.visitors} visitors`;
|
|
1290
|
+
switch (l.evidence) {
|
|
1291
|
+
case "collecting":
|
|
1292
|
+
return `early \u2014 ${n}; a number shows at ${minPerArm} per side`;
|
|
1293
|
+
case "awaiting_conversions":
|
|
1294
|
+
return `early \u2014 ${n}; waiting on control-group conversions`;
|
|
1295
|
+
case "not_significant":
|
|
1296
|
+
return `not proven yet${l.liftPct != null ? ` (${l.liftPct > 0 ? "+" : ""}${l.liftPct}%, could be chance)` : ""}${l.testStarted ? "" : " \u2014 test not started"} \u2014 ${n}`;
|
|
1297
|
+
case "significant_positive":
|
|
1298
|
+
case "significant_negative":
|
|
1299
|
+
return `tested: ${l.liftPct != null && l.liftPct > 0 ? "+" : ""}${l.liftPct}% conversion${l.evidence === "significant_negative" ? " (worse)" : ""}${l.diffInterval ? `, range ${(l.diffInterval.lower * 100).toFixed(2)} to ${(l.diffInterval.upper * 100).toFixed(2)} pts` : ""} \u2014 ${n}`;
|
|
1300
|
+
default:
|
|
1301
|
+
return n;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1275
1304
|
function registerStageTools(server, client) {
|
|
1276
1305
|
server.registerTool(
|
|
1277
1306
|
"get_stage_breakdown",
|
|
@@ -1280,7 +1309,7 @@ function registerStageTools(server, client) {
|
|
|
1280
1309
|
// Mirrors GET /projects/:id/stage-report. Says OBSERVATIONAL in the
|
|
1281
1310
|
// description because nothing serves on stage yet: an agent must not
|
|
1282
1311
|
// read a per-context arm result as "stage-based serving would win".
|
|
1283
|
-
description:
|
|
1312
|
+
description: `E-commerce projects: where visitors are in buying (new, browsing, carted, customer, lapsed) \u2014 share of human sessions per stage (each session counted once, at its latest recorded stage; hinted = set by a tagged campaign, not observed history), arrival channel x stage with conversion, how visitors moved between stages from one visit to the next, the TESTED holdout lift per first-visit context and per first-visit arrival channel (the same always-valid test as the headline lift, all-time, alpha split over all 23 possible series; "collecting" and "awaiting_conversions" are early, not results), and each region's versions per context judged against the original with the per-audience evidence rule. OBSERVATIONAL: nothing is served by stage yet; the per-context results are what stage-based serving would have to beat. Defaults to the last 30 days; pass range or from/to. Returns enabled:false when the project does not record stages.` + UNTRUSTED_FIELDS_NOTE,
|
|
1284
1313
|
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("30d")),
|
|
1285
1314
|
outputSchema: {
|
|
1286
1315
|
enabled: import_zod6.z.boolean().describe("False when the project does not record funnel stages (settings.stage absent)"),
|
|
@@ -1293,11 +1322,29 @@ function registerStageTools(server, client) {
|
|
|
1293
1322
|
contexts: import_zod6.z.array(import_zod6.z.object({
|
|
1294
1323
|
context: import_zod6.z.string(),
|
|
1295
1324
|
kind: import_zod6.z.string().describe("stage | arrival"),
|
|
1296
|
-
sessions: import_zod6.z.number()
|
|
1297
|
-
treated: side,
|
|
1298
|
-
holdout: side,
|
|
1299
|
-
rawLiftPct: import_zod6.z.number().nullable().describe("Raw relative difference, %; null until both arms have 100 sessions. Observational.")
|
|
1325
|
+
sessions: import_zod6.z.number()
|
|
1300
1326
|
})),
|
|
1327
|
+
holdoutLift: import_zod6.z.object({
|
|
1328
|
+
basis: import_zod6.z.string().describe("'first_visit': visitors grouped by their first visit's context/channel"),
|
|
1329
|
+
allTime: import_zod6.z.boolean().describe("True: the window does not apply to the lift"),
|
|
1330
|
+
goal: import_zod6.z.string(),
|
|
1331
|
+
alpha: import_zod6.z.number().describe("Per-series alpha after the correction"),
|
|
1332
|
+
family: import_zod6.z.number(),
|
|
1333
|
+
minPerArm: import_zod6.z.number(),
|
|
1334
|
+
units: import_zod6.z.number(),
|
|
1335
|
+
unclassified: import_zod6.z.number().describe("Exposed visitors with no first-visit record (exposed before recording began)"),
|
|
1336
|
+
contexts: import_zod6.z.array(segmentLift),
|
|
1337
|
+
channels: import_zod6.z.array(segmentLift)
|
|
1338
|
+
}).nullable().optional(),
|
|
1339
|
+
transitions: import_zod6.z.object({
|
|
1340
|
+
pairs: import_zod6.z.number().describe("Consecutive recorded visits in the window"),
|
|
1341
|
+
visitors: import_zod6.z.number(),
|
|
1342
|
+
rows: import_zod6.z.array(import_zod6.z.object({
|
|
1343
|
+
from: import_zod6.z.string(),
|
|
1344
|
+
nextVisits: import_zod6.z.number(),
|
|
1345
|
+
to: import_zod6.z.array(import_zod6.z.object({ stage: import_zod6.z.string(), visits: import_zod6.z.number(), visitors: import_zod6.z.number(), share: import_zod6.z.number().describe("0-1") }))
|
|
1346
|
+
}))
|
|
1347
|
+
}).optional(),
|
|
1301
1348
|
arms: import_zod6.z.array(import_zod6.z.object({
|
|
1302
1349
|
slotId: import_zod6.z.string(),
|
|
1303
1350
|
slotName: import_zod6.z.string(),
|
|
@@ -1315,6 +1362,7 @@ function registerStageTools(server, client) {
|
|
|
1315
1362
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
1316
1363
|
},
|
|
1317
1364
|
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
1365
|
+
var _a;
|
|
1318
1366
|
const id = encodeURIComponent(projectId);
|
|
1319
1367
|
const r = await client.get(`/projects/${id}/stage-report${rangeQuery({ range, from, to })}`);
|
|
1320
1368
|
const structuredContent = {
|
|
@@ -1326,6 +1374,8 @@ function registerStageTools(server, client) {
|
|
|
1326
1374
|
channels: r.channels,
|
|
1327
1375
|
arrivals: r.arrivals,
|
|
1328
1376
|
contexts: r.contexts,
|
|
1377
|
+
holdoutLift: (_a = r.holdoutLift) != null ? _a : null,
|
|
1378
|
+
transitions: r.transitions,
|
|
1329
1379
|
arms: r.arms,
|
|
1330
1380
|
window: r.window
|
|
1331
1381
|
};
|
|
@@ -1350,11 +1400,24 @@ function registerStageTools(server, client) {
|
|
|
1350
1400
|
...r.stages.map((s) => `- ${s.stage}: ${s.sessions} (${(s.share * 100).toFixed(1)}%)${s.hinted ? `, ${s.hinted} hinted` : ""}`),
|
|
1351
1401
|
"",
|
|
1352
1402
|
"Arrival channel x stage (conversion):",
|
|
1353
|
-
...r.arrivals.map((a) => `- ${a.channel} / ${a.stage}: ${a.sessions} sessions, ${pct(a.conversionRate)}`)
|
|
1354
|
-
"",
|
|
1355
|
-
"Holdout vs treated per context (raw rates, no significance test):",
|
|
1356
|
-
...r.contexts.filter((c) => c.sessions > 0).map((c) => `- ${c.context}: treated ${pct(c.treated.conversionRate)} (n=${c.treated.sessions}), holdout ${pct(c.holdout.conversionRate)} (n=${c.holdout.sessions})${c.rawLiftPct != null ? `, raw difference ${c.rawLiftPct > 0 ? "+" : ""}${c.rawLiftPct}%` : ""}`)
|
|
1403
|
+
...r.arrivals.map((a) => `- ${a.channel} / ${a.stage}: ${a.sessions} sessions, ${pct(a.conversionRate)}`)
|
|
1357
1404
|
];
|
|
1405
|
+
const t = r.transitions;
|
|
1406
|
+
if (t && t.rows.length > 0) {
|
|
1407
|
+
lines.push("", `Stage moves between visits (${t.pairs} next visits from ${t.visitors} returning visitors in the window):`);
|
|
1408
|
+
for (const row of t.rows) {
|
|
1409
|
+
lines.push(`- from ${row.from} (${row.nextVisits} next visits): ${row.to.map((x) => `${x.stage} ${(x.share * 100).toFixed(0)}%`).join(", ")}`);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
const h = r.holdoutLift;
|
|
1413
|
+
if (h && (h.contexts.length > 0 || h.channels.length > 0)) {
|
|
1414
|
+
lines.push(
|
|
1415
|
+
"",
|
|
1416
|
+
`Holdout lift by first-visit context and channel (tested, all-time \u2014 the window does not apply; alpha ${h.alpha.toPrecision(2)} per series over ${h.family}; ${h.unclassified} of ${h.units} visitors predate recording and are not in any row):`,
|
|
1417
|
+
...h.contexts.map((l) => `- context ${l.key}: ${liftWords(l, h.minPerArm)}`),
|
|
1418
|
+
...h.channels.map((l) => `- channel ${l.key}: ${liftWords(l, h.minPerArm)}`)
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1358
1421
|
if (r.arms.length > 0) {
|
|
1359
1422
|
lines.push("", "Versions per context (what stage-based serving would have to beat):");
|
|
1360
1423
|
for (const a of r.arms) {
|
|
@@ -1871,7 +1934,7 @@ function registerVariantWriteTools(server, client) {
|
|
|
1871
1934
|
"create_variant",
|
|
1872
1935
|
{
|
|
1873
1936
|
title: "Create managed variant",
|
|
1874
|
-
description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Works on every plan with an editor/admin login or the project's sk_ server key (anonymous demo tokens are read-only). The variant is created as a DRAFT \u2014 it serves no traffic until activated with update_variant (status 'active'). Confirm the text with the user before calling.",
|
|
1937
|
+
description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Works on every plan with an editor/admin login or the project's sk_ server key (anonymous demo tokens are read-only). The variant is created as a DRAFT \u2014 it serves no traffic until activated with update_variant (status 'active'). Confirm the text with the user before calling. On a component that has moved to the shared track, the text is added to the component's versions instead (still a draft until activated), and text is required there (an empty create is refused); the call and its result are otherwise the same.",
|
|
1875
1938
|
inputSchema: {
|
|
1876
1939
|
projectId: projectIdSchema,
|
|
1877
1940
|
componentId: import_zod11.z.string().min(1).max(200).describe("The component ID to add a variant to"),
|
|
@@ -1990,7 +2053,7 @@ function registerVariantWriteTools(server, client) {
|
|
|
1990
2053
|
"update_variant",
|
|
1991
2054
|
{
|
|
1992
2055
|
title: "Update managed variant",
|
|
1993
|
-
description: "Edit a NO-CODE managed variant (one created with create_variant or in the dashboard): its display name, its text, or its status \u2014 'active' starts serving it to visitors, 'draft' takes it back out of rotation. Code-native variants cannot be edited here (change the code). Overwriting text or activating changes what live visitors see, so CONFIRM with the user first. Omit a field to leave it unchanged.",
|
|
2056
|
+
description: "Edit a NO-CODE managed variant (one created with create_variant or in the dashboard): its display name, its text, or its status \u2014 'active' starts serving it to visitors, 'draft' takes it back out of rotation. Code-native variants cannot be edited here (change the code). Overwriting text or activating changes what live visitors see, so CONFIRM with the user first. Omit a field to leave it unchanged. On a component that has moved to the shared track (one experiment with its versions), the text is edited on that component's version instead; the call and its result are the same.",
|
|
1994
2057
|
inputSchema: {
|
|
1995
2058
|
projectId: projectIdSchema,
|
|
1996
2059
|
componentId: import_zod11.z.string().min(1).max(200).describe("The component ID"),
|
|
@@ -2659,7 +2722,8 @@ and then, in the same tag after the ';', runs the inline pre-paint script; then
|
|
|
2659
2722
|
loader. The pre-paint script reads window.sentient when it runs, so sharing the tag is safe. It
|
|
2660
2723
|
is optional but recommended \u2014 the loader is deferred, so on a return visit the page can paint
|
|
2661
2724
|
its original state before the loader runs; the inline script applies the last served decision
|
|
2662
|
-
from the visitor's own device first, with no network call and no cloak
|
|
2725
|
+
from the visitor's own device first, with no network call and no page-wide cloak (it briefly hides
|
|
2726
|
+
only published components, and only for a visitor who just clicked an ad or email). Get the exact bytes from
|
|
2663
2727
|
the dashboard's Install page, or from renderSnippetInstall({ config }) in
|
|
2664
2728
|
'@sentientui/snippet/install' (renderSnippetPrePaintScript() for the script alone).
|
|
2665
2729
|
|
|
@@ -3156,7 +3220,7 @@ function registerCellTools(server, client) {
|
|
|
3156
3220
|
}
|
|
3157
3221
|
|
|
3158
3222
|
// src/server.ts
|
|
3159
|
-
var PKG_VERSION = true ? "0.
|
|
3223
|
+
var PKG_VERSION = true ? "0.24.1" : "0.0.0-dev";
|
|
3160
3224
|
function createMcpServer(client) {
|
|
3161
3225
|
const server = new import_mcp.McpServer(
|
|
3162
3226
|
{
|
|
@@ -3224,7 +3288,7 @@ var TOOL_CATALOG = [
|
|
|
3224
3288
|
{ name: "list_guardrail_events", access: "read", summary: "Every variant currently paused by a guardrail (optionally only pauses from the last N days)" },
|
|
3225
3289
|
// Audience and layout
|
|
3226
3290
|
{ name: "get_persona_breakdown", access: "read", summary: "Visitor clusters with session counts and reliability (all retained sessions)" },
|
|
3227
|
-
{ name: "get_stage_breakdown", access: "read", summary: "E-commerce funnel stages: stage mix, arrival channel x stage, holdout per context and versions per context (windowed, observational)" },
|
|
3291
|
+
{ name: "get_stage_breakdown", access: "read", summary: "E-commerce funnel stages: stage mix, arrival channel x stage, stage moves between visits, tested holdout lift per first-visit context and channel, and versions per context (windowed, observational)" },
|
|
3228
3292
|
{ name: "get_layout_stats", access: "read", summary: "Per-persona section order with bandit pulls and reward (cumulative state)" },
|
|
3229
3293
|
// Insights
|
|
3230
3294
|
{ name: "get_insights", access: "read", summary: "Ranked measured findings with their sample, plus AI narrations marked unmeasured" },
|
package/dist/lib.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
ApiError,
|
|
5
5
|
PUBLIC_UI_RESOURCE_URIS,
|
|
6
6
|
createMcpServer
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-G6WGJ7A5.js";
|
|
8
8
|
|
|
9
9
|
// src/tool-catalog.ts
|
|
10
10
|
var TOOL_CATALOG = [
|
|
@@ -34,7 +34,7 @@ var TOOL_CATALOG = [
|
|
|
34
34
|
{ name: "list_guardrail_events", access: "read", summary: "Every variant currently paused by a guardrail (optionally only pauses from the last N days)" },
|
|
35
35
|
// Audience and layout
|
|
36
36
|
{ name: "get_persona_breakdown", access: "read", summary: "Visitor clusters with session counts and reliability (all retained sessions)" },
|
|
37
|
-
{ name: "get_stage_breakdown", access: "read", summary: "E-commerce funnel stages: stage mix, arrival channel x stage, holdout per context and versions per context (windowed, observational)" },
|
|
37
|
+
{ name: "get_stage_breakdown", access: "read", summary: "E-commerce funnel stages: stage mix, arrival channel x stage, stage moves between visits, tested holdout lift per first-visit context and channel, and versions per context (windowed, observational)" },
|
|
38
38
|
{ name: "get_layout_stats", access: "read", summary: "Per-persona section order with bandit pulls and reward (cumulative state)" },
|
|
39
39
|
// Insights
|
|
40
40
|
{ name: "get_insights", access: "read", summary: "Ranked measured findings with their sample, plus AI narrations marked unmeasured" },
|