@madewithremy/admin 0.1.5 → 0.1.7
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 +531 -26
- package/dist/index.js +279 -29
- package/dist/index.js.map +1 -1
- package/dist/prod.js +673 -35
- package/package.json +1 -1
package/dist/prod.js
CHANGED
|
@@ -228,6 +228,16 @@ function parseCommand(spec, argv) {
|
|
|
228
228
|
|
|
229
229
|
// src/http.ts
|
|
230
230
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
231
|
+
var TRANSIENT_GRACE_MS = 2 * 6e4;
|
|
232
|
+
function isTransientError(err) {
|
|
233
|
+
if (err instanceof AdminApiError) {
|
|
234
|
+
return err.status >= 500;
|
|
235
|
+
}
|
|
236
|
+
if (err instanceof AdminTimeoutError) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
return err instanceof TypeError;
|
|
240
|
+
}
|
|
231
241
|
var REPORT_TIMEOUT_MS = 6e4;
|
|
232
242
|
function seg(value) {
|
|
233
243
|
return encodeURIComponent(String(value));
|
|
@@ -913,7 +923,9 @@ function summarizeRelease(release) {
|
|
|
913
923
|
}
|
|
914
924
|
return {
|
|
915
925
|
...summary2,
|
|
916
|
-
error: buildFailureReason(release) ?? "Build failed (no error entry in the build log)"
|
|
926
|
+
error: release.failureReason ?? buildFailureReason(release) ?? "Build failed (no error entry in the build log)",
|
|
927
|
+
...release.failureKind ? { failureKind: release.failureKind } : {},
|
|
928
|
+
...release.failurePhase ? { failurePhase: release.failurePhase } : {}
|
|
917
929
|
};
|
|
918
930
|
}
|
|
919
931
|
var POLL_MS = 3e3;
|
|
@@ -1164,6 +1176,12 @@ the exit code so you can branch on $? without parsing:
|
|
|
1164
1176
|
Any other failure (bad arguments, auth, API error) exits 10, so exit 1 always
|
|
1165
1177
|
means the build itself failed.
|
|
1166
1178
|
|
|
1179
|
+
Every release shape ('get', 'list', 'status', 'wait') carries why a failed
|
|
1180
|
+
build failed: 'failureReason' (message), 'failurePhase' (the stage that was
|
|
1181
|
+
running), and 'failureKind' \u2014 'build' (the code), 'unbuildable' (commit is
|
|
1182
|
+
not a readable app), or 'interrupted' (a platform restart killed the build;
|
|
1183
|
+
a retry is already running, so don't re-push).
|
|
1184
|
+
|
|
1167
1185
|
Examples:
|
|
1168
1186
|
git push origin HEAD && remy-admin releases wait
|
|
1169
1187
|
remy-admin releases wait --commit 91ca67a --timeout 600
|
|
@@ -2919,12 +2937,26 @@ async function waitForIngest(ctx, params) {
|
|
|
2919
2937
|
}
|
|
2920
2938
|
const wanted = new Set(documentIds);
|
|
2921
2939
|
const start = Date.now();
|
|
2940
|
+
let transientSince = null;
|
|
2922
2941
|
for (; ; ) {
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
)
|
|
2942
|
+
let docs;
|
|
2943
|
+
try {
|
|
2944
|
+
docs = await allDocuments(ctx, { slug, ids: documentIds });
|
|
2945
|
+
transientSince = null;
|
|
2946
|
+
} catch (err) {
|
|
2947
|
+
if (!isTransientError(err)) {
|
|
2948
|
+
throw err;
|
|
2949
|
+
}
|
|
2950
|
+
transientSince ??= Date.now();
|
|
2951
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
2952
|
+
throw err;
|
|
2953
|
+
}
|
|
2954
|
+
onProgress?.(
|
|
2955
|
+
`retrying after a gateway error\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
2956
|
+
);
|
|
2957
|
+
await sleep(POLL_MS2);
|
|
2958
|
+
continue;
|
|
2959
|
+
}
|
|
2928
2960
|
const tracked = (docs ?? []).filter((d) => wanted.has(d.id));
|
|
2929
2961
|
const pending = tracked.filter((d) => d.status === "processing");
|
|
2930
2962
|
const failed = tracked.filter((d) => d.status === "error");
|
|
@@ -2949,12 +2981,41 @@ async function waitForIngest(ctx, params) {
|
|
|
2949
2981
|
await sleep(POLL_MS2);
|
|
2950
2982
|
}
|
|
2951
2983
|
}
|
|
2984
|
+
var DOCUMENTS_IDS_MAX = 200;
|
|
2952
2985
|
function documents(ctx, params) {
|
|
2953
2986
|
return call(
|
|
2954
2987
|
ctx,
|
|
2955
2988
|
"GET",
|
|
2956
|
-
`${base(ctx.appId)}/documents${qs({
|
|
2957
|
-
|
|
2989
|
+
`${base(ctx.appId)}/documents${qs({
|
|
2990
|
+
slug: params.slug,
|
|
2991
|
+
candidate: params.candidate || void 0,
|
|
2992
|
+
ids: params.ids?.length ? params.ids.join(",") : void 0,
|
|
2993
|
+
limit: params.limit,
|
|
2994
|
+
cursor: params.cursor
|
|
2995
|
+
})}`
|
|
2996
|
+
);
|
|
2997
|
+
}
|
|
2998
|
+
async function allDocuments(ctx, params) {
|
|
2999
|
+
const groups = params.ids ? Array.from(
|
|
3000
|
+
{ length: Math.ceil(params.ids.length / DOCUMENTS_IDS_MAX) },
|
|
3001
|
+
(_, i) => params.ids.slice(i * DOCUMENTS_IDS_MAX, (i + 1) * DOCUMENTS_IDS_MAX)
|
|
3002
|
+
) : [void 0];
|
|
3003
|
+
const out2 = [];
|
|
3004
|
+
for (const ids of groups) {
|
|
3005
|
+
let cursor;
|
|
3006
|
+
do {
|
|
3007
|
+
const page = await documents(ctx, {
|
|
3008
|
+
slug: params.slug,
|
|
3009
|
+
candidate: params.candidate,
|
|
3010
|
+
ids,
|
|
3011
|
+
limit: 1e3,
|
|
3012
|
+
cursor
|
|
3013
|
+
});
|
|
3014
|
+
out2.push(...page.documents ?? []);
|
|
3015
|
+
cursor = page.nextCursor ?? void 0;
|
|
3016
|
+
} while (cursor);
|
|
3017
|
+
}
|
|
3018
|
+
return out2;
|
|
2958
3019
|
}
|
|
2959
3020
|
function list8(ctx) {
|
|
2960
3021
|
return call(ctx, "GET", base(ctx.appId));
|
|
@@ -2996,7 +3057,7 @@ function configGet(ctx, slug) {
|
|
|
2996
3057
|
);
|
|
2997
3058
|
}
|
|
2998
3059
|
function configSet(ctx, params) {
|
|
2999
|
-
const { slug, ingest, retrieval } = params;
|
|
3060
|
+
const { slug, ingest, retrieval, placement } = params;
|
|
3000
3061
|
return call(
|
|
3001
3062
|
ctx,
|
|
3002
3063
|
"POST",
|
|
@@ -3004,10 +3065,75 @@ function configSet(ctx, params) {
|
|
|
3004
3065
|
{
|
|
3005
3066
|
slug,
|
|
3006
3067
|
...ingest ? { ingest } : {},
|
|
3007
|
-
...retrieval ? { retrieval } : {}
|
|
3068
|
+
...retrieval ? { retrieval } : {},
|
|
3069
|
+
...placement !== void 0 ? { placement } : {}
|
|
3008
3070
|
}
|
|
3009
3071
|
);
|
|
3010
3072
|
}
|
|
3073
|
+
function create2(ctx, params) {
|
|
3074
|
+
const { slug, name, ingest, placement } = params;
|
|
3075
|
+
return call(ctx, "POST", base(ctx.appId), {
|
|
3076
|
+
slug,
|
|
3077
|
+
...name ? { name } : {},
|
|
3078
|
+
...ingest ? { ingest } : {},
|
|
3079
|
+
...placement !== void 0 ? { placement } : {}
|
|
3080
|
+
});
|
|
3081
|
+
}
|
|
3082
|
+
function move(ctx, params) {
|
|
3083
|
+
return call(ctx, "POST", `${base(ctx.appId)}/move`, {
|
|
3084
|
+
slug: params.slug,
|
|
3085
|
+
placement: params.placement
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
async function waitForMove(ctx, params) {
|
|
3089
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
3090
|
+
const start = Date.now();
|
|
3091
|
+
let transientSince = null;
|
|
3092
|
+
for (; ; ) {
|
|
3093
|
+
let source;
|
|
3094
|
+
try {
|
|
3095
|
+
const { dataSources } = await list8(ctx);
|
|
3096
|
+
source = dataSources.find((s) => s.slug === params.slug);
|
|
3097
|
+
transientSince = null;
|
|
3098
|
+
} catch (err) {
|
|
3099
|
+
if (!isTransientError(err)) {
|
|
3100
|
+
throw err;
|
|
3101
|
+
}
|
|
3102
|
+
transientSince ??= Date.now();
|
|
3103
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
3104
|
+
throw err;
|
|
3105
|
+
}
|
|
3106
|
+
params.onProgress?.(
|
|
3107
|
+
`retrying after a gateway error\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
3108
|
+
);
|
|
3109
|
+
await sleep(POLL_MS2);
|
|
3110
|
+
continue;
|
|
3111
|
+
}
|
|
3112
|
+
if (!source) {
|
|
3113
|
+
throw new Error(`Data source "${params.slug}" not found.`);
|
|
3114
|
+
}
|
|
3115
|
+
const migration = source.migration;
|
|
3116
|
+
if (!migration) {
|
|
3117
|
+
return { status: "done", source };
|
|
3118
|
+
}
|
|
3119
|
+
if (migration.error) {
|
|
3120
|
+
return { status: "failed", source, error: migration.error };
|
|
3121
|
+
}
|
|
3122
|
+
if (Date.now() - start > timeoutMs) {
|
|
3123
|
+
return {
|
|
3124
|
+
status: "timeout",
|
|
3125
|
+
source,
|
|
3126
|
+
error: `Timed out after ${Math.round(timeoutMs / 1e3)}s with ${migration.copied}/${migration.total} documents copied`
|
|
3127
|
+
};
|
|
3128
|
+
}
|
|
3129
|
+
params.onProgress?.(
|
|
3130
|
+
`moving\u2026 ${migration.copied}/${migration.total} documents (${Math.round(
|
|
3131
|
+
(Date.now() - start) / 1e3
|
|
3132
|
+
)}s)`
|
|
3133
|
+
);
|
|
3134
|
+
await sleep(POLL_MS2);
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3011
3137
|
function revectorize(ctx, params) {
|
|
3012
3138
|
const { slug, ingest } = params;
|
|
3013
3139
|
return call(
|
|
@@ -3065,8 +3191,8 @@ function deleteSource(ctx, slug) {
|
|
|
3065
3191
|
// src/commands/dataSources.ts
|
|
3066
3192
|
var DEFAULT_SOURCE = "default";
|
|
3067
3193
|
var POLL_MS3 = 3e3;
|
|
3068
|
-
var
|
|
3069
|
-
|
|
3194
|
+
var INGEST_FLAGS = {
|
|
3195
|
+
chunking: { type: "string" },
|
|
3070
3196
|
"max-chars": { type: "number", min: 200 },
|
|
3071
3197
|
"min-chars": { type: "number", min: 0 },
|
|
3072
3198
|
"drop-blocks": { type: "string" },
|
|
@@ -3074,9 +3200,12 @@ var CONFIG_FLAGS = {
|
|
|
3074
3200
|
"contextual-model": { type: "string" },
|
|
3075
3201
|
"describe-images": { type: "string" },
|
|
3076
3202
|
"embedding-model": { type: "string" },
|
|
3203
|
+
"embedding-dimensions": { type: "number", min: 1 },
|
|
3077
3204
|
"image-model": { type: "string" },
|
|
3078
|
-
"extraction-model": { type: "string" }
|
|
3079
|
-
|
|
3205
|
+
"extraction-model": { type: "string" }
|
|
3206
|
+
};
|
|
3207
|
+
var CHUNKING_STRATEGIES = ["structural", "whole"];
|
|
3208
|
+
var RETRIEVAL_FLAGS = {
|
|
3080
3209
|
rerank: { type: "string" },
|
|
3081
3210
|
// Which cross-encoder reranks. Live, not pinned: a reranker runs at query
|
|
3082
3211
|
// time over text already in the index, so switching costs nothing and is
|
|
@@ -3085,6 +3214,10 @@ var CONFIG_FLAGS = {
|
|
|
3085
3214
|
hybrid: { type: "string" },
|
|
3086
3215
|
"top-k": { type: "number", min: 1 }
|
|
3087
3216
|
};
|
|
3217
|
+
var CONFIG_FLAGS = {
|
|
3218
|
+
...INGEST_FLAGS,
|
|
3219
|
+
...RETRIEVAL_FLAGS
|
|
3220
|
+
};
|
|
3088
3221
|
var dataSourcesSpecs = {
|
|
3089
3222
|
"datasources add": {
|
|
3090
3223
|
usage: "Usage: remy-admin datasources add [--source <slug>] [--metadata <k=v,...>] [--wait] [--timeout <sec>] <file...>",
|
|
@@ -3124,9 +3257,37 @@ var dataSourcesSpecs = {
|
|
|
3124
3257
|
highlight: { type: "boolean" }
|
|
3125
3258
|
}
|
|
3126
3259
|
},
|
|
3260
|
+
"datasources create": {
|
|
3261
|
+
usage: "Usage: remy-admin datasources create --source <slug> [--name <name>] [--placement <resource-id|shared>] [ingest settings...]",
|
|
3262
|
+
flags: {
|
|
3263
|
+
source: { type: "string" },
|
|
3264
|
+
name: { type: "string" },
|
|
3265
|
+
placement: { type: "string" },
|
|
3266
|
+
...INGEST_FLAGS
|
|
3267
|
+
}
|
|
3268
|
+
},
|
|
3127
3269
|
"datasources config": {
|
|
3128
|
-
usage: "Usage: remy-admin datasources config [--source <slug>] [settings...]",
|
|
3129
|
-
flags: {
|
|
3270
|
+
usage: "Usage: remy-admin datasources config [--source <slug>] [--placement <resource-id|shared>] [settings...]",
|
|
3271
|
+
flags: {
|
|
3272
|
+
source: { type: "string" },
|
|
3273
|
+
// Where the corpus lives: a dedicated resource id from `infra list`, or
|
|
3274
|
+
// `shared`. A populated source starts a background move (see `move`).
|
|
3275
|
+
placement: { type: "string" },
|
|
3276
|
+
...CONFIG_FLAGS
|
|
3277
|
+
}
|
|
3278
|
+
},
|
|
3279
|
+
"datasources move": {
|
|
3280
|
+
usage: "Usage: remy-admin datasources move [--source <slug>] --to <resource-id|shared> [--wait] [--timeout <sec>]",
|
|
3281
|
+
flags: {
|
|
3282
|
+
source: { type: "string" },
|
|
3283
|
+
to: { type: "string" },
|
|
3284
|
+
wait: { type: "boolean" },
|
|
3285
|
+
timeout: { type: "string" }
|
|
3286
|
+
},
|
|
3287
|
+
requireAnyOf: {
|
|
3288
|
+
flags: ["to"],
|
|
3289
|
+
message: "--to is required: a resource id from `infra list`, or `shared`."
|
|
3290
|
+
}
|
|
3130
3291
|
},
|
|
3131
3292
|
"datasources revectorize": {
|
|
3132
3293
|
usage: "Usage: remy-admin datasources revectorize [--source <slug>] [settings...] [--wait]",
|
|
@@ -3215,10 +3376,10 @@ async function dataSourcesList(ctx) {
|
|
|
3215
3376
|
}
|
|
3216
3377
|
async function dataSourcesStatus(ctx, a) {
|
|
3217
3378
|
const slug = sourceOf(a);
|
|
3218
|
-
const
|
|
3379
|
+
const documents2 = await allDocuments(ctx, { slug });
|
|
3219
3380
|
out({
|
|
3220
3381
|
dataSource: slug,
|
|
3221
|
-
documents:
|
|
3382
|
+
documents: documents2.map(summarize)
|
|
3222
3383
|
});
|
|
3223
3384
|
}
|
|
3224
3385
|
async function dataSourcesRm(ctx, a) {
|
|
@@ -3327,6 +3488,15 @@ function triState(a, flag, key) {
|
|
|
3327
3488
|
}
|
|
3328
3489
|
function configFromFlags(a) {
|
|
3329
3490
|
const chunking = {};
|
|
3491
|
+
const strategy = a.str("chunking");
|
|
3492
|
+
if (strategy !== void 0) {
|
|
3493
|
+
if (!CHUNKING_STRATEGIES.includes(strategy)) {
|
|
3494
|
+
fatal(
|
|
3495
|
+
`--chunking must be one of: ${CHUNKING_STRATEGIES.join(", ")} (got "${strategy}").`
|
|
3496
|
+
);
|
|
3497
|
+
}
|
|
3498
|
+
chunking.strategy = strategy;
|
|
3499
|
+
}
|
|
3330
3500
|
if (a.num("max-chars") !== void 0) {
|
|
3331
3501
|
chunking.maxChars = a.num("max-chars");
|
|
3332
3502
|
}
|
|
@@ -3346,6 +3516,7 @@ function configFromFlags(a) {
|
|
|
3346
3516
|
...a.str("image-model") ? { modelId: a.str("image-model") } : {}
|
|
3347
3517
|
};
|
|
3348
3518
|
const embeddingModel = a.str("embedding-model");
|
|
3519
|
+
const embeddingDimensions = a.num("embedding-dimensions");
|
|
3349
3520
|
const extractionModel = a.str("extraction-model");
|
|
3350
3521
|
const ingest = {};
|
|
3351
3522
|
if (Object.keys(chunking).length) {
|
|
@@ -3357,8 +3528,11 @@ function configFromFlags(a) {
|
|
|
3357
3528
|
if (Object.keys(images).length) {
|
|
3358
3529
|
ingest.images = images;
|
|
3359
3530
|
}
|
|
3360
|
-
if (embeddingModel) {
|
|
3361
|
-
ingest.embedding = {
|
|
3531
|
+
if (embeddingModel || embeddingDimensions !== void 0) {
|
|
3532
|
+
ingest.embedding = {
|
|
3533
|
+
...embeddingModel ? { modelId: embeddingModel } : {},
|
|
3534
|
+
...embeddingDimensions !== void 0 ? { dimensions: embeddingDimensions } : {}
|
|
3535
|
+
};
|
|
3362
3536
|
}
|
|
3363
3537
|
if (extractionModel) {
|
|
3364
3538
|
ingest.extraction = { modelId: extractionModel };
|
|
@@ -3381,21 +3555,80 @@ function configFromFlags(a) {
|
|
|
3381
3555
|
retrieval: Object.keys(retrieval).length ? retrieval : void 0
|
|
3382
3556
|
};
|
|
3383
3557
|
}
|
|
3558
|
+
var placementOf = (a) => {
|
|
3559
|
+
const flag = a.str("placement");
|
|
3560
|
+
return flag === void 0 ? void 0 : flag === "shared" ? "shared" : { resourceId: flag };
|
|
3561
|
+
};
|
|
3562
|
+
var MOVE_NOTE = "Moving in the background; `datasources list` shows progress, or re-run with `datasources move --wait`.";
|
|
3563
|
+
async function dataSourcesCreate(ctx, a) {
|
|
3564
|
+
const slug = a.str("source");
|
|
3565
|
+
if (!slug) {
|
|
3566
|
+
fatal("--source is required.");
|
|
3567
|
+
}
|
|
3568
|
+
const { ingest } = configFromFlags(a);
|
|
3569
|
+
const name = a.str("name");
|
|
3570
|
+
const placement = placementOf(a);
|
|
3571
|
+
const result = await create2(ctx, {
|
|
3572
|
+
slug,
|
|
3573
|
+
...name ? { name } : {},
|
|
3574
|
+
...ingest ? { ingest } : {},
|
|
3575
|
+
...placement !== void 0 ? { placement } : {}
|
|
3576
|
+
});
|
|
3577
|
+
out(
|
|
3578
|
+
result.migration && !result.migration.error ? { ...result, note: MOVE_NOTE } : result
|
|
3579
|
+
);
|
|
3580
|
+
}
|
|
3384
3581
|
async function dataSourcesConfig(ctx, a) {
|
|
3385
3582
|
const slug = sourceOf(a);
|
|
3386
3583
|
const { ingest, retrieval } = configFromFlags(a);
|
|
3387
|
-
|
|
3584
|
+
const placement = placementOf(a);
|
|
3585
|
+
if (!ingest && !retrieval && placement === void 0) {
|
|
3388
3586
|
out(await configGet(ctx, slug));
|
|
3389
3587
|
return;
|
|
3390
3588
|
}
|
|
3589
|
+
const result = await configSet(ctx, {
|
|
3590
|
+
slug,
|
|
3591
|
+
...ingest ? { ingest } : {},
|
|
3592
|
+
...retrieval ? { retrieval } : {},
|
|
3593
|
+
...placement !== void 0 ? { placement } : {}
|
|
3594
|
+
});
|
|
3391
3595
|
out(
|
|
3392
|
-
|
|
3393
|
-
slug,
|
|
3394
|
-
...ingest ? { ingest } : {},
|
|
3395
|
-
...retrieval ? { retrieval } : {}
|
|
3396
|
-
})
|
|
3596
|
+
result.placementChanged && result.migration && !result.migration.error ? { ...result, note: MOVE_NOTE } : result
|
|
3397
3597
|
);
|
|
3398
3598
|
}
|
|
3599
|
+
async function dataSourcesMove(ctx, a) {
|
|
3600
|
+
const slug = sourceOf(a);
|
|
3601
|
+
const to = a.str("to");
|
|
3602
|
+
const placement = to === "shared" ? "shared" : { resourceId: to };
|
|
3603
|
+
const started = await move(ctx, { slug, placement });
|
|
3604
|
+
if (!started.migration || !a.bool("wait")) {
|
|
3605
|
+
out({
|
|
3606
|
+
dataSource: slug,
|
|
3607
|
+
...started,
|
|
3608
|
+
...started.migration ? { note: MOVE_NOTE } : {}
|
|
3609
|
+
});
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
const timeoutSec = a.num("timeout");
|
|
3613
|
+
const result = await waitForMove(ctx, {
|
|
3614
|
+
slug,
|
|
3615
|
+
...timeoutSec ? { timeoutMs: timeoutSec * 1e3 } : {},
|
|
3616
|
+
onProgress: progress
|
|
3617
|
+
});
|
|
3618
|
+
out({
|
|
3619
|
+
dataSource: slug,
|
|
3620
|
+
status: result.status,
|
|
3621
|
+
placement: result.source.placement,
|
|
3622
|
+
migration: result.source.migration,
|
|
3623
|
+
..."error" in result ? { error: result.error } : {}
|
|
3624
|
+
});
|
|
3625
|
+
if (result.status === "failed") {
|
|
3626
|
+
process.exit(EXIT.buildFailed);
|
|
3627
|
+
}
|
|
3628
|
+
if (result.status === "timeout") {
|
|
3629
|
+
process.exit(EXIT.timeout);
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3399
3632
|
async function dataSourcesRevectorize(ctx, a) {
|
|
3400
3633
|
const slug = sourceOf(a);
|
|
3401
3634
|
const { ingest } = configFromFlags(a);
|
|
@@ -3411,12 +3644,12 @@ async function dataSourcesRevectorize(ctx, a) {
|
|
|
3411
3644
|
const timeoutMs = timeoutSec ? timeoutSec * 1e3 : DEFAULT_WAIT_TIMEOUT_MS;
|
|
3412
3645
|
const start = Date.now();
|
|
3413
3646
|
for (; ; ) {
|
|
3414
|
-
const
|
|
3647
|
+
const documents2 = await allDocuments(ctx, {
|
|
3415
3648
|
slug,
|
|
3416
3649
|
candidate: true
|
|
3417
3650
|
});
|
|
3418
|
-
const pending =
|
|
3419
|
-
const failed =
|
|
3651
|
+
const pending = documents2.filter((d) => d.status === "processing");
|
|
3652
|
+
const failed = documents2.filter((d) => d.status === "error");
|
|
3420
3653
|
if (pending.length === 0) {
|
|
3421
3654
|
out({
|
|
3422
3655
|
dataSource: slug,
|
|
@@ -3469,7 +3702,9 @@ var dataSourcesHandlers = {
|
|
|
3469
3702
|
"datasources status": dataSourcesStatus,
|
|
3470
3703
|
"datasources rm": dataSourcesRm,
|
|
3471
3704
|
"datasources search": dataSourcesSearch,
|
|
3705
|
+
"datasources create": dataSourcesCreate,
|
|
3472
3706
|
"datasources config": dataSourcesConfig,
|
|
3707
|
+
"datasources move": dataSourcesMove,
|
|
3473
3708
|
"datasources revectorize": dataSourcesRevectorize,
|
|
3474
3709
|
"datasources promote": dataSourcesPromote,
|
|
3475
3710
|
"datasources drop": dataSourcesDrop,
|
|
@@ -3486,7 +3721,9 @@ Subcommands:
|
|
|
3486
3721
|
status Show per-document ingest state
|
|
3487
3722
|
rm Remove a document and its vectors
|
|
3488
3723
|
search Query a corpus \u2014 useful to sanity-check one you just built
|
|
3724
|
+
create Create an empty source, optionally on dedicated capacity
|
|
3489
3725
|
config Show or change how a corpus is processed and searched
|
|
3726
|
+
move Move a corpus between shared and dedicated capacity, data intact
|
|
3490
3727
|
revectorize Rebuild a corpus under new settings, alongside the live one
|
|
3491
3728
|
promote Make a rebuilt version live
|
|
3492
3729
|
drop Discard a candidate or a superseded version
|
|
@@ -3498,7 +3735,9 @@ Usage:
|
|
|
3498
3735
|
remy-admin datasources status [--source <slug>]
|
|
3499
3736
|
remy-admin datasources rm [--source <slug>] --document <id>
|
|
3500
3737
|
remy-admin datasources search [--source <slug>] [search options] <query>
|
|
3501
|
-
remy-admin datasources
|
|
3738
|
+
remy-admin datasources create --source <slug> [--name <name>] [--placement <resource-id|shared>] [rebuild settings...]
|
|
3739
|
+
remy-admin datasources config [--source <slug>] [--placement <resource-id|shared>] [settings...]
|
|
3740
|
+
remy-admin datasources move [--source <slug>] --to <resource-id|shared> [--wait] [--timeout <sec>]
|
|
3502
3741
|
remy-admin datasources revectorize [--source <slug>] [settings...] [--wait]
|
|
3503
3742
|
remy-admin datasources promote [--source <slug>] [--force]
|
|
3504
3743
|
remy-admin datasources drop [--source <slug>] [--version <n>]
|
|
@@ -3540,6 +3779,13 @@ Tuning a corpus:
|
|
|
3540
3779
|
reprocessed. Changing these on a corpus that already has documents is
|
|
3541
3780
|
REJECTED; use \`revectorize\` instead, which builds a new version alongside
|
|
3542
3781
|
the live one so search never degrades:
|
|
3782
|
+
--chunking <structural|whole>
|
|
3783
|
+
structural (default) splits on headings, blocks
|
|
3784
|
+
and paragraphs. whole embeds each document as one
|
|
3785
|
+
chunk: for corpora of short records (articles,
|
|
3786
|
+
tickets, product rows) where the document is the
|
|
3787
|
+
unit you want back. Documents over --max-chars
|
|
3788
|
+
(default 24000 for whole) fall back to structural.
|
|
3543
3789
|
--max-chars <n> Target chunk size (default 2000)
|
|
3544
3790
|
--min-chars <n> Merge chunks smaller than this (default 120)
|
|
3545
3791
|
--drop-blocks <a,b> Block types to discard, e.g. footer,header
|
|
@@ -3555,10 +3801,30 @@ Tuning a corpus:
|
|
|
3555
3801
|
invisible to search rather than merely ranked low.
|
|
3556
3802
|
--image-model <id>
|
|
3557
3803
|
--embedding-model <id>
|
|
3804
|
+
--embedding-dimensions <n> Vector width, for models that offer several
|
|
3805
|
+
(Matryoshka). Must be the model's native size or
|
|
3806
|
+
one it lists; the error names the choices.
|
|
3807
|
+
Smaller vectors cut index memory, and dedicated
|
|
3808
|
+
capacity needs, roughly in proportion.
|
|
3558
3809
|
--extraction-model <id>
|
|
3559
3810
|
|
|
3811
|
+
Placement (shared pool vs dedicated capacity, see \`infra --help\`):
|
|
3812
|
+
--source defaults to "${DEFAULT_SOURCE}" and is created on first use, on the
|
|
3813
|
+
shared pool. Start a corpus on a resource with \`create --placement\`, or
|
|
3814
|
+
move one at any time with \`move --to <resource-id|shared>\`.
|
|
3815
|
+
A move copies the corpus's stored vectors onto the new capacity in the
|
|
3816
|
+
background: no re-extraction, no re-embedding, no charge beyond the
|
|
3817
|
+
resource itself. Search keeps working from the old placement until the
|
|
3818
|
+
copy lands; add, rm, config, revectorize and delete are refused with
|
|
3819
|
+
data_source_migrating until then. \`datasources list\` shows progress;
|
|
3820
|
+
\`move --wait\` blocks on it (exits ${EXIT.buildFailed} if the move failed,
|
|
3821
|
+
${EXIT.timeout} on timeout). Moving to \`shared\` is how a source leaves a
|
|
3822
|
+
resource you mean to destroy.
|
|
3823
|
+
A move is refused while documents are still building or a candidate version
|
|
3824
|
+
exists (data_source_busy), when the target is not active
|
|
3825
|
+
(capacity_<phase>), or when it would not fit (capacity_exceeded).
|
|
3826
|
+
|
|
3560
3827
|
Notes:
|
|
3561
|
-
--source defaults to "${DEFAULT_SOURCE}" and is created on first use.
|
|
3562
3828
|
--wait blocks until processing finishes, so you can search immediately after.
|
|
3563
3829
|
Exits ${EXIT.buildFailed} if a document failed, ${EXIT.timeout} on timeout.
|
|
3564
3830
|
Re-adding an unchanged file is free: no upload, no re-embedding. Re-adding
|
|
@@ -5333,6 +5599,373 @@ Examples:
|
|
|
5333
5599
|
remy-admin cron list --runs 50
|
|
5334
5600
|
remy-admin cron run dailyDigest`;
|
|
5335
5601
|
|
|
5602
|
+
// src/ops/infra.ts
|
|
5603
|
+
var DEFAULT_WAIT_TIMEOUT_MS2 = 10 * 60 * 1e3;
|
|
5604
|
+
var POLL_MS4 = 3e3;
|
|
5605
|
+
function base2(appId) {
|
|
5606
|
+
return `/_internal/v2/apps/${appId}/infra`;
|
|
5607
|
+
}
|
|
5608
|
+
function list11(ctx, params) {
|
|
5609
|
+
return call(
|
|
5610
|
+
ctx,
|
|
5611
|
+
"GET",
|
|
5612
|
+
`${base2(ctx.appId)}${params?.includeDestroyed ? "?includeDestroyed=true" : ""}`
|
|
5613
|
+
);
|
|
5614
|
+
}
|
|
5615
|
+
function get8(ctx, params) {
|
|
5616
|
+
return call(
|
|
5617
|
+
ctx,
|
|
5618
|
+
"GET",
|
|
5619
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}`
|
|
5620
|
+
);
|
|
5621
|
+
}
|
|
5622
|
+
function provision(ctx, params) {
|
|
5623
|
+
return call(ctx, "POST", base2(ctx.appId), {
|
|
5624
|
+
offeringId: params.offeringId,
|
|
5625
|
+
...params.name ? { name: params.name } : {}
|
|
5626
|
+
});
|
|
5627
|
+
}
|
|
5628
|
+
function hibernate(ctx, params) {
|
|
5629
|
+
return call(
|
|
5630
|
+
ctx,
|
|
5631
|
+
"POST",
|
|
5632
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/hibernate`
|
|
5633
|
+
);
|
|
5634
|
+
}
|
|
5635
|
+
function resume(ctx, params) {
|
|
5636
|
+
return call(
|
|
5637
|
+
ctx,
|
|
5638
|
+
"POST",
|
|
5639
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/resume`
|
|
5640
|
+
);
|
|
5641
|
+
}
|
|
5642
|
+
function destroy(ctx, params) {
|
|
5643
|
+
return call(
|
|
5644
|
+
ctx,
|
|
5645
|
+
"POST",
|
|
5646
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/destroy`
|
|
5647
|
+
);
|
|
5648
|
+
}
|
|
5649
|
+
function resize(ctx, params) {
|
|
5650
|
+
return call(
|
|
5651
|
+
ctx,
|
|
5652
|
+
"POST",
|
|
5653
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/resize`,
|
|
5654
|
+
{ offeringId: params.offeringId }
|
|
5655
|
+
);
|
|
5656
|
+
}
|
|
5657
|
+
function rename(ctx, params) {
|
|
5658
|
+
return call(
|
|
5659
|
+
ctx,
|
|
5660
|
+
"POST",
|
|
5661
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/rename`,
|
|
5662
|
+
{ name: params.name }
|
|
5663
|
+
);
|
|
5664
|
+
}
|
|
5665
|
+
async function waitForPhase(ctx, params) {
|
|
5666
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS2;
|
|
5667
|
+
const wanted = new Set(params.phases);
|
|
5668
|
+
const start = Date.now();
|
|
5669
|
+
let transientSince = null;
|
|
5670
|
+
for (; ; ) {
|
|
5671
|
+
let resource;
|
|
5672
|
+
try {
|
|
5673
|
+
({ resource } = await get8(ctx, { id: params.id }));
|
|
5674
|
+
transientSince = null;
|
|
5675
|
+
} catch (err) {
|
|
5676
|
+
if (!isTransientError(err)) {
|
|
5677
|
+
throw err;
|
|
5678
|
+
}
|
|
5679
|
+
transientSince ??= Date.now();
|
|
5680
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
5681
|
+
throw err;
|
|
5682
|
+
}
|
|
5683
|
+
params.onProgress?.(
|
|
5684
|
+
`retrying after a gateway error\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
5685
|
+
);
|
|
5686
|
+
await sleep(POLL_MS4);
|
|
5687
|
+
continue;
|
|
5688
|
+
}
|
|
5689
|
+
if (wanted.has(resource.phase) && (params.until?.(resource) ?? true)) {
|
|
5690
|
+
return { status: "done", resource };
|
|
5691
|
+
}
|
|
5692
|
+
if (resource.phase === "failed") {
|
|
5693
|
+
return {
|
|
5694
|
+
status: "failed",
|
|
5695
|
+
resource,
|
|
5696
|
+
error: resource.lastError ?? "The platform could not complete the change."
|
|
5697
|
+
};
|
|
5698
|
+
}
|
|
5699
|
+
if (Date.now() - start > timeoutMs) {
|
|
5700
|
+
return {
|
|
5701
|
+
status: "timeout",
|
|
5702
|
+
resource,
|
|
5703
|
+
error: `Timed out after ${Math.round(timeoutMs / 1e3)}s; resource is still ${resource.phase}`
|
|
5704
|
+
};
|
|
5705
|
+
}
|
|
5706
|
+
params.onProgress?.(
|
|
5707
|
+
`${resource.phase}${resource.detail ? ` \xB7 ${resource.detail}` : ""}${resource.resizingTo ? ` \xB7 resizing to ${resource.resizingTo.label}` : ""}\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
5708
|
+
);
|
|
5709
|
+
await sleep(POLL_MS4);
|
|
5710
|
+
}
|
|
5711
|
+
}
|
|
5712
|
+
|
|
5713
|
+
// src/commands/infra.ts
|
|
5714
|
+
var infraSpecs = {
|
|
5715
|
+
"infra list": {
|
|
5716
|
+
usage: "Usage: remy-admin infra list [--include-destroyed]",
|
|
5717
|
+
flags: { "include-destroyed": { type: "boolean" } }
|
|
5718
|
+
},
|
|
5719
|
+
"infra get": {
|
|
5720
|
+
usage: "Usage: remy-admin infra get <id>",
|
|
5721
|
+
positionals: [{ name: "id", required: true }]
|
|
5722
|
+
},
|
|
5723
|
+
"infra provision": {
|
|
5724
|
+
usage: "Usage: remy-admin infra provision --offering <id> [--name <name>] [--wait] [--timeout <sec>]",
|
|
5725
|
+
flags: {
|
|
5726
|
+
offering: { type: "string" },
|
|
5727
|
+
name: { type: "string" },
|
|
5728
|
+
wait: { type: "boolean" },
|
|
5729
|
+
timeout: { type: "string" }
|
|
5730
|
+
},
|
|
5731
|
+
requireAnyOf: {
|
|
5732
|
+
flags: ["offering"],
|
|
5733
|
+
message: "--offering is required (see `infra list` for the catalog)."
|
|
5734
|
+
}
|
|
5735
|
+
},
|
|
5736
|
+
"infra hibernate": {
|
|
5737
|
+
usage: "Usage: remy-admin infra hibernate <id> [--wait] [--timeout <sec>]",
|
|
5738
|
+
positionals: [{ name: "id", required: true }],
|
|
5739
|
+
flags: { wait: { type: "boolean" }, timeout: { type: "string" } }
|
|
5740
|
+
},
|
|
5741
|
+
"infra resume": {
|
|
5742
|
+
usage: "Usage: remy-admin infra resume <id> [--wait] [--timeout <sec>]",
|
|
5743
|
+
positionals: [{ name: "id", required: true }],
|
|
5744
|
+
flags: { wait: { type: "boolean" }, timeout: { type: "string" } }
|
|
5745
|
+
},
|
|
5746
|
+
"infra destroy": {
|
|
5747
|
+
usage: "Usage: remy-admin infra destroy <id> [--wait] [--timeout <sec>]",
|
|
5748
|
+
positionals: [{ name: "id", required: true }],
|
|
5749
|
+
flags: { wait: { type: "boolean" }, timeout: { type: "string" } }
|
|
5750
|
+
},
|
|
5751
|
+
"infra rename": {
|
|
5752
|
+
usage: "Usage: remy-admin infra rename <id> --name <name>",
|
|
5753
|
+
positionals: [{ name: "id", required: true }],
|
|
5754
|
+
flags: { name: { type: "string" } },
|
|
5755
|
+
requireAnyOf: { flags: ["name"], message: "--name is required." }
|
|
5756
|
+
},
|
|
5757
|
+
"infra resize": {
|
|
5758
|
+
usage: "Usage: remy-admin infra resize <id> --offering <id> [--wait] [--timeout <sec>]",
|
|
5759
|
+
positionals: [{ name: "id", required: true }],
|
|
5760
|
+
flags: {
|
|
5761
|
+
offering: { type: "string" },
|
|
5762
|
+
wait: { type: "boolean" },
|
|
5763
|
+
timeout: { type: "string" }
|
|
5764
|
+
},
|
|
5765
|
+
requireAnyOf: {
|
|
5766
|
+
flags: ["offering"],
|
|
5767
|
+
message: "--offering is required (see `infra list` for the sizes)."
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5770
|
+
};
|
|
5771
|
+
async function waitAndReport(ctx, a, id, phases, summary2, until) {
|
|
5772
|
+
const timeoutSec = a.str("timeout");
|
|
5773
|
+
const result = await waitForPhase(ctx, {
|
|
5774
|
+
id,
|
|
5775
|
+
phases,
|
|
5776
|
+
...until ? { until } : {},
|
|
5777
|
+
...timeoutSec ? { timeoutMs: Number(timeoutSec) * 1e3 } : {},
|
|
5778
|
+
onProgress: progress
|
|
5779
|
+
});
|
|
5780
|
+
out({ ...summary2, ...result });
|
|
5781
|
+
if (result.status === "failed") {
|
|
5782
|
+
throw new CliError(result.error, EXIT.buildFailed);
|
|
5783
|
+
}
|
|
5784
|
+
if (result.status === "timeout") {
|
|
5785
|
+
throw new CliError(result.error, EXIT.timeout);
|
|
5786
|
+
}
|
|
5787
|
+
}
|
|
5788
|
+
async function infraList(ctx, a) {
|
|
5789
|
+
out(await list11(ctx, { includeDestroyed: a.bool("include-destroyed") }));
|
|
5790
|
+
}
|
|
5791
|
+
async function infraGet(ctx, a) {
|
|
5792
|
+
out(await get8(ctx, { id: a.req("id") }));
|
|
5793
|
+
}
|
|
5794
|
+
function pricingOf(resource) {
|
|
5795
|
+
const offering = resource.offering;
|
|
5796
|
+
if (!offering) {
|
|
5797
|
+
return null;
|
|
5798
|
+
}
|
|
5799
|
+
return {
|
|
5800
|
+
offering: offering.id,
|
|
5801
|
+
activeMonthlyDollars: offering.monthlyPriceDollars,
|
|
5802
|
+
hibernatedMonthlyDollars: offering.hibernatedMonthlyPriceDollars,
|
|
5803
|
+
note: "Bills hourly from activation. A month's credits were verified before the lease was accepted."
|
|
5804
|
+
};
|
|
5805
|
+
}
|
|
5806
|
+
async function infraProvision(ctx, a) {
|
|
5807
|
+
const offeringId = a.str("offering");
|
|
5808
|
+
const name = a.str("name");
|
|
5809
|
+
const { resource } = await provision(ctx, {
|
|
5810
|
+
offeringId,
|
|
5811
|
+
...name ? { name } : {}
|
|
5812
|
+
});
|
|
5813
|
+
const pricing = pricingOf(resource);
|
|
5814
|
+
if (!a.bool("wait")) {
|
|
5815
|
+
out({
|
|
5816
|
+
resource,
|
|
5817
|
+
pricing,
|
|
5818
|
+
note: "Provisioning; poll `infra get <id>` or re-run with --wait."
|
|
5819
|
+
});
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
await waitAndReport(ctx, a, resource.id, ["active"], {
|
|
5823
|
+
action: "provision",
|
|
5824
|
+
pricing
|
|
5825
|
+
});
|
|
5826
|
+
}
|
|
5827
|
+
async function infraHibernate(ctx, a) {
|
|
5828
|
+
const id = a.req("id");
|
|
5829
|
+
const { resource } = await hibernate(ctx, { id });
|
|
5830
|
+
if (!a.bool("wait")) {
|
|
5831
|
+
out({ resource });
|
|
5832
|
+
return;
|
|
5833
|
+
}
|
|
5834
|
+
await waitAndReport(ctx, a, id, ["hibernated"], { action: "hibernate" });
|
|
5835
|
+
}
|
|
5836
|
+
async function infraResume(ctx, a) {
|
|
5837
|
+
const id = a.req("id");
|
|
5838
|
+
const { resource } = await resume(ctx, { id });
|
|
5839
|
+
if (!a.bool("wait")) {
|
|
5840
|
+
out({ resource });
|
|
5841
|
+
return;
|
|
5842
|
+
}
|
|
5843
|
+
await waitAndReport(ctx, a, id, ["active"], { action: "resume" });
|
|
5844
|
+
}
|
|
5845
|
+
async function infraDestroy(ctx, a) {
|
|
5846
|
+
const id = a.req("id");
|
|
5847
|
+
const { resource } = await destroy(ctx, { id });
|
|
5848
|
+
if (!a.bool("wait")) {
|
|
5849
|
+
out({ resource });
|
|
5850
|
+
return;
|
|
5851
|
+
}
|
|
5852
|
+
await waitAndReport(ctx, a, id, ["destroyed"], { action: "destroy" });
|
|
5853
|
+
}
|
|
5854
|
+
async function infraRename(ctx, a) {
|
|
5855
|
+
out(
|
|
5856
|
+
await rename(ctx, {
|
|
5857
|
+
id: a.req("id"),
|
|
5858
|
+
name: a.str("name")
|
|
5859
|
+
})
|
|
5860
|
+
);
|
|
5861
|
+
}
|
|
5862
|
+
async function infraResize(ctx, a) {
|
|
5863
|
+
const id = a.req("id");
|
|
5864
|
+
const { resource } = await resize(ctx, {
|
|
5865
|
+
id,
|
|
5866
|
+
offeringId: a.str("offering")
|
|
5867
|
+
});
|
|
5868
|
+
const pricing = pricingOf({
|
|
5869
|
+
...resource,
|
|
5870
|
+
offering: resource.resizingTo ?? resource.offering
|
|
5871
|
+
});
|
|
5872
|
+
if (!a.bool("wait")) {
|
|
5873
|
+
out({
|
|
5874
|
+
resource,
|
|
5875
|
+
pricing,
|
|
5876
|
+
note: "Resizing; searches on its sources pause while it is parked and restored. Poll `infra get <id>` or re-run with --wait."
|
|
5877
|
+
});
|
|
5878
|
+
return;
|
|
5879
|
+
}
|
|
5880
|
+
await waitAndReport(
|
|
5881
|
+
ctx,
|
|
5882
|
+
a,
|
|
5883
|
+
id,
|
|
5884
|
+
[resource.phase],
|
|
5885
|
+
{ action: "resize", pricing },
|
|
5886
|
+
(r) => r.resizingTo === null
|
|
5887
|
+
);
|
|
5888
|
+
}
|
|
5889
|
+
var infraHandlers = {
|
|
5890
|
+
"infra list": infraList,
|
|
5891
|
+
"infra get": infraGet,
|
|
5892
|
+
"infra provision": infraProvision,
|
|
5893
|
+
"infra hibernate": infraHibernate,
|
|
5894
|
+
"infra resume": infraResume,
|
|
5895
|
+
"infra destroy": infraDestroy,
|
|
5896
|
+
"infra rename": infraRename,
|
|
5897
|
+
"infra resize": infraResize
|
|
5898
|
+
};
|
|
5899
|
+
var infraHelp = `remy-admin infra \u2014 Dedicated infrastructure your app leases from the platform.
|
|
5900
|
+
|
|
5901
|
+
Today the one kind is dedicated retrieval: the app's own vector-store capacity
|
|
5902
|
+
for data sources, isolated from the shared pool. Sizes and prices come from the
|
|
5903
|
+
platform catalog (\`infra list\` prints them); nothing is priced client-side.
|
|
5904
|
+
|
|
5905
|
+
A resource bills by the hour from activation, at the retained-storage rate while
|
|
5906
|
+
hibernated, and not at all once destroyed. Provisioning (and growing) needs a
|
|
5907
|
+
month's worth of credits available in the workspace, checked before the request
|
|
5908
|
+
is accepted; nothing is charged until activation. The provision output prints
|
|
5909
|
+
the price it committed to. Every action below is audited.
|
|
5910
|
+
|
|
5911
|
+
Subcommands:
|
|
5912
|
+
list Resources on this app, plus the offerings you can provision
|
|
5913
|
+
get One resource with its state timeline and attached sources
|
|
5914
|
+
provision Lease a new resource (needs a month's credits; prints the price)
|
|
5915
|
+
hibernate Park it: data kept, searches paused, compute charge stops
|
|
5916
|
+
resume Bring a hibernated resource back
|
|
5917
|
+
resize Change its size, data intact (passes through hibernated)
|
|
5918
|
+
destroy Delete it (refused while data sources are placed on it)
|
|
5919
|
+
rename Change the display name
|
|
5920
|
+
|
|
5921
|
+
Usage:
|
|
5922
|
+
remy-admin infra list [--include-destroyed]
|
|
5923
|
+
remy-admin infra get <id>
|
|
5924
|
+
remy-admin infra provision --offering <id> [--name <name>] [--wait] [--timeout <sec>]
|
|
5925
|
+
remy-admin infra hibernate <id> [--wait] [--timeout <sec>]
|
|
5926
|
+
remy-admin infra resume <id> [--wait] [--timeout <sec>]
|
|
5927
|
+
remy-admin infra resize <id> --offering <id> [--wait] [--timeout <sec>]
|
|
5928
|
+
remy-admin infra destroy <id> [--wait] [--timeout <sec>]
|
|
5929
|
+
remy-admin infra rename <id> --name <name>
|
|
5930
|
+
|
|
5931
|
+
Placing a data source on a resource:
|
|
5932
|
+
remy-admin datasources create --source <slug> --placement <resource-id>
|
|
5933
|
+
remy-admin datasources move --source <slug> --to <resource-id|shared> [--wait]
|
|
5934
|
+
|
|
5935
|
+
Start a new corpus on a resource with \`create\`; \`add\` creates a source on
|
|
5936
|
+
the shared pool. A populated source moves with \`datasources move\`: its
|
|
5937
|
+
stored vectors are copied onto the new capacity in the background (no
|
|
5938
|
+
re-embedding), search keeps working from the old placement until the copy
|
|
5939
|
+
lands, and adding or removing documents is refused with
|
|
5940
|
+
data_source_migrating until it finishes. Moving to \`shared\` is how a source
|
|
5941
|
+
leaves a resource you mean to destroy. See \`datasources --help\`.
|
|
5942
|
+
|
|
5943
|
+
Searches on a source whose resource is not active fail with
|
|
5944
|
+
capacity_<phase>: capacity_hibernated once parked, capacity_hibernating /
|
|
5945
|
+
capacity_resuming while it moves. \`active\` means searchable: a resumed
|
|
5946
|
+
resource reports active only once its data is restored. capacity_restoring
|
|
5947
|
+
is the rare case of an active instance that was replaced (node loss) and is
|
|
5948
|
+
refilling from its snapshot. The messages are written for the app's end
|
|
5949
|
+
user; the stable code is what to act on.
|
|
5950
|
+
|
|
5951
|
+
Resizing:
|
|
5952
|
+
A resize keeps the data. The resource is parked (a fresh snapshot), its spec
|
|
5953
|
+
is swapped, and it comes back up restored from that snapshot, so searches on
|
|
5954
|
+
its sources pause for the few minutes it takes. A hibernated resource swaps
|
|
5955
|
+
in place and stays parked. Growing needs a month's credits at the new rate;
|
|
5956
|
+
shrinking is refused below what the resource holds (resize_too_small).
|
|
5957
|
+
\`infra get\` shows resizingTo until the swap has happened.
|
|
5958
|
+
|
|
5959
|
+
Phases and timing:
|
|
5960
|
+
requested \u2192 provisioning \u2192 active \u21C4 hibernated \u2192 destroyed, with hibernating /
|
|
5961
|
+
resuming / decommissioning in between and failed when a change cannot complete
|
|
5962
|
+
(retried automatically; resume or hibernate to retry by hand). Each transition
|
|
5963
|
+
takes about two minutes, more with more data: snapshots and restores scale
|
|
5964
|
+
with the collection. --wait defaults to 600s; pass --timeout for a large one.
|
|
5965
|
+
|
|
5966
|
+
--wait exit codes: 0 reached the target phase \xB7 1 the platform reported failure \xB7
|
|
5967
|
+
2 still transitioning when --timeout elapsed (default 600s).`;
|
|
5968
|
+
|
|
5336
5969
|
// src/commands/index.ts
|
|
5337
5970
|
var SPECS = {
|
|
5338
5971
|
...requestsSpecs,
|
|
@@ -5356,7 +5989,8 @@ var SPECS = {
|
|
|
5356
5989
|
...jewelsSpecs,
|
|
5357
5990
|
...settingsSpecs,
|
|
5358
5991
|
...emailSpecs,
|
|
5359
|
-
...cronSpecs
|
|
5992
|
+
...cronSpecs,
|
|
5993
|
+
...infraSpecs
|
|
5360
5994
|
};
|
|
5361
5995
|
var HANDLERS = {
|
|
5362
5996
|
...requestsHandlers,
|
|
@@ -5380,7 +6014,8 @@ var HANDLERS = {
|
|
|
5380
6014
|
...jewelsHandlers,
|
|
5381
6015
|
...settingsHandlers,
|
|
5382
6016
|
...emailHandlers,
|
|
5383
|
-
...cronHandlers
|
|
6017
|
+
...cronHandlers,
|
|
6018
|
+
...infraHandlers
|
|
5384
6019
|
};
|
|
5385
6020
|
var GROUP_HELP = {
|
|
5386
6021
|
requests: requestsHelp,
|
|
@@ -5404,7 +6039,8 @@ var GROUP_HELP = {
|
|
|
5404
6039
|
jewels: jewelsHelp,
|
|
5405
6040
|
settings: settingsHelp,
|
|
5406
6041
|
email: emailHelp,
|
|
5407
|
-
cron: cronHelp
|
|
6042
|
+
cron: cronHelp,
|
|
6043
|
+
infra: infraHelp
|
|
5408
6044
|
};
|
|
5409
6045
|
|
|
5410
6046
|
// src/ctx.ts
|
|
@@ -5486,6 +6122,7 @@ Commands:
|
|
|
5486
6122
|
settings App settings \u2014 signup allowlist, test accounts, embed origins, toggles
|
|
5487
6123
|
email Email \u2014 delivery log, blast stats, unsubscribes, inbox, custom domains
|
|
5488
6124
|
cron Scheduled jobs \u2014 schedules, run history, manual trigger
|
|
6125
|
+
infra Dedicated infrastructure \u2014 provision, hibernate, resize + destroy retrieval capacity
|
|
5489
6126
|
|
|
5490
6127
|
Run 'remy-admin <command> --help' for details on each command.
|
|
5491
6128
|
|
|
@@ -5517,7 +6154,8 @@ var GROUPS = [
|
|
|
5517
6154
|
"jewels",
|
|
5518
6155
|
"settings",
|
|
5519
6156
|
"email",
|
|
5520
|
-
"cron"
|
|
6157
|
+
"cron",
|
|
6158
|
+
"infra"
|
|
5521
6159
|
];
|
|
5522
6160
|
var KEYS = new Set(Object.keys(SPECS));
|
|
5523
6161
|
function resolveRoute(argv) {
|