@bike4mind/cli 0.20.1 → 0.20.2
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/{AgentHistoryStore-BQiATPsQ.mjs → AgentHistoryStore-T7Oh84Yn.mjs} +1174 -313
- package/dist/{ApiClient-BPmlalut.mjs → ApiClient-BopvMmQk.mjs} +5 -5
- package/dist/{ConfigStore-CNfbeaJf.mjs → ConfigStore-cIyF7hDg.mjs} +732 -89
- package/dist/ProxyManager-B1jFWL7b.mjs +3 -0
- package/dist/{buildAgent-DwPvcTpz.mjs → buildAgent-P0tOMLt1.mjs} +3 -3
- package/dist/commands/acpCommand.mjs +4 -4
- package/dist/commands/apiCommand.mjs +1 -1
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/envCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +4 -4
- package/dist/commands/mcpCommand.mjs +3 -3
- package/dist/commands/pluginCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +44 -13
- package/dist/{package-CxHSRXdp.mjs → package-CnVCHR3U.mjs} +1 -1
- package/dist/{serve-Du3HiqAH.mjs → serve-BocVOJ3W.mjs} +2 -2
- package/package.json +8 -8
- package/dist/ProxyManager-Bqr7Lmsd.mjs +0 -3
- package/dist/{ProxyManager-C5H0pUyK.mjs → ProxyManager-C1-lgzEU.mjs} +1 -1
|
@@ -699,6 +699,12 @@ let KnowledgeType = /* @__PURE__ */ function(KnowledgeType) {
|
|
|
699
699
|
* so the client can branch to a targeted error UI (see `IChatHistoryItem.errorCode`).
|
|
700
700
|
* Single source of truth: the streamed-action Zod enum in `schemas/actions.ts`
|
|
701
701
|
* derives its values from this tuple, so the two can never drift.
|
|
702
|
+
*
|
|
703
|
+
* SSE-frame scoped, and a NARROWING of the platform-wide `API_ERROR_CODES`: a
|
|
704
|
+
* quest fails for billing reasons, never for the provider-configuration reasons
|
|
705
|
+
* the HTTP surface reports. The `satisfies` is what keeps it a narrowing rather
|
|
706
|
+
* than a second vocabulary - a code added here that is not in `API_ERROR_CODES`
|
|
707
|
+
* fails the build.
|
|
702
708
|
*/
|
|
703
709
|
const QUEST_ERROR_CODES = ["insufficient_credits", "spend_cap_exceeded"];
|
|
704
710
|
z$1.union([
|
|
@@ -896,6 +902,12 @@ let ChatModels = /* @__PURE__ */ function(ChatModels) {
|
|
|
896
902
|
const CHAT_MODELS = Object.values(ChatModels);
|
|
897
903
|
const supportedChatModels = z$1.enum(ChatModels);
|
|
898
904
|
/**
|
|
905
|
+
* Every `ChatModels` Gemini entry is named `gemini...` (see the GEMINI block above) - a prefix
|
|
906
|
+
* check tracks that naming convention automatically as new Gemini models are added, unlike an
|
|
907
|
+
* explicit id list that would need updating in lockstep and could silently miss one.
|
|
908
|
+
*/
|
|
909
|
+
const isGeminiModelId = (model) => model.startsWith("gemini");
|
|
910
|
+
/**
|
|
899
911
|
* Models that support the reasoning_effort parameter.
|
|
900
912
|
* o1-preview and o1-mini do NOT support reasoning_effort.
|
|
901
913
|
*/
|
|
@@ -1369,6 +1381,12 @@ z$1.object({
|
|
|
1369
1381
|
ownerId: z$1.string(),
|
|
1370
1382
|
ownerType: z$1.enum(CreditHolderType),
|
|
1371
1383
|
sessionId: z$1.string().optional(),
|
|
1384
|
+
/**
|
|
1385
|
+
* Data lake this call is 1:1 attributable to (ingestion embeds only - a query
|
|
1386
|
+
* embedding can span multiple lakes and is never attributed here). Unset for
|
|
1387
|
+
* every other feature/call.
|
|
1388
|
+
*/
|
|
1389
|
+
dataLakeId: z$1.string().optional(),
|
|
1372
1390
|
feature: z$1.enum([
|
|
1373
1391
|
"chat",
|
|
1374
1392
|
"image_generation",
|
|
@@ -2246,6 +2264,46 @@ z$1.object({
|
|
|
2246
2264
|
expiresAt: z$1.date().nullish()
|
|
2247
2265
|
});
|
|
2248
2266
|
/**
|
|
2267
|
+
* Every `IDataLake` field, classified as audited or not. A TOTAL map keyed by `keyof IDataLake`,
|
|
2268
|
+
* exactly like `LAKE_FIELD_VISIBILITY` in redactLakeForActor.ts and for the same reason: a list of
|
|
2269
|
+
* strings cannot notice an ABSENCE, so a new config field would simply never be audited and nobody
|
|
2270
|
+
* would find out. Keyed this way, a field added to the entity and classified nowhere is a COMPILE
|
|
2271
|
+
* error here, which is the only forcing function that actually works.
|
|
2272
|
+
*
|
|
2273
|
+
* `excluded` is for fields no operator chooses and which steer no answer: the content stats, the
|
|
2274
|
+
* teardown bookkeeping stamps, the cost meter and the lake-memory lease. They change constantly and
|
|
2275
|
+
* a history full of them would bury the changes that matter.
|
|
2276
|
+
*/
|
|
2277
|
+
const LAKE_CONFIG_FIELD_AUDIT = {
|
|
2278
|
+
name: "audited",
|
|
2279
|
+
slug: "audited",
|
|
2280
|
+
description: "audited",
|
|
2281
|
+
systemPrompt: "audited",
|
|
2282
|
+
preferredSystemPromptId: "audited",
|
|
2283
|
+
groundingMode: "audited",
|
|
2284
|
+
requiredPassageTokenTarget: "audited",
|
|
2285
|
+
fileTagPrefix: "audited",
|
|
2286
|
+
datalakeTag: "audited",
|
|
2287
|
+
requiredUserTag: "audited",
|
|
2288
|
+
requiredEntitlement: "audited",
|
|
2289
|
+
organizationId: "audited",
|
|
2290
|
+
isPublic: "audited",
|
|
2291
|
+
auditQueryTextEnabled: "audited",
|
|
2292
|
+
status: "audited",
|
|
2293
|
+
createdByUserId: "audited",
|
|
2294
|
+
lastUpdatedByUserId: "excluded",
|
|
2295
|
+
fileCount: "excluded",
|
|
2296
|
+
totalSizeBytes: "excluded",
|
|
2297
|
+
totalChunkedChars: "excluded",
|
|
2298
|
+
embeddingSpendMicroUsd: "excluded",
|
|
2299
|
+
lastSyncAt: "excluded",
|
|
2300
|
+
filesDeletedAt: "excluded",
|
|
2301
|
+
filesArchivedAt: "excluded",
|
|
2302
|
+
lakeMemoryExtractionAt: "excluded",
|
|
2303
|
+
lakeMemoryCursor: "excluded"
|
|
2304
|
+
};
|
|
2305
|
+
[...Object.keys(LAKE_CONFIG_FIELD_AUDIT).filter((field) => LAKE_CONFIG_FIELD_AUDIT[field] === "audited")];
|
|
2306
|
+
/**
|
|
2249
2307
|
* SRE Agent Trio - Shared Types
|
|
2250
2308
|
*
|
|
2251
2309
|
* Types for the autonomous SRE pipeline:
|
|
@@ -3043,6 +3101,66 @@ z.enum([
|
|
|
3043
3101
|
"xai",
|
|
3044
3102
|
"gemini"
|
|
3045
3103
|
]);
|
|
3104
|
+
z$1.object({
|
|
3105
|
+
sessionId: z$1.string().nullish(),
|
|
3106
|
+
message: z$1.string(),
|
|
3107
|
+
organizationId: z$1.string().optional(),
|
|
3108
|
+
model: z$1.string().optional(),
|
|
3109
|
+
temperature: z$1.number().min(0).max(2).optional(),
|
|
3110
|
+
max_tokens: z$1.number().positive().optional(),
|
|
3111
|
+
maxTokens: z$1.number().positive().optional(),
|
|
3112
|
+
maxOutputTokens: z$1.number().positive().optional(),
|
|
3113
|
+
stream: z$1.boolean().prefault(false),
|
|
3114
|
+
historyCount: z$1.number().positive().default(10),
|
|
3115
|
+
fileIds: z$1.array(z$1.string()).prefault([]),
|
|
3116
|
+
wait: z$1.boolean().prefault(false),
|
|
3117
|
+
enableTools: z$1.boolean().prefault(false),
|
|
3118
|
+
toolMode: z$1.enum(["fast", "smart"]).optional(),
|
|
3119
|
+
tools: z$1.array(z$1.string()).optional(),
|
|
3120
|
+
enableQuestMaster: z$1.boolean().optional(),
|
|
3121
|
+
enableMementos: z$1.boolean().optional(),
|
|
3122
|
+
enableAgents: z$1.boolean().optional(),
|
|
3123
|
+
promptMode: z$1.enum([
|
|
3124
|
+
"raw",
|
|
3125
|
+
"grounded",
|
|
3126
|
+
"surface"
|
|
3127
|
+
]).optional(),
|
|
3128
|
+
includePromptDetails: z$1.boolean().optional(),
|
|
3129
|
+
includeSystemPrompt: z$1.boolean().optional()
|
|
3130
|
+
});
|
|
3131
|
+
z$1.object({
|
|
3132
|
+
id: z$1.string(),
|
|
3133
|
+
status: z$1.string(),
|
|
3134
|
+
message_received: z$1.boolean(),
|
|
3135
|
+
timestamp: z$1.string(),
|
|
3136
|
+
model: z$1.string(),
|
|
3137
|
+
message: z$1.string().optional(),
|
|
3138
|
+
tracking_info: z$1.object({
|
|
3139
|
+
quest_id: z$1.string(),
|
|
3140
|
+
check_status_url: z$1.string(),
|
|
3141
|
+
poll_url: z$1.string().optional()
|
|
3142
|
+
})
|
|
3143
|
+
});
|
|
3144
|
+
/**
|
|
3145
|
+
* Reusable JSON error envelope (plain; the OpenAPI layer annotates it).
|
|
3146
|
+
*
|
|
3147
|
+
* Must stay in sync with the published `ErrorResponse` component
|
|
3148
|
+
* (../openapi/schemas.ts) - `openapi/errorEnvelopeParity.test.ts` pins the two
|
|
3149
|
+
* together, and apps/client's errorHandler test uses this shape as the stand-in for
|
|
3150
|
+
* the component, which is generate-time only and cannot be imported at runtime.
|
|
3151
|
+
*/
|
|
3152
|
+
const ApiErrorSchema = z$1.object({
|
|
3153
|
+
error: z$1.string(),
|
|
3154
|
+
request_id: z$1.string().optional(),
|
|
3155
|
+
/**
|
|
3156
|
+
* Deprecated, sunset 2026-12-01. The `name` of whatever was thrown - our own error
|
|
3157
|
+
* classes usually, a library/driver class name on an unhandled 500 - added to every
|
|
3158
|
+
* body by apps/client's errorHandler. Documented here so the runtime and the spec
|
|
3159
|
+
* agree while it is still served; do not build on it. See CONVENTIONS.md section 1.
|
|
3160
|
+
*/
|
|
3161
|
+
name: z$1.string().optional()
|
|
3162
|
+
});
|
|
3163
|
+
ApiErrorSchema.extend({ errorCode: z$1.literal("insufficient_credits").optional() });
|
|
3046
3164
|
const supportedVoiceGenerationVendor = z.enum(["openai", "elevenlabs"]);
|
|
3047
3165
|
const voiceOutputFormatSchema = z.enum([
|
|
3048
3166
|
"mp3",
|
|
@@ -3071,6 +3189,49 @@ z.object({
|
|
|
3071
3189
|
languageCode: ttsLanguageCodeSchema.optional(),
|
|
3072
3190
|
preview: z.boolean().optional()
|
|
3073
3191
|
});
|
|
3192
|
+
/**
|
|
3193
|
+
* Why a browsable copy of generated audio was not kept. Saving is best-effort and
|
|
3194
|
+
* never fatal (the caller was already billed for the bytes it is being handed), so
|
|
3195
|
+
* this is reported alongside a successful response rather than as an error.
|
|
3196
|
+
*
|
|
3197
|
+
* Must stay in sync with `PersistGeneratedAudioResult` in
|
|
3198
|
+
* apps/client/server/utils/persistGeneratedAudio.ts, which derives its `reason`
|
|
3199
|
+
* from this schema.
|
|
3200
|
+
*/
|
|
3201
|
+
const audioSaveSkippedReasonSchema = z.enum([
|
|
3202
|
+
"storage_limit",
|
|
3203
|
+
"file_too_large",
|
|
3204
|
+
"error"
|
|
3205
|
+
]);
|
|
3206
|
+
z.object({
|
|
3207
|
+
/** Base64-encoded audio payload. */
|
|
3208
|
+
audio: z.string(),
|
|
3209
|
+
format: voiceOutputFormatSchema,
|
|
3210
|
+
contentType: z.string(),
|
|
3211
|
+
saved: z.boolean().optional(),
|
|
3212
|
+
fabFileId: z.string().optional(),
|
|
3213
|
+
fileUrl: z.string().optional(),
|
|
3214
|
+
saveSkippedReason: audioSaveSkippedReasonSchema.optional(),
|
|
3215
|
+
/** The provider that actually produced the audio, present only on a fallback. */
|
|
3216
|
+
provider: supportedVoiceGenerationVendor.optional(),
|
|
3217
|
+
/** The originally requested provider that could not serve the request. */
|
|
3218
|
+
fallbackFrom: supportedVoiceGenerationVendor.optional()
|
|
3219
|
+
});
|
|
3220
|
+
ApiErrorSchema.extend({
|
|
3221
|
+
provider: supportedVoiceGenerationVendor.optional(),
|
|
3222
|
+
errorCode: z.enum([
|
|
3223
|
+
"insufficient_credits",
|
|
3224
|
+
"provider_not_configured",
|
|
3225
|
+
"provider_rejected"
|
|
3226
|
+
]).optional()
|
|
3227
|
+
});
|
|
3228
|
+
z.object({
|
|
3229
|
+
error: z.string(),
|
|
3230
|
+
provider: supportedVoiceGenerationVendor,
|
|
3231
|
+
saved: z.literal(true).optional(),
|
|
3232
|
+
fabFileId: z.string().optional(),
|
|
3233
|
+
fileUrl: z.string().optional()
|
|
3234
|
+
});
|
|
3074
3235
|
z.enum(["openai"]);
|
|
3075
3236
|
/**
|
|
3076
3237
|
* Supported sound-effects generation vendors. Currently only ElevenLabs.
|
|
@@ -4578,51 +4739,6 @@ z$1.discriminatedUnion("action", [
|
|
|
4578
4739
|
PermissionRequestAction,
|
|
4579
4740
|
ReconnectResultAction
|
|
4580
4741
|
]);
|
|
4581
|
-
z$1.object({
|
|
4582
|
-
sessionId: z$1.string().nullish(),
|
|
4583
|
-
message: z$1.string(),
|
|
4584
|
-
organizationId: z$1.string().optional(),
|
|
4585
|
-
model: z$1.string().optional(),
|
|
4586
|
-
temperature: z$1.number().min(0).max(2).optional(),
|
|
4587
|
-
max_tokens: z$1.number().positive().optional(),
|
|
4588
|
-
maxTokens: z$1.number().positive().optional(),
|
|
4589
|
-
maxOutputTokens: z$1.number().positive().optional(),
|
|
4590
|
-
stream: z$1.boolean().prefault(false),
|
|
4591
|
-
historyCount: z$1.number().positive().default(10),
|
|
4592
|
-
fileIds: z$1.array(z$1.string()).prefault([]),
|
|
4593
|
-
wait: z$1.boolean().prefault(false),
|
|
4594
|
-
enableTools: z$1.boolean().prefault(false),
|
|
4595
|
-
toolMode: z$1.enum(["fast", "smart"]).optional(),
|
|
4596
|
-
tools: z$1.array(z$1.string()).optional(),
|
|
4597
|
-
enableQuestMaster: z$1.boolean().optional(),
|
|
4598
|
-
enableMementos: z$1.boolean().optional(),
|
|
4599
|
-
enableAgents: z$1.boolean().optional(),
|
|
4600
|
-
promptMode: z$1.enum([
|
|
4601
|
-
"raw",
|
|
4602
|
-
"grounded",
|
|
4603
|
-
"surface"
|
|
4604
|
-
]).optional(),
|
|
4605
|
-
includePromptDetails: z$1.boolean().optional(),
|
|
4606
|
-
includeSystemPrompt: z$1.boolean().optional()
|
|
4607
|
-
});
|
|
4608
|
-
z$1.object({
|
|
4609
|
-
id: z$1.string(),
|
|
4610
|
-
status: z$1.string(),
|
|
4611
|
-
message_received: z$1.boolean(),
|
|
4612
|
-
timestamp: z$1.string(),
|
|
4613
|
-
model: z$1.string(),
|
|
4614
|
-
message: z$1.string().optional(),
|
|
4615
|
-
tracking_info: z$1.object({
|
|
4616
|
-
quest_id: z$1.string(),
|
|
4617
|
-
check_status_url: z$1.string(),
|
|
4618
|
-
poll_url: z$1.string().optional()
|
|
4619
|
-
})
|
|
4620
|
-
});
|
|
4621
|
-
/** Reusable JSON error envelope (plain; the OpenAPI layer annotates it). */
|
|
4622
|
-
const ApiErrorSchema = z$1.object({
|
|
4623
|
-
error: z$1.string(),
|
|
4624
|
-
request_id: z$1.string().optional()
|
|
4625
|
-
});
|
|
4626
4742
|
/**
|
|
4627
4743
|
* Tool schema matching ICompletionOptionTools.toolSchema. The Zod surface only
|
|
4628
4744
|
* covers wire-format fields (toolFn is server-side). Replaces the historical
|
|
@@ -4716,6 +4832,7 @@ const CompletionContentEventSchema = z$1.object({
|
|
|
4716
4832
|
"tool_use",
|
|
4717
4833
|
"best-effort"
|
|
4718
4834
|
]).optional(),
|
|
4835
|
+
stopReason: z$1.string().optional(),
|
|
4719
4836
|
thinking: z$1.array(z$1.any()).optional()
|
|
4720
4837
|
});
|
|
4721
4838
|
const CompletionSseErrorEventSchema = z$1.object({
|
|
@@ -5294,7 +5411,7 @@ const BFL_SAFETY_TOLERANCE = {
|
|
|
5294
5411
|
*/
|
|
5295
5412
|
const BFLSafetyToleranceSchema = z$1.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.LEGACY_INPUT_MAX).optional().prefault(BFL_SAFETY_TOLERANCE.DEFAULT).transform((value) => Math.min(value, BFL_SAFETY_TOLERANCE.MAX));
|
|
5296
5413
|
/**
|
|
5297
|
-
* List of image models supported by
|
|
5414
|
+
* List of image models supported by Black Forest Labs
|
|
5298
5415
|
*/
|
|
5299
5416
|
const BFL_IMAGE_MODELS = [
|
|
5300
5417
|
"flux-pro-1.1",
|
|
@@ -5595,6 +5712,32 @@ z$1.enum([
|
|
|
5595
5712
|
"complex"
|
|
5596
5713
|
]);
|
|
5597
5714
|
z$1.preprocess((v) => Array.isArray(v) ? v.at(-1) : v, z$1.union([z$1.boolean(), z$1.string()])).prefault(false).transform((v) => ["true", "1"].includes(String(v).toLowerCase())).catch(false);
|
|
5715
|
+
const SessionTagSchema = z$1.object({
|
|
5716
|
+
name: z$1.string(),
|
|
5717
|
+
strength: z$1.number()
|
|
5718
|
+
});
|
|
5719
|
+
z$1.object({
|
|
5720
|
+
name: z$1.string().min(1).optional(),
|
|
5721
|
+
knowledgeIds: z$1.array(z$1.string()).optional(),
|
|
5722
|
+
artifactIds: z$1.array(z$1.string()).optional(),
|
|
5723
|
+
tags: z$1.array(SessionTagSchema).optional(),
|
|
5724
|
+
lastUsedModel: z$1.string().min(1).nullish().describe("Pin a specific model id, or omit/send null to leave the current pin unchanged. Sending null does NOT clear it."),
|
|
5725
|
+
forceKnowledgeRetrieval: z$1.boolean().optional(),
|
|
5726
|
+
propagateToProjects: z$1.boolean().optional().describe("Defaults to true when omitted. When knowledgeIds grows, the newly-added file ids are also appended to every project that contains this session, granting every member of that project access to those files. This propagation is append-only and cannot be undone through the UI - pass false if newly-attached files should not be shared with the project.")
|
|
5727
|
+
});
|
|
5728
|
+
z$1.object({ id: z$1.string().min(1) });
|
|
5729
|
+
z$1.object({
|
|
5730
|
+
id: z$1.string(),
|
|
5731
|
+
name: z$1.string(),
|
|
5732
|
+
userId: z$1.string(),
|
|
5733
|
+
knowledgeIds: z$1.array(z$1.string()).optional(),
|
|
5734
|
+
artifactIds: z$1.array(z$1.string()).optional(),
|
|
5735
|
+
tags: z$1.array(SessionTagSchema).optional(),
|
|
5736
|
+
forceKnowledgeRetrieval: z$1.boolean().optional(),
|
|
5737
|
+
lastUsedModel: z$1.string().nullish(),
|
|
5738
|
+
firstCreated: z$1.date(),
|
|
5739
|
+
lastUpdated: z$1.date()
|
|
5740
|
+
});
|
|
5598
5741
|
z$2.enum([
|
|
5599
5742
|
"",
|
|
5600
5743
|
"TFG",
|
|
@@ -5662,16 +5805,129 @@ z$2.object({
|
|
|
5662
5805
|
isOnline: z$2.boolean()
|
|
5663
5806
|
});
|
|
5664
5807
|
/**
|
|
5665
|
-
*
|
|
5666
|
-
*
|
|
5667
|
-
*
|
|
5668
|
-
*
|
|
5669
|
-
*
|
|
5670
|
-
|
|
5808
|
+
* A chunk larger than this (in tokens) marks a file whose chunking predates the passage-target
|
|
5809
|
+
* fix: a whole-document / whole-section blob rather than a ~512-token passage. Used to detect the
|
|
5810
|
+
* files a lake "Rebuild passages" pass should re-chunk. Deliberately well above
|
|
5811
|
+
* DEFAULT_PASSAGE_TOKEN_TARGET (512) so a correctly-chunked passage never trips it, and below the
|
|
5812
|
+
* ~6.5K model-window packing the old chunker produced, so every legacy blob does.
|
|
5813
|
+
*/
|
|
5814
|
+
const OVERSIZED_PASSAGE_TOKEN_THRESHOLD = 1500;
|
|
5815
|
+
/**
|
|
5816
|
+
* `FabFile.notes` marker written when the data-lake convergence kill switch abandons a vectorize
|
|
5817
|
+
* (#1676). The file keeps its chunks but has no vectors, so it is unsearchable until re-indexed, and
|
|
5818
|
+
* it does NOT auto-resume.
|
|
5819
|
+
*
|
|
5820
|
+
* Lives here rather than beside its writer (apps/client fabFileVectorize) because it is a
|
|
5821
|
+
* cross-layer contract: the queue handler writes it and the lake-health evaluator
|
|
5822
|
+
* (constants/lakeHealth.ts) reads it to tell a permanently-stalled file from one still in flight.
|
|
5823
|
+
* b4m-core cannot import from apps/client, so a copy there would have to drift silently.
|
|
5824
|
+
*/
|
|
5825
|
+
const CONVERGENCE_PAUSED_NOTE = "Indexing paused by the data-lake convergence kill switch - reprocess to complete.";
|
|
5826
|
+
/**
|
|
5827
|
+
* `FabFile.notes` marker for the OTHER half of the same kill switch: a re-chunk dropped before it
|
|
5828
|
+
* ran (#1676/#1681). Distinct from `CONVERGENCE_PAUSED_NOTE` because the damage is worse and the
|
|
5829
|
+
* wording has to say so - the producer resets a wave's chunk state BEFORE the messages are handled,
|
|
5830
|
+
* so a file halted here has NO chunks at all rather than chunks without vectors.
|
|
5831
|
+
*
|
|
5832
|
+
* Without a marker this state is invisible to every surface at once, which is the failure it exists
|
|
5833
|
+
* to prevent: `chunkCount: 0` with `error: null` reads as an image or a pending upload, so health
|
|
5834
|
+
* drops it from the denominator, convergence grades it `conformant` (its stale stamp still matches),
|
|
5835
|
+
* search does not withhold it because it is not "in flight", and the rescue sweep's own filter
|
|
5836
|
+
* passes over it. The file's passages are simply gone and nothing reports it.
|
|
5837
|
+
*
|
|
5838
|
+
* Same cross-layer reason as the constant above for living here: the queue handler writes it and
|
|
5839
|
+
* b4m-core's evaluators read it, and b4m-core cannot import from apps/client.
|
|
5840
|
+
*/
|
|
5841
|
+
const CONVERGENCE_PAUSED_CHUNK_NOTE = "Re-chunking paused by the data-lake convergence kill switch - its passages were removed and are rebuilt when convergence resumes.";
|
|
5842
|
+
/**
|
|
5843
|
+
* `FabFile.chunkRebuildRequestedAt`: stamped by `resetChunkStateByIds` in the SAME write that
|
|
5844
|
+
* clears a file's chunk rollups, so "this file's passages are being rebuilt" can never be lost the
|
|
5845
|
+
* way the pair of steps that creates the state can be. The reset and the queue send are two
|
|
5846
|
+
* operations - kill the producer between them, or lose the consumer's marker write, and the file
|
|
5847
|
+
* sits at `chunkCount: 0` with `error: null` and `notes: ''`, a shape indistinguishable from an
|
|
5848
|
+
* image or a still-uploading row. It then drops out of lake health's denominator, out of the
|
|
5849
|
+
* convergence plan and out of the retrieval withhold at the same moment: every rollup says its
|
|
5850
|
+
* passages are gone, and nothing reports it.
|
|
5851
|
+
*
|
|
5852
|
+
* Deliberately NOT `CONVERGENCE_PAUSED_CHUNK_NOTE` pre-written by the producer, which is the obvious
|
|
5853
|
+
* fix and the wrong one: that marker means "halted, needs an administrator", so a file awaiting an
|
|
5854
|
+
* ORDINARY rebuild would read to every reader as permanently paused for the whole rebuild - search
|
|
5855
|
+
* would tell readers it does not return on its own, health would hard-fail P3, and "Rebuild
|
|
5856
|
+
* passages" would offer to repair a file that is already repairing. A flag that cries wolf on the
|
|
5857
|
+
* normal path is worse than the rare window it closes.
|
|
5858
|
+
*
|
|
5859
|
+
* So the two facts are distinct states, and the consumer UPGRADES one to the other: pending means
|
|
5860
|
+
* "in flight, returns on its own", the paused note means "halted, needs intervention". A LOST
|
|
5861
|
+
* upgrade therefore degrades to mislabelled-but-visible rather than invisible, which is the trade
|
|
5862
|
+
* this field exists to make - invisibility is the real harm, labelling is secondary.
|
|
5863
|
+
*
|
|
5864
|
+
* A dedicated field rather than a third `notes` string on purpose: `notes` already carries two
|
|
5865
|
+
* unrelated facts (the user's own note / NO_EXTRACTABLE_TEXT, and the kill-switch markers), so every
|
|
5866
|
+
* writer of it clobbers the others.
|
|
5867
|
+
*
|
|
5868
|
+
* Cleared by `commitFabFileChunks` (the rebuild landed) and by the chunk handler's pause write (the
|
|
5869
|
+
* rebuild was halted instead). A file carrying `error` is settled regardless - see
|
|
5870
|
+
* `isMemberIndexingInFlight`, which is where the precedence between these three lives.
|
|
5871
|
+
*/
|
|
5872
|
+
function isChunkRebuildPending(requestedAt) {
|
|
5873
|
+
return requestedAt !== null && requestedAt !== void 0 && requestedAt !== "";
|
|
5874
|
+
}
|
|
5875
|
+
/**
|
|
5876
|
+
* Whether a file's `notes` marks it as stalled by the convergence kill switch, by either arm.
|
|
5877
|
+
* THE predicate every reader uses, so adding a third stall marker reaches health, convergence and
|
|
5878
|
+
* retrieval without three separate string comparisons drifting apart.
|
|
5879
|
+
*/
|
|
5880
|
+
function isConvergencePausedNote(notes) {
|
|
5881
|
+
return CONVERGENCE_PAUSED_NOTES.includes(notes);
|
|
5882
|
+
}
|
|
5883
|
+
/**
|
|
5884
|
+
* Datastore mirror of `isConvergencePausedNote`, for a Mongo `notes: { $in: [...] }`. Exported so a
|
|
5885
|
+
* query and the in-memory predicate cannot drift: adding a third stall marker to this array reaches
|
|
5886
|
+
* both. Declared after the two constants it names so the function above can close over it.
|
|
5671
5887
|
*/
|
|
5672
|
-
const
|
|
5888
|
+
const CONVERGENCE_PAUSED_NOTES = [CONVERGENCE_PAUSED_NOTE, CONVERGENCE_PAUSED_CHUNK_NOTE];
|
|
5673
5889
|
/** Ceiling so "adjustable" cannot mean "unbounded" in either direction. */
|
|
5674
5890
|
const LAKE_ACCESS_AUDIT_RETENTION_MAX_DAYS = 2555;
|
|
5891
|
+
/**
|
|
5892
|
+
* Lake CONFIG-change audit retention and value caps.
|
|
5893
|
+
*
|
|
5894
|
+
* Twin of `constants/lakeAccessAudit.ts` and here for the same reason: the values are needed by
|
|
5895
|
+
* both the admin-settings schema in this package and by the repository that applies them
|
|
5896
|
+
* (`packages/database`, which cannot import an app-server layer).
|
|
5897
|
+
*
|
|
5898
|
+
* DELIBERATELY NOT the same numbers as the read audit, and deliberately not the same lever. A
|
|
5899
|
+
* retrieval is frequent, low-value and cheap to lose; a config change is rare, high-value and
|
|
5900
|
+
* alters every future answer the lake gives, so the two want opposite retention. Folding config
|
|
5901
|
+
* changes into the read collection would force one of them onto the other's clock - either a
|
|
5902
|
+
* config change expiring on a read-volume schedule, or a high-volume collection's storage
|
|
5903
|
+
* multiplied to serve a low-volume need.
|
|
5904
|
+
*
|
|
5905
|
+
* Same one-way ratchet as the read side (#1658's levers rule): `resolveLakeConfigAuditRetentionDays`
|
|
5906
|
+
* can only raise a configured value to the floor, never lower it, so an org cannot configure its
|
|
5907
|
+
* own retention down to nothing and defeat the control. Platform-level, not per-org: the setting
|
|
5908
|
+
* carries no `scope.settableAt`, so #1660's resolver returns the platform value at every scope.
|
|
5909
|
+
*/
|
|
5910
|
+
/** 3 years: long enough to outlive a typical contract and audit cycle, on a collection whose
|
|
5911
|
+
* volume is a few rows per lake per year. Longer than the read audit's 450 days on purpose - the
|
|
5912
|
+
* rarer and more consequential the event, the longer it is worth keeping. */
|
|
5913
|
+
const LAKE_CONFIG_AUDIT_RETENTION_FLOOR_DAYS = 1095;
|
|
5914
|
+
/** A separate constant from the floor on purpose, even though they agree today - a future change
|
|
5915
|
+
* to one must not silently move the other. */
|
|
5916
|
+
const LAKE_CONFIG_AUDIT_RETENTION_DEFAULT_DAYS = 1095;
|
|
5917
|
+
/** Ceiling so "adjustable" cannot mean "unbounded" in either direction. */
|
|
5918
|
+
const LAKE_CONFIG_AUDIT_RETENTION_MAX_DAYS = 3650;
|
|
5919
|
+
/**
|
|
5920
|
+
* Forced-retrieval budget defaults, shared between the admin-settings schema in this package and
|
|
5921
|
+
* `ChatCompletionFeatures.ts` (which cannot import from `common`'s settings schema without a
|
|
5922
|
+
* dependency cycle, so the constant lives here instead).
|
|
5923
|
+
*
|
|
5924
|
+
* Only `FORCED_RETRIEVAL_CHAR_BUDGET_DEFAULT` is a lever (see the `forcedRetrievalCharBudget`
|
|
5925
|
+
* setting) - the char budget is the measured binding constraint on how much of a corpus reaches
|
|
5926
|
+
* the model on every Data-Lake-mode turn. The relevance floor is exported alongside it so the two
|
|
5927
|
+
* stay next to each other, not because it is tunable today.
|
|
5928
|
+
*/
|
|
5929
|
+
/** Total characters of retrieved chunk text injected into a forced-retrieval prompt. */
|
|
5930
|
+
const FORCED_RETRIEVAL_CHAR_BUDGET_DEFAULT = 12e3;
|
|
5675
5931
|
let OpenAIEmbeddingModel = /* @__PURE__ */ function(OpenAIEmbeddingModel) {
|
|
5676
5932
|
OpenAIEmbeddingModel["TEXT_EMBEDDING_3_SMALL"] = "text-embedding-3-small";
|
|
5677
5933
|
OpenAIEmbeddingModel["TEXT_EMBEDDING_3_LARGE"] = "text-embedding-3-large";
|
|
@@ -5882,6 +6138,10 @@ z$1.enum([
|
|
|
5882
6138
|
"EnableLakeMemory",
|
|
5883
6139
|
"EnableDataLakeVectorSearch",
|
|
5884
6140
|
"PauseLakeConvergence",
|
|
6141
|
+
"LakeConvergenceBulkChangeSharePct",
|
|
6142
|
+
"EnforceLakeReadGrants",
|
|
6143
|
+
"EnableDataLakeDrivePoll",
|
|
6144
|
+
"EnforceLakeAdmission",
|
|
5885
6145
|
"EnableBriefcase",
|
|
5886
6146
|
"EnableBriefcaseDefault",
|
|
5887
6147
|
"EnableImageTemplates",
|
|
@@ -5907,6 +6167,7 @@ z$1.enum([
|
|
|
5907
6167
|
"ReferralCreditsAmount",
|
|
5908
6168
|
"registrationLink",
|
|
5909
6169
|
"FeedbackReceiveEmail",
|
|
6170
|
+
"FeedbackReceiveEmailNonProd",
|
|
5910
6171
|
"FeedbackKyle",
|
|
5911
6172
|
"EnableFeedBackToEmail",
|
|
5912
6173
|
"EnableFeedBackToSlack",
|
|
@@ -5972,6 +6233,10 @@ z$1.enum([
|
|
|
5972
6233
|
"defaultEmbeddingModel",
|
|
5973
6234
|
"dataLakeSearchMaxFiles",
|
|
5974
6235
|
"dataLakeSearchMaxChunks",
|
|
6236
|
+
"forcedRetrievalCharBudget",
|
|
6237
|
+
"kbSearchDefaultResults",
|
|
6238
|
+
"kbSearchResultTokenBudget",
|
|
6239
|
+
"kbSearchMinRelevancePct",
|
|
5975
6240
|
"dataLakeEmbeddingSpendEnabled",
|
|
5976
6241
|
"dataLakeEmbeddingBudgetPerRunUsd",
|
|
5977
6242
|
"dataLakeEmbeddingBudgetPerLakeUsd",
|
|
@@ -5979,8 +6244,11 @@ z$1.enum([
|
|
|
5979
6244
|
"dataLakeEmbeddingBudgetPeriodHours",
|
|
5980
6245
|
"dataLakeEmbeddingMaxCallsPerMinute",
|
|
5981
6246
|
"dataLakeVectorizeChunkBatchSize",
|
|
6247
|
+
"dataLakeEmbeddingTierMultiplierIndividual",
|
|
6248
|
+
"dataLakeEmbeddingTierMultiplierOrganization",
|
|
5982
6249
|
"LakeAccessAuditRetentionDays",
|
|
5983
6250
|
"LakeAccessQueryTextRetentionDays",
|
|
6251
|
+
"LakeConfigAuditRetentionDays",
|
|
5984
6252
|
"MaxContentLength",
|
|
5985
6253
|
"enableAutoChunk",
|
|
5986
6254
|
"SlackDefaultWebhookUrl",
|
|
@@ -5988,6 +6256,7 @@ z$1.enum([
|
|
|
5988
6256
|
"SlackLiveopsWebhookUrl",
|
|
5989
6257
|
"SlackUserActivityWebhookUrl",
|
|
5990
6258
|
"SlackFeedbackWebhookUrl",
|
|
6259
|
+
"SlackNonProdFeedbackWebhookUrl",
|
|
5991
6260
|
"SlackEmailAuditWebhookUrl",
|
|
5992
6261
|
"slackSigningSecret",
|
|
5993
6262
|
"slackBotToken",
|
|
@@ -6052,7 +6321,7 @@ z$1.enum([
|
|
|
6052
6321
|
"modelDiscoveryAutoRemap",
|
|
6053
6322
|
"prReportRepo",
|
|
6054
6323
|
"prReportIdentityMap",
|
|
6055
|
-
"
|
|
6324
|
+
"prReportWebhookUrl",
|
|
6056
6325
|
"prReportEgressAllowlist"
|
|
6057
6326
|
]);
|
|
6058
6327
|
/**
|
|
@@ -6761,13 +7030,29 @@ const API_SERVICE_GROUPS = {
|
|
|
6761
7030
|
{
|
|
6762
7031
|
key: "dataLakeSearchMaxChunks",
|
|
6763
7032
|
order: 3
|
|
7033
|
+
},
|
|
7034
|
+
{
|
|
7035
|
+
key: "forcedRetrievalCharBudget",
|
|
7036
|
+
order: 4
|
|
7037
|
+
},
|
|
7038
|
+
{
|
|
7039
|
+
key: "kbSearchDefaultResults",
|
|
7040
|
+
order: 5
|
|
7041
|
+
},
|
|
7042
|
+
{
|
|
7043
|
+
key: "kbSearchResultTokenBudget",
|
|
7044
|
+
order: 6
|
|
7045
|
+
},
|
|
7046
|
+
{
|
|
7047
|
+
key: "kbSearchMinRelevancePct",
|
|
7048
|
+
order: 7
|
|
6764
7049
|
}
|
|
6765
7050
|
]
|
|
6766
7051
|
},
|
|
6767
7052
|
DATA_LAKE_COST: {
|
|
6768
7053
|
id: "dataLakeCostGovernance",
|
|
6769
7054
|
name: "Data Lake Cost Governance",
|
|
6770
|
-
description: "Spend levers for data-lake embedding work (ingestion, reprocessing, convergence). Budgets are USD; 0 means stop spending, not \"use the default\".",
|
|
7055
|
+
description: "Spend levers for data-lake embedding work (ingestion, reprocessing, convergence). Budgets are USD; 0 means stop spending, not \"use the default\". The two tier multipliers scale the per-run and per-lake budgets by whether a lake is individual- or organization-owned.",
|
|
6771
7056
|
icon: "Savings",
|
|
6772
7057
|
settings: [
|
|
6773
7058
|
{
|
|
@@ -6797,6 +7082,14 @@ const API_SERVICE_GROUPS = {
|
|
|
6797
7082
|
{
|
|
6798
7083
|
key: "dataLakeVectorizeChunkBatchSize",
|
|
6799
7084
|
order: 7
|
|
7085
|
+
},
|
|
7086
|
+
{
|
|
7087
|
+
key: "dataLakeEmbeddingTierMultiplierIndividual",
|
|
7088
|
+
order: 8
|
|
7089
|
+
},
|
|
7090
|
+
{
|
|
7091
|
+
key: "dataLakeEmbeddingTierMultiplierOrganization",
|
|
7092
|
+
order: 9
|
|
6800
7093
|
}
|
|
6801
7094
|
]
|
|
6802
7095
|
},
|
|
@@ -7045,6 +7338,14 @@ const API_SERVICE_GROUPS = {
|
|
|
7045
7338
|
key: "SlackEmailAuditWebhookUrl",
|
|
7046
7339
|
order: 6.5
|
|
7047
7340
|
},
|
|
7341
|
+
{
|
|
7342
|
+
key: "SlackFeedbackWebhookUrl",
|
|
7343
|
+
order: 6.75
|
|
7344
|
+
},
|
|
7345
|
+
{
|
|
7346
|
+
key: "SlackNonProdFeedbackWebhookUrl",
|
|
7347
|
+
order: 6.8
|
|
7348
|
+
},
|
|
7048
7349
|
{
|
|
7049
7350
|
key: "FeedbackSendEmailUsername",
|
|
7050
7351
|
order: 7
|
|
@@ -7057,6 +7358,10 @@ const API_SERVICE_GROUPS = {
|
|
|
7057
7358
|
key: "FeedbackReceiveEmail",
|
|
7058
7359
|
order: 9
|
|
7059
7360
|
},
|
|
7361
|
+
{
|
|
7362
|
+
key: "FeedbackReceiveEmailNonProd",
|
|
7363
|
+
order: 9.5
|
|
7364
|
+
},
|
|
7060
7365
|
{
|
|
7061
7366
|
key: "liveFeedbackEmail",
|
|
7062
7367
|
order: 10
|
|
@@ -7572,16 +7877,23 @@ const API_SERVICE_GROUPS = {
|
|
|
7572
7877
|
},
|
|
7573
7878
|
DATA_LAKE_AUDIT: {
|
|
7574
7879
|
id: "dataLakeAuditService",
|
|
7575
|
-
name: "Data Lake
|
|
7576
|
-
description: "Retention for the lake
|
|
7880
|
+
name: "Data Lake Audit",
|
|
7881
|
+
description: "Retention for the lake audit trail: who READ a lake (plus the opt-in query-text log) and who CHANGED its configuration",
|
|
7577
7882
|
icon: "Security",
|
|
7578
|
-
settings: [
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7883
|
+
settings: [
|
|
7884
|
+
{
|
|
7885
|
+
key: "LakeAccessAuditRetentionDays",
|
|
7886
|
+
order: 1
|
|
7887
|
+
},
|
|
7888
|
+
{
|
|
7889
|
+
key: "LakeAccessQueryTextRetentionDays",
|
|
7890
|
+
order: 2
|
|
7891
|
+
},
|
|
7892
|
+
{
|
|
7893
|
+
key: "LakeConfigAuditRetentionDays",
|
|
7894
|
+
order: 3
|
|
7895
|
+
}
|
|
7896
|
+
]
|
|
7585
7897
|
}
|
|
7586
7898
|
};
|
|
7587
7899
|
const settingsMap = {
|
|
@@ -7686,8 +7998,8 @@ const settingsMap = {
|
|
|
7686
7998
|
EnableDataLakeSlackAdd: makeBooleanSetting({
|
|
7687
7999
|
key: "EnableDataLakeSlackAdd",
|
|
7688
8000
|
name: "Data Lakes: Slack \"@datalake add\" path",
|
|
7689
|
-
defaultValue:
|
|
7690
|
-
description: "Server-side gate for adding content to a Data Lake from Slack via \"@datalake add\".
|
|
8001
|
+
defaultValue: true,
|
|
8002
|
+
description: "Server-side gate for adding content to a Data Lake from Slack via \"@datalake add\". On by default. Turn OFF to make the Slack command inert - it is still intercepted deterministically, so the bot stays silent rather than falling through to the LLM.",
|
|
7691
8003
|
category: "Experimental",
|
|
7692
8004
|
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
7693
8005
|
order: 90,
|
|
@@ -7738,6 +8050,57 @@ const settingsMap = {
|
|
|
7738
8050
|
"lake"
|
|
7739
8051
|
] }
|
|
7740
8052
|
}),
|
|
8053
|
+
LakeConvergenceBulkChangeSharePct: makeNumberSetting({
|
|
8054
|
+
key: "LakeConvergenceBulkChangeSharePct",
|
|
8055
|
+
name: "Data Lakes: Convergence bulk-change confirmation threshold (%)",
|
|
8056
|
+
defaultValue: 25,
|
|
8057
|
+
min: 1,
|
|
8058
|
+
max: 100,
|
|
8059
|
+
description: "Share of a data lake, as a percentage of its gradable members, above which owner-triggered convergence (#1681) requires an explicit confirmation before it rewrites anything. A mass rewrite is the signature of a misconfigured chunk policy, and every individual change inside one looks locally reasonable, so the share is the only place the mistake is visible. The guard is suppressed on lakes with fewer gradable members than the plan needs for a percentage to mean anything. Lower it to make convergence ask more often; it never blocks a confirmed run.",
|
|
8060
|
+
category: "AI",
|
|
8061
|
+
order: 4,
|
|
8062
|
+
dependsOn: "EnableDataLakes",
|
|
8063
|
+
scope: { settableAt: [
|
|
8064
|
+
"organization",
|
|
8065
|
+
"owner",
|
|
8066
|
+
"lake"
|
|
8067
|
+
] }
|
|
8068
|
+
}),
|
|
8069
|
+
EnforceLakeReadGrants: makeBooleanSetting({
|
|
8070
|
+
key: "EnforceLakeReadGrants",
|
|
8071
|
+
name: "Data Lakes: Enforce read-time grant resolution",
|
|
8072
|
+
defaultValue: false,
|
|
8073
|
+
description: "Read-time grant cutover (#1673). OFF by default = report-only: the read gate resolves a persisted READER/org grant into an ephemeral membership view and logs where it WOULD change access ([lakeReadGrantCutover] lines), but the enforced decision stays the legacy owner/org/tag/entitlement/public rule so no one gains or loses access. NOTE: turning this ON is currently a NO-OP guarded by a source-level interlock (READ_GRANT_ENFORCEMENT_READY) - enforcement will not activate until the follow-up code (member-management write path + retrieval arm) lands and flips it, and a premature toggle just logs a warning and stays report-only. This is deliberate so the setting cannot half-enable a half-wired gate. Platform altitude on purpose: a one-time install-wide migration cutover, not a per-lake lever. Tag and entitlement grants always resolve live and are never affected by this flag; only persisted reader/org rows are gated by it.",
|
|
8074
|
+
category: "Experimental",
|
|
8075
|
+
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
8076
|
+
order: 94,
|
|
8077
|
+
dependsOn: "EnableDataLakes"
|
|
8078
|
+
}),
|
|
8079
|
+
EnableDataLakeDrivePoll: makeBooleanSetting({
|
|
8080
|
+
key: "EnableDataLakeDrivePoll",
|
|
8081
|
+
name: "Data Lakes: Google Drive auto re-sync poll",
|
|
8082
|
+
defaultValue: false,
|
|
8083
|
+
description: "Server-side gate for the scheduled poll that keeps connected Google Drive folders in sync with their data lakes (adds/edits/removals). Off by default - a connected folder still syncs on demand via the Re-sync button; turn this on to also reconcile it automatically on a schedule.",
|
|
8084
|
+
category: "Experimental",
|
|
8085
|
+
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
8086
|
+
order: 95,
|
|
8087
|
+
dependsOn: "EnableDataLakes"
|
|
8088
|
+
}),
|
|
8089
|
+
EnforceLakeAdmission: makeBooleanSetting({
|
|
8090
|
+
key: "EnforceLakeAdmission",
|
|
8091
|
+
name: "Data Lakes: Enforce the admission contract",
|
|
8092
|
+
defaultValue: false,
|
|
8093
|
+
description: "Retrievability contract at admission (#1680). OFF by default = report-only: a file whose chunks cannot honor the chunk policy a lake REQUIRES is logged as quarantined ([admission] lines) but still joins the lake, exactly as today. ON refuses the membership write instead, so unretrievable content never becomes a member and no embedding spend is incurred for it; the caller gets an error naming the required and actual passage targets. Enforcement applies to NEW memberships only - files already in a lake are never evicted, and no query is ever blocked on lake health, which is advisory permanently. Turn this on only after the lake health report shows how many members would be refused. The lake rung is the one that matters (a lake enforces its own contract); the org and owner rungs enforce across every lake in that scope at once. A flip is not instantaneous: the settings cache is per-instance, so it applies immediately on the instance that served the change and within ~5 min (one cache TTL) everywhere else - an upload that still succeeds right after turning this on is stale cache, not a broken lever.",
|
|
8094
|
+
category: "Experimental",
|
|
8095
|
+
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
8096
|
+
order: 96,
|
|
8097
|
+
dependsOn: "EnableDataLakes",
|
|
8098
|
+
scope: { settableAt: [
|
|
8099
|
+
"organization",
|
|
8100
|
+
"owner",
|
|
8101
|
+
"lake"
|
|
8102
|
+
] }
|
|
8103
|
+
}),
|
|
7741
8104
|
EnableBriefcase: makeBooleanSetting({
|
|
7742
8105
|
key: "EnableBriefcase",
|
|
7743
8106
|
name: "Enable Briefcase",
|
|
@@ -7960,12 +8323,13 @@ const settingsMap = {
|
|
|
7960
8323
|
name: "Default Chunk Size",
|
|
7961
8324
|
defaultValue: 512,
|
|
7962
8325
|
min: 64,
|
|
7963
|
-
|
|
8326
|
+
max: OVERSIZED_PASSAGE_TOKEN_THRESHOLD,
|
|
8327
|
+
description: "Passage target in TOKENS for splitting large documents. The DEFAULT matches the chunker; a value stored here overrides it, and a stored value larger than the chunker default makes the UI reprocess path produce coarser chunks than /api/files/reprocess. Coarser chunks measurably worsen retrieval, and values above the under-chunked detection threshold also stop \"Rebuild passages\" converging, so the accepted range is capped there. Resolves at file-OWNER altitude: an org/individual owner may pin their own default above the platform value; a data lake does NOT override it (epic decision 7) - a lake declares the policy it REQUIRES and a file that cannot satisfy every lake it belongs to is reported as a conflict rather than silently re-chunked.",
|
|
7964
8328
|
category: "AI",
|
|
7965
8329
|
order: 3,
|
|
7966
8330
|
scope: {
|
|
7967
8331
|
settableAt: ["organization", "owner"],
|
|
7968
|
-
clamp: (value) => Math.min(Math.max(Math.floor(value), 64),
|
|
8332
|
+
clamp: (value) => Math.min(Math.max(Math.floor(value), 64), OVERSIZED_PASSAGE_TOKEN_THRESHOLD)
|
|
7969
8333
|
}
|
|
7970
8334
|
}),
|
|
7971
8335
|
ModerationEnabled: makeBooleanSetting({
|
|
@@ -8136,6 +8500,15 @@ const settingsMap = {
|
|
|
8136
8500
|
group: API_SERVICE_GROUPS.FEEDBACK.id,
|
|
8137
8501
|
order: 9
|
|
8138
8502
|
}),
|
|
8503
|
+
FeedbackReceiveEmailNonProd: makeStringSetting({
|
|
8504
|
+
key: "FeedbackReceiveEmailNonProd",
|
|
8505
|
+
name: "Non-Production Feedback Email",
|
|
8506
|
+
defaultValue: "",
|
|
8507
|
+
description: "Comma-separated recipient list for feedback submitted from every non-production stage (dev, staging, previews). Does not apply to a self-host install, which routes through FeedbackReceiveEmail like production. Leave empty to suppress non-production email entirely - it never falls back to the production recipient list.",
|
|
8508
|
+
category: "Feedback",
|
|
8509
|
+
group: API_SERVICE_GROUPS.FEEDBACK.id,
|
|
8510
|
+
order: 9.5
|
|
8511
|
+
}),
|
|
8139
8512
|
FeedbackKyle: makeStringSetting({
|
|
8140
8513
|
key: "FeedbackKyle",
|
|
8141
8514
|
name: "Kyle Feedback Email",
|
|
@@ -8210,7 +8583,17 @@ const settingsMap = {
|
|
|
8210
8583
|
description: "The webhook URL for sending feedback to the #bike4mind-feedback Slack channel.",
|
|
8211
8584
|
category: "Feedback",
|
|
8212
8585
|
group: API_SERVICE_GROUPS.FEEDBACK.id,
|
|
8213
|
-
order:
|
|
8586
|
+
order: 6.75,
|
|
8587
|
+
isSensitive: true
|
|
8588
|
+
}),
|
|
8589
|
+
SlackNonProdFeedbackWebhookUrl: makeStringSetting({
|
|
8590
|
+
key: "SlackNonProdFeedbackWebhookUrl",
|
|
8591
|
+
name: "Non-Production Feedback Channel Webhook URL",
|
|
8592
|
+
defaultValue: "",
|
|
8593
|
+
description: "Incoming-webhook URL that receives feedback submitted from every non-production stage (dev, staging, previews). Does not apply to a self-host install, which routes through SlackFeedbackWebhookUrl like production. Leave empty to suppress non-production feedback entirely - it never falls back to the production feedback channel.",
|
|
8594
|
+
category: "Feedback",
|
|
8595
|
+
group: API_SERVICE_GROUPS.FEEDBACK.id,
|
|
8596
|
+
order: 6.8,
|
|
8214
8597
|
isSensitive: true
|
|
8215
8598
|
}),
|
|
8216
8599
|
SlackEmailAuditWebhookUrl: makeStringSetting({
|
|
@@ -8817,9 +9200,9 @@ const settingsMap = {
|
|
|
8817
9200
|
}),
|
|
8818
9201
|
bflApiKey: makeStringSetting({
|
|
8819
9202
|
key: "bflApiKey",
|
|
8820
|
-
name: "
|
|
9203
|
+
name: "Black Forest Labs API Key",
|
|
8821
9204
|
defaultValue: "",
|
|
8822
|
-
description: "The API Key for
|
|
9205
|
+
description: "The API Key for Black Forest Labs image generation service.",
|
|
8823
9206
|
isSensitive: true,
|
|
8824
9207
|
category: "AI",
|
|
8825
9208
|
group: API_SERVICE_GROUPS.IMAGE_GENERATION.id,
|
|
@@ -8869,13 +9252,60 @@ const settingsMap = {
|
|
|
8869
9252
|
"lake"
|
|
8870
9253
|
] }
|
|
8871
9254
|
}),
|
|
9255
|
+
forcedRetrievalCharBudget: makeNumberSetting({
|
|
9256
|
+
key: "forcedRetrievalCharBudget",
|
|
9257
|
+
name: "Forced Retrieval Char Budget",
|
|
9258
|
+
defaultValue: FORCED_RETRIEVAL_CHAR_BUDGET_DEFAULT,
|
|
9259
|
+
min: 1e3,
|
|
9260
|
+
max: 1e5,
|
|
9261
|
+
description: "Total characters of retrieved chunk text injected into a Data-Lake-mode turn. Measured saturating on every turn against a 47-document lake, so this is the binding constraint on how much of a corpus reaches the model - not the relevance floor. Raising it admits more passages at the cost of prompt tokens and latency on every Data-Lake turn; it is NOT automatically better, since more context can dilute ranking. Platform-only for now: this read does not go through the scoped-settings resolver, so a `settableAt` block here would be inert metadata at best and could arm the resolver's fail-loud owner check at worst.",
|
|
9262
|
+
category: "AI",
|
|
9263
|
+
group: API_SERVICE_GROUPS.EMBEDDING.id,
|
|
9264
|
+
order: 4
|
|
9265
|
+
}),
|
|
9266
|
+
kbSearchDefaultResults: makeNumberSetting({
|
|
9267
|
+
key: "kbSearchDefaultResults",
|
|
9268
|
+
name: "Knowledge Base Search Default Results",
|
|
9269
|
+
defaultValue: 5,
|
|
9270
|
+
min: 1,
|
|
9271
|
+
max: 10,
|
|
9272
|
+
description: "Passages the search_knowledge_base tool returns when a model call omits max_results, which is most calls. This is the exact bound while kbSearchResultTokenBudget is unset (0). Once a token budget is set, it takes over as the primary bound for search results (this setting's own value is then unused there, though it still governs the keyword-search fallback, and the count served if token pricing itself fails). Does NOT raise the tool's hard ceiling of 10 passages per call - a model that reads max_results up to 10 from its own tool schema won't ask for more than that regardless of this setting.",
|
|
9273
|
+
category: "AI",
|
|
9274
|
+
group: API_SERVICE_GROUPS.EMBEDDING.id,
|
|
9275
|
+
order: 5,
|
|
9276
|
+
scope: { settableAt: ["organization", "owner"] }
|
|
9277
|
+
}),
|
|
9278
|
+
kbSearchResultTokenBudget: makeNumberSetting({
|
|
9279
|
+
key: "kbSearchResultTokenBudget",
|
|
9280
|
+
name: "Knowledge Base Search Result Token Budget",
|
|
9281
|
+
defaultValue: 0,
|
|
9282
|
+
min: 0,
|
|
9283
|
+
max: 2e4,
|
|
9284
|
+
description: "Approximate tokens of served passage TEXT (post-trim, post-clip - what the model actually receives, not the raw stored chunk) the search_knowledge_base tool may return in one call. Counted with a fixed tokenizer as a proxy, not billed against any specific model. Replaces a passage count as the primary bound once set, since it is invariant to chunk size - a lake chunked smaller no longer silently returns less material for the same setting. 0 (default) disables it: search_knowledge_base then serves exactly kbSearchDefaultResults passages, unchanged from before this setting existed. The FIRST matching passage is always returned even if it alone exceeds the budget - a search that found something never returns nothing.",
|
|
9285
|
+
category: "AI",
|
|
9286
|
+
group: API_SERVICE_GROUPS.EMBEDDING.id,
|
|
9287
|
+
order: 6,
|
|
9288
|
+
scope: { settableAt: ["organization", "owner"] }
|
|
9289
|
+
}),
|
|
9290
|
+
kbSearchMinRelevancePct: makeNumberSetting({
|
|
9291
|
+
key: "kbSearchMinRelevancePct",
|
|
9292
|
+
name: "Knowledge Base Search Minimum Relevance (%)",
|
|
9293
|
+
defaultValue: 0,
|
|
9294
|
+
min: 0,
|
|
9295
|
+
max: 100,
|
|
9296
|
+
description: "Minimum cosine relevance, as a percent, a passage must clear to be returned by search_knowledge_base. 0 (default) matches current behavior (no relevance floor beyond a non-negative cosine score). Raising it lets breadth adapt per query - a narrow question can return fewer, more relevant passages instead of always padding out to the configured count. Cosine similarity is not comparable across embedding models: a floor tuned for one model can filter out an entire alternate model, when a lake mixes embedding models, more aggressively than intended. Start low and raise gradually while watching the tool's own retrieval-skipped notices.",
|
|
9297
|
+
category: "AI",
|
|
9298
|
+
group: API_SERVICE_GROUPS.EMBEDDING.id,
|
|
9299
|
+
order: 7,
|
|
9300
|
+
scope: { settableAt: ["organization", "owner"] }
|
|
9301
|
+
}),
|
|
8872
9302
|
LakeAccessAuditRetentionDays: makeNumberSetting({
|
|
8873
9303
|
key: "LakeAccessAuditRetentionDays",
|
|
8874
9304
|
name: "Lake Access Audit Retention (days)",
|
|
8875
9305
|
defaultValue: 450,
|
|
8876
9306
|
min: 450,
|
|
8877
9307
|
max: LAKE_ACCESS_AUDIT_RETENTION_MAX_DAYS,
|
|
8878
|
-
description: "How long a lake access audit event (who read a lake, and when) is retained, in days. Has a floor of 450 days (12 months live plus a Type II observation tail) - this is a platform-wide value, not per-organization, until a scoped settings resolver exists.",
|
|
9308
|
+
description: "How long a lake access audit event (who read a lake, and when) is retained, in days. Has a floor of 450 days (12 months live plus a Type II observation tail) - this is a platform-wide value, not per-organization, until a scoped settings resolver exists. Applies only to events written after a change: expiresAt is computed once at write time and is immutable, so raising or lowering this value never affects rows already recorded.",
|
|
8879
9309
|
category: "SecOps",
|
|
8880
9310
|
group: API_SERVICE_GROUPS.DATA_LAKE_AUDIT.id,
|
|
8881
9311
|
order: 1
|
|
@@ -8886,11 +9316,22 @@ const settingsMap = {
|
|
|
8886
9316
|
defaultValue: 30,
|
|
8887
9317
|
min: 1,
|
|
8888
9318
|
max: 90,
|
|
8889
|
-
description: "How long the opt-in query-text log (the natural-language question behind a lake retrieval) is retained, in days. Always resolved shorter than the audit event retention itself, regardless of this value, since the query text is more sensitive than the event metadata.",
|
|
9319
|
+
description: "How long the opt-in query-text log (the natural-language question behind a lake retrieval) is retained, in days. Always resolved shorter than the audit event retention itself, regardless of this value, since the query text is more sensitive than the event metadata. Applies only to events written after a change - already-recorded rows keep the expiry computed at write time and are not retroactively shortened or extended.",
|
|
8890
9320
|
category: "SecOps",
|
|
8891
9321
|
group: API_SERVICE_GROUPS.DATA_LAKE_AUDIT.id,
|
|
8892
9322
|
order: 2
|
|
8893
9323
|
}),
|
|
9324
|
+
LakeConfigAuditRetentionDays: makeNumberSetting({
|
|
9325
|
+
key: "LakeConfigAuditRetentionDays",
|
|
9326
|
+
name: "Lake Config Change Audit Retention (days)",
|
|
9327
|
+
defaultValue: LAKE_CONFIG_AUDIT_RETENTION_DEFAULT_DAYS,
|
|
9328
|
+
min: LAKE_CONFIG_AUDIT_RETENTION_FLOOR_DAYS,
|
|
9329
|
+
max: LAKE_CONFIG_AUDIT_RETENTION_MAX_DAYS,
|
|
9330
|
+
description: "How long a lake CONFIG-change event (who changed a lake, what they changed, and which manage rung authorized it) is retained, in days. Floored at 1095 days - deliberately longer than the access-audit retention above, because a config change is rare and alters every future answer the lake gives, where a read is one turn. Platform-wide, not per-organization, until a scoped settings resolver exists.",
|
|
9331
|
+
category: "SecOps",
|
|
9332
|
+
group: API_SERVICE_GROUPS.DATA_LAKE_AUDIT.id,
|
|
9333
|
+
order: 3
|
|
9334
|
+
}),
|
|
8894
9335
|
dataLakeEmbeddingSpendEnabled: makeBooleanSetting({
|
|
8895
9336
|
key: "dataLakeEmbeddingSpendEnabled",
|
|
8896
9337
|
name: "Data Lake Embedding Spend Enabled",
|
|
@@ -8966,6 +9407,28 @@ const settingsMap = {
|
|
|
8966
9407
|
group: API_SERVICE_GROUPS.DATA_LAKE_COST.id,
|
|
8967
9408
|
order: 7
|
|
8968
9409
|
}),
|
|
9410
|
+
dataLakeEmbeddingTierMultiplierIndividual: makeNumberSetting({
|
|
9411
|
+
key: "dataLakeEmbeddingTierMultiplierIndividual",
|
|
9412
|
+
name: "Cost Tier Multiplier - Individual-Owned Lakes",
|
|
9413
|
+
defaultValue: 1,
|
|
9414
|
+
min: 0,
|
|
9415
|
+
max: 100,
|
|
9416
|
+
description: "Scales the per-run and per-lake embedding budgets for lakes owned by an individual user. 1 means those lakes get exactly the configured budgets; 0 stops them spending at all. The effective budget is still capped by the same hard rail as the untiered value.",
|
|
9417
|
+
category: "AI",
|
|
9418
|
+
group: API_SERVICE_GROUPS.DATA_LAKE_COST.id,
|
|
9419
|
+
order: 8
|
|
9420
|
+
}),
|
|
9421
|
+
dataLakeEmbeddingTierMultiplierOrganization: makeNumberSetting({
|
|
9422
|
+
key: "dataLakeEmbeddingTierMultiplierOrganization",
|
|
9423
|
+
name: "Cost Tier Multiplier - Organization-Owned Lakes",
|
|
9424
|
+
defaultValue: 5,
|
|
9425
|
+
min: 0,
|
|
9426
|
+
max: 100,
|
|
9427
|
+
description: "Scales the per-run and per-lake embedding budgets for lakes owned by an organization, which serve a whole team rather than one person. 0 stops org-owned lakes spending at all. The effective budget is still capped by the same hard rail as the untiered value.",
|
|
9428
|
+
category: "AI",
|
|
9429
|
+
group: API_SERVICE_GROUPS.DATA_LAKE_COST.id,
|
|
9430
|
+
order: 9
|
|
9431
|
+
}),
|
|
8969
9432
|
slackSigningSecret: makeStringSetting({
|
|
8970
9433
|
key: "slackSigningSecret",
|
|
8971
9434
|
name: "Slack Signing Secret",
|
|
@@ -9691,19 +10154,20 @@ const settingsMap = {
|
|
|
9691
10154
|
category: "Admin",
|
|
9692
10155
|
order: 142
|
|
9693
10156
|
}),
|
|
9694
|
-
|
|
9695
|
-
key: "
|
|
9696
|
-
name: "PR Report Slack
|
|
10157
|
+
prReportWebhookUrl: makeStringSetting({
|
|
10158
|
+
key: "prReportWebhookUrl",
|
|
10159
|
+
name: "PR Report Slack Webhook URL",
|
|
9697
10160
|
defaultValue: "",
|
|
9698
|
-
|
|
10161
|
+
isSensitive: true,
|
|
10162
|
+
description: "Slack Incoming Webhook URL the PR status digest posts to (https://hooks.slack.com/services/...). It already encodes its channel and workspace, so no bot token or channel ID is needed to send. Bearer-equivalent: anyone holding it can post to the channel, so it is stored encrypted and never returned to the browser.",
|
|
9699
10163
|
category: "Slack",
|
|
9700
10164
|
order: 143
|
|
9701
10165
|
}),
|
|
9702
10166
|
prReportEgressAllowlist: makeObjectSetting({
|
|
9703
10167
|
key: "prReportEgressAllowlist",
|
|
9704
10168
|
name: "PR Report Egress Allowlist",
|
|
9705
|
-
defaultValue: { hosts: ["
|
|
9706
|
-
description: "Hosts the PR digest may post to. FAILS CLOSED: an empty list rejects every send rather than degrading to allow-any, because the post body carries PR titles, author logins and the staffing implied by the role rosters.
|
|
10169
|
+
defaultValue: { hosts: ["hooks.slack.com"] },
|
|
10170
|
+
description: "Hosts the PR digest may post to, checked against the webhook URL its own hostname. FAILS CLOSED: an empty list rejects every send rather than degrading to allow-any, because the post body carries PR titles, author logins and the staffing implied by the role rosters. Slack incoming webhooks live at hooks.slack.com, so that is the default.",
|
|
9707
10171
|
category: "Slack",
|
|
9708
10172
|
order: 144,
|
|
9709
10173
|
schema: z$1.object({ hosts: z$1.array(z$1.string()).default([]) })
|
|
@@ -10095,6 +10559,7 @@ const PromptMetaTokenUsageSchema = z$1.object({
|
|
|
10095
10559
|
actualOutputTokens: z$1.number().optional(),
|
|
10096
10560
|
actualTotalTokens: z$1.number().optional(),
|
|
10097
10561
|
cacheReadInputTokens: z$1.number().optional(),
|
|
10562
|
+
cacheCreationInputTokens: z$1.number().optional(),
|
|
10098
10563
|
settledBasis: z$1.enum(["provider", "local"]).optional(),
|
|
10099
10564
|
estimatedCost: z$1.number().optional(),
|
|
10100
10565
|
creditsUsed: z$1.number().optional()
|
|
@@ -10294,10 +10759,67 @@ const CitableSourceSchema = z$1.object({
|
|
|
10294
10759
|
fullContext: z$1.string().optional()
|
|
10295
10760
|
}).optional()
|
|
10296
10761
|
});
|
|
10762
|
+
/**
|
|
10763
|
+
* Per-turn retrieval outcome (#1867): whether retrieval was attempted this turn and what happened,
|
|
10764
|
+
* independent of whether the model then cited anything. Exists specifically to make the zero case
|
|
10765
|
+
* distinguishable from "never asked" - `context.lakeMemory` and `citables` both go silent on a
|
|
10766
|
+
* zero-result retrieval, so a turn that legitimately found nothing is indistinguishable from one
|
|
10767
|
+
* where retrieval never ran at all.
|
|
10768
|
+
*
|
|
10769
|
+
* Deliberately holds NO counts and NO chunk/document identifiers. Counts already exist and are
|
|
10770
|
+
* more precise: `citables.filter(c => c.type === 'document')` is deduped by id/url/title in
|
|
10771
|
+
* `applyQuestStatusChanges`, while this shape cannot dedupe (no identifiers to dedupe by) and
|
|
10772
|
+
* would have to sum - producing a second, disagreeing number for the same question. Similarity
|
|
10773
|
+
* scores live on `LakeAccessEvent`, not here.
|
|
10774
|
+
*
|
|
10775
|
+
* CAUTION, not a guarantee: the absence of chunk/document identifiers is what keeps this shape
|
|
10776
|
+
* OUT of `promptMetaRedaction.ts`'s scope (that helper is a functionCalls-only denylist and would
|
|
10777
|
+
* not catch a nested nonidentifier field like `dataLakeTags` regardless). It does NOT mean this
|
|
10778
|
+
* field never needs redaction consideration - `dataLakeTags` (which lakes were involved) already
|
|
10779
|
+
* reaches non-owner viewers the same way `lakeMemory.dataLakeTags` does (session shares, feedback
|
|
10780
|
+
* egress, admin logs, session clone - see redactedFeedback.ts, admin/model-logs.ts, clone.ts, none
|
|
10781
|
+
* of which touch this field). That exposure is not new in the general case, but it IS new
|
|
10782
|
+
* specifically on a zero-recall turn: `lakeMemory` was never written there before this field
|
|
10783
|
+
* existed, so a turn that previously carried no lake-identity signal at all now carries one.
|
|
10784
|
+
*
|
|
10785
|
+
* `attempted`/`outcome` on their own would still be ambiguous about WHICH lakes were searched on a
|
|
10786
|
+
* zero-recall turn (dataLakeTags otherwise lives only inside `lakeMemory`, written after the
|
|
10787
|
+
* zero-belief return), so this stamps the resolved tags at write time rather than making a reader
|
|
10788
|
+
* fall back to the session's current (possibly since-changed) `retrievalTags`.
|
|
10789
|
+
*
|
|
10790
|
+
* Absent-or-fully-present, matching `lakeMemory` above - see the Mongoose-side subSchema comment
|
|
10791
|
+
* in QuestModel.ts for why partial-write and default-array shapes are unsafe here.
|
|
10792
|
+
*/
|
|
10793
|
+
const RetrievalSummarySchema = z$1.object({
|
|
10794
|
+
/** True once a retrieval-capable surface actually ran (not merely offered) this turn. */
|
|
10795
|
+
attempted: z$1.boolean(),
|
|
10796
|
+
/**
|
|
10797
|
+
* 'ok' - ran, whether or not anything came back (the zero case is a legitimate 'ok').
|
|
10798
|
+
* 'no_lakes' - ran but the user had no entitled/selected lake in scope.
|
|
10799
|
+
* 'failed' - threw; recall did not complete.
|
|
10800
|
+
* On multiple retrieval calls within one turn, merge priority is failed > ok > no_lakes (see
|
|
10801
|
+
* retrievalSummaryMerge.ts's mergeRetrievalSummary): a single failure is never masked by a later
|
|
10802
|
+
* success or abstain, and a real success on one surface is never masked by another surface's
|
|
10803
|
+
* "no lakes in scope" abstain in the same turn.
|
|
10804
|
+
*/
|
|
10805
|
+
outcome: z$1.enum([
|
|
10806
|
+
"ok",
|
|
10807
|
+
"no_lakes",
|
|
10808
|
+
"failed"
|
|
10809
|
+
]),
|
|
10810
|
+
/** Which retrieval-capable surface(s) ran this turn, e.g. 'lake-memory', 'knowledgeBaseSearch'. */
|
|
10811
|
+
surfaces: z$1.array(z$1.string()),
|
|
10812
|
+
/** Lakes resolved at the moment retrieval ran, stamped point-in-time (not read live from the session). */
|
|
10813
|
+
dataLakeTags: z$1.array(z$1.string())
|
|
10814
|
+
});
|
|
10297
10815
|
z$1.object({
|
|
10298
10816
|
model: PromptMetaModelSchema.optional(),
|
|
10299
10817
|
tokenUsage: PromptMetaTokenUsageSchema.optional(),
|
|
10300
10818
|
context: PromptMetaContextSchema.optional(),
|
|
10819
|
+
/** Per-turn retrieval outcome - see RetrievalSummarySchema. Top-level (not under `context`)
|
|
10820
|
+
* deliberately: applyQuestStatusChanges does a one-level spread merge, so a field nested under
|
|
10821
|
+
* `context` would be replaced wholesale by any tool-arm write instead of merging. */
|
|
10822
|
+
retrieval: RetrievalSummarySchema.optional(),
|
|
10301
10823
|
functionCalls: z$1.array(PromptMetaFunctionCallSchema).optional(),
|
|
10302
10824
|
/**
|
|
10303
10825
|
* Names of the tools actually offered to the model this turn - the output of `buildTools`
|
|
@@ -10945,7 +11467,16 @@ const INVISIBLE_INK = /\u115F|\u1160|\u17B4|\u17B5|\u2800|\u3164|\uFFA0/g;
|
|
|
10945
11467
|
const hasBlankTagPrefixSegment = (prefix) => {
|
|
10946
11468
|
return (prefix.endsWith(":") ? prefix.slice(0, -1) : prefix).split(":").some((part) => !/[\p{L}\p{N}\p{P}\p{S}\p{M}]/u.test(part.replace(INVISIBLE_INK, "")));
|
|
10947
11469
|
};
|
|
10948
|
-
|
|
11470
|
+
const DATA_LAKE_SLUG_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
|
|
11471
|
+
const DATA_LAKES = [{
|
|
11472
|
+
id: "opti-knowledge",
|
|
11473
|
+
slug: "opti-knowledge",
|
|
11474
|
+
name: "Optimization Knowledge Base",
|
|
11475
|
+
requiredUserTag: "Opti",
|
|
11476
|
+
requiredEntitlement: "optihashi:pro",
|
|
11477
|
+
fileTagPrefix: "opti:",
|
|
11478
|
+
datalakeTag: "datalake:opti-knowledge"
|
|
11479
|
+
}, ...(() => {
|
|
10949
11480
|
const raw = process.env.NEXT_PUBLIC_PREMIUM_DATA_LAKES;
|
|
10950
11481
|
if (!raw) return [];
|
|
10951
11482
|
try {
|
|
@@ -10955,6 +11486,7 @@ const hasBlankTagPrefixSegment = (prefix) => {
|
|
|
10955
11486
|
return [];
|
|
10956
11487
|
}
|
|
10957
11488
|
})()];
|
|
11489
|
+
new Set(DATA_LAKES.map((l) => l.id));
|
|
10958
11490
|
/**
|
|
10959
11491
|
* Canonical normalization for entitlement keys + `requiredEntitlement` values - the ONE
|
|
10960
11492
|
* rule, applied at write time (create/update/stamp) and at match time. Mirrors the
|
|
@@ -10962,11 +11494,10 @@ const hasBlankTagPrefixSegment = (prefix) => {
|
|
|
10962
11494
|
* casing matches the lowercase keys the resolver produces.
|
|
10963
11495
|
*/
|
|
10964
11496
|
const normalizeEntitlementKey = (key) => key.trim().toLowerCase();
|
|
10965
|
-
const slugRegex = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
|
|
10966
11497
|
const sha256Regex = /^[a-f0-9]{64}$/;
|
|
10967
11498
|
z.object({
|
|
10968
11499
|
name: z.string().min(1).max(200),
|
|
10969
|
-
slug: z.string().min(2).max(60).regex(
|
|
11500
|
+
slug: z.string().min(2).max(60).regex(DATA_LAKE_SLUG_REGEX, "Slug must be lowercase alphanumeric with hyphens (e.g. \"my-data-lake\")"),
|
|
10970
11501
|
description: z.string().max(2e3).optional(),
|
|
10971
11502
|
fileTagPrefix: z.string().trim().min(2).max(30).refine((s) => s.endsWith(":"), "Tag prefix must end with \":\" (e.g. \"acme:\")").refine((s) => !hasBlankTagPrefixSegment(s), "Tag prefix segments must be non-empty (e.g. \"acme:\" or \"acme:legal:\")").refine((s) => !isReservedTagPrefix(s), `Tag prefix cannot use the reserved "${DATALAKE_TAG_PREFIX}" namespace`),
|
|
10972
11503
|
requiredUserTag: z.string().min(1).max(100).optional(),
|
|
@@ -10982,7 +11513,12 @@ z.object({
|
|
|
10982
11513
|
requiredUserTag: z.union([z.literal(""), z.string().min(1).max(100)]).optional(),
|
|
10983
11514
|
requiredEntitlement: z.union([z.literal(""), z.string().min(3).max(100).refine((s) => s.includes(":") && s.split(":").every((part) => part.length > 0), "Entitlement key must be namespaced with non-empty parts (e.g. \"product:pro\")")]).optional(),
|
|
10984
11515
|
auditQueryTextEnabled: z.boolean().optional(),
|
|
10985
|
-
requiredPassageTokenTarget: z.number().int().min(64).max(
|
|
11516
|
+
requiredPassageTokenTarget: z.number().int().min(64).max(OVERSIZED_PASSAGE_TOKEN_THRESHOLD).nullable().optional()
|
|
11517
|
+
});
|
|
11518
|
+
z.object({
|
|
11519
|
+
groundingMode: z.enum(DATA_LAKE_GROUNDING_MODES).optional(),
|
|
11520
|
+
preferredSystemPromptId: z.union([z.literal(""), z.string().min(1).max(200)]).optional(),
|
|
11521
|
+
systemPrompt: z.string().optional()
|
|
10986
11522
|
});
|
|
10987
11523
|
z.object({
|
|
10988
11524
|
organizationId: z.string().optional(),
|
|
@@ -11169,6 +11705,45 @@ z$1.object({
|
|
|
11169
11705
|
}).omit({ model: true }).partial();
|
|
11170
11706
|
z$1.union([ToolExecutionResponseSchema, ApiErrorSchema]);
|
|
11171
11707
|
/**
|
|
11708
|
+
* Response details shared by the endpoints that return generated audio as raw
|
|
11709
|
+
* bytes (music, sound effects). Not a contract - just the pieces both of their
|
|
11710
|
+
* contracts declare, kept in one place so the published media types and headers
|
|
11711
|
+
* cannot describe one endpoint and not the other.
|
|
11712
|
+
*/
|
|
11713
|
+
/**
|
|
11714
|
+
* Every Content-Type the ElevenLabs generators map an `output_format` token to
|
|
11715
|
+
* (`contentTypeForFormat` in ElevenLabsMusicGenerator / ElevenLabsSoundGenerator).
|
|
11716
|
+
* The first entry is the default (mp3); the rest are declared as alternates.
|
|
11717
|
+
* Must stay in sync with those two mappings.
|
|
11718
|
+
*/
|
|
11719
|
+
const GENERATED_AUDIO_CONTENT_TYPES = [
|
|
11720
|
+
"audio/mpeg",
|
|
11721
|
+
"audio/opus",
|
|
11722
|
+
"audio/L16",
|
|
11723
|
+
"audio/basic",
|
|
11724
|
+
"application/octet-stream"
|
|
11725
|
+
];
|
|
11726
|
+
/**
|
|
11727
|
+
* Where the browsable copy of the generated audio ended up. These are the ONLY
|
|
11728
|
+
* channel for that information on these endpoints: the body is raw audio, so a
|
|
11729
|
+
* caller that wants the saved file has nowhere else to read it from.
|
|
11730
|
+
*/
|
|
11731
|
+
const GENERATED_AUDIO_SAVE_HEADERS = {
|
|
11732
|
+
"X-B4M-Audio-Saved": "Whether a browsable copy was saved to the file browser (\"true\"/\"false\").",
|
|
11733
|
+
"X-B4M-Audio-Fab-File-Id": "Id of the saved file. Present only when the copy was saved.",
|
|
11734
|
+
"X-B4M-Audio-File-Name": "File name of the saved copy. Present only when the copy was saved.",
|
|
11735
|
+
"X-B4M-Audio-File-Url": "Signed URL for the saved copy, minted at creation. Use this rather than re-resolving the file via GET /api/files/{id}, which fails closed until the async moderation scan completes."
|
|
11736
|
+
};
|
|
11737
|
+
/** The 200 response body of a raw-audio endpoint: default media type plus alternates. */
|
|
11738
|
+
const generatedAudioBody = () => ({
|
|
11739
|
+
contentType: GENERATED_AUDIO_CONTENT_TYPES[0],
|
|
11740
|
+
alsoReturns: GENERATED_AUDIO_CONTENT_TYPES.slice(1).map((contentType) => ({ contentType })),
|
|
11741
|
+
headers: GENERATED_AUDIO_SAVE_HEADERS
|
|
11742
|
+
});
|
|
11743
|
+
({ ...generatedAudioBody() });
|
|
11744
|
+
({ ...generatedAudioBody() });
|
|
11745
|
+
z$1.enum(["user", "convergence"]).optional().catch(void 0), z$1.string().optional();
|
|
11746
|
+
/**
|
|
11172
11747
|
* Blessed, self-hosted artifact library script paths (root-relative).
|
|
11173
11748
|
*
|
|
11174
11749
|
* Single source of truth shared across the artifact pipeline:
|
|
@@ -11272,6 +11847,10 @@ OpenAIImageGenerationInput.extend({
|
|
|
11272
11847
|
aspect_ratio: z$1.string().optional(),
|
|
11273
11848
|
fabFileIds: z$1.array(z$1.string()).prefault([]),
|
|
11274
11849
|
tools: z$1.array(z$1.union([b4mLLMTools, z$1.string()])).optional(),
|
|
11850
|
+
safety_tolerance: BFLSafetyToleranceSchema,
|
|
11851
|
+
prompt_upsampling: z$1.boolean().optional(),
|
|
11852
|
+
seed: z$1.number().nullable().optional(),
|
|
11853
|
+
output_format: z$1.enum(["jpeg", "png"]).nullable().optional(),
|
|
11275
11854
|
/** Resolved by the API route's prompt resolver. Defaults to 'fresh' for first-turn or sessions with no prior image. */
|
|
11276
11855
|
intent: PromptIntentSchema.optional(),
|
|
11277
11856
|
promptEnhancement: z$1.object({
|
|
@@ -11465,6 +12044,12 @@ z$1.object({
|
|
|
11465
12044
|
}).optional()
|
|
11466
12045
|
});
|
|
11467
12046
|
const MCP_PROVIDER_METADATA = {
|
|
12047
|
+
notion: { defaultToolDescriptions: {
|
|
12048
|
+
notion_search: "Search for pages and databases in the connected Notion workspace by text query. Returns matching page titles, IDs, and URLs.",
|
|
12049
|
+
notion_create_page: "Create a new page in the connected Notion workspace. Requires write access to be enabled. The page is created under the configured root page or a specified parent.",
|
|
12050
|
+
notion_read_page: "Read the content of a Notion page by its ID. Returns the child blocks (text, headings, lists, etc.) and a plain-text summary. Results are paginated; pass start_cursor with the returned next_cursor when has_more is true.",
|
|
12051
|
+
notion_append_blocks: "Append content blocks (paragraphs, headings, lists, code, etc.) to an existing Notion page or block. Requires write access."
|
|
12052
|
+
} },
|
|
11468
12053
|
atlassian: { defaultToolDescriptions: {
|
|
11469
12054
|
confluence_get_page: "Retrieve a Confluence page by ID or search by title within a space. Include page metadata and optional content.",
|
|
11470
12055
|
confluence_create_page: "Create a new Confluence page. Automatically uses your personal space when spaceId is omitted - no need to call confluence_get_current_user first.",
|
|
@@ -11910,6 +12495,7 @@ z$1.object({
|
|
|
11910
12495
|
reason: ReportReasonSchema,
|
|
11911
12496
|
details: z$1.string().max(2e3).optional()
|
|
11912
12497
|
});
|
|
12498
|
+
const PublishTagsSchema = z$1.array(z$1.string().max(60)).max(20);
|
|
11913
12499
|
z$1.object({
|
|
11914
12500
|
/** Short opaque id for short URLs (`/p/r/{publicId}`, `/p/f/{publicId}`) and lookups. */
|
|
11915
12501
|
publicId: z$1.string(),
|
|
@@ -11918,6 +12504,11 @@ z$1.object({
|
|
|
11918
12504
|
slug: SlugSchema,
|
|
11919
12505
|
title: z$1.string().min(1).max(200),
|
|
11920
12506
|
description: z$1.string().max(1e3).optional(),
|
|
12507
|
+
/** Freeform owner-supplied labels, normalized by normalizePublishTags. Shares a vocabulary
|
|
12508
|
+
* with AppFile tags (see GET /api/publish/tags) so one label means one thing across the app,
|
|
12509
|
+
* but stored per artifact rather than in a central tag table - there is no tag entity to keep
|
|
12510
|
+
* in sync, and a tag nobody uses simply stops appearing. */
|
|
12511
|
+
tags: PublishTagsSchema.prefault([]),
|
|
11921
12512
|
visibility: VisibilitySchema.prefault("private"),
|
|
11922
12513
|
/** Group id a viewer must belong to when gated cross-scope. */
|
|
11923
12514
|
gatedToGroupId: z$1.string().optional(),
|
|
@@ -12003,6 +12594,9 @@ z$1.object({
|
|
|
12003
12594
|
title: z$1.string().min(1).max(200),
|
|
12004
12595
|
description: z$1.string().max(1e3).optional(),
|
|
12005
12596
|
visibility: VisibilitySchema.optional(),
|
|
12597
|
+
/** Optional at publish time so a client that already knows its labels - the CLI publish
|
|
12598
|
+
* skill - can set them in the same call instead of a follow-up PATCH. */
|
|
12599
|
+
tags: PublishTagsSchema.optional(),
|
|
12006
12600
|
gatedToGroupId: z$1.string().optional(),
|
|
12007
12601
|
/** Who may annotate the published artifact. Defaults to `none` (read-only). */
|
|
12008
12602
|
commentPolicy: CommentPolicySchema.optional(),
|
|
@@ -12243,6 +12837,32 @@ function isModelAccessible(model, userTags, isAdmin = false, entitlementKeys = [
|
|
|
12243
12837
|
const normalizedAllowedEntitlements = (model.allowedEntitlements ?? []).map(normalizeEntitlementKey);
|
|
12244
12838
|
return normalizedKeys.some((key) => normalizedAllowedEntitlements.includes(key));
|
|
12245
12839
|
}
|
|
12840
|
+
[...OPENAI_IMAGE_MODELS, ...GEMINI_IMAGE_MODELS];
|
|
12841
|
+
/** Generation was cut off against the output-token ceiling. */
|
|
12842
|
+
const TRUNCATED_FINISH_REASON = "max_tokens";
|
|
12843
|
+
/**
|
|
12844
|
+
* We aborted the stream ourselves because it degenerated into repetition
|
|
12845
|
+
* (`DEGENERATE_STREAM_STOP_REASON` in `@bike4mind/llm-adapters`). Distinct from
|
|
12846
|
+
* `max_tokens` because the useful advice differs: telling a user to continue is actively
|
|
12847
|
+
* wrong here, since resuming from a degenerated tail tends to reproduce the loop.
|
|
12848
|
+
*/
|
|
12849
|
+
const DEGENERATE_FINISH_REASON = "degenerate_repetition";
|
|
12850
|
+
/**
|
|
12851
|
+
* Every reason meaning "this reply stopped early". Membership rather than equality with a
|
|
12852
|
+
* single literal, so a newly-added early-stop reason surfaces a notice automatically.
|
|
12853
|
+
*/
|
|
12854
|
+
const EARLY_STOP_FINISH_REASONS = /* @__PURE__ */ new Set([TRUNCATED_FINISH_REASON, DEGENERATE_FINISH_REASON]);
|
|
12855
|
+
/**
|
|
12856
|
+
* Whether a reply stopped early, given the reason reported for it.
|
|
12857
|
+
*
|
|
12858
|
+
* An ABSENT reason is NOT an early stop. Plenty of paths never report one (a backend whose
|
|
12859
|
+
* complete() leaves it unset, an older server, a non-terminal chunk), and treating silence
|
|
12860
|
+
* as truncation would cry wolf on every one of them. Only a reason we recognize as an
|
|
12861
|
+
* early stop counts - an unrecognized value is left alone rather than guessed at.
|
|
12862
|
+
*/
|
|
12863
|
+
function isEarlyStop(stopReason) {
|
|
12864
|
+
return !!stopReason && EARLY_STOP_FINISH_REASONS.has(stopReason);
|
|
12865
|
+
}
|
|
12246
12866
|
/**
|
|
12247
12867
|
* Trigger-word validation, shared between client form and server agent
|
|
12248
12868
|
* endpoints so the validation rules can't drift.
|
|
@@ -12852,9 +13472,9 @@ Array.from(new Set([
|
|
|
12852
13472
|
requiresAdmin: true
|
|
12853
13473
|
},
|
|
12854
13474
|
{
|
|
12855
|
-
id: "admin.
|
|
13475
|
+
id: "admin.feedback",
|
|
12856
13476
|
section: "admin",
|
|
12857
|
-
label: "
|
|
13477
|
+
label: "Feedback",
|
|
12858
13478
|
description: "View and manage user feedback, bug reports, and feature requests",
|
|
12859
13479
|
navigationType: "tab",
|
|
12860
13480
|
target: "2",
|
|
@@ -13875,7 +14495,7 @@ const CliConfigSchema = z$1.object({
|
|
|
13875
14495
|
}).optional(),
|
|
13876
14496
|
mcpServers: McpServersSchema,
|
|
13877
14497
|
preferences: z$1.object({
|
|
13878
|
-
maxTokens: z$1.number(),
|
|
14498
|
+
maxTokens: z$1.number().optional(),
|
|
13879
14499
|
temperature: z$1.number(),
|
|
13880
14500
|
autoSave: z$1.boolean(),
|
|
13881
14501
|
autoCompact: z$1.boolean().optional().prefault(true),
|
|
@@ -13970,10 +14590,27 @@ const ProjectLocalConfigSchema = z$1.object({
|
|
|
13970
14590
|
sandbox: PartialSandboxConfigSchema
|
|
13971
14591
|
});
|
|
13972
14592
|
/**
|
|
14593
|
+
* The output budget every pre-migration config was born with, back when
|
|
14594
|
+
* `preferences.maxTokens` was required and DEFAULT_CONFIG supplied this value. It is
|
|
14595
|
+
* indistinguishable from a user who deliberately typed 4096, and the migration reverts
|
|
14596
|
+
* it either way - acceptable only because the cleanup runs ONCE (see CONFIG_SCHEMA_VERSION):
|
|
14597
|
+
* a user who wanted 4096 sets it again and keeps it, while an install that never chose it
|
|
14598
|
+
* stops being capped by it. A value-keyed rule with no marker would instead make 4096
|
|
14599
|
+
* permanently unrepresentable, even though the /config select still offers it.
|
|
14600
|
+
*/
|
|
14601
|
+
const LEGACY_PINNED_MAX_TOKENS = 4096;
|
|
14602
|
+
/**
|
|
14603
|
+
* Schema version of the on-disk config, and the marker that makes the migrations in
|
|
14604
|
+
* `load()` one-time. A file stamped with anything else gets the upgrade pass and is
|
|
14605
|
+
* rewritten at the current version; a file already at it is left alone. Bump this when
|
|
14606
|
+
* adding a migration, and gate the new step on the version it needs to run from.
|
|
14607
|
+
*/
|
|
14608
|
+
const CONFIG_SCHEMA_VERSION = "0.2.0";
|
|
14609
|
+
/**
|
|
13973
14610
|
* Default configuration
|
|
13974
14611
|
*/
|
|
13975
14612
|
const DEFAULT_CONFIG = {
|
|
13976
|
-
version:
|
|
14613
|
+
version: CONFIG_SCHEMA_VERSION,
|
|
13977
14614
|
userId: v4(),
|
|
13978
14615
|
defaultModel: ChatModels.CLAUDE_4_5_SONNET,
|
|
13979
14616
|
toolApiKeys: {
|
|
@@ -13982,7 +14619,6 @@ const DEFAULT_CONFIG = {
|
|
|
13982
14619
|
},
|
|
13983
14620
|
mcpServers: [],
|
|
13984
14621
|
preferences: {
|
|
13985
|
-
maxTokens: 4096,
|
|
13986
14622
|
temperature: .7,
|
|
13987
14623
|
autoSave: true,
|
|
13988
14624
|
autoCompact: true,
|
|
@@ -14262,6 +14898,13 @@ var ConfigStore = class {
|
|
|
14262
14898
|
if (oldApiConfig.environment === "custom" && oldApiConfig.customUrl) rawConfig.apiConfig = { customUrl: oldApiConfig.customUrl };
|
|
14263
14899
|
else rawConfig.apiConfig = {};
|
|
14264
14900
|
}
|
|
14901
|
+
if (rawConfig.version !== CONFIG_SCHEMA_VERSION) {
|
|
14902
|
+
if (rawConfig.preferences?.maxTokens === LEGACY_PINNED_MAX_TOKENS) delete rawConfig.preferences.maxTokens;
|
|
14903
|
+
rawConfig.version = CONFIG_SCHEMA_VERSION;
|
|
14904
|
+
try {
|
|
14905
|
+
await promises.writeFile(this.configPath, JSON.stringify(rawConfig, null, 2), "utf-8");
|
|
14906
|
+
} catch {}
|
|
14907
|
+
}
|
|
14265
14908
|
const validated = CliConfigSchema.parse(rawConfig);
|
|
14266
14909
|
const normalizedMcpServers = normalizeMcpServers(validated.mcpServers);
|
|
14267
14910
|
globalConfig = {
|
|
@@ -14692,4 +15335,4 @@ var ConfigStore = class {
|
|
|
14692
15335
|
}
|
|
14693
15336
|
};
|
|
14694
15337
|
//#endregion
|
|
14695
|
-
export {
|
|
15338
|
+
export { VoyageAIEmbeddingModel as $, HTTPError as A, resolveHistoryFetchLimit as At, PermissionDeniedError as B, isNearLimit as Bt, DEFAULT_MUSIC_MODEL_ID as C, isRetryableError as Ct, FIXED_TEMPERATURE_MODELS as D, isZodError as Dt, FIELD_GROUP_OF as E, isUserInitiatedAbort as Et, ModelBackend as F, usdToCredits as Ft, SpeechToTextModels as G, REASONING_SUPPORTED_MODELS as H, NO_TEMPERATURE_MODELS as I, usdToCreditsStochastic as It, TooManyRequestsError as J, SupportedFabFileMimeTypes as K, NotFoundError as L, withRetry as Lt, ImageModels as M, settingsMap as Mt, InternalServerError as N, toModelInfo as Nt, FORMAT_PROMPT_TEMPLATE as O, mapMimeTypeToArtifactType as Ot, MODEL_INFO_FIELD_GROUP_OF as P, toModelRecord as Pt, VideoModels as Q, OllamaEmbeddingModel as R, buildRateLimitLogEntry as Rt, CorruptedFileError as S, isRenderableModelType as St, DEGENERATE_FINISH_REASON as T, isUnlimitedHistory as Tt, REFUSAL_FALLBACK_MODELS as U, REASONING_EFFORT_INCOMPATIBLE_WITH_TOOLS_MODELS as V, parseRateLimitHeaders as Vt, RESPONSES_API_TOOL_MODELS as W, UnprocessableEntityError as X, UnauthorizedError as Y, VIDEO_SIZE_CONSTRAINTS as Z, BadRequestError as _, isImageServeable as _t, getCreditsUrl as a, getMcpProviderMetadata as at, CREDIT_DEDUCT_TRANSACTION_TYPES as b, isModelDeprecated as bt, requireApiUrl as c, isAudioMimeType as ct, AGENT_QUEST_MANIFEST as d, isEarlyStop as dt, WORK_ITEM_STATUSES as et, AGENT_QUEST_MCP_URI as f, isFieldGroup as ft, BFL_SAFETY_TOLERANCE as g, isImageAttachment as gt, BEDROCK_NO_PROMPT_CACHING_MODELS as h, isGeminiModelId as ht, LOCAL_DEV_URL as i, defaultEmbeddingModelForEnv as it, HttpStatus as j, secureParameters as jt, ForbiddenError as k, obfuscateApiKey as kt, resolveApiEndpoint as l, isChunkRebuildPending as lt, ApiKeyType as m, isGPTImageModel as mt, logger as n, calculateRetryDelay as nt, getEnvironmentName as o, getQuestErrorCode as ot, ARTIFACT_ATTRS_PATTERN as p, isGPTImage2Model as pt, TTS_MAX_INPUT_CHARS as q, ApiEndpointUnconfiguredError as r, dayjsConfig_default as rt, parseApiUrl as s, getRetryAfterMs as st, ConfigStore as t, applyModelPriceCatalog as tt, AGENT_QUEST_ID as u, isConvergencePausedNote as ut, BedrockEmbeddingModel as v, isMediaModelType as vt, DEFAULT_UNKNOWN_CONTEXT_WINDOW as w, isSupportedFabFileMimeType as wt, ChatModels as x, isPlaceholderApiKey as xt, CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS as y, isModelAccessible as yt, OpenAIEmbeddingModel as z, extractSnippetMeta as zt };
|