@convertcom/mcp-server 0.0.1-beta.15 → 0.0.1-beta.17
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/build/api-config.js +21 -3
- package/build/api-config.js.map +1 -1
- package/build/auth-context.d.ts +3 -0
- package/build/auth-context.js.map +1 -1
- package/build/catalog-change.d.ts +6 -2
- package/build/catalog-change.js +5 -1
- package/build/catalog-change.js.map +1 -1
- package/build/executor.d.ts +6 -0
- package/build/executor.js +73 -22
- package/build/executor.js.map +1 -1
- package/build/generated-tool-validators.js +141 -158
- package/build/generated-tool-validators.js.map +1 -1
- package/build/index.js +19 -12
- package/build/index.js.map +1 -1
- package/build/kb-hybrid.d.ts +13 -5
- package/build/kb-hybrid.js +16 -10
- package/build/kb-hybrid.js.map +1 -1
- package/build/kb-search.d.ts +9 -3
- package/build/kb-search.js +95 -4
- package/build/kb-search.js.map +1 -1
- package/build/kb-semantic.d.ts +2 -2
- package/build/kb-semantic.js +11 -2
- package/build/kb-semantic.js.map +1 -1
- package/build/local-docs.d.ts +12 -0
- package/build/local-docs.js +9 -0
- package/build/local-docs.js.map +1 -0
- package/build/local-execution-context.d.ts +7 -0
- package/build/local-execution-context.js +18 -0
- package/build/local-execution-context.js.map +1 -0
- package/build/mcp-server-compat.d.ts +8 -0
- package/build/mcp-server-compat.js +28 -0
- package/build/mcp-server-compat.js.map +1 -0
- package/build/modern-runtime.d.ts +13 -0
- package/build/modern-runtime.js +148 -0
- package/build/modern-runtime.js.map +1 -0
- package/build/namespaced.js +31 -4
- package/build/namespaced.js.map +1 -1
- package/build/operator.js +60 -4
- package/build/operator.js.map +1 -1
- package/build/runtime.d.ts +226 -5
- package/build/runtime.js +185 -73
- package/build/runtime.js.map +1 -1
- package/package.json +6 -6
- package/server.json +2 -2
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const FALSY_REQUEST_ID_COMPAT = Symbol('convert.falsy-request-id-cancellation');
|
|
2
|
+
/**
|
|
3
|
+
* @modelcontextprotocol/server 2.0.0 ignores cancellation for the valid
|
|
4
|
+
* falsy JSON-RPC IDs 0 and "".
|
|
5
|
+
* Keep the workaround on each Convert-owned server instance so the published
|
|
6
|
+
* npm package and Worker bundle have identical behavior without package-manager
|
|
7
|
+
* patch protocols. Remove this shim once the pinned SDK contains the fix.
|
|
8
|
+
*/
|
|
9
|
+
export function applyFalsyRequestIdCancellationCompat(server) {
|
|
10
|
+
const protocol = server;
|
|
11
|
+
if (protocol[FALSY_REQUEST_ID_COMPAT])
|
|
12
|
+
return;
|
|
13
|
+
if (typeof protocol._oncancel !== 'function'
|
|
14
|
+
|| !(protocol._requestHandlerAbortControllers instanceof Map)) {
|
|
15
|
+
throw new Error('MCP server cancellation compatibility seam is unavailable.');
|
|
16
|
+
}
|
|
17
|
+
const original = protocol._oncancel.bind(protocol);
|
|
18
|
+
protocol._oncancel = async (notification) => {
|
|
19
|
+
const requestId = notification.params.requestId;
|
|
20
|
+
if (requestId !== 0 && requestId !== '') {
|
|
21
|
+
await original(notification);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
protocol._requestHandlerAbortControllers.get(requestId)?.abort(notification.params.reason);
|
|
25
|
+
};
|
|
26
|
+
protocol[FALSY_REQUEST_ID_COMPAT] = true;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=mcp-server-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server-compat.js","sourceRoot":"","sources":["../src/mcp-server-compat.ts"],"names":[],"mappings":"AAaA,MAAM,uBAAuB,GAAG,MAAM,CAAC,uCAAuC,CAAC,CAAC;AAEhF;;;;;;GAMG;AACH,MAAM,UAAU,qCAAqC,CAAC,MAAc;IAClE,MAAM,QAAQ,GAAG,MAAiD,CAAC;IACnE,IAAI,QAAQ,CAAC,uBAAuB,CAAC;QAAE,OAAO;IAC9C,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,UAAU;WACvC,CAAC,CAAC,QAAQ,CAAC,+BAA+B,YAAY,GAAG,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnD,QAAQ,CAAC,SAAS,GAAG,KAAK,EAAE,YAAY,EAAE,EAAE;QAC1C,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC;QAChD,IAAI,SAAS,KAAK,CAAC,IAAI,SAAS,KAAK,EAAE,EAAE,CAAC;YACxC,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,+BAA+B,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7F,CAAC,CAAC;IACF,QAAQ,CAAC,uBAAuB,CAAC,GAAG,IAAI,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type ConvertMcpServerIdentityOptions, type ConvertMcpRuntimeOptions } from './runtime.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the v2 protocol server while keeping catalog and dispatch behavior in
|
|
5
|
+
* the shared runtime. The HTTP entry must create one of these per request.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createModernConvertMcpServer(options: ConvertMcpRuntimeOptions): Server;
|
|
8
|
+
/**
|
|
9
|
+
* A listen request needs only identity and capabilities. Keeping this factory
|
|
10
|
+
* separate prevents a long-lived SSE handler from retaining Convert OAuth
|
|
11
|
+
* props, catalogs, docs providers, validators, or execution closures.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createModernConvertMcpListenServer(options: ConvertMcpServerIdentityOptions, advertiseListChanged: boolean): Server;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { CLIENT_INFO_META_KEY, ProtocolError, Server, } from '@modelcontextprotocol/server';
|
|
2
|
+
import { McpError as LegacyMcpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { convertMcpServerDefinition, createConvertMcpHandlers, } from './runtime.js';
|
|
4
|
+
import { applyFalsyRequestIdCancellationCompat } from './mcp-server-compat.js';
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function sharedClientInfoFrom(value) {
|
|
9
|
+
if (!isRecord(value) || typeof value.name !== 'string' || typeof value.version !== 'string')
|
|
10
|
+
return undefined;
|
|
11
|
+
const clientInfo = { name: value.name, version: value.version };
|
|
12
|
+
for (const key of ['title', 'description', 'websiteUrl']) {
|
|
13
|
+
if (typeof value[key] === 'string')
|
|
14
|
+
clientInfo[key] = value[key];
|
|
15
|
+
}
|
|
16
|
+
if (Array.isArray(value.icons)) {
|
|
17
|
+
const icons = value.icons
|
|
18
|
+
.filter(isRecord)
|
|
19
|
+
.map((icon) => {
|
|
20
|
+
if (typeof icon.src !== 'string')
|
|
21
|
+
return undefined;
|
|
22
|
+
const sanitized = { src: icon.src };
|
|
23
|
+
if (typeof icon.mimeType === 'string')
|
|
24
|
+
sanitized.mimeType = icon.mimeType;
|
|
25
|
+
if (Array.isArray(icon.sizes) && icon.sizes.every((size) => typeof size === 'string')) {
|
|
26
|
+
sanitized.sizes = icon.sizes;
|
|
27
|
+
}
|
|
28
|
+
if (icon.theme === 'light' || icon.theme === 'dark')
|
|
29
|
+
sanitized.theme = icon.theme;
|
|
30
|
+
return sanitized;
|
|
31
|
+
})
|
|
32
|
+
.filter((icon) => icon !== undefined);
|
|
33
|
+
if (icons.length > 0)
|
|
34
|
+
clientInfo.icons = icons;
|
|
35
|
+
}
|
|
36
|
+
return clientInfo;
|
|
37
|
+
}
|
|
38
|
+
function clientInfoFromEnvelope(envelope) {
|
|
39
|
+
if (!envelope)
|
|
40
|
+
return undefined;
|
|
41
|
+
const value = envelope[CLIENT_INFO_META_KEY];
|
|
42
|
+
return sharedClientInfoFrom(value);
|
|
43
|
+
}
|
|
44
|
+
function translateLegacyProtocolError(error) {
|
|
45
|
+
if (error instanceof LegacyMcpError) {
|
|
46
|
+
throw new ProtocolError(error.code, error.message, error.data);
|
|
47
|
+
}
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
async function withModernProtocolErrors(operation) {
|
|
51
|
+
try {
|
|
52
|
+
return await operation();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return translateLegacyProtocolError(error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builds the v2 protocol server while keeping catalog and dispatch behavior in
|
|
60
|
+
* the shared runtime. The HTTP entry must create one of these per request.
|
|
61
|
+
*/
|
|
62
|
+
export function createModernConvertMcpServer(options) {
|
|
63
|
+
const definition = convertMcpServerDefinition(options);
|
|
64
|
+
const capabilities = options.advertiseListChanged === false
|
|
65
|
+
? {
|
|
66
|
+
tools: { listChanged: false },
|
|
67
|
+
prompts: { listChanged: false },
|
|
68
|
+
resources: { listChanged: false },
|
|
69
|
+
}
|
|
70
|
+
: definition.options.capabilities;
|
|
71
|
+
const server = new Server(definition.implementation, {
|
|
72
|
+
...definition.options,
|
|
73
|
+
capabilities,
|
|
74
|
+
});
|
|
75
|
+
applyFalsyRequestIdCancellationCompat(server);
|
|
76
|
+
const handlers = createConvertMcpHandlers(options, (extra) => extra.clientInfo ?? sharedClientInfoFrom(server.getClientVersion()));
|
|
77
|
+
const runtimeExtra = (ctx) => {
|
|
78
|
+
const extra = {
|
|
79
|
+
signal: ctx.mcpReq.signal,
|
|
80
|
+
requestId: ctx.mcpReq.id,
|
|
81
|
+
sendNotification: (notification) => ctx.mcpReq.notify(notification),
|
|
82
|
+
clientInfo: clientInfoFromEnvelope(ctx.mcpReq.envelope),
|
|
83
|
+
};
|
|
84
|
+
return extra;
|
|
85
|
+
};
|
|
86
|
+
server.setRequestHandler('tools/list', async (_request, ctx) => {
|
|
87
|
+
return await withModernProtocolErrors(async () => {
|
|
88
|
+
return await handlers.listTools(runtimeExtra(ctx));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
server.setRequestHandler('resources/list', async (_request, ctx) => {
|
|
92
|
+
return await withModernProtocolErrors(async () => {
|
|
93
|
+
return await handlers.listResources(runtimeExtra(ctx));
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
server.setRequestHandler('resources/templates/list', async (_request, ctx) => {
|
|
97
|
+
return await withModernProtocolErrors(async () => {
|
|
98
|
+
return await handlers.listResourceTemplates(runtimeExtra(ctx));
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
server.setRequestHandler('resources/read', async (request, ctx) => {
|
|
102
|
+
return await withModernProtocolErrors(async () => {
|
|
103
|
+
return await handlers.readResource(request, runtimeExtra(ctx));
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
server.setRequestHandler('prompts/list', async (_request, ctx) => {
|
|
107
|
+
return await withModernProtocolErrors(async () => {
|
|
108
|
+
return await handlers.listPrompts(runtimeExtra(ctx));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
server.setRequestHandler('prompts/get', async (request, ctx) => {
|
|
112
|
+
return await withModernProtocolErrors(async () => {
|
|
113
|
+
return await handlers.getPrompt(request, runtimeExtra(ctx));
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
server.setRequestHandler('tools/call', async (request, ctx) => {
|
|
117
|
+
return await withModernProtocolErrors(async () => {
|
|
118
|
+
let outputSchema;
|
|
119
|
+
const result = await handlers.callTool(request, runtimeExtra(ctx), (tool) => {
|
|
120
|
+
outputSchema = tool?.outputSchema;
|
|
121
|
+
});
|
|
122
|
+
// Low-level v2 handlers use this public codec seam. Convert's schemas
|
|
123
|
+
// and structured results are object-rooted, so projection is identity
|
|
124
|
+
// today while retaining the SDK's required text fallback behavior.
|
|
125
|
+
return server.projectCallToolResult(result, outputSchema);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
return server;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* A listen request needs only identity and capabilities. Keeping this factory
|
|
132
|
+
* separate prevents a long-lived SSE handler from retaining Convert OAuth
|
|
133
|
+
* props, catalogs, docs providers, validators, or execution closures.
|
|
134
|
+
*/
|
|
135
|
+
export function createModernConvertMcpListenServer(options, advertiseListChanged) {
|
|
136
|
+
const definition = convertMcpServerDefinition(options);
|
|
137
|
+
return new Server(definition.implementation, {
|
|
138
|
+
...definition.options,
|
|
139
|
+
capabilities: advertiseListChanged
|
|
140
|
+
? definition.options.capabilities
|
|
141
|
+
: {
|
|
142
|
+
tools: { listChanged: false },
|
|
143
|
+
prompts: { listChanged: false },
|
|
144
|
+
resources: { listChanged: false },
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=modern-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modern-runtime.js","sourceRoot":"","sources":["../src/modern-runtime.ts"],"names":[],"mappings":"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"}
|
package/build/namespaced.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toolDefinitionMap } from './tools.js';
|
|
2
|
-
import { executeToolByName, truncateSchemaText, validateToolArgs } from './executor.js';
|
|
2
|
+
import { executeToolByName, executeValidatedToolByName, truncateSchemaText, validateToolArgs } from './executor.js';
|
|
3
3
|
import { JSON_SCHEMA_DRAFT_2020_12, pathParamsFromTemplate, tryParseJsonLike } from './shared.js';
|
|
4
4
|
import { toolSafetyKindForDelegate } from './tool-safety.js';
|
|
5
5
|
import { MDE_FRACTION_BOUNDARY_VERSION, experienceStatsVersion, usesLegacyFixedMdeScale, } from './stats-engine-version.js';
|
|
@@ -15,6 +15,7 @@ const STATS_ENGINE_EVIDENCE_NOTE = [
|
|
|
15
15
|
'Never mix engine vocabularies in the same interpretation.',
|
|
16
16
|
'Never calculate, estimate, simulate, or label an inactive-engine result from the current report counts, including hypothetical or "what if we switched" requests. A Convert chance_to_win must come from a fresh Bayesian aggregate report; a Convert significance result must come from a fresh Frequentist aggregate report.',
|
|
17
17
|
'After any stats-lens change, fetch a fresh aggregated report and never carry a conclusion across lenses.',
|
|
18
|
+
'Use settings.min_variation_conversions for the minimum conversion count. Deprecated min_conversion_value aliases the same stored count; it is not a separate revenue threshold. Settings are returned configuration, not an include/expand relation.',
|
|
18
19
|
].join(' ');
|
|
19
20
|
function requiredPathParamsForDef(def) {
|
|
20
21
|
const declared = (def.executionParameters || [])
|
|
@@ -320,6 +321,7 @@ export const ACTION_NOTES = {
|
|
|
320
321
|
'Type enum: "a/b", "a/a", "mvt", "split_url", "multipage", "deploy" (standard projects), "a/b_fullstack", "feature_rollout" (fullstack projects only).',
|
|
321
322
|
'Deploy semantics: type "deploy" is a rollout/deployment container, not a tracked experience. Do not expect visitor/conversion reporting for deploys.',
|
|
322
323
|
'Required body fields: name, type, url. If status is omitted, MCP defaults it to "draft".',
|
|
324
|
+
'Before creation, fetch projects.get with default_goals, default_audiences, and default_locations included/expanded, inspect project stats/allocation and integrations, and resolve the intended resources by name. Discuss inherited defaults with the user; operator.get_defaults is a suggestion, not consent to attach a goal or enable MAB/integrations. Read back the draft with expanded goals, audiences, locations and variations and disclose any inherited configuration before activation. Do not promise that omitted fields mean disabled or empty.',
|
|
323
325
|
'Setting status to "active" requires explicit user confirmation at tool-call level: confirmation: { "user_confirmed": true, "reason": "..." }.',
|
|
324
326
|
'For hand-written JS/CSS in an A/B test, use changes[].type "customCode" with data { "js": "...", "css": "" }. Do not use "defaultCode" unless sending Visual Editor data with custom_js.',
|
|
325
327
|
'Create control+treatment variations by sending body.variations with each variation name and optional changes array. Use traffic_distribution for variation traffic; MCP also accepts legacy traffic_percentage and normalizes it.',
|
|
@@ -397,7 +399,7 @@ export const ACTION_NOTES = {
|
|
|
397
399
|
'Engine vocabularies are mutually exclusive. For Bayesian reports, use chance_to_win, done, and estimated_progress. Never describe Bayesian evidence as confidence or statistically significant; never use confidence, statistically_significant, observed_power, or other Frequentist significance fields, and do not quote or interpret the ambiguous numeric risk vector. For Frequentist reports, use confidence, statistically_significant, done, and engine-appropriate progress; never use chance_to_win, Bayesian risk, or Bayesian decision-threshold language. MCP removes inactive-engine metric fields before returning the report.',
|
|
398
400
|
'Do not describe a shared settings field as active evidence merely because it is present. Resolve stats_methodology first, then discuss only settings and metric fields that belong to that engine.',
|
|
399
401
|
].join('\n'),
|
|
400
|
-
'experiences.daily_report': 'Works on tracked experience types.
|
|
402
|
+
'experiences.daily_report': 'Use body.goal (numeric goal ID), not query.goal_id or body.goal_id. Example: { "action": "daily_report", "path": { "account_id": 123, "project_id": 456, "experience_id": 789 }, "body": { "goal": 101, "report_type": "non_cumulative", "metric": "conversion_rate" } }. Date range and segments also belong in the documented body fields; resolve goal IDs from the experience before selecting a non-primary goal. Works on tracked experience types. An empty series does not prove zero traffic; check lifecycle and collection coverage. Deploy experiences are not tracked experiences, so daily reports are not applicable and clients must skip this request when diagnosing deploy tracking.',
|
|
401
403
|
'experiences.get_heatmap_background': 'Requires heatmap_id in path. Optional body.device is one of "desktop", "tablet", or "mobile" and defaults to "desktop".',
|
|
402
404
|
'experiences.get_heatmap_overlay': 'Requires heatmap_id in path. Optional body.device is one of "desktop", "tablet", or "mobile"; optional body.interaction is "click", "scroll", or "move". Defaults are desktop/click.',
|
|
403
405
|
// ── locations ────────────────────────────────────────────
|
|
@@ -523,9 +525,11 @@ export const ACTION_NOTES = {
|
|
|
523
525
|
'MCP accepts legacy type aliases "custom_js" -> "code_trigger" and "scrolls_to" -> "scroll_percentage".',
|
|
524
526
|
'description max length is 500 characters.',
|
|
525
527
|
'Use triggering_rule for URL or audience-style scoping; it accepts nested OR→AND→OR_WHEN rules.',
|
|
528
|
+
'visits_page does not use settings.url for tracking. Put page matching in triggering_rule; an echoed settings value is not proof that targeting was applied. Omit settings for an intentionally unscoped page-visit goal.',
|
|
526
529
|
'clicks_element settings example: { "selector": ".cta" }. code_trigger requires no settings.',
|
|
527
530
|
'clicks_link requires settings.href as a string; Convert API rejects match objects there. Use triggering_rule for page scoping, or create multiple link goals when multiple href patterns are needed.',
|
|
528
531
|
].join('\n'),
|
|
532
|
+
'goals.update': 'Use triggering_rule for page scoping, not settings.url, including partial updates that omit type. Preserve existing triggering_rule conditions when editing scope; omission preserves them, while null clears them. Do not infer a goal collection start from its creation date or compare goals as if they necessarily share a collection window.',
|
|
529
533
|
// ── accounts ─────────────────────────────────────────────
|
|
530
534
|
'accounts.list_sdk_keys': 'Requires "project_id" in path even though it\'s under the accounts namespace.',
|
|
531
535
|
'accounts.create_sdk_key': [
|
|
@@ -1042,6 +1046,18 @@ function evaluateGoalGuardrails(action, body) {
|
|
|
1042
1046
|
return null;
|
|
1043
1047
|
if (!isNonArrayObject(body.settings))
|
|
1044
1048
|
return null;
|
|
1049
|
+
if ((typeof body.type === 'undefined' || body.type === 'visits_page')
|
|
1050
|
+
&& Object.prototype.hasOwnProperty.call(body.settings, 'url')) {
|
|
1051
|
+
return {
|
|
1052
|
+
code: 'GoalUrlRequiresTriggeringRule',
|
|
1053
|
+
message: [
|
|
1054
|
+
'goals.create/update: body.settings.url does not scope visits_page tracking, even when the API echoes it. No write was sent.',
|
|
1055
|
+
'For partial updates that omit type, fetch goals.get to confirm the goal type before editing its tracking configuration.',
|
|
1056
|
+
'Remove settings.url and express page scoping in triggering_rule, for example: { "OR": [{ "AND": [{ "OR_WHEN": [{ "rule_type": "url", "value": "https://example.com/free-trial", "matching": { "match_type": "contains" } }] }] }] }.',
|
|
1057
|
+
'Preserve any existing triggering_rule conditions; do not replace them blindly. Omit settings for an intentionally unscoped visits_page goal.',
|
|
1058
|
+
].join('\n'),
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1045
1061
|
if (typeof body.type !== 'undefined' && body.type !== 'clicks_link')
|
|
1046
1062
|
return null;
|
|
1047
1063
|
const href = body.settings.href;
|
|
@@ -1528,6 +1544,10 @@ const AGGREGATED_REPORT_GUIDANCE = {
|
|
|
1528
1544
|
interpretation: 'srm=true is an API-detected sample-ratio mismatch and blocks inferential conclusions for the affected scope. srm=false means the API did not flag SRM for this response; it is not independent proof of correct allocation when threshold, expected-allocation, or sample context is absent.',
|
|
1529
1545
|
provenance: 'api_boolean_without_threshold_context',
|
|
1530
1546
|
},
|
|
1547
|
+
computation_provenance: {
|
|
1548
|
+
state: 'unknown_without_upstream_computation_metadata',
|
|
1549
|
+
interpretation: 'The API transformer may default missing srm_pvalue to 1, missing chance_to_win/confidence to 0, and missing done/srm to false. Preserve genuine numeric 0/1, boolean true/false, and explicit missing/null values; the wire value alone cannot establish whether the statistic was computed. done=false means no completion is reported, not proof that a computation ran and failed its stopping gates. Respect reported done=true and engine-specific decision gates; never manufacture completion. Do not infer a paused-experience effect, a minimum-conversion gate, or a clean allocation from default-like values. Disclose the uncertainty when it affects a conclusion.',
|
|
1550
|
+
},
|
|
1531
1551
|
};
|
|
1532
1552
|
const DYNAMIC_MDE_GUIDANCE = {
|
|
1533
1553
|
semantics_version: 'convert.dynamic-mde.v1',
|
|
@@ -1768,6 +1788,7 @@ export function normalizeAggregatedReportResult(result) {
|
|
|
1768
1788
|
'- Deprecated conversion_data, revenue_data, and products_data blocks were removed.',
|
|
1769
1789
|
'- Use reportData[].variations[].metrics[] as the only statistical evidence source.',
|
|
1770
1790
|
'- Treat srm=true as an API-detected allocation mismatch. Treat srm=false only as "not flagged by this API response", not as independent proof that allocation is correct when threshold context is absent.',
|
|
1791
|
+
`- ${AGGREGATED_REPORT_GUIDANCE.computation_provenance.interpretation}`,
|
|
1771
1792
|
`- ${engineGuidance}`,
|
|
1772
1793
|
].join('\n');
|
|
1773
1794
|
const content = [{
|
|
@@ -2237,12 +2258,18 @@ export async function executeNamespacedTool(toolName, args, executionContext, to
|
|
|
2237
2258
|
isError: true,
|
|
2238
2259
|
}, namespace, action, delegate);
|
|
2239
2260
|
}
|
|
2240
|
-
const executedResult = await
|
|
2261
|
+
const executedResult = await executeValidatedToolByName(delegate, flattenedArgs, executionContext);
|
|
2241
2262
|
const approvalAwareResult = normalizeApprovalRequiredError(namespace, action, path, executedResult);
|
|
2242
2263
|
const result = normalizeProjectCreatePermissionError(namespace, action, approvalAwareResult);
|
|
2243
2264
|
// Append action-specific guidance to error messages so agents can self-correct
|
|
2244
2265
|
if (result.isError) {
|
|
2245
|
-
const
|
|
2266
|
+
const lifecycleDenied = namespace === 'experiences' && isNonArrayObject(normalizedBody)
|
|
2267
|
+
&& ((action === 'update' && ['active', 'paused'].includes(String(normalizedBody.status)))
|
|
2268
|
+
|| (action === 'create' && normalizedBody.status === 'active'))
|
|
2269
|
+
&& asObject(result.structuredContent)?.status === 403;
|
|
2270
|
+
const note = lifecycleDenied
|
|
2271
|
+
? `Activation/pause was denied by Convert. Human confirmation records intent; it does not grant authorization. Verify the exact account/project, the credential principal's current ${action === 'create' ? 'experience.add' : 'experience.pauseplay'} permission and OAuth grant scope. Plan or approval restrictions are possibilities, not established causes unless the backend explicitly identifies them. Do not retry with different payloads, reconnect automatically, or submit an approval request unless Convert returns ApprovalRequired and the user asks to submit it. Staff impersonation remains browse-only.`
|
|
2272
|
+
: ACTION_NOTES[`${namespace}.${action}`];
|
|
2246
2273
|
if (note && result.content?.[0]?.type === 'text') {
|
|
2247
2274
|
result.content[0].text += `\n\nHint for ${namespace}.${action}:\n${note}`;
|
|
2248
2275
|
}
|