@relvo/mcp 0.1.2 → 0.1.4
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 +47 -154
- package/bin/relvo-mcp.mjs +1 -1
- package/dist/client/agent-run.js +681 -0
- package/dist/client/browser.js +652 -0
- package/dist/client/evm-wallet.js +214 -0
- package/dist/client/index.js +3 -360
- package/dist/client/local-input.js +18 -11
- package/dist/client/local-profile.js +22 -110
- package/dist/client/local-setup.js +0 -1
- package/dist/client/tool-name-hints.js +48 -0
- package/dist/client/wallet-access.js +207 -0
- package/dist/mcp/agent-server.js +237 -0
- package/dist/mcp/context.js +3 -2
- package/dist/mcp/host-schema.js +47 -0
- package/dist/mcp/instructions.js +12 -2
- package/dist/mcp/local-upload.js +12 -4
- package/dist/mcp/operations.js +30 -0
- package/dist/mcp/runtime.js +25 -5
- package/dist/mcp/server.js +191 -37
- package/dist/mcp/version.js +1 -0
- package/dist/schema/accountRequestMethods.js +1 -0
- package/dist/schema/cronValidator.js +150 -0
- package/dist/schema/platformApiKey.js +5 -5
- package/dist/schema/platformBillingConstants.js +3 -0
- package/dist/schema/platformCapabilityFamilies.js +269 -0
- package/dist/schema/platformConnectionCatalog.js +20 -3
- package/dist/schema/platformConnectionPolicy.js +26 -0
- package/dist/schema/platformCustomTools.js +113 -0
- package/dist/schema/platformFunding.js +9 -0
- package/dist/schema/platformHttpConstraints.js +7 -0
- package/dist/schema/platformMcpTools.js +7 -0
- package/dist/schema/platformMetaTools.js +8 -6
- package/dist/schema/platformMonitorSchedule.js +123 -0
- package/dist/schema/platformMonitors.js +159 -0
- package/dist/schema/platformOAuth.js +7 -0
- package/dist/schema/platformPublicExecution.js +53 -15
- package/dist/schema/platformRoutes.js +61 -1
- package/dist/schema/platformSkills.js +1 -1
- package/dist/schema/platformTeamSecretName.js +3 -0
- package/dist/schema/platformTeamSkills.js +49 -0
- package/dist/schema/platformToolAccess.js +18 -0
- package/dist/schema/platformTriggers.js +152 -0
- package/dist/schema/platformWorkflows.js +100 -0
- package/dist/schema/scheduleTimeZone.js +15 -0
- package/dist/schema/toolDiscovery.js +20 -3
- package/dist/schema/toolInputRepair.js +110 -0
- package/dist/schema/toolResultContext.js +1 -1
- package/package.json +1 -1
- package/dist/schema/amazonAds.js +0 -13
- package/dist/schema/oauth2.js +0 -64
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { isCronTooFrequent, isValidCron, parseCron } from "./cronValidator.js";
|
|
3
|
+
import { ScheduleTimeZone } from "./scheduleTimeZone.js";
|
|
4
|
+
export const PLATFORM_MONITOR_INTERVALS = { "15m": 900, "1h": 3600, "1d": 86_400 };
|
|
5
|
+
export const platformMonitorIntervalSchema = z.enum(["15m", "1h", "1d"]);
|
|
6
|
+
export const PLATFORM_MONITOR_DEFAULT_INTERVAL = "1h";
|
|
7
|
+
export const PLATFORM_MONITOR_DEFAULT_TIME_ZONE = "UTC";
|
|
8
|
+
export const PLATFORM_MONITOR_MIN_CRON_MINUTES = 15;
|
|
9
|
+
export const PLATFORM_MONITOR_CRON_CHARS = 100;
|
|
10
|
+
const cronText = z.string().trim().max(PLATFORM_MONITOR_CRON_CHARS)
|
|
11
|
+
.refine(isValidCron, "platform_monitor_cron_invalid")
|
|
12
|
+
.refine(cron => !isCronTooFrequent(cron, PLATFORM_MONITOR_MIN_CRON_MINUTES), "platform_monitor_cron_too_frequent");
|
|
13
|
+
export const platformMonitorCronSchema = z.union([z.literal(""), cronText]);
|
|
14
|
+
export const platformMonitorTimeZoneSchema = z.union([z.literal(""), ScheduleTimeZone]);
|
|
15
|
+
export const normalizeMonitorCron = (cron) => cron.trim().split(/\s+/).map(field => field.toUpperCase()).join(" ");
|
|
16
|
+
export class PlatformMonitorScheduleError extends Error {
|
|
17
|
+
}
|
|
18
|
+
export function resolvePlatformMonitorSchedule(input, after = Date.now()) {
|
|
19
|
+
if (!input.cron) {
|
|
20
|
+
if (input.timeZone)
|
|
21
|
+
throw new PlatformMonitorScheduleError("platform_monitor_time_zone_needs_cron");
|
|
22
|
+
return { interval: input.interval ?? PLATFORM_MONITOR_DEFAULT_INTERVAL };
|
|
23
|
+
}
|
|
24
|
+
if (input.interval)
|
|
25
|
+
throw new PlatformMonitorScheduleError("platform_monitor_schedule_conflict");
|
|
26
|
+
const zone = ScheduleTimeZone.safeParse(input.timeZone || PLATFORM_MONITOR_DEFAULT_TIME_ZONE);
|
|
27
|
+
if (!zone.success)
|
|
28
|
+
throw new PlatformMonitorScheduleError("platform_monitor_time_zone_invalid");
|
|
29
|
+
const cron = normalizeMonitorCron(input.cron), timeZone = zone.data;
|
|
30
|
+
if (nextCronFire(cron, timeZone, after) === null)
|
|
31
|
+
throw new PlatformMonitorScheduleError("platform_monitor_cron_never_runs");
|
|
32
|
+
return { cron, timeZone };
|
|
33
|
+
}
|
|
34
|
+
const MINUTE = 60_000, HOUR = 3_600_000, DAY = 86_400_000;
|
|
35
|
+
const SEARCH_DAYS = 366 * 8;
|
|
36
|
+
const formatters = new Map();
|
|
37
|
+
function offsetAt(timeZone, at) {
|
|
38
|
+
let format = formatters.get(timeZone);
|
|
39
|
+
if (!format) {
|
|
40
|
+
format = new Intl.DateTimeFormat("en-US", { timeZone, hourCycle: "h23", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric" });
|
|
41
|
+
formatters.set(timeZone, format);
|
|
42
|
+
}
|
|
43
|
+
const part = {};
|
|
44
|
+
for (const { type, value } of format.formatToParts(at))
|
|
45
|
+
if (type !== "literal")
|
|
46
|
+
part[type] = Number(value);
|
|
47
|
+
return Date.UTC(part.year, part.month - 1, part.day, part.hour, part.minute, part.second) - Math.floor(at / 1000) * 1000;
|
|
48
|
+
}
|
|
49
|
+
function instantOf(timeZone, wall) {
|
|
50
|
+
const before = offsetAt(timeZone, wall - DAY), after = offsetAt(timeZone, wall + DAY);
|
|
51
|
+
const candidates = [...new Set([wall - before, wall - after])].sort((a, b) => a - b);
|
|
52
|
+
const valid = candidates.filter(at => offsetAt(timeZone, at) === wall - at);
|
|
53
|
+
if (valid.length)
|
|
54
|
+
return valid[0];
|
|
55
|
+
let low = candidates[0], high = candidates[candidates.length - 1];
|
|
56
|
+
if (low === high)
|
|
57
|
+
return low;
|
|
58
|
+
const lowOffset = offsetAt(timeZone, low);
|
|
59
|
+
while (high - low > MINUTE) {
|
|
60
|
+
const mid = low + Math.floor((high - low) / (2 * MINUTE)) * MINUTE;
|
|
61
|
+
if (offsetAt(timeZone, mid) === lowOffset)
|
|
62
|
+
low = mid;
|
|
63
|
+
else
|
|
64
|
+
high = mid;
|
|
65
|
+
}
|
|
66
|
+
return high;
|
|
67
|
+
}
|
|
68
|
+
const dayMatches = (parsed, year, month, day) => {
|
|
69
|
+
if (!parsed.months.has(month))
|
|
70
|
+
return false;
|
|
71
|
+
const dom = parsed.daysOfMonth.has(day), dow = parsed.daysOfWeek.has(new Date(Date.UTC(year, month - 1, day)).getUTCDay());
|
|
72
|
+
return parsed.dayRestrictionOr ? dom || dow : dom && dow;
|
|
73
|
+
};
|
|
74
|
+
const ascending = (values) => [...values].sort((a, b) => a - b);
|
|
75
|
+
export function nextCronFire(cron, timeZone, after) {
|
|
76
|
+
const parsed = parseCron(cron);
|
|
77
|
+
if (!parsed)
|
|
78
|
+
return null;
|
|
79
|
+
const hours = ascending(parsed.hours), minutes = ascending(parsed.minutes);
|
|
80
|
+
const wallAfter = after + offsetAt(timeZone, after);
|
|
81
|
+
const first = new Date(wallAfter);
|
|
82
|
+
const start = Date.UTC(first.getUTCFullYear(), first.getUTCMonth(), first.getUTCDate()) - DAY;
|
|
83
|
+
for (let index = 0; index < SEARCH_DAYS; index++) {
|
|
84
|
+
const dayStart = start + index * DAY, date = new Date(dayStart);
|
|
85
|
+
if (!dayMatches(parsed, date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()))
|
|
86
|
+
continue;
|
|
87
|
+
for (const hour of hours)
|
|
88
|
+
for (const minute of minutes) {
|
|
89
|
+
const wall = dayStart + hour * HOUR + minute * MINUTE;
|
|
90
|
+
if (wall < wallAfter - 6 * HOUR)
|
|
91
|
+
continue;
|
|
92
|
+
const at = instantOf(timeZone, wall);
|
|
93
|
+
if (at > after)
|
|
94
|
+
return at;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
export function upcomingCronFires(cron, timeZone, after, count) {
|
|
100
|
+
const fires = [];
|
|
101
|
+
for (let at = after; fires.length < count;) {
|
|
102
|
+
const next = nextCronFire(cron, timeZone, at);
|
|
103
|
+
if (next === null)
|
|
104
|
+
break;
|
|
105
|
+
fires.push(next);
|
|
106
|
+
at = next;
|
|
107
|
+
}
|
|
108
|
+
return fires;
|
|
109
|
+
}
|
|
110
|
+
export function monitorRunsPerMonth(schedule) {
|
|
111
|
+
if (!("cron" in schedule))
|
|
112
|
+
return Math.round((365 / 12) * 86_400 / PLATFORM_MONITOR_INTERVALS[schedule.interval]);
|
|
113
|
+
const parsed = parseCron(schedule.cron);
|
|
114
|
+
if (!parsed)
|
|
115
|
+
return 0;
|
|
116
|
+
let days = 0;
|
|
117
|
+
for (let index = 0; index < 365; index++) {
|
|
118
|
+
const date = new Date(Date.UTC(2026, 0, 1 + index));
|
|
119
|
+
if (dayMatches(parsed, date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()))
|
|
120
|
+
days++;
|
|
121
|
+
}
|
|
122
|
+
return Math.round(days * parsed.hours.size * parsed.minutes.size / 12);
|
|
123
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { projectScopeSchema, platformJsonObjectSchema, platformMicrosSchema } from "./platformPublicExecution.js";
|
|
3
|
+
import { platformMonitorCronSchema, platformMonitorIntervalSchema, platformMonitorTimeZoneSchema } from "./platformMonitorSchedule.js";
|
|
4
|
+
export { PLATFORM_MONITOR_INTERVALS, platformMonitorIntervalSchema } from "./platformMonitorSchedule.js";
|
|
5
|
+
export const PLATFORM_MONITOR_LIMITS = {
|
|
6
|
+
perProject: 25,
|
|
7
|
+
nameChars: 80,
|
|
8
|
+
eventsPage: 100,
|
|
9
|
+
eventItemBytes: 8_192,
|
|
10
|
+
snapshotItems: 500,
|
|
11
|
+
retentionDays: 30,
|
|
12
|
+
popularMinimumOrganizations: 3,
|
|
13
|
+
popularPage: 50,
|
|
14
|
+
};
|
|
15
|
+
export const PLATFORM_MONITOR_DESTINATION_LIMITS = {
|
|
16
|
+
perMonitor: 5,
|
|
17
|
+
emailRecipients: 5,
|
|
18
|
+
labelChars: 80,
|
|
19
|
+
urlChars: 512,
|
|
20
|
+
digestEvents: 10,
|
|
21
|
+
};
|
|
22
|
+
export const PLATFORM_MONITOR_EMAIL_PRICE_MICROS = 900;
|
|
23
|
+
export const platformMonitorDestinationKindSchema = z.enum(["webhook", "slack", "discord", "email"]);
|
|
24
|
+
const httpsUrl = (value) => {
|
|
25
|
+
try {
|
|
26
|
+
const url = new URL(value);
|
|
27
|
+
return url.protocol === "https:" && !url.username && !url.password && url.hash === "" ? url : null;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export const isPlatformWebhookUrl = (value) => {
|
|
34
|
+
const url = httpsUrl(value);
|
|
35
|
+
return Boolean(url && url.port === "");
|
|
36
|
+
};
|
|
37
|
+
export const isPlatformSlackWebhookUrl = (value) => {
|
|
38
|
+
const url = httpsUrl(value);
|
|
39
|
+
return Boolean(url && url.hostname === "hooks.slack.com" && url.port === "" && url.search === "" && /^\/services\/[A-Za-z0-9]+\/[A-Za-z0-9]+\/[A-Za-z0-9]+$/.test(url.pathname));
|
|
40
|
+
};
|
|
41
|
+
export const isPlatformDiscordWebhookUrl = (value) => {
|
|
42
|
+
const url = httpsUrl(value);
|
|
43
|
+
return Boolean(url && ["discord.com", "discordapp.com"].includes(url.hostname) && url.port === "" && url.search === "" &&
|
|
44
|
+
/^\/api(\/v\d{1,2})?\/webhooks\/\d{1,25}\/[A-Za-z0-9_-]{1,200}$/.test(url.pathname));
|
|
45
|
+
};
|
|
46
|
+
const destinationUrl = z.string().trim().max(PLATFORM_MONITOR_DESTINATION_LIMITS.urlChars);
|
|
47
|
+
const destinationLabel = z.string().trim().max(PLATFORM_MONITOR_DESTINATION_LIMITS.labelChars).default("");
|
|
48
|
+
const memberId = z.string().min(1).max(64);
|
|
49
|
+
export const platformMonitorDestinationInputSchema = z.discriminatedUnion("kind", [
|
|
50
|
+
z.object({ kind: z.literal("webhook"), label: destinationLabel, url: destinationUrl.refine(isPlatformWebhookUrl, "platform_monitor_destination_url_invalid") }).strict(),
|
|
51
|
+
z.object({ kind: z.literal("slack"), label: destinationLabel, url: destinationUrl.refine(isPlatformSlackWebhookUrl, "platform_monitor_destination_url_invalid") }).strict(),
|
|
52
|
+
z.object({ kind: z.literal("discord"), label: destinationLabel, url: destinationUrl.refine(isPlatformDiscordWebhookUrl, "platform_monitor_destination_url_invalid") }).strict(),
|
|
53
|
+
z.object({ kind: z.literal("email"), label: destinationLabel,
|
|
54
|
+
memberIds: z.array(memberId).min(1).max(PLATFORM_MONITOR_DESTINATION_LIMITS.emailRecipients) }).strict(),
|
|
55
|
+
]);
|
|
56
|
+
export const platformMonitorDestinationSchema = z.object({
|
|
57
|
+
id: z.string().regex(/^dst_[A-Za-z0-9_-]{1,100}$/),
|
|
58
|
+
kind: platformMonitorDestinationKindSchema,
|
|
59
|
+
label: z.string(),
|
|
60
|
+
target: z.string(),
|
|
61
|
+
memberIds: z.array(z.string()),
|
|
62
|
+
createdAt: z.string(),
|
|
63
|
+
lastDeliveredAt: z.string().nullable(),
|
|
64
|
+
lastStatus: z.enum(["ok", "failed"]).nullable(),
|
|
65
|
+
lastError: z.string().nullable(),
|
|
66
|
+
signingSecret: z.string().optional(),
|
|
67
|
+
});
|
|
68
|
+
export const platformMonitorRecipientSchema = z.object({ memberId, email: z.string(), name: z.string() });
|
|
69
|
+
const toolName = z.string().regex(/^[a-z][a-z0-9_]{1,63}$/);
|
|
70
|
+
export const PLATFORM_MONITOR_ID = /^mon_[A-Za-z0-9_-]{1,100}$/;
|
|
71
|
+
const monitorId = z.string().regex(PLATFORM_MONITOR_ID);
|
|
72
|
+
export const platformMonitorCreateSchema = z.object({
|
|
73
|
+
tool: toolName,
|
|
74
|
+
arguments: platformJsonObjectSchema.default({}),
|
|
75
|
+
provider: z.string().trim().max(64).default(""),
|
|
76
|
+
interval: platformMonitorIntervalSchema.optional().describe("Run every 15m, 1h (default) or 1d. Omit when using cron."),
|
|
77
|
+
cron: platformMonitorCronSchema.optional().describe("5-field cron for fixed times, at least 15 minutes between runs, for example '0 9 * * 1-5' (weekdays 09:00). Omit when using interval."),
|
|
78
|
+
timeZone: platformMonitorTimeZoneSchema.optional().describe("IANA time zone the cron is read in, for example Asia/Tokyo; UTC when omitted. Only with cron."),
|
|
79
|
+
name: z.string().trim().max(PLATFORM_MONITOR_LIMITS.nameChars).default(""),
|
|
80
|
+
maximumChargeMicrosPerRun: platformMicrosSchema.default(0),
|
|
81
|
+
destinations: z.array(platformMonitorDestinationInputSchema).max(PLATFORM_MONITOR_DESTINATION_LIMITS.perMonitor).default([]),
|
|
82
|
+
}).strict();
|
|
83
|
+
export const platformMonitorPoolSchema = z.object({
|
|
84
|
+
chargeCeilingMicros: platformMicrosSchema,
|
|
85
|
+
members: z.number().int().min(0),
|
|
86
|
+
shareMicros: platformMicrosSchema,
|
|
87
|
+
});
|
|
88
|
+
export const platformMonitorQuoteSchema = platformMonitorCreateSchema.pick({ tool: true, arguments: true, provider: true, interval: true, cron: true, timeZone: true }).strict();
|
|
89
|
+
export const platformMonitorQuoteResultSchema = platformMonitorPoolSchema.extend({
|
|
90
|
+
joined: z.boolean(),
|
|
91
|
+
payers: z.number().int().min(1),
|
|
92
|
+
});
|
|
93
|
+
export const platformMonitorResumeSchema = z.object({ maximumChargeMicrosPerRun: platformMicrosSchema.optional() }).strict();
|
|
94
|
+
export const platformMonitorSchema = z.object({
|
|
95
|
+
id: monitorId,
|
|
96
|
+
name: z.string(),
|
|
97
|
+
tool: toolName,
|
|
98
|
+
provider: z.string(),
|
|
99
|
+
arguments: platformJsonObjectSchema,
|
|
100
|
+
interval: platformMonitorIntervalSchema.nullable(),
|
|
101
|
+
cron: z.string().nullable().default(null),
|
|
102
|
+
timeZone: z.string().nullable().default(null),
|
|
103
|
+
subscribers: z.number().int().min(1),
|
|
104
|
+
lastCheckedAt: z.string().nullable(),
|
|
105
|
+
lastChangedAt: z.string().nullable(),
|
|
106
|
+
nextCheckAt: z.string().nullable(),
|
|
107
|
+
lastError: z.string().nullable(),
|
|
108
|
+
createdAt: z.string(),
|
|
109
|
+
maximumChargeMicrosPerRun: platformMicrosSchema,
|
|
110
|
+
pool: platformMonitorPoolSchema,
|
|
111
|
+
status: z.enum(["active", "suspended"]),
|
|
112
|
+
suspendedReason: z.string().nullable(),
|
|
113
|
+
destinations: z.array(platformMonitorDestinationSchema).default([]),
|
|
114
|
+
});
|
|
115
|
+
const changeValue = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
|
116
|
+
export const platformMonitorEventSchema = z.object({
|
|
117
|
+
id: z.string().regex(/^\d{1,20}$/),
|
|
118
|
+
monitorId: monitorId,
|
|
119
|
+
kind: z.enum(["added", "changed", "removed"]),
|
|
120
|
+
itemKey: z.string(),
|
|
121
|
+
title: z.string(),
|
|
122
|
+
url: z.string(),
|
|
123
|
+
item: platformJsonObjectSchema,
|
|
124
|
+
changes: z.array(z.object({ field: z.string(), before: changeValue, after: changeValue })),
|
|
125
|
+
detectedAt: z.string(),
|
|
126
|
+
});
|
|
127
|
+
export const platformMonitorEventsQuerySchema = z.object({
|
|
128
|
+
after: z.string().regex(/^\d{1,20}$/).optional(),
|
|
129
|
+
limit: z.coerce.number().int().min(1).max(PLATFORM_MONITOR_LIMITS.eventsPage).default(50),
|
|
130
|
+
}).strict();
|
|
131
|
+
export const platformMonitorEventsSchema = z.object({ events: z.array(platformMonitorEventSchema), nextAfter: z.string().nullable() });
|
|
132
|
+
export const platformPopularMonitorSchema = z.object({
|
|
133
|
+
tool: toolName, provider: z.string(), arguments: platformJsonObjectSchema,
|
|
134
|
+
interval: platformMonitorIntervalSchema.nullable(), cron: z.string().nullable().default(null), timeZone: z.string().nullable().default(null),
|
|
135
|
+
organizations: z.number().int().min(1),
|
|
136
|
+
chargeCeilingMicros: platformMicrosSchema,
|
|
137
|
+
});
|
|
138
|
+
export const platformMonitorableToolSchema = z.object({ name: toolName, provider: z.string(), chargeCeilingMicros: platformMicrosSchema });
|
|
139
|
+
export function platformMonitorWire(monitor) {
|
|
140
|
+
const { cron, timeZone, destinations, ...rest } = monitor;
|
|
141
|
+
return { ...rest, ...(cron == null ? {} : { cron }), ...(timeZone == null ? {} : { timeZone }), ...(destinations?.length ? { destinations } : {}) };
|
|
142
|
+
}
|
|
143
|
+
export const platformMonitorContracts = {
|
|
144
|
+
listDeveloperMonitors: { input: projectScopeSchema.strict(), output: z.object({ monitors: z.array(platformMonitorSchema) }).strict() },
|
|
145
|
+
createDeveloperMonitor: { input: projectScopeSchema.extend({ monitor: platformMonitorCreateSchema }).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
|
|
146
|
+
deleteDeveloperMonitor: { input: projectScopeSchema.extend({ monitorId }).strict(), output: z.object({ success: z.literal(true) }).strict() },
|
|
147
|
+
quoteDeveloperMonitor: { input: projectScopeSchema.extend({ monitor: platformMonitorQuoteSchema }).strict(), output: z.object({ quote: platformMonitorQuoteResultSchema }).strict() },
|
|
148
|
+
resumeDeveloperMonitor: { input: projectScopeSchema.extend({ monitorId }).merge(platformMonitorResumeSchema).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
|
|
149
|
+
listDeveloperMonitorEvents: {
|
|
150
|
+
input: projectScopeSchema.extend({ monitorId: monitorId.optional(), after: platformMonitorEventsQuerySchema.shape.after,
|
|
151
|
+
limit: z.number().int().min(1).max(PLATFORM_MONITOR_LIMITS.eventsPage).default(50) }).strict(),
|
|
152
|
+
output: platformMonitorEventsSchema,
|
|
153
|
+
},
|
|
154
|
+
addDeveloperMonitorDestination: { input: projectScopeSchema.extend({ monitorId, destination: platformMonitorDestinationInputSchema }).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
|
|
155
|
+
removeDeveloperMonitorDestination: { input: projectScopeSchema.extend({ monitorId, destinationId: platformMonitorDestinationSchema.shape.id }).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
|
|
156
|
+
listDeveloperMonitorRecipients: { input: projectScopeSchema.strict(), output: z.object({ recipients: z.array(platformMonitorRecipientSchema) }).strict() },
|
|
157
|
+
listPopularMonitors: { input: projectScopeSchema.strict(), output: z.object({ monitors: z.array(platformPopularMonitorSchema) }).strict() },
|
|
158
|
+
listMonitorableTools: { input: projectScopeSchema.strict(), output: z.object({ tools: z.array(platformMonitorableToolSchema) }).strict() },
|
|
159
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const platformOAuthScopeAlternativesSchema = z.array(z.array(z.string().min(1).max(256)).max(128)).min(1).max(128);
|
|
3
|
+
export const platformOAuthPermissionSchema = z.object({
|
|
4
|
+
status: z.enum(["available", "missing_scopes", "unknown_grant", "unknown_requirements", "not_applicable"]),
|
|
5
|
+
required: platformOAuthScopeAlternativesSchema.optional(),
|
|
6
|
+
missing: z.array(z.string()).optional(),
|
|
7
|
+
});
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { fitToolResultPage, TOOL_RESULT_CONTEXT_MAX_BYTES, toolResultContextSchema, toolResultPageSchema } from "./toolResultContext.js";
|
|
3
|
+
import { platformOAuthPermissionSchema } from "./platformOAuth.js";
|
|
3
4
|
export const PLATFORM_EXECUTION_MAX_STEPS = 20;
|
|
4
5
|
export const PLATFORM_EXECUTION_MAX_WAIT_SECONDS = 25;
|
|
5
6
|
export const PLATFORM_STEP_OUTPUT_MAX_BYTES = 1_048_576;
|
|
6
7
|
export const PLATFORM_EXECUTION_RESPONSE_MAX_BYTES = PLATFORM_EXECUTION_MAX_STEPS * PLATFORM_STEP_OUTPUT_MAX_BYTES + 65_536;
|
|
7
8
|
export const platformJsonObjectSchema = z.record(z.string(), z.json());
|
|
9
|
+
export const organizationScopeSchema = z.object({ developerOrganizationId: z.string().min(1).max(128) });
|
|
10
|
+
export const projectScopeSchema = organizationScopeSchema.extend({ developerProjectId: z.string().min(1).max(128) });
|
|
8
11
|
export const developerKeyScopeSchema = z.enum(["project:read", "usage:read", "tools:read", "tools:execute", "executions:read"]);
|
|
12
|
+
export const developerKeyAnyScopeSchema = z.enum([...developerKeyScopeSchema.options, "access:write"]);
|
|
9
13
|
export const PLATFORM_INPUT_MAX_BYTES = 12 * 1024 * 1024;
|
|
14
|
+
export const PLATFORM_FILE_CHUNK_MAX_BYTES = 32 * 1024 * 1024;
|
|
10
15
|
export const PLATFORM_UPLOAD_MAX_BYTES = 16 * 1024 * 1024 + 4096;
|
|
11
16
|
export const platformInputFileIdSchema = z.string().regex(/^f_[a-f0-9]{64}$/);
|
|
12
17
|
export const platformInputMimeSchema = z.enum(["image/jpeg", "image/png", "image/webp", "audio/wav", "audio/mpeg", "video/mp4", "video/quicktime"]);
|
|
13
|
-
export const
|
|
14
|
-
export const
|
|
18
|
+
export const platformInputFileMimeSchema = z.string().max(255).regex(/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/);
|
|
19
|
+
export const platformInputUploadSchema = z.object({ mimeType: platformInputFileMimeSchema, data: z.string().min(4).max(16 * 1024 * 1024),
|
|
20
|
+
purpose: z.literal("file").optional().describe("file stores opaque bytes for provider uploads, including GIF, documents, archives and local upload chunks. Omit for validated AI media.") }).strict();
|
|
21
|
+
export const platformInputFileSchema = z.object({ id: platformInputFileIdSchema, mimeType: platformInputFileMimeSchema,
|
|
15
22
|
sizeBytes: z.number().int().positive().max(PLATFORM_INPUT_MAX_BYTES), sha256: z.string().regex(/^[a-f0-9]{64}$/), expiresAt: z.iso.datetime() });
|
|
16
23
|
export const platformMicrosSchema = z.number().int().min(0).max(1_000_000_000_000);
|
|
17
24
|
export const platformToolNameSchema = z.string().regex(/^[a-z][a-z0-9_]{1,63}$/);
|
|
@@ -22,34 +29,55 @@ export const PLATFORM_SANDBOX_LIMITS = { code: 64000, sourceExecutions: 10, time
|
|
|
22
29
|
export const platformProviderChoiceSchema = z.string().trim().regex(/^(?:[a-z][a-z0-9_]{0,63})?$/)
|
|
23
30
|
.transform(value => value === "" || value === "auto" ? undefined : value).optional()
|
|
24
31
|
.describe("Omit, use auto, or use an empty string for automatic routing. A catalog provider ID strictly selects that compatible provider; no other provider is substituted.");
|
|
32
|
+
export const platformRelevanceCheckSchema = z.enum(["", "auto", "light"])
|
|
33
|
+
.transform(value => value === "light" ? "light" : undefined).optional()
|
|
34
|
+
.describe("Auto result filtering: auto (default) or light, a cheaper check that keeps rows it cannot decide.");
|
|
35
|
+
export const platformInvalidArgumentFieldsSchema = z.array(z.string().max(200).regex(/^[\w.-]*$/)).max(50);
|
|
25
36
|
export const PLATFORM_REQUEST_INTENT_MAX_CHARS = 1000;
|
|
26
37
|
export const platformRequestIntentSchema = z.string().trim().max(PLATFORM_REQUEST_INTENT_MAX_CHARS).transform(value => value || undefined).optional()
|
|
27
38
|
.describe("Brief user goal without secrets or private content. Empty means omitted.");
|
|
28
39
|
export const platformExecutionStatusSchema = z.enum(["queued", "running", "waiting", "succeeded", "failed", "cancelled", "needs_review"]);
|
|
29
|
-
export const platformFundingSchema = z.enum(["relvo", "
|
|
30
|
-
|
|
31
|
-
const platformModelFundingSchema = z.enum(["relvo", "toolhub", "provider"])
|
|
32
|
-
.transform(value => value === "toolhub" ? "relvo" : value);
|
|
40
|
+
export const platformFundingSchema = z.enum(["relvo", "provider", "mixed"]);
|
|
41
|
+
const platformModelFundingSchema = z.enum(["relvo", "provider"]);
|
|
33
42
|
const workspaceArgumentNames = new Set(["workspaceid", "workspaceids", "teamid", "provideraccountid", "provideraccountids", "datasetid", "datasetids", "knowledgebaseid", "sessionid", "skillid"]);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
export function validatePlatformArgumentIdentifiers(tool, input, context, field = "arguments") {
|
|
44
|
+
if (tool?.includes("__"))
|
|
45
|
+
return;
|
|
46
|
+
const nativeFields = tool?.startsWith("tikhub_") ? ["session_id"]
|
|
47
|
+
: tool?.startsWith("brightdata_") ? ["dataset_id"]
|
|
48
|
+
: tool?.startsWith("firecrawl_") ? ["dataset_id", "session_id", "team_id"] : [];
|
|
49
|
+
for (const key of Object.keys(input))
|
|
50
|
+
if (workspaceArgumentNames.has(key.replaceAll("_", "").toLowerCase()) && !nativeFields.includes(key)) {
|
|
51
|
+
context.addIssue({ code: "custom", path: [field, key], message: "Workspace-owned data is unavailable on the standalone Platform." });
|
|
38
52
|
}
|
|
39
|
-
}
|
|
53
|
+
}
|
|
54
|
+
const standaloneArgumentsSchema = z.record(z.string(), z.unknown()).pipe(platformJsonObjectSchema)
|
|
55
|
+
.describe("Self-contained tool arguments: prompts, public URLs or public account identifiers. Web workspace identifiers are not supported.");
|
|
40
56
|
export const platformToolInputSchema = z.object({ tool: platformToolNameSchema.describe("Tool name from the standalone Platform catalog."), arguments: standaloneArgumentsSchema,
|
|
41
57
|
provider: platformProviderChoiceSchema,
|
|
58
|
+
relevanceCheck: platformRelevanceCheckSchema,
|
|
42
59
|
intent: platformRequestIntentSchema,
|
|
43
|
-
sessionId: platformOptionalToolSessionIdSchema.describe("Relvo tool session returned by platform_search_tools. Omit or use an empty string for standalone executions.") }).strict()
|
|
60
|
+
sessionId: platformOptionalToolSessionIdSchema.describe("Relvo tool session returned by platform_search_tools. Omit or use an empty string for standalone executions.") }).strict()
|
|
61
|
+
.superRefine((value, context) => validatePlatformArgumentIdentifiers(value.tool, value.arguments, context));
|
|
62
|
+
export const platformQuoteRequestSchema = platformToolInputSchema.extend({
|
|
63
|
+
maximumChargeMicros: platformMicrosSchema.optional()
|
|
64
|
+
.describe("Optional cap: an Auto quote above it returns the best plan within it as plan; execute with plan's fields."),
|
|
65
|
+
}).strict();
|
|
66
|
+
export const platformRunRequestHashSchema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
67
|
+
export const platformRecoverExecutionSchema = z.object({ idempotencyKey: z.string().regex(/^[A-Za-z0-9._:-]{8,128}$/),
|
|
68
|
+
requestHash: platformRunRequestHashSchema.optional() }).strict();
|
|
44
69
|
export const platformCreateExecutionSchema = platformToolInputSchema.extend({
|
|
45
70
|
maximumChargeMicros: platformMicrosSchema,
|
|
46
71
|
priceVersion: z.string().min(1).max(100),
|
|
72
|
+
runRequestHash: platformRunRequestHashSchema.optional(),
|
|
47
73
|
}).strict();
|
|
48
74
|
export const platformQuoteSchema = z.object({
|
|
49
75
|
tool: platformToolNameSchema, priceVersion: z.string(), currency: z.literal("usd"),
|
|
50
76
|
minimumChargeMicros: platformMicrosSchema, maximumChargeMicros: platformMicrosSchema,
|
|
77
|
+
lowestChargeMicros: platformMicrosSchema.optional(),
|
|
51
78
|
expiresAt: z.string(),
|
|
52
79
|
funding: platformFundingSchema.optional(), externalBillingProviders: z.array(z.string()).optional(),
|
|
80
|
+
plan: z.object({ provider: z.string().optional(), relevanceCheck: z.literal("light").optional() }).strict().optional(),
|
|
53
81
|
});
|
|
54
82
|
export const platformExecutionSchema = z.object({
|
|
55
83
|
id: platformExecutionIdSchema, tool: platformToolNameSchema, status: platformExecutionStatusSchema, cancelRequested: z.boolean(),
|
|
@@ -121,16 +149,26 @@ export const platformArtifactSchema = z.object({
|
|
|
121
149
|
generation: z.string().regex(/^\d{1,30}$/), expiresAt: z.iso.datetime(),
|
|
122
150
|
});
|
|
123
151
|
export const platformArtifactDownloadSchema = z.object({ url: z.url().refine((value) => { const url = new URL(value); return url.protocol === "https:" && !url.username && !url.password; }), expiresAt: z.iso.datetime() });
|
|
152
|
+
export const platformUnavailableReasonSchema = z.enum(["setup", "own_key", "connection", "permission", "retired"]);
|
|
124
153
|
export const platformCatalogToolSchema = z.object({
|
|
125
154
|
name: platformToolNameSchema, title: z.string().optional(), description: z.string(), category: z.enum(["research", "seo", "social", "generation", "enrichment", "finance", "news"]),
|
|
126
|
-
available: z.boolean(), inputSchema: platformJsonObjectSchema, example: platformJsonObjectSchema,
|
|
127
|
-
|
|
155
|
+
available: z.boolean(), unavailable: platformUnavailableReasonSchema.optional(), inputSchema: platformJsonObjectSchema, example: platformJsonObjectSchema,
|
|
156
|
+
permission: platformOAuthPermissionSchema.optional(),
|
|
157
|
+
providers: z.array(z.object({ id: z.string(), name: z.string(), available: z.boolean(), unavailable: platformUnavailableReasonSchema.optional(),
|
|
128
158
|
role: z.enum(["primary", "fallback", "alternative"]), condition: z.string().optional() })).optional(),
|
|
129
|
-
models: z.array(z.object({ id: z.string(), available: z.boolean(), example: platformJsonObjectSchema, priceDescription: z.string(), funding: platformModelFundingSchema.optional() })).optional(),
|
|
159
|
+
models: z.array(z.object({ id: z.string(), available: z.boolean(), unavailable: platformUnavailableReasonSchema.optional(), example: platformJsonObjectSchema, priceDescription: z.string(), funding: platformModelFundingSchema.optional() })).optional(),
|
|
130
160
|
price: z.object({ minimumChargeMicros: platformMicrosSchema, unit: z.string(), unitPriceMicros: platformMicrosSchema.nullable(), unitPriceCeilingMicros: platformMicrosSchema.optional(), description: z.string(),
|
|
161
|
+
unitsPerRequest: z.object({ minimum: z.number().int().positive(), maximum: z.number().int().positive() }).refine(range => range.minimum <= range.maximum).optional(),
|
|
131
162
|
funding: platformFundingSchema.optional(), externalBillingProviders: z.array(z.string()).optional() }),
|
|
132
163
|
});
|
|
133
164
|
const platformCatalogHeader = { priceVersion: z.string(), currency: z.literal("usd"), executionEnabled: z.boolean() };
|
|
134
165
|
export const platformCatalogSchema = z.object({ ...platformCatalogHeader, tools: z.array(platformCatalogToolSchema) });
|
|
166
|
+
export const PLATFORM_CATALOG_PAGE_MAX = 50;
|
|
167
|
+
export const PLATFORM_READ_UNIT_BYTES = 262_144;
|
|
168
|
+
export const platformCatalogPageQuerySchema = z.object({
|
|
169
|
+
offset: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).default(0),
|
|
170
|
+
limit: z.number().int().min(1).max(PLATFORM_CATALOG_PAGE_MAX).default(PLATFORM_CATALOG_PAGE_MAX),
|
|
171
|
+
}).strict();
|
|
172
|
+
export const platformCatalogPageSchema = platformCatalogSchema.extend({ total: z.number().int().min(0), nextOffset: z.number().int().min(0).nullable() });
|
|
135
173
|
export const platformCatalogSummarySchema = z.object({ ...platformCatalogHeader, tools: z.array(platformCatalogToolSchema.omit({ inputSchema: true })) });
|
|
136
174
|
export const platformCatalogToolDetailSchema = z.object({ ...platformCatalogHeader, tool: platformCatalogToolSchema });
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
const TOOL = "[a-z][a-z0-9_]{1,63}";
|
|
2
2
|
const EXECUTION = "[A-Za-z0-9_-]{1,128}";
|
|
3
3
|
const ARTIFACT = "a_[A-Za-z0-9_-]{1,100}";
|
|
4
|
+
const MONITOR = "mon_[A-Za-z0-9_-]{1,100}";
|
|
5
|
+
const CUSTOM_TOOL = "custom__[a-z][a-z0-9_]{1,39}";
|
|
6
|
+
const TEAM_SKILL = "[a-z][a-z0-9_]{1,39}";
|
|
7
|
+
const WORKFLOW = "[a-z][a-z0-9_]{1,39}";
|
|
8
|
+
const WORKFLOW_RUN = "wfr_[A-Za-z0-9_-]{1,100}";
|
|
9
|
+
const TRIGGER = "trg_[A-Za-z0-9_-]{1,100}";
|
|
10
|
+
const MEMBER = "[A-Za-z0-9-]{1,128}";
|
|
4
11
|
export const PLATFORM_ROUTES = {
|
|
5
12
|
tools: "/v1/tools",
|
|
6
13
|
connections: "/v1/connections",
|
|
@@ -8,11 +15,56 @@ export const PLATFORM_ROUTES = {
|
|
|
8
15
|
project: "/v1/project",
|
|
9
16
|
usage: "/v1/usage",
|
|
10
17
|
executions: "/v1/executions",
|
|
18
|
+
executionRecovery: "/v1/executions/recover",
|
|
11
19
|
execution: `/v1/executions/:id{${EXECUTION}}`,
|
|
12
20
|
executionContext: `/v1/executions/:id{${EXECUTION}}/context`,
|
|
13
21
|
executionResult: `/v1/executions/:id{${EXECUTION}}/result`,
|
|
14
22
|
executionCancel: `/v1/executions/:id{${EXECUTION}}/cancel`,
|
|
15
23
|
artifactDownload: `/v1/executions/:id{${EXECUTION}}/artifacts/:artifact{${ARTIFACT}}/download`,
|
|
24
|
+
monitors: "/v1/monitors",
|
|
25
|
+
monitorTools: "/v1/monitors/tools",
|
|
26
|
+
monitorsPopular: "/v1/monitors/popular",
|
|
27
|
+
monitorQuote: "/v1/monitors/quote",
|
|
28
|
+
monitorResume: `/v1/monitors/:id{${MONITOR}}/resume`,
|
|
29
|
+
monitor: `/v1/monitors/:id{${MONITOR}}`,
|
|
30
|
+
monitorDelete: `/v1/monitors/:id{${MONITOR}}/delete`,
|
|
31
|
+
monitorEvents: `/v1/monitors/:id{${MONITOR}}/events`,
|
|
32
|
+
monitorDestinations: `/v1/monitors/:id{${MONITOR}}/destinations`,
|
|
33
|
+
monitorDestinationDelete: `/v1/monitors/:id{${MONITOR}}/destinations/:destinationId{dst_[A-Za-z0-9_-]{1,100}}/delete`,
|
|
34
|
+
monitorRecipients: "/v1/monitor-recipients",
|
|
35
|
+
monitorFeed: "/v1/monitor-events",
|
|
36
|
+
customTools: "/v1/custom-tools",
|
|
37
|
+
customTool: `/v1/custom-tools/:name{${CUSTOM_TOOL}}`,
|
|
38
|
+
customToolUpdate: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/update`,
|
|
39
|
+
customToolDelete: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/delete`,
|
|
40
|
+
customToolVersions: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/versions`,
|
|
41
|
+
customToolRestore: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/restore`,
|
|
42
|
+
teamSkills: "/v1/team-skills",
|
|
43
|
+
teamSkill: `/v1/team-skills/:slug{${TEAM_SKILL}}`,
|
|
44
|
+
teamSkillUpdate: `/v1/team-skills/:slug{${TEAM_SKILL}}/update`,
|
|
45
|
+
teamSkillDelete: `/v1/team-skills/:slug{${TEAM_SKILL}}/delete`,
|
|
46
|
+
teamSkillVersions: `/v1/team-skills/:slug{${TEAM_SKILL}}/versions`,
|
|
47
|
+
teamSkillRestore: `/v1/team-skills/:slug{${TEAM_SKILL}}/restore`,
|
|
48
|
+
workflows: "/v1/workflows",
|
|
49
|
+
workflow: `/v1/workflows/:slug{${WORKFLOW}}`,
|
|
50
|
+
workflowUpdate: `/v1/workflows/:slug{${WORKFLOW}}/update`,
|
|
51
|
+
workflowDelete: `/v1/workflows/:slug{${WORKFLOW}}/delete`,
|
|
52
|
+
workflowVersions: `/v1/workflows/:slug{${WORKFLOW}}/versions`,
|
|
53
|
+
workflowRuns: `/v1/workflows/:slug{${WORKFLOW}}/runs`,
|
|
54
|
+
workflowRun: `/v1/workflow-runs/:id{${WORKFLOW_RUN}}`,
|
|
55
|
+
workflowRunCancel: `/v1/workflow-runs/:id{${WORKFLOW_RUN}}/cancel`,
|
|
56
|
+
triggers: "/v1/triggers",
|
|
57
|
+
trigger: `/v1/triggers/:id{${TRIGGER}}`,
|
|
58
|
+
triggerUpdate: `/v1/triggers/:id{${TRIGGER}}/update`,
|
|
59
|
+
triggerDelete: `/v1/triggers/:id{${TRIGGER}}/delete`,
|
|
60
|
+
triggerEvents: `/v1/triggers/:id{${TRIGGER}}/events`,
|
|
61
|
+
triggerDestinations: `/v1/triggers/:id{${TRIGGER}}/destinations`,
|
|
62
|
+
triggerDestinationDelete: `/v1/triggers/:id{${TRIGGER}}/destinations/:destinationId{dst_[A-Za-z0-9_-]{1,100}}/delete`,
|
|
63
|
+
triggerFeed: "/v1/trigger-events",
|
|
64
|
+
triggerTypes: "/v1/trigger-types",
|
|
65
|
+
suggestions: "/v1/suggestions",
|
|
66
|
+
access: "/v1/access",
|
|
67
|
+
memberAccess: `/v1/access/members/:id{${MEMBER}}/update`,
|
|
16
68
|
definition: `/tools/definition/:name{${TOOL}}`,
|
|
17
69
|
tool: `/tools/:tool{${TOOL}}`,
|
|
18
70
|
discover: "/tools/discover",
|
|
@@ -25,11 +77,19 @@ export const PLATFORM_ROUTES = {
|
|
|
25
77
|
metaWorkbench: "/tools/meta/workbench",
|
|
26
78
|
metaBash: "/tools/meta/bash",
|
|
27
79
|
};
|
|
80
|
+
export const PLATFORM_TRIGGER_INGRESS_ROUTES = {
|
|
81
|
+
endpoint: "/v1/trigger-ingress/:endpoint{tep_[a-f0-9]{32}}",
|
|
82
|
+
app: "/v1/trigger-ingress/app/:app{[a-z0-9][a-z0-9_]{0,63}}",
|
|
83
|
+
};
|
|
84
|
+
export const PLATFORM_WALLET_ROUTES = {
|
|
85
|
+
signIn: "/v1/wallet/sign-in",
|
|
86
|
+
topUp: "/v1/wallet/top-up",
|
|
87
|
+
};
|
|
28
88
|
export const PLATFORM_META_ROUTES = [PLATFORM_ROUTES.metaSearch, PLATFORM_ROUTES.metaSchemas, PLATFORM_ROUTES.metaConnections,
|
|
29
89
|
PLATFORM_ROUTES.metaExecute, PLATFORM_ROUTES.metaWorkbench, PLATFORM_ROUTES.metaBash];
|
|
30
90
|
export const PLATFORM_BRIDGE_ROUTES = [
|
|
31
91
|
PLATFORM_ROUTES.tools, PLATFORM_ROUTES.connections, PLATFORM_ROUTES.quote, PLATFORM_ROUTES.project, PLATFORM_ROUTES.usage,
|
|
32
|
-
PLATFORM_ROUTES.executions, PLATFORM_ROUTES.execution, PLATFORM_ROUTES.executionContext, PLATFORM_ROUTES.executionResult,
|
|
92
|
+
PLATFORM_ROUTES.executions, PLATFORM_ROUTES.executionRecovery, PLATFORM_ROUTES.execution, PLATFORM_ROUTES.executionContext, PLATFORM_ROUTES.executionResult,
|
|
33
93
|
PLATFORM_ROUTES.executionCancel, PLATFORM_ROUTES.artifactDownload, PLATFORM_ROUTES.definition, PLATFORM_ROUTES.tool,
|
|
34
94
|
];
|
|
35
95
|
const ALIASED = "(?:project|usage|quote|executions|connections)(?:\\/|$)";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export const PLATFORM_SKILLS_MAX_BYTES = 1_048_576;
|
|
3
3
|
export const PLATFORM_SKILL_MAX_BYTES = 65_536;
|
|
4
|
-
export const platformSkillSchema = z.object({ name: z.string().regex(/^
|
|
4
|
+
export const platformSkillSchema = z.object({ name: z.string().regex(/^relvo(?:-[a-z0-9]+)*$/).max(64),
|
|
5
5
|
description: z.string().min(1).max(1000), sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
6
6
|
content: z.string().min(1).max(PLATFORM_SKILL_MAX_BYTES).refine(value => new TextEncoder().encode(value).byteLength <= PLATFORM_SKILL_MAX_BYTES) }).strict();
|
|
7
7
|
export const platformSkillsBundleSchema = z.object({ version: z.string().regex(/^[a-f0-9]{64}$/),
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const PLATFORM_TEAM_SECRET_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
3
|
+
export const platformTeamSecretNameSchema = z.string().regex(PLATFORM_TEAM_SECRET_NAME).describe("Letters, digits and underscores, not starting with a digit, e.g. STRIPE_API_KEY.");
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { projectScopeSchema } from "./platformPublicExecution.js";
|
|
3
|
+
import { PLATFORM_CUSTOM_TOOL_LIMITS, platformVersionAuthorSchema } from "./platformCustomTools.js";
|
|
4
|
+
export const PLATFORM_TEAM_SKILL_LIMITS = {
|
|
5
|
+
perProject: 200,
|
|
6
|
+
versions: 50,
|
|
7
|
+
titleChars: 80,
|
|
8
|
+
descriptionChars: 500,
|
|
9
|
+
contentBytes: 32_768,
|
|
10
|
+
};
|
|
11
|
+
export const PLATFORM_TEAM_SKILL_SLUG = /^[a-z][a-z0-9_]{1,39}$/;
|
|
12
|
+
export const platformTeamSkillSlugSchema = z.string().regex(PLATFORM_TEAM_SKILL_SLUG).describe("Lowercase letters, digits and underscores, starting with a letter.");
|
|
13
|
+
export const platformTeamSkillDefinitionSchema = z.object({
|
|
14
|
+
title: z.string().trim().min(1).max(PLATFORM_TEAM_SKILL_LIMITS.titleChars),
|
|
15
|
+
description: z.string().trim().min(1).max(PLATFORM_TEAM_SKILL_LIMITS.descriptionChars).describe("When an agent should follow this skill; agents choose skills by it."),
|
|
16
|
+
content: z.string().trim().min(1).refine(value => new TextEncoder().encode(value).byteLength <= PLATFORM_TEAM_SKILL_LIMITS.contentBytes, "The content is too long")
|
|
17
|
+
.describe("Markdown: the steps, the tools to use (by name) and what to check. No secrets."),
|
|
18
|
+
}).strict();
|
|
19
|
+
export const platformTeamSkillCreateSchema = platformTeamSkillDefinitionSchema.extend({ slug: platformTeamSkillSlugSchema }).strict();
|
|
20
|
+
export const platformTeamSkillUpdateSchema = platformTeamSkillDefinitionSchema.extend({ expectedVersion: z.number().int().min(1) }).strict();
|
|
21
|
+
export const platformTeamSkillRestoreSchema = z.object({ version: z.number().int().min(1), expectedVersion: z.number().int().min(1) }).strict();
|
|
22
|
+
export const platformTeamSkillSchema = z.object({ slug: platformTeamSkillSlugSchema, title: z.string(), description: z.string(), content: z.string(),
|
|
23
|
+
version: z.number().int().min(1), createdAt: z.string(), updatedAt: z.string() });
|
|
24
|
+
export const platformTeamSkillSummarySchema = platformTeamSkillSchema.omit({ content: true });
|
|
25
|
+
export const platformTeamSkillVersionSchema = z.object({ version: z.number().int().min(1), title: z.string(), createdAt: z.string() });
|
|
26
|
+
export const platformSuggestionSchema = z.discriminatedUnion("kind", [
|
|
27
|
+
z.object({ kind: z.literal("custom_tool"), occurrences: z.number().int().min(2), lastSeenAt: z.string(),
|
|
28
|
+
executions: z.array(z.string()).min(1).max(3),
|
|
29
|
+
code: z.string().min(1).max(PLATFORM_CUSTOM_TOOL_LIMITS.codeChars) }),
|
|
30
|
+
z.object({ kind: z.literal("skill"), occurrences: z.number().int().min(2), lastSeenAt: z.string(), tools: z.array(z.string()).min(2).max(3) }),
|
|
31
|
+
]);
|
|
32
|
+
export const platformSuggestionsSchema = z.object({ suggestions: z.array(platformSuggestionSchema).max(20), since: z.string() });
|
|
33
|
+
export const platformTeamSkillHistorySchema = platformTeamSkillVersionSchema.extend({ author: platformVersionAuthorSchema });
|
|
34
|
+
export const platformTeamSkillVersionDetailSchema = platformTeamSkillSchema.pick({ title: true, description: true, content: true })
|
|
35
|
+
.extend({ version: z.number().int().min(1), createdAt: z.string(), author: platformVersionAuthorSchema });
|
|
36
|
+
const skillInput = projectScopeSchema.extend({ slug: platformTeamSkillSlugSchema });
|
|
37
|
+
const skillResult = z.object({ skill: platformTeamSkillSchema }).strict();
|
|
38
|
+
export const platformTeamSkillContracts = {
|
|
39
|
+
listDeveloperTeamSkills: { input: projectScopeSchema.strict(), output: z.object({ skills: z.array(platformTeamSkillSummarySchema.extend({ canEdit: z.boolean(), canDelete: z.boolean() })),
|
|
40
|
+
canCreate: z.boolean() }).strict() },
|
|
41
|
+
getDeveloperTeamSkill: { input: skillInput.strict(), output: skillResult },
|
|
42
|
+
createDeveloperTeamSkill: { input: projectScopeSchema.extend({ skill: platformTeamSkillCreateSchema }).strict(), output: skillResult },
|
|
43
|
+
updateDeveloperTeamSkill: { input: skillInput.extend({ skill: platformTeamSkillUpdateSchema }).strict(), output: skillResult },
|
|
44
|
+
restoreDeveloperTeamSkill: { input: skillInput.merge(platformTeamSkillRestoreSchema).strict(), output: skillResult },
|
|
45
|
+
deleteDeveloperTeamSkill: { input: skillInput.strict(), output: z.object({ success: z.literal(true) }).strict() },
|
|
46
|
+
listDeveloperTeamSkillVersions: { input: skillInput.strict(), output: z.object({ versions: z.array(platformTeamSkillHistorySchema) }).strict() },
|
|
47
|
+
getDeveloperTeamSkillVersion: { input: skillInput.extend({ version: z.number().int().min(1) }).strict(), output: z.object({ version: platformTeamSkillVersionDetailSchema }).strict() },
|
|
48
|
+
listDeveloperSuggestions: { input: projectScopeSchema.strict(), output: platformSuggestionsSchema },
|
|
49
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { platformCustomToolNameSchema } from "./platformCustomTools.js";
|
|
3
|
+
import { PLATFORM_TEAM_SECRET_NAME } from "./platformTeamSecretName.js";
|
|
4
|
+
import { PLATFORM_TEAM_SKILL_SLUG } from "./platformTeamSkills.js";
|
|
5
|
+
const connectionId = z.string().regex(/^[A-Za-z0-9-]{1,64}$/), projectId = connectionId;
|
|
6
|
+
export const platformConnectionGrantSchema = z.templateLiteral(["connection:", connectionId]);
|
|
7
|
+
export const platformConnectionOperationGrantSchema = z.templateLiteral(["connection:", connectionId, "/", z.string().regex(/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/)]);
|
|
8
|
+
export const platformSkillGrantSchema = z.templateLiteral(["skill:", projectId, "/", z.string().regex(PLATFORM_TEAM_SKILL_SLUG)]);
|
|
9
|
+
export const platformSecretGrantSchema = z.templateLiteral(["secret:", projectId, "/", z.string().regex(PLATFORM_TEAM_SECRET_NAME)]);
|
|
10
|
+
export const memberToolAccessSchema = z.array(z.union([platformCustomToolNameSchema, platformConnectionGrantSchema, platformConnectionOperationGrantSchema,
|
|
11
|
+
platformSkillGrantSchema, platformSecretGrantSchema])).max(20_000).nullable();
|
|
12
|
+
export const keyToolAccessSchema = memberToolAccessSchema;
|
|
13
|
+
export const platformTeamAccessSchema = z.object({
|
|
14
|
+
members: z.array(z.object({ memberId: z.string(), email: z.string(), name: z.string().nullable(), role: z.string(), toolAccess: memberToolAccessSchema }).loose()),
|
|
15
|
+
invitations: z.array(z.object({ id: z.string(), email: z.string(), role: z.string(), expiresAt: z.string(), toolAccess: memberToolAccessSchema }).loose()),
|
|
16
|
+
});
|
|
17
|
+
export const platformMemberAccessUpdateSchema = z.object({ toolAccess: memberToolAccessSchema }).strict();
|
|
18
|
+
export const memberTeamSkillAccessSchema = z.enum(["EDIT", "OWN", "READ"]);
|