@canonry/canonry 4.133.2 → 4.134.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/README.md +0 -13
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +25 -0
- package/assets/assets/{AuditHistoryPanel-CVDg3GXg.js → AuditHistoryPanel-DBUWbfNk.js} +1 -1
- package/assets/assets/{BacklinksPage-Dh4RIvS7.js → BacklinksPage-BFm0VdUO.js} +1 -1
- package/assets/assets/{ChartPrimitives-BK89G5H_.js → ChartPrimitives-oV_nduTH.js} +1 -1
- package/assets/assets/{HistoryPage-D8rMu_Js.js → HistoryPage-IF2FMem3.js} +1 -1
- package/assets/assets/{ProjectPage-CiTDveNK.js → ProjectPage-ClwxX9Ga.js} +2 -2
- package/assets/assets/{RunRow-DVOwbmTp.js → RunRow-De5zdch5.js} +1 -1
- package/assets/assets/{RunsPage-tz3Oil7N.js → RunsPage-xtRF78r8.js} +1 -1
- package/assets/assets/{SettingsPage-C698YidM.js → SettingsPage-B_GAxaWu.js} +1 -1
- package/assets/assets/{TrafficPage-XDXWMtey.js → TrafficPage-E8I5ineJ.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-Clz8kOR8.js → TrafficSourceDetailPage-DGk2MqSp.js} +1 -1
- package/assets/assets/{arrow-left-GWLbh0pE.js → arrow-left-D-4QMxi9.js} +1 -1
- package/assets/assets/{extract-error-message-Dk8w-sb1.js → extract-error-message-DuqIFU8Z.js} +1 -1
- package/assets/assets/{index-jTshRRh0.js → index-De1MKbc7.js} +90 -90
- package/assets/assets/{trash-2-DwnzsuH1.js → trash-2-BVh__r6G.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-IEZTETUZ.js → chunk-LIXWDIDR.js} +787 -42
- package/dist/{chunk-ZPQX5ZQ2.js → chunk-PC7AYXND.js} +325 -2
- package/dist/{chunk-V2YR3YK6.js → chunk-TKXWTDV6.js} +73 -7
- package/dist/{chunk-JTJQZ4UC.js → chunk-ZUQPHGEN.js} +73 -2
- package/dist/cli.js +109 -4
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-WZNE23TV.js → intelligence-service-4XOFUN5E.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +10 -10
|
@@ -47,8 +47,8 @@ function authInvalid() {
|
|
|
47
47
|
function forbidden(message = "Forbidden", details) {
|
|
48
48
|
return new AppError("FORBIDDEN", message, 403, details);
|
|
49
49
|
}
|
|
50
|
-
function quotaExceeded(metric) {
|
|
51
|
-
return new AppError("QUOTA_EXCEEDED", `Quota exceeded for ${metric}`, 429);
|
|
50
|
+
function quotaExceeded(metric, details) {
|
|
51
|
+
return new AppError("QUOTA_EXCEEDED", `Quota exceeded for ${metric}`, 429, details);
|
|
52
52
|
}
|
|
53
53
|
function providerError(message, details) {
|
|
54
54
|
return new AppError("PROVIDER_ERROR", message, 502, details);
|
|
@@ -960,6 +960,111 @@ function formatIsoDate(iso) {
|
|
|
960
960
|
return iso;
|
|
961
961
|
}
|
|
962
962
|
}
|
|
963
|
+
function zonedClockFormat(timeZone) {
|
|
964
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
965
|
+
timeZone,
|
|
966
|
+
year: "numeric",
|
|
967
|
+
month: "2-digit",
|
|
968
|
+
day: "2-digit",
|
|
969
|
+
hour: "2-digit",
|
|
970
|
+
minute: "2-digit",
|
|
971
|
+
second: "2-digit",
|
|
972
|
+
hourCycle: "h23"
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
function readZonedParts(format, date) {
|
|
976
|
+
const values = {};
|
|
977
|
+
for (const part of format.formatToParts(date)) values[part.type] = part.value;
|
|
978
|
+
return values;
|
|
979
|
+
}
|
|
980
|
+
function readZonedClock(format, date) {
|
|
981
|
+
const parts = readZonedParts(format, date);
|
|
982
|
+
const value = (raw) => {
|
|
983
|
+
if (raw === void 0) return null;
|
|
984
|
+
const parsed = Number(raw);
|
|
985
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
986
|
+
};
|
|
987
|
+
const year = value(parts.year);
|
|
988
|
+
const month = value(parts.month);
|
|
989
|
+
const day = value(parts.day);
|
|
990
|
+
const hour = value(parts.hour);
|
|
991
|
+
const minute = value(parts.minute);
|
|
992
|
+
const second = value(parts.second);
|
|
993
|
+
if (year === null || month === null || day === null) return null;
|
|
994
|
+
if (hour === null || minute === null || second === null) return null;
|
|
995
|
+
return { year, month, day, hour, minute, second };
|
|
996
|
+
}
|
|
997
|
+
function formatIsoDateInTimeZone(iso, timeZone) {
|
|
998
|
+
if (!iso) return formatIsoDate(iso);
|
|
999
|
+
const d = new Date(iso);
|
|
1000
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
1001
|
+
try {
|
|
1002
|
+
const parts = readZonedParts(zonedClockFormat(timeZone), d);
|
|
1003
|
+
const yyyy = parts.year;
|
|
1004
|
+
const mm = parts.month;
|
|
1005
|
+
const dd = parts.day;
|
|
1006
|
+
if (!yyyy || !mm || !dd) return formatIsoDate(iso);
|
|
1007
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
1008
|
+
} catch {
|
|
1009
|
+
return formatIsoDate(iso);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
function shiftIsoCalendarDate(isoDate, days) {
|
|
1013
|
+
if (!Number.isFinite(days)) return isoDate;
|
|
1014
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(isoDate);
|
|
1015
|
+
if (!match?.[1] || !match[2] || !match[3]) return isoDate;
|
|
1016
|
+
const shifted = new Date(Date.UTC(
|
|
1017
|
+
Number(match[1]),
|
|
1018
|
+
Number(match[2]) - 1,
|
|
1019
|
+
Number(match[3]) + Math.trunc(days)
|
|
1020
|
+
));
|
|
1021
|
+
if (Number.isNaN(shifted.getTime())) return isoDate;
|
|
1022
|
+
const yyyy = shifted.getUTCFullYear();
|
|
1023
|
+
const mm = String(shifted.getUTCMonth() + 1).padStart(2, "0");
|
|
1024
|
+
const dd = String(shifted.getUTCDate()).padStart(2, "0");
|
|
1025
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
1026
|
+
}
|
|
1027
|
+
function isoDateDaysBeforeInTimeZone(iso, days, timeZone) {
|
|
1028
|
+
return shiftIsoCalendarDate(formatIsoDateInTimeZone(iso, timeZone), -days);
|
|
1029
|
+
}
|
|
1030
|
+
var HOURS_PER_DAY = 24;
|
|
1031
|
+
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
1032
|
+
function localHourExists(format, year, month, day, hour) {
|
|
1033
|
+
const asIfUtcMs = Date.UTC(year, month - 1, day, hour);
|
|
1034
|
+
for (const probeMs of [asIfUtcMs - ONE_DAY_MS, asIfUtcMs + ONE_DAY_MS]) {
|
|
1035
|
+
const probeClock = readZonedClock(format, new Date(probeMs));
|
|
1036
|
+
if (!probeClock) continue;
|
|
1037
|
+
const offsetMs = Date.UTC(
|
|
1038
|
+
probeClock.year,
|
|
1039
|
+
probeClock.month - 1,
|
|
1040
|
+
probeClock.day,
|
|
1041
|
+
probeClock.hour,
|
|
1042
|
+
probeClock.minute,
|
|
1043
|
+
probeClock.second
|
|
1044
|
+
) - probeMs;
|
|
1045
|
+
const candidate = readZonedClock(format, new Date(asIfUtcMs - offsetMs));
|
|
1046
|
+
if (!candidate) continue;
|
|
1047
|
+
if (candidate.year === year && candidate.month === month && candidate.day === day && candidate.hour === hour && candidate.minute === 0 && candidate.second === 0) return true;
|
|
1048
|
+
}
|
|
1049
|
+
return false;
|
|
1050
|
+
}
|
|
1051
|
+
function startOfDayHourInTimeZone(isoDate, timeZone) {
|
|
1052
|
+
const hourBoundary = (hour) => `${isoDate}T${String(hour).padStart(2, "0")}`;
|
|
1053
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(isoDate);
|
|
1054
|
+
if (!match?.[1] || !match[2] || !match[3]) return hourBoundary(0);
|
|
1055
|
+
const year = Number(match[1]);
|
|
1056
|
+
const month = Number(match[2]);
|
|
1057
|
+
const day = Number(match[3]);
|
|
1058
|
+
try {
|
|
1059
|
+
const format = zonedClockFormat(timeZone);
|
|
1060
|
+
for (let hour = 0; hour < HOURS_PER_DAY; hour += 1) {
|
|
1061
|
+
if (localHourExists(format, year, month, day, hour)) return hourBoundary(hour);
|
|
1062
|
+
}
|
|
1063
|
+
return hourBoundary(0);
|
|
1064
|
+
} catch {
|
|
1065
|
+
return hourBoundary(0);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
963
1068
|
function formatDateRange(start, end) {
|
|
964
1069
|
if (!start && !end) return "";
|
|
965
1070
|
if (start && end) return `${formatDate(start)} \u2192 ${formatDate(end)}`;
|
|
@@ -6518,6 +6623,8 @@ var researchRunQuerySchema = z37.object({
|
|
|
6518
6623
|
groundingSources: z37.array(groundingSourceSchema),
|
|
6519
6624
|
citedDomains: z37.array(z37.string()),
|
|
6520
6625
|
searchQueries: z37.array(z37.string()),
|
|
6626
|
+
namedCompetitors: z37.array(z37.string()).default([]),
|
|
6627
|
+
citedCompetitorDomains: z37.array(z37.string()).default([]),
|
|
6521
6628
|
answerMentioned: z37.boolean().nullable(),
|
|
6522
6629
|
citationState: citationStateSchema.nullable(),
|
|
6523
6630
|
error: z37.string().nullable(),
|
|
@@ -6742,6 +6849,91 @@ var adsSummaryDtoSchema = z38.object({
|
|
|
6742
6849
|
/** Campaign-level rollup totals over the window (levels are not summed across). */
|
|
6743
6850
|
totals: adsTotalsDtoSchema
|
|
6744
6851
|
});
|
|
6852
|
+
var adsDeliverySnapshotStatusSchema = z38.enum(["unavailable", "partial", "complete"]);
|
|
6853
|
+
var AdsDeliverySnapshotStatuses = adsDeliverySnapshotStatusSchema.enum;
|
|
6854
|
+
var adsDeliverySnapshotIssueSchema = z38.enum([
|
|
6855
|
+
"no_ads_connection",
|
|
6856
|
+
"connection_not_synced",
|
|
6857
|
+
"no_ads_sync",
|
|
6858
|
+
"entity_rows_missing_sync_run_id",
|
|
6859
|
+
"entity_rows_span_multiple_sync_runs",
|
|
6860
|
+
"source_sync_missing",
|
|
6861
|
+
"source_sync_not_ads_sync",
|
|
6862
|
+
"source_sync_not_completed"
|
|
6863
|
+
]);
|
|
6864
|
+
var AdsDeliverySnapshotIssues = adsDeliverySnapshotIssueSchema.enum;
|
|
6865
|
+
var adsHistoricalCampaignRollupStatusSchema = z38.enum(["unavailable", "reported"]);
|
|
6866
|
+
var AdsHistoricalCampaignRollupStatuses = adsHistoricalCampaignRollupStatusSchema.enum;
|
|
6867
|
+
var AdsDeliveryConfigurationBases = {
|
|
6868
|
+
storedSnapshot: "stored_ads_snapshot"
|
|
6869
|
+
};
|
|
6870
|
+
var adsActivityAssessmentStateSchema = z38.enum([
|
|
6871
|
+
"unavailable",
|
|
6872
|
+
"partial_snapshot",
|
|
6873
|
+
"metrics_unavailable",
|
|
6874
|
+
"observed_activity",
|
|
6875
|
+
"no_observed_activity"
|
|
6876
|
+
]);
|
|
6877
|
+
var AdsActivityAssessmentStates = adsActivityAssessmentStateSchema.enum;
|
|
6878
|
+
var adsDeliveryDiagnosticsAdSchema = z38.object({
|
|
6879
|
+
id: z38.string(),
|
|
6880
|
+
name: z38.string(),
|
|
6881
|
+
status: z38.string(),
|
|
6882
|
+
reviewStatus: z38.string().nullable()
|
|
6883
|
+
});
|
|
6884
|
+
var adsDeliveryDiagnosticsAdGroupSchema = z38.object({
|
|
6885
|
+
id: z38.string(),
|
|
6886
|
+
name: z38.string(),
|
|
6887
|
+
status: z38.string(),
|
|
6888
|
+
billingEventType: z38.union([adsAdGroupBillingEventTypeSchema, z38.null()]),
|
|
6889
|
+
maxBidMicros: z38.number().int().nullable(),
|
|
6890
|
+
contextHints: z38.array(z38.string()),
|
|
6891
|
+
ads: z38.array(adsDeliveryDiagnosticsAdSchema)
|
|
6892
|
+
});
|
|
6893
|
+
var adsDeliveryDiagnosticsCampaignSchema = z38.object({
|
|
6894
|
+
id: z38.string(),
|
|
6895
|
+
name: z38.string(),
|
|
6896
|
+
status: z38.string(),
|
|
6897
|
+
biddingType: z38.union([adsCampaignBiddingTypeSchema, z38.null()]),
|
|
6898
|
+
dailySpendLimitMicros: z38.number().int().nullable(),
|
|
6899
|
+
lifetimeSpendLimitMicros: z38.number().int().nullable(),
|
|
6900
|
+
conversionEventSettingIds: z38.array(z38.string()),
|
|
6901
|
+
adGroups: z38.array(adsDeliveryDiagnosticsAdGroupSchema)
|
|
6902
|
+
});
|
|
6903
|
+
var adsDeliveryDiagnosticsDtoSchema = z38.object({
|
|
6904
|
+
snapshot: z38.object({
|
|
6905
|
+
status: adsDeliverySnapshotStatusSchema,
|
|
6906
|
+
// A union keeps the OpenAPI form explicit enough for the generated SDK to
|
|
6907
|
+
// retain the complete-snapshot `null` value (rather than narrowing it to
|
|
6908
|
+
// the issue enum alone).
|
|
6909
|
+
issue: z38.union([adsDeliverySnapshotIssueSchema, z38.null()]),
|
|
6910
|
+
lastSyncedAt: z38.string().nullable(),
|
|
6911
|
+
campaignCount: z38.number().int().nonnegative(),
|
|
6912
|
+
adGroupCount: z38.number().int().nonnegative(),
|
|
6913
|
+
adCount: z38.number().int().nonnegative(),
|
|
6914
|
+
sourceSync: z38.object({
|
|
6915
|
+
runId: z38.string(),
|
|
6916
|
+
status: runStatusSchema
|
|
6917
|
+
}).nullable()
|
|
6918
|
+
}),
|
|
6919
|
+
historicalCampaignRollups: z38.object({
|
|
6920
|
+
status: adsHistoricalCampaignRollupStatusSchema,
|
|
6921
|
+
window: z38.object({ from: z38.string().nullable(), to: z38.string().nullable() }),
|
|
6922
|
+
totals: adsTotalsDtoSchema.nullable()
|
|
6923
|
+
}),
|
|
6924
|
+
storedConfiguration: z38.object({
|
|
6925
|
+
basis: z38.literal(AdsDeliveryConfigurationBases.storedSnapshot),
|
|
6926
|
+
connection: z38.object({
|
|
6927
|
+
status: z38.string().nullable(),
|
|
6928
|
+
reviewStatus: z38.string().nullable(),
|
|
6929
|
+
integrityReviewStatus: z38.string().nullable(),
|
|
6930
|
+
integrityDecision: z38.string().nullable(),
|
|
6931
|
+
conversionTrackingConfigured: z38.boolean()
|
|
6932
|
+
}).nullable(),
|
|
6933
|
+
campaigns: z38.array(adsDeliveryDiagnosticsCampaignSchema)
|
|
6934
|
+
}),
|
|
6935
|
+
assessment: z38.object({ state: adsActivityAssessmentStateSchema })
|
|
6936
|
+
});
|
|
6745
6937
|
var adsOperationKeySchema = z38.string().min(8).max(128).regex(/^[\w.:-]+$/, "operationKey may contain letters, numbers, dot, underscore, colon, and hyphen");
|
|
6746
6938
|
var adsEntityIdSchema = z38.string().min(1).max(200);
|
|
6747
6939
|
var adsNameSchema = z38.string().min(3).max(1e3).refine((value) => value.trim().length > 0);
|
|
@@ -7248,6 +7440,122 @@ var adsOperationReconcileResponseSchema = z38.object({
|
|
|
7248
7440
|
operation: adsOperationDtoSchema,
|
|
7249
7441
|
resolved: z38.boolean()
|
|
7250
7442
|
});
|
|
7443
|
+
var adsLiveDeliveryQuerySchema = z38.object({
|
|
7444
|
+
campaignId: z38.string().min(1).max(200).optional(),
|
|
7445
|
+
lookbackDays: z38.coerce.number().int().min(1).max(30).default(7)
|
|
7446
|
+
});
|
|
7447
|
+
var adsLiveEntityTypeSchema = z38.enum(["campaign", "ad_group", "ad"]);
|
|
7448
|
+
var AdsLiveEntityTypes = adsLiveEntityTypeSchema.enum;
|
|
7449
|
+
var adsLivePresenceSchema = z38.enum(["both", "live-only", "stored-only"]);
|
|
7450
|
+
var AdsLivePresences = adsLivePresenceSchema.enum;
|
|
7451
|
+
var adsLiveDeliveryBasisSchema = z38.literal("live-provider-read");
|
|
7452
|
+
var AdsLiveDeliveryBases = { liveProviderRead: "live-provider-read" };
|
|
7453
|
+
var adsLiveMetricRowSchema = z38.object({
|
|
7454
|
+
date: z38.string().nullable(),
|
|
7455
|
+
startTime: z38.number().nullable(),
|
|
7456
|
+
endTime: z38.number().nullable(),
|
|
7457
|
+
impressions: z38.number().nullable(),
|
|
7458
|
+
clicks: z38.number().nullable(),
|
|
7459
|
+
spend: z38.number().nullable(),
|
|
7460
|
+
conversions: z38.number().nullable(),
|
|
7461
|
+
ctr: z38.number().nullable(),
|
|
7462
|
+
cpc: z38.number().nullable(),
|
|
7463
|
+
cpm: z38.number().nullable()
|
|
7464
|
+
});
|
|
7465
|
+
var adsLiveMetricValuesSchema = z38.object({
|
|
7466
|
+
impressions: z38.number().int(),
|
|
7467
|
+
clicks: z38.number().int(),
|
|
7468
|
+
spendMicros: z38.number().int(),
|
|
7469
|
+
conversions: z38.number().int()
|
|
7470
|
+
});
|
|
7471
|
+
var adsLiveMetricDeltaSchema = z38.object({
|
|
7472
|
+
date: z38.string(),
|
|
7473
|
+
live: adsLiveMetricValuesSchema.nullable(),
|
|
7474
|
+
stored: adsLiveMetricValuesSchema.nullable(),
|
|
7475
|
+
drifted: z38.boolean()
|
|
7476
|
+
});
|
|
7477
|
+
var adsLiveFieldDeltaSchema = z38.object({
|
|
7478
|
+
field: z38.string(),
|
|
7479
|
+
live: z38.string().nullable(),
|
|
7480
|
+
stored: z38.string().nullable()
|
|
7481
|
+
});
|
|
7482
|
+
var adsLiveEntityStateSchema = z38.object({
|
|
7483
|
+
name: z38.string().nullable(),
|
|
7484
|
+
status: z38.string(),
|
|
7485
|
+
reviewStatus: z38.string().nullable(),
|
|
7486
|
+
mode: z38.string().nullable(),
|
|
7487
|
+
updatedAt: z38.number().nullable()
|
|
7488
|
+
});
|
|
7489
|
+
var adsStoredEntityStateSchema = z38.object({
|
|
7490
|
+
name: z38.string(),
|
|
7491
|
+
status: z38.string(),
|
|
7492
|
+
reviewStatus: z38.string().nullable(),
|
|
7493
|
+
upstreamUpdatedAt: z38.number().nullable(),
|
|
7494
|
+
syncedAt: z38.string()
|
|
7495
|
+
});
|
|
7496
|
+
var adsLiveEntityComparisonSchema = z38.object({
|
|
7497
|
+
entityType: adsLiveEntityTypeSchema,
|
|
7498
|
+
id: z38.string(),
|
|
7499
|
+
parentId: z38.string().nullable(),
|
|
7500
|
+
presence: adsLivePresenceSchema,
|
|
7501
|
+
live: adsLiveEntityStateSchema.nullable(),
|
|
7502
|
+
stored: adsStoredEntityStateSchema.nullable(),
|
|
7503
|
+
fieldDeltas: z38.array(adsLiveFieldDeltaSchema),
|
|
7504
|
+
/** Provider rows, unaggregated. Null for ads (no per-ad insights surface). */
|
|
7505
|
+
liveMetrics: z38.array(adsLiveMetricRowSchema).nullable(),
|
|
7506
|
+
metricDeltas: z38.array(adsLiveMetricDeltaSchema).nullable(),
|
|
7507
|
+
drifted: z38.boolean()
|
|
7508
|
+
});
|
|
7509
|
+
var adsLiveReadFailureSchema = z38.object({
|
|
7510
|
+
surface: z38.string(),
|
|
7511
|
+
entityId: z38.string().nullable(),
|
|
7512
|
+
upstreamStatus: z38.number().int().nullable()
|
|
7513
|
+
});
|
|
7514
|
+
var adsLiveDeliveryDtoSchema = z38.object({
|
|
7515
|
+
basis: adsLiveDeliveryBasisSchema,
|
|
7516
|
+
/** Instant the live read was issued; the metrics window is measured back from it. */
|
|
7517
|
+
fetchedAt: z38.string(),
|
|
7518
|
+
adAccountId: z38.string(),
|
|
7519
|
+
storedSnapshotSyncedAt: z38.string().nullable(),
|
|
7520
|
+
metricsWindow: z38.object({ lookbackDays: z38.number().int().positive() }),
|
|
7521
|
+
/**
|
|
7522
|
+
* Two different units live here, and confusing them understates the cost of
|
|
7523
|
+
* this endpoint by two orders of magnitude.
|
|
7524
|
+
*
|
|
7525
|
+
* A READER CALL is one logical list or insight read. Every list/insight
|
|
7526
|
+
* reader call is an auto-paginating walk, so one reader call can issue up to
|
|
7527
|
+
* `maxPagesPerReaderCall` upstream HTTP requests before the client gives up.
|
|
7528
|
+
* `maxUpstreamHttpRequests` is the honest worst-case ceiling in HTTP
|
|
7529
|
+
* requests (`maxReaderCalls * maxPagesPerReaderCall`, about 4000 at the
|
|
7530
|
+
* shipped defaults, not 40).
|
|
7531
|
+
*
|
|
7532
|
+
* `readerCalls` is an observed count of reader calls. There is deliberately
|
|
7533
|
+
* no observed HTTP-request count: the pagination happens inside the provider
|
|
7534
|
+
* client, below the injected reader seam, so the route cannot see it.
|
|
7535
|
+
*/
|
|
7536
|
+
bounds: z38.object({
|
|
7537
|
+
maxCampaigns: z38.number().int().positive(),
|
|
7538
|
+
maxAdGroupsPerCampaign: z38.number().int().positive(),
|
|
7539
|
+
maxAdsPerAdGroup: z38.number().int().positive(),
|
|
7540
|
+
/** Budget in logical reader calls, NOT in upstream HTTP requests. */
|
|
7541
|
+
maxReaderCalls: z38.number().int().positive(),
|
|
7542
|
+
/** Reader calls this read actually issued. Observed, not a bound. */
|
|
7543
|
+
readerCalls: z38.number().int().nonnegative(),
|
|
7544
|
+
/** Pages one paginated reader call may fetch before the client gives up. */
|
|
7545
|
+
maxPagesPerReaderCall: z38.number().int().positive(),
|
|
7546
|
+
/** Worst-case upstream HTTP requests. A documented bound, not an observation. */
|
|
7547
|
+
maxUpstreamHttpRequests: z38.number().int().positive(),
|
|
7548
|
+
truncated: z38.boolean()
|
|
7549
|
+
}),
|
|
7550
|
+
entities: z38.array(adsLiveEntityComparisonSchema),
|
|
7551
|
+
drift: z38.object({
|
|
7552
|
+
entitiesCompared: z38.number().int().nonnegative(),
|
|
7553
|
+
driftedEntities: z38.number().int().nonnegative(),
|
|
7554
|
+
statusDrifted: z38.number().int().nonnegative(),
|
|
7555
|
+
metricsDrifted: z38.number().int().nonnegative()
|
|
7556
|
+
}),
|
|
7557
|
+
errors: z38.array(adsLiveReadFailureSchema)
|
|
7558
|
+
});
|
|
7251
7559
|
function adsCtr(clicks, impressions) {
|
|
7252
7560
|
return impressions > 0 ? clicks / impressions : null;
|
|
7253
7561
|
}
|
|
@@ -7498,6 +7806,9 @@ export {
|
|
|
7498
7806
|
formatNumber,
|
|
7499
7807
|
formatDate,
|
|
7500
7808
|
formatIsoDate,
|
|
7809
|
+
formatIsoDateInTimeZone,
|
|
7810
|
+
isoDateDaysBeforeInTimeZone,
|
|
7811
|
+
startOfDayHourInTimeZone,
|
|
7501
7812
|
formatDateRange,
|
|
7502
7813
|
parseInclusiveEndMs,
|
|
7503
7814
|
deltaPercent,
|
|
@@ -7776,8 +8087,15 @@ export {
|
|
|
7776
8087
|
AdsAdGroupBillingEventTypes,
|
|
7777
8088
|
adsCampaignListResponseSchema,
|
|
7778
8089
|
adsInsightLevelSchema,
|
|
8090
|
+
AdsInsightLevels,
|
|
7779
8091
|
adsInsightsResponseSchema,
|
|
7780
8092
|
adsSummaryDtoSchema,
|
|
8093
|
+
AdsDeliverySnapshotStatuses,
|
|
8094
|
+
AdsDeliverySnapshotIssues,
|
|
8095
|
+
AdsHistoricalCampaignRollupStatuses,
|
|
8096
|
+
AdsDeliveryConfigurationBases,
|
|
8097
|
+
AdsActivityAssessmentStates,
|
|
8098
|
+
adsDeliveryDiagnosticsDtoSchema,
|
|
7781
8099
|
AdsOperationKinds,
|
|
7782
8100
|
AdsOperationStates,
|
|
7783
8101
|
AdsReconcileStrategies,
|
|
@@ -7810,6 +8128,11 @@ export {
|
|
|
7810
8128
|
adsUnresolvedOperationListResponseSchema,
|
|
7811
8129
|
adsOperationReconcileRequestSchema,
|
|
7812
8130
|
adsOperationReconcileResponseSchema,
|
|
8131
|
+
adsLiveDeliveryQuerySchema,
|
|
8132
|
+
AdsLiveEntityTypes,
|
|
8133
|
+
AdsLivePresences,
|
|
8134
|
+
AdsLiveDeliveryBases,
|
|
8135
|
+
adsLiveDeliveryDtoSchema,
|
|
7813
8136
|
adsCtr,
|
|
7814
8137
|
adsCpcMicros,
|
|
7815
8138
|
dollarsToMicros,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadConfig,
|
|
11
11
|
loadConfigRaw,
|
|
12
12
|
saveConfigPatch
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZUQPHGEN.js";
|
|
14
14
|
import {
|
|
15
15
|
CC_CACHE_DIR,
|
|
16
16
|
DUCKDB_SPEC,
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
classifyAiUserFetch,
|
|
41
41
|
classifyCrawler,
|
|
42
42
|
competitors,
|
|
43
|
+
computeCitedCompetitorDomains,
|
|
43
44
|
computeCompetitorOverlap,
|
|
44
45
|
countAttributes,
|
|
45
46
|
countPopulatedGroups,
|
|
@@ -118,7 +119,7 @@ import {
|
|
|
118
119
|
siteAuditPages,
|
|
119
120
|
siteAuditSnapshots,
|
|
120
121
|
usageCounters
|
|
121
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-LIXWDIDR.js";
|
|
122
123
|
import {
|
|
123
124
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
124
125
|
AGENT_PROVIDER_IDS,
|
|
@@ -188,10 +189,11 @@ import {
|
|
|
188
189
|
serializeRunError,
|
|
189
190
|
skillsClientSchema,
|
|
190
191
|
splitList,
|
|
192
|
+
startOfDayHourInTimeZone,
|
|
191
193
|
validationError,
|
|
192
194
|
winnabilityClassLabel,
|
|
193
195
|
withRetry
|
|
194
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-PC7AYXND.js";
|
|
195
197
|
|
|
196
198
|
// src/telemetry.ts
|
|
197
199
|
import crypto from "crypto";
|
|
@@ -4877,14 +4879,22 @@ function accountHour(date, timezone) {
|
|
|
4877
4879
|
};
|
|
4878
4880
|
return `${value("year")}-${value("month")}-${value("day")}T${value("hour")}`;
|
|
4879
4881
|
}
|
|
4880
|
-
function trailingAdsInsightHourRange(now, timezone) {
|
|
4882
|
+
function trailingAdsInsightHourRange(now, timezone, lookbackMs = INSIGHTS_LOOKBACK_MS) {
|
|
4881
4883
|
return {
|
|
4882
4884
|
type: "hour_range",
|
|
4883
|
-
since: accountHour(new Date(now.getTime() -
|
|
4885
|
+
since: accountHour(new Date(now.getTime() - lookbackMs), timezone),
|
|
4884
4886
|
until: accountHour(now, timezone),
|
|
4885
4887
|
timezone
|
|
4886
4888
|
};
|
|
4887
4889
|
}
|
|
4890
|
+
function liveAdsInsightHourRange(request) {
|
|
4891
|
+
return {
|
|
4892
|
+
type: "hour_range",
|
|
4893
|
+
since: startOfDayHourInTimeZone(request.startDate, request.timezone),
|
|
4894
|
+
until: accountHour(new Date(request.fetchedAtMs), request.timezone),
|
|
4895
|
+
timezone: request.timezone
|
|
4896
|
+
};
|
|
4897
|
+
}
|
|
4888
4898
|
function toInsightUpserts(level, entityId, rows) {
|
|
4889
4899
|
const upserts = [];
|
|
4890
4900
|
for (const row of rows) {
|
|
@@ -7000,7 +7010,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
7000
7010
|
return result;
|
|
7001
7011
|
}
|
|
7002
7012
|
async function backfillInsightsCommand(project, opts) {
|
|
7003
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
7013
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-4XOFUN5E.js");
|
|
7004
7014
|
const config = loadConfig();
|
|
7005
7015
|
const db = createClient(config.database);
|
|
7006
7016
|
migrate(db);
|
|
@@ -9113,6 +9123,8 @@ var AERO_ADS_OPERATOR_MCP_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
9113
9123
|
CanonryMcpToolNames.canonry_ads_campaigns,
|
|
9114
9124
|
CanonryMcpToolNames.canonry_ads_insights,
|
|
9115
9125
|
CanonryMcpToolNames.canonry_ads_summary,
|
|
9126
|
+
CanonryMcpToolNames.canonry_ads_delivery_diagnostics,
|
|
9127
|
+
CanonryMcpToolNames.canonry_ads_live_delivery,
|
|
9116
9128
|
CanonryMcpToolNames.canonry_ads_operations_unresolved,
|
|
9117
9129
|
CanonryMcpToolNames.canonry_ads_operation_get,
|
|
9118
9130
|
CanonryMcpToolNames.canonry_ads_operation_reconcile,
|
|
@@ -9234,7 +9246,7 @@ function buildAdsOperatorContextTool(ctx) {
|
|
|
9234
9246
|
return {
|
|
9235
9247
|
name: AERO_ADS_OPERATOR_CONTEXT_TOOL_NAME,
|
|
9236
9248
|
label: "Get ads operator context",
|
|
9237
|
-
description: "One-call Aero context pack for ads operations. Reads the project overview, ads connection, paid summary, bounded campaign snapshots, recent paid rollups, ads doctor checks, and recent Aero memory. Use before diagnosing ChatGPT ads performance or planning the next operator action.",
|
|
9249
|
+
description: "One-call Aero context pack for ads operations. Reads the project overview, stored ads delivery diagnostics, ads connection, paid summary, bounded campaign snapshots, recent paid rollups, ads doctor checks, and recent Aero memory. Use before diagnosing ChatGPT ads performance or planning the next operator action.",
|
|
9238
9250
|
parameters: Type3.Object({
|
|
9239
9251
|
windowDays: Type3.Optional(Type3.Integer({
|
|
9240
9252
|
minimum: 1,
|
|
@@ -9262,6 +9274,7 @@ function buildAdsOperatorContextTool(ctx) {
|
|
|
9262
9274
|
const [
|
|
9263
9275
|
overview,
|
|
9264
9276
|
adsStatus,
|
|
9277
|
+
deliveryDiagnostics,
|
|
9265
9278
|
adsSummary,
|
|
9266
9279
|
campaigns,
|
|
9267
9280
|
campaignInsights,
|
|
@@ -9271,6 +9284,7 @@ function buildAdsOperatorContextTool(ctx) {
|
|
|
9271
9284
|
] = await Promise.all([
|
|
9272
9285
|
readSection(() => ctx.client.getProjectOverview(ctx.projectName)),
|
|
9273
9286
|
readSection(() => ctx.client.getAdsStatus(ctx.projectName)),
|
|
9287
|
+
readSection(() => ctx.client.getAdsDeliveryDiagnostics(ctx.projectName)),
|
|
9274
9288
|
readSection(() => ctx.client.getAdsSummary(ctx.projectName)),
|
|
9275
9289
|
readSection(async () => compactCampaigns(await ctx.client.getAdsCampaigns(ctx.projectName), campaignLimit)),
|
|
9276
9290
|
readSection(
|
|
@@ -9298,6 +9312,7 @@ function buildAdsOperatorContextTool(ctx) {
|
|
|
9298
9312
|
overview: overview.status === "ok" && overview.data ? { status: "ok", data: compactOverview(overview.data) } : overview,
|
|
9299
9313
|
ads: {
|
|
9300
9314
|
status: adsStatus,
|
|
9315
|
+
deliveryDiagnostics,
|
|
9301
9316
|
summary: adsSummary,
|
|
9302
9317
|
campaigns,
|
|
9303
9318
|
insights: {
|
|
@@ -11588,6 +11603,14 @@ async function executeResearchRun(db, registry, runId, projectId) {
|
|
|
11588
11603
|
return provider.adapter.executeTrackedQuery({ query: row.queryText, canonicalDomains: domains, competitorDomains, ...run.location ? { location: run.location } : {} }, config);
|
|
11589
11604
|
});
|
|
11590
11605
|
const normalized = provider.adapter.normalizeResult(raw);
|
|
11606
|
+
const namedCompetitors = extractRecommendedCompetitors(
|
|
11607
|
+
normalized.answerText,
|
|
11608
|
+
domains,
|
|
11609
|
+
normalized.citedDomains,
|
|
11610
|
+
competitorDomains,
|
|
11611
|
+
brands
|
|
11612
|
+
);
|
|
11613
|
+
const citedCompetitorDomains = computeCitedCompetitorDomains(normalized.citedDomains, competitorDomains);
|
|
11591
11614
|
const completed = db.update(researchRunQueries).set({
|
|
11592
11615
|
status: ResearchQueryStatuses.completed,
|
|
11593
11616
|
servedModel: raw.servedModel ?? null,
|
|
@@ -11595,6 +11618,8 @@ async function executeResearchRun(db, registry, runId, projectId) {
|
|
|
11595
11618
|
groundingSources: normalized.groundingSources,
|
|
11596
11619
|
citedDomains: normalized.citedDomains,
|
|
11597
11620
|
searchQueries: normalized.searchQueries,
|
|
11621
|
+
namedCompetitors,
|
|
11622
|
+
citedCompetitorDomains,
|
|
11598
11623
|
answerMentioned: determineAnswerMentioned(normalized.answerText, brands, domains),
|
|
11599
11624
|
citationState: determineCitationState(normalized, domains),
|
|
11600
11625
|
rawResponse: raw.rawResponse,
|
|
@@ -12200,6 +12225,42 @@ async function createServer(opts) {
|
|
|
12200
12225
|
activateAd: async (apiKey, id) => adsAdEntityResult(await activateAd(apiKey, id)),
|
|
12201
12226
|
pauseAd: async (apiKey, id) => adsAdEntityResult(await pauseAd(apiKey, id))
|
|
12202
12227
|
};
|
|
12228
|
+
const adsLiveEntity = (entity, extra) => ({
|
|
12229
|
+
id: entity.id,
|
|
12230
|
+
name: entity.name,
|
|
12231
|
+
status: entity.status,
|
|
12232
|
+
reviewStatus: extra?.reviewStatus ?? null,
|
|
12233
|
+
mode: extra?.mode ?? null,
|
|
12234
|
+
updatedAt: entity.updated_at
|
|
12235
|
+
});
|
|
12236
|
+
const adsLiveMetricRow = (row) => ({
|
|
12237
|
+
date: row.readable_time ?? null,
|
|
12238
|
+
startTime: row.start_time ?? null,
|
|
12239
|
+
endTime: row.end_time ?? null,
|
|
12240
|
+
impressions: row.impressions ?? null,
|
|
12241
|
+
clicks: row.clicks ?? null,
|
|
12242
|
+
// Provider units: the insights API returns decimal currency for spend.
|
|
12243
|
+
spend: row.spend ?? null,
|
|
12244
|
+
conversions: row.conversions ?? null,
|
|
12245
|
+
ctr: row.ctr ?? null,
|
|
12246
|
+
cpc: row.cpc ?? null,
|
|
12247
|
+
cpm: row.cpm ?? null
|
|
12248
|
+
});
|
|
12249
|
+
const adsLiveDeliveryReader = {
|
|
12250
|
+
listCampaigns: async (apiKey) => (await listCampaigns(apiKey)).map((campaign) => adsLiveEntity(campaign, { mode: campaign.mode })),
|
|
12251
|
+
listAdGroups: async (apiKey, campaignId) => (await listAdGroups(apiKey, campaignId)).map((adGroup) => adsLiveEntity(adGroup)),
|
|
12252
|
+
listAds: async (apiKey, adGroupId) => (await listAds(apiKey, adGroupId)).map(
|
|
12253
|
+
(ad) => adsLiveEntity(ad, { reviewStatus: ad.review_status ?? ad.review?.status ?? null })
|
|
12254
|
+
),
|
|
12255
|
+
campaignInsights: async (apiKey, campaignId, request) => (await getCampaignInsights(apiKey, campaignId, {
|
|
12256
|
+
fields: CAMPAIGN_INSIGHT_FIELDS,
|
|
12257
|
+
timeRanges: [liveAdsInsightHourRange(request)]
|
|
12258
|
+
})).map(adsLiveMetricRow),
|
|
12259
|
+
adGroupInsights: async (apiKey, adGroupId, request) => (await getAdGroupInsights(apiKey, adGroupId, {
|
|
12260
|
+
fields: AD_GROUP_INSIGHT_FIELDS,
|
|
12261
|
+
timeRanges: [liveAdsInsightHourRange(request)]
|
|
12262
|
+
})).map(adsLiveMetricRow)
|
|
12263
|
+
};
|
|
12203
12264
|
const scheduler = new Scheduler(opts.db, {
|
|
12204
12265
|
onRunCreated: (runId, projectId, providers2, location) => {
|
|
12205
12266
|
jobRunner.executeRun(runId, projectId, providers2, location).catch((err) => {
|
|
@@ -12799,6 +12860,11 @@ async function createServer(opts) {
|
|
|
12799
12860
|
adsCredentialStore,
|
|
12800
12861
|
verifyAdsAccount,
|
|
12801
12862
|
adsReader,
|
|
12863
|
+
adsLiveDeliveryReader,
|
|
12864
|
+
// Reporting only: lets the route state the true upstream HTTP ceiling
|
|
12865
|
+
// (reader-call budget x pages per reader call) instead of implying that a
|
|
12866
|
+
// reader call is one request.
|
|
12867
|
+
adsLiveDeliveryMaxPagesPerReaderCall: OPENAI_ADS_MAX_PAGES,
|
|
12802
12868
|
adsOperator,
|
|
12803
12869
|
onAdsSyncRequested: (runId, projectId) => {
|
|
12804
12870
|
runAdsSync(runId, projectId);
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
trafficConnectWordpressRequestSchema,
|
|
43
43
|
trafficEventKindSchema,
|
|
44
44
|
trafficSeriesGranularitySchema
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-PC7AYXND.js";
|
|
46
46
|
|
|
47
47
|
// src/config.ts
|
|
48
48
|
import fs from "fs";
|
|
@@ -2727,6 +2727,30 @@ var getApiV1ProjectsByNameAdsSummary = (options) => {
|
|
|
2727
2727
|
...options
|
|
2728
2728
|
});
|
|
2729
2729
|
};
|
|
2730
|
+
var getApiV1ProjectsByNameAdsDeliveryDiagnostics = (options) => {
|
|
2731
|
+
return (options.client ?? client).get({
|
|
2732
|
+
security: [
|
|
2733
|
+
{
|
|
2734
|
+
scheme: "bearer",
|
|
2735
|
+
type: "http"
|
|
2736
|
+
}
|
|
2737
|
+
],
|
|
2738
|
+
url: "/api/v1/projects/{name}/ads/delivery-diagnostics",
|
|
2739
|
+
...options
|
|
2740
|
+
});
|
|
2741
|
+
};
|
|
2742
|
+
var getApiV1ProjectsByNameAdsLiveDelivery = (options) => {
|
|
2743
|
+
return (options.client ?? client).get({
|
|
2744
|
+
security: [
|
|
2745
|
+
{
|
|
2746
|
+
scheme: "bearer",
|
|
2747
|
+
type: "http"
|
|
2748
|
+
}
|
|
2749
|
+
],
|
|
2750
|
+
url: "/api/v1/projects/{name}/ads/live-delivery",
|
|
2751
|
+
...options
|
|
2752
|
+
});
|
|
2753
|
+
};
|
|
2730
2754
|
var postApiV1ProjectsByNameBingConnect = (options) => {
|
|
2731
2755
|
return (options.client ?? client).post({
|
|
2732
2756
|
security: [
|
|
@@ -4854,6 +4878,23 @@ var ApiClient = class {
|
|
|
4854
4878
|
() => getApiV1ProjectsByNameAdsSummary({ client: this.heyClient, path: { name: project } })
|
|
4855
4879
|
);
|
|
4856
4880
|
}
|
|
4881
|
+
async getAdsDeliveryDiagnostics(project) {
|
|
4882
|
+
return this.invoke(
|
|
4883
|
+
() => getApiV1ProjectsByNameAdsDeliveryDiagnostics({ client: this.heyClient, path: { name: project } })
|
|
4884
|
+
);
|
|
4885
|
+
}
|
|
4886
|
+
async getAdsLiveDelivery(project, opts) {
|
|
4887
|
+
return this.invoke(
|
|
4888
|
+
() => getApiV1ProjectsByNameAdsLiveDelivery({
|
|
4889
|
+
client: this.heyClient,
|
|
4890
|
+
path: { name: project },
|
|
4891
|
+
query: {
|
|
4892
|
+
...opts?.campaignId === void 0 ? {} : { campaignId: opts.campaignId },
|
|
4893
|
+
...opts?.lookbackDays === void 0 ? {} : { lookbackDays: opts.lookbackDays }
|
|
4894
|
+
}
|
|
4895
|
+
})
|
|
4896
|
+
);
|
|
4897
|
+
}
|
|
4857
4898
|
async getAdsOperation(project, operationKey) {
|
|
4858
4899
|
return this.invoke(
|
|
4859
4900
|
() => getApiV1ProjectsByNameAdsOperationsByOperationKey({
|
|
@@ -6152,6 +6193,11 @@ var adsInsightsInputSchema = z2.object({
|
|
|
6152
6193
|
var adsGeoSearchInputSchema = adsGeoSearchQuerySchema.extend({
|
|
6153
6194
|
project: projectNameSchema
|
|
6154
6195
|
});
|
|
6196
|
+
var adsLiveDeliveryInputSchema = z2.object({
|
|
6197
|
+
project: projectNameSchema,
|
|
6198
|
+
campaignId: z2.string().min(1).max(200).optional(),
|
|
6199
|
+
lookbackDays: z2.number().int().min(1).max(30).optional()
|
|
6200
|
+
});
|
|
6155
6201
|
var adsOperationInputSchema = z2.object({
|
|
6156
6202
|
project: projectNameSchema,
|
|
6157
6203
|
operationKey: z2.string().min(8).max(128)
|
|
@@ -7693,7 +7739,7 @@ var canonryMcpTools = [
|
|
|
7693
7739
|
defineTool({
|
|
7694
7740
|
name: "canonry_research_run_get",
|
|
7695
7741
|
title: "Get research query run",
|
|
7696
|
-
description: "Get
|
|
7742
|
+
description: "Get saved per-query answers, source links, cited domains, answer-text named competitors, cited competitor domains, and independent mention/citation results for one research run. It is read-only and does not promote or track any query.",
|
|
7697
7743
|
access: "read",
|
|
7698
7744
|
tier: "discovery",
|
|
7699
7745
|
inputSchema: researchRunIdInputSchema,
|
|
@@ -7912,6 +7958,31 @@ var canonryMcpTools = [
|
|
|
7912
7958
|
openApiOperations: ["GET /api/v1/projects/{name}/ads/summary"],
|
|
7913
7959
|
handler: (client2, input) => client2.getAdsSummary(input.project)
|
|
7914
7960
|
}),
|
|
7961
|
+
defineTool({
|
|
7962
|
+
name: "canonry_ads_delivery_diagnostics",
|
|
7963
|
+
title: "Stored ads delivery diagnostics",
|
|
7964
|
+
description: "Read stored ads snapshot provenance, account/campaign/ad-group/ad configuration facts, and historical campaign activity in one call. This is not a live OpenAI eligibility or serving verdict.",
|
|
7965
|
+
access: "read",
|
|
7966
|
+
tier: "ads",
|
|
7967
|
+
inputSchema: projectInputSchema,
|
|
7968
|
+
annotations: readAnnotations(),
|
|
7969
|
+
openApiOperations: ["GET /api/v1/projects/{name}/ads/delivery-diagnostics"],
|
|
7970
|
+
handler: (client2, input) => client2.getAdsDeliveryDiagnostics(input.project)
|
|
7971
|
+
}),
|
|
7972
|
+
defineTool({
|
|
7973
|
+
name: "canonry_ads_live_delivery",
|
|
7974
|
+
title: "Live ads read with stored-snapshot delta",
|
|
7975
|
+
description: "Call the OpenAI Ads API right now and return the provider's current status and metrics per campaign / ad group / ad, unaggregated, alongside the stored snapshot values and an explicit per-entity delta. Use this when stored data is suspected of being stale or contradicted by the advertiser UI. Read-only: it mutates nothing and does not wait for a sync. The walk is bounded and one project may issue at most one live read per minute, so prefer canonry_ads_delivery_diagnostics for routine checks.",
|
|
7976
|
+
access: "read",
|
|
7977
|
+
tier: "ads",
|
|
7978
|
+
inputSchema: adsLiveDeliveryInputSchema,
|
|
7979
|
+
annotations: readAnnotations(),
|
|
7980
|
+
openApiOperations: ["GET /api/v1/projects/{name}/ads/live-delivery"],
|
|
7981
|
+
handler: (client2, input) => client2.getAdsLiveDelivery(input.project, {
|
|
7982
|
+
campaignId: input.campaignId,
|
|
7983
|
+
lookbackDays: input.lookbackDays
|
|
7984
|
+
})
|
|
7985
|
+
}),
|
|
7915
7986
|
defineTool({
|
|
7916
7987
|
name: "canonry_ads_operations_unresolved",
|
|
7917
7988
|
title: "List unresolved ads mutation receipts",
|