@nextclaw/server 0.13.4 → 0.13.6
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/dist/index.d.ts +138 -41
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +447 -353
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -832,23 +832,6 @@ async function connectChannelAuth(params) {
|
|
|
832
832
|
return toPublicChannelAuthPollResult(result);
|
|
833
833
|
}
|
|
834
834
|
//#endregion
|
|
835
|
-
//#region src/features/config/utils/default-provider-config.utils.ts
|
|
836
|
-
function createDefaultProviderConfig(defaultWireApi = "auto", defaultModels = [], modelConfig = {}) {
|
|
837
|
-
return {
|
|
838
|
-
enabled: true,
|
|
839
|
-
displayName: "",
|
|
840
|
-
apiKey: "",
|
|
841
|
-
apiBase: null,
|
|
842
|
-
extraHeaders: null,
|
|
843
|
-
wireApi: defaultWireApi,
|
|
844
|
-
models: [...defaultModels],
|
|
845
|
-
modelConfig
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
function createDefaultProviderConfigFromSpec(spec) {
|
|
849
|
-
return createDefaultProviderConfig(spec?.defaultWireApi ?? "auto", spec?.defaultModels ?? [], normalizeProviderModelConfig(spec?.modelConfig ?? {}));
|
|
850
|
-
}
|
|
851
|
-
//#endregion
|
|
852
835
|
//#region src/features/config/providers/server-builtin-provider.provider.ts
|
|
853
836
|
const SERVER_BUILTIN_PROVIDER_OVERRIDES = [{
|
|
854
837
|
name: "minimax-portal",
|
|
@@ -864,7 +847,12 @@ const SERVER_BUILTIN_PROVIDER_OVERRIDES = [{
|
|
|
864
847
|
detectByKeyPrefix: "",
|
|
865
848
|
detectByBaseKeyword: "",
|
|
866
849
|
defaultApiBase: "https://api.minimax.io/v1",
|
|
867
|
-
defaultModels: [
|
|
850
|
+
defaultModels: [
|
|
851
|
+
"minimax-portal/MiniMax-M3",
|
|
852
|
+
"minimax-portal/MiniMax-M2.5",
|
|
853
|
+
"minimax-portal/MiniMax-M2.5-highspeed"
|
|
854
|
+
],
|
|
855
|
+
modelConfig: { "minimax-portal/MiniMax-M3": { vision: true } },
|
|
868
856
|
stripModelPrefix: false,
|
|
869
857
|
modelOverrides: [],
|
|
870
858
|
logo: "minimax.svg",
|
|
@@ -1068,15 +1056,33 @@ function readFieldAsString(source, fieldName) {
|
|
|
1068
1056
|
function setProviderApiKey({ configPath, provider, accessToken, defaultApiBase }) {
|
|
1069
1057
|
const config = loadConfig(configPath);
|
|
1070
1058
|
const providers = config.providers;
|
|
1071
|
-
if (!providers[provider])
|
|
1059
|
+
if (!providers[provider]) return;
|
|
1072
1060
|
const target = providers[provider];
|
|
1073
1061
|
target.apiKey = accessToken;
|
|
1074
|
-
if (
|
|
1062
|
+
if (defaultApiBase) target.apiBase = defaultApiBase;
|
|
1075
1063
|
saveConfig(ConfigSchema.parse(config), configPath);
|
|
1076
1064
|
}
|
|
1077
|
-
|
|
1065
|
+
function resolveProviderAuthTarget(configPath, providerId) {
|
|
1066
|
+
const provider = loadConfig(configPath).providers[providerId];
|
|
1067
|
+
if (!provider) return null;
|
|
1068
|
+
const configuredType = typeof provider.providerType === "string" ? provider.providerType.trim() : "";
|
|
1069
|
+
if (configuredType && findServerBuiltinProviderByName(configuredType)) return {
|
|
1070
|
+
providerId,
|
|
1071
|
+
providerType: configuredType,
|
|
1072
|
+
provider
|
|
1073
|
+
};
|
|
1074
|
+
if (findServerBuiltinProviderByName(providerId)) return {
|
|
1075
|
+
providerId,
|
|
1076
|
+
providerType: providerId,
|
|
1077
|
+
provider
|
|
1078
|
+
};
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
async function startProviderAuth(configPath, providerId, options) {
|
|
1078
1082
|
cleanupExpiredAuthSessions();
|
|
1079
|
-
const
|
|
1083
|
+
const target = resolveProviderAuthTarget(configPath, providerId);
|
|
1084
|
+
if (!target) return null;
|
|
1085
|
+
const spec = findServerBuiltinProviderByName(target.providerType);
|
|
1080
1086
|
if (!spec?.auth || spec.auth.kind !== "device_code") return null;
|
|
1081
1087
|
const resolvedMethod = resolveAuthMethod(spec.auth, options?.methodId);
|
|
1082
1088
|
const { deviceCodeEndpoint, tokenEndpoint } = resolveDeviceCodeEndpoints(resolvedMethod.baseUrl, resolvedMethod.deviceCodePath, resolvedMethod.tokenPath);
|
|
@@ -1150,7 +1156,8 @@ async function startProviderAuth(configPath, providerName, options) {
|
|
|
1150
1156
|
const sessionId = randomUUID();
|
|
1151
1157
|
authSessions.set(sessionId, {
|
|
1152
1158
|
sessionId,
|
|
1153
|
-
|
|
1159
|
+
providerId,
|
|
1160
|
+
providerType: target.providerType,
|
|
1154
1161
|
configPath,
|
|
1155
1162
|
authorizationCode,
|
|
1156
1163
|
tokenCodeField,
|
|
@@ -1168,7 +1175,7 @@ async function startProviderAuth(configPath, providerName, options) {
|
|
|
1168
1175
|
const methodLabel = methodConfig ? resolveLocalizedMethodLabel(methodConfig, resolvedMethod.id ?? "") : void 0;
|
|
1169
1176
|
const methodHint = methodConfig ? resolveLocalizedMethodHint(methodConfig) : void 0;
|
|
1170
1177
|
return {
|
|
1171
|
-
provider:
|
|
1178
|
+
provider: providerId,
|
|
1172
1179
|
kind: "device_code",
|
|
1173
1180
|
methodId: resolvedMethod.id,
|
|
1174
1181
|
sessionId,
|
|
@@ -1180,14 +1187,14 @@ async function startProviderAuth(configPath, providerName, options) {
|
|
|
1180
1187
|
};
|
|
1181
1188
|
}
|
|
1182
1189
|
async function pollProviderAuth(params) {
|
|
1183
|
-
const { configPath, providerName, sessionId } = params;
|
|
1190
|
+
const { configPath, providerName: providerId, sessionId } = params;
|
|
1184
1191
|
cleanupExpiredAuthSessions();
|
|
1185
1192
|
const session = authSessions.get(sessionId);
|
|
1186
|
-
if (!session || session.
|
|
1193
|
+
if (!session || session.providerId !== providerId || session.configPath !== configPath) return null;
|
|
1187
1194
|
if (Date.now() >= session.expiresAtMs) {
|
|
1188
1195
|
authSessions.delete(sessionId);
|
|
1189
1196
|
return {
|
|
1190
|
-
provider:
|
|
1197
|
+
provider: providerId,
|
|
1191
1198
|
status: "expired",
|
|
1192
1199
|
message: "authorization session expired"
|
|
1193
1200
|
};
|
|
@@ -1216,7 +1223,7 @@ async function pollProviderAuth(params) {
|
|
|
1216
1223
|
payload = {};
|
|
1217
1224
|
}
|
|
1218
1225
|
if (!response.ok) return {
|
|
1219
|
-
provider:
|
|
1226
|
+
provider: providerId,
|
|
1220
1227
|
status: "error",
|
|
1221
1228
|
message: buildMinimaxErrorMessage(payload, raw || response.statusText || "authorization failed")
|
|
1222
1229
|
};
|
|
@@ -1224,7 +1231,7 @@ async function pollProviderAuth(params) {
|
|
|
1224
1231
|
if (status === "success") {
|
|
1225
1232
|
accessToken = payload.access_token?.trim() ?? "";
|
|
1226
1233
|
if (!accessToken) return {
|
|
1227
|
-
provider:
|
|
1234
|
+
provider: providerId,
|
|
1228
1235
|
status: "error",
|
|
1229
1236
|
message: "provider token response missing access token"
|
|
1230
1237
|
};
|
|
@@ -1233,7 +1240,7 @@ async function pollProviderAuth(params) {
|
|
|
1233
1240
|
const classified = classifyMiniMaxErrorStatus(message);
|
|
1234
1241
|
if (classified === "denied" || classified === "expired") authSessions.delete(sessionId);
|
|
1235
1242
|
return {
|
|
1236
|
-
provider:
|
|
1243
|
+
provider: providerId,
|
|
1237
1244
|
status: classified,
|
|
1238
1245
|
message
|
|
1239
1246
|
};
|
|
@@ -1242,7 +1249,7 @@ async function pollProviderAuth(params) {
|
|
|
1242
1249
|
session.intervalMs = nextPollMs;
|
|
1243
1250
|
authSessions.set(sessionId, session);
|
|
1244
1251
|
return {
|
|
1245
|
-
provider:
|
|
1252
|
+
provider: providerId,
|
|
1246
1253
|
status: "pending",
|
|
1247
1254
|
nextPollMs
|
|
1248
1255
|
};
|
|
@@ -1252,7 +1259,7 @@ async function pollProviderAuth(params) {
|
|
|
1252
1259
|
if (!response.ok) {
|
|
1253
1260
|
const errorCode = payload.error?.trim().toLowerCase();
|
|
1254
1261
|
if (errorCode === "authorization_pending") return {
|
|
1255
|
-
provider:
|
|
1262
|
+
provider: providerId,
|
|
1256
1263
|
status: "pending",
|
|
1257
1264
|
nextPollMs: session.intervalMs
|
|
1258
1265
|
};
|
|
@@ -1261,7 +1268,7 @@ async function pollProviderAuth(params) {
|
|
|
1261
1268
|
session.intervalMs = nextPollMs;
|
|
1262
1269
|
authSessions.set(sessionId, session);
|
|
1263
1270
|
return {
|
|
1264
|
-
provider:
|
|
1271
|
+
provider: providerId,
|
|
1265
1272
|
status: "pending",
|
|
1266
1273
|
nextPollMs
|
|
1267
1274
|
};
|
|
@@ -1269,7 +1276,7 @@ async function pollProviderAuth(params) {
|
|
|
1269
1276
|
if (errorCode === "access_denied") {
|
|
1270
1277
|
authSessions.delete(sessionId);
|
|
1271
1278
|
return {
|
|
1272
|
-
provider:
|
|
1279
|
+
provider: providerId,
|
|
1273
1280
|
status: "denied",
|
|
1274
1281
|
message: payload.error_description || "authorization denied"
|
|
1275
1282
|
};
|
|
@@ -1277,38 +1284,40 @@ async function pollProviderAuth(params) {
|
|
|
1277
1284
|
if (errorCode === "expired_token") {
|
|
1278
1285
|
authSessions.delete(sessionId);
|
|
1279
1286
|
return {
|
|
1280
|
-
provider:
|
|
1287
|
+
provider: providerId,
|
|
1281
1288
|
status: "expired",
|
|
1282
1289
|
message: payload.error_description || "authorization session expired"
|
|
1283
1290
|
};
|
|
1284
1291
|
}
|
|
1285
1292
|
return {
|
|
1286
|
-
provider:
|
|
1293
|
+
provider: providerId,
|
|
1287
1294
|
status: "error",
|
|
1288
1295
|
message: payload.error_description || payload.error || response.statusText || "authorization failed"
|
|
1289
1296
|
};
|
|
1290
1297
|
}
|
|
1291
1298
|
accessToken = payload.access_token?.trim() ?? "";
|
|
1292
1299
|
if (!accessToken) return {
|
|
1293
|
-
provider:
|
|
1300
|
+
provider: providerId,
|
|
1294
1301
|
status: "error",
|
|
1295
1302
|
message: "provider token response missing access token"
|
|
1296
1303
|
};
|
|
1297
1304
|
}
|
|
1298
1305
|
setProviderApiKey({
|
|
1299
1306
|
configPath,
|
|
1300
|
-
provider:
|
|
1307
|
+
provider: providerId,
|
|
1301
1308
|
accessToken,
|
|
1302
1309
|
defaultApiBase: session.defaultApiBase
|
|
1303
1310
|
});
|
|
1304
1311
|
authSessions.delete(sessionId);
|
|
1305
1312
|
return {
|
|
1306
|
-
provider:
|
|
1313
|
+
provider: providerId,
|
|
1307
1314
|
status: "authorized"
|
|
1308
1315
|
};
|
|
1309
1316
|
}
|
|
1310
|
-
async function importProviderAuthFromCli(configPath,
|
|
1311
|
-
const
|
|
1317
|
+
async function importProviderAuthFromCli(configPath, providerId) {
|
|
1318
|
+
const target = resolveProviderAuthTarget(configPath, providerId);
|
|
1319
|
+
if (!target) return null;
|
|
1320
|
+
const spec = findServerBuiltinProviderByName(target.providerType);
|
|
1312
1321
|
if (!spec?.auth || spec.auth.kind !== "device_code" || !spec.auth.cliCredential) return null;
|
|
1313
1322
|
const credentialPath = resolveHomePath(spec.auth.cliCredential.path);
|
|
1314
1323
|
if (!credentialPath) throw new Error("provider cli credential path is empty");
|
|
@@ -1334,12 +1343,12 @@ async function importProviderAuthFromCli(configPath, providerName) {
|
|
|
1334
1343
|
if (typeof expiresAtMs === "number" && expiresAtMs <= Date.now()) throw new Error("CLI credential has expired, please login again");
|
|
1335
1344
|
setProviderApiKey({
|
|
1336
1345
|
configPath,
|
|
1337
|
-
provider:
|
|
1346
|
+
provider: providerId,
|
|
1338
1347
|
accessToken,
|
|
1339
1348
|
defaultApiBase: spec.defaultApiBase
|
|
1340
1349
|
});
|
|
1341
1350
|
return {
|
|
1342
|
-
provider:
|
|
1351
|
+
provider: providerId,
|
|
1343
1352
|
status: "imported",
|
|
1344
1353
|
source: "cli",
|
|
1345
1354
|
expiresAt: expiresAtMs ? new Date(expiresAtMs).toISOString() : void 0
|
|
@@ -1405,6 +1414,13 @@ var ConfigRoutesController = class {
|
|
|
1405
1414
|
const config = loadConfigOrDefault(this.options.configPath);
|
|
1406
1415
|
return c.json(ok(buildConfigMeta(config, this.getExtensionConfigProjectionOptions())));
|
|
1407
1416
|
};
|
|
1417
|
+
listProviders = (c) => {
|
|
1418
|
+
const config = loadConfigOrDefault(this.options.configPath);
|
|
1419
|
+
return c.json(ok(buildProvidersView(config)));
|
|
1420
|
+
};
|
|
1421
|
+
listProviderTemplates = (c) => {
|
|
1422
|
+
return c.json(ok(buildProviderTemplatesView()));
|
|
1423
|
+
};
|
|
1408
1424
|
getConfigSchema = (c) => {
|
|
1409
1425
|
const config = loadConfigOrDefault(this.options.configPath);
|
|
1410
1426
|
return c.json(ok(buildConfigSchemaView(config, this.getExtensionConfigProjectionOptions())));
|
|
@@ -1435,35 +1451,36 @@ var ConfigRoutesController = class {
|
|
|
1435
1451
|
return c.json(ok(result));
|
|
1436
1452
|
};
|
|
1437
1453
|
updateProvider = async (c) => {
|
|
1438
|
-
const
|
|
1454
|
+
const providerId = c.req.param("providerId");
|
|
1439
1455
|
const body = await readJson(c.req.raw);
|
|
1440
1456
|
if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1441
|
-
const result = updateProvider(this.options.configPath,
|
|
1442
|
-
if (!result) return c.json(err("NOT_FOUND", `unknown provider: ${
|
|
1443
|
-
await this.publishConfigUpdates([`providers.${
|
|
1457
|
+
const result = updateProvider(this.options.configPath, providerId, body.data);
|
|
1458
|
+
if (!result) return c.json(err("NOT_FOUND", `unknown provider: ${providerId}`), 404);
|
|
1459
|
+
await this.publishConfigUpdates([`providers.${providerId}`]);
|
|
1444
1460
|
return c.json(ok(result));
|
|
1445
1461
|
};
|
|
1446
1462
|
createProvider = async (c) => {
|
|
1447
1463
|
const body = await readJson(c.req.raw);
|
|
1448
1464
|
if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1449
|
-
const result =
|
|
1450
|
-
|
|
1465
|
+
const result = createProvider(this.options.configPath, body.data);
|
|
1466
|
+
if (!result) return c.json(err("PROVIDER_EXISTS", "provider already exists"), 409);
|
|
1467
|
+
await this.publishConfigUpdates([`providers.${result.providerId}`]);
|
|
1451
1468
|
return c.json(ok({
|
|
1452
|
-
|
|
1469
|
+
providerId: result.providerId,
|
|
1453
1470
|
provider: result.provider
|
|
1454
1471
|
}));
|
|
1455
1472
|
};
|
|
1456
1473
|
deleteProvider = async (c) => {
|
|
1457
|
-
const
|
|
1458
|
-
if (
|
|
1459
|
-
await this.publishConfigUpdates([`providers.${
|
|
1474
|
+
const providerId = c.req.param("providerId");
|
|
1475
|
+
if (deleteProvider(this.options.configPath, providerId) === null) return c.json(err("NOT_FOUND", `provider not found: ${providerId}`), 404);
|
|
1476
|
+
await this.publishConfigUpdates([`providers.${providerId}`]);
|
|
1460
1477
|
return c.json(ok({
|
|
1461
1478
|
deleted: true,
|
|
1462
|
-
|
|
1479
|
+
providerId
|
|
1463
1480
|
}));
|
|
1464
1481
|
};
|
|
1465
1482
|
testProviderConnection = async (c) => {
|
|
1466
|
-
const provider = c.req.param("
|
|
1483
|
+
const provider = c.req.param("providerId");
|
|
1467
1484
|
const body = await readJson(c.req.raw);
|
|
1468
1485
|
if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1469
1486
|
const result = await testProviderConnection(this.options.configPath, provider, body.data, this.options.kernel.llmProviders);
|
|
@@ -1471,7 +1488,7 @@ var ConfigRoutesController = class {
|
|
|
1471
1488
|
return c.json(ok(result));
|
|
1472
1489
|
};
|
|
1473
1490
|
startProviderAuth = async (c) => {
|
|
1474
|
-
const provider = c.req.param("
|
|
1491
|
+
const provider = c.req.param("providerId");
|
|
1475
1492
|
let payload = {};
|
|
1476
1493
|
const rawBody = await c.req.raw.text();
|
|
1477
1494
|
if (rawBody.trim().length > 0) try {
|
|
@@ -1490,7 +1507,7 @@ var ConfigRoutesController = class {
|
|
|
1490
1507
|
}
|
|
1491
1508
|
};
|
|
1492
1509
|
pollProviderAuth = async (c) => {
|
|
1493
|
-
const provider = c.req.param("
|
|
1510
|
+
const provider = c.req.param("providerId");
|
|
1494
1511
|
const body = await readJson(c.req.raw);
|
|
1495
1512
|
if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1496
1513
|
const sessionId = typeof body.data.sessionId === "string" ? body.data.sessionId.trim() : "";
|
|
@@ -1505,7 +1522,7 @@ var ConfigRoutesController = class {
|
|
|
1505
1522
|
return c.json(ok(result));
|
|
1506
1523
|
};
|
|
1507
1524
|
importProviderAuthFromCli = async (c) => {
|
|
1508
|
-
const provider = c.req.param("
|
|
1525
|
+
const provider = c.req.param("providerId");
|
|
1509
1526
|
try {
|
|
1510
1527
|
const result = await importProviderAuthFromCli(this.options.configPath, provider);
|
|
1511
1528
|
if (!result) return c.json(err("NOT_SUPPORTED", `provider cli auth import is not supported: ${provider}`), 404);
|
|
@@ -1872,11 +1889,6 @@ const PREFERRED_PROVIDER_ORDER_INDEX = new Map([
|
|
|
1872
1889
|
].map((name, index) => [name, index]));
|
|
1873
1890
|
const BUILTIN_PROVIDERS = listServerBuiltinProviders();
|
|
1874
1891
|
const BUILTIN_PROVIDER_NAMES = new Set(BUILTIN_PROVIDERS.map((spec) => spec.name));
|
|
1875
|
-
const CUSTOM_PROVIDER_WIRE_API_OPTIONS = [
|
|
1876
|
-
"auto",
|
|
1877
|
-
"chat",
|
|
1878
|
-
"responses"
|
|
1879
|
-
];
|
|
1880
1892
|
const CUSTOM_PROVIDER_PREFIX = "custom-";
|
|
1881
1893
|
const PROVIDER_TEST_MAX_TOKENS = 16;
|
|
1882
1894
|
function normalizeOptionalDisplayName(value) {
|
|
@@ -1894,13 +1906,8 @@ function resolveCustomProviderFallbackDisplayName(name) {
|
|
|
1894
1906
|
}
|
|
1895
1907
|
return name;
|
|
1896
1908
|
}
|
|
1897
|
-
function
|
|
1898
|
-
|
|
1899
|
-
if (isCustomProviderName(providerName)) return configDisplayName ?? resolveCustomProviderFallbackDisplayName(providerName);
|
|
1900
|
-
return spec?.displayName ?? configDisplayName ?? spec?.name;
|
|
1901
|
-
}
|
|
1902
|
-
function listCustomProviderNames(config) {
|
|
1903
|
-
return Object.keys(config.providers).filter((name) => isCustomProviderName(name));
|
|
1909
|
+
function resolveProviderInstanceDisplayName(providerId, provider, spec) {
|
|
1910
|
+
return normalizeOptionalDisplayName(provider?.displayName) ?? spec?.displayName ?? (providerId.startsWith(CUSTOM_PROVIDER_PREFIX) ? resolveCustomProviderFallbackDisplayName(providerId) : providerId);
|
|
1904
1911
|
}
|
|
1905
1912
|
function findNextCustomProviderName(config) {
|
|
1906
1913
|
const providers = config.providers;
|
|
@@ -1908,16 +1915,39 @@ function findNextCustomProviderName(config) {
|
|
|
1908
1915
|
while (providers[`${CUSTOM_PROVIDER_PREFIX}${index}`]) index += 1;
|
|
1909
1916
|
return `${CUSTOM_PROVIDER_PREFIX}${index}`;
|
|
1910
1917
|
}
|
|
1911
|
-
function
|
|
1918
|
+
function normalizeProviderId(value) {
|
|
1919
|
+
if (typeof value !== "string") return null;
|
|
1920
|
+
const trimmed = value.trim();
|
|
1921
|
+
if (!trimmed || trimmed.includes("/")) return null;
|
|
1922
|
+
return trimmed;
|
|
1923
|
+
}
|
|
1924
|
+
function resolveProviderType(providerId, provider) {
|
|
1925
|
+
const configuredType = normalizeProviderId(provider?.providerType);
|
|
1926
|
+
if (configuredType && findServerBuiltinProviderByName(configuredType)) return configuredType;
|
|
1927
|
+
if (findServerBuiltinProviderByName(providerId)) return providerId;
|
|
1928
|
+
return null;
|
|
1929
|
+
}
|
|
1930
|
+
function findNextProviderId(config, baseProviderId) {
|
|
1912
1931
|
const providers = config.providers;
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1932
|
+
let providerId = baseProviderId;
|
|
1933
|
+
let index = 2;
|
|
1934
|
+
while (providers[providerId]) {
|
|
1935
|
+
providerId = `${baseProviderId}-${index}`;
|
|
1936
|
+
index += 1;
|
|
1937
|
+
}
|
|
1938
|
+
return providerId;
|
|
1939
|
+
}
|
|
1940
|
+
function resolveProviderDisplayNameSuffix(providerId, baseProviderId) {
|
|
1941
|
+
if (providerId === baseProviderId) return "";
|
|
1942
|
+
const suffix = providerId.slice(baseProviderId.length + 1).trim();
|
|
1943
|
+
return suffix ? ` ${suffix}` : "";
|
|
1944
|
+
}
|
|
1945
|
+
function buildProviderScopedModels(providerId, models) {
|
|
1946
|
+
return normalizeModelList(models).map((model) => {
|
|
1947
|
+
const slashIndex = model.indexOf("/");
|
|
1948
|
+
const modelSuffix = slashIndex >= 0 ? model.slice(slashIndex + 1).trim() : model;
|
|
1949
|
+
return modelSuffix ? `${providerId}/${modelSuffix}` : "";
|
|
1950
|
+
}).filter(Boolean);
|
|
1921
1951
|
}
|
|
1922
1952
|
function clearSecretRefsByPrefix(refs, pathPrefix) {
|
|
1923
1953
|
return Object.fromEntries(Object.entries(refs).filter(([key]) => key !== pathPrefix && !key.startsWith(`${pathPrefix}.`)));
|
|
@@ -2082,13 +2112,18 @@ function normalizeModelList(input) {
|
|
|
2082
2112
|
}
|
|
2083
2113
|
return [...deduped];
|
|
2084
2114
|
}
|
|
2085
|
-
function toProviderView(config, provider,
|
|
2086
|
-
const
|
|
2115
|
+
function toProviderView(config, provider, providerId, uiHints, spec) {
|
|
2116
|
+
const providerType = resolveProviderType(providerId, provider);
|
|
2117
|
+
const apiKeyRefSet = hasSecretRef(config, `providers.${providerId}.apiKey`);
|
|
2087
2118
|
const masked = maskApiKey(provider.apiKey);
|
|
2088
|
-
const extraHeaders = provider.extraHeaders && Object.keys(provider.extraHeaders).length > 0 ? sanitizePublicConfigValue(provider.extraHeaders, `providers.${
|
|
2119
|
+
const extraHeaders = provider.extraHeaders && Object.keys(provider.extraHeaders).length > 0 ? sanitizePublicConfigValue(provider.extraHeaders, `providers.${providerId}.extraHeaders`, uiHints) : null;
|
|
2089
2120
|
const view = {
|
|
2121
|
+
providerId,
|
|
2122
|
+
providerType,
|
|
2123
|
+
isBuiltInType: providerType !== null,
|
|
2124
|
+
isCustom: providerType === null,
|
|
2090
2125
|
enabled: provider.enabled !== false,
|
|
2091
|
-
displayName:
|
|
2126
|
+
displayName: resolveProviderInstanceDisplayName(providerId, provider, spec),
|
|
2092
2127
|
apiKeySet: masked.apiKeySet || apiKeyRefSet,
|
|
2093
2128
|
apiKeyMasked: masked.apiKeyMasked ?? (apiKeyRefSet ? "****" : void 0),
|
|
2094
2129
|
apiBase: provider.apiBase ?? null,
|
|
@@ -2096,14 +2131,17 @@ function toProviderView(config, provider, providerName, uiHints, spec) {
|
|
|
2096
2131
|
models: normalizeModelList(provider.models ?? []),
|
|
2097
2132
|
modelConfig: normalizeProviderModelConfig(provider.modelConfig ?? {})
|
|
2098
2133
|
};
|
|
2099
|
-
if (Boolean(spec?.supportsWireApi) ||
|
|
2134
|
+
if (Boolean(spec?.supportsWireApi) || providerType === null) view.wireApi = provider.wireApi ?? spec?.defaultWireApi ?? "auto";
|
|
2100
2135
|
return view;
|
|
2101
2136
|
}
|
|
2102
2137
|
function buildConfigView(config, options) {
|
|
2103
2138
|
const uiHints = buildUiHints(config, options);
|
|
2104
2139
|
const projectedChannels = getProjectedChannelMap(config, options);
|
|
2105
2140
|
const providers = {};
|
|
2106
|
-
for (const [
|
|
2141
|
+
for (const [providerId, provider] of Object.entries(config.providers)) {
|
|
2142
|
+
const providerConfig = provider;
|
|
2143
|
+
providers[providerId] = toProviderView(config, providerConfig, providerId, uiHints, findServerBuiltinProviderByName(resolveProviderType(providerId, providerConfig) ?? ""));
|
|
2144
|
+
}
|
|
2107
2145
|
return {
|
|
2108
2146
|
companion: sanitizePublicConfigValue(config.companion, "companion", uiHints),
|
|
2109
2147
|
agents: sanitizePublicConfigValue(config.agents, "agents", uiHints),
|
|
@@ -2182,13 +2220,18 @@ function clearSecretRef(refs, path) {
|
|
|
2182
2220
|
return nextRefs;
|
|
2183
2221
|
}
|
|
2184
2222
|
function buildConfigMeta(config, options) {
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2223
|
+
return {
|
|
2224
|
+
search: SEARCH_PROVIDER_META,
|
|
2225
|
+
channels: buildProjectedChannelMeta(config, options)
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
function buildProviderTemplatesView() {
|
|
2229
|
+
return { providerTemplates: BUILTIN_PROVIDERS.map((spec) => {
|
|
2188
2230
|
return {
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2231
|
+
id: spec.name,
|
|
2232
|
+
providerType: spec.name,
|
|
2233
|
+
displayName: spec.displayName ?? spec.name,
|
|
2234
|
+
apiProtocol: spec.apiProtocol,
|
|
2192
2235
|
modelPrefix: spec.modelPrefix,
|
|
2193
2236
|
keywords: spec.keywords,
|
|
2194
2237
|
envKey: spec.envKey,
|
|
@@ -2216,43 +2259,22 @@ function buildConfigMeta(config, options) {
|
|
|
2216
2259
|
defaultWireApi: spec.defaultWireApi
|
|
2217
2260
|
};
|
|
2218
2261
|
}).sort((left, right) => {
|
|
2219
|
-
const leftRank = PREFERRED_PROVIDER_ORDER_INDEX.get(left.
|
|
2220
|
-
const rightRank = PREFERRED_PROVIDER_ORDER_INDEX.get(right.
|
|
2262
|
+
const leftRank = PREFERRED_PROVIDER_ORDER_INDEX.get(left.id);
|
|
2263
|
+
const rightRank = PREFERRED_PROVIDER_ORDER_INDEX.get(right.id);
|
|
2221
2264
|
if (leftRank !== void 0 && rightRank !== void 0) return leftRank - rightRank;
|
|
2222
2265
|
if (leftRank !== void 0) return -1;
|
|
2223
2266
|
if (rightRank !== void 0) return 1;
|
|
2224
|
-
return left.
|
|
2225
|
-
});
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
displayName,
|
|
2236
|
-
isCustom: true,
|
|
2237
|
-
modelPrefix: name,
|
|
2238
|
-
keywords: normalizeModelList([name, displayName ?? ""]),
|
|
2239
|
-
envKey: "OPENAI_API_KEY",
|
|
2240
|
-
isGateway: false,
|
|
2241
|
-
isLocal: false,
|
|
2242
|
-
defaultApiBase: void 0,
|
|
2243
|
-
logo: void 0,
|
|
2244
|
-
apiBaseHelp: void 0,
|
|
2245
|
-
auth: void 0,
|
|
2246
|
-
defaultModels: [],
|
|
2247
|
-
modelConfig: {},
|
|
2248
|
-
supportsWireApi: true,
|
|
2249
|
-
wireApiOptions: CUSTOM_PROVIDER_WIRE_API_OPTIONS,
|
|
2250
|
-
defaultWireApi: "auto"
|
|
2251
|
-
};
|
|
2252
|
-
}), ...builtinProviders],
|
|
2253
|
-
search: SEARCH_PROVIDER_META,
|
|
2254
|
-
channels: buildProjectedChannelMeta(config, options)
|
|
2255
|
-
};
|
|
2267
|
+
return left.id.localeCompare(right.id);
|
|
2268
|
+
}) };
|
|
2269
|
+
}
|
|
2270
|
+
function buildProvidersView(config) {
|
|
2271
|
+
const uiHints = buildUiHints(config);
|
|
2272
|
+
const providers = {};
|
|
2273
|
+
for (const [providerId, provider] of Object.entries(config.providers)) {
|
|
2274
|
+
const providerConfig = provider;
|
|
2275
|
+
providers[providerId] = toProviderView(config, providerConfig, providerId, uiHints, findServerBuiltinProviderByName(resolveProviderType(providerId, providerConfig) ?? ""));
|
|
2276
|
+
}
|
|
2277
|
+
return { providers };
|
|
2256
2278
|
}
|
|
2257
2279
|
function buildConfigSchemaView(_config, options) {
|
|
2258
2280
|
const base = buildConfigSchema({ version: getPackageVersion() });
|
|
@@ -2315,60 +2337,67 @@ function updateModel(configPath, patch) {
|
|
|
2315
2337
|
saveConfig(next, configPath);
|
|
2316
2338
|
return buildConfigView(next);
|
|
2317
2339
|
}
|
|
2318
|
-
function updateProvider(configPath,
|
|
2340
|
+
function updateProvider(configPath, providerId, patch) {
|
|
2319
2341
|
const config = loadConfigOrDefault(configPath);
|
|
2320
|
-
const provider =
|
|
2342
|
+
const provider = config.providers[providerId];
|
|
2321
2343
|
if (!provider) return null;
|
|
2322
|
-
const
|
|
2323
|
-
const
|
|
2324
|
-
if (Object.prototype.hasOwnProperty.call(patch, "
|
|
2344
|
+
const currentProviderType = resolveProviderType(providerId, provider);
|
|
2345
|
+
const spec = findServerBuiltinProviderByName((Object.prototype.hasOwnProperty.call(patch, "providerType") ? normalizeProviderId(patch.providerType) : currentProviderType) ?? "");
|
|
2346
|
+
if (Object.prototype.hasOwnProperty.call(patch, "providerType")) provider.providerType = spec?.name ?? null;
|
|
2347
|
+
if (Object.prototype.hasOwnProperty.call(patch, "displayName")) provider.displayName = normalizeOptionalDisplayName(patch.displayName) ?? "";
|
|
2325
2348
|
if (Object.prototype.hasOwnProperty.call(patch, "enabled")) provider.enabled = patch.enabled !== false;
|
|
2326
2349
|
if (Object.prototype.hasOwnProperty.call(patch, "apiKey")) {
|
|
2327
2350
|
provider.apiKey = patch.apiKey ?? "";
|
|
2328
|
-
config.secrets.refs = clearSecretRef(config.secrets.refs, `providers.${
|
|
2351
|
+
config.secrets.refs = clearSecretRef(config.secrets.refs, `providers.${providerId}.apiKey`);
|
|
2329
2352
|
}
|
|
2330
2353
|
if (Object.prototype.hasOwnProperty.call(patch, "apiBase")) provider.apiBase = patch.apiBase ?? null;
|
|
2331
2354
|
if (Object.prototype.hasOwnProperty.call(patch, "extraHeaders")) provider.extraHeaders = patch.extraHeaders ?? null;
|
|
2332
|
-
if (Object.prototype.hasOwnProperty.call(patch, "wireApi") && (spec?.supportsWireApi ||
|
|
2355
|
+
if (Object.prototype.hasOwnProperty.call(patch, "wireApi") && (spec?.supportsWireApi || !spec)) provider.wireApi = patch.wireApi ?? spec?.defaultWireApi ?? "auto";
|
|
2333
2356
|
if (Object.prototype.hasOwnProperty.call(patch, "models")) provider.models = normalizeModelList(patch.models ?? []);
|
|
2334
2357
|
if (Object.prototype.hasOwnProperty.call(patch, "modelConfig")) provider.modelConfig = normalizeProviderModelConfig(patch.modelConfig ?? {});
|
|
2335
2358
|
const next = ConfigSchema.parse(config);
|
|
2336
2359
|
saveConfig(next, configPath);
|
|
2337
2360
|
const uiHints = buildUiHints(next);
|
|
2338
|
-
const updated = next.providers[
|
|
2339
|
-
return toProviderView(next, updated,
|
|
2361
|
+
const updated = next.providers[providerId];
|
|
2362
|
+
return toProviderView(next, updated, providerId, uiHints, spec ?? void 0);
|
|
2340
2363
|
}
|
|
2341
|
-
function
|
|
2364
|
+
function createProvider(configPath, patch = {}) {
|
|
2342
2365
|
const config = loadConfigOrDefault(configPath);
|
|
2343
|
-
const providerName = findNextCustomProviderName(config);
|
|
2344
2366
|
const providers = config.providers;
|
|
2345
|
-
const
|
|
2346
|
-
|
|
2367
|
+
const requestedProviderType = normalizeProviderId(patch.providerType);
|
|
2368
|
+
const spec = requestedProviderType ? findServerBuiltinProviderByName(requestedProviderType) : void 0;
|
|
2369
|
+
const fallbackProviderId = spec ? spec.name : findNextCustomProviderName(config);
|
|
2370
|
+
const requestedProviderId = normalizeProviderId(patch.providerId);
|
|
2371
|
+
if (requestedProviderId && providers[requestedProviderId]) return null;
|
|
2372
|
+
const providerId = requestedProviderId ? requestedProviderId : findNextProviderId(config, fallbackProviderId);
|
|
2373
|
+
const generatedDisplayName = spec ? `${spec.displayName}${resolveProviderDisplayNameSuffix(providerId, spec.name)}` : resolveCustomProviderFallbackDisplayName(providerId);
|
|
2374
|
+
const defaultModels = spec ? buildProviderScopedModels(providerId, spec.defaultModels ?? []) : [];
|
|
2375
|
+
providers[providerId] = {
|
|
2347
2376
|
enabled: patch.enabled !== false,
|
|
2377
|
+
providerType: spec?.name ?? null,
|
|
2348
2378
|
displayName: normalizeOptionalDisplayName(patch.displayName) ?? generatedDisplayName,
|
|
2349
2379
|
apiKey: normalizeOptionalString(patch.apiKey) ?? "",
|
|
2350
|
-
apiBase: normalizeOptionalString(patch.apiBase),
|
|
2380
|
+
apiBase: normalizeOptionalString(patch.apiBase) ?? spec?.defaultApiBase ?? null,
|
|
2351
2381
|
extraHeaders: normalizeHeaders(patch.extraHeaders ?? null),
|
|
2352
|
-
wireApi: patch.wireApi ?? "auto",
|
|
2353
|
-
models: normalizeModelList(patch.models ?? []),
|
|
2354
|
-
modelConfig: normalizeProviderModelConfig(patch.modelConfig ?? {})
|
|
2382
|
+
wireApi: patch.wireApi ?? spec?.defaultWireApi ?? "auto",
|
|
2383
|
+
models: Object.prototype.hasOwnProperty.call(patch, "models") ? normalizeModelList(patch.models ?? []) : defaultModels,
|
|
2384
|
+
modelConfig: normalizeProviderModelConfig(patch.modelConfig ?? spec?.modelConfig ?? {})
|
|
2355
2385
|
};
|
|
2356
2386
|
const next = ConfigSchema.parse(config);
|
|
2357
2387
|
saveConfig(next, configPath);
|
|
2358
2388
|
const uiHints = buildUiHints(next);
|
|
2359
|
-
const created = next.providers[
|
|
2389
|
+
const created = next.providers[providerId];
|
|
2360
2390
|
return {
|
|
2361
|
-
|
|
2362
|
-
provider: toProviderView(next, created,
|
|
2391
|
+
providerId,
|
|
2392
|
+
provider: toProviderView(next, created, providerId, uiHints, spec)
|
|
2363
2393
|
};
|
|
2364
2394
|
}
|
|
2365
|
-
function
|
|
2366
|
-
if (!isCustomProviderName(providerName)) return null;
|
|
2395
|
+
function deleteProvider(configPath, providerId) {
|
|
2367
2396
|
const config = loadConfigOrDefault(configPath);
|
|
2368
2397
|
const providers = config.providers;
|
|
2369
|
-
if (!providers[
|
|
2370
|
-
delete providers[
|
|
2371
|
-
config.secrets.refs = clearSecretRefsByPrefix(config.secrets.refs, `providers.${
|
|
2398
|
+
if (!providers[providerId]) return null;
|
|
2399
|
+
delete providers[providerId];
|
|
2400
|
+
config.secrets.refs = clearSecretRefsByPrefix(config.secrets.refs, `providers.${providerId}`);
|
|
2372
2401
|
saveConfig(ConfigSchema.parse(config), configPath);
|
|
2373
2402
|
return true;
|
|
2374
2403
|
}
|
|
@@ -2408,32 +2437,35 @@ function buildScopedProviderModel(providerName, model, spec) {
|
|
|
2408
2437
|
if (!prefix) return trimmed;
|
|
2409
2438
|
return `${prefix}/${trimmed}`;
|
|
2410
2439
|
}
|
|
2411
|
-
function
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2440
|
+
function stripProviderIdPrefix(providerId, model) {
|
|
2441
|
+
const prefix = `${providerId}/`;
|
|
2442
|
+
if (!model.startsWith(prefix)) return model;
|
|
2443
|
+
return model.slice(prefix.length).trim() || model;
|
|
2444
|
+
}
|
|
2445
|
+
function resolveTestModel(config, providerId, requestedModel, provider, spec) {
|
|
2446
|
+
if (requestedModel) return spec ? requestedModel.replace(`${providerId}/`, `${spec.name}/`) : stripProviderIdPrefix(providerId, requestedModel);
|
|
2447
|
+
const providerModels = normalizeModelList(provider.models ?? []).map((modelId) => {
|
|
2448
|
+
const providerModel = stripProviderIdPrefix(providerId, modelId);
|
|
2449
|
+
return spec ? buildScopedProviderModel(spec.name, providerModel, spec) : providerModel;
|
|
2450
|
+
}).filter((modelId) => modelId.length > 0);
|
|
2420
2451
|
if (providerModels.length > 0) return providerModels[0];
|
|
2421
2452
|
const defaultModel = normalizeOptionalString(config.agents.defaults.model);
|
|
2422
2453
|
if (defaultModel) {
|
|
2423
2454
|
const routedProvider = getProviderName(config, defaultModel);
|
|
2424
|
-
if (!routedProvider || routedProvider ===
|
|
2455
|
+
if (!routedProvider || routedProvider === providerId) return spec ? defaultModel.replace(`${providerId}/`, `${spec.name}/`) : stripProviderIdPrefix(providerId, defaultModel);
|
|
2425
2456
|
}
|
|
2426
|
-
if (
|
|
2457
|
+
if (!spec) return null;
|
|
2427
2458
|
return normalizeModelList(spec?.defaultModels ?? [])[0] ?? null ?? defaultModel ?? null;
|
|
2428
2459
|
}
|
|
2429
2460
|
function stringifyError(error) {
|
|
2430
2461
|
return (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim();
|
|
2431
2462
|
}
|
|
2432
|
-
async function testProviderConnection(configPath,
|
|
2463
|
+
async function testProviderConnection(configPath, providerId, patch, providerManager) {
|
|
2433
2464
|
const config = loadConfigOrDefault(configPath);
|
|
2434
|
-
const provider =
|
|
2465
|
+
const provider = config.providers[providerId];
|
|
2435
2466
|
if (!provider) return null;
|
|
2436
|
-
const
|
|
2467
|
+
const providerType = resolveProviderType(providerId, provider);
|
|
2468
|
+
const spec = findServerBuiltinProviderByName(providerType ?? "");
|
|
2437
2469
|
const hasApiKeyPatch = Object.prototype.hasOwnProperty.call(patch, "apiKey");
|
|
2438
2470
|
const providedApiKey = normalizeOptionalString(patch.apiKey);
|
|
2439
2471
|
const currentApiKey = normalizeOptionalString(provider.apiKey);
|
|
@@ -2443,32 +2475,31 @@ async function testProviderConnection(configPath, providerName, patch, providerM
|
|
|
2443
2475
|
const currentApiBase = normalizeOptionalString(provider.apiBase);
|
|
2444
2476
|
const apiBase = hasApiBasePatch ? patchedApiBase ?? spec?.defaultApiBase ?? null : currentApiBase ?? spec?.defaultApiBase ?? null;
|
|
2445
2477
|
const extraHeaders = Object.prototype.hasOwnProperty.call(patch, "extraHeaders") ? normalizeHeaders(patch.extraHeaders ?? null) : normalizeHeaders(provider.extraHeaders ?? null);
|
|
2446
|
-
const
|
|
2447
|
-
const wireApi = spec?.supportsWireApi || isCustom ? patch.wireApi ?? provider.wireApi ?? spec?.defaultWireApi ?? "auto" : null;
|
|
2478
|
+
const wireApi = spec?.supportsWireApi || !spec ? patch.wireApi ?? provider.wireApi ?? spec?.defaultWireApi ?? "auto" : null;
|
|
2448
2479
|
if (!apiKey && !spec?.isLocal) return {
|
|
2449
2480
|
success: false,
|
|
2450
|
-
provider:
|
|
2481
|
+
provider: providerId,
|
|
2451
2482
|
latencyMs: 0,
|
|
2452
2483
|
message: "API key is required before testing the connection."
|
|
2453
2484
|
};
|
|
2454
|
-
const model = resolveTestModel(config,
|
|
2485
|
+
const model = resolveTestModel(config, providerId, normalizeOptionalString(patch.model), provider, spec ?? void 0);
|
|
2455
2486
|
if (!model) return {
|
|
2456
2487
|
success: false,
|
|
2457
|
-
provider:
|
|
2488
|
+
provider: providerId,
|
|
2458
2489
|
latencyMs: 0,
|
|
2459
2490
|
message: "No test model found. Configure provider models or set a default model for this provider, then try again."
|
|
2460
2491
|
};
|
|
2461
2492
|
const startedAtMs = Date.now();
|
|
2462
2493
|
if (!providerManager) return {
|
|
2463
2494
|
success: false,
|
|
2464
|
-
provider:
|
|
2495
|
+
provider: providerId,
|
|
2465
2496
|
model,
|
|
2466
2497
|
latencyMs: Date.now() - startedAtMs,
|
|
2467
2498
|
message: "Provider manager is unavailable."
|
|
2468
2499
|
};
|
|
2469
2500
|
try {
|
|
2470
2501
|
await providerManager.testConnection({
|
|
2471
|
-
providerName,
|
|
2502
|
+
providerName: providerType,
|
|
2472
2503
|
apiKey,
|
|
2473
2504
|
apiBase,
|
|
2474
2505
|
defaultModel: model,
|
|
@@ -2482,7 +2513,7 @@ async function testProviderConnection(configPath, providerName, patch, providerM
|
|
|
2482
2513
|
});
|
|
2483
2514
|
return {
|
|
2484
2515
|
success: true,
|
|
2485
|
-
provider:
|
|
2516
|
+
provider: providerId,
|
|
2486
2517
|
model,
|
|
2487
2518
|
latencyMs: Date.now() - startedAtMs,
|
|
2488
2519
|
message: "Connection test passed."
|
|
@@ -2490,7 +2521,7 @@ async function testProviderConnection(configPath, providerName, patch, providerM
|
|
|
2490
2521
|
} catch (error) {
|
|
2491
2522
|
return {
|
|
2492
2523
|
success: false,
|
|
2493
|
-
provider:
|
|
2524
|
+
provider: providerId,
|
|
2494
2525
|
model,
|
|
2495
2526
|
latencyMs: Date.now() - startedAtMs,
|
|
2496
2527
|
message: stringifyError(error) || "Connection test failed."
|
|
@@ -3306,6 +3337,7 @@ var McpMarketplaceController = class {
|
|
|
3306
3337
|
//#endregion
|
|
3307
3338
|
//#region src/features/marketplace/utils/marketplace-installed.utils.ts
|
|
3308
3339
|
const getWorkspacePathFromConfig = NextclawCore.getWorkspacePathFromConfig;
|
|
3340
|
+
const MARKETPLACE_INSTALL_STATE_FILE = ".nextclaw-install.json";
|
|
3309
3341
|
function createSkillsLoader(workspace) {
|
|
3310
3342
|
const ctor = NextclawCore.SkillsLoader;
|
|
3311
3343
|
if (!ctor) return null;
|
|
@@ -3319,14 +3351,21 @@ function collectInstalledSkillRecords(options) {
|
|
|
3319
3351
|
const metadata = skillsLoader?.getSkillMetadata?.(skill);
|
|
3320
3352
|
const description = readNonEmptyString(metadata?.description);
|
|
3321
3353
|
const descriptionZh = readNonEmptyString(metadata?.description_zh) ?? readNonEmptyString(metadata?.descriptionZh) ?? readNonEmptyString(MARKETPLACE_ZH_COPY_BY_SLUG[skill.name]?.description);
|
|
3354
|
+
const marketplaceState = readMarketplaceSkillInstallState(dirname(skill.path));
|
|
3355
|
+
const origin = marketplaceState ? "marketplace" : void 0;
|
|
3356
|
+
const catalogSlug = marketplaceState?.slug;
|
|
3357
|
+
const installedAt = marketplaceState?.installedAt;
|
|
3322
3358
|
return {
|
|
3323
3359
|
type: "skill",
|
|
3324
3360
|
id: skill.name,
|
|
3325
3361
|
spec: skill.name,
|
|
3326
3362
|
label: skill.name,
|
|
3327
|
-
|
|
3328
|
-
|
|
3363
|
+
description,
|
|
3364
|
+
descriptionZh,
|
|
3329
3365
|
source: skill.source,
|
|
3366
|
+
origin,
|
|
3367
|
+
catalogSlug,
|
|
3368
|
+
installedAt,
|
|
3330
3369
|
enabled,
|
|
3331
3370
|
runtimeStatus: enabled ? "enabled" : "disabled"
|
|
3332
3371
|
};
|
|
@@ -3336,6 +3375,20 @@ function collectInstalledSkillRecords(options) {
|
|
|
3336
3375
|
records
|
|
3337
3376
|
};
|
|
3338
3377
|
}
|
|
3378
|
+
function readMarketplaceSkillInstallState(destinationDir) {
|
|
3379
|
+
const statePath = join(destinationDir, MARKETPLACE_INSTALL_STATE_FILE);
|
|
3380
|
+
if (!existsSync(statePath)) return null;
|
|
3381
|
+
try {
|
|
3382
|
+
const parsed = JSON.parse(readFileSync(statePath, "utf8"));
|
|
3383
|
+
if (parsed.schemaVersion !== 1 || parsed.type !== "skill" || parsed.source !== "marketplace" || typeof parsed.slug !== "string") return null;
|
|
3384
|
+
return {
|
|
3385
|
+
slug: parsed.slug,
|
|
3386
|
+
installedAt: typeof parsed.installedAt === "string" ? parsed.installedAt : void 0
|
|
3387
|
+
};
|
|
3388
|
+
} catch {
|
|
3389
|
+
return null;
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3339
3392
|
function collectSkillMarketplaceInstalledView(options) {
|
|
3340
3393
|
const installed = collectInstalledSkillRecords(options);
|
|
3341
3394
|
return {
|
|
@@ -3390,9 +3443,24 @@ async function manageMarketplaceSkill(params) {
|
|
|
3390
3443
|
const { body, options } = params;
|
|
3391
3444
|
const action = body.action;
|
|
3392
3445
|
const targetId = typeof body.id === "string" && body.id.trim().length > 0 ? body.id.trim() : typeof body.spec === "string" && body.spec.trim().length > 0 ? body.spec.trim() : "";
|
|
3393
|
-
if (action !== "uninstall" || !targetId) throw new Error("INVALID_BODY:skill manage requires uninstall action and non-empty id/spec");
|
|
3446
|
+
if (action !== "update" && action !== "uninstall" || !targetId) throw new Error("INVALID_BODY:skill manage requires update/uninstall action and non-empty id/spec");
|
|
3394
3447
|
const installer = options.marketplace?.installer;
|
|
3395
3448
|
if (!installer) throw new Error("NOT_AVAILABLE:marketplace installer is not configured");
|
|
3449
|
+
if (action === "update") {
|
|
3450
|
+
if (!installer.updateSkill) throw new Error("NOT_AVAILABLE:skill update is not configured");
|
|
3451
|
+
const result = await installer.updateSkill({
|
|
3452
|
+
slug: targetId,
|
|
3453
|
+
force: body.force
|
|
3454
|
+
});
|
|
3455
|
+
emitConfigUpdated(options, "skills");
|
|
3456
|
+
return {
|
|
3457
|
+
type: "skill",
|
|
3458
|
+
action,
|
|
3459
|
+
id: targetId,
|
|
3460
|
+
message: result.message,
|
|
3461
|
+
output: result.output
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3396
3464
|
if (!installer.uninstallSkill) throw new Error("NOT_AVAILABLE:skill uninstall is not configured");
|
|
3397
3465
|
const result = await installer.uninstallSkill(targetId);
|
|
3398
3466
|
emitConfigUpdated(options, "skills");
|
|
@@ -4261,6 +4329,13 @@ var ServiceAppsRoutesController = class {
|
|
|
4261
4329
|
return this.handleServiceAppError(c, error);
|
|
4262
4330
|
}
|
|
4263
4331
|
};
|
|
4332
|
+
deleteServiceApp = async (c) => {
|
|
4333
|
+
try {
|
|
4334
|
+
return c.json(ok(await this.params.serviceAppManager.deleteServiceApp(c.req.param("appId"))));
|
|
4335
|
+
} catch (error) {
|
|
4336
|
+
return this.handleServiceAppError(c, error);
|
|
4337
|
+
}
|
|
4338
|
+
};
|
|
4264
4339
|
requireBridgeSession = (c) => {
|
|
4265
4340
|
const token = c.req.raw.headers.get(PANEL_BRIDGE_SESSION_HEADER)?.trim();
|
|
4266
4341
|
if (!token) throw new Error("panel app bridge session is required");
|
|
@@ -4684,182 +4759,8 @@ var UiRouteRegistry = class {
|
|
|
4684
4759
|
ncpAsset.getAssetContent
|
|
4685
4760
|
]]);
|
|
4686
4761
|
};
|
|
4687
|
-
|
|
4688
|
-
const {
|
|
4689
|
-
this.mountRoutes([
|
|
4690
|
-
[
|
|
4691
|
-
"get",
|
|
4692
|
-
"/api/health",
|
|
4693
|
-
app.health
|
|
4694
|
-
],
|
|
4695
|
-
[
|
|
4696
|
-
"get",
|
|
4697
|
-
"/api/app/meta",
|
|
4698
|
-
app.appMeta
|
|
4699
|
-
],
|
|
4700
|
-
[
|
|
4701
|
-
"get",
|
|
4702
|
-
"/api/runtime/bootstrap-status",
|
|
4703
|
-
app.bootstrapStatus
|
|
4704
|
-
],
|
|
4705
|
-
[
|
|
4706
|
-
"get",
|
|
4707
|
-
"/api/auth/status",
|
|
4708
|
-
auth.getStatus
|
|
4709
|
-
],
|
|
4710
|
-
[
|
|
4711
|
-
"post",
|
|
4712
|
-
"/api/auth/setup",
|
|
4713
|
-
auth.setup
|
|
4714
|
-
],
|
|
4715
|
-
[
|
|
4716
|
-
"post",
|
|
4717
|
-
"/api/auth/login",
|
|
4718
|
-
auth.login
|
|
4719
|
-
],
|
|
4720
|
-
[
|
|
4721
|
-
"post",
|
|
4722
|
-
"/api/auth/logout",
|
|
4723
|
-
auth.logout
|
|
4724
|
-
],
|
|
4725
|
-
[
|
|
4726
|
-
"put",
|
|
4727
|
-
"/api/auth/password",
|
|
4728
|
-
auth.updatePassword
|
|
4729
|
-
],
|
|
4730
|
-
[
|
|
4731
|
-
"put",
|
|
4732
|
-
"/api/auth/enabled",
|
|
4733
|
-
auth.updateEnabled
|
|
4734
|
-
],
|
|
4735
|
-
[
|
|
4736
|
-
"post",
|
|
4737
|
-
"/api/auth/bridge",
|
|
4738
|
-
auth.issueBridgeSession
|
|
4739
|
-
],
|
|
4740
|
-
[
|
|
4741
|
-
"get",
|
|
4742
|
-
"/api/agents",
|
|
4743
|
-
agents.listAgents
|
|
4744
|
-
],
|
|
4745
|
-
[
|
|
4746
|
-
"post",
|
|
4747
|
-
"/api/agents",
|
|
4748
|
-
agents.createAgent
|
|
4749
|
-
],
|
|
4750
|
-
[
|
|
4751
|
-
"put",
|
|
4752
|
-
"/api/agents/:agentId",
|
|
4753
|
-
agents.updateAgent
|
|
4754
|
-
],
|
|
4755
|
-
[
|
|
4756
|
-
"delete",
|
|
4757
|
-
"/api/agents/:agentId",
|
|
4758
|
-
agents.deleteAgent
|
|
4759
|
-
],
|
|
4760
|
-
[
|
|
4761
|
-
"get",
|
|
4762
|
-
"/api/agents/:agentId/avatar",
|
|
4763
|
-
agents.getAgentAvatar
|
|
4764
|
-
]
|
|
4765
|
-
]);
|
|
4766
|
-
this.mountRoutes([
|
|
4767
|
-
[
|
|
4768
|
-
"get",
|
|
4769
|
-
"/api/config",
|
|
4770
|
-
config.getConfig
|
|
4771
|
-
],
|
|
4772
|
-
[
|
|
4773
|
-
"get",
|
|
4774
|
-
"/api/config/meta",
|
|
4775
|
-
config.getConfigMeta
|
|
4776
|
-
],
|
|
4777
|
-
[
|
|
4778
|
-
"get",
|
|
4779
|
-
"/api/config/schema",
|
|
4780
|
-
config.getConfigSchema
|
|
4781
|
-
],
|
|
4782
|
-
[
|
|
4783
|
-
"put",
|
|
4784
|
-
"/api/config/model",
|
|
4785
|
-
config.updateConfigModel
|
|
4786
|
-
],
|
|
4787
|
-
[
|
|
4788
|
-
"put",
|
|
4789
|
-
"/api/config/search",
|
|
4790
|
-
config.updateConfigSearch
|
|
4791
|
-
],
|
|
4792
|
-
[
|
|
4793
|
-
"put",
|
|
4794
|
-
"/api/config/providers/:provider",
|
|
4795
|
-
config.updateProvider
|
|
4796
|
-
],
|
|
4797
|
-
[
|
|
4798
|
-
"post",
|
|
4799
|
-
"/api/config/providers",
|
|
4800
|
-
config.createProvider
|
|
4801
|
-
],
|
|
4802
|
-
[
|
|
4803
|
-
"delete",
|
|
4804
|
-
"/api/config/providers/:provider",
|
|
4805
|
-
config.deleteProvider
|
|
4806
|
-
],
|
|
4807
|
-
[
|
|
4808
|
-
"post",
|
|
4809
|
-
"/api/config/providers/:provider/test",
|
|
4810
|
-
config.testProviderConnection
|
|
4811
|
-
],
|
|
4812
|
-
[
|
|
4813
|
-
"post",
|
|
4814
|
-
"/api/config/providers/:provider/auth/start",
|
|
4815
|
-
config.startProviderAuth
|
|
4816
|
-
],
|
|
4817
|
-
[
|
|
4818
|
-
"post",
|
|
4819
|
-
"/api/config/providers/:provider/auth/poll",
|
|
4820
|
-
config.pollProviderAuth
|
|
4821
|
-
],
|
|
4822
|
-
[
|
|
4823
|
-
"post",
|
|
4824
|
-
"/api/config/providers/:provider/auth/import-cli",
|
|
4825
|
-
config.importProviderAuthFromCli
|
|
4826
|
-
],
|
|
4827
|
-
[
|
|
4828
|
-
"put",
|
|
4829
|
-
"/api/config/channels/:channel",
|
|
4830
|
-
config.updateChannel
|
|
4831
|
-
],
|
|
4832
|
-
[
|
|
4833
|
-
"post",
|
|
4834
|
-
"/api/config/channels/:channel/auth/start",
|
|
4835
|
-
config.startChannelAuth
|
|
4836
|
-
],
|
|
4837
|
-
[
|
|
4838
|
-
"post",
|
|
4839
|
-
"/api/config/channels/:channel/auth/connect",
|
|
4840
|
-
config.connectChannelAuth
|
|
4841
|
-
],
|
|
4842
|
-
[
|
|
4843
|
-
"post",
|
|
4844
|
-
"/api/config/channels/:channel/auth/poll",
|
|
4845
|
-
config.pollChannelAuth
|
|
4846
|
-
],
|
|
4847
|
-
[
|
|
4848
|
-
"put",
|
|
4849
|
-
"/api/config/secrets",
|
|
4850
|
-
config.updateSecrets
|
|
4851
|
-
],
|
|
4852
|
-
[
|
|
4853
|
-
"put",
|
|
4854
|
-
"/api/config/runtime",
|
|
4855
|
-
config.updateRuntime
|
|
4856
|
-
],
|
|
4857
|
-
[
|
|
4858
|
-
"post",
|
|
4859
|
-
"/api/config/actions/:actionId/execute",
|
|
4860
|
-
config.executeAction
|
|
4861
|
-
]
|
|
4862
|
-
]);
|
|
4762
|
+
mountResourceRoutes = () => {
|
|
4763
|
+
const { ncpSession, panelApps, serviceApps, serverPath } = this.controllers;
|
|
4863
4764
|
this.mountRoutes([
|
|
4864
4765
|
[
|
|
4865
4766
|
"get",
|
|
@@ -4981,6 +4882,11 @@ var UiRouteRegistry = class {
|
|
|
4981
4882
|
"/api/service-apps/:appId",
|
|
4982
4883
|
serviceApps.getServiceApp
|
|
4983
4884
|
],
|
|
4885
|
+
[
|
|
4886
|
+
"delete",
|
|
4887
|
+
"/api/service-apps/:appId",
|
|
4888
|
+
serviceApps.deleteServiceApp
|
|
4889
|
+
],
|
|
4984
4890
|
[
|
|
4985
4891
|
"get",
|
|
4986
4892
|
"/api/service-actions",
|
|
@@ -5022,6 +4928,194 @@ var UiRouteRegistry = class {
|
|
|
5022
4928
|
serverPath.read
|
|
5023
4929
|
]
|
|
5024
4930
|
]);
|
|
4931
|
+
};
|
|
4932
|
+
register = () => {
|
|
4933
|
+
const { agents, app, auth, config, cron, ncpAsset, remote, runtimeControl, runtimeUpdate } = this.controllers;
|
|
4934
|
+
this.mountRoutes([
|
|
4935
|
+
[
|
|
4936
|
+
"get",
|
|
4937
|
+
"/api/health",
|
|
4938
|
+
app.health
|
|
4939
|
+
],
|
|
4940
|
+
[
|
|
4941
|
+
"get",
|
|
4942
|
+
"/api/app/meta",
|
|
4943
|
+
app.appMeta
|
|
4944
|
+
],
|
|
4945
|
+
[
|
|
4946
|
+
"get",
|
|
4947
|
+
"/api/runtime/bootstrap-status",
|
|
4948
|
+
app.bootstrapStatus
|
|
4949
|
+
],
|
|
4950
|
+
[
|
|
4951
|
+
"get",
|
|
4952
|
+
"/api/auth/status",
|
|
4953
|
+
auth.getStatus
|
|
4954
|
+
],
|
|
4955
|
+
[
|
|
4956
|
+
"post",
|
|
4957
|
+
"/api/auth/setup",
|
|
4958
|
+
auth.setup
|
|
4959
|
+
],
|
|
4960
|
+
[
|
|
4961
|
+
"post",
|
|
4962
|
+
"/api/auth/login",
|
|
4963
|
+
auth.login
|
|
4964
|
+
],
|
|
4965
|
+
[
|
|
4966
|
+
"post",
|
|
4967
|
+
"/api/auth/logout",
|
|
4968
|
+
auth.logout
|
|
4969
|
+
],
|
|
4970
|
+
[
|
|
4971
|
+
"put",
|
|
4972
|
+
"/api/auth/password",
|
|
4973
|
+
auth.updatePassword
|
|
4974
|
+
],
|
|
4975
|
+
[
|
|
4976
|
+
"put",
|
|
4977
|
+
"/api/auth/enabled",
|
|
4978
|
+
auth.updateEnabled
|
|
4979
|
+
],
|
|
4980
|
+
[
|
|
4981
|
+
"post",
|
|
4982
|
+
"/api/auth/bridge",
|
|
4983
|
+
auth.issueBridgeSession
|
|
4984
|
+
],
|
|
4985
|
+
[
|
|
4986
|
+
"get",
|
|
4987
|
+
"/api/agents",
|
|
4988
|
+
agents.listAgents
|
|
4989
|
+
],
|
|
4990
|
+
[
|
|
4991
|
+
"post",
|
|
4992
|
+
"/api/agents",
|
|
4993
|
+
agents.createAgent
|
|
4994
|
+
],
|
|
4995
|
+
[
|
|
4996
|
+
"put",
|
|
4997
|
+
"/api/agents/:agentId",
|
|
4998
|
+
agents.updateAgent
|
|
4999
|
+
],
|
|
5000
|
+
[
|
|
5001
|
+
"delete",
|
|
5002
|
+
"/api/agents/:agentId",
|
|
5003
|
+
agents.deleteAgent
|
|
5004
|
+
],
|
|
5005
|
+
[
|
|
5006
|
+
"get",
|
|
5007
|
+
"/api/agents/:agentId/avatar",
|
|
5008
|
+
agents.getAgentAvatar
|
|
5009
|
+
]
|
|
5010
|
+
]);
|
|
5011
|
+
this.mountRoutes([
|
|
5012
|
+
[
|
|
5013
|
+
"get",
|
|
5014
|
+
"/api/config",
|
|
5015
|
+
config.getConfig
|
|
5016
|
+
],
|
|
5017
|
+
[
|
|
5018
|
+
"get",
|
|
5019
|
+
"/api/config/meta",
|
|
5020
|
+
config.getConfigMeta
|
|
5021
|
+
],
|
|
5022
|
+
[
|
|
5023
|
+
"get",
|
|
5024
|
+
"/api/config/schema",
|
|
5025
|
+
config.getConfigSchema
|
|
5026
|
+
],
|
|
5027
|
+
[
|
|
5028
|
+
"get",
|
|
5029
|
+
"/api/providers",
|
|
5030
|
+
config.listProviders
|
|
5031
|
+
],
|
|
5032
|
+
[
|
|
5033
|
+
"get",
|
|
5034
|
+
"/api/provider-templates",
|
|
5035
|
+
config.listProviderTemplates
|
|
5036
|
+
],
|
|
5037
|
+
[
|
|
5038
|
+
"post",
|
|
5039
|
+
"/api/providers",
|
|
5040
|
+
config.createProvider
|
|
5041
|
+
],
|
|
5042
|
+
[
|
|
5043
|
+
"put",
|
|
5044
|
+
"/api/providers/:providerId",
|
|
5045
|
+
config.updateProvider
|
|
5046
|
+
],
|
|
5047
|
+
[
|
|
5048
|
+
"delete",
|
|
5049
|
+
"/api/providers/:providerId",
|
|
5050
|
+
config.deleteProvider
|
|
5051
|
+
],
|
|
5052
|
+
[
|
|
5053
|
+
"post",
|
|
5054
|
+
"/api/providers/:providerId/test",
|
|
5055
|
+
config.testProviderConnection
|
|
5056
|
+
],
|
|
5057
|
+
[
|
|
5058
|
+
"post",
|
|
5059
|
+
"/api/providers/:providerId/auth/start",
|
|
5060
|
+
config.startProviderAuth
|
|
5061
|
+
],
|
|
5062
|
+
[
|
|
5063
|
+
"post",
|
|
5064
|
+
"/api/providers/:providerId/auth/poll",
|
|
5065
|
+
config.pollProviderAuth
|
|
5066
|
+
],
|
|
5067
|
+
[
|
|
5068
|
+
"post",
|
|
5069
|
+
"/api/providers/:providerId/auth/import-cli",
|
|
5070
|
+
config.importProviderAuthFromCli
|
|
5071
|
+
],
|
|
5072
|
+
[
|
|
5073
|
+
"put",
|
|
5074
|
+
"/api/config/model",
|
|
5075
|
+
config.updateConfigModel
|
|
5076
|
+
],
|
|
5077
|
+
[
|
|
5078
|
+
"put",
|
|
5079
|
+
"/api/config/search",
|
|
5080
|
+
config.updateConfigSearch
|
|
5081
|
+
],
|
|
5082
|
+
[
|
|
5083
|
+
"put",
|
|
5084
|
+
"/api/config/channels/:channel",
|
|
5085
|
+
config.updateChannel
|
|
5086
|
+
],
|
|
5087
|
+
[
|
|
5088
|
+
"post",
|
|
5089
|
+
"/api/config/channels/:channel/auth/start",
|
|
5090
|
+
config.startChannelAuth
|
|
5091
|
+
],
|
|
5092
|
+
[
|
|
5093
|
+
"post",
|
|
5094
|
+
"/api/config/channels/:channel/auth/connect",
|
|
5095
|
+
config.connectChannelAuth
|
|
5096
|
+
],
|
|
5097
|
+
[
|
|
5098
|
+
"post",
|
|
5099
|
+
"/api/config/channels/:channel/auth/poll",
|
|
5100
|
+
config.pollChannelAuth
|
|
5101
|
+
],
|
|
5102
|
+
[
|
|
5103
|
+
"put",
|
|
5104
|
+
"/api/config/secrets",
|
|
5105
|
+
config.updateSecrets
|
|
5106
|
+
],
|
|
5107
|
+
[
|
|
5108
|
+
"put",
|
|
5109
|
+
"/api/config/runtime",
|
|
5110
|
+
config.updateRuntime
|
|
5111
|
+
],
|
|
5112
|
+
[
|
|
5113
|
+
"post",
|
|
5114
|
+
"/api/config/actions/:actionId/execute",
|
|
5115
|
+
config.executeAction
|
|
5116
|
+
]
|
|
5117
|
+
]);
|
|
5118
|
+
this.mountResourceRoutes();
|
|
5025
5119
|
this.mountNcpAgentRoutes(this.options.kernel, ncpAsset);
|
|
5026
5120
|
this.mountRoutes([
|
|
5027
5121
|
[
|
|
@@ -5338,6 +5432,6 @@ async function startUiServer(gateway) {
|
|
|
5338
5432
|
};
|
|
5339
5433
|
}
|
|
5340
5434
|
//#endregion
|
|
5341
|
-
export { ConfigRoutesController, PanelAppsRoutesController, RuntimeControlRoutesController, ServiceAppsRoutesController, buildConfigMeta, buildConfigSchemaView, buildConfigView,
|
|
5435
|
+
export { ConfigRoutesController, PanelAppsRoutesController, RuntimeControlRoutesController, ServiceAppsRoutesController, buildConfigMeta, buildConfigSchemaView, buildConfigView, buildProviderTemplatesView, buildProvidersView, createProvider, createUiRouter, deleteProvider, ensureUiBridgeSecret, executeConfigAction, getUiBridgeSecretPath, loadConfigOrDefault, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
|
|
5342
5436
|
|
|
5343
5437
|
//# sourceMappingURL=index.js.map
|