@bike4mind/cli 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{AgentHistoryStore-DIMzvf-y.mjs → AgentHistoryStore-DdYKfx7C.mjs} +145 -95
- package/dist/{ApiClient-BTI0-m0g.mjs → ApiClient-dIB3YQc2.mjs} +2 -2
- package/dist/{ConfigStore-DIs-K9oD.mjs → ConfigStore-BygzEI6H.mjs} +2756 -1316
- package/dist/{WorkItemsClient-Cow6nXx7.mjs → WorkItemsClient-ClBC49y0.mjs} +52 -8
- package/dist/{buildAgent-DOvEp92a.mjs → buildAgent-B7cMwRAy.mjs} +33 -2
- 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 +75 -23
- package/dist/{package-Dl_F2Fah.mjs → package-CRNnNXxq.mjs} +1 -1
- package/dist/{serve-Y2zMbfGs.mjs → serve-DM7ld3-o.mjs} +452 -25
- package/package.json +11 -11
|
@@ -61,6 +61,11 @@ const hearthEventKindSchema = z$1.enum([
|
|
|
61
61
|
"gate.resolve",
|
|
62
62
|
"system"
|
|
63
63
|
]);
|
|
64
|
+
const hearthEventOriginSchema = z$1.enum([
|
|
65
|
+
"session",
|
|
66
|
+
"api-key",
|
|
67
|
+
"gateway"
|
|
68
|
+
]);
|
|
64
69
|
const hearthHumanBodySchema = z$1.object({
|
|
65
70
|
text: z$1.string().min(1),
|
|
66
71
|
format: z$1.enum(["md", "text"])
|
|
@@ -81,7 +86,8 @@ z$1.object({
|
|
|
81
86
|
kind: hearthEventKindSchema,
|
|
82
87
|
human: hearthHumanBodySchema,
|
|
83
88
|
machine: hearthMachineBodySchema.optional(),
|
|
84
|
-
refs: hearthEventRefsSchema
|
|
89
|
+
refs: hearthEventRefsSchema,
|
|
90
|
+
origin: hearthEventOriginSchema
|
|
85
91
|
});
|
|
86
92
|
/** djb2. Deterministic across processes and restarts, which is the whole point. */
|
|
87
93
|
function hashOf(value) {
|
|
@@ -139,7 +145,18 @@ function lookup(map, kind, fallback) {
|
|
|
139
145
|
function actorKindMarker(kind) {
|
|
140
146
|
return lookup(ACTOR_KIND_MARKERS, kind, "?");
|
|
141
147
|
}
|
|
142
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Every field optional and unknown keys dropped: a low-disclosure hook tier
|
|
150
|
+
* forwards no activity block at all, and a hand-posted presence event should
|
|
151
|
+
* still refresh lastSeen rather than being rejected. No length caps here on
|
|
152
|
+
* purpose - the projection truncates, because losing a whole presence update
|
|
153
|
+
* over a long workspace name is the worse failure.
|
|
154
|
+
*
|
|
155
|
+
* This is the bare SHAPE only. Validate a stored or wire payload with
|
|
156
|
+
* `presencePayloadWithDefaults`, which reads a null payload as `{}`; this schema
|
|
157
|
+
* alone would reject one.
|
|
158
|
+
*/
|
|
159
|
+
const presencePayloadSchema = z$1.object({
|
|
143
160
|
/** Claude Code lifecycle event name; the reason fallback for tiers 0 and 1. */
|
|
144
161
|
hook_event_name: z$1.string().nullish(),
|
|
145
162
|
session_id: z$1.string().nullish(),
|
|
@@ -166,6 +183,14 @@ z$1.object({
|
|
|
166
183
|
background_tasks: z$1.number().int().min(0).nullish()
|
|
167
184
|
}).nullish()
|
|
168
185
|
});
|
|
186
|
+
z$1.preprocess((v) => v ?? {}, presencePayloadSchema);
|
|
187
|
+
/** `machine.schema` for `delegation` events; the only schema that kind accepts. */
|
|
188
|
+
const DELEGATION_PAYLOAD_SCHEMA_NAME = "hearth.delegation@1";
|
|
189
|
+
/** Extra keys are kept: hearth_delegate spreads caller-supplied extras into the payload. */
|
|
190
|
+
const delegationPayloadSchema = z$1.looseObject({
|
|
191
|
+
targetActorId: z$1.string().min(1),
|
|
192
|
+
task: z$1.string().min(1).max(4e3)
|
|
193
|
+
});
|
|
169
194
|
//#endregion
|
|
170
195
|
//#region ../../b4m-core/common/dist/index.mjs
|
|
171
196
|
var HTTPError = class extends Error {
|
|
@@ -269,6 +294,7 @@ const b4mLLMTools = z$1.enum([
|
|
|
269
294
|
"edit_image",
|
|
270
295
|
"music_generation",
|
|
271
296
|
"audio_generation",
|
|
297
|
+
"video_generation",
|
|
272
298
|
"weather_info",
|
|
273
299
|
"web_search",
|
|
274
300
|
"web_fetch",
|
|
@@ -637,6 +663,8 @@ let KnowledgeType = /* @__PURE__ */ function(KnowledgeType) {
|
|
|
637
663
|
* excluded from every LLM-attachment and vectorization path.
|
|
638
664
|
*/
|
|
639
665
|
KnowledgeType["AUDIO"] = "AUDIO";
|
|
666
|
+
/** Generated video. Media-only like AUDIO: storable and browsable, never ingested. */
|
|
667
|
+
KnowledgeType["VIDEO"] = "VIDEO";
|
|
640
668
|
return KnowledgeType;
|
|
641
669
|
}({});
|
|
642
670
|
/**
|
|
@@ -896,9 +924,14 @@ let ChatModels = /* @__PURE__ */ function(ChatModels) {
|
|
|
896
924
|
ChatModels["CLAUDE_4_5_OPUS_BEDROCK"] = "global.anthropic.claude-opus-4-5-20251101-v1:0";
|
|
897
925
|
ChatModels["CLAUDE_4_6_SONNET_BEDROCK"] = "global.anthropic.claude-sonnet-4-6";
|
|
898
926
|
ChatModels["CLAUDE_5_SONNET_BEDROCK"] = "global.anthropic.claude-sonnet-5";
|
|
927
|
+
ChatModels["CLAUDE_5_5_SONNET_BEDROCK"] = "global.anthropic.claude-sonnet-5-5";
|
|
899
928
|
ChatModels["CLAUDE_4_6_OPUS_BEDROCK"] = "global.anthropic.claude-opus-4-6-v1";
|
|
900
929
|
ChatModels["CLAUDE_4_7_OPUS_BEDROCK"] = "global.anthropic.claude-opus-4-7";
|
|
901
930
|
ChatModels["CLAUDE_4_8_OPUS_BEDROCK"] = "global.anthropic.claude-opus-4-8";
|
|
931
|
+
ChatModels["CLAUDE_FABLE_5_BEDROCK"] = "global.anthropic.claude-fable-5";
|
|
932
|
+
ChatModels["CLAUDE_FABLE_5_1_BEDROCK"] = "global.anthropic.claude-fable-5-1";
|
|
933
|
+
ChatModels["CLAUDE_5_OPUS_BEDROCK"] = "global.anthropic.claude-opus-5";
|
|
934
|
+
ChatModels["CLAUDE_5_5_OPUS_BEDROCK"] = "global.anthropic.claude-opus-5-5";
|
|
902
935
|
ChatModels["CLAUDE_3_OPUS"] = "claude-3-opus-20240229";
|
|
903
936
|
ChatModels["CLAUDE_3_5_HAIKU_ANTHROPIC"] = "claude-3-5-haiku-20241022";
|
|
904
937
|
ChatModels["CLAUDE_3_5_SONNET_ANTHROPIC"] = "claude-3-5-sonnet-20241022";
|
|
@@ -990,39 +1023,10 @@ let SpeechToTextModels = /* @__PURE__ */ function(SpeechToTextModels) {
|
|
|
990
1023
|
}({});
|
|
991
1024
|
Object.values(SpeechToTextModels);
|
|
992
1025
|
z$1.enum(SpeechToTextModels);
|
|
993
|
-
/**
|
|
994
|
-
* Video Models
|
|
995
|
-
*/
|
|
996
|
-
let VideoModels = /* @__PURE__ */ function(VideoModels) {
|
|
997
|
-
VideoModels["SORA_2"] = "sora-2";
|
|
998
|
-
VideoModels["SORA_2_PRO"] = "sora-2-pro";
|
|
999
|
-
return VideoModels;
|
|
1000
|
-
}({});
|
|
1001
|
-
Object.values(VideoModels);
|
|
1002
|
-
z$1.enum(VideoModels);
|
|
1003
|
-
/**
|
|
1004
|
-
* Video size constraints and options for Sora
|
|
1005
|
-
*/
|
|
1006
|
-
const VIDEO_SIZE_CONSTRAINTS = { SORA: {
|
|
1007
|
-
durations: [
|
|
1008
|
-
4,
|
|
1009
|
-
8,
|
|
1010
|
-
12
|
|
1011
|
-
],
|
|
1012
|
-
sizes: [
|
|
1013
|
-
"720x1280",
|
|
1014
|
-
"1280x720",
|
|
1015
|
-
"1024x1792",
|
|
1016
|
-
"1792x1024"
|
|
1017
|
-
],
|
|
1018
|
-
defaultDuration: 4,
|
|
1019
|
-
defaultSize: "720x1280"
|
|
1020
|
-
} };
|
|
1021
1026
|
z$1.enum({
|
|
1022
1027
|
...ChatModels,
|
|
1023
1028
|
...ImageModels,
|
|
1024
|
-
...SpeechToTextModels
|
|
1025
|
-
...VideoModels
|
|
1029
|
+
...SpeechToTextModels
|
|
1026
1030
|
});
|
|
1027
1031
|
Object.freeze({
|
|
1028
1032
|
requestsPerMinute: 60,
|
|
@@ -1589,7 +1593,7 @@ const ModelRecordFields = z$1.strictObject({
|
|
|
1589
1593
|
/** Operator-owned block. Discovery may never set or clear it. */
|
|
1590
1594
|
disabled: z$1.boolean().optional(),
|
|
1591
1595
|
disabledReason: z$1.string().optional(),
|
|
1592
|
-
/** Discovery-owned block ("discovered, awaiting price"). Operators may never clear it. */
|
|
1596
|
+
/** Discovery-owned block (e.g. "discovered, awaiting price"). Operators may never clear it. */
|
|
1593
1597
|
autoDisabled: z$1.boolean().optional(),
|
|
1594
1598
|
autoDisabledReason: z$1.string().optional(),
|
|
1595
1599
|
private: z$1.boolean().optional(),
|
|
@@ -2034,6 +2038,8 @@ z$1.object({
|
|
|
2034
2038
|
joinCoverage: z$1.array(DiscoveryJoinCoverage).optional(),
|
|
2035
2039
|
/** Ids no aggregator matched: a work item, not a log line. */
|
|
2036
2040
|
unmatchedIds: z$1.array(z$1.string()).optional(),
|
|
2041
|
+
/** Bedrock profile ids whose foundation id a covered listing omitted: neither sighted nor missed. */
|
|
2042
|
+
frozenProfileIds: z$1.array(z$1.string()).optional(),
|
|
2037
2043
|
changes: DiscoveryRunChanges.optional(),
|
|
2038
2044
|
/** Convergence passes the run made; the cap being hit is worth seeing. */
|
|
2039
2045
|
passes: z$1.number().int().nonnegative().optional(),
|
|
@@ -2436,6 +2442,21 @@ z$1.object({
|
|
|
2436
2442
|
onBehalfOfUserId: z$1.string().optional()
|
|
2437
2443
|
}).optional()
|
|
2438
2444
|
});
|
|
2445
|
+
const GENERATION_JOB_KINDS = ["video"];
|
|
2446
|
+
const GENERATION_JOB_STATES = [
|
|
2447
|
+
"pending",
|
|
2448
|
+
"running",
|
|
2449
|
+
"storing",
|
|
2450
|
+
"succeeded",
|
|
2451
|
+
"failed",
|
|
2452
|
+
"blocked",
|
|
2453
|
+
"cancelled"
|
|
2454
|
+
];
|
|
2455
|
+
const GENERATION_JOB_SOURCES = [
|
|
2456
|
+
"api",
|
|
2457
|
+
"studio",
|
|
2458
|
+
"agent"
|
|
2459
|
+
];
|
|
2439
2460
|
/**
|
|
2440
2461
|
* SRE Agent Trio - Shared Types
|
|
2441
2462
|
*
|
|
@@ -2866,6 +2887,47 @@ const AGENT_QUEST_MANIFEST = {
|
|
|
2866
2887
|
}
|
|
2867
2888
|
};
|
|
2868
2889
|
/**
|
|
2890
|
+
* Click-time template resolution for briefcase prompts. Pure and DOM-free so it
|
|
2891
|
+
* is unit-testable and reusable on any surface.
|
|
2892
|
+
*/
|
|
2893
|
+
const PLACEHOLDER_RE = /\{\{(\w+)\}\}/g;
|
|
2894
|
+
/**
|
|
2895
|
+
* Replace every `{{key}}` in `promptText` with the matching context value.
|
|
2896
|
+
*
|
|
2897
|
+
* Invariants (see the briefcase blueprint's Test Patterns):
|
|
2898
|
+
* - SINGLE PASS: each placeholder is resolved exactly once against the ORIGINAL
|
|
2899
|
+
* template - a value that itself contains `{{x}}` is never re-substituted.
|
|
2900
|
+
* - Unknown placeholders are left untouched.
|
|
2901
|
+
* - null/undefined values are skipped (the placeholder is left untouched - no
|
|
2902
|
+
* literal "null"/"undefined" leaks into the prompt).
|
|
2903
|
+
* - The FUNCTION form of replace is used so `$&`, `$1`, `$$` etc. in a value
|
|
2904
|
+
* are inserted literally rather than interpreted as replacement patterns.
|
|
2905
|
+
*/
|
|
2906
|
+
function replacePromptVariables(promptText, context) {
|
|
2907
|
+
const ctx = context;
|
|
2908
|
+
return promptText.replace(PLACEHOLDER_RE, (match, key) => {
|
|
2909
|
+
const value = ctx[key];
|
|
2910
|
+
if (value === null || value === void 0) return match;
|
|
2911
|
+
return String(value);
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
/**
|
|
2915
|
+
* Build a fresh substitution context from the signed-in user, the selected org,
|
|
2916
|
+
* and the current clock. `now` is injectable for deterministic tests.
|
|
2917
|
+
*/
|
|
2918
|
+
function buildPromptContext(user, organizationName, now = /* @__PURE__ */ new Date()) {
|
|
2919
|
+
return {
|
|
2920
|
+
organization: organizationName ?? void 0,
|
|
2921
|
+
userName: user?.name ?? void 0,
|
|
2922
|
+
userEmail: user?.email ?? void 0,
|
|
2923
|
+
userRole: user?.role ?? void 0,
|
|
2924
|
+
currentDateTime: now.toISOString(),
|
|
2925
|
+
currentDate: now.toISOString().slice(0, 10),
|
|
2926
|
+
currentTime: now.toISOString().slice(11, 19),
|
|
2927
|
+
currentYear: String(now.getUTCFullYear())
|
|
2928
|
+
};
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2869
2931
|
* Input headroom the chat path holds back on top of a request's reserved output.
|
|
2870
2932
|
* safeInputWindow (ChatCompletionProcess) subtracts it, so a text entry whose output
|
|
2871
2933
|
* reserve leaves less than this has no room for a prompt at all.
|
|
@@ -3029,7 +3091,8 @@ const BRIEFCASE_DISALLOWED_TOOLS = [
|
|
|
3029
3091
|
"blog_draft"
|
|
3030
3092
|
];
|
|
3031
3093
|
const BriefcaseRequiredToolsSchema = z$1.array(b4mLLMTools.refine((t) => !BRIEFCASE_DISALLOWED_TOOLS.includes(t), "This tool is not permitted in a briefcase prompt")).max(16);
|
|
3032
|
-
|
|
3094
|
+
/** A 24-char hex Mongo ObjectId string (for by-id refetch and personal CRUD). */
|
|
3095
|
+
const BriefcasePromptIdSchema = z$1.string().regex(/^[a-f0-9]{24}$/i, "Invalid prompt id");
|
|
3033
3096
|
/** Shared cap for every free-text prompt body a caller can supply. Exported so the
|
|
3034
3097
|
* caller-prompt caps on the chat request, the invoke params and the CLI tool import it
|
|
3035
3098
|
* rather than each restating the literal. */
|
|
@@ -3056,813 +3119,1152 @@ const PromptBatchQuerySchema = z$1.object({
|
|
|
3056
3119
|
});
|
|
3057
3120
|
z$1.object({ queries: z$1.array(PromptBatchQuerySchema).min(1).max(32).refine((qs) => new Set(qs.map((q) => q.key)).size === qs.length, { message: "Batch query keys must be unique" }) });
|
|
3058
3121
|
/**
|
|
3059
|
-
*
|
|
3060
|
-
*
|
|
3061
|
-
* Shared
|
|
3062
|
-
*
|
|
3063
|
-
* (
|
|
3064
|
-
* what the handler actually accepts. The model is optional here and resolved
|
|
3065
|
-
* server-side from admin settings when omitted.
|
|
3066
|
-
*
|
|
3067
|
-
* Public-API rule: no `.catch()` / top-level `.transform()`. Both silently mutate
|
|
3068
|
-
* caller input (fail-quiet) and are opaque to zod-to-openapi. `historyCount` uses
|
|
3069
|
-
* `.default()` (fail loud on a bad value); unknown tool ids are filtered in the
|
|
3070
|
-
* handler (see filterKnownTools) instead of by a schema transform. This keeps the
|
|
3071
|
-
* schema fully OpenAPI-representable with no doc projection needed.
|
|
3122
|
+
* The default catalog layout: one group per seeded system category (the `type`
|
|
3123
|
+
* discriminator set by the briefcase seed migration) plus the caller's personal
|
|
3124
|
+
* prompts. Shared by the web launcher panel and the CLI's MCP prompts surface so
|
|
3125
|
+
* both list the same catalog. `as const` lets a consumer derive the key union
|
|
3126
|
+
* (e.g. for a label map) instead of restating it.
|
|
3072
3127
|
*/
|
|
3073
|
-
const
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
"surface"
|
|
3097
|
-
]).optional(),
|
|
3098
|
-
skip_auto_offers: z$1.boolean().optional().describe("Suppress tools the server would otherwise attach on its own for this session (the knowledge-base search offer, in-app view navigation, blog drafting/editing/publishing, skill invocation, and every tool from a connected MCP server). Native tools you request explicitly in `tools` are unaffected, but an MCP server tool cannot be named through this field, so with this flag set a caller with an MCP server connected sees none of its tools regardless of `tools`. One system-prompt block goes with them: withholding in-app view navigation also drops the view-registry block that exists only to describe it. No other prompt content changes. This does not switch off retrieval: a session with forced knowledge retrieval still retrieves, and documents already attached to the session are still placed in the prompt directly. Any promptMode suppresses these too, so false has no effect alongside one."),
|
|
3099
|
-
includePromptDetails: z$1.boolean().optional(),
|
|
3100
|
-
includeSystemPrompt: z$1.boolean().optional(),
|
|
3101
|
-
systemPrompt: z$1.string().max(PROMPT_TEXT_MAX).optional().describe("System-prompt text for this request only, never persisted. Rendered as a defended block appended after every other system-prompt source, with prose instructing the model to defer to organization, session and data-lake guidance. Over the cap is a 422, never truncated.")
|
|
3128
|
+
const BRIEFCASE_CATALOG_QUERIES = [
|
|
3129
|
+
{
|
|
3130
|
+
key: "general",
|
|
3131
|
+
type: "general"
|
|
3132
|
+
},
|
|
3133
|
+
{
|
|
3134
|
+
key: "writing",
|
|
3135
|
+
type: "writing"
|
|
3136
|
+
},
|
|
3137
|
+
{
|
|
3138
|
+
key: "learning",
|
|
3139
|
+
type: "learning"
|
|
3140
|
+
},
|
|
3141
|
+
{
|
|
3142
|
+
key: "personal",
|
|
3143
|
+
personal: true
|
|
3144
|
+
}
|
|
3145
|
+
];
|
|
3146
|
+
const AnonymousSessionIdSchema = z$1.object({
|
|
3147
|
+
/** SHA256(userId|orgId|dailySalt|date) - cannot be reversed */
|
|
3148
|
+
hash: z$1.string(),
|
|
3149
|
+
/** YYYY-MM-DD for salt lookup during deletion */
|
|
3150
|
+
dateKey: z$1.string()
|
|
3102
3151
|
});
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
* handler assembles the ack body inline (apps/client/pages/api/chat.ts), so
|
|
3109
|
-
* this schema MUST stay in sync with that `res.json({...})` shape.
|
|
3110
|
-
*/
|
|
3111
|
-
const ChatAckSchema = z$1.object({
|
|
3112
|
-
id: z$1.string(),
|
|
3113
|
-
status: z$1.string(),
|
|
3114
|
-
message_received: z$1.boolean(),
|
|
3115
|
-
timestamp: z$1.string(),
|
|
3116
|
-
model: z$1.string(),
|
|
3117
|
-
sessionId: z$1.string().optional(),
|
|
3118
|
-
message: z$1.string().optional(),
|
|
3119
|
-
type: z$1.enum(CHAT_HISTORY_ITEM_TYPES).optional(),
|
|
3120
|
-
errorCode: z$1.enum(QUEST_ERROR_CODES).optional(),
|
|
3121
|
-
tools: z$1.object({
|
|
3122
|
-
toolMode: z$1.enum(["fast", "smart"]).optional(),
|
|
3123
|
-
autoSelectedTools: z$1.array(z$1.string()).optional(),
|
|
3124
|
-
effectiveTools: z$1.array(z$1.string()),
|
|
3125
|
-
unrecognizedTools: z$1.array(z$1.string()).optional()
|
|
3126
|
-
}).optional(),
|
|
3127
|
-
tracking_info: z$1.object({
|
|
3128
|
-
quest_id: z$1.string(),
|
|
3129
|
-
check_status_url: z$1.string(),
|
|
3130
|
-
poll_url: z$1.string().optional()
|
|
3131
|
-
})
|
|
3152
|
+
const SpanContextSchema = z$1.object({
|
|
3153
|
+
/** gen_ai.trace_id */
|
|
3154
|
+
traceId: z$1.string(),
|
|
3155
|
+
/** gen_ai.span_id */
|
|
3156
|
+
spanId: z$1.string()
|
|
3132
3157
|
});
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
* content, so it polls back as `type: 'message'`. What marks it unfinished is
|
|
3147
|
-
* `promptMeta.finishReason` - RUN_TIMED_OUT_FINISH_REASON or
|
|
3148
|
-
* RUN_ABANDONED_FINISH_REASON (utils/stopReasons.ts) - plus a notice appended to
|
|
3149
|
-
* the reply.
|
|
3150
|
-
*/
|
|
3151
|
-
const PolledFallbackInfoSchema = FallbackInfoSchema.pick({
|
|
3152
|
-
primaryModel: true,
|
|
3153
|
-
primaryModelName: true,
|
|
3154
|
-
fallbackModel: true,
|
|
3155
|
-
fallbackModelName: true,
|
|
3156
|
-
reason: true
|
|
3158
|
+
const OperationSchema = z$1.object({
|
|
3159
|
+
name: z$1.enum([
|
|
3160
|
+
"chat_completion",
|
|
3161
|
+
"agent_invoke",
|
|
3162
|
+
"tool_execute"
|
|
3163
|
+
]),
|
|
3164
|
+
finishReason: z$1.enum([
|
|
3165
|
+
"stop",
|
|
3166
|
+
"length",
|
|
3167
|
+
"tool_use",
|
|
3168
|
+
"content_filter",
|
|
3169
|
+
"error"
|
|
3170
|
+
]).optional()
|
|
3157
3171
|
});
|
|
3158
|
-
const
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
"
|
|
3163
|
-
"
|
|
3164
|
-
"
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3172
|
+
const ModelTelemetrySchema = z$1.object({
|
|
3173
|
+
/** gen_ai.request.model */
|
|
3174
|
+
modelId: z$1.string(),
|
|
3175
|
+
provider: z$1.enum([
|
|
3176
|
+
"anthropic",
|
|
3177
|
+
"openai",
|
|
3178
|
+
"bedrock",
|
|
3179
|
+
"google",
|
|
3180
|
+
"xai",
|
|
3181
|
+
"ollama",
|
|
3182
|
+
"moonshot",
|
|
3183
|
+
"deepseek"
|
|
3184
|
+
]),
|
|
3185
|
+
fallbackUsed: z$1.boolean(),
|
|
3186
|
+
fallbackReason: z$1.string().optional(),
|
|
3187
|
+
originalModelId: z$1.string().optional(),
|
|
3188
|
+
usedThinking: z$1.boolean(),
|
|
3189
|
+
/** Extended thinking tokens */
|
|
3190
|
+
thinkingTokensUsed: z$1.number().optional(),
|
|
3191
|
+
usedTools: z$1.boolean()
|
|
3171
3192
|
});
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3193
|
+
const SystemPromptDetailSchema = z$1.object({
|
|
3194
|
+
source: z$1.enum([
|
|
3195
|
+
"hardcoded",
|
|
3196
|
+
"admin",
|
|
3197
|
+
"user",
|
|
3198
|
+
"project",
|
|
3199
|
+
"session",
|
|
3200
|
+
"org",
|
|
3201
|
+
"caller"
|
|
3202
|
+
]),
|
|
3203
|
+
/** e.g., "date_context", "tool_guidance" */
|
|
3204
|
+
name: z$1.string(),
|
|
3205
|
+
tokenCount: z$1.number(),
|
|
3206
|
+
wasIncluded: z$1.boolean(),
|
|
3207
|
+
exclusionReason: z$1.enum([
|
|
3208
|
+
"duplicate",
|
|
3209
|
+
"disabled",
|
|
3210
|
+
"token_limit"
|
|
3211
|
+
]).optional()
|
|
3212
|
+
});
|
|
3213
|
+
const SystemPromptsTelemetrySchema = z$1.object({
|
|
3214
|
+
prompts: z$1.array(SystemPromptDetailSchema),
|
|
3215
|
+
totalTokens: z$1.number(),
|
|
3216
|
+
duplicateCount: z$1.number()
|
|
3217
|
+
});
|
|
3218
|
+
const FeatureContributionSchema = z$1.object({
|
|
3219
|
+
/** e.g., "mementos", "quest_master", "deep_research" */
|
|
3220
|
+
featureName: z$1.string(),
|
|
3221
|
+
messagesAdded: z$1.number(),
|
|
3222
|
+
tokenCount: z$1.number(),
|
|
3223
|
+
executionTimeMs: z$1.number(),
|
|
3224
|
+
success: z$1.boolean(),
|
|
3225
|
+
errorType: z$1.string().optional()
|
|
3226
|
+
});
|
|
3227
|
+
const FeaturesTelemetrySchema = z$1.object({ contributions: z$1.array(FeatureContributionSchema) });
|
|
3228
|
+
const TokensBySourceSchema = z$1.object({
|
|
3229
|
+
systemPrompts: z$1.number(),
|
|
3230
|
+
conversationHistory: z$1.number(),
|
|
3231
|
+
mementos: z$1.number(),
|
|
3232
|
+
fabFiles: z$1.number(),
|
|
3233
|
+
urlContent: z$1.number(),
|
|
3234
|
+
toolSchemas: z$1.number(),
|
|
3235
|
+
userPrompt: z$1.number(),
|
|
3183
3236
|
/**
|
|
3184
|
-
*
|
|
3185
|
-
*
|
|
3186
|
-
*
|
|
3187
|
-
*
|
|
3237
|
+
* Lake-sourced content injected this turn (forced retrieval + the lake-memory hot card), split out
|
|
3238
|
+
* of `systemPrompts`. Optional and absent means UNKNOWN, never zero - telemetry captured before
|
|
3239
|
+
* this bucket existed has no value to report and must not be read as "no lake content". Mirrors
|
|
3240
|
+
* PromptMetaTokensBySourceSchema in promptMeta.ts.
|
|
3188
3241
|
*/
|
|
3189
|
-
|
|
3242
|
+
lakeRetrieval: z$1.number().optional()
|
|
3190
3243
|
});
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
*/
|
|
3202
|
-
|
|
3203
|
-
/** 503 when this deployment has no usable key for a provider the request needs (data-lake search, voice). */
|
|
3204
|
-
const ProviderNotConfiguredErrorSchema = ApiErrorSchema.extend({ errorCode: z$1.literal("provider_not_configured").optional() });
|
|
3205
|
-
/**
|
|
3206
|
-
* Error envelope for the 403 apiKeyAuth (apps/client/server/middlewares/apiKeyAuth.ts)
|
|
3207
|
-
* throws when an API key lacks a route's scopes. It names what the ROUTE requires,
|
|
3208
|
-
* never what the key holds, so a caller knows which scope to mint a key with.
|
|
3209
|
-
* Values are `ApiKeyScope` strings; plain `z.string()` because the enum's module is
|
|
3210
|
-
* not import-safe for the install-only openapi job (see the import note above).
|
|
3211
|
-
*/
|
|
3212
|
-
const ScopeForbiddenErrorSchema = ApiErrorSchema.extend({
|
|
3213
|
-
required_scopes: z$1.array(z$1.string()).optional().describe("API key scopes this route accepts. Holding any one of them satisfies it."),
|
|
3214
|
-
also_required_scopes: z$1.array(z$1.string()).optional().describe("API key scopes this route also requires. Every one must be held, on top of `required_scopes`.")
|
|
3244
|
+
z$1.object({
|
|
3245
|
+
/** gen_ai.usage.input_tokens */
|
|
3246
|
+
inputTokens: z$1.number(),
|
|
3247
|
+
/** gen_ai.usage.output_tokens */
|
|
3248
|
+
outputTokens: z$1.number(),
|
|
3249
|
+
contextWindowLimit: z$1.number(),
|
|
3250
|
+
utilizationPercentage: z$1.number(),
|
|
3251
|
+
reservedOutputTokens: z$1.number(),
|
|
3252
|
+
overflowDetected: z$1.boolean(),
|
|
3253
|
+
overflowAmount: z$1.number().optional(),
|
|
3254
|
+
/** Token breakdown by source */
|
|
3255
|
+
tokensBySource: TokensBySourceSchema
|
|
3215
3256
|
});
|
|
3216
|
-
const
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
"pcm"
|
|
3225
|
-
]);
|
|
3226
|
-
const TTS_ABSOLUTE_MAX_INPUT_CHARS = Math.max(...Object.values({
|
|
3227
|
-
openai: 4096,
|
|
3228
|
-
elevenlabs: 1e4
|
|
3229
|
-
}));
|
|
3230
|
-
const ttsLanguageCodeSchema = z.string().regex(/^[a-z]{2}$/, "languageCode must be a lowercase ISO 639-1 code, e.g. \"en\" or \"ja\"");
|
|
3231
|
-
const ttsRequestSchema = z.object({
|
|
3232
|
-
text: z.string().min(1).max(TTS_ABSOLUTE_MAX_INPUT_CHARS),
|
|
3233
|
-
provider: supportedVoiceGenerationVendor.optional(),
|
|
3234
|
-
model: z.string().optional(),
|
|
3235
|
-
voice: z.string().optional(),
|
|
3236
|
-
format: voiceOutputFormatSchema.optional(),
|
|
3237
|
-
stability: z.number().min(0).max(1).optional(),
|
|
3238
|
-
similarityBoost: z.number().min(0).max(1).optional(),
|
|
3239
|
-
languageCode: ttsLanguageCodeSchema.optional(),
|
|
3240
|
-
...generatedAudioRequestFields
|
|
3257
|
+
const CacheTelemetrySchema = z$1.object({
|
|
3258
|
+
/** Anthropic cache_read_input_tokens */
|
|
3259
|
+
cacheReadTokens: z$1.number(),
|
|
3260
|
+
/** Anthropic cache_creation_input_tokens */
|
|
3261
|
+
cacheWriteTokens: z$1.number(),
|
|
3262
|
+
/** 0-100% */
|
|
3263
|
+
cacheHitRate: z$1.number(),
|
|
3264
|
+
costSavingsPercent: z$1.number().optional()
|
|
3241
3265
|
});
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
const ttsBase64ResponseSchema = extendGeneratedAudioResponseSchema({
|
|
3248
|
-
format: voiceOutputFormatSchema,
|
|
3249
|
-
/** The provider that actually produced the audio, present only on a fallback. */
|
|
3250
|
-
provider: supportedVoiceGenerationVendor.optional(),
|
|
3251
|
-
/** The originally requested provider that could not serve the request. */
|
|
3252
|
-
fallbackFrom: supportedVoiceGenerationVendor.optional()
|
|
3266
|
+
const CostsTelemetrySchema = z$1.object({
|
|
3267
|
+
inputCostUsd: z$1.number(),
|
|
3268
|
+
outputCostUsd: z$1.number(),
|
|
3269
|
+
totalCostUsd: z$1.number(),
|
|
3270
|
+
creditsUsed: z$1.number()
|
|
3253
3271
|
});
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
* `provider_not_configured` and for an upstream credential rejection
|
|
3267
|
-
* (`provider_rejected`, from an upstream 401 or 403).
|
|
3268
|
-
* - 422: thrown by request validation and by the char-limit / format guards;
|
|
3269
|
-
* written by the handler for `insufficient_credits` and for every upstream 4xx
|
|
3270
|
-
* that is neither a credential rejection nor a 429.
|
|
3271
|
-
* - 429: thrown by apiKeyRateLimit; written by the handler on an upstream 429.
|
|
3272
|
-
* - 502: only ever written.
|
|
3273
|
-
*
|
|
3274
|
-
* So those two are genuinely optional here, and splitting this per status would be
|
|
3275
|
-
* wrong for the first three. The 502 does advertise both without ever sending them;
|
|
3276
|
-
* that is not worth a fourth error schema on one route, and `request_id` missing from
|
|
3277
|
-
* this handler's written bodies is a gap in the handler rather than something to
|
|
3278
|
-
* enshrine in a schema.
|
|
3279
|
-
*/
|
|
3280
|
-
const ttsErrorResponseSchema = ApiErrorSchema.extend({
|
|
3281
|
-
provider: supportedVoiceGenerationVendor.optional(),
|
|
3282
|
-
errorCode: z.enum([
|
|
3283
|
-
"insufficient_credits",
|
|
3284
|
-
"provider_not_configured",
|
|
3285
|
-
"provider_rejected"
|
|
3286
|
-
]).optional()
|
|
3272
|
+
const TruncationTelemetrySchema = z$1.object({
|
|
3273
|
+
wasTruncated: z$1.boolean(),
|
|
3274
|
+
originalMessageCount: z$1.number(),
|
|
3275
|
+
finalMessageCount: z$1.number(),
|
|
3276
|
+
truncatedMessageCount: z$1.number(),
|
|
3277
|
+
truncationMethod: z$1.enum([
|
|
3278
|
+
"priority",
|
|
3279
|
+
"token-budget",
|
|
3280
|
+
"history-limit",
|
|
3281
|
+
"context-overflow"
|
|
3282
|
+
]).optional(),
|
|
3283
|
+
truncationPercentage: z$1.number()
|
|
3287
3284
|
});
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
*/
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3285
|
+
const ToolErrorCategorySchema = z$1.enum([
|
|
3286
|
+
"timeout",
|
|
3287
|
+
"rate_limit",
|
|
3288
|
+
"auth_error",
|
|
3289
|
+
"validation_error",
|
|
3290
|
+
"network_error",
|
|
3291
|
+
"internal_error"
|
|
3292
|
+
]);
|
|
3293
|
+
const ToolTelemetrySchema = z$1.object({
|
|
3294
|
+
toolName: z$1.string(),
|
|
3295
|
+
/** MCP vs native tool */
|
|
3296
|
+
isMcpTool: z$1.boolean(),
|
|
3297
|
+
/** For MCP tools */
|
|
3298
|
+
mcpServerName: z$1.string().optional(),
|
|
3299
|
+
invocationCount: z$1.number(),
|
|
3300
|
+
successCount: z$1.number(),
|
|
3301
|
+
failureCount: z$1.number(),
|
|
3302
|
+
totalDurationMs: z$1.number(),
|
|
3303
|
+
maxDurationMs: z$1.number(),
|
|
3304
|
+
/** Retry tracking */
|
|
3305
|
+
retryCount: z$1.number(),
|
|
3306
|
+
/** Max 200 chars */
|
|
3307
|
+
lastError: z$1.string().max(200).optional(),
|
|
3308
|
+
errorCategories: z$1.array(ToolErrorCategorySchema).optional(),
|
|
3309
|
+
/**
|
|
3310
|
+
* Content-size metrics for tools that extract text (currently web_fetch, issue #452).
|
|
3311
|
+
* Zero-PII integer counts, so kept at both basic and enhanced capture levels.
|
|
3312
|
+
*/
|
|
3313
|
+
/** Count of unique truncated citables at the tool's size cap (citables dedupe by url,
|
|
3314
|
+
* so same-url refetches within a completion collapse to one - see WebFetchContentTelemetry). */
|
|
3315
|
+
truncatedInvocationCount: z$1.number().optional(),
|
|
3316
|
+
/** Largest single extracted (post-cap) content length across invocations. */
|
|
3317
|
+
maxExtractedChars: z$1.number().optional(),
|
|
3318
|
+
/** Sum of extracted (post-cap) content length across invocations. */
|
|
3319
|
+
totalExtractedChars: z$1.number().optional()
|
|
3306
3320
|
});
|
|
3307
|
-
z.
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
*/
|
|
3321
|
-
const soundEffectsRequestSchema = z.object({
|
|
3322
|
-
provider: supportedSoundGenerationVendor.default("elevenlabs"),
|
|
3323
|
-
text: z.string().min(1).max(1e3),
|
|
3324
|
-
durationSeconds: z.number().min(.5).max(30).optional(),
|
|
3325
|
-
promptInfluence: z.number().min(0).max(1).optional(),
|
|
3326
|
-
format: z.string().optional(),
|
|
3327
|
-
...generatedAudioRequestFields
|
|
3321
|
+
const SubagentTelemetrySchema = z$1.object({
|
|
3322
|
+
agentName: z$1.string(),
|
|
3323
|
+
delegationCount: z$1.number(),
|
|
3324
|
+
successCount: z$1.number(),
|
|
3325
|
+
failureCount: z$1.number(),
|
|
3326
|
+
timeoutCount: z$1.number(),
|
|
3327
|
+
totalDurationMs: z$1.number(),
|
|
3328
|
+
totalTokensUsed: z$1.number(),
|
|
3329
|
+
thoroughness: z$1.enum([
|
|
3330
|
+
"quick",
|
|
3331
|
+
"medium",
|
|
3332
|
+
"very_thorough"
|
|
3333
|
+
]).optional()
|
|
3328
3334
|
});
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
const supportedMusicGenerationVendor = z.enum(["elevenlabs"]);
|
|
3334
|
-
/**
|
|
3335
|
-
* Supported ElevenLabs music models. Scoped to `music_v1` for now; `music_v2` is
|
|
3336
|
-
* a deliberate follow-up (see the parent issue). Adding it here is the only
|
|
3337
|
-
* change the request surface needs to accept it.
|
|
3338
|
-
*/
|
|
3339
|
-
const supportedMusicModel = z.enum(["music_v1"]);
|
|
3340
|
-
/**
|
|
3341
|
-
* Inbound request body for `POST /api/ai/music`.
|
|
3342
|
-
*
|
|
3343
|
-
* `lengthMs` upper bound is capped below the ElevenLabs Music API ceiling to fit
|
|
3344
|
-
* the serving function's time budget (see MAX_MUSIC_LENGTH_MS). It carries a
|
|
3345
|
-
* default rather than being optional so the billed
|
|
3346
|
-
* length is always known up front (the reserve/settle path needs a deterministic
|
|
3347
|
-
* cost before generation) and the route can force that exact length on the
|
|
3348
|
-
* provider. `format` is the provider-specific output encoding token (e.g.
|
|
3349
|
-
* `mp3_44100_128`).
|
|
3350
|
-
*/
|
|
3351
|
-
const musicRequestSchema = z.object({
|
|
3352
|
-
provider: supportedMusicGenerationVendor.default("elevenlabs"),
|
|
3353
|
-
prompt: z.string().min(1).max(2e3),
|
|
3354
|
-
lengthMs: z.number().int().min(3e3).max(12e4).default(1e4),
|
|
3355
|
-
forceInstrumental: z.boolean().optional(),
|
|
3356
|
-
modelId: supportedMusicModel.default("music_v1"),
|
|
3357
|
-
format: z.string().optional(),
|
|
3358
|
-
...generatedAudioRequestFields
|
|
3335
|
+
const LatencyPercentilesSchema = z$1.object({
|
|
3336
|
+
p50Ms: z$1.number(),
|
|
3337
|
+
p95Ms: z$1.number(),
|
|
3338
|
+
p99Ms: z$1.number()
|
|
3359
3339
|
});
|
|
3360
|
-
const
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3340
|
+
const PerformanceTelemetrySchema = z$1.object({
|
|
3341
|
+
totalResponseTimeMs: z$1.number(),
|
|
3342
|
+
firstTokenTimeMs: z$1.number().optional(),
|
|
3343
|
+
/**
|
|
3344
|
+
* Elapsed ms until the first chunk of any kind, hidden thinking included. Paired with
|
|
3345
|
+
* firstTokenTimeMs so computeAnomalies can tell a never-rendered turn (streamed, nothing
|
|
3346
|
+
* visible) from one that never streamed at all - see ttfvtState in @bike4mind/common.
|
|
3347
|
+
*/
|
|
3348
|
+
firstChunkTimeMs: z$1.number().optional(),
|
|
3349
|
+
contextRetrievalMs: z$1.number().optional(),
|
|
3350
|
+
modelInferenceMs: z$1.number().optional(),
|
|
3351
|
+
toolExecutionMs: z$1.number().optional(),
|
|
3352
|
+
/** Latency percentiles for trend analysis */
|
|
3353
|
+
latencyPercentiles: LatencyPercentilesSchema.optional()
|
|
3354
|
+
});
|
|
3355
|
+
const AnomalySeveritySchema = z$1.enum([
|
|
3356
|
+
"critical",
|
|
3357
|
+
"high",
|
|
3358
|
+
"medium",
|
|
3359
|
+
"low"
|
|
3369
3360
|
]);
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
/**
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
/**
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3361
|
+
const PrimaryAnomalySchema = z$1.enum([
|
|
3362
|
+
"none",
|
|
3363
|
+
"context_overflow",
|
|
3364
|
+
"high_utilization",
|
|
3365
|
+
"high_truncation",
|
|
3366
|
+
"tool_failure",
|
|
3367
|
+
"subagent_timeout",
|
|
3368
|
+
"slow_response",
|
|
3369
|
+
"multiple"
|
|
3370
|
+
]);
|
|
3371
|
+
const AnomaliesTelemetrySchema = z$1.object({
|
|
3372
|
+
contextOverflow: z$1.boolean(),
|
|
3373
|
+
/** >= 90% */
|
|
3374
|
+
highUtilization: z$1.boolean(),
|
|
3375
|
+
/** >= 95% */
|
|
3376
|
+
criticalUtilization: z$1.boolean(),
|
|
3377
|
+
/** >= 50% */
|
|
3378
|
+
highTruncation: z$1.boolean(),
|
|
3379
|
+
/** >= 75% */
|
|
3380
|
+
criticalTruncation: z$1.boolean(),
|
|
3381
|
+
/** >= 3 failures */
|
|
3382
|
+
toolFailureSpike: z$1.boolean(),
|
|
3383
|
+
/** > 30s */
|
|
3384
|
+
toolTimeout: z$1.boolean(),
|
|
3385
|
+
/** > 5min */
|
|
3386
|
+
subagentTimeout: z$1.boolean(),
|
|
3387
|
+
/** > 10s */
|
|
3388
|
+
slowFirstToken: z$1.boolean(),
|
|
3389
|
+
/** > 60s */
|
|
3390
|
+
slowTotalResponse: z$1.boolean(),
|
|
3391
|
+
/** 0-100 */
|
|
3392
|
+
anomalyScore: z$1.number().min(0).max(100),
|
|
3393
|
+
/** Severity mapping */
|
|
3394
|
+
severity: AnomalySeveritySchema,
|
|
3395
|
+
/** Pattern-based dedup key, e.g., "tool_failure_claude-3-5-sonnet_delegate-to-agent" */
|
|
3396
|
+
dedupKey: z$1.string(),
|
|
3397
|
+
primaryAnomaly: PrimaryAnomalySchema
|
|
3397
3398
|
});
|
|
3398
|
-
z$1.object({
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
"queued",
|
|
3404
|
-
"in_progress",
|
|
3405
|
-
"completed",
|
|
3406
|
-
"failed"
|
|
3399
|
+
const RequestMetadataSchema = z$1.object({
|
|
3400
|
+
queryComplexity: z$1.enum([
|
|
3401
|
+
"simple",
|
|
3402
|
+
"contextual",
|
|
3403
|
+
"complex"
|
|
3407
3404
|
]),
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3405
|
+
historyMessageCount: z$1.number(),
|
|
3406
|
+
attachedFileCount: z$1.number(),
|
|
3407
|
+
mementoCount: z$1.number(),
|
|
3408
|
+
enabledFeatures: z$1.array(z$1.string())
|
|
3409
|
+
});
|
|
3410
|
+
const ContextWindowTelemetryWithOptionalSourceSchema = z$1.object({
|
|
3411
|
+
/** gen_ai.usage.input_tokens */
|
|
3412
|
+
inputTokens: z$1.number(),
|
|
3413
|
+
/** gen_ai.usage.output_tokens */
|
|
3414
|
+
outputTokens: z$1.number(),
|
|
3415
|
+
contextWindowLimit: z$1.number(),
|
|
3416
|
+
utilizationPercentage: z$1.number(),
|
|
3417
|
+
reservedOutputTokens: z$1.number(),
|
|
3418
|
+
overflowDetected: z$1.boolean(),
|
|
3419
|
+
overflowAmount: z$1.number().optional(),
|
|
3420
|
+
/** Token breakdown by source (enhanced only) */
|
|
3421
|
+
tokensBySource: TokensBySourceSchema.optional()
|
|
3422
|
+
});
|
|
3423
|
+
const ContextTelemetrySchema = z$1.object({
|
|
3424
|
+
schemaVersion: z$1.enum([
|
|
3425
|
+
"1.0",
|
|
3426
|
+
"1.1",
|
|
3427
|
+
"1.2"
|
|
3428
|
+
]),
|
|
3429
|
+
/** ISO 8601 */
|
|
3430
|
+
timestamp: z$1.string(),
|
|
3431
|
+
/** Self-monitoring: time to capture telemetry */
|
|
3432
|
+
captureOverheadMs: z$1.number(),
|
|
3433
|
+
/** Capture level: basic or enhanced */
|
|
3434
|
+
captureLevel: z$1.enum(["basic", "enhanced"]).optional(),
|
|
3435
|
+
anonymousSessionId: AnonymousSessionIdSchema,
|
|
3436
|
+
spanContext: SpanContextSchema.optional(),
|
|
3437
|
+
operation: OperationSchema,
|
|
3438
|
+
model: ModelTelemetrySchema,
|
|
3439
|
+
systemPrompts: SystemPromptsTelemetrySchema.optional(),
|
|
3440
|
+
features: FeaturesTelemetrySchema.optional(),
|
|
3441
|
+
contextWindow: ContextWindowTelemetryWithOptionalSourceSchema,
|
|
3442
|
+
cache: CacheTelemetrySchema.optional(),
|
|
3443
|
+
costs: CostsTelemetrySchema,
|
|
3444
|
+
truncation: TruncationTelemetrySchema.optional(),
|
|
3445
|
+
tools: z$1.array(ToolTelemetrySchema).optional(),
|
|
3446
|
+
subagents: z$1.array(SubagentTelemetrySchema).optional(),
|
|
3447
|
+
performance: PerformanceTelemetrySchema,
|
|
3448
|
+
anomalies: AnomaliesTelemetrySchema,
|
|
3449
|
+
requestMetadata: RequestMetadataSchema.optional(),
|
|
3450
|
+
captureErrors: z$1.array(z$1.string()).optional()
|
|
3415
3451
|
});
|
|
3416
3452
|
z$1.object({
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
resolution: z$1.string().optional()
|
|
3453
|
+
avgResponseTimeMs: z$1.number(),
|
|
3454
|
+
p95ResponseTimeMs: z$1.number(),
|
|
3455
|
+
avgUtilization: z$1.number(),
|
|
3456
|
+
utilizationRange: z$1.object({
|
|
3457
|
+
low: z$1.number(),
|
|
3458
|
+
high: z$1.number()
|
|
3459
|
+
}),
|
|
3460
|
+
sampleCount: z$1.number(),
|
|
3461
|
+
windowDays: z$1.number()
|
|
3427
3462
|
});
|
|
3463
|
+
z$1.enum([
|
|
3464
|
+
"no_action",
|
|
3465
|
+
"monitor",
|
|
3466
|
+
"investigate_soon",
|
|
3467
|
+
"immediate_action"
|
|
3468
|
+
]);
|
|
3428
3469
|
/**
|
|
3429
|
-
*
|
|
3470
|
+
* Request schema for POST /api/chat - the simplified external chat surface.
|
|
3471
|
+
*
|
|
3472
|
+
* Shared between the Next.js API handler (apps/client/pages/api/chat.ts, which
|
|
3473
|
+
* validates req.body with this exact object) and the OpenAPI registry
|
|
3474
|
+
* (b4m-core/common/src/openapi), so the published contract cannot drift from
|
|
3475
|
+
* what the handler actually accepts. The model is optional here and resolved
|
|
3476
|
+
* server-side from admin settings when omitted.
|
|
3477
|
+
*
|
|
3478
|
+
* Public-API rule: no `.catch()` / top-level `.transform()`. Both silently mutate
|
|
3479
|
+
* caller input (fail-quiet) and are opaque to zod-to-openapi. `historyCount` uses
|
|
3480
|
+
* `.default()` (fail loud on a bad value); unknown tool ids are filtered in the
|
|
3481
|
+
* handler (see filterKnownTools) instead of by a schema transform. This keeps the
|
|
3482
|
+
* schema fully OpenAPI-representable with no doc projection needed.
|
|
3430
3483
|
*/
|
|
3431
|
-
const
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3484
|
+
const SimplifiedChatRequestSchema = z$1.object({
|
|
3485
|
+
sessionId: z$1.string().nullish(),
|
|
3486
|
+
newConversation: z$1.boolean().optional(),
|
|
3487
|
+
message: z$1.string(),
|
|
3488
|
+
organizationId: z$1.string().optional(),
|
|
3489
|
+
model: z$1.string().optional(),
|
|
3490
|
+
temperature: z$1.number().min(0).max(2).optional(),
|
|
3491
|
+
max_tokens: z$1.number().positive().optional(),
|
|
3492
|
+
maxTokens: z$1.number().positive().optional(),
|
|
3493
|
+
maxOutputTokens: z$1.number().positive().optional(),
|
|
3494
|
+
stream: z$1.boolean().prefault(false),
|
|
3495
|
+
historyCount: z$1.number().positive().default(10),
|
|
3496
|
+
fileIds: z$1.array(z$1.string()).prefault([]),
|
|
3497
|
+
wait: z$1.boolean().prefault(false),
|
|
3498
|
+
enableTools: z$1.boolean().prefault(false),
|
|
3499
|
+
toolMode: z$1.enum(["fast", "smart"]).optional(),
|
|
3500
|
+
tools: z$1.array(z$1.string()).optional().describe("Explicit tool ids to offer the model. A non-empty array enables tools on its own; no companion `toolMode` or `enableTools` is required. Merged with the auto-selected set under `toolMode: \"smart\"`, and ignored under `toolMode: \"fast\"`. This list ADDS to what is offered rather than restricting it - the server still offers tools of its own (for example knowledge retrieval when the session has reachable documents). Unrecognized ids are dropped rather than rejecting the request; the response reports the surviving set as `tools.effectiveTools` and the ids that are not tools in this deployment as `tools.unrecognizedTools`, since no endpoint enumerates the valid ids. `unrecognizedTools` is reported under every `toolMode` - it describes the ids, not what the mode did with them - so under `toolMode: \"fast\"` an id can be absent from `effectiveTools` (the mode discarded it) without being unrecognized. Both reported lists are deduplicated, and `unrecognizedTools` names at most the first 10 distinct ids."),
|
|
3501
|
+
enableQuestMaster: z$1.boolean().optional(),
|
|
3502
|
+
enableMementos: z$1.boolean().optional(),
|
|
3503
|
+
enableAgents: z$1.boolean().optional(),
|
|
3504
|
+
promptMode: z$1.enum([
|
|
3505
|
+
"raw",
|
|
3506
|
+
"grounded",
|
|
3507
|
+
"surface"
|
|
3508
|
+
]).optional(),
|
|
3509
|
+
skip_auto_offers: z$1.boolean().optional().describe("Suppress tools the server would otherwise attach on its own for this session (the knowledge-base search offer, in-app view navigation, blog drafting/editing/publishing, skill invocation, and every tool from a connected MCP server). Native tools you request explicitly in `tools` are unaffected, but an MCP server tool cannot be named through this field, so with this flag set a caller with an MCP server connected sees none of its tools regardless of `tools`. One system-prompt block goes with them: withholding in-app view navigation also drops the view-registry block that exists only to describe it. No other prompt content changes. This does not switch off retrieval: a session with forced knowledge retrieval still retrieves, and documents already attached to the session are still placed in the prompt directly. Any promptMode suppresses these too, so false has no effect alongside one."),
|
|
3510
|
+
includePromptDetails: z$1.boolean().optional(),
|
|
3511
|
+
includeSystemPrompt: z$1.boolean().optional(),
|
|
3512
|
+
systemPrompt: z$1.string().max(PROMPT_TEXT_MAX).optional().describe("System-prompt text for this request only, never persisted. Rendered as a defended block appended after every other system-prompt source, with prose instructing the model to defer to organization, session and data-lake guidance. Over the cap is a 422, never truncated.")
|
|
3451
3513
|
});
|
|
3452
|
-
GenerateVideoRequestBodySchema.extend({ sessionId: z$1.string() });
|
|
3453
3514
|
/**
|
|
3454
|
-
*
|
|
3455
|
-
*
|
|
3456
|
-
*
|
|
3457
|
-
*
|
|
3458
|
-
*
|
|
3515
|
+
* Async ACK returned on the default (wait:false) path of POST /api/chat. The
|
|
3516
|
+
* `type`/`errorCode` pair below is the same classifier the `wait: true` body and
|
|
3517
|
+
* the polled quest (`GET /api/v1/quests/{id}`) carry, so it is modelled once here.
|
|
3518
|
+
* The rest of the `wait: true` body is ChatWaitResponseSchema below. The
|
|
3519
|
+
* handler assembles the ack body inline (apps/client/pages/api/chat.ts), so
|
|
3520
|
+
* this schema MUST stay in sync with that `res.json({...})` shape.
|
|
3459
3521
|
*/
|
|
3460
|
-
const
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
]
|
|
3522
|
+
const ChatAckSchema = z$1.object({
|
|
3523
|
+
id: z$1.string(),
|
|
3524
|
+
status: z$1.string(),
|
|
3525
|
+
message_received: z$1.boolean(),
|
|
3526
|
+
timestamp: z$1.string(),
|
|
3527
|
+
model: z$1.string(),
|
|
3528
|
+
sessionId: z$1.string().optional(),
|
|
3529
|
+
message: z$1.string().optional(),
|
|
3530
|
+
type: z$1.enum(CHAT_HISTORY_ITEM_TYPES).optional(),
|
|
3531
|
+
errorCode: z$1.enum(QUEST_ERROR_CODES).optional(),
|
|
3532
|
+
tools: z$1.object({
|
|
3533
|
+
toolMode: z$1.enum(["fast", "smart"]).optional(),
|
|
3534
|
+
autoSelectedTools: z$1.array(z$1.string()).optional(),
|
|
3535
|
+
effectiveTools: z$1.array(z$1.string()),
|
|
3536
|
+
unrecognizedTools: z$1.array(z$1.string()).optional()
|
|
3537
|
+
}).optional(),
|
|
3538
|
+
tracking_info: z$1.object({
|
|
3539
|
+
quest_id: z$1.string(),
|
|
3540
|
+
check_status_url: z$1.string(),
|
|
3541
|
+
poll_url: z$1.string().optional()
|
|
3542
|
+
})
|
|
3543
|
+
});
|
|
3544
|
+
const ToolPayloadSchema = z$1.object({
|
|
3545
|
+
type: z$1.string(),
|
|
3546
|
+
payload: z$1.unknown()
|
|
3547
|
+
});
|
|
3472
3548
|
/**
|
|
3473
|
-
*
|
|
3474
|
-
*
|
|
3475
|
-
*
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3549
|
+
* The completed-turn body POST /api/chat returns with `wait: true`. Like the ACK it is
|
|
3550
|
+
* assembled inline in apps/client/pages/api/chat.ts and MUST stay in sync with that
|
|
3551
|
+
* `res.json({...})` shape.
|
|
3552
|
+
*/
|
|
3553
|
+
const ChatWaitResponseSchema = ChatAckSchema.extend({
|
|
3554
|
+
type: z$1.enum(CHAT_HISTORY_ITEM_TYPES),
|
|
3555
|
+
response: z$1.string().nullable(),
|
|
3556
|
+
responses: z$1.array(z$1.string()),
|
|
3557
|
+
toolPayloads: z$1.array(ToolPayloadSchema),
|
|
3558
|
+
createdAt: z$1.union([z$1.string().datetime(), z$1.date()]),
|
|
3559
|
+
promptDetails: z$1.array(SystemPromptDetailSchema).optional(),
|
|
3560
|
+
promptText: z$1.string().optional(),
|
|
3561
|
+
performance: z$1.object({
|
|
3562
|
+
total_ms: z$1.number(),
|
|
3563
|
+
phases: z$1.record(z$1.string(), z$1.number()),
|
|
3564
|
+
pipeline_phases: z$1.record(z$1.string(), z$1.number()).optional()
|
|
3565
|
+
})
|
|
3566
|
+
});
|
|
3567
|
+
/**
|
|
3568
|
+
* The quest a `wait: false` caller polls at `GET /api/v1/quests/{id}` - the outcome
|
|
3569
|
+
* of the turn the ACK above only acknowledged.
|
|
3480
3570
|
*
|
|
3481
|
-
*
|
|
3482
|
-
*
|
|
3483
|
-
*
|
|
3484
|
-
*
|
|
3485
|
-
* document. It is typed by SummarizationDecision there, not by the session field.
|
|
3571
|
+
* Deliberately the OUTCOME SUBSET, not the whole quest: it models only what decides
|
|
3572
|
+
* whether the turn succeeded. The full response of that endpoint is
|
|
3573
|
+
* QuestPollResponseSchema (schemas/quest.ts), which extends this schema and is
|
|
3574
|
+
* the 200 body of the `getQuest` contract.
|
|
3486
3575
|
*
|
|
3487
|
-
*
|
|
3488
|
-
*
|
|
3489
|
-
*
|
|
3490
|
-
*
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
*
|
|
3494
|
-
*
|
|
3495
|
-
* so 'throttling' cannot be published, cannot be stored, and therefore cannot reach a copy path.
|
|
3496
|
-
* Add a new reason-it-happened here, not to SESSION_SUMMARY_TRIGGERS, and every one of those
|
|
3497
|
-
* boundaries picks it up.
|
|
3576
|
+
* A failed turn is still `status: 'done'` with the failure text in `reply`, so
|
|
3577
|
+
* `reply` alone cannot tell an answer from a failure - `type` and `errorCode` are
|
|
3578
|
+
* what separate a CLASSIFIED failure. A run that died with partial content is not
|
|
3579
|
+
* one of those: `terminalRecoveryFor` (questTimeoutRecovery.ts) keeps the surviving
|
|
3580
|
+
* content, so it polls back as `type: 'message'`. What marks it unfinished is
|
|
3581
|
+
* `promptMeta.finishReason` - RUN_TIMED_OUT_FINISH_REASON or
|
|
3582
|
+
* RUN_ABANDONED_FINISH_REASON (utils/stopReasons.ts) - plus a notice appended to
|
|
3583
|
+
* the reply.
|
|
3498
3584
|
*/
|
|
3499
|
-
const
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3585
|
+
const PolledFallbackInfoSchema = FallbackInfoSchema.pick({
|
|
3586
|
+
primaryModel: true,
|
|
3587
|
+
primaryModelName: true,
|
|
3588
|
+
fallbackModel: true,
|
|
3589
|
+
fallbackModelName: true,
|
|
3590
|
+
reason: true
|
|
3591
|
+
});
|
|
3592
|
+
const ChatQuestPollResultSchema = z$1.object({
|
|
3593
|
+
id: z$1.string(),
|
|
3594
|
+
status: z$1.enum([
|
|
3595
|
+
"pending",
|
|
3596
|
+
"stopped",
|
|
3597
|
+
"running",
|
|
3598
|
+
"done"
|
|
3599
|
+
]).optional(),
|
|
3600
|
+
type: z$1.enum(CHAT_HISTORY_ITEM_TYPES).optional(),
|
|
3601
|
+
errorCode: z$1.enum(QUEST_ERROR_CODES).optional(),
|
|
3602
|
+
reply: z$1.string().nullable().optional(),
|
|
3603
|
+
replies: z$1.array(z$1.string()).optional(),
|
|
3604
|
+
fallbackInfo: PolledFallbackInfoSchema.optional()
|
|
3605
|
+
});
|
|
3507
3606
|
/**
|
|
3508
|
-
*
|
|
3509
|
-
*
|
|
3510
|
-
* The WS data-subscribe handler forwards that filter to `Model.find` and persists it on the
|
|
3511
|
-
* QuerySubscription the separate subscriber-fanout service replays, so an unconstrained
|
|
3512
|
-
* `$`-prefixed key lets any authenticated socket ask the database to run server-side JavaScript
|
|
3513
|
-
* (`$where`, `$expr` + `$function`) or an unbounded `$regex` - either of which pins a pooled
|
|
3514
|
-
* connection for as long as it runs.
|
|
3607
|
+
* Reusable JSON error envelope (plain; the OpenAPI layer annotates it).
|
|
3515
3608
|
*
|
|
3516
|
-
*
|
|
3517
|
-
*
|
|
3518
|
-
*
|
|
3609
|
+
* Must stay in sync with the published `ErrorResponse` component
|
|
3610
|
+
* (../openapi/schemas.ts) - `openapi/errorEnvelopeParity.test.ts` pins the two
|
|
3611
|
+
* together, and apps/client's errorHandler test uses this shape as the stand-in for
|
|
3612
|
+
* the component, which is generate-time only and cannot be imported at runtime.
|
|
3613
|
+
*/
|
|
3614
|
+
const ApiErrorSchema = z$1.object({
|
|
3615
|
+
error: z$1.string(),
|
|
3616
|
+
request_id: z$1.string().optional(),
|
|
3617
|
+
/**
|
|
3618
|
+
* Deprecated, sunset 2026-12-01. The `name` of whatever was thrown - our own error
|
|
3619
|
+
* classes usually, a library/driver class name on an unhandled 500 - added to every
|
|
3620
|
+
* body by apps/client's errorHandler. Documented here so the runtime and the spec
|
|
3621
|
+
* agree while it is still served; do not build on it. See CONVENTIONS.md section 1.
|
|
3622
|
+
*/
|
|
3623
|
+
name: z$1.string().optional()
|
|
3624
|
+
});
|
|
3625
|
+
/**
|
|
3626
|
+
* Error envelope for the 422 a credit-metered endpoint returns for two unrelated
|
|
3627
|
+
* reasons: "your body is invalid" and "you cannot afford this". `errorCode` is
|
|
3628
|
+
* what separates them - `insufficientCreditsError` (see insufficientCredits.ts)
|
|
3629
|
+
* tags the credit case, so its absence means an ordinary validation failure.
|
|
3519
3630
|
*
|
|
3520
|
-
*
|
|
3521
|
-
*
|
|
3522
|
-
*
|
|
3523
|
-
*
|
|
3631
|
+
* Derived from `ApiErrorSchema` rather than re-declaring `error`/`request_id`:
|
|
3632
|
+
* both of those 422s are *thrown*, so errorHandler serves the body and adds
|
|
3633
|
+
* `name`. Extending is what keeps that documented here (and what drops it again
|
|
3634
|
+
* on the sunset date) instead of leaving a bespoke copy behind to drift.
|
|
3524
3635
|
*/
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
"$or",
|
|
3529
|
-
"$nor",
|
|
3530
|
-
"$not"
|
|
3531
|
-
];
|
|
3532
|
-
/** Value-level operators a subscription filter may use. */
|
|
3533
|
-
const SUBSCRIPTION_FILTER_VALUE_OPERATORS = [
|
|
3534
|
-
"$eq",
|
|
3535
|
-
"$ne",
|
|
3536
|
-
"$gt",
|
|
3537
|
-
"$gte",
|
|
3538
|
-
"$lt",
|
|
3539
|
-
"$lte",
|
|
3540
|
-
"$in",
|
|
3541
|
-
"$nin",
|
|
3542
|
-
"$exists",
|
|
3543
|
-
"$type",
|
|
3544
|
-
"$size",
|
|
3545
|
-
"$all",
|
|
3546
|
-
"$elemMatch"
|
|
3547
|
-
];
|
|
3548
|
-
const ALLOWED_OPERATORS = /* @__PURE__ */ new Set([...SUBSCRIPTION_FILTER_LOGICAL_OPERATORS, ...SUBSCRIPTION_FILTER_VALUE_OPERATORS]);
|
|
3636
|
+
const InsufficientCreditsErrorSchema = ApiErrorSchema.extend({ errorCode: z$1.literal("insufficient_credits").optional() });
|
|
3637
|
+
/** 503 when this deployment has no usable key for a provider the request needs (data-lake search, voice). */
|
|
3638
|
+
const ProviderNotConfiguredErrorSchema = ApiErrorSchema.extend({ errorCode: z$1.literal("provider_not_configured").optional() });
|
|
3549
3639
|
/**
|
|
3550
|
-
*
|
|
3551
|
-
*
|
|
3552
|
-
*
|
|
3640
|
+
* Error envelope for the 403 apiKeyAuth (apps/client/server/middlewares/apiKeyAuth.ts)
|
|
3641
|
+
* throws when an API key lacks a route's scopes. It names what the ROUTE requires,
|
|
3642
|
+
* never what the key holds, so a caller knows which scope to mint a key with.
|
|
3643
|
+
* Values are `ApiKeyScope` strings; plain `z.string()` because the enum's module is
|
|
3644
|
+
* not import-safe for the install-only openapi job (see the import note above).
|
|
3553
3645
|
*/
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
if (depth > 12) {
|
|
3558
|
-
violations.push(`${path} (nested deeper than 12)`);
|
|
3559
|
-
return;
|
|
3560
|
-
}
|
|
3561
|
-
if (node instanceof RegExp) {
|
|
3562
|
-
violations.push(`${path} (regular expression)`);
|
|
3563
|
-
return;
|
|
3564
|
-
}
|
|
3565
|
-
if (Array.isArray(node)) {
|
|
3566
|
-
node.forEach((entry, i) => walk(entry, `${path}[${i}]`, depth + 1));
|
|
3567
|
-
return;
|
|
3568
|
-
}
|
|
3569
|
-
if (node === null || typeof node !== "object") return;
|
|
3570
|
-
for (const [key, value] of Object.entries(node)) {
|
|
3571
|
-
const childPath = path ? `${path}.${key}` : key;
|
|
3572
|
-
if (key.startsWith("$") && !ALLOWED_OPERATORS.has(key)) {
|
|
3573
|
-
violations.push(childPath);
|
|
3574
|
-
continue;
|
|
3575
|
-
}
|
|
3576
|
-
walk(value, childPath, depth + 1);
|
|
3577
|
-
}
|
|
3578
|
-
};
|
|
3579
|
-
walk(filter, "", 0);
|
|
3580
|
-
return violations;
|
|
3581
|
-
}
|
|
3582
|
-
const DataSubscribeRequestAction = z$1.object({
|
|
3583
|
-
action: z$1.literal("subscribe_query"),
|
|
3584
|
-
accessToken: z$1.string().optional(),
|
|
3585
|
-
subscriptionId: z$1.string(),
|
|
3586
|
-
collectionName: z$1.string(),
|
|
3587
|
-
query: z$1.looseObject({}).superRefine((filter, ctx) => {
|
|
3588
|
-
for (const key of findDisallowedSubscriptionFilterKeys(filter)) ctx.addIssue({
|
|
3589
|
-
code: "custom",
|
|
3590
|
-
message: `Disallowed subscription filter: ${key}`
|
|
3591
|
-
});
|
|
3592
|
-
}),
|
|
3593
|
-
fields: z$1.record(z$1.string(), z$1.union([z$1.boolean(), z$1.number()])),
|
|
3594
|
-
fetchInitialData: z$1.boolean().prefault(true).optional(),
|
|
3595
|
-
clientId: z$1.string().optional()
|
|
3596
|
-
});
|
|
3597
|
-
const DataUnsubscribeRequestAction = z$1.object({
|
|
3598
|
-
action: z$1.literal("unsubscribe_query"),
|
|
3599
|
-
accessToken: z$1.string().optional(),
|
|
3600
|
-
subscriptionId: z$1.string()
|
|
3646
|
+
const ScopeForbiddenErrorSchema = ApiErrorSchema.extend({
|
|
3647
|
+
required_scopes: z$1.array(z$1.string()).optional().describe("API key scopes this route accepts. Holding any one of them satisfies it."),
|
|
3648
|
+
also_required_scopes: z$1.array(z$1.string()).optional().describe("API key scopes this route also requires. Every one must be held, on top of `required_scopes`.")
|
|
3601
3649
|
});
|
|
3602
|
-
const
|
|
3603
|
-
const
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3650
|
+
const supportedVoiceGenerationVendor = z.enum(["openai", "elevenlabs"]);
|
|
3651
|
+
const DEFAULT_TTS_PROVIDER = "openai";
|
|
3652
|
+
const voiceOutputFormatSchema = z.enum([
|
|
3653
|
+
"mp3",
|
|
3654
|
+
"wav",
|
|
3655
|
+
"opus",
|
|
3656
|
+
"aac",
|
|
3657
|
+
"flac",
|
|
3658
|
+
"pcm"
|
|
3659
|
+
]);
|
|
3660
|
+
const TTS_ABSOLUTE_MAX_INPUT_CHARS = Math.max(...Object.values({
|
|
3661
|
+
openai: 4096,
|
|
3662
|
+
elevenlabs: 1e4
|
|
3663
|
+
}));
|
|
3664
|
+
const ttsLanguageCodeSchema = z.string().regex(/^[a-z]{2}$/, "languageCode must be a lowercase ISO 639-1 code, e.g. \"en\" or \"ja\"");
|
|
3665
|
+
const ttsRequestSchema = z.object({
|
|
3666
|
+
text: z.string().min(1).max(TTS_ABSOLUTE_MAX_INPUT_CHARS),
|
|
3667
|
+
provider: supportedVoiceGenerationVendor.optional(),
|
|
3668
|
+
model: z.string().optional(),
|
|
3669
|
+
voice: z.string().optional(),
|
|
3670
|
+
format: voiceOutputFormatSchema.optional(),
|
|
3671
|
+
stability: z.number().min(0).max(1).optional(),
|
|
3672
|
+
similarityBoost: z.number().min(0).max(1).optional(),
|
|
3673
|
+
languageCode: ttsLanguageCodeSchema.optional(),
|
|
3674
|
+
...generatedAudioRequestFields
|
|
3611
3675
|
});
|
|
3612
3676
|
/**
|
|
3613
|
-
*
|
|
3677
|
+
* JSON body of `POST /api/ai/tts` for `encoding: 'base64'`: the shared generated-audio
|
|
3678
|
+
* body plus the TTS fields. `provider`/`fallbackFrom` appear only when the requested
|
|
3679
|
+
* provider was unavailable and another one stood in.
|
|
3614
3680
|
*/
|
|
3615
|
-
const
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
role: z$1.enum([
|
|
3622
|
-
"user",
|
|
3623
|
-
"assistant",
|
|
3624
|
-
"system"
|
|
3625
|
-
]),
|
|
3626
|
-
content: z$1.union([z$1.string(), z$1.array(z$1.unknown())]),
|
|
3627
|
-
cache: z$1.boolean().optional()
|
|
3628
|
-
})),
|
|
3629
|
-
options: z$1.object({
|
|
3630
|
-
temperature: z$1.number().optional(),
|
|
3631
|
-
maxTokens: z$1.number().optional(),
|
|
3632
|
-
stream: z$1.boolean().optional(),
|
|
3633
|
-
tools: z$1.array(z$1.unknown()).optional(),
|
|
3634
|
-
response_format: z$1.discriminatedUnion("type", [z$1.object({ type: z$1.literal("text") }), z$1.object({
|
|
3635
|
-
type: z$1.literal("json_schema"),
|
|
3636
|
-
json_schema: z$1.object({
|
|
3637
|
-
name: z$1.string(),
|
|
3638
|
-
description: z$1.string().optional(),
|
|
3639
|
-
schema: z$1.record(z$1.string(), z$1.any()),
|
|
3640
|
-
strict: z$1.boolean().optional().default(true)
|
|
3641
|
-
})
|
|
3642
|
-
})]).optional()
|
|
3643
|
-
}).optional()
|
|
3681
|
+
const ttsBase64ResponseSchema = extendGeneratedAudioResponseSchema({
|
|
3682
|
+
format: voiceOutputFormatSchema,
|
|
3683
|
+
/** The provider that actually produced the audio, present only on a fallback. */
|
|
3684
|
+
provider: supportedVoiceGenerationVendor.optional(),
|
|
3685
|
+
/** The originally requested provider that could not serve the request. */
|
|
3686
|
+
fallbackFrom: supportedVoiceGenerationVendor.optional()
|
|
3644
3687
|
});
|
|
3645
3688
|
/**
|
|
3646
|
-
*
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
})
|
|
3689
|
+
* Error body for `POST /api/ai/tts`, shared by the 401, 422, 429 and 502; the 413
|
|
3690
|
+
* has a shape of its own (`ttsResponseTooLargeSchema`). `errorCode` is present only
|
|
3691
|
+
* on the conditions that carry a classifier; an ordinary validation 422 has none.
|
|
3692
|
+
*
|
|
3693
|
+
* Extends `ApiErrorSchema` because what decides whether a body carries the fields
|
|
3694
|
+
* errorHandler adds - `request_id`, and `name` until its 2026-12-01 sunset - is
|
|
3695
|
+
* whether the body was THROWN, not which status it wears, and three of these four
|
|
3696
|
+
* statuses are reachable both ways:
|
|
3697
|
+
*
|
|
3698
|
+
* - 401: thrown by apiKeyAuth on a rejected key; written by `auth` when no
|
|
3699
|
+
* credential was presented at all, and by the handler for
|
|
3700
|
+
* `provider_not_configured` and for an upstream credential rejection
|
|
3701
|
+
* (`provider_rejected`, from an upstream 401 or 403).
|
|
3702
|
+
* - 422: thrown by request validation and by the char-limit / format guards;
|
|
3703
|
+
* written by the handler for `insufficient_credits` and for every upstream 4xx
|
|
3704
|
+
* that is neither a credential rejection nor a 429.
|
|
3705
|
+
* - 429: thrown by apiKeyRateLimit; written by the handler on an upstream 429.
|
|
3706
|
+
* - 502: only ever written.
|
|
3707
|
+
*
|
|
3708
|
+
* So those two are genuinely optional here, and splitting this per status would be
|
|
3709
|
+
* wrong for the first three. The 502 does advertise both without ever sending them;
|
|
3710
|
+
* that is not worth a fourth error schema on one route, and `request_id` missing from
|
|
3711
|
+
* this handler's written bodies is a gap in the handler rather than something to
|
|
3712
|
+
* enshrine in a schema.
|
|
3713
|
+
*/
|
|
3714
|
+
const ttsErrorResponseSchema = ApiErrorSchema.extend({
|
|
3715
|
+
provider: supportedVoiceGenerationVendor.optional(),
|
|
3716
|
+
errorCode: z.enum([
|
|
3717
|
+
"insufficient_credits",
|
|
3718
|
+
"provider_not_configured",
|
|
3719
|
+
"provider_rejected"
|
|
3720
|
+
]).optional()
|
|
3679
3721
|
});
|
|
3680
3722
|
/**
|
|
3681
|
-
*
|
|
3682
|
-
*
|
|
3683
|
-
*
|
|
3684
|
-
*
|
|
3723
|
+
* TTS 413 body: `generatedAudioTooLargeSchema` plus the provider. The handler never
|
|
3724
|
+
* sends the `saved`/`fabFileId`/`fileUrl` fields (a saved copy's `fileUrl` is now
|
|
3725
|
+
* served as the oversized-audio URL); they stay so a client still parses a server
|
|
3726
|
+
* that predates the offload.
|
|
3727
|
+
*
|
|
3728
|
+
* Not derived from `ApiErrorSchema`: every 413 on this route is written, never
|
|
3729
|
+
* thrown, so `name` is genuinely absent rather than optional - a stronger claim than
|
|
3730
|
+
* `ttsErrorResponseSchema` can make for its own statuses, see the note there (a
|
|
3731
|
+
* provider 413 is folded onto a 422 by documentedStatusForUpstream4xx). An oversized
|
|
3732
|
+
* *request* body is another 413 that never reaches this schema at all - Next's own
|
|
3733
|
+
* body parser answers it in plain text before the router runs.
|
|
3685
3734
|
*/
|
|
3686
|
-
const
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
const LLMStatusUpdateAction = z$1.object({
|
|
3692
|
-
action: z$1.literal("llm_status_update"),
|
|
3693
|
-
status: z$1.string().nullable(),
|
|
3694
|
-
clientId: z$1.string().optional()
|
|
3695
|
-
});
|
|
3696
|
-
const InboxRefetchAction = z$1.object({
|
|
3697
|
-
action: z$1.literal("inbox_refetch"),
|
|
3698
|
-
status: z$1.string(),
|
|
3699
|
-
clientId: z$1.string().optional()
|
|
3700
|
-
});
|
|
3701
|
-
const InvitesRefetchAction = z$1.object({
|
|
3702
|
-
action: z$1.literal("invites_refetch"),
|
|
3703
|
-
status: z$1.string(),
|
|
3704
|
-
clientId: z$1.string().optional()
|
|
3705
|
-
});
|
|
3706
|
-
const UpdateCurrentUserAction = z$1.object({
|
|
3707
|
-
action: z$1.literal("update_current_user"),
|
|
3708
|
-
clientId: z$1.string().optional(),
|
|
3709
|
-
user: z$1.object({
|
|
3710
|
-
id: z$1.string(),
|
|
3711
|
-
username: z$1.string(),
|
|
3712
|
-
name: z$1.string(),
|
|
3713
|
-
email: z$1.string(),
|
|
3714
|
-
groups: z$1.array(z$1.string()),
|
|
3715
|
-
isAdmin: z$1.boolean(),
|
|
3716
|
-
storageLimit: z$1.number(),
|
|
3717
|
-
currentStorageSize: z$1.number()
|
|
3718
|
-
}).partial()
|
|
3719
|
-
});
|
|
3720
|
-
const ResearchTaskStatusUpdateAction = z$1.object({
|
|
3721
|
-
action: z$1.literal("research_task_status_update"),
|
|
3722
|
-
taskId: z$1.string(),
|
|
3723
|
-
status: z$1.string(),
|
|
3724
|
-
currentStep: z$1.string(),
|
|
3725
|
-
progress: z$1.number()
|
|
3726
|
-
});
|
|
3727
|
-
const NotebookCurationProgressUpdateAction = z$1.object({
|
|
3728
|
-
action: z$1.literal("notebook_curation_progress"),
|
|
3729
|
-
curationJobId: z$1.string(),
|
|
3730
|
-
sessionId: z$1.string(),
|
|
3731
|
-
status: z$1.enum([
|
|
3732
|
-
"pending",
|
|
3733
|
-
"loading",
|
|
3734
|
-
"extracting",
|
|
3735
|
-
"generating",
|
|
3736
|
-
"storing",
|
|
3737
|
-
"completed",
|
|
3738
|
-
"failed"
|
|
3739
|
-
]),
|
|
3740
|
-
stage: z$1.enum([
|
|
3741
|
-
"loading",
|
|
3742
|
-
"extracting",
|
|
3743
|
-
"generating",
|
|
3744
|
-
"storing"
|
|
3745
|
-
]).optional(),
|
|
3746
|
-
percentage: z$1.number(),
|
|
3747
|
-
message: z$1.string().optional(),
|
|
3748
|
-
messagesProcessed: z$1.number().optional(),
|
|
3749
|
-
totalMessages: z$1.number().optional(),
|
|
3750
|
-
artifactsFound: z$1.number().optional(),
|
|
3751
|
-
curatedFileId: z$1.string().optional(),
|
|
3752
|
-
errorMessage: z$1.string().optional(),
|
|
3753
|
-
tokensDeducted: z$1.number().optional(),
|
|
3754
|
-
clientId: z$1.string().optional()
|
|
3755
|
-
});
|
|
3756
|
-
const QuestExportProgressAction = z$1.object({
|
|
3757
|
-
action: z$1.literal("quest_export_progress"),
|
|
3758
|
-
exportJobId: z$1.string(),
|
|
3759
|
-
planId: z$1.string(),
|
|
3760
|
-
status: z$1.enum([
|
|
3761
|
-
"assembling",
|
|
3762
|
-
"downloading_images",
|
|
3763
|
-
"summarizing",
|
|
3764
|
-
"zipping",
|
|
3765
|
-
"completed",
|
|
3766
|
-
"failed"
|
|
3767
|
-
]),
|
|
3768
|
-
progress: z$1.number(),
|
|
3769
|
-
detail: z$1.string().optional(),
|
|
3770
|
-
downloadUrl: z$1.string().optional(),
|
|
3771
|
-
filename: z$1.string().optional(),
|
|
3772
|
-
errorMessage: z$1.string().optional(),
|
|
3773
|
-
droppedQuestCount: z$1.number().optional(),
|
|
3774
|
-
clientId: z$1.string().optional()
|
|
3775
|
-
});
|
|
3776
|
-
const OrgFeedbackSummaryProgressAction = z$1.object({
|
|
3777
|
-
action: z$1.literal("org_feedback_summary_progress"),
|
|
3778
|
-
summaryJobId: z$1.string(),
|
|
3779
|
-
organizationId: z$1.string(),
|
|
3780
|
-
status: z$1.enum([
|
|
3781
|
-
"processing",
|
|
3782
|
-
"completed",
|
|
3783
|
-
"failed"
|
|
3784
|
-
]),
|
|
3785
|
-
progress: z$1.number(),
|
|
3786
|
-
errorMessage: z$1.string().optional(),
|
|
3787
|
-
clientId: z$1.string().optional()
|
|
3735
|
+
const ttsResponseTooLargeSchema = generatedAudioTooLargeSchema.extend({
|
|
3736
|
+
provider: supportedVoiceGenerationVendor,
|
|
3737
|
+
saved: z.literal(true).optional(),
|
|
3738
|
+
fabFileId: z.string().optional(),
|
|
3739
|
+
fileUrl: z.string().optional()
|
|
3788
3740
|
});
|
|
3789
|
-
const
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3741
|
+
const VIDEO_MODES = ["text_to_video", "image_to_video"];
|
|
3742
|
+
const ASPECT_RATIOS = [
|
|
3743
|
+
"16:9",
|
|
3744
|
+
"9:16",
|
|
3745
|
+
"1:1",
|
|
3746
|
+
"4:3",
|
|
3747
|
+
"3:4",
|
|
3748
|
+
"3:2",
|
|
3749
|
+
"2:3",
|
|
3750
|
+
"21:9"
|
|
3751
|
+
];
|
|
3752
|
+
const RESOLUTION_TIERS = [
|
|
3753
|
+
"360p",
|
|
3754
|
+
"480p",
|
|
3755
|
+
"720p",
|
|
3756
|
+
"1080p",
|
|
3757
|
+
"4k"
|
|
3758
|
+
];
|
|
3759
|
+
const VideoModelIdSchema = z$1.enum([
|
|
3760
|
+
"test-video",
|
|
3761
|
+
"gemini-omni-1.1-flash",
|
|
3762
|
+
"grok-imagine-video-1.5",
|
|
3763
|
+
"veo-3.1-fast-generate-preview"
|
|
3764
|
+
]);
|
|
3765
|
+
z$1.object({
|
|
3766
|
+
model: VideoModelIdSchema,
|
|
3767
|
+
mode: z$1.enum(VIDEO_MODES),
|
|
3768
|
+
prompt: z$1.string().trim().min(1).max(4e3),
|
|
3769
|
+
durationSeconds: z$1.number().positive(),
|
|
3770
|
+
aspectRatio: z$1.enum(ASPECT_RATIOS),
|
|
3771
|
+
resolution: z$1.enum(RESOLUTION_TIERS),
|
|
3772
|
+
inputImageFileId: z$1.string().min(1).optional(),
|
|
3773
|
+
inputGeneratedImageKey: z$1.string().min(1).optional(),
|
|
3774
|
+
audio: z$1.boolean().optional()
|
|
3775
|
+
});
|
|
3776
|
+
const VIDEO_VALIDATION_ERROR_CODES = [
|
|
3777
|
+
"unsupported_duration",
|
|
3778
|
+
"unsupported_aspect_ratio",
|
|
3779
|
+
"unsupported_resolution",
|
|
3780
|
+
"unsupported_mode",
|
|
3781
|
+
"missing_input_image",
|
|
3782
|
+
"unexpected_input_image",
|
|
3783
|
+
"unsupported_audio_option"
|
|
3784
|
+
];
|
|
3785
|
+
/**
|
|
3786
|
+
* Supported sound-effects generation vendors. Currently only ElevenLabs.
|
|
3787
|
+
* New vendors are added here and in the `aiSoundService` factory.
|
|
3788
|
+
*/
|
|
3789
|
+
const supportedSoundGenerationVendor = z.enum(["elevenlabs"]);
|
|
3790
|
+
/**
|
|
3791
|
+
* Inbound request body for `POST /api/ai/sound-effects`.
|
|
3792
|
+
*
|
|
3793
|
+
* `durationSeconds` and `promptInfluence` bounds mirror the ElevenLabs
|
|
3794
|
+
* sound-generation limits (0.5-30s for the default eleven_text_to_sound_v2
|
|
3795
|
+
* model, prompt influence 0-1). `format` is the provider-specific output
|
|
3796
|
+
* encoding token (e.g. `mp3_44100_128`).
|
|
3797
|
+
*/
|
|
3798
|
+
const soundEffectsRequestSchema = z.object({
|
|
3799
|
+
provider: supportedSoundGenerationVendor.default("elevenlabs"),
|
|
3800
|
+
text: z.string().min(1).max(1e3),
|
|
3801
|
+
durationSeconds: z.number().min(.5).max(30).optional(),
|
|
3802
|
+
promptInfluence: z.number().min(0).max(1).optional(),
|
|
3803
|
+
format: z.string().optional(),
|
|
3804
|
+
...generatedAudioRequestFields
|
|
3799
3805
|
});
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3806
|
+
/**
|
|
3807
|
+
* Supported background-music generation vendors. Currently only ElevenLabs.
|
|
3808
|
+
* New vendors are added here and in the `aiMusicService` factory.
|
|
3809
|
+
*/
|
|
3810
|
+
const supportedMusicGenerationVendor = z.enum(["elevenlabs"]);
|
|
3811
|
+
/**
|
|
3812
|
+
* Supported ElevenLabs music models. Scoped to `music_v1` for now; `music_v2` is
|
|
3813
|
+
* a deliberate follow-up (see the parent issue). Adding it here is the only
|
|
3814
|
+
* change the request surface needs to accept it.
|
|
3815
|
+
*/
|
|
3816
|
+
const supportedMusicModel = z.enum(["music_v1"]);
|
|
3817
|
+
/**
|
|
3818
|
+
* Inbound request body for `POST /api/ai/music`.
|
|
3819
|
+
*
|
|
3820
|
+
* `lengthMs` upper bound is capped below the ElevenLabs Music API ceiling to fit
|
|
3821
|
+
* the serving function's time budget (see MAX_MUSIC_LENGTH_MS). It carries a
|
|
3822
|
+
* default rather than being optional so the billed
|
|
3823
|
+
* length is always known up front (the reserve/settle path needs a deterministic
|
|
3824
|
+
* cost before generation) and the route can force that exact length on the
|
|
3825
|
+
* provider. `format` is the provider-specific output encoding token (e.g.
|
|
3826
|
+
* `mp3_44100_128`).
|
|
3827
|
+
*/
|
|
3828
|
+
const musicRequestSchema = z.object({
|
|
3829
|
+
provider: supportedMusicGenerationVendor.default("elevenlabs"),
|
|
3830
|
+
prompt: z.string().min(1).max(2e3),
|
|
3831
|
+
lengthMs: z.number().int().min(3e3).max(12e4).default(1e4),
|
|
3832
|
+
forceInstrumental: z.boolean().optional(),
|
|
3833
|
+
modelId: supportedMusicModel.default("music_v1"),
|
|
3834
|
+
format: z.string().optional(),
|
|
3835
|
+
...generatedAudioRequestFields
|
|
3815
3836
|
});
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3837
|
+
/**
|
|
3838
|
+
* Canonical agent execution status tuple. Shared between the database model
|
|
3839
|
+
* (`AgentExecutionModel`), the client store (`useAgentExecutionStore`), and
|
|
3840
|
+
* wire schemas (`ChildExecutionSnapshotSchema`, etc.) so the value space can't
|
|
3841
|
+
* drift across boundaries, and so the Zod schemas can type `status` as
|
|
3842
|
+
* `z.enum(AGENT_EXECUTION_STATUSES)` instead of `z.string()`.
|
|
3843
|
+
*/
|
|
3844
|
+
const AGENT_EXECUTION_STATUSES = [
|
|
3845
|
+
"pending",
|
|
3846
|
+
"running",
|
|
3847
|
+
"continuing",
|
|
3848
|
+
"awaiting_permission",
|
|
3849
|
+
"awaiting_subagent",
|
|
3850
|
+
"awaiting_dag_children",
|
|
3851
|
+
"paused",
|
|
3852
|
+
"completed",
|
|
3853
|
+
"failed",
|
|
3854
|
+
"aborted"
|
|
3855
|
+
];
|
|
3856
|
+
/**
|
|
3857
|
+
* Why a session summarization happened, stamped on `ISession.summaryTrigger`. Single source for the
|
|
3858
|
+
* places that each used to spell this list out: the Session zod schema (schemas/actions.ts), the
|
|
3859
|
+
* entity type (types/entities/SessionTypes.ts), the Mongoose path (packages/database SessionModel)
|
|
3860
|
+
* and the session.summarize event payload (apps/client server/utils/eventBus.ts). They drifted -
|
|
3861
|
+
* the Mongoose enum said 'milestone'/'growth' for two values nothing produces - and a drift there
|
|
3862
|
+
* is invisible on the update path, because BaseModel's findOneAndUpdate writes without
|
|
3863
|
+
* runValidators.
|
|
3864
|
+
*
|
|
3865
|
+
* Those surfaces now name PERSISTED_SESSION_SUMMARY_TRIGGERS below, not the full union: a stored
|
|
3866
|
+
* field may only carry a reason a run HAPPENED. 'throttling' is the exception that forced the
|
|
3867
|
+
* split - shouldSummarizeSession (b4m-core/services ChatCompletionFeatures) returns it as the
|
|
3868
|
+
* reason it DECLINED to summarize, so it describes no run and belongs to a decision, not a
|
|
3869
|
+
* document. It is typed by SummarizationDecision there, not by the session field.
|
|
3870
|
+
*
|
|
3871
|
+
* 'manual' means someone asked for one notebook's summary. The admin sweep
|
|
3872
|
+
* (apps/workers/src/events/spider.ts) summarizes every un-summarized notebook of the admin who ran it in one
|
|
3873
|
+
* billed pass, so it stamps 'spider' instead: without that, one deliberate click and a whole sweep
|
|
3874
|
+
* are indistinguishable when someone investigates unexpected summarization spend.
|
|
3875
|
+
*/
|
|
3876
|
+
/**
|
|
3877
|
+
* The triggers a document may actually carry - every reason a summarization HAPPENED. The event
|
|
3878
|
+
* payload and createSessionParametersSchema both name this list rather than the full union below,
|
|
3879
|
+
* so 'throttling' cannot be published, cannot be stored, and therefore cannot reach a copy path.
|
|
3880
|
+
* Add a new reason-it-happened here, not to SESSION_SUMMARY_TRIGGERS, and every one of those
|
|
3881
|
+
* boundaries picks it up.
|
|
3882
|
+
*/
|
|
3883
|
+
const PERSISTED_SESSION_SUMMARY_TRIGGERS = [
|
|
3884
|
+
"manual",
|
|
3885
|
+
"project",
|
|
3886
|
+
"earlyMilestone",
|
|
3887
|
+
"contentGrowth",
|
|
3888
|
+
"spider"
|
|
3889
|
+
];
|
|
3890
|
+
[...PERSISTED_SESSION_SUMMARY_TRIGGERS];
|
|
3891
|
+
/**
|
|
3892
|
+
* Operator allow-list for the client-authored Mongo filter carried on a `subscribe_query` frame.
|
|
3893
|
+
*
|
|
3894
|
+
* The WS data-subscribe handler forwards that filter to `Model.find` and persists it on the
|
|
3895
|
+
* QuerySubscription the separate subscriber-fanout service replays, so an unconstrained
|
|
3896
|
+
* `$`-prefixed key lets any authenticated socket ask the database to run server-side JavaScript
|
|
3897
|
+
* (`$where`, `$expr` + `$function`) or an unbounded `$regex` - either of which pins a pooled
|
|
3898
|
+
* connection for as long as it runs.
|
|
3899
|
+
*
|
|
3900
|
+
* Live subscriptions only ever need equality, membership and range matching, so anything outside
|
|
3901
|
+
* this list is REFUSED rather than stripped: silently dropping an operator would quietly widen the
|
|
3902
|
+
* document set the caller ends up subscribed to.
|
|
3903
|
+
*
|
|
3904
|
+
* The scan is deliberately structural rather than a model of Mongo's grammar - it flags any
|
|
3905
|
+
* `$`-prefixed key anywhere in the tree that isn't allow-listed. It can therefore accept an
|
|
3906
|
+
* allow-listed operator in a position Mongo would treat as a literal sub-document field name, but
|
|
3907
|
+
* that is inert; what matters is that no disallowed operator can reach the driver.
|
|
3908
|
+
*/
|
|
3909
|
+
/** Combinators whose operands are themselves filters. */
|
|
3910
|
+
const SUBSCRIPTION_FILTER_LOGICAL_OPERATORS = [
|
|
3911
|
+
"$and",
|
|
3912
|
+
"$or",
|
|
3913
|
+
"$nor",
|
|
3914
|
+
"$not"
|
|
3915
|
+
];
|
|
3916
|
+
/** Value-level operators a subscription filter may use. */
|
|
3917
|
+
const SUBSCRIPTION_FILTER_VALUE_OPERATORS = [
|
|
3918
|
+
"$eq",
|
|
3919
|
+
"$ne",
|
|
3920
|
+
"$gt",
|
|
3921
|
+
"$gte",
|
|
3922
|
+
"$lt",
|
|
3923
|
+
"$lte",
|
|
3924
|
+
"$in",
|
|
3925
|
+
"$nin",
|
|
3926
|
+
"$exists",
|
|
3927
|
+
"$type",
|
|
3928
|
+
"$size",
|
|
3929
|
+
"$all",
|
|
3930
|
+
"$elemMatch"
|
|
3931
|
+
];
|
|
3932
|
+
const ALLOWED_OPERATORS = /* @__PURE__ */ new Set([...SUBSCRIPTION_FILTER_LOGICAL_OPERATORS, ...SUBSCRIPTION_FILTER_VALUE_OPERATORS]);
|
|
3933
|
+
/**
|
|
3934
|
+
* Returns a dotted path for every part of `filter` a subscription may not send: a disallowed
|
|
3935
|
+
* `$`-prefixed key, a `RegExp` operand, or nesting past {@link SUBSCRIPTION_FILTER_MAX_DEPTH}.
|
|
3936
|
+
* An empty array means the filter is safe to forward to the database.
|
|
3937
|
+
*/
|
|
3938
|
+
function findDisallowedSubscriptionFilterKeys(filter) {
|
|
3939
|
+
const violations = [];
|
|
3940
|
+
const walk = (node, path, depth) => {
|
|
3941
|
+
if (depth > 12) {
|
|
3942
|
+
violations.push(`${path} (nested deeper than 12)`);
|
|
3943
|
+
return;
|
|
3944
|
+
}
|
|
3945
|
+
if (node instanceof RegExp) {
|
|
3946
|
+
violations.push(`${path} (regular expression)`);
|
|
3947
|
+
return;
|
|
3948
|
+
}
|
|
3949
|
+
if (Array.isArray(node)) {
|
|
3950
|
+
node.forEach((entry, i) => walk(entry, `${path}[${i}]`, depth + 1));
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
if (node === null || typeof node !== "object") return;
|
|
3954
|
+
for (const [key, value] of Object.entries(node)) {
|
|
3955
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
3956
|
+
if (key.startsWith("$") && !ALLOWED_OPERATORS.has(key)) {
|
|
3957
|
+
violations.push(childPath);
|
|
3958
|
+
continue;
|
|
3959
|
+
}
|
|
3960
|
+
walk(value, childPath, depth + 1);
|
|
3961
|
+
}
|
|
3962
|
+
};
|
|
3963
|
+
walk(filter, "", 0);
|
|
3964
|
+
return violations;
|
|
3965
|
+
}
|
|
3966
|
+
const DataSubscribeRequestAction = z$1.object({
|
|
3967
|
+
action: z$1.literal("subscribe_query"),
|
|
3968
|
+
accessToken: z$1.string().optional(),
|
|
3969
|
+
subscriptionId: z$1.string(),
|
|
3970
|
+
collectionName: z$1.string(),
|
|
3971
|
+
query: z$1.looseObject({}).superRefine((filter, ctx) => {
|
|
3972
|
+
for (const key of findDisallowedSubscriptionFilterKeys(filter)) ctx.addIssue({
|
|
3973
|
+
code: "custom",
|
|
3974
|
+
message: `Disallowed subscription filter: ${key}`
|
|
3975
|
+
});
|
|
3976
|
+
}),
|
|
3977
|
+
fields: z$1.record(z$1.string(), z$1.union([z$1.boolean(), z$1.number()])),
|
|
3978
|
+
fetchInitialData: z$1.boolean().prefault(true).optional(),
|
|
3823
3979
|
clientId: z$1.string().optional()
|
|
3824
3980
|
});
|
|
3825
|
-
const
|
|
3826
|
-
action: z$1.literal("
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
phase: z$1.enum([
|
|
3830
|
-
"fetching_issues",
|
|
3831
|
-
"fetching_prs",
|
|
3832
|
-
"calculating_stats",
|
|
3833
|
-
"building_profiles",
|
|
3834
|
-
"extracting_keywords",
|
|
3835
|
-
"saving"
|
|
3836
|
-
]),
|
|
3837
|
-
percentage: z$1.number(),
|
|
3838
|
-
message: z$1.string(),
|
|
3839
|
-
itemsProcessed: z$1.number().optional(),
|
|
3840
|
-
totalItems: z$1.number().optional(),
|
|
3841
|
-
clientId: z$1.string().optional()
|
|
3981
|
+
const DataUnsubscribeRequestAction = z$1.object({
|
|
3982
|
+
action: z$1.literal("unsubscribe_query"),
|
|
3983
|
+
accessToken: z$1.string().optional(),
|
|
3984
|
+
subscriptionId: z$1.string()
|
|
3842
3985
|
});
|
|
3843
|
-
const
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
clientId: z$1.string().optional()
|
|
3986
|
+
const HeartbeatAction = z$1.object({ action: z$1.literal("heartbeat") });
|
|
3987
|
+
const VoiceSessionSendTranscriptAction = z$1.object({
|
|
3988
|
+
action: z$1.literal("voice_session_send_transcript"),
|
|
3989
|
+
userId: z$1.string(),
|
|
3990
|
+
sessionId: z$1.string(),
|
|
3991
|
+
transcript: z$1.string(),
|
|
3992
|
+
type: z$1.enum(["input", "response"]),
|
|
3993
|
+
conversationItemId: z$1.string(),
|
|
3994
|
+
timestamp: z$1.coerce.date().optional()
|
|
3853
3995
|
});
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3996
|
+
/**
|
|
3997
|
+
* CLI Completion request over WebSocket (bypasses CloudFront 20s timeout)
|
|
3998
|
+
*/
|
|
3999
|
+
const CliCompletionRequestAction = z$1.object({
|
|
4000
|
+
action: z$1.literal("cli_completion_request"),
|
|
4001
|
+
accessToken: z$1.string(),
|
|
4002
|
+
requestId: z$1.uuid(),
|
|
4003
|
+
model: z$1.string(),
|
|
4004
|
+
messages: z$1.array(z$1.object({
|
|
4005
|
+
role: z$1.enum([
|
|
4006
|
+
"user",
|
|
4007
|
+
"assistant",
|
|
4008
|
+
"system"
|
|
4009
|
+
]),
|
|
4010
|
+
content: z$1.union([z$1.string(), z$1.array(z$1.unknown())]),
|
|
4011
|
+
cache: z$1.boolean().optional()
|
|
4012
|
+
})),
|
|
4013
|
+
options: z$1.object({
|
|
4014
|
+
temperature: z$1.number().optional(),
|
|
4015
|
+
maxTokens: z$1.number().optional(),
|
|
4016
|
+
stream: z$1.boolean().optional(),
|
|
4017
|
+
tools: z$1.array(z$1.unknown()).optional(),
|
|
4018
|
+
response_format: z$1.discriminatedUnion("type", [z$1.object({ type: z$1.literal("text") }), z$1.object({
|
|
4019
|
+
type: z$1.literal("json_schema"),
|
|
4020
|
+
json_schema: z$1.object({
|
|
4021
|
+
name: z$1.string(),
|
|
4022
|
+
description: z$1.string().optional(),
|
|
4023
|
+
schema: z$1.record(z$1.string(), z$1.any()),
|
|
4024
|
+
strict: z$1.boolean().optional().default(true)
|
|
4025
|
+
})
|
|
4026
|
+
})]).optional()
|
|
4027
|
+
}).optional()
|
|
3861
4028
|
});
|
|
3862
|
-
|
|
3863
|
-
|
|
4029
|
+
/**
|
|
4030
|
+
* CLI Tool execution request over WebSocket
|
|
4031
|
+
*/
|
|
4032
|
+
const CliToolRequestAction = z$1.object({
|
|
4033
|
+
action: z$1.literal("cli_tool_request"),
|
|
4034
|
+
accessToken: z$1.string(),
|
|
4035
|
+
requestId: z$1.uuid(),
|
|
4036
|
+
toolName: z$1.string(),
|
|
4037
|
+
input: z$1.record(z$1.string(), z$1.unknown())
|
|
4038
|
+
});
|
|
4039
|
+
const VoiceSessionEndedAction = z$1.object({
|
|
4040
|
+
action: z$1.literal("voice_session_ended"),
|
|
4041
|
+
userId: z$1.string(),
|
|
4042
|
+
model: z$1.string(),
|
|
4043
|
+
sessionId: z$1.string(),
|
|
4044
|
+
usage: z$1.object({
|
|
4045
|
+
audioInputTokens: z$1.number().min(0),
|
|
4046
|
+
audioCachedInputTokens: z$1.number().min(0),
|
|
4047
|
+
audioOutputTokens: z$1.number().min(0),
|
|
4048
|
+
textInputTokens: z$1.number().min(0),
|
|
4049
|
+
textCachedInputTokens: z$1.number().min(0),
|
|
4050
|
+
textOutputTokens: z$1.number().min(0)
|
|
4051
|
+
})
|
|
4052
|
+
});
|
|
4053
|
+
const DataSubscriptionUpdateAction = z$1.object({
|
|
4054
|
+
action: z$1.literal("data_update"),
|
|
4055
|
+
subscriptionId: z$1.string(),
|
|
4056
|
+
collectionName: z$1.string(),
|
|
4057
|
+
operationType: z$1.string(),
|
|
3864
4058
|
clientId: z$1.string().optional(),
|
|
3865
|
-
|
|
4059
|
+
data: z$1.looseObject({
|
|
4060
|
+
_id: z$1.string(),
|
|
4061
|
+
id: z$1.string()
|
|
4062
|
+
})
|
|
4063
|
+
});
|
|
4064
|
+
/**
|
|
4065
|
+
* Server -> Client: a `subscribe_query` frame was refused (the operator allow-list, `fields`
|
|
4066
|
+
* validation) or its initial fetch was aborted (`maxTimeMS`). Neither failure throws an
|
|
4067
|
+
* UnauthorizedError/JsonWebTokenError, so withWebSocketContext's status code never reaches the
|
|
4068
|
+
* client as a frame - this is the only signal the caller gets that the subscription never took.
|
|
4069
|
+
*/
|
|
4070
|
+
const DataSubscribeErrorAction = z$1.object({
|
|
4071
|
+
action: z$1.literal("data_subscribe_error"),
|
|
4072
|
+
subscriptionId: z$1.string(),
|
|
4073
|
+
error: z$1.string()
|
|
4074
|
+
});
|
|
4075
|
+
const LLMStatusUpdateAction = z$1.object({
|
|
4076
|
+
action: z$1.literal("llm_status_update"),
|
|
4077
|
+
status: z$1.string().nullable(),
|
|
4078
|
+
clientId: z$1.string().optional()
|
|
4079
|
+
});
|
|
4080
|
+
const InboxRefetchAction = z$1.object({
|
|
4081
|
+
action: z$1.literal("inbox_refetch"),
|
|
4082
|
+
status: z$1.string(),
|
|
4083
|
+
clientId: z$1.string().optional()
|
|
4084
|
+
});
|
|
4085
|
+
const InvitesRefetchAction = z$1.object({
|
|
4086
|
+
action: z$1.literal("invites_refetch"),
|
|
4087
|
+
status: z$1.string(),
|
|
4088
|
+
clientId: z$1.string().optional()
|
|
4089
|
+
});
|
|
4090
|
+
const UpdateCurrentUserAction = z$1.object({
|
|
4091
|
+
action: z$1.literal("update_current_user"),
|
|
4092
|
+
clientId: z$1.string().optional(),
|
|
4093
|
+
user: z$1.object({
|
|
4094
|
+
id: z$1.string(),
|
|
4095
|
+
username: z$1.string(),
|
|
4096
|
+
name: z$1.string(),
|
|
4097
|
+
email: z$1.string(),
|
|
4098
|
+
groups: z$1.array(z$1.string()),
|
|
4099
|
+
isAdmin: z$1.boolean(),
|
|
4100
|
+
storageLimit: z$1.number(),
|
|
4101
|
+
currentStorageSize: z$1.number()
|
|
4102
|
+
}).partial()
|
|
4103
|
+
});
|
|
4104
|
+
const ResearchTaskStatusUpdateAction = z$1.object({
|
|
4105
|
+
action: z$1.literal("research_task_status_update"),
|
|
4106
|
+
taskId: z$1.string(),
|
|
4107
|
+
status: z$1.string(),
|
|
4108
|
+
currentStep: z$1.string(),
|
|
4109
|
+
progress: z$1.number()
|
|
4110
|
+
});
|
|
4111
|
+
const NotebookCurationProgressUpdateAction = z$1.object({
|
|
4112
|
+
action: z$1.literal("notebook_curation_progress"),
|
|
4113
|
+
curationJobId: z$1.string(),
|
|
4114
|
+
sessionId: z$1.string(),
|
|
4115
|
+
status: z$1.enum([
|
|
4116
|
+
"pending",
|
|
4117
|
+
"loading",
|
|
4118
|
+
"extracting",
|
|
4119
|
+
"generating",
|
|
4120
|
+
"storing",
|
|
4121
|
+
"completed",
|
|
4122
|
+
"failed"
|
|
4123
|
+
]),
|
|
4124
|
+
stage: z$1.enum([
|
|
4125
|
+
"loading",
|
|
4126
|
+
"extracting",
|
|
4127
|
+
"generating",
|
|
4128
|
+
"storing"
|
|
4129
|
+
]).optional(),
|
|
4130
|
+
percentage: z$1.number(),
|
|
4131
|
+
message: z$1.string().optional(),
|
|
4132
|
+
messagesProcessed: z$1.number().optional(),
|
|
4133
|
+
totalMessages: z$1.number().optional(),
|
|
4134
|
+
artifactsFound: z$1.number().optional(),
|
|
4135
|
+
curatedFileId: z$1.string().optional(),
|
|
4136
|
+
errorMessage: z$1.string().optional(),
|
|
4137
|
+
tokensDeducted: z$1.number().optional(),
|
|
4138
|
+
clientId: z$1.string().optional()
|
|
4139
|
+
});
|
|
4140
|
+
const QuestExportProgressAction = z$1.object({
|
|
4141
|
+
action: z$1.literal("quest_export_progress"),
|
|
4142
|
+
exportJobId: z$1.string(),
|
|
4143
|
+
planId: z$1.string(),
|
|
4144
|
+
status: z$1.enum([
|
|
4145
|
+
"assembling",
|
|
4146
|
+
"downloading_images",
|
|
4147
|
+
"summarizing",
|
|
4148
|
+
"zipping",
|
|
4149
|
+
"completed",
|
|
4150
|
+
"failed"
|
|
4151
|
+
]),
|
|
4152
|
+
progress: z$1.number(),
|
|
4153
|
+
detail: z$1.string().optional(),
|
|
4154
|
+
downloadUrl: z$1.string().optional(),
|
|
4155
|
+
filename: z$1.string().optional(),
|
|
4156
|
+
errorMessage: z$1.string().optional(),
|
|
4157
|
+
droppedQuestCount: z$1.number().optional(),
|
|
4158
|
+
clientId: z$1.string().optional()
|
|
4159
|
+
});
|
|
4160
|
+
const OrgFeedbackSummaryProgressAction = z$1.object({
|
|
4161
|
+
action: z$1.literal("org_feedback_summary_progress"),
|
|
4162
|
+
summaryJobId: z$1.string(),
|
|
4163
|
+
organizationId: z$1.string(),
|
|
4164
|
+
status: z$1.enum([
|
|
4165
|
+
"processing",
|
|
4166
|
+
"completed",
|
|
4167
|
+
"failed"
|
|
4168
|
+
]),
|
|
4169
|
+
progress: z$1.number(),
|
|
4170
|
+
errorMessage: z$1.string().optional(),
|
|
4171
|
+
clientId: z$1.string().optional()
|
|
4172
|
+
});
|
|
4173
|
+
const SpiderProgressUpdateAction = z$1.object({
|
|
4174
|
+
action: z$1.literal("spider_progress"),
|
|
4175
|
+
spiderJobId: z$1.string(),
|
|
4176
|
+
notebooksProcessed: z$1.number(),
|
|
4177
|
+
totalNotebooks: z$1.number(),
|
|
4178
|
+
currentOperation: z$1.string(),
|
|
4179
|
+
currentNotebookId: z$1.string().optional(),
|
|
4180
|
+
currentNotebookName: z$1.string().optional(),
|
|
4181
|
+
dryRun: z$1.boolean().optional(),
|
|
4182
|
+
clientId: z$1.string().optional()
|
|
4183
|
+
});
|
|
4184
|
+
const SpiderCompleteAction = z$1.object({
|
|
4185
|
+
action: z$1.literal("spider_complete"),
|
|
4186
|
+
spiderJobId: z$1.string(),
|
|
4187
|
+
totalNotebooks: z$1.number(),
|
|
4188
|
+
stats: z$1.object({
|
|
4189
|
+
messageCountsUpdated: z$1.number(),
|
|
4190
|
+
notebooksCurated: z$1.number(),
|
|
4191
|
+
notebooksSummarized: z$1.number(),
|
|
4192
|
+
notebooksTagged: z$1.number(),
|
|
4193
|
+
messagesEmbedded: z$1.number().optional(),
|
|
4194
|
+
errors: z$1.number().optional(),
|
|
4195
|
+
skipped: z$1.number().optional()
|
|
4196
|
+
}),
|
|
4197
|
+
dryRun: z$1.boolean().optional(),
|
|
4198
|
+
clientId: z$1.string().optional()
|
|
4199
|
+
});
|
|
4200
|
+
const SpiderErrorAction = z$1.object({
|
|
4201
|
+
action: z$1.literal("spider_error"),
|
|
4202
|
+
spiderJobId: z$1.string(),
|
|
4203
|
+
error: z$1.string(),
|
|
4204
|
+
notebooksProcessed: z$1.number().optional(),
|
|
4205
|
+
totalNotebooks: z$1.number(),
|
|
4206
|
+
dryRun: z$1.boolean().optional(),
|
|
4207
|
+
clientId: z$1.string().optional()
|
|
4208
|
+
});
|
|
4209
|
+
const PiHistoryProgressAction = z$1.object({
|
|
4210
|
+
action: z$1.literal("pi_history_progress"),
|
|
4211
|
+
analysisJobId: z$1.string(),
|
|
4212
|
+
repoFullName: z$1.string(),
|
|
4213
|
+
phase: z$1.enum([
|
|
4214
|
+
"fetching_issues",
|
|
4215
|
+
"fetching_prs",
|
|
4216
|
+
"calculating_stats",
|
|
4217
|
+
"building_profiles",
|
|
4218
|
+
"extracting_keywords",
|
|
4219
|
+
"saving"
|
|
4220
|
+
]),
|
|
4221
|
+
percentage: z$1.number(),
|
|
4222
|
+
message: z$1.string(),
|
|
4223
|
+
itemsProcessed: z$1.number().optional(),
|
|
4224
|
+
totalItems: z$1.number().optional(),
|
|
4225
|
+
clientId: z$1.string().optional()
|
|
4226
|
+
});
|
|
4227
|
+
const PiHistoryCompleteAction = z$1.object({
|
|
4228
|
+
action: z$1.literal("pi_history_complete"),
|
|
4229
|
+
analysisJobId: z$1.string(),
|
|
4230
|
+
repoFullName: z$1.string(),
|
|
4231
|
+
stats: z$1.object({
|
|
4232
|
+
closedIssues: z$1.number(),
|
|
4233
|
+
mergedPRs: z$1.number(),
|
|
4234
|
+
contributors: z$1.number()
|
|
4235
|
+
}),
|
|
4236
|
+
clientId: z$1.string().optional()
|
|
4237
|
+
});
|
|
4238
|
+
const PiHistoryErrorAction = z$1.object({
|
|
4239
|
+
action: z$1.literal("pi_history_error"),
|
|
4240
|
+
analysisJobId: z$1.string(),
|
|
4241
|
+
repoFullName: z$1.string(),
|
|
4242
|
+
error: z$1.string(),
|
|
4243
|
+
phase: z$1.string(),
|
|
4244
|
+
clientId: z$1.string().optional()
|
|
4245
|
+
});
|
|
4246
|
+
const GenerationJobUpdatedAction = z$1.object({
|
|
4247
|
+
action: z$1.literal("generation_job_updated"),
|
|
4248
|
+
job: z$1.object({
|
|
4249
|
+
id: z$1.string(),
|
|
4250
|
+
kind: z$1.enum(GENERATION_JOB_KINDS),
|
|
4251
|
+
state: z$1.enum(GENERATION_JOB_STATES),
|
|
4252
|
+
progress: z$1.number().min(0).max(1).optional(),
|
|
4253
|
+
error: z$1.object({
|
|
4254
|
+
code: z$1.string(),
|
|
4255
|
+
message: z$1.string()
|
|
4256
|
+
}).optional(),
|
|
4257
|
+
output: z$1.object({
|
|
4258
|
+
fileId: z$1.string().optional(),
|
|
4259
|
+
contentType: z$1.string(),
|
|
4260
|
+
durationSeconds: z$1.number()
|
|
4261
|
+
}).optional()
|
|
4262
|
+
})
|
|
4263
|
+
});
|
|
4264
|
+
const StreamedChatCompletionAction = z$1.object({
|
|
4265
|
+
action: z$1.literal("streamed_chat_completion"),
|
|
4266
|
+
clientId: z$1.string().optional(),
|
|
4267
|
+
statusMessage: z$1.string().nullable().optional(),
|
|
3866
4268
|
quest: z$1.object({
|
|
3867
4269
|
id: z$1.string(),
|
|
3868
4270
|
sessionId: z$1.string(),
|
|
@@ -3870,6 +4272,7 @@ const StreamedChatCompletionAction = z$1.object({
|
|
|
3870
4272
|
replies: z$1.array(z$1.string()).optional(),
|
|
3871
4273
|
images: z$1.array(z$1.string()).optional(),
|
|
3872
4274
|
videos: z$1.array(z$1.string()).optional(),
|
|
4275
|
+
videoJobIds: z$1.array(z$1.string()).optional(),
|
|
3873
4276
|
type: z$1.enum(CHAT_HISTORY_ITEM_TYPES),
|
|
3874
4277
|
status: z$1.enum([
|
|
3875
4278
|
"stopped",
|
|
@@ -4415,6 +4818,7 @@ const HearthEventAction = z$1.object({
|
|
|
4415
4818
|
}),
|
|
4416
4819
|
machine: hearthMachineBodySchema.optional(),
|
|
4417
4820
|
refs: hearthEventRefsSchema.prefault({}),
|
|
4821
|
+
origin: hearthEventOriginSchema.optional(),
|
|
4418
4822
|
createdAt: z$1.string()
|
|
4419
4823
|
})
|
|
4420
4824
|
});
|
|
@@ -4893,6 +5297,7 @@ const ReconnectResultAction = z$1.object({
|
|
|
4893
5297
|
action: z$1.literal("reconnect_result"),
|
|
4894
5298
|
found: z$1.boolean(),
|
|
4895
5299
|
executionId: z$1.string().optional(),
|
|
5300
|
+
sessionId: z$1.string().optional(),
|
|
4896
5301
|
status: z$1.enum(AGENT_EXECUTION_STATUSES).optional(),
|
|
4897
5302
|
pendingPermission: z$1.object({
|
|
4898
5303
|
toolName: z$1.string(),
|
|
@@ -4930,6 +5335,7 @@ const OptiHashiRunUpdatedAction = z$1.object({
|
|
|
4930
5335
|
status: z$1.string()
|
|
4931
5336
|
});
|
|
4932
5337
|
z$1.discriminatedUnion("action", [
|
|
5338
|
+
GenerationJobUpdatedAction,
|
|
4933
5339
|
DataSubscriptionUpdateAction,
|
|
4934
5340
|
DataSubscribeErrorAction,
|
|
4935
5341
|
InboxRefetchAction,
|
|
@@ -5226,7 +5632,7 @@ const CompletionRequestSchema = z$1.object({
|
|
|
5226
5632
|
stream: z$1.boolean().optional(),
|
|
5227
5633
|
tools: z$1.array(CompletionToolSchema).optional(),
|
|
5228
5634
|
response_format: ResponseFormatSchema.optional(),
|
|
5229
|
-
reasoningEffort: CompletionReasoningEffortSchema.optional()
|
|
5635
|
+
reasoningEffort: CompletionReasoningEffortSchema.optional().describe("Reasoning effort hint. Honoured only by the OpenAI (reasoning models only, and not alongside tools on some of them), Kimi (K3 only) and DeepSeek adapters; Kimi and DeepSeek map it onto their own scale. Silently ignored by every other adapter (Anthropic, Gemini, Bedrock, xAI, Ollama) and by non-reasoning models, so sending it there is a no-op.")
|
|
5230
5636
|
}).optional()
|
|
5231
5637
|
});
|
|
5232
5638
|
const CompletionUsageSchema = z$1.object({
|
|
@@ -6269,6 +6675,24 @@ const DATA_LAKES = [{
|
|
|
6269
6675
|
}
|
|
6270
6676
|
})()];
|
|
6271
6677
|
new Set(DATA_LAKES.map((l) => l.id));
|
|
6678
|
+
/**
|
|
6679
|
+
* Query parameters for a cursor-paginated public list (CONVENTIONS.md section 8).
|
|
6680
|
+
*
|
|
6681
|
+
* `limit` is `z.coerce` because query values arrive as strings; registerContract publishes it as an
|
|
6682
|
+
* integer. A non-numeric, zero, or over-cap value is a 422, never silently clamped.
|
|
6683
|
+
*/
|
|
6684
|
+
const PaginationQuerySchema = z$1.object({
|
|
6685
|
+
limit: z$1.coerce.number().int().min(1).max(100).default(25),
|
|
6686
|
+
cursor: z$1.string().min(1).optional()
|
|
6687
|
+
});
|
|
6688
|
+
/**
|
|
6689
|
+
* The response envelope every cursor-paginated public list returns. `next_cursor` is required and
|
|
6690
|
+
* `null` on the last page, so a caller loops on it rather than on the page length.
|
|
6691
|
+
*/
|
|
6692
|
+
const paginatedResponseSchema = (itemSchema) => z$1.object({
|
|
6693
|
+
data: z$1.array(itemSchema),
|
|
6694
|
+
next_cursor: z$1.string().nullable()
|
|
6695
|
+
});
|
|
6272
6696
|
const SessionTagSchema = z$1.object({
|
|
6273
6697
|
name: z$1.string(),
|
|
6274
6698
|
strength: z$1.number()
|
|
@@ -6286,14 +6710,15 @@ const SessionUpdateRequestSchema = z$1.object({
|
|
|
6286
6710
|
tags: z$1.array(SessionTagSchema).optional(),
|
|
6287
6711
|
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."),
|
|
6288
6712
|
forceKnowledgeRetrieval: z$1.boolean().optional(),
|
|
6289
|
-
lakeScope: z$1.array(z$1.string()).nullable().optional().describe("The data lakes this session grounds on, as lake tags (the `
|
|
6713
|
+
lakeScope: z$1.array(z$1.string()).nullable().optional().describe("The data lakes this session grounds on, as lake tags (the `datalake_tag` of each lake from GET /api/v1/data-lakes). Send a list to ground only on those lakes, `[]` to ground on no lake at all, or `null` to clear the choice so retrieval falls back to every lake you can reach. Omit to leave the current choice unchanged. Tags naming a lake you cannot reach are ignored at retrieval time rather than rejected here. Narrowing the scope does not by itself turn retrieval on: pair it with `forceKnowledgeRetrieval: true` for a session that is not already grounded. Conversely `[]` leaves a grounded session nothing to retrieve from, so its forced retrieval is skipped rather than run against every lake."),
|
|
6714
|
+
includeLibraryFiles: z$1.boolean().optional().describe("Whether the session grounds on your own library (files you own, or that are shared with you or your groups) alongside its lakes. `false` confines retrieval to lake content, including when every lake is in scope; the session's attached files still reach the model and stay searchable by its knowledge-base tools. Omit to leave it unchanged; while never set, the library is excluded only when a lake was picked for the session (Data Lakes mode or an explicit lake scope), not when lake tags were derived from an attached file. While `forceKnowledgeRetrieval` is `false` the library is included regardless; the stored value applies again once it is turned back on."),
|
|
6290
6715
|
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.")
|
|
6291
6716
|
});
|
|
6292
6717
|
/** Path parameter for session-scoped endpoints, e.g. GET/PUT /api/sessions/{id}. */
|
|
6293
6718
|
const SessionIdParamSchema = z$1.object({ id: z$1.string().min(1) });
|
|
6294
6719
|
/**
|
|
6295
|
-
* Practical response subset for PUT /api/sessions/{id} - the fields a caller needs to
|
|
6296
|
-
* confirm an update took effect. ISession (types/entities/SessionTypes.ts) carries many
|
|
6720
|
+
* Practical response subset for GET and PUT /api/sessions/{id} - the fields a caller needs to
|
|
6721
|
+
* read a session or confirm an update took effect. ISession (types/entities/SessionTypes.ts) carries many
|
|
6297
6722
|
* more server-internal fields not documented as public API surface here.
|
|
6298
6723
|
*/
|
|
6299
6724
|
const SessionResponseSchema = z$1.object({
|
|
@@ -6307,10 +6732,22 @@ const SessionResponseSchema = z$1.object({
|
|
|
6307
6732
|
forceKnowledgeRetrieval: z$1.boolean().optional(),
|
|
6308
6733
|
retrievalTags: z$1.array(z$1.string()).optional(),
|
|
6309
6734
|
lakeScopeExplicit: z$1.boolean().optional().describe("True when `retrievalTags` is a deliberate choice, so an empty list means \"no lake\" rather than \"any\"."),
|
|
6735
|
+
includeLibraryFiles: z$1.boolean().optional().describe("Whether the session grounds on your own library alongside its lakes. Absent when never set."),
|
|
6310
6736
|
lastUsedModel: z$1.string().nullish(),
|
|
6311
6737
|
firstCreated: z$1.date(),
|
|
6312
6738
|
lastUpdated: z$1.date()
|
|
6313
6739
|
});
|
|
6740
|
+
/** Request body for POST /api/v1/sessions/{id}/clone. */
|
|
6741
|
+
const SessionCloneRequestSchema = z$1.preprocess((body) => body === "" ? void 0 : body, z$1.object({ targetSurface: z$1.string().nullable().optional() }).default({}));
|
|
6742
|
+
/** Query for GET /api/v1/sessions: the pagination convention plus flat filters. */
|
|
6743
|
+
const ListSessionsQuerySchema = PaginationQuerySchema.extend({
|
|
6744
|
+
search: z$1.string().min(1).max(200).optional().describe("Case-insensitive substring match on the session name, its summary, or a tag name."),
|
|
6745
|
+
surface: z$1.string().min(1).optional().describe("Lists only sessions of this product surface. When omitted, only sessions with no surface are listed."),
|
|
6746
|
+
origin: z$1.enum(SESSION_ORIGIN_CHANNELS).optional().describe("Lists only sessions created through this channel. `web` also matches sessions with no recorded origin.")
|
|
6747
|
+
});
|
|
6748
|
+
const ListSessionsResponseSchema = paginatedResponseSchema(SessionResponseSchema);
|
|
6749
|
+
/** Response for DELETE /api/sessions/{id}. */
|
|
6750
|
+
const SessionDeleteResponseSchema = z$1.object({ newLastNotebookId: z$1.string().nullable().describe("The caller's most recently updated remaining session, which the product UI opens next; null when none remains.") });
|
|
6314
6751
|
/**
|
|
6315
6752
|
* Request schema for POST /api/v1/sessions. Declares every client-settable field of
|
|
6316
6753
|
* createSessionParametersSchema (b4m-core/services/src/sessionService/create.ts), which stays the
|
|
@@ -6321,7 +6758,7 @@ const SessionResponseSchema = z$1.object({
|
|
|
6321
6758
|
const CreateSessionRequestSchema = z$1.object({
|
|
6322
6759
|
name: z$1.string(),
|
|
6323
6760
|
projectId: z$1.string().optional().describe("Adds the new session to this project."),
|
|
6324
|
-
dataLakeId: z$1.string().nullish().describe("Seeds retrieval defaults from this data lake."),
|
|
6761
|
+
dataLakeId: z$1.string().nullish().describe("Seeds retrieval defaults from this data lake and turns on forced retrieval. Get ids from `GET /api/v1/data-lakes`."),
|
|
6325
6762
|
preauthorizedLakeIds: z$1.unknown().optional().describe("Data lakes the caller manages, armed for this session. At most 10; requires management rights."),
|
|
6326
6763
|
knowledgeIds: z$1.array(z$1.string()).optional(),
|
|
6327
6764
|
artifactIds: z$1.array(z$1.string()).optional(),
|
|
@@ -6335,6 +6772,7 @@ const CreateSessionRequestSchema = z$1.object({
|
|
|
6335
6772
|
forceKnowledgeRetrieval: z$1.boolean().optional(),
|
|
6336
6773
|
retrievalTags: z$1.array(z$1.string()).optional(),
|
|
6337
6774
|
lakeScopeExplicit: z$1.boolean().optional(),
|
|
6775
|
+
includeLibraryFiles: z$1.boolean().optional(),
|
|
6338
6776
|
corpusGroundingMode: z$1.enum(DATA_LAKE_GROUNDING_MODES).optional().describe("Honored only when a lake is named by `retrievalTags` without `dataLakeId`."),
|
|
6339
6777
|
retrievalExcludeFilenameMarkers: z$1.array(z$1.string()).optional(),
|
|
6340
6778
|
retrievalVectorizedOnly: z$1.boolean().optional(),
|
|
@@ -6590,6 +7028,125 @@ const SupportedEmbeddingModelSchema = z$1.union([
|
|
|
6590
7028
|
z$1.enum(OllamaEmbeddingModel)
|
|
6591
7029
|
]);
|
|
6592
7030
|
/**
|
|
7031
|
+
* Absolute floors for the FILE/RAG corpus that forced retrieval scans, by embedding space.
|
|
7032
|
+
*
|
|
7033
|
+
* Backs the `forcedRetrievalMinSimilarityPct` default. An operator's explicit value still wins -
|
|
7034
|
+
* this is what "unset" resolves to, and the reason the setting cannot simply carry one static
|
|
7035
|
+
* default any more.
|
|
7036
|
+
*
|
|
7037
|
+
* ada-002 at 75 is the value production shipped and the only one with a production-lake history
|
|
7038
|
+
* behind it. 3-small at 58 is MEASURED, on a live 520-file / 21,327-chunk capture of the
|
|
7039
|
+
* `opti-knowledge` lake (1536 dims, 2026-09-18), swept against 30 positives authored from that
|
|
7040
|
+
* corpus's own passages plus screened negatives - so recall and false-positive rate come out of ONE
|
|
7041
|
+
* corpus snapshot rather than two. The negatives were screened by reading the served chunk TEXT,
|
|
7042
|
+
* which reclassified 44 of 89 as answerable; the two right-hand columns are that screen's two
|
|
7043
|
+
* defensible readings, counting a PARTIAL answer as answerable or as a false positive.
|
|
7044
|
+
*
|
|
7045
|
+
* floor recall positives emptied FP (45 strict neg) FP (61 partial-as-neg)
|
|
7046
|
+
* 85:49 100.0% 0 71.1% 78.7%
|
|
7047
|
+
* 85:53 100.0% 0 64.4% 73.8%
|
|
7048
|
+
* 85:55 96.7% 1 60.0% 68.9%
|
|
7049
|
+
* 85:58 93.3% 2 42.2% 52.5%
|
|
7050
|
+
* 85:61 86.7% 4 22.2% 36.1%
|
|
7051
|
+
* 85:64 76.7% 7 13.3% 19.7%
|
|
7052
|
+
* 85:75 20.0% 24 0.0% 0.0%
|
|
7053
|
+
*
|
|
7054
|
+
* WHY 58 RATHER THAN THE SEPARATION OPTIMUM, WHICH IS 61-64. Recall here is measured on positives
|
|
7055
|
+
* authored FROM corpus passages, so each supporting document is the easiest possible match for its
|
|
7056
|
+
* own question, and this recall is an UPPER BOUND on recall against a real user's phrasing. The
|
|
7057
|
+
* false-positive rate, measured on screened negatives, carries no matching optimism. An optimistic
|
|
7058
|
+
* recall beside an honest false-positive rate biases the optimum HIGH, so the shipped floor is the
|
|
7059
|
+
* low end of the bracket rather than its peak.
|
|
7060
|
+
*
|
|
7061
|
+
* WHAT THE PREVIOUS 49 GOT WRONG, and it was not the magnitude. 49 emptied ZERO positives - it was
|
|
7062
|
+
* not buying recall protection, it simply was not cutting - while 71-79% of screened true negatives
|
|
7063
|
+
* still got something served. The entire range 0-53 costs no recall on this corpus, which the
|
|
7064
|
+
* 35-file capture 49 was fitted to could not show: its decoy column rested on 6 negatives.
|
|
7065
|
+
*
|
|
7066
|
+
* Recall above is of the ACCEPTED set, so it answers "did the floor cut the supporting document",
|
|
7067
|
+
* which is the floor's own question, and is NOT a claim the model saw it - the char budget and the
|
|
7068
|
+
* 256-chunk candidate pool cap are separate narrowings downstream of this gate.
|
|
7069
|
+
*
|
|
7070
|
+
* ada-002's 75 applied in this space would be an outage in all but name: 20% recall, 24 of 30
|
|
7071
|
+
* positives emptied outright. That is the per-space case above restated as a measurement.
|
|
7072
|
+
*
|
|
7073
|
+
* 3-large is deliberately absent despite having a measured band (0.2104-0.5197): the choice between
|
|
7074
|
+
* it and 3-small is recorded as NOT SETTLED, and guessing a floor for a space nobody has run the
|
|
7075
|
+
* sweep against is what this module exists to stop. Voyage, Bedrock and the Ollama self-host
|
|
7076
|
+
* embedders are absent for the same reason - none has ever been measured, and the 0.75 they inherit
|
|
7077
|
+
* today was fitted to a model none of them is.
|
|
7078
|
+
*/
|
|
7079
|
+
const FORCED_RETRIEVAL_MIN_SIMILARITY_PCT_BY_SPACE = {
|
|
7080
|
+
["text-embedding-ada-002"]: 75,
|
|
7081
|
+
["text-embedding-3-small"]: 58
|
|
7082
|
+
};
|
|
7083
|
+
const ReleaseNoteCategorySchema = z$1.enum([
|
|
7084
|
+
"new",
|
|
7085
|
+
"improved",
|
|
7086
|
+
"fixed"
|
|
7087
|
+
]);
|
|
7088
|
+
const ReleaseNoteItemSchema = z$1.object({
|
|
7089
|
+
category: ReleaseNoteCategorySchema,
|
|
7090
|
+
text: z$1.string().min(1),
|
|
7091
|
+
importance: z$1.number().int().min(1).max(3),
|
|
7092
|
+
sourcePrs: z$1.array(z$1.number().int().positive())
|
|
7093
|
+
});
|
|
7094
|
+
const ReleaseNoteStatusSchema = z$1.enum(["scheduled", "hidden"]);
|
|
7095
|
+
z$1.object({
|
|
7096
|
+
releaseTag: z$1.string().min(1),
|
|
7097
|
+
deployedSha: z$1.string().min(1),
|
|
7098
|
+
deployedAt: z$1.coerce.date(),
|
|
7099
|
+
headline: z$1.string(),
|
|
7100
|
+
summary: z$1.string(),
|
|
7101
|
+
items: z$1.array(ReleaseNoteItemSchema),
|
|
7102
|
+
audience: z$1.literal("public"),
|
|
7103
|
+
status: ReleaseNoteStatusSchema,
|
|
7104
|
+
publishAt: z$1.coerce.date(),
|
|
7105
|
+
editedAt: z$1.coerce.date().nullable(),
|
|
7106
|
+
schemaVersion: z$1.number().int()
|
|
7107
|
+
});
|
|
7108
|
+
const ReleaseNotesJobPrSchema = z$1.object({
|
|
7109
|
+
number: z$1.number().int().positive(),
|
|
7110
|
+
title: z$1.string(),
|
|
7111
|
+
labels: z$1.array(z$1.string()),
|
|
7112
|
+
customerNote: z$1.string().optional(),
|
|
7113
|
+
excerpt: z$1.string()
|
|
7114
|
+
});
|
|
7115
|
+
z$1.object({
|
|
7116
|
+
kind: z$1.literal("release-notes"),
|
|
7117
|
+
schemaVersion: z$1.number().int(),
|
|
7118
|
+
releaseTag: z$1.string().min(1),
|
|
7119
|
+
releaseUrl: z$1.string().regex(/^https:\/\/[^\s<>|]+$/),
|
|
7120
|
+
previousTag: z$1.string().nullable(),
|
|
7121
|
+
deployedSha: z$1.string().min(1),
|
|
7122
|
+
deployedAt: z$1.coerce.date(),
|
|
7123
|
+
prs: z$1.array(ReleaseNotesJobPrSchema)
|
|
7124
|
+
});
|
|
7125
|
+
const ReleaseNotesConfigSchema = z$1.object({
|
|
7126
|
+
enabled: z$1.boolean().default(false),
|
|
7127
|
+
modelId: z$1.string().default("gpt-4o-mini"),
|
|
7128
|
+
embargoHours: z$1.number().min(0).max(168).default(12),
|
|
7129
|
+
denylist: z$1.array(z$1.string()).default([]),
|
|
7130
|
+
slackTeamId: z$1.string().optional(),
|
|
7131
|
+
slackChannelId: z$1.string().optional()
|
|
7132
|
+
});
|
|
7133
|
+
/**
|
|
7134
|
+
* A release note as GET /api/v1/whats-new serves it. An allowlist: provenance (sourcePrs, deployedSha),
|
|
7135
|
+
* workflow state (status, editedAt) and storage fields never reach the public wire.
|
|
7136
|
+
*/
|
|
7137
|
+
const PublicReleaseNoteSchema = z$1.object({
|
|
7138
|
+
id: z$1.string(),
|
|
7139
|
+
release_tag: z$1.string(),
|
|
7140
|
+
headline: z$1.string(),
|
|
7141
|
+
summary: z$1.string(),
|
|
7142
|
+
published_at: z$1.string(),
|
|
7143
|
+
items: z$1.array(z$1.object({
|
|
7144
|
+
category: ReleaseNoteCategorySchema,
|
|
7145
|
+
text: z$1.string(),
|
|
7146
|
+
importance: z$1.number().int().min(1).max(3)
|
|
7147
|
+
}))
|
|
7148
|
+
});
|
|
7149
|
+
/**
|
|
6593
7150
|
* The measured per-space floors, rendered for an admin-facing description (e.g. "75 for
|
|
6594
7151
|
* text-embedding-ada-002, 58 for text-embedding-3-small").
|
|
6595
7152
|
*
|
|
@@ -6597,10 +7154,7 @@ const SupportedEmbeddingModelSchema = z$1.union([
|
|
|
6597
7154
|
* against a production lake, and a description that restates the table is a wrong number shown to
|
|
6598
7155
|
* operators the moment it drifts, with nothing failing.
|
|
6599
7156
|
*/
|
|
6600
|
-
const forcedRetrievalFloorsBySpaceSummary = Object.entries({
|
|
6601
|
-
["text-embedding-ada-002"]: 75,
|
|
6602
|
-
["text-embedding-3-small"]: 58
|
|
6603
|
-
}).map(([space, pct]) => `${pct} for ${space}`).join(", ");
|
|
7157
|
+
const forcedRetrievalFloorsBySpaceSummary = Object.entries(FORCED_RETRIEVAL_MIN_SIMILARITY_PCT_BY_SPACE).map(([space, pct]) => `${pct} for ${space}`).join(", ");
|
|
6604
7158
|
/**
|
|
6605
7159
|
* Default text for the artifact-emission system prompt. Single source of truth used BOTH as the
|
|
6606
7160
|
* `ArtifactEmissionPrompt` admin setting's default AND as the runtime fallback in
|
|
@@ -6827,6 +7381,7 @@ z$1.enum([
|
|
|
6827
7381
|
"EnforceLakeReadGrants",
|
|
6828
7382
|
"EnableDataLakeDrivePoll",
|
|
6829
7383
|
"EnableDataLakeGitHub",
|
|
7384
|
+
"EnableDataLakeGitHubReconcile",
|
|
6830
7385
|
"EnforceLakeAdmission",
|
|
6831
7386
|
"EnforceLakeOriginOnIngest",
|
|
6832
7387
|
"EnableBriefcase",
|
|
@@ -6970,6 +7525,7 @@ z$1.enum([
|
|
|
6970
7525
|
"whatsNewAutomationEnabled",
|
|
6971
7526
|
"whatsNewConfig",
|
|
6972
7527
|
"whatsNewSyncConfig",
|
|
7528
|
+
"releaseNotesConfig",
|
|
6973
7529
|
"enableAgentProactiveMessages",
|
|
6974
7530
|
"EnableEnhancedDateTime",
|
|
6975
7531
|
"EnableHistoricalFeatures",
|
|
@@ -7006,6 +7562,7 @@ z$1.enum([
|
|
|
7006
7562
|
"apiRateLimitProPerMin",
|
|
7007
7563
|
"overwatchRollupSync",
|
|
7008
7564
|
"orchestrationDefaults",
|
|
7565
|
+
"videoGeneration",
|
|
7009
7566
|
"enableModelDiscovery",
|
|
7010
7567
|
"modelDiscoveryMode",
|
|
7011
7568
|
"modelDiscoveryAutoEnable",
|
|
@@ -7252,6 +7809,7 @@ const RapidReplySettingsSchema = z$1.object({
|
|
|
7252
7809
|
lastUpdated: /* @__PURE__ */ new Date()
|
|
7253
7810
|
})
|
|
7254
7811
|
});
|
|
7812
|
+
const VideoGenerationSettingsSchema = z$1.object({ enabledModels: z$1.record(z$1.string(), z$1.boolean()).prefault({}) });
|
|
7255
7813
|
/**
|
|
7256
7814
|
* Canonical repository and branch the What's New generator reads from.
|
|
7257
7815
|
*
|
|
@@ -8899,6 +9457,16 @@ const settingsMap = {
|
|
|
8899
9457
|
order: 96,
|
|
8900
9458
|
dependsOn: "EnableDataLakes"
|
|
8901
9459
|
}),
|
|
9460
|
+
EnableDataLakeGitHubReconcile: makeBooleanSetting({
|
|
9461
|
+
key: "EnableDataLakeGitHubReconcile",
|
|
9462
|
+
name: "Data Lakes: GitHub scheduled reconcile",
|
|
9463
|
+
defaultValue: false,
|
|
9464
|
+
description: "Server-side gate for the scheduled check that compares each connected GitHub repository's default-branch HEAD with the last synced commit and queues a sync when they differ, so a missed or dropped push webhook still reaches the lake. Off by default - pushes still sync through the webhook and the Re-sync button; turn this on to also reconcile on a schedule.",
|
|
9465
|
+
category: "Experimental",
|
|
9466
|
+
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
|
|
9467
|
+
order: 96,
|
|
9468
|
+
dependsOn: "EnableDataLakeGitHub"
|
|
9469
|
+
}),
|
|
8902
9470
|
EnforceLakeAdmission: makeBooleanSetting({
|
|
8903
9471
|
key: "EnforceLakeAdmission",
|
|
8904
9472
|
name: "Data Lakes: Enforce the admission contract",
|
|
@@ -10652,6 +11220,15 @@ const settingsMap = {
|
|
|
10652
11220
|
order: 102,
|
|
10653
11221
|
schema: WhatsNewSyncConfigSchema
|
|
10654
11222
|
}),
|
|
11223
|
+
releaseNotesConfig: makeObjectSetting({
|
|
11224
|
+
key: "releaseNotesConfig",
|
|
11225
|
+
name: "Release Notes Configuration",
|
|
11226
|
+
defaultValue: ReleaseNotesConfigSchema.parse({}),
|
|
11227
|
+
description: "Customer-facing release notes generated from each production release. Disabled by default. Sets the model, the embargo before a note becomes visible, a denylist of terms that must never appear, and the Slack channel that gets the pre-publish preview.",
|
|
11228
|
+
category: "Admin",
|
|
11229
|
+
order: 103,
|
|
11230
|
+
schema: ReleaseNotesConfigSchema
|
|
11231
|
+
}),
|
|
10655
11232
|
enableAgentProactiveMessages: makeBooleanSetting({
|
|
10656
11233
|
key: "enableAgentProactiveMessages",
|
|
10657
11234
|
name: "Enable Agent Proactive Messages",
|
|
@@ -11004,6 +11581,16 @@ const settingsMap = {
|
|
|
11004
11581
|
order: 140,
|
|
11005
11582
|
schema: OrchestrationDefaultsSchema
|
|
11006
11583
|
}),
|
|
11584
|
+
videoGeneration: makeObjectSetting({
|
|
11585
|
+
key: "videoGeneration",
|
|
11586
|
+
userReadable: true,
|
|
11587
|
+
name: "Video Generation",
|
|
11588
|
+
defaultValue: VideoGenerationSettingsSchema.parse({}),
|
|
11589
|
+
description: "Enable or disable individual video generation models. Models without an override use their built-in default.",
|
|
11590
|
+
category: "AI",
|
|
11591
|
+
order: 145,
|
|
11592
|
+
schema: VideoGenerationSettingsSchema
|
|
11593
|
+
}),
|
|
11007
11594
|
enableModelDiscovery: makeBooleanSetting({
|
|
11008
11595
|
key: "enableModelDiscovery",
|
|
11009
11596
|
name: "Enable Model Discovery",
|
|
@@ -11103,352 +11690,37 @@ const settingsMap = {
|
|
|
11103
11690
|
}),
|
|
11104
11691
|
prReportEgressAllowlist: makeObjectSetting({
|
|
11105
11692
|
key: "prReportEgressAllowlist",
|
|
11106
|
-
name: "PR Report Egress Allowlist",
|
|
11107
|
-
defaultValue: { hosts: ["hooks.slack.com"] },
|
|
11108
|
-
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.",
|
|
11109
|
-
category: "Slack",
|
|
11110
|
-
order: 144,
|
|
11111
|
-
schema: z$1.object({ hosts: z$1.array(z$1.string()).default([]) })
|
|
11112
|
-
})
|
|
11113
|
-
};
|
|
11114
|
-
/**
|
|
11115
|
-
* Experimental setting keys the client reads but that intentionally live OUTSIDE
|
|
11116
|
-
* the `EXPERIMENTAL` group, so the group rule below can't pick them up:
|
|
11117
|
-
* - `EnableContextTelemetry` - category `Admin` (rendered in the telemetry card),
|
|
11118
|
-
* read as an experimental admin gate.
|
|
11119
|
-
*
|
|
11120
|
-
* Exported so the guard test asserts against this exact list rather than keeping a
|
|
11121
|
-
* second hand-copied array (which would re-introduce two-place drift).
|
|
11122
|
-
*/
|
|
11123
|
-
const experimentalNonGroupSettingKeys = ["EnableContextTelemetry"];
|
|
11124
|
-
(() => {
|
|
11125
|
-
const groupKeys = Object.values(settingsMap).filter((s) => s.group === API_SERVICE_GROUPS.EXPERIMENTAL.id).map((s) => s.key);
|
|
11126
|
-
return Array.from(/* @__PURE__ */ new Set([...groupKeys, ...experimentalNonGroupSettingKeys]));
|
|
11127
|
-
})();
|
|
11128
|
-
z$1.preprocess((val) => {
|
|
11129
|
-
if (typeof val === "string") {
|
|
11130
|
-
if (val.toLowerCase() === "true") return true;
|
|
11131
|
-
if (val.toLowerCase() === "false") return false;
|
|
11132
|
-
}
|
|
11133
|
-
return val;
|
|
11134
|
-
}, z$1.boolean());
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
hash: z$1.string(),
|
|
11138
|
-
/** YYYY-MM-DD for salt lookup during deletion */
|
|
11139
|
-
dateKey: z$1.string()
|
|
11140
|
-
});
|
|
11141
|
-
const SpanContextSchema = z$1.object({
|
|
11142
|
-
/** gen_ai.trace_id */
|
|
11143
|
-
traceId: z$1.string(),
|
|
11144
|
-
/** gen_ai.span_id */
|
|
11145
|
-
spanId: z$1.string()
|
|
11146
|
-
});
|
|
11147
|
-
const OperationSchema = z$1.object({
|
|
11148
|
-
name: z$1.enum([
|
|
11149
|
-
"chat_completion",
|
|
11150
|
-
"agent_invoke",
|
|
11151
|
-
"tool_execute"
|
|
11152
|
-
]),
|
|
11153
|
-
finishReason: z$1.enum([
|
|
11154
|
-
"stop",
|
|
11155
|
-
"length",
|
|
11156
|
-
"tool_use",
|
|
11157
|
-
"content_filter",
|
|
11158
|
-
"error"
|
|
11159
|
-
]).optional()
|
|
11160
|
-
});
|
|
11161
|
-
const ModelTelemetrySchema = z$1.object({
|
|
11162
|
-
/** gen_ai.request.model */
|
|
11163
|
-
modelId: z$1.string(),
|
|
11164
|
-
provider: z$1.enum([
|
|
11165
|
-
"anthropic",
|
|
11166
|
-
"openai",
|
|
11167
|
-
"bedrock",
|
|
11168
|
-
"google",
|
|
11169
|
-
"xai",
|
|
11170
|
-
"ollama",
|
|
11171
|
-
"moonshot",
|
|
11172
|
-
"deepseek"
|
|
11173
|
-
]),
|
|
11174
|
-
fallbackUsed: z$1.boolean(),
|
|
11175
|
-
fallbackReason: z$1.string().optional(),
|
|
11176
|
-
originalModelId: z$1.string().optional(),
|
|
11177
|
-
usedThinking: z$1.boolean(),
|
|
11178
|
-
/** Extended thinking tokens */
|
|
11179
|
-
thinkingTokensUsed: z$1.number().optional(),
|
|
11180
|
-
usedTools: z$1.boolean()
|
|
11181
|
-
});
|
|
11182
|
-
const SystemPromptDetailSchema = z$1.object({
|
|
11183
|
-
source: z$1.enum([
|
|
11184
|
-
"hardcoded",
|
|
11185
|
-
"admin",
|
|
11186
|
-
"user",
|
|
11187
|
-
"project",
|
|
11188
|
-
"session",
|
|
11189
|
-
"org",
|
|
11190
|
-
"caller"
|
|
11191
|
-
]),
|
|
11192
|
-
/** e.g., "date_context", "tool_guidance" */
|
|
11193
|
-
name: z$1.string(),
|
|
11194
|
-
tokenCount: z$1.number(),
|
|
11195
|
-
wasIncluded: z$1.boolean(),
|
|
11196
|
-
exclusionReason: z$1.enum([
|
|
11197
|
-
"duplicate",
|
|
11198
|
-
"disabled",
|
|
11199
|
-
"token_limit"
|
|
11200
|
-
]).optional()
|
|
11201
|
-
});
|
|
11202
|
-
const SystemPromptsTelemetrySchema = z$1.object({
|
|
11203
|
-
prompts: z$1.array(SystemPromptDetailSchema),
|
|
11204
|
-
totalTokens: z$1.number(),
|
|
11205
|
-
duplicateCount: z$1.number()
|
|
11206
|
-
});
|
|
11207
|
-
const FeatureContributionSchema = z$1.object({
|
|
11208
|
-
/** e.g., "mementos", "quest_master", "deep_research" */
|
|
11209
|
-
featureName: z$1.string(),
|
|
11210
|
-
messagesAdded: z$1.number(),
|
|
11211
|
-
tokenCount: z$1.number(),
|
|
11212
|
-
executionTimeMs: z$1.number(),
|
|
11213
|
-
success: z$1.boolean(),
|
|
11214
|
-
errorType: z$1.string().optional()
|
|
11215
|
-
});
|
|
11216
|
-
const FeaturesTelemetrySchema = z$1.object({ contributions: z$1.array(FeatureContributionSchema) });
|
|
11217
|
-
const TokensBySourceSchema = z$1.object({
|
|
11218
|
-
systemPrompts: z$1.number(),
|
|
11219
|
-
conversationHistory: z$1.number(),
|
|
11220
|
-
mementos: z$1.number(),
|
|
11221
|
-
fabFiles: z$1.number(),
|
|
11222
|
-
urlContent: z$1.number(),
|
|
11223
|
-
toolSchemas: z$1.number(),
|
|
11224
|
-
userPrompt: z$1.number(),
|
|
11225
|
-
/**
|
|
11226
|
-
* Lake-sourced content injected this turn (forced retrieval + the lake-memory hot card), split out
|
|
11227
|
-
* of `systemPrompts`. Optional and absent means UNKNOWN, never zero - telemetry captured before
|
|
11228
|
-
* this bucket existed has no value to report and must not be read as "no lake content". Mirrors
|
|
11229
|
-
* PromptMetaTokensBySourceSchema in promptMeta.ts.
|
|
11230
|
-
*/
|
|
11231
|
-
lakeRetrieval: z$1.number().optional()
|
|
11232
|
-
});
|
|
11233
|
-
z$1.object({
|
|
11234
|
-
/** gen_ai.usage.input_tokens */
|
|
11235
|
-
inputTokens: z$1.number(),
|
|
11236
|
-
/** gen_ai.usage.output_tokens */
|
|
11237
|
-
outputTokens: z$1.number(),
|
|
11238
|
-
contextWindowLimit: z$1.number(),
|
|
11239
|
-
utilizationPercentage: z$1.number(),
|
|
11240
|
-
reservedOutputTokens: z$1.number(),
|
|
11241
|
-
overflowDetected: z$1.boolean(),
|
|
11242
|
-
overflowAmount: z$1.number().optional(),
|
|
11243
|
-
/** Token breakdown by source */
|
|
11244
|
-
tokensBySource: TokensBySourceSchema
|
|
11245
|
-
});
|
|
11246
|
-
const CacheTelemetrySchema = z$1.object({
|
|
11247
|
-
/** Anthropic cache_read_input_tokens */
|
|
11248
|
-
cacheReadTokens: z$1.number(),
|
|
11249
|
-
/** Anthropic cache_creation_input_tokens */
|
|
11250
|
-
cacheWriteTokens: z$1.number(),
|
|
11251
|
-
/** 0-100% */
|
|
11252
|
-
cacheHitRate: z$1.number(),
|
|
11253
|
-
costSavingsPercent: z$1.number().optional()
|
|
11254
|
-
});
|
|
11255
|
-
const CostsTelemetrySchema = z$1.object({
|
|
11256
|
-
inputCostUsd: z$1.number(),
|
|
11257
|
-
outputCostUsd: z$1.number(),
|
|
11258
|
-
totalCostUsd: z$1.number(),
|
|
11259
|
-
creditsUsed: z$1.number()
|
|
11260
|
-
});
|
|
11261
|
-
const TruncationTelemetrySchema = z$1.object({
|
|
11262
|
-
wasTruncated: z$1.boolean(),
|
|
11263
|
-
originalMessageCount: z$1.number(),
|
|
11264
|
-
finalMessageCount: z$1.number(),
|
|
11265
|
-
truncatedMessageCount: z$1.number(),
|
|
11266
|
-
truncationMethod: z$1.enum([
|
|
11267
|
-
"priority",
|
|
11268
|
-
"token-budget",
|
|
11269
|
-
"history-limit",
|
|
11270
|
-
"context-overflow"
|
|
11271
|
-
]).optional(),
|
|
11272
|
-
truncationPercentage: z$1.number()
|
|
11273
|
-
});
|
|
11274
|
-
const ToolErrorCategorySchema = z$1.enum([
|
|
11275
|
-
"timeout",
|
|
11276
|
-
"rate_limit",
|
|
11277
|
-
"auth_error",
|
|
11278
|
-
"validation_error",
|
|
11279
|
-
"network_error",
|
|
11280
|
-
"internal_error"
|
|
11281
|
-
]);
|
|
11282
|
-
const ToolTelemetrySchema = z$1.object({
|
|
11283
|
-
toolName: z$1.string(),
|
|
11284
|
-
/** MCP vs native tool */
|
|
11285
|
-
isMcpTool: z$1.boolean(),
|
|
11286
|
-
/** For MCP tools */
|
|
11287
|
-
mcpServerName: z$1.string().optional(),
|
|
11288
|
-
invocationCount: z$1.number(),
|
|
11289
|
-
successCount: z$1.number(),
|
|
11290
|
-
failureCount: z$1.number(),
|
|
11291
|
-
totalDurationMs: z$1.number(),
|
|
11292
|
-
maxDurationMs: z$1.number(),
|
|
11293
|
-
/** Retry tracking */
|
|
11294
|
-
retryCount: z$1.number(),
|
|
11295
|
-
/** Max 200 chars */
|
|
11296
|
-
lastError: z$1.string().max(200).optional(),
|
|
11297
|
-
errorCategories: z$1.array(ToolErrorCategorySchema).optional(),
|
|
11298
|
-
/**
|
|
11299
|
-
* Content-size metrics for tools that extract text (currently web_fetch, issue #452).
|
|
11300
|
-
* Zero-PII integer counts, so kept at both basic and enhanced capture levels.
|
|
11301
|
-
*/
|
|
11302
|
-
/** Count of unique truncated citables at the tool's size cap (citables dedupe by url,
|
|
11303
|
-
* so same-url refetches within a completion collapse to one - see WebFetchContentTelemetry). */
|
|
11304
|
-
truncatedInvocationCount: z$1.number().optional(),
|
|
11305
|
-
/** Largest single extracted (post-cap) content length across invocations. */
|
|
11306
|
-
maxExtractedChars: z$1.number().optional(),
|
|
11307
|
-
/** Sum of extracted (post-cap) content length across invocations. */
|
|
11308
|
-
totalExtractedChars: z$1.number().optional()
|
|
11309
|
-
});
|
|
11310
|
-
const SubagentTelemetrySchema = z$1.object({
|
|
11311
|
-
agentName: z$1.string(),
|
|
11312
|
-
delegationCount: z$1.number(),
|
|
11313
|
-
successCount: z$1.number(),
|
|
11314
|
-
failureCount: z$1.number(),
|
|
11315
|
-
timeoutCount: z$1.number(),
|
|
11316
|
-
totalDurationMs: z$1.number(),
|
|
11317
|
-
totalTokensUsed: z$1.number(),
|
|
11318
|
-
thoroughness: z$1.enum([
|
|
11319
|
-
"quick",
|
|
11320
|
-
"medium",
|
|
11321
|
-
"very_thorough"
|
|
11322
|
-
]).optional()
|
|
11323
|
-
});
|
|
11324
|
-
const LatencyPercentilesSchema = z$1.object({
|
|
11325
|
-
p50Ms: z$1.number(),
|
|
11326
|
-
p95Ms: z$1.number(),
|
|
11327
|
-
p99Ms: z$1.number()
|
|
11328
|
-
});
|
|
11329
|
-
const PerformanceTelemetrySchema = z$1.object({
|
|
11330
|
-
totalResponseTimeMs: z$1.number(),
|
|
11331
|
-
firstTokenTimeMs: z$1.number().optional(),
|
|
11332
|
-
contextRetrievalMs: z$1.number().optional(),
|
|
11333
|
-
modelInferenceMs: z$1.number().optional(),
|
|
11334
|
-
toolExecutionMs: z$1.number().optional(),
|
|
11335
|
-
/** Latency percentiles for trend analysis */
|
|
11336
|
-
latencyPercentiles: LatencyPercentilesSchema.optional()
|
|
11337
|
-
});
|
|
11338
|
-
const AnomalySeveritySchema = z$1.enum([
|
|
11339
|
-
"critical",
|
|
11340
|
-
"high",
|
|
11341
|
-
"medium",
|
|
11342
|
-
"low"
|
|
11343
|
-
]);
|
|
11344
|
-
const PrimaryAnomalySchema = z$1.enum([
|
|
11345
|
-
"none",
|
|
11346
|
-
"context_overflow",
|
|
11347
|
-
"high_utilization",
|
|
11348
|
-
"high_truncation",
|
|
11349
|
-
"tool_failure",
|
|
11350
|
-
"subagent_timeout",
|
|
11351
|
-
"slow_response",
|
|
11352
|
-
"multiple"
|
|
11353
|
-
]);
|
|
11354
|
-
const AnomaliesTelemetrySchema = z$1.object({
|
|
11355
|
-
contextOverflow: z$1.boolean(),
|
|
11356
|
-
/** >= 90% */
|
|
11357
|
-
highUtilization: z$1.boolean(),
|
|
11358
|
-
/** >= 95% */
|
|
11359
|
-
criticalUtilization: z$1.boolean(),
|
|
11360
|
-
/** >= 50% */
|
|
11361
|
-
highTruncation: z$1.boolean(),
|
|
11362
|
-
/** >= 75% */
|
|
11363
|
-
criticalTruncation: z$1.boolean(),
|
|
11364
|
-
/** >= 3 failures */
|
|
11365
|
-
toolFailureSpike: z$1.boolean(),
|
|
11366
|
-
/** > 30s */
|
|
11367
|
-
toolTimeout: z$1.boolean(),
|
|
11368
|
-
/** > 5min */
|
|
11369
|
-
subagentTimeout: z$1.boolean(),
|
|
11370
|
-
/** > 10s */
|
|
11371
|
-
slowFirstToken: z$1.boolean(),
|
|
11372
|
-
/** > 60s */
|
|
11373
|
-
slowTotalResponse: z$1.boolean(),
|
|
11374
|
-
/** 0-100 */
|
|
11375
|
-
anomalyScore: z$1.number().min(0).max(100),
|
|
11376
|
-
/** Severity mapping */
|
|
11377
|
-
severity: AnomalySeveritySchema,
|
|
11378
|
-
/** Pattern-based dedup key, e.g., "tool_failure_claude-3-5-sonnet_delegate-to-agent" */
|
|
11379
|
-
dedupKey: z$1.string(),
|
|
11380
|
-
primaryAnomaly: PrimaryAnomalySchema
|
|
11381
|
-
});
|
|
11382
|
-
const RequestMetadataSchema = z$1.object({
|
|
11383
|
-
queryComplexity: z$1.enum([
|
|
11384
|
-
"simple",
|
|
11385
|
-
"contextual",
|
|
11386
|
-
"complex"
|
|
11387
|
-
]),
|
|
11388
|
-
historyMessageCount: z$1.number(),
|
|
11389
|
-
attachedFileCount: z$1.number(),
|
|
11390
|
-
mementoCount: z$1.number(),
|
|
11391
|
-
enabledFeatures: z$1.array(z$1.string())
|
|
11392
|
-
});
|
|
11393
|
-
const ContextWindowTelemetryWithOptionalSourceSchema = z$1.object({
|
|
11394
|
-
/** gen_ai.usage.input_tokens */
|
|
11395
|
-
inputTokens: z$1.number(),
|
|
11396
|
-
/** gen_ai.usage.output_tokens */
|
|
11397
|
-
outputTokens: z$1.number(),
|
|
11398
|
-
contextWindowLimit: z$1.number(),
|
|
11399
|
-
utilizationPercentage: z$1.number(),
|
|
11400
|
-
reservedOutputTokens: z$1.number(),
|
|
11401
|
-
overflowDetected: z$1.boolean(),
|
|
11402
|
-
overflowAmount: z$1.number().optional(),
|
|
11403
|
-
/** Token breakdown by source (enhanced only) */
|
|
11404
|
-
tokensBySource: TokensBySourceSchema.optional()
|
|
11405
|
-
});
|
|
11406
|
-
const ContextTelemetrySchema = z$1.object({
|
|
11407
|
-
schemaVersion: z$1.enum([
|
|
11408
|
-
"1.0",
|
|
11409
|
-
"1.1",
|
|
11410
|
-
"1.2"
|
|
11411
|
-
]),
|
|
11412
|
-
/** ISO 8601 */
|
|
11413
|
-
timestamp: z$1.string(),
|
|
11414
|
-
/** Self-monitoring: time to capture telemetry */
|
|
11415
|
-
captureOverheadMs: z$1.number(),
|
|
11416
|
-
/** Capture level: basic or enhanced */
|
|
11417
|
-
captureLevel: z$1.enum(["basic", "enhanced"]).optional(),
|
|
11418
|
-
anonymousSessionId: AnonymousSessionIdSchema,
|
|
11419
|
-
spanContext: SpanContextSchema.optional(),
|
|
11420
|
-
operation: OperationSchema,
|
|
11421
|
-
model: ModelTelemetrySchema,
|
|
11422
|
-
systemPrompts: SystemPromptsTelemetrySchema.optional(),
|
|
11423
|
-
features: FeaturesTelemetrySchema.optional(),
|
|
11424
|
-
contextWindow: ContextWindowTelemetryWithOptionalSourceSchema,
|
|
11425
|
-
cache: CacheTelemetrySchema.optional(),
|
|
11426
|
-
costs: CostsTelemetrySchema,
|
|
11427
|
-
truncation: TruncationTelemetrySchema.optional(),
|
|
11428
|
-
tools: z$1.array(ToolTelemetrySchema).optional(),
|
|
11429
|
-
subagents: z$1.array(SubagentTelemetrySchema).optional(),
|
|
11430
|
-
performance: PerformanceTelemetrySchema,
|
|
11431
|
-
anomalies: AnomaliesTelemetrySchema,
|
|
11432
|
-
requestMetadata: RequestMetadataSchema.optional(),
|
|
11433
|
-
captureErrors: z$1.array(z$1.string()).optional()
|
|
11434
|
-
});
|
|
11435
|
-
z$1.object({
|
|
11436
|
-
avgResponseTimeMs: z$1.number(),
|
|
11437
|
-
p95ResponseTimeMs: z$1.number(),
|
|
11438
|
-
avgUtilization: z$1.number(),
|
|
11439
|
-
utilizationRange: z$1.object({
|
|
11440
|
-
low: z$1.number(),
|
|
11441
|
-
high: z$1.number()
|
|
11442
|
-
}),
|
|
11443
|
-
sampleCount: z$1.number(),
|
|
11444
|
-
windowDays: z$1.number()
|
|
11445
|
-
});
|
|
11446
|
-
z$1.enum([
|
|
11447
|
-
"no_action",
|
|
11448
|
-
"monitor",
|
|
11449
|
-
"investigate_soon",
|
|
11450
|
-
"immediate_action"
|
|
11451
|
-
]);
|
|
11693
|
+
name: "PR Report Egress Allowlist",
|
|
11694
|
+
defaultValue: { hosts: ["hooks.slack.com"] },
|
|
11695
|
+
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.",
|
|
11696
|
+
category: "Slack",
|
|
11697
|
+
order: 144,
|
|
11698
|
+
schema: z$1.object({ hosts: z$1.array(z$1.string()).default([]) })
|
|
11699
|
+
})
|
|
11700
|
+
};
|
|
11701
|
+
/**
|
|
11702
|
+
* Experimental setting keys the client reads but that intentionally live OUTSIDE
|
|
11703
|
+
* the `EXPERIMENTAL` group, so the group rule below can't pick them up:
|
|
11704
|
+
* - `EnableContextTelemetry` - category `Admin` (rendered in the telemetry card),
|
|
11705
|
+
* read as an experimental admin gate.
|
|
11706
|
+
*
|
|
11707
|
+
* Exported so the guard test asserts against this exact list rather than keeping a
|
|
11708
|
+
* second hand-copied array (which would re-introduce two-place drift).
|
|
11709
|
+
*/
|
|
11710
|
+
const experimentalNonGroupSettingKeys = ["EnableContextTelemetry"];
|
|
11711
|
+
(() => {
|
|
11712
|
+
const groupKeys = Object.values(settingsMap).filter((s) => s.group === API_SERVICE_GROUPS.EXPERIMENTAL.id).map((s) => s.key);
|
|
11713
|
+
return Array.from(/* @__PURE__ */ new Set([...groupKeys, ...experimentalNonGroupSettingKeys]));
|
|
11714
|
+
})();
|
|
11715
|
+
z$1.preprocess((val) => {
|
|
11716
|
+
if (typeof val === "string") {
|
|
11717
|
+
if (val.toLowerCase() === "true") return true;
|
|
11718
|
+
if (val.toLowerCase() === "false") return false;
|
|
11719
|
+
}
|
|
11720
|
+
return val;
|
|
11721
|
+
}, z$1.boolean());
|
|
11722
|
+
/** Splits on the marker tokens, keeping them in the result so a scan can track nesting depth. */
|
|
11723
|
+
const THINK_TAG_TOKENS = /(<think>|<\/think>)/g;
|
|
11452
11724
|
/**
|
|
11453
11725
|
* Zero-width space spliced into a defanged marker. It is invisible wherever the text is
|
|
11454
11726
|
* rendered, so escaping never changes what the reader sees - only what the parser matches.
|
|
@@ -11513,6 +11785,52 @@ function createThinkMarkerEscaper() {
|
|
|
11513
11785
|
};
|
|
11514
11786
|
}
|
|
11515
11787
|
/**
|
|
11788
|
+
* The visible remainder of one reply slot, with hidden reasoning removed.
|
|
11789
|
+
*
|
|
11790
|
+
* This is the rule the chat transcript renders by - `extractReplies` in
|
|
11791
|
+
* apps/client/shared/replyUtils.ts calls straight into it, so the two cannot drift.
|
|
11792
|
+
* Anything deriving "did the user see something yet" (latency metrics in particular) must
|
|
11793
|
+
* use this and not a looser non-empty check: a metric built on a looser rule reports text
|
|
11794
|
+
* as seen while the UI is still hiding it.
|
|
11795
|
+
*
|
|
11796
|
+
* Thinking is removed span by span rather than by keeping the tail after the last close
|
|
11797
|
+
* marker. A turn that answers, calls a tool and then thinks again reopens its thinking
|
|
11798
|
+
* inside the slot that already holds the partial answer (the provider restarts its
|
|
11799
|
+
* content-block indices - see appendStreamedChunk), so a tail rule would drop text the user
|
|
11800
|
+
* has already watched stream in. An unclosed trailing marker hides everything after it, so a
|
|
11801
|
+
* reopened block does not render its raw marker while it streams.
|
|
11802
|
+
*
|
|
11803
|
+
* Markers are tracked by nesting depth rather than matched pairwise, because reasoning text
|
|
11804
|
+
* is provider-authored and can itself contain marker-shaped substrings (a model reasoning
|
|
11805
|
+
* about the `<think>` protocol, say). A naive non-greedy pair match on
|
|
11806
|
+
* `<think>outer<think>inner</think>tail</think>answer` would strip only the innermost pair
|
|
11807
|
+
* and let `tail` leak into the transcript; walking depth instead keeps everything between an
|
|
11808
|
+
* open and its matching close hidden regardless of what markers appear in between, and an
|
|
11809
|
+
* unmatched trailing `</think>` (depth already zero) is treated as ordinary text rather than
|
|
11810
|
+
* closing something that was never open.
|
|
11811
|
+
*
|
|
11812
|
+
* Interior whitespace is preserved: callers concatenate slots with no separator, so trimming
|
|
11813
|
+
* every slot would weld a heading onto the table beneath it.
|
|
11814
|
+
*/
|
|
11815
|
+
function visibleReplyText(part) {
|
|
11816
|
+
if (!part || !part.trim()) return "";
|
|
11817
|
+
let depth = 0;
|
|
11818
|
+
let visible = "";
|
|
11819
|
+
for (const token of part.split(THINK_TAG_TOKENS)) if (token === "<think>") depth += 1;
|
|
11820
|
+
else if (token === "</think>") if (depth > 0) depth -= 1;
|
|
11821
|
+
else visible += token;
|
|
11822
|
+
else if (depth === 0) visible += token;
|
|
11823
|
+
return visible.trim() ? visible : "";
|
|
11824
|
+
}
|
|
11825
|
+
/**
|
|
11826
|
+
* Joins visible reply slots into one string. Each slot is a separate content block, so a slot that
|
|
11827
|
+
* does not end in a newline gets a paragraph break; with a bare join a closing code fence would
|
|
11828
|
+
* land on the same line as the next slot's text and never close.
|
|
11829
|
+
*/
|
|
11830
|
+
function joinReplySlots(parts) {
|
|
11831
|
+
return parts.reduce((joined, part) => !joined || joined.endsWith("\n") ? joined + part : `${joined}\n\n${part}`, "");
|
|
11832
|
+
}
|
|
11833
|
+
/**
|
|
11516
11834
|
* Reply choices: the discrete next steps a reply offers, rendered as numbered buttons.
|
|
11517
11835
|
*
|
|
11518
11836
|
* The model ends a reply with a fenced `choices` block; the server strips it with
|
|
@@ -11532,6 +11850,173 @@ const REPLY_CHOICES_INVALID_REASONS = [
|
|
|
11532
11850
|
"unterminated",
|
|
11533
11851
|
"think_unclosed"
|
|
11534
11852
|
];
|
|
11853
|
+
const ABSENT = { status: "absent" };
|
|
11854
|
+
const invalid = (reason) => ({
|
|
11855
|
+
status: "invalid",
|
|
11856
|
+
reason
|
|
11857
|
+
});
|
|
11858
|
+
const FENCE_OPEN_LINE = /^[ \t]*(`{3,}|~{3,})(.*)$/;
|
|
11859
|
+
const FENCE_CLOSE_LINE = /^[ \t]*(`{3,}|~{3,})[ \t]*$/;
|
|
11860
|
+
/**
|
|
11861
|
+
* Offset where a slot's visible answer starts: just past its last top-level `</think>`, 0 when it
|
|
11862
|
+
* has none, or null while a `<think>` is still open. Depth-tracked to match visibleReplyText in
|
|
11863
|
+
* ./streamVisibility.ts, so a marker-shaped string inside reasoning cannot end it early.
|
|
11864
|
+
*/
|
|
11865
|
+
function answerStart(reply) {
|
|
11866
|
+
let depth = 0;
|
|
11867
|
+
let start = 0;
|
|
11868
|
+
for (const marker of reply.matchAll(/<\/?think>/g)) if (marker[0] === "<think>") depth += 1;
|
|
11869
|
+
else if (depth > 0) {
|
|
11870
|
+
depth -= 1;
|
|
11871
|
+
if (depth === 0) start = (marker.index ?? 0) + marker[0].length;
|
|
11872
|
+
}
|
|
11873
|
+
return depth === 0 ? start : null;
|
|
11874
|
+
}
|
|
11875
|
+
/**
|
|
11876
|
+
* The last top-level ```choices fence in `text`, walking fences line by line (CommonMark rules: a
|
|
11877
|
+
* fence closes on a bare line of the same character at least as long), so a choices sample nested
|
|
11878
|
+
* inside a longer outer fence is content rather than a block.
|
|
11879
|
+
*/
|
|
11880
|
+
function findLastChoicesFence(text) {
|
|
11881
|
+
let last = null;
|
|
11882
|
+
let open = null;
|
|
11883
|
+
let lineStart = 0;
|
|
11884
|
+
while (lineStart <= text.length) {
|
|
11885
|
+
const newline = text.indexOf("\n", lineStart);
|
|
11886
|
+
const lineEnd = newline === -1 ? text.length : newline;
|
|
11887
|
+
const line = text.slice(lineStart, lineEnd).replace(/\r$/, "");
|
|
11888
|
+
if (!open) {
|
|
11889
|
+
const match = line.match(FENCE_OPEN_LINE);
|
|
11890
|
+
if (match && !(match[1][0] === "`" && match[2].includes("`"))) open = {
|
|
11891
|
+
start: lineStart,
|
|
11892
|
+
bodyStart: newline === -1 ? text.length : newline + 1,
|
|
11893
|
+
marker: match[1],
|
|
11894
|
+
isChoices: match[1] === "```" && match[2].trim().toLowerCase() === "choices"
|
|
11895
|
+
};
|
|
11896
|
+
} else {
|
|
11897
|
+
const match = line.match(FENCE_CLOSE_LINE);
|
|
11898
|
+
if (match && match[1][0] === open.marker[0] && match[1].length >= open.marker.length) {
|
|
11899
|
+
if (open.isChoices) last = {
|
|
11900
|
+
start: open.start,
|
|
11901
|
+
end: lineEnd,
|
|
11902
|
+
body: text.slice(open.bodyStart, lineStart)
|
|
11903
|
+
};
|
|
11904
|
+
open = null;
|
|
11905
|
+
}
|
|
11906
|
+
}
|
|
11907
|
+
if (newline === -1) break;
|
|
11908
|
+
lineStart = newline + 1;
|
|
11909
|
+
}
|
|
11910
|
+
if (open?.isChoices) last = {
|
|
11911
|
+
start: open.start,
|
|
11912
|
+
end: null,
|
|
11913
|
+
body: text.slice(open.bodyStart)
|
|
11914
|
+
};
|
|
11915
|
+
return last;
|
|
11916
|
+
}
|
|
11917
|
+
/**
|
|
11918
|
+
* Strips the last ```choices block from a reply's visible answer and validates its options.
|
|
11919
|
+
*
|
|
11920
|
+
* Only the text after the slot's last `</think>` is eligible, so a block the model drafted while
|
|
11921
|
+
* reasoning is never read, and the reasoning prefix is returned byte-for-byte. Nothing visible is
|
|
11922
|
+
* deleted: prose the model added after the block's closing fence is kept, with only the block
|
|
11923
|
+
* removed. A block still open at the end (truncated, or streaming) is hidden through to the end.
|
|
11924
|
+
* Any invalid option rejects the whole block, because dropping one would shift the numbering away
|
|
11925
|
+
* from the prose.
|
|
11926
|
+
*/
|
|
11927
|
+
function extractChoicesBlock(reply) {
|
|
11928
|
+
const unchanged = {
|
|
11929
|
+
text: reply,
|
|
11930
|
+
choices: null,
|
|
11931
|
+
found: false,
|
|
11932
|
+
outcome: ABSENT
|
|
11933
|
+
};
|
|
11934
|
+
const start = answerStart(reply);
|
|
11935
|
+
if (start === null) return findLastChoicesFence(reply) ? {
|
|
11936
|
+
...unchanged,
|
|
11937
|
+
outcome: invalid("think_unclosed")
|
|
11938
|
+
} : unchanged;
|
|
11939
|
+
const answer = reply.slice(start);
|
|
11940
|
+
const fence = findLastChoicesFence(answer);
|
|
11941
|
+
if (!fence) return unchanged;
|
|
11942
|
+
const before = answer.slice(0, fence.start).trimEnd();
|
|
11943
|
+
const after = fence.end === null ? "" : answer.slice(fence.end).replace(/^(?:[ \t]*\r?\n)+/, "");
|
|
11944
|
+
const kept = after.trim() ? before ? `${before}\n\n${after}` : after : before;
|
|
11945
|
+
const parsed = fence.end === null ? { reason: "unterminated" } : parseChoiceOptions(fence.body);
|
|
11946
|
+
const text = reply.slice(0, start) + kept;
|
|
11947
|
+
return "options" in parsed ? {
|
|
11948
|
+
text,
|
|
11949
|
+
choices: parsed.options,
|
|
11950
|
+
found: true,
|
|
11951
|
+
outcome: { status: "parsed" }
|
|
11952
|
+
} : {
|
|
11953
|
+
text,
|
|
11954
|
+
choices: null,
|
|
11955
|
+
found: true,
|
|
11956
|
+
outcome: invalid(parsed.reason)
|
|
11957
|
+
};
|
|
11958
|
+
}
|
|
11959
|
+
/**
|
|
11960
|
+
* {@link extractChoicesBlock} over the reply slots. Every slot's block is stripped (a pre-tool-call
|
|
11961
|
+
* answer must not leak raw JSON), but only the last slot with visible text - the final answer -
|
|
11962
|
+
* supplies the options, so an abandoned earlier draft block can never offer buttons.
|
|
11963
|
+
*/
|
|
11964
|
+
function stripChoicesFromReplies(replies) {
|
|
11965
|
+
const stripped = replies.map((slot) => visibleReplyText(slot) ? extractChoicesBlock(slot).text : slot);
|
|
11966
|
+
let answerIndex = replies.length - 1;
|
|
11967
|
+
while (answerIndex >= 0 && !visibleReplyText(replies[answerIndex])) answerIndex -= 1;
|
|
11968
|
+
if (answerIndex < 0) return {
|
|
11969
|
+
replies: stripped,
|
|
11970
|
+
choices: null,
|
|
11971
|
+
found: false,
|
|
11972
|
+
outcome: ABSENT
|
|
11973
|
+
};
|
|
11974
|
+
const { choices, found, outcome } = extractChoicesBlock(replies[answerIndex]);
|
|
11975
|
+
return {
|
|
11976
|
+
replies: stripped,
|
|
11977
|
+
choices,
|
|
11978
|
+
found,
|
|
11979
|
+
outcome
|
|
11980
|
+
};
|
|
11981
|
+
}
|
|
11982
|
+
/**
|
|
11983
|
+
* The visible answer text of a quest, derived from its reply slots (choices stripped, `<think>`
|
|
11984
|
+
* hidden) with the scalar `reply` as the fallback when no slot has visible text. `joinSlots` joins
|
|
11985
|
+
* the visible slots: a bare join by default, matching the scalar the server persists, and a
|
|
11986
|
+
* paragraph join for a reader that renders the text as markdown (see streamVisibility.ts), since a
|
|
11987
|
+
* bare join glues a slot's closing code fence to the next slot's text.
|
|
11988
|
+
*/
|
|
11989
|
+
function questReplyText(quest, joinSlots = (slots) => slots.join("")) {
|
|
11990
|
+
return joinSlots(stripChoicesFromReplies(quest.replies ?? []).replies.map((slot) => visibleReplyText(slot)).filter(Boolean)) || (quest.reply ?? null);
|
|
11991
|
+
}
|
|
11992
|
+
function parseChoiceOptions(body) {
|
|
11993
|
+
let parsed;
|
|
11994
|
+
try {
|
|
11995
|
+
parsed = JSON.parse(body.trim());
|
|
11996
|
+
} catch {
|
|
11997
|
+
return { reason: "json" };
|
|
11998
|
+
}
|
|
11999
|
+
const raw = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.options) ? parsed.options : null;
|
|
12000
|
+
if (!raw) return { reason: "shape" };
|
|
12001
|
+
const options = [];
|
|
12002
|
+
const seenLabels = /* @__PURE__ */ new Set();
|
|
12003
|
+
for (const item of raw.slice(0, 4)) {
|
|
12004
|
+
if (!item || typeof item !== "object") return { reason: "shape" };
|
|
12005
|
+
const { label, description } = item;
|
|
12006
|
+
if (typeof label !== "string" || typeof description !== "string") return { reason: "shape" };
|
|
12007
|
+
const cleanLabel = label.trim();
|
|
12008
|
+
const cleanDescription = description.trim();
|
|
12009
|
+
if (!cleanLabel || cleanLabel.length > 40) return { reason: "label_length" };
|
|
12010
|
+
if (!cleanDescription || cleanDescription.length > 300) return { reason: "description_length" };
|
|
12011
|
+
if (seenLabels.has(cleanLabel)) return { reason: "duplicate_label" };
|
|
12012
|
+
seenLabels.add(cleanLabel);
|
|
12013
|
+
options.push({
|
|
12014
|
+
label: cleanLabel,
|
|
12015
|
+
description: cleanDescription
|
|
12016
|
+
});
|
|
12017
|
+
}
|
|
12018
|
+
return options.length >= 2 ? { options } : { reason: "too_few" };
|
|
12019
|
+
}
|
|
11535
12020
|
[
|
|
11536
12021
|
"# Reply choices",
|
|
11537
12022
|
"",
|
|
@@ -11749,6 +12234,7 @@ const PromptMetaPerformanceSchema = z$1.object({
|
|
|
11749
12234
|
firstTokenTime: z$1.number().optional(),
|
|
11750
12235
|
/** Elapsed ms until the first chunk of any kind, including a hidden thinking block. */
|
|
11751
12236
|
firstChunkTime: z$1.number().optional(),
|
|
12237
|
+
/** @deprecated Read/write the quest-level clientFirstTokenTime instead. */
|
|
11752
12238
|
clientFirstTokenTime: z$1.number().optional(),
|
|
11753
12239
|
streamingPerformance: z$1.object({
|
|
11754
12240
|
chunkCount: z$1.number().optional(),
|
|
@@ -12273,11 +12759,10 @@ const RetrievalSummarySchema = z$1.object({
|
|
|
12273
12759
|
* an archived or quota-limited lake) adds an enum value here rather than a description.
|
|
12274
12760
|
*
|
|
12275
12761
|
* 'access' is the only reason today: the caller could see the lake exists (their org membership,
|
|
12276
|
-
* the lake's public listing, or having created it;
|
|
12277
|
-
*
|
|
12278
|
-
*
|
|
12279
|
-
*
|
|
12280
|
-
* membership only.
|
|
12762
|
+
* the lake's public listing, or having created it; administering its org; an admin may see any
|
|
12763
|
+
* lake) but they hold neither its own gate/entitlement nor an ownership or grant exception for
|
|
12764
|
+
* it. A lake the caller could not see is never counted, so the count cannot confirm that a
|
|
12765
|
+
* guessed lake tag exists.
|
|
12281
12766
|
*
|
|
12282
12767
|
* A session-preauthorized lake (unionPreauthorizedLakeAccess) that is ALSO gate-dropped from
|
|
12283
12768
|
* this account-wide count is corrected, not merely narrow: the seed's targeted measurement
|
|
@@ -12705,6 +13190,7 @@ const CORE_TOOL_SIDE_EFFECTS = {
|
|
|
12705
13190
|
edit_image: "external",
|
|
12706
13191
|
music_generation: "external",
|
|
12707
13192
|
audio_generation: "external",
|
|
13193
|
+
video_generation: "external",
|
|
12708
13194
|
excel_generation: "external",
|
|
12709
13195
|
create_data_lake: "external",
|
|
12710
13196
|
save_content_to_data_lake: "external",
|
|
@@ -12745,15 +13231,13 @@ const EXTERNAL_REGISTRY_SIDE_EFFECTS = {
|
|
|
12745
13231
|
notebook_status: "none",
|
|
12746
13232
|
share_curated_file: "external",
|
|
12747
13233
|
notebook_new: "external",
|
|
12748
|
-
confirm_pending_action: "external",
|
|
12749
13234
|
cancel_pending_action: "external",
|
|
12750
13235
|
mission_status: "none",
|
|
12751
13236
|
optihashi_decompose: "local",
|
|
12752
13237
|
optihashi_solve: "local",
|
|
12753
13238
|
send_slack_message: "external",
|
|
12754
13239
|
coordinate_task: "external",
|
|
12755
|
-
code_execute: "external"
|
|
12756
|
-
video_generation: "external"
|
|
13240
|
+
code_execute: "external"
|
|
12757
13241
|
};
|
|
12758
13242
|
({
|
|
12759
13243
|
...CORE_TOOL_SIDE_EFFECTS,
|
|
@@ -13369,24 +13853,6 @@ z.object({
|
|
|
13369
13853
|
})
|
|
13370
13854
|
});
|
|
13371
13855
|
/**
|
|
13372
|
-
* Query parameters for a cursor-paginated public list (CONVENTIONS.md section 8).
|
|
13373
|
-
*
|
|
13374
|
-
* `limit` is `z.coerce` because query values arrive as strings; registerContract publishes it as an
|
|
13375
|
-
* integer. A non-numeric, zero, or over-cap value is a 422, never silently clamped.
|
|
13376
|
-
*/
|
|
13377
|
-
const PaginationQuerySchema = z$1.object({
|
|
13378
|
-
limit: z$1.coerce.number().int().min(1).max(100).default(25),
|
|
13379
|
-
cursor: z$1.string().min(1).optional()
|
|
13380
|
-
});
|
|
13381
|
-
/**
|
|
13382
|
-
* The response envelope every cursor-paginated public list returns. `next_cursor` is required and
|
|
13383
|
-
* `null` on the last page, so a caller loops on it rather than on the page length.
|
|
13384
|
-
*/
|
|
13385
|
-
const paginatedResponseSchema = (itemSchema) => z$1.object({
|
|
13386
|
-
data: z$1.array(itemSchema),
|
|
13387
|
-
next_cursor: z$1.string().nullable()
|
|
13388
|
-
});
|
|
13389
|
-
/**
|
|
13390
13856
|
* Wire schemas for the public `/api/v1/data-lakes/*` contracts
|
|
13391
13857
|
* (api-contract/contracts/dataLakes.contract.ts). Deliberately narrower than the SPA's data-lake
|
|
13392
13858
|
* payloads: a field published here can be added to later but never removed, so only what an
|
|
@@ -13399,6 +13865,11 @@ const DataLakeResourceSchema = z$1.object({
|
|
|
13399
13865
|
id: z$1.string(),
|
|
13400
13866
|
name: z$1.string(),
|
|
13401
13867
|
slug: z$1.string(),
|
|
13868
|
+
/**
|
|
13869
|
+
* The value to pass in a session's `lakeScope`. Not derivable from `slug` + `organization_id`: a
|
|
13870
|
+
* lake moved into an org keeps the `datalake:<slug>` tag it was created with.
|
|
13871
|
+
*/
|
|
13872
|
+
datalake_tag: z$1.string(),
|
|
13402
13873
|
description: z$1.string().nullable(),
|
|
13403
13874
|
organization_id: z$1.string().nullable(),
|
|
13404
13875
|
is_public: z$1.boolean(),
|
|
@@ -13464,6 +13935,108 @@ const DataLakeSearchResponseSchema = z$1.object({
|
|
|
13464
13935
|
paused_files: z$1.number().int().nonnegative()
|
|
13465
13936
|
})
|
|
13466
13937
|
});
|
|
13938
|
+
const ProjectResourceSchema = z$1.object({
|
|
13939
|
+
id: z$1.string(),
|
|
13940
|
+
name: z$1.string(),
|
|
13941
|
+
description: z$1.string(),
|
|
13942
|
+
session_ids: z$1.array(z$1.string()).describe("Sessions grouped in the project. Anyone the project is shared with can read them."),
|
|
13943
|
+
file_ids: z$1.array(z$1.string()).describe("Files grouped in the project. Anyone the project is shared with can read them."),
|
|
13944
|
+
created_at: z$1.string().nullable().describe("ISO 8601 timestamp."),
|
|
13945
|
+
updated_at: z$1.string().nullable().describe("ISO 8601 timestamp.")
|
|
13946
|
+
});
|
|
13947
|
+
const ListProjectsResponseSchema = paginatedResponseSchema(ProjectResourceSchema);
|
|
13948
|
+
/**
|
|
13949
|
+
* `id` is a plain string on purpose: a malformed id must answer 404 (CONVENTIONS.md status table),
|
|
13950
|
+
* and a path-param schema failure would answer 422.
|
|
13951
|
+
*/
|
|
13952
|
+
const ProjectIdParamSchema = z$1.object({ id: z$1.string().min(1) });
|
|
13953
|
+
/**
|
|
13954
|
+
* Strict, so a camelCase `sessionIds`/`fileIds` (the SPA route's spelling) is a 422 rather than
|
|
13955
|
+
* silently dropped, which would create a project without the content the caller meant to attach.
|
|
13956
|
+
*/
|
|
13957
|
+
const CreateProjectRequestSchema = z$1.object({
|
|
13958
|
+
name: z$1.string().min(1).describe("Unique among your live projects."),
|
|
13959
|
+
description: z$1.string().min(1),
|
|
13960
|
+
session_ids: z$1.array(z$1.string().min(1)).max(500).optional().describe("Sessions to group in the project. Each must be readable by the caller."),
|
|
13961
|
+
file_ids: z$1.array(z$1.string().min(1)).max(500).optional().describe("Files to group in the project. Each must be readable by the caller.")
|
|
13962
|
+
}).strict();
|
|
13963
|
+
/**
|
|
13964
|
+
* The public projection of `ModelInfo` served by `GET /api/v1/models`.
|
|
13965
|
+
*
|
|
13966
|
+
* Deliberately narrower than `ModelInfo`: every field here is one an integrator can pin, so
|
|
13967
|
+
* internal catalog fields (`adapterFamily`, `dispatchProfile`, `rank`, `pricing`, `logoFile`)
|
|
13968
|
+
* stay off the wire. The legacy `GET /api/models` keeps serving the full internal type to the
|
|
13969
|
+
* SPA and CLI. Wire fields are snake_case (CONVENTIONS.md section 2).
|
|
13970
|
+
*/
|
|
13971
|
+
const PublicImageSizingSchema = z$1.discriminatedUnion("kind", [
|
|
13972
|
+
z$1.object({
|
|
13973
|
+
kind: z$1.literal("presets"),
|
|
13974
|
+
presets: z$1.array(z$1.string()).describe("Accepted `size` values, as `WxH`."),
|
|
13975
|
+
default_size: z$1.string()
|
|
13976
|
+
}),
|
|
13977
|
+
z$1.object({
|
|
13978
|
+
kind: z$1.literal("constrained"),
|
|
13979
|
+
presets: z$1.array(z$1.string()).describe("Suggested `size` values; any `WxH` meeting `constraints` is accepted."),
|
|
13980
|
+
default_size: z$1.string(),
|
|
13981
|
+
auto_size: z$1.string().describe("The `size` value that lets the provider choose."),
|
|
13982
|
+
constraints: z$1.object({
|
|
13983
|
+
max_edge: z$1.number().int(),
|
|
13984
|
+
min_total_pixels: z$1.number().int(),
|
|
13985
|
+
max_total_pixels: z$1.number().int(),
|
|
13986
|
+
edge_multiple: z$1.number().int().describe("Both edges must be a multiple of this."),
|
|
13987
|
+
max_aspect_ratio: z$1.number().describe("Longest edge divided by shortest edge.")
|
|
13988
|
+
})
|
|
13989
|
+
}),
|
|
13990
|
+
z$1.object({
|
|
13991
|
+
kind: z$1.literal("dimensions"),
|
|
13992
|
+
presets: z$1.array(z$1.string()),
|
|
13993
|
+
default_size: z$1.string(),
|
|
13994
|
+
min_width: z$1.number().int(),
|
|
13995
|
+
max_width: z$1.number().int(),
|
|
13996
|
+
min_height: z$1.number().int(),
|
|
13997
|
+
max_height: z$1.number().int(),
|
|
13998
|
+
step: z$1.number().int().describe("`width` and `height` are rounded to the nearest multiple of this.")
|
|
13999
|
+
}),
|
|
14000
|
+
z$1.object({ kind: z$1.literal("aspect_ratio").describe("Takes an `aspect_ratio` such as `16:9`, not a `size`.") }),
|
|
14001
|
+
z$1.object({
|
|
14002
|
+
kind: z$1.literal("input_image").describe("Sized by the input image; takes no `size`."),
|
|
14003
|
+
aspect_ratio: z$1.boolean().describe("Whether an `aspect_ratio` override is honoured.")
|
|
14004
|
+
}),
|
|
14005
|
+
z$1.object({ kind: z$1.literal("fixed").describe("The provider takes no size at all.") })
|
|
14006
|
+
]);
|
|
14007
|
+
const PublicImageCapabilitiesSchema = z$1.object({
|
|
14008
|
+
sizing: PublicImageSizingSchema,
|
|
14009
|
+
supports: z$1.object({
|
|
14010
|
+
transparent_background: z$1.boolean().describe("`background: 'transparent'` yields real alpha."),
|
|
14011
|
+
seed: z$1.boolean(),
|
|
14012
|
+
qualities: z$1.array(OpenAIImageQualitySchema).describe("Accepted `quality` tiers; empty when none is taken."),
|
|
14013
|
+
max_images: z$1.number().int().describe("Most images one request may ask for via `n`."),
|
|
14014
|
+
max_reference_images: z$1.number().int().describe("Most `referenceImageFabFileIds` honoured; 0 when the model takes none."),
|
|
14015
|
+
edit: z$1.boolean().describe("Accepted by `POST /api/v1/image-edits`."),
|
|
14016
|
+
requires_input_image: z$1.boolean()
|
|
14017
|
+
})
|
|
14018
|
+
});
|
|
14019
|
+
const ListModelsResponseSchema = paginatedResponseSchema(z$1.object({
|
|
14020
|
+
id: z$1.string().describe("Pass as `model` on the generation endpoints."),
|
|
14021
|
+
name: z$1.string(),
|
|
14022
|
+
type: z$1.enum([
|
|
14023
|
+
"text",
|
|
14024
|
+
"image",
|
|
14025
|
+
"speech-to-text",
|
|
14026
|
+
"video"
|
|
14027
|
+
]),
|
|
14028
|
+
backend: z$1.enum(ModelBackend).describe("The provider that serves the model."),
|
|
14029
|
+
description: z$1.string().nullable(),
|
|
14030
|
+
context_window: z$1.number().int().describe("Input context, in tokens."),
|
|
14031
|
+
max_output_tokens: z$1.number().int(),
|
|
14032
|
+
supports_streaming: z$1.boolean(),
|
|
14033
|
+
supports_thinking: z$1.boolean(),
|
|
14034
|
+
supports_tools: z$1.boolean(),
|
|
14035
|
+
supports_vision: z$1.boolean(),
|
|
14036
|
+
deprecation_date: z$1.string().nullable().describe("`YYYY-MM-DD`; null when no retirement is scheduled."),
|
|
14037
|
+
replaced_by: z$1.string().nullable().describe("The id of the recommended successor, when there is one."),
|
|
14038
|
+
image: PublicImageCapabilitiesSchema.nullable().describe("Size rules and supported parameters. Present on image models only; null for every other type.")
|
|
14039
|
+
}));
|
|
13467
14040
|
z$1.string().regex(/^[a-f0-9]{24}$/i, "Invalid template id");
|
|
13468
14041
|
/**
|
|
13469
14042
|
* The bound model. Reuses the legacy-remap preprocess so a template saved under
|
|
@@ -13625,6 +14198,21 @@ z$1.object({
|
|
|
13625
14198
|
}))
|
|
13626
14199
|
});
|
|
13627
14200
|
[...OPENAI_IMAGE_MODELS, ...GEMINI_IMAGE_MODELS];
|
|
14201
|
+
const GenerationCallbackUrlSchema = z$1.url({
|
|
14202
|
+
protocol: /^https$/,
|
|
14203
|
+
error: "callbackUrl must be an https URL"
|
|
14204
|
+
}).max(2048).describe("Optional https URL that receives one signed POST when the job settles (success or failure). Requires API-key authentication and a callback signing secret on that key. The body is the GET /api/v1/quests/{id} response. Verify it with the `X-Webhook-Signature-256` header: `sha256=` + hex HMAC-SHA256 of `<X-Webhook-Timestamp>.<raw body>` keyed with the signing secret. Polling keeps working either way.");
|
|
14205
|
+
z$1.enum([
|
|
14206
|
+
"pending",
|
|
14207
|
+
"dispatched",
|
|
14208
|
+
"delivered",
|
|
14209
|
+
"failed"
|
|
14210
|
+
]);
|
|
14211
|
+
/**
|
|
14212
|
+
* The 400 clause every queued-generation contract declares for a rejected `callbackUrl`; must stay
|
|
14213
|
+
* in sync with the rejections in apps/client/server/generationCallback/armGenerationCallback.ts.
|
|
14214
|
+
*/
|
|
14215
|
+
const GENERATION_CALLBACK_REJECTED_DESCRIPTION = "`callbackUrl` was rejected: the request is not API-key authenticated, the key has no callback signing secret, the URL resolves to a private address, or the deployment does not deliver callbacks.";
|
|
13628
14216
|
const DashboardParamsSchema = z$1.object({
|
|
13629
14217
|
dashboardDataSources: z$1.array(z$1.object({
|
|
13630
14218
|
sourceName: z$1.string(),
|
|
@@ -13958,24 +14546,108 @@ const GenerateImageResponseSchema = z$1.object({
|
|
|
13958
14546
|
promptWasEnhanced: z$1.boolean(),
|
|
13959
14547
|
intent: PromptIntentSchema
|
|
13960
14548
|
});
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
const
|
|
13972
|
-
|
|
13973
|
-
|
|
14549
|
+
const VIDEO_GENERATION_API_ERROR_CODES = [
|
|
14550
|
+
...VIDEO_VALIDATION_ERROR_CODES,
|
|
14551
|
+
"invalid_request",
|
|
14552
|
+
"model_disabled",
|
|
14553
|
+
"model_unavailable",
|
|
14554
|
+
"insufficient_credits",
|
|
14555
|
+
"input_image_not_found",
|
|
14556
|
+
"idempotency_key_reused",
|
|
14557
|
+
"invalid_idempotency_key"
|
|
14558
|
+
];
|
|
14559
|
+
const VIDEO_JOB_PUBLIC_ERROR_CODES = [
|
|
14560
|
+
"content_blocked",
|
|
14561
|
+
"provider_timeout",
|
|
14562
|
+
"provider_error",
|
|
14563
|
+
"region_unavailable",
|
|
14564
|
+
"output_too_large",
|
|
14565
|
+
"input_image_not_found",
|
|
14566
|
+
"cancelled"
|
|
14567
|
+
];
|
|
14568
|
+
const VideoGenerationErrorResponseSchema = ApiErrorSchema.extend({ errorCode: z$1.enum(VIDEO_GENERATION_API_ERROR_CODES).optional() });
|
|
14569
|
+
const CreateVideoGenerationBodySchema = z$1.strictObject({
|
|
14570
|
+
model: z$1.string().min(1).describe("A model id from GET /api/v1/video-models."),
|
|
14571
|
+
prompt: z$1.string().min(1).max(4e3),
|
|
14572
|
+
mode: z$1.enum(VIDEO_MODES).optional().describe("Defaults to image_to_video when input_image_file_id is set, else text_to_video."),
|
|
14573
|
+
duration_seconds: z$1.number().positive().optional().describe("Defaults to the model's default duration."),
|
|
14574
|
+
aspect_ratio: z$1.enum(ASPECT_RATIOS).optional(),
|
|
14575
|
+
resolution: z$1.enum(RESOLUTION_TIERS).optional(),
|
|
14576
|
+
input_image_file_id: z$1.string().min(1).optional().describe("An image file you own, for image_to_video."),
|
|
14577
|
+
audio: z$1.boolean().optional()
|
|
14578
|
+
});
|
|
14579
|
+
const VideoGenerationSchema = z$1.object({
|
|
14580
|
+
id: z$1.string(),
|
|
14581
|
+
object: z$1.literal("video_generation"),
|
|
14582
|
+
state: z$1.enum(GENERATION_JOB_STATES),
|
|
14583
|
+
model: z$1.string(),
|
|
14584
|
+
mode: z$1.enum(VIDEO_MODES),
|
|
14585
|
+
prompt: z$1.string(),
|
|
14586
|
+
duration_seconds: z$1.number(),
|
|
14587
|
+
aspect_ratio: z$1.enum(ASPECT_RATIOS),
|
|
14588
|
+
resolution: z$1.enum(RESOLUTION_TIERS),
|
|
14589
|
+
source: z$1.enum(GENERATION_JOB_SOURCES),
|
|
14590
|
+
progress: z$1.number().min(0).max(1).nullable(),
|
|
14591
|
+
error: z$1.object({
|
|
14592
|
+
code: z$1.enum(VIDEO_JOB_PUBLIC_ERROR_CODES),
|
|
14593
|
+
message: z$1.string()
|
|
14594
|
+
}).nullable(),
|
|
14595
|
+
output: z$1.object({
|
|
14596
|
+
availability: z$1.enum([
|
|
14597
|
+
"ready",
|
|
14598
|
+
"pending_scan",
|
|
14599
|
+
"unavailable"
|
|
14600
|
+
]).describe("`ready`: url is set. `pending_scan`: the saved file is still being scanned; re-fetch the job until it changes (self-hosted installs can stay here for up to ~30 minutes). `unavailable`: the file was blocked by the scan or deleted and url will never be set; stop polling."),
|
|
14601
|
+
url: z$1.string().nullable().describe("Signed download URL, valid until expires_at; re-fetch the job for a fresh one. Set only when availability is `ready`, otherwise null."),
|
|
14602
|
+
expires_at: z$1.string().nullable().describe("ISO 8601. When url stops working; null whenever url is."),
|
|
14603
|
+
content_type: z$1.string(),
|
|
14604
|
+
duration_seconds: z$1.number(),
|
|
14605
|
+
file_id: z$1.string().nullable().describe("The Files entry, or null when the clip was stored outside Files.")
|
|
14606
|
+
}).nullable(),
|
|
14607
|
+
credits: z$1.object({
|
|
14608
|
+
reserved: z$1.number().nullable(),
|
|
14609
|
+
settled: z$1.number().nullable()
|
|
14610
|
+
}),
|
|
14611
|
+
created_at: z$1.string(),
|
|
14612
|
+
updated_at: z$1.string()
|
|
14613
|
+
});
|
|
14614
|
+
const VideoModelSchema = z$1.object({
|
|
14615
|
+
id: z$1.string(),
|
|
14616
|
+
object: z$1.literal("video_model"),
|
|
14617
|
+
display_name: z$1.string(),
|
|
14618
|
+
provider: z$1.string(),
|
|
14619
|
+
modes: z$1.array(z$1.enum(VIDEO_MODES)),
|
|
14620
|
+
duration: z$1.union([z$1.object({
|
|
14621
|
+
kind: z$1.literal("range"),
|
|
14622
|
+
min: z$1.number(),
|
|
14623
|
+
max: z$1.number(),
|
|
14624
|
+
step: z$1.number()
|
|
14625
|
+
}), z$1.object({
|
|
14626
|
+
kind: z$1.literal("discrete"),
|
|
14627
|
+
values: z$1.array(z$1.number())
|
|
14628
|
+
})]),
|
|
14629
|
+
aspect_ratios: z$1.array(z$1.enum(ASPECT_RATIOS)),
|
|
14630
|
+
resolutions: z$1.array(z$1.enum(RESOLUTION_TIERS)),
|
|
14631
|
+
defaults: z$1.object({
|
|
14632
|
+
duration_seconds: z$1.number(),
|
|
14633
|
+
aspect_ratio: z$1.enum(ASPECT_RATIOS),
|
|
14634
|
+
resolution: z$1.enum(RESOLUTION_TIERS)
|
|
14635
|
+
}),
|
|
14636
|
+
audio: z$1.enum([
|
|
14637
|
+
"always",
|
|
14638
|
+
"optional",
|
|
14639
|
+
"none"
|
|
14640
|
+
]),
|
|
14641
|
+
credits_per_second: z$1.record(z$1.string(), z$1.number()).nullable().describe("Credits per second of output by resolution; null for per-clip priced models."),
|
|
14642
|
+
deprecation_date: z$1.string().nullable()
|
|
13974
14643
|
});
|
|
13975
|
-
const
|
|
13976
|
-
|
|
13977
|
-
|
|
14644
|
+
const ListVideoModelsResponseSchema = z$1.object({ models: z$1.array(VideoModelSchema) });
|
|
14645
|
+
const ListVideoGenerationsQuerySchema = PaginationQuerySchema.extend({
|
|
14646
|
+
state: z$1.enum(GENERATION_JOB_STATES).optional(),
|
|
14647
|
+
source: z$1.enum(GENERATION_JOB_SOURCES).optional()
|
|
13978
14648
|
});
|
|
14649
|
+
const ListVideoGenerationsResponseSchema = paginatedResponseSchema(VideoGenerationSchema);
|
|
14650
|
+
const VideoGenerationIdParamSchema = z$1.object({ id: z$1.string().min(1) });
|
|
13979
14651
|
/**
|
|
13980
14652
|
* Wire schemas for the public `/api/v1/voice/*` contracts (api-contract/contracts/voice.contract.ts).
|
|
13981
14653
|
* The legacy `/api/voice/v2/*` paths serve the same handlers, so these shapes are also what the SPA
|
|
@@ -14067,8 +14739,8 @@ defineEndpoint({
|
|
|
14067
14739
|
emitsRateLimitHeaders: true,
|
|
14068
14740
|
responses: {
|
|
14069
14741
|
200: {
|
|
14070
|
-
description: "Message accepted - NOT a completed turn. The default (async) path returns this queued ACK; the outcome arrives on `GET /api/v1/quests/{id}` (see the `sendChatMessage200PollResult` schema). With `wait: true` the body
|
|
14071
|
-
schema: ChatAckSchema,
|
|
14742
|
+
description: "Message accepted - NOT a completed turn. The default (async) path returns this queued ACK; the outcome arrives on `GET /api/v1/quests/{id}` (see the `sendChatMessage200PollResult` schema). With `wait: true` the body is instead the completed turn: the ACK fields plus the reply (`response`/`responses`), `toolPayloads`, `createdAt`, `performance` timings and, when requested, `promptDetails`/`promptText`. A turn that FAILS still resolves with `200`, never a 4xx, on both that `wait: true` body and the polled quest (`GET /api/v1/quests/{id}`) - the prose explaining why lands in `reply`/`response` like any other answer, so the reply text alone cannot tell a failure from an answer. `type` is the field that can: both surfaces carry it unconditionally, so match on `type: \"error\"` first - it covers credit exhaustion, a provider timeout or overload, and an in-process aborted turn; a real answer carries the turn's actual completion type instead (`\"message\"` for an ordinary reply). Two related states do NOT set `type: \"error\"`: a user-cancelled turn resolves as `status: \"stopped\"` with `type` left at `\"message\"`, and a recovered stuck quest that still has renderable content resolves as a success (`status: \"done\"`, no error) by design, to avoid destroying content to report a failure. `errorCode` then names the failure reason, but only for the billing failures that have one - `\"insufficient_credits\"` today; it is absent on every other `type: \"error\"` turn, so never use its absence to infer success. On a real answer `errorCode` is absent from the `wait: true` body. The body also carries `sessionId`, the notebook the turn was recorded in - for an API-key caller that sent none (or any caller sending `newConversation: true`), that is the freshly created notebook's id; pass it back as the request's `sessionId` to continue. Contrast the tts/music/soundEffects contracts, which reject synchronously with a 422 carrying the same `errorCode` vocabulary.",
|
|
14743
|
+
schema: z$1.union([ChatWaitResponseSchema, ChatAckSchema]),
|
|
14072
14744
|
pollResult: {
|
|
14073
14745
|
schema: ChatQuestPollResultSchema,
|
|
14074
14746
|
description: "Outcome fields of the quest polled at `GET /api/v1/quests/{id}` after this ACK. A finished turn that failed is `status: \"done\"` with `type: \"error\"` and the failure text in `reply`, so a caller reading `reply` alone cannot tell a failure from an answer - check `type` first, and also treat a terminal `status: \"stopped\"` (a missing session, a user-cancelled turn) as failure even though it never sets `type`. `errorCode` is an optional refinement of `type: \"error\"`, present only for a classified billing failure; credit exhaustion arrives here as `insufficient_credits`, the same vocabulary the synchronous 422s on `/api/ai/music`, `/api/ai/sound-effects` and `/api/ai/tts` use. `QUEST_ERROR_CODES` publishes a second member, `spend_cap_exceeded`, but no current throw site on this endpoint raises it as a quest errorCode: its only one, the embed chat route's pre-flight 422, fires outside the process try/catch that would classify it onto the quest. Most `type: \"error\"` turns - an abort, a provider timeout or overload - have NO `errorCode`; its absence does not mean success, only that the failure is unclassified. A recovered stuck quest that still has renderable content is not a failure at all: it keeps `type: \"message\"` even though it did not finish, so a caller gets the content rather than an error. `fallbackInfo` is present only when the requested model failed and another model produced the reply: `fallbackModel` answered, `primaryModel` is what was asked for, and `reason` is the error from the first failed attempt on the requested model. The poll body carries further fields not modelled here, including `images`, `files`, `toolPayloads`, `promptMeta`, and the attachment report (`attachmentNotices`/`attachmentDelivery`) - only the outcome subset is modelled here.",
|
|
@@ -14142,39 +14814,143 @@ defineEndpoint({
|
|
|
14142
14814
|
429: {
|
|
14143
14815
|
description: "Per-user rate limit exceeded.",
|
|
14144
14816
|
schema: ApiErrorSchema
|
|
14145
|
-
},
|
|
14146
|
-
502: {
|
|
14147
|
-
description: "The executor could not be dispatched. The run did not start, so a retry is safe.",
|
|
14148
|
-
schema: ApiErrorSchema
|
|
14817
|
+
},
|
|
14818
|
+
502: {
|
|
14819
|
+
description: "The executor could not be dispatched. The run did not start, so a retry is safe.",
|
|
14820
|
+
schema: ApiErrorSchema
|
|
14821
|
+
}
|
|
14822
|
+
},
|
|
14823
|
+
codeSample: {
|
|
14824
|
+
authToken: "b4m_live_<key>",
|
|
14825
|
+
streaming: false,
|
|
14826
|
+
body: {
|
|
14827
|
+
session_id: "<sessionId>",
|
|
14828
|
+
message: "Audit this data set and summarize what stands out."
|
|
14829
|
+
}
|
|
14830
|
+
}
|
|
14831
|
+
});
|
|
14832
|
+
defineEndpoint({
|
|
14833
|
+
method: "get",
|
|
14834
|
+
path: "/api/v1/agent-executions/{id}",
|
|
14835
|
+
operationId: "getAgentExecution",
|
|
14836
|
+
summary: "Get an agent execution",
|
|
14837
|
+
description: "Returns the status, reasoning trace, and (once terminal) the final answer of a run started by `POST /api/v1/agent-executions`. `steps` grows while the run is in flight, so polling this endpoint is also how a REST caller follows the loop. Safe (GET) requests on this route are exempt from the per-day API-key quota: a poll consumes no daily slot, and only the per-minute burst limit applies.",
|
|
14838
|
+
tags: ["AI"],
|
|
14839
|
+
auth: "apiKeyOrJwt",
|
|
14840
|
+
scopes: ["ai:chat", "ai:generate"],
|
|
14841
|
+
pathParams: AgentExecutionIdParamSchema,
|
|
14842
|
+
emitsRateLimitHeaders: true,
|
|
14843
|
+
responses: {
|
|
14844
|
+
200: {
|
|
14845
|
+
description: "The execution, its trace, and its answer if it has finished.",
|
|
14846
|
+
schema: AgentExecutionStatusResponseSchema
|
|
14847
|
+
},
|
|
14848
|
+
404: {
|
|
14849
|
+
description: "No execution with that id is visible to the caller.",
|
|
14850
|
+
schema: ApiErrorSchema
|
|
14851
|
+
},
|
|
14852
|
+
429: {
|
|
14853
|
+
description: "Per-user rate limit exceeded.",
|
|
14854
|
+
schema: ApiErrorSchema
|
|
14855
|
+
}
|
|
14856
|
+
},
|
|
14857
|
+
codeSample: {
|
|
14858
|
+
authToken: "b4m_live_<key>",
|
|
14859
|
+
streaming: false,
|
|
14860
|
+
body: {}
|
|
14861
|
+
}
|
|
14862
|
+
});
|
|
14863
|
+
defineEndpoint({
|
|
14864
|
+
method: "put",
|
|
14865
|
+
path: "/api/sessions/{id}",
|
|
14866
|
+
operationId: "updateSession",
|
|
14867
|
+
summary: "Update a session",
|
|
14868
|
+
description: "Updates a session (called a \"notebook\" in the product UI): its name, attached knowledge files, tags, or retrieval settings. Set `knowledgeIds` and `forceKnowledgeRetrieval: true` together to enable grounded retrieval for `POST /api/chat` against this session - retrieval is gated by these session fields, not by the chat request. `lakeScope` narrows that retrieval to a chosen set of data lakes; omit it to leave the current choice unchanged, or send `null` to clear it so retrieval reaches every lake you can access. `includeLibraryFiles` sets whether the session grounds on your own library alongside its lakes; `false` confines it to lake content even when every lake is in scope (files attached to the session still reach the model and its knowledge-base tools), and is set aside (library included) while `forceKnowledgeRetrieval` is `false`. Authenticate with an API key (`b4m_live_`) or a JWT. Warning: adding to `knowledgeIds` shares those files with every member of every project containing this session by default (see `propagateToProjects`), and that sharing cannot be undone through the UI.",
|
|
14869
|
+
tags: ["Sessions"],
|
|
14870
|
+
auth: "apiKeyOrJwt",
|
|
14871
|
+
scopes: ["notebooks:write"],
|
|
14872
|
+
pathParams: SessionIdParamSchema,
|
|
14873
|
+
request: SessionUpdateRequestSchema,
|
|
14874
|
+
emitsRateLimitHeaders: true,
|
|
14875
|
+
requestExample: {
|
|
14876
|
+
knowledgeIds: ["<fabFileId>"],
|
|
14877
|
+
forceKnowledgeRetrieval: true
|
|
14878
|
+
},
|
|
14879
|
+
responses: {
|
|
14880
|
+
200: {
|
|
14881
|
+
description: "The updated session.",
|
|
14882
|
+
schema: SessionResponseSchema
|
|
14883
|
+
},
|
|
14884
|
+
404: {
|
|
14885
|
+
description: "No session exists with the given id.",
|
|
14886
|
+
schema: ApiErrorSchema
|
|
14887
|
+
},
|
|
14888
|
+
429: {
|
|
14889
|
+
description: "Per-user rate limit exceeded.",
|
|
14890
|
+
schema: ApiErrorSchema
|
|
14891
|
+
}
|
|
14892
|
+
},
|
|
14893
|
+
codeSample: {
|
|
14894
|
+
authToken: "b4m_live_<key>",
|
|
14895
|
+
streaming: false,
|
|
14896
|
+
body: {
|
|
14897
|
+
knowledgeIds: ["<fabFileId>"],
|
|
14898
|
+
forceKnowledgeRetrieval: true
|
|
14899
|
+
}
|
|
14900
|
+
}
|
|
14901
|
+
});
|
|
14902
|
+
defineEndpoint({
|
|
14903
|
+
method: "get",
|
|
14904
|
+
path: "/api/sessions/{id}",
|
|
14905
|
+
operationId: "getSession",
|
|
14906
|
+
summary: "Get a session",
|
|
14907
|
+
description: "Reads a session you own or that was shared with you (called a \"notebook\" in the product UI): its name, attached knowledge files, tags, and retrieval settings. Use it to confirm what a `PUT` on the same path stored. A session not visible to you, or one that was deleted, is `404`. An API key needs `notebooks:read` or `notebooks:write`.",
|
|
14908
|
+
tags: ["Sessions"],
|
|
14909
|
+
auth: "apiKeyOrJwt",
|
|
14910
|
+
scopes: ["notebooks:read", "notebooks:write"],
|
|
14911
|
+
pathParams: SessionIdParamSchema,
|
|
14912
|
+
emitsRateLimitHeaders: true,
|
|
14913
|
+
responses: {
|
|
14914
|
+
200: {
|
|
14915
|
+
description: "The session.",
|
|
14916
|
+
schema: SessionResponseSchema
|
|
14917
|
+
},
|
|
14918
|
+
404: {
|
|
14919
|
+
description: "No session with that id is visible to the caller.",
|
|
14920
|
+
schema: ApiErrorSchema
|
|
14921
|
+
},
|
|
14922
|
+
429: {
|
|
14923
|
+
description: "Per-user rate limit exceeded.",
|
|
14924
|
+
schema: ApiErrorSchema
|
|
14149
14925
|
}
|
|
14150
14926
|
},
|
|
14151
14927
|
codeSample: {
|
|
14152
14928
|
authToken: "b4m_live_<key>",
|
|
14153
|
-
streaming: false
|
|
14154
|
-
body: {
|
|
14155
|
-
session_id: "<sessionId>",
|
|
14156
|
-
message: "Audit this data set and summarize what stands out."
|
|
14157
|
-
}
|
|
14929
|
+
streaming: false
|
|
14158
14930
|
}
|
|
14159
14931
|
});
|
|
14160
14932
|
defineEndpoint({
|
|
14161
|
-
method: "
|
|
14162
|
-
path: "/api/
|
|
14163
|
-
operationId: "
|
|
14164
|
-
summary: "
|
|
14165
|
-
description: "
|
|
14166
|
-
tags: ["
|
|
14933
|
+
method: "delete",
|
|
14934
|
+
path: "/api/sessions/{id}",
|
|
14935
|
+
operationId: "deleteSession",
|
|
14936
|
+
summary: "Delete a session",
|
|
14937
|
+
description: "Deletes one of your sessions (called a \"notebook\" in the product UI). This cannot be undone through the API. Files you uploaded into the session are deleted with it; files other people uploaded into it are kept, and every access grant this session gave out on a file is revoked. A session you do not own, or one already deleted, is `404`. A `409` means a concurrent change touched one of those files mid-delete; nothing was deleted, so retry. An API key needs `notebooks:write`.",
|
|
14938
|
+
tags: ["Sessions"],
|
|
14167
14939
|
auth: "apiKeyOrJwt",
|
|
14168
|
-
scopes: ["
|
|
14169
|
-
pathParams:
|
|
14940
|
+
scopes: ["notebooks:write"],
|
|
14941
|
+
pathParams: SessionIdParamSchema,
|
|
14170
14942
|
emitsRateLimitHeaders: true,
|
|
14171
14943
|
responses: {
|
|
14172
14944
|
200: {
|
|
14173
|
-
description: "The
|
|
14174
|
-
schema:
|
|
14945
|
+
description: "The session was deleted.",
|
|
14946
|
+
schema: SessionDeleteResponseSchema
|
|
14175
14947
|
},
|
|
14176
14948
|
404: {
|
|
14177
|
-
description: "No
|
|
14949
|
+
description: "No session with that id is visible to the caller.",
|
|
14950
|
+
schema: ApiErrorSchema
|
|
14951
|
+
},
|
|
14952
|
+
409: {
|
|
14953
|
+
description: "A concurrent change touched a file this session shares; nothing was deleted. Retry.",
|
|
14178
14954
|
schema: ApiErrorSchema
|
|
14179
14955
|
},
|
|
14180
14956
|
429: {
|
|
@@ -14184,43 +14960,51 @@ defineEndpoint({
|
|
|
14184
14960
|
},
|
|
14185
14961
|
codeSample: {
|
|
14186
14962
|
authToken: "b4m_live_<key>",
|
|
14187
|
-
streaming: false
|
|
14188
|
-
body: {}
|
|
14963
|
+
streaming: false
|
|
14189
14964
|
}
|
|
14190
14965
|
});
|
|
14191
14966
|
defineEndpoint({
|
|
14192
|
-
method: "
|
|
14193
|
-
path: "/api/sessions/{id}",
|
|
14194
|
-
operationId: "
|
|
14195
|
-
summary: "
|
|
14196
|
-
description: "
|
|
14967
|
+
method: "post",
|
|
14968
|
+
path: "/api/v1/sessions/{id}/clone",
|
|
14969
|
+
operationId: "cloneSession",
|
|
14970
|
+
summary: "Clone a session",
|
|
14971
|
+
description: "Clones a session (called a \"notebook\" in the product UI), including its messages and attachments. Omit `targetSurface` to inherit the source workspace, send `null` for the main notebook list, or send a surface id for another workspace. An API key needs `notebooks:write`.",
|
|
14197
14972
|
tags: ["Sessions"],
|
|
14198
14973
|
auth: "apiKeyOrJwt",
|
|
14199
14974
|
scopes: ["notebooks:write"],
|
|
14200
14975
|
pathParams: SessionIdParamSchema,
|
|
14201
|
-
request:
|
|
14976
|
+
request: SessionCloneRequestSchema,
|
|
14977
|
+
requestBodyRequired: false,
|
|
14978
|
+
validationErrorStatus: 400,
|
|
14202
14979
|
emitsRateLimitHeaders: true,
|
|
14203
|
-
requestExample: {
|
|
14204
|
-
knowledgeIds: ["<fabFileId>"],
|
|
14205
|
-
forceKnowledgeRetrieval: true
|
|
14206
|
-
},
|
|
14980
|
+
requestExample: {},
|
|
14207
14981
|
responses: {
|
|
14208
14982
|
200: {
|
|
14209
|
-
description: "The
|
|
14983
|
+
description: "The cloned session.",
|
|
14210
14984
|
schema: SessionResponseSchema
|
|
14211
14985
|
},
|
|
14986
|
+
400: {
|
|
14987
|
+
description: "The session id is missing or `targetSurface` is malformed.",
|
|
14988
|
+
schema: ApiErrorSchema
|
|
14989
|
+
},
|
|
14990
|
+
403: {
|
|
14991
|
+
description: "The API key lacks `notebooks:write` or the caller is not allowed to clone sessions.",
|
|
14992
|
+
schema: ScopeForbiddenErrorSchema
|
|
14993
|
+
},
|
|
14212
14994
|
404: {
|
|
14213
|
-
description: "No session
|
|
14995
|
+
description: "No session with that id is visible to the caller.",
|
|
14214
14996
|
schema: ApiErrorSchema
|
|
14997
|
+
},
|
|
14998
|
+
429: {
|
|
14999
|
+
description: "The clone limit of 10 requests per minute per caller was exceeded.",
|
|
15000
|
+
schema: ApiErrorSchema,
|
|
15001
|
+
headers: { "Retry-After": "Seconds until the caller can retry." }
|
|
14215
15002
|
}
|
|
14216
15003
|
},
|
|
14217
15004
|
codeSample: {
|
|
14218
15005
|
authToken: "b4m_live_<key>",
|
|
14219
15006
|
streaming: false,
|
|
14220
|
-
body: {
|
|
14221
|
-
knowledgeIds: ["<fabFileId>"],
|
|
14222
|
-
forceKnowledgeRetrieval: true
|
|
14223
|
-
}
|
|
15007
|
+
body: {}
|
|
14224
15008
|
}
|
|
14225
15009
|
});
|
|
14226
15010
|
defineEndpoint({
|
|
@@ -14255,6 +15039,10 @@ defineEndpoint({
|
|
|
14255
15039
|
description: "Missing or invalid JWT (an API key is rejected here).",
|
|
14256
15040
|
schema: ApiErrorSchema
|
|
14257
15041
|
},
|
|
15042
|
+
403: {
|
|
15043
|
+
description: "Valid JWT, but the account is suspended or has a dispute pending.",
|
|
15044
|
+
schema: ApiErrorSchema
|
|
15045
|
+
},
|
|
14258
15046
|
429: {
|
|
14259
15047
|
description: "Rate limit exceeded (100 requests/hour per user for this endpoint).",
|
|
14260
15048
|
schema: ApiErrorSchema
|
|
@@ -14651,6 +15439,80 @@ defineEndpoint({
|
|
|
14651
15439
|
body: {}
|
|
14652
15440
|
}
|
|
14653
15441
|
});
|
|
15442
|
+
defineEndpoint({
|
|
15443
|
+
method: "get",
|
|
15444
|
+
path: "/api/v1/models",
|
|
15445
|
+
operationId: "listModels",
|
|
15446
|
+
summary: "List models",
|
|
15447
|
+
description: "Lists the models the caller can use right now - the platform catalog filtered to the providers the caller has a key for, their own or the platform's. Use it to choose a `model` by capability before calling a generation endpoint: `context_window` and `max_output_tokens` for text models, and for image models the `image` block, which lists the accepted `size` values (or the rule they must meet) and whether `background`, `seed`, `quality`, `n` and reference images are honoured. The list is cached for up to a minute per caller. Cursor-paginated (see the pagination convention): pass `next_cursor` back as `cursor` until it is `null`. Authenticate with an API key (`b4m_live_`) carrying `ai:chat` or `ai:generate`, or a JWT.",
|
|
15448
|
+
tags: ["Models"],
|
|
15449
|
+
auth: "apiKeyOrJwt",
|
|
15450
|
+
scopes: ["ai:chat", "ai:generate"],
|
|
15451
|
+
queryParams: PaginationQuerySchema,
|
|
15452
|
+
emitsRateLimitHeaders: true,
|
|
15453
|
+
responses: {
|
|
15454
|
+
200: {
|
|
15455
|
+
description: "One page of models, ordered by `id`.",
|
|
15456
|
+
schema: ListModelsResponseSchema,
|
|
15457
|
+
example: {
|
|
15458
|
+
data: [{
|
|
15459
|
+
id: "gpt-image-1",
|
|
15460
|
+
name: "GPT Image 1",
|
|
15461
|
+
type: "image",
|
|
15462
|
+
backend: "openai",
|
|
15463
|
+
description: null,
|
|
15464
|
+
context_window: 0,
|
|
15465
|
+
max_output_tokens: 0,
|
|
15466
|
+
supports_streaming: false,
|
|
15467
|
+
supports_thinking: false,
|
|
15468
|
+
supports_tools: false,
|
|
15469
|
+
supports_vision: false,
|
|
15470
|
+
deprecation_date: null,
|
|
15471
|
+
replaced_by: null,
|
|
15472
|
+
image: {
|
|
15473
|
+
sizing: {
|
|
15474
|
+
kind: "presets",
|
|
15475
|
+
presets: [
|
|
15476
|
+
"1024x1024",
|
|
15477
|
+
"1024x1536",
|
|
15478
|
+
"1536x1024"
|
|
15479
|
+
],
|
|
15480
|
+
default_size: "1024x1024"
|
|
15481
|
+
},
|
|
15482
|
+
supports: {
|
|
15483
|
+
transparent_background: true,
|
|
15484
|
+
seed: false,
|
|
15485
|
+
qualities: [
|
|
15486
|
+
"low",
|
|
15487
|
+
"medium",
|
|
15488
|
+
"high",
|
|
15489
|
+
"auto"
|
|
15490
|
+
],
|
|
15491
|
+
max_images: 10,
|
|
15492
|
+
max_reference_images: 4,
|
|
15493
|
+
edit: true,
|
|
15494
|
+
requires_input_image: false
|
|
15495
|
+
}
|
|
15496
|
+
}
|
|
15497
|
+
}],
|
|
15498
|
+
next_cursor: null
|
|
15499
|
+
}
|
|
15500
|
+
},
|
|
15501
|
+
422: {
|
|
15502
|
+
description: "`limit` is out of range, or `cursor` is malformed or was issued by a different endpoint. A cursor is opaque: pass back exactly the `next_cursor` you were given.",
|
|
15503
|
+
schema: ApiErrorSchema
|
|
15504
|
+
},
|
|
15505
|
+
429: {
|
|
15506
|
+
description: "Per-user rate limit exceeded.",
|
|
15507
|
+
schema: ApiErrorSchema
|
|
15508
|
+
}
|
|
15509
|
+
},
|
|
15510
|
+
codeSample: {
|
|
15511
|
+
authToken: "b4m_live_<key>",
|
|
15512
|
+
streaming: false,
|
|
15513
|
+
body: {}
|
|
15514
|
+
}
|
|
15515
|
+
});
|
|
14654
15516
|
/** Shared by generateImage and editImage: both hand off to the same quest poll. */
|
|
14655
15517
|
const imageQuestPollResult = {
|
|
14656
15518
|
schema: ImageQuestSchema,
|
|
@@ -14668,7 +15530,7 @@ defineEndpoint({
|
|
|
14668
15530
|
path: "/api/v1/image-generations",
|
|
14669
15531
|
operationId: "generateImage",
|
|
14670
15532
|
summary: "Generate an image",
|
|
14671
|
-
description: "Queues an image generation and returns immediately with the quest that will carry the result - no image yet, and the call never blocks on the render. Poll `GET /api/v1/quests/{id}` until `status` is `\"done\"` (see the `generateImage200PollResult` schema). Omit `sessionId` to create a new session. The prompt is resolved against the session history first, so a follow-up such as \"make it darker\" binds to the previous image; `enhancedPrompt` reports the prompt actually sent to the model. Send `prompt_resolution: \"literal\"` to skip that step and have the prompt sent as written (apart from truncation to the model's prompt limit). `referenceImageFabFileIds` passes up to 4 already-uploaded images as style anchors, after the input image taken from `fabFileIds`. Only gpt-image models accept them: sending any with another model is rejected with a 400 rather than ignored. Which `size` values a model accepts, and whether it honours `background`, `seed`, `quality`, `n` and reference images, is listed per model in the `image` block of `GET /api/models`. Credits are checked when the render runs, so insufficient credits arrive on the polled quest rather than as a 422. `POST /api/ai/generate-image` is a legacy alias of this endpoint. Authenticate with an API key (`b4m_live_`) or a JWT.\n\nOptional `callbackUrl`: an https URL that receives a signed POST when the quest settles (success, failure, or a stop; a failed render is `type: \"error\"` in the body, same as the poll). The body is the `GET /api/v1/quests/{id}` response. Headers: `X-Webhook-Event-ID` (the same on every attempt for one settlement; delivery is at-least-once, so dedupe on it, and a retried quest settles again under a new one), `X-Webhook-Delivery-ID` (unique per attempt), `X-Webhook-Timestamp` (unix seconds), `X-Webhook-Signature-256` (`sha256=` + hex HMAC-SHA256 of `<timestamp>.<raw body>` keyed with the API key's callback signing secret), and `X-Event-Type: quest.settled`. Delivery makes up to 5 attempts, retrying on a 5xx, 408, 429, timeout or network error - never on any other 4xx, and redirects are not followed; your endpoint must answer 2xx within 10 seconds. Requires API-key authentication and a signing secret on that key (returned once at key creation, or via `POST /api/user-api-keys/{id}/callback-secret`). A `callbackUrl` is rejected with a 400 when the request is not API-key authenticated, the key has no signing secret, the URL resolves to a private address, or the deployment does not deliver callbacks; a URL that is not https fails request validation with a 422. Polling still works whether or not `callbackUrl` is set.",
|
|
15533
|
+
description: "Queues an image generation and returns immediately with the quest that will carry the result - no image yet, and the call never blocks on the render. Poll `GET /api/v1/quests/{id}` until `status` is `\"done\"` (see the `generateImage200PollResult` schema). Omit `sessionId` to create a new session. The prompt is resolved against the session history first, so a follow-up such as \"make it darker\" binds to the previous image; `enhancedPrompt` reports the prompt actually sent to the model. Send `prompt_resolution: \"literal\"` to skip that step and have the prompt sent as written (apart from truncation to the model's prompt limit). `referenceImageFabFileIds` passes up to 4 already-uploaded images as style anchors, after the input image taken from `fabFileIds`. Only gpt-image models accept them: sending any with another model is rejected with a 400 rather than ignored. Which `size` values a model accepts, and whether it honours `background`, `seed`, `quality`, `n` and reference images, is listed per model in the `image` block of `GET /api/v1/models`. Credits are checked when the render runs, so insufficient credits arrive on the polled quest rather than as a 422. `POST /api/ai/generate-image` is a legacy alias of this endpoint. Authenticate with an API key (`b4m_live_`) or a JWT.\n\nOptional `callbackUrl`: an https URL that receives a signed POST when the quest settles (success, failure, or a stop; a failed render is `type: \"error\"` in the body, same as the poll). The body is the `GET /api/v1/quests/{id}` response. Headers: `X-Webhook-Event-ID` (the same on every attempt for one settlement; delivery is at-least-once, so dedupe on it, and a retried quest settles again under a new one), `X-Webhook-Delivery-ID` (unique per attempt), `X-Webhook-Timestamp` (unix seconds), `X-Webhook-Signature-256` (`sha256=` + hex HMAC-SHA256 of `<timestamp>.<raw body>` keyed with the API key's callback signing secret), and `X-Event-Type: quest.settled`. Delivery makes up to 5 attempts, retrying on a 5xx, 408, 429, timeout or network error - never on any other 4xx, and redirects are not followed; your endpoint must answer 2xx within 10 seconds. Requires API-key authentication and a signing secret on that key (returned once at key creation, or via `POST /api/user-api-keys/{id}/callback-secret`). A `callbackUrl` is rejected with a 400 when the request is not API-key authenticated, the key has no signing secret, the URL resolves to a private address, or the deployment does not deliver callbacks; a URL that is not https fails request validation with a 422. Polling still works whether or not `callbackUrl` is set.",
|
|
14672
15534
|
tags: ["Images"],
|
|
14673
15535
|
auth: "apiKeyOrJwt",
|
|
14674
15536
|
scopes: ["ai:generate"],
|
|
@@ -14953,7 +15815,7 @@ defineEndpoint({
|
|
|
14953
15815
|
path: "/api/v1/sessions",
|
|
14954
15816
|
operationId: "createSession",
|
|
14955
15817
|
summary: "Create a session",
|
|
14956
|
-
description: "Creates a session (called a \"notebook\" in the product UI). Pass the returned `id` as `
|
|
15818
|
+
description: "Creates a session (called a \"notebook\" in the product UI). Pass the returned `id` as `sessionId` to `POST /api/chat`, then poll `GET /api/v1/quests/{id}` for the reply. An API key needs `notebooks:write` for this call, so a chat round trip needs that scope as well as `ai:chat`. Unknown body fields are ignored. Naming a data lake with `dataLakeId` (ids come from `GET /api/v1/data-lakes`) seeds the session with that lake's retrieval defaults and turns on forced retrieval.",
|
|
14957
15819
|
tags: ["Sessions"],
|
|
14958
15820
|
auth: "apiKeyOrJwt",
|
|
14959
15821
|
scopes: ["notebooks:write"],
|
|
@@ -14984,6 +15846,68 @@ defineEndpoint({
|
|
|
14984
15846
|
body: { name: "Quarterly analysis" }
|
|
14985
15847
|
}
|
|
14986
15848
|
});
|
|
15849
|
+
defineEndpoint({
|
|
15850
|
+
method: "get",
|
|
15851
|
+
path: "/api/v1/sessions",
|
|
15852
|
+
operationId: "listSessions",
|
|
15853
|
+
summary: "List sessions",
|
|
15854
|
+
description: "Lists the sessions you own (called \"notebooks\" in the product UI), newest first. Sessions shared with you are not included; read one of those by id with `GET /api/sessions/{id}`. Each item has the same shape `GET /api/sessions/{id}` returns. Cursor-paginated (see the pagination convention): pass `next_cursor` back as `cursor` until it is `null`. Changing `search`, `surface` or `origin` starts a new listing, so drop the cursor when you do. An API key needs `notebooks:read` or `notebooks:write`.",
|
|
15855
|
+
tags: ["Sessions"],
|
|
15856
|
+
auth: "apiKeyOrJwt",
|
|
15857
|
+
scopes: ["notebooks:read", "notebooks:write"],
|
|
15858
|
+
queryParams: ListSessionsQuerySchema,
|
|
15859
|
+
emitsRateLimitHeaders: true,
|
|
15860
|
+
responses: {
|
|
15861
|
+
200: {
|
|
15862
|
+
description: "One page of sessions, newest first by `id`.",
|
|
15863
|
+
schema: ListSessionsResponseSchema
|
|
15864
|
+
},
|
|
15865
|
+
403: {
|
|
15866
|
+
description: "The API key holds neither `notebooks:read` nor `notebooks:write`.",
|
|
15867
|
+
schema: ScopeForbiddenErrorSchema
|
|
15868
|
+
},
|
|
15869
|
+
422: {
|
|
15870
|
+
description: "`limit` is out of range, a filter is malformed, or `cursor` is malformed or was issued by a different endpoint. A cursor is opaque: pass back exactly the `next_cursor` you were given.",
|
|
15871
|
+
schema: ApiErrorSchema
|
|
15872
|
+
},
|
|
15873
|
+
429: {
|
|
15874
|
+
description: "Per-user rate limit exceeded.",
|
|
15875
|
+
schema: ApiErrorSchema
|
|
15876
|
+
}
|
|
15877
|
+
},
|
|
15878
|
+
codeSample: {
|
|
15879
|
+
authToken: "b4m_live_<key>",
|
|
15880
|
+
streaming: false
|
|
15881
|
+
}
|
|
15882
|
+
});
|
|
15883
|
+
defineEndpoint({
|
|
15884
|
+
method: "get",
|
|
15885
|
+
path: "/api/v1/whats-new",
|
|
15886
|
+
operationId: "listWhatsNew",
|
|
15887
|
+
summary: "List release notes",
|
|
15888
|
+
description: "Lists published release notes, newest first. Public: no credentials are needed, and the response is cacheable for up to about 15 minutes (5 fresh plus 10 stale-while-revalidate), so a newly published or withdrawn note can take that long to show. A deployment that proxies an upstream feed stacks its own caching on the upstream's, so there it can take about 31 minutes. Cursor-paginated (see the pagination convention): pass `next_cursor` back as `cursor` until it is `null`. Rate limited per client IP.",
|
|
15889
|
+
tags: ["Release notes"],
|
|
15890
|
+
auth: "public",
|
|
15891
|
+
queryParams: PaginationQuerySchema,
|
|
15892
|
+
responses: {
|
|
15893
|
+
200: {
|
|
15894
|
+
description: "One page of published release notes, newest first by `published_at`.",
|
|
15895
|
+
schema: paginatedResponseSchema(PublicReleaseNoteSchema)
|
|
15896
|
+
},
|
|
15897
|
+
422: {
|
|
15898
|
+
description: "`limit` is out of range, or `cursor` is malformed or was issued by a different endpoint. A cursor is opaque: pass back exactly the `next_cursor` you were given. On a deployment that proxies an upstream feed, a cursor issued by that upstream which can no longer be served there ends the list (200 with empty `data`) rather than returning 422.",
|
|
15899
|
+
schema: ApiErrorSchema
|
|
15900
|
+
},
|
|
15901
|
+
429: {
|
|
15902
|
+
description: "Per-IP rate limit exceeded.",
|
|
15903
|
+
schema: ApiErrorSchema
|
|
15904
|
+
},
|
|
15905
|
+
500: {
|
|
15906
|
+
description: "Unexpected server error.",
|
|
15907
|
+
schema: ApiErrorSchema
|
|
15908
|
+
}
|
|
15909
|
+
}
|
|
15910
|
+
});
|
|
14987
15911
|
/**
|
|
14988
15912
|
* The read/write/query API-key scope sets the data-lake doors accept (OR semantics), shared by the
|
|
14989
15913
|
* SPA routes (`apps/client/server/dataLakes/dataLakeScopes.ts` re-exports these) and the public
|
|
@@ -15173,22 +16097,202 @@ defineEndpoint({
|
|
|
15173
16097
|
emitsRateLimitHeaders: true,
|
|
15174
16098
|
responses: {
|
|
15175
16099
|
200: {
|
|
15176
|
-
description: "The file is no longer a member; the lake's updated totals.",
|
|
15177
|
-
schema: DataLakeFileMembershipResponseSchema
|
|
15178
|
-
},
|
|
15179
|
-
403: {
|
|
15180
|
-
description: WRITE_FORBIDDEN,
|
|
15181
|
-
schema: ScopeForbiddenErrorSchema
|
|
15182
|
-
},
|
|
15183
|
-
404: {
|
|
15184
|
-
description: "The lake is not visible to the caller, or the file is not a current member of it.",
|
|
15185
|
-
schema: ApiErrorSchema
|
|
16100
|
+
description: "The file is no longer a member; the lake's updated totals.",
|
|
16101
|
+
schema: DataLakeFileMembershipResponseSchema
|
|
16102
|
+
},
|
|
16103
|
+
403: {
|
|
16104
|
+
description: WRITE_FORBIDDEN,
|
|
16105
|
+
schema: ScopeForbiddenErrorSchema
|
|
16106
|
+
},
|
|
16107
|
+
404: {
|
|
16108
|
+
description: "The lake is not visible to the caller, or the file is not a current member of it.",
|
|
16109
|
+
schema: ApiErrorSchema
|
|
16110
|
+
},
|
|
16111
|
+
429: {
|
|
16112
|
+
description: "Per-user rate limit exceeded.",
|
|
16113
|
+
schema: ApiErrorSchema
|
|
16114
|
+
}
|
|
16115
|
+
},
|
|
16116
|
+
codeSample: {
|
|
16117
|
+
authToken: "b4m_live_<key>",
|
|
16118
|
+
streaming: false,
|
|
16119
|
+
body: {}
|
|
16120
|
+
}
|
|
16121
|
+
});
|
|
16122
|
+
defineEndpoint({
|
|
16123
|
+
method: "post",
|
|
16124
|
+
path: "/api/v1/data-lakes/{id}/search",
|
|
16125
|
+
operationId: "searchDataLake",
|
|
16126
|
+
summary: "Search a data lake",
|
|
16127
|
+
description: "Semantic (vector) search over one lake: the query is embedded with the model the corpus was indexed with and the top `top_k` passages at or above `min_score` are returned. Only members of this lake are searched - never the caller's other files. `tags` narrows to files carrying any of the listed tags. Files still being indexed or paused are withheld rather than searched stale: `partial_results` is then true and `retrieval_unavailable` counts them (poll `GET /api/v1/data-lakes/{id}/files/{file_id}` for a specific file). The query embedding is billed as credits. Limited to 10 searches per minute per caller, shared with the product UI.",
|
|
16128
|
+
tags: ["Data Lakes"],
|
|
16129
|
+
auth: "apiKeyOrJwt",
|
|
16130
|
+
scopes: DATA_LAKE_QUERY_API_KEY_SCOPES,
|
|
16131
|
+
pathParams: DataLakeIdParamSchema,
|
|
16132
|
+
request: DataLakeSearchRequestSchema,
|
|
16133
|
+
requestExample: {
|
|
16134
|
+
query: "What is our refund policy for annual plans?",
|
|
16135
|
+
top_k: 5
|
|
16136
|
+
},
|
|
16137
|
+
emitsRateLimitHeaders: true,
|
|
16138
|
+
responses: {
|
|
16139
|
+
200: {
|
|
16140
|
+
description: "The ranked passages and what, if anything, was withheld.",
|
|
16141
|
+
schema: DataLakeSearchResponseSchema
|
|
16142
|
+
},
|
|
16143
|
+
400: {
|
|
16144
|
+
description: "The API key bills an organization that no longer exists, or one its owner is no longer a member of.",
|
|
16145
|
+
schema: ApiErrorSchema
|
|
16146
|
+
},
|
|
16147
|
+
403: {
|
|
16148
|
+
description: `The API key lacks \`datalake:query\`, ${FEATURE_DISABLED_NOTE}.`,
|
|
16149
|
+
schema: ScopeForbiddenErrorSchema
|
|
16150
|
+
},
|
|
16151
|
+
404: {
|
|
16152
|
+
description: `${NOT_VISIBLE_LAKE} A lake the caller can read but is not entitled to search is reported the same way, as is a lake that is not \`active\` yet (a draft lake is readable but not yet searchable).`,
|
|
16153
|
+
schema: ApiErrorSchema
|
|
16154
|
+
},
|
|
16155
|
+
422: {
|
|
16156
|
+
description: "Request body failed validation, or the caller cannot afford the query embedding - the latter is tagged `errorCode: \"insufficient_credits\"` (the balance is short, or the org member credit cap is exhausted).",
|
|
16157
|
+
schema: InsufficientCreditsErrorSchema
|
|
16158
|
+
},
|
|
16159
|
+
429: {
|
|
16160
|
+
description: "Search rate limit (10 per minute) or per-user API rate limit exceeded.",
|
|
16161
|
+
schema: ApiErrorSchema
|
|
16162
|
+
},
|
|
16163
|
+
503: {
|
|
16164
|
+
description: "No usable key is configured on this deployment for the embedding provider the query needs (`errorCode: \"provider_not_configured\"`).",
|
|
16165
|
+
schema: ProviderNotConfiguredErrorSchema
|
|
16166
|
+
}
|
|
16167
|
+
},
|
|
16168
|
+
codeSample: {
|
|
16169
|
+
authToken: "b4m_live_<key>",
|
|
16170
|
+
streaming: false,
|
|
16171
|
+
body: {
|
|
16172
|
+
query: "What is our refund policy for annual plans?",
|
|
16173
|
+
top_k: 5
|
|
16174
|
+
}
|
|
16175
|
+
}
|
|
16176
|
+
});
|
|
16177
|
+
const exampleJob = {
|
|
16178
|
+
id: EXAMPLE_RESOURCE_ID,
|
|
16179
|
+
object: "video_generation",
|
|
16180
|
+
state: "pending",
|
|
16181
|
+
model: "grok-imagine-video-1.5",
|
|
16182
|
+
mode: "text_to_video",
|
|
16183
|
+
prompt: "A slow dolly shot of a red lighthouse at dusk",
|
|
16184
|
+
duration_seconds: 6,
|
|
16185
|
+
aspect_ratio: "16:9",
|
|
16186
|
+
resolution: "480p",
|
|
16187
|
+
source: "api",
|
|
16188
|
+
progress: null,
|
|
16189
|
+
error: null,
|
|
16190
|
+
output: null,
|
|
16191
|
+
credits: {
|
|
16192
|
+
reserved: 960,
|
|
16193
|
+
settled: null
|
|
16194
|
+
},
|
|
16195
|
+
created_at: "2026-10-06T00:00:00.000Z",
|
|
16196
|
+
updated_at: "2026-10-06T00:00:00.000Z"
|
|
16197
|
+
};
|
|
16198
|
+
const scopeForbidden = {
|
|
16199
|
+
description: "The API key lacks the `ai:generate` scope.",
|
|
16200
|
+
schema: ScopeForbiddenErrorSchema
|
|
16201
|
+
};
|
|
16202
|
+
const notFound = {
|
|
16203
|
+
description: "No video generation with that id was requested by the caller (a malformed id is also a 404).",
|
|
16204
|
+
schema: ApiErrorSchema
|
|
16205
|
+
};
|
|
16206
|
+
const rateLimited = {
|
|
16207
|
+
description: "Per-user rate limit exceeded.",
|
|
16208
|
+
schema: ApiErrorSchema
|
|
16209
|
+
};
|
|
16210
|
+
defineEndpoint({
|
|
16211
|
+
method: "get",
|
|
16212
|
+
path: "/api/v1/video-models",
|
|
16213
|
+
operationId: "listVideoModels",
|
|
16214
|
+
summary: "List the video models you can use",
|
|
16215
|
+
description: "Returns the video models that are enabled, available in this deployment and have a usable provider key for the caller, with their capabilities and per-second credit price. Validate requests against these capabilities: an unsupported duration, aspect ratio or resolution is a 422, never silently adjusted.",
|
|
16216
|
+
tags: ["Videos"],
|
|
16217
|
+
auth: "apiKeyOrJwt",
|
|
16218
|
+
scopes: ["ai:generate"],
|
|
16219
|
+
responses: {
|
|
16220
|
+
200: {
|
|
16221
|
+
description: "The usable models.",
|
|
16222
|
+
schema: ListVideoModelsResponseSchema
|
|
16223
|
+
},
|
|
16224
|
+
403: scopeForbidden,
|
|
16225
|
+
429: rateLimited
|
|
16226
|
+
},
|
|
16227
|
+
emitsRateLimitHeaders: true,
|
|
16228
|
+
codeSample: {
|
|
16229
|
+
authToken: "b4m_live_<key>",
|
|
16230
|
+
streaming: false,
|
|
16231
|
+
body: {}
|
|
16232
|
+
}
|
|
16233
|
+
});
|
|
16234
|
+
defineEndpoint({
|
|
16235
|
+
method: "post",
|
|
16236
|
+
path: "/api/v1/video-generations",
|
|
16237
|
+
operationId: "createVideoGeneration",
|
|
16238
|
+
summary: "Start a video generation",
|
|
16239
|
+
description: "Queues a video generation and returns `202` with the job. Poll `GET /api/v1/video-generations/{id}` until `state` is `succeeded`, `failed`, `blocked` or `cancelled`. On success, `output.availability` says whether the clip can be downloaded: `ready` means `output.url` is a signed download URL valid for 15 minutes (re-fetch the job for a fresh one); `pending_scan` means the saved file is still being scanned, so keep re-fetching the job (self-hosted installs can stay here for up to ~30 minutes); `unavailable` means the file was blocked or deleted and `output.url` will never be set, so stop polling. Credits for the requested duration are reserved up front and settled on completion; a failed or cancelled job is not charged. A `blocked` job is not charged either, unless the provider generated the clip before rejecting it and billed it: then the requested duration is charged and `credits.settled` shows it. Send an `Idempotency-Key` header (1-255 printable ASCII characters) to make retries safe: a repeat with the same key and body returns the original job, and the same key with a different body is a 422 `idempotency_key_reused`. Omitted fields take the model defaults from `GET /api/v1/video-models`.",
|
|
16240
|
+
tags: ["Videos"],
|
|
16241
|
+
auth: "apiKeyOrJwt",
|
|
16242
|
+
scopes: ["ai:generate"],
|
|
16243
|
+
request: CreateVideoGenerationBodySchema,
|
|
16244
|
+
requestExample: {
|
|
16245
|
+
model: "grok-imagine-video-1.5",
|
|
16246
|
+
prompt: "A slow dolly shot of a red lighthouse at dusk"
|
|
16247
|
+
},
|
|
16248
|
+
responses: {
|
|
16249
|
+
202: {
|
|
16250
|
+
description: "Accepted; the job is queued (or replayed for a repeated Idempotency-Key).",
|
|
16251
|
+
schema: VideoGenerationSchema,
|
|
16252
|
+
example: exampleJob
|
|
16253
|
+
},
|
|
16254
|
+
403: scopeForbidden,
|
|
16255
|
+
404: {
|
|
16256
|
+
description: "`input_image_file_id` does not name an image you own (`errorCode: input_image_not_found`).",
|
|
16257
|
+
schema: VideoGenerationErrorResponseSchema
|
|
16258
|
+
},
|
|
16259
|
+
422: {
|
|
16260
|
+
description: "The request cannot run: a body or capability violation (`errorCode` names it, e.g. `unsupported_duration`), an unknown or unavailable model (`model_unavailable`), a model your administrator disabled (`model_disabled`), too few credits (`insufficient_credits`), or an Idempotency-Key problem (`invalid_idempotency_key`, `idempotency_key_reused`).",
|
|
16261
|
+
schema: VideoGenerationErrorResponseSchema
|
|
16262
|
+
},
|
|
16263
|
+
429: rateLimited
|
|
16264
|
+
},
|
|
16265
|
+
emitsRateLimitHeaders: true,
|
|
16266
|
+
codeSample: {
|
|
16267
|
+
authToken: "b4m_live_<key>",
|
|
16268
|
+
streaming: false,
|
|
16269
|
+
body: {
|
|
16270
|
+
model: "grok-imagine-video-1.5",
|
|
16271
|
+
prompt: "A slow dolly shot of a red lighthouse at dusk"
|
|
16272
|
+
}
|
|
16273
|
+
}
|
|
16274
|
+
});
|
|
16275
|
+
defineEndpoint({
|
|
16276
|
+
method: "get",
|
|
16277
|
+
path: "/api/v1/video-generations/{id}",
|
|
16278
|
+
operationId: "getVideoGeneration",
|
|
16279
|
+
summary: "Get a video generation",
|
|
16280
|
+
description: "Returns one job you requested. Each read signs a fresh `output.url` (valid 15 minutes, see `expires_at`).",
|
|
16281
|
+
tags: ["Videos"],
|
|
16282
|
+
auth: "apiKeyOrJwt",
|
|
16283
|
+
scopes: ["ai:generate"],
|
|
16284
|
+
pathParams: VideoGenerationIdParamSchema,
|
|
16285
|
+
responses: {
|
|
16286
|
+
200: {
|
|
16287
|
+
description: "The job.",
|
|
16288
|
+
schema: VideoGenerationSchema,
|
|
16289
|
+
example: exampleJob
|
|
15186
16290
|
},
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
}
|
|
16291
|
+
403: scopeForbidden,
|
|
16292
|
+
404: notFound,
|
|
16293
|
+
429: rateLimited
|
|
15191
16294
|
},
|
|
16295
|
+
emitsRateLimitHeaders: true,
|
|
15192
16296
|
codeSample: {
|
|
15193
16297
|
authToken: "b4m_live_<key>",
|
|
15194
16298
|
streaming: false,
|
|
@@ -15196,105 +16300,59 @@ defineEndpoint({
|
|
|
15196
16300
|
}
|
|
15197
16301
|
});
|
|
15198
16302
|
defineEndpoint({
|
|
15199
|
-
method: "
|
|
15200
|
-
path: "/api/v1/
|
|
15201
|
-
operationId: "
|
|
15202
|
-
summary: "
|
|
15203
|
-
description: "
|
|
15204
|
-
tags: ["
|
|
16303
|
+
method: "get",
|
|
16304
|
+
path: "/api/v1/video-generations",
|
|
16305
|
+
operationId: "listVideoGenerations",
|
|
16306
|
+
summary: "List your video generations",
|
|
16307
|
+
description: "Your jobs, newest first, optionally filtered by `state` and `source`. Cursor-paginated (see the pagination convention): pass `next_cursor` back as `cursor` until it is `null`.",
|
|
16308
|
+
tags: ["Videos"],
|
|
15205
16309
|
auth: "apiKeyOrJwt",
|
|
15206
|
-
scopes:
|
|
15207
|
-
|
|
15208
|
-
request: DataLakeSearchRequestSchema,
|
|
15209
|
-
requestExample: {
|
|
15210
|
-
query: "What is our refund policy for annual plans?",
|
|
15211
|
-
top_k: 5
|
|
15212
|
-
},
|
|
15213
|
-
emitsRateLimitHeaders: true,
|
|
16310
|
+
scopes: ["ai:generate"],
|
|
16311
|
+
queryParams: ListVideoGenerationsQuerySchema,
|
|
15214
16312
|
responses: {
|
|
15215
16313
|
200: {
|
|
15216
|
-
description: "
|
|
15217
|
-
schema:
|
|
15218
|
-
},
|
|
15219
|
-
403: {
|
|
15220
|
-
description: `The API key lacks \`datalake:query\`, ${FEATURE_DISABLED_NOTE}.`,
|
|
15221
|
-
schema: ScopeForbiddenErrorSchema
|
|
15222
|
-
},
|
|
15223
|
-
404: {
|
|
15224
|
-
description: `${NOT_VISIBLE_LAKE} A lake the caller can read but is not entitled to search is reported the same way, as is a lake that is not \`active\` yet (a draft lake is readable but not yet searchable).`,
|
|
15225
|
-
schema: ApiErrorSchema
|
|
16314
|
+
description: "A page of jobs.",
|
|
16315
|
+
schema: ListVideoGenerationsResponseSchema
|
|
15226
16316
|
},
|
|
16317
|
+
403: scopeForbidden,
|
|
15227
16318
|
422: {
|
|
15228
|
-
description: "
|
|
15229
|
-
schema: InsufficientCreditsErrorSchema
|
|
15230
|
-
},
|
|
15231
|
-
429: {
|
|
15232
|
-
description: "Search rate limit (10 per minute) or per-user API rate limit exceeded.",
|
|
16319
|
+
description: "A malformed `cursor`, `limit`, `state` or `source`.",
|
|
15233
16320
|
schema: ApiErrorSchema
|
|
15234
16321
|
},
|
|
15235
|
-
|
|
15236
|
-
description: "No usable key is configured on this deployment for the embedding provider the query needs (`errorCode: \"provider_not_configured\"`).",
|
|
15237
|
-
schema: ProviderNotConfiguredErrorSchema
|
|
15238
|
-
}
|
|
16322
|
+
429: rateLimited
|
|
15239
16323
|
},
|
|
16324
|
+
emitsRateLimitHeaders: true,
|
|
15240
16325
|
codeSample: {
|
|
15241
16326
|
authToken: "b4m_live_<key>",
|
|
15242
16327
|
streaming: false,
|
|
15243
|
-
body: {
|
|
15244
|
-
query: "What is our refund policy for annual plans?",
|
|
15245
|
-
top_k: 5
|
|
15246
|
-
}
|
|
16328
|
+
body: {}
|
|
15247
16329
|
}
|
|
15248
16330
|
});
|
|
15249
16331
|
defineEndpoint({
|
|
15250
16332
|
method: "post",
|
|
15251
|
-
path: "/api/v1/video-generations",
|
|
15252
|
-
operationId: "
|
|
15253
|
-
summary: "
|
|
15254
|
-
description: "
|
|
16333
|
+
path: "/api/v1/video-generations/{id}/cancel",
|
|
16334
|
+
operationId: "cancelVideoGeneration",
|
|
16335
|
+
summary: "Cancel a video generation",
|
|
16336
|
+
description: "Requests cancellation and returns the job. A `pending` or `running` job moves to `cancelled` shortly after and its reserved credits are returned. A job already `storing` or finished is returned unchanged (the provider has already produced, and charged for, the video).",
|
|
15255
16337
|
tags: ["Videos"],
|
|
15256
16338
|
auth: "apiKeyOrJwt",
|
|
15257
16339
|
scopes: ["ai:generate"],
|
|
15258
|
-
|
|
15259
|
-
requestExample: {
|
|
15260
|
-
prompt: "a drone shot over a foggy pine forest at sunrise",
|
|
15261
|
-
model: "sora-2",
|
|
15262
|
-
seconds: 4
|
|
15263
|
-
},
|
|
16340
|
+
pathParams: VideoGenerationIdParamSchema,
|
|
15264
16341
|
responses: {
|
|
15265
16342
|
200: {
|
|
15266
|
-
description: "
|
|
15267
|
-
schema:
|
|
15268
|
-
|
|
15269
|
-
schema: VideoQuestSchema,
|
|
15270
|
-
description: "The quest polled at `GET /api/v1/quests/{id}` after this ACK. The render is finished once `status` is `\"done\"`: on success `videos` holds the rendered videos; a render that FAILED is `type: \"error\"` with the reason in `reply`, never a 4xx. That covers credit exhaustion (tagged `errorCode: \"insufficient_credits\"`, the same vocabulary as the synchronous 422s on the audio endpoints) and a provider error. Check `type` before reading `videos`; `errorCode` is absent on unclassified failures, so its absence does not mean success.",
|
|
15271
|
-
example: {
|
|
15272
|
-
id: EXAMPLE_RESOURCE_ID,
|
|
15273
|
-
sessionId: EXAMPLE_SESSION_ID,
|
|
15274
|
-
status: "done",
|
|
15275
|
-
type: "message",
|
|
15276
|
-
videos: ["3f6c1a52-9d1e-4b7a-8c2f-5e0d4a9b1c7e.mp4"]
|
|
15277
|
-
}
|
|
15278
|
-
}
|
|
15279
|
-
},
|
|
15280
|
-
400: {
|
|
15281
|
-
description: `The ${GENERATION_CALLBACK_REJECTED_DESCRIPTION}`,
|
|
15282
|
-
schema: ApiErrorSchema
|
|
16343
|
+
description: "The job after the cancel request.",
|
|
16344
|
+
schema: VideoGenerationSchema,
|
|
16345
|
+
example: exampleJob
|
|
15283
16346
|
},
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
}
|
|
16347
|
+
403: scopeForbidden,
|
|
16348
|
+
404: notFound,
|
|
16349
|
+
429: rateLimited
|
|
15288
16350
|
},
|
|
15289
16351
|
emitsRateLimitHeaders: true,
|
|
15290
16352
|
codeSample: {
|
|
15291
16353
|
authToken: "b4m_live_<key>",
|
|
15292
16354
|
streaming: false,
|
|
15293
|
-
body: {
|
|
15294
|
-
prompt: "a drone shot over a foggy pine forest at sunrise",
|
|
15295
|
-
model: "sora-2",
|
|
15296
|
-
seconds: 4
|
|
15297
|
-
}
|
|
16355
|
+
body: {}
|
|
15298
16356
|
}
|
|
15299
16357
|
});
|
|
15300
16358
|
/**
|
|
@@ -15433,12 +16491,136 @@ defineEndpoint({
|
|
|
15433
16491
|
}
|
|
15434
16492
|
},
|
|
15435
16493
|
emitsRateLimitHeaders: true,
|
|
16494
|
+
codeSample: {
|
|
16495
|
+
authToken: "b4m_live_<key>",
|
|
16496
|
+
streaming: false
|
|
16497
|
+
}
|
|
16498
|
+
});
|
|
16499
|
+
/**
|
|
16500
|
+
* The integrator-facing subset of the project API. Each route is a `/api/v1` twin of an SPA route
|
|
16501
|
+
* under `/api/projects/*` and reuses its service logic; the SPA routes are unchanged. Update, delete
|
|
16502
|
+
* and every sub-resource (files, sessions, members, invites, system prompts) are deliberately not
|
|
16503
|
+
* published yet.
|
|
16504
|
+
*/
|
|
16505
|
+
const READ_SCOPES = ["projects:read", "projects:write"];
|
|
16506
|
+
const READ_FORBIDDEN = "The API key holds neither `projects:read` nor `projects:write`.";
|
|
16507
|
+
const MEMBERSHIP_NOTE = "A project's `file_ids` and `session_ids` are shared with it: anyone the project is shared with can read every file and session it groups.";
|
|
16508
|
+
defineEndpoint({
|
|
16509
|
+
method: "get",
|
|
16510
|
+
path: "/api/v1/projects",
|
|
16511
|
+
operationId: "listProjects",
|
|
16512
|
+
summary: "List projects",
|
|
16513
|
+
description: `Lists the projects the caller can read: projects they own and projects shared with them. ${MEMBERSHIP_NOTE} Cursor-paginated (see the pagination convention): pass \`next_cursor\` back as \`cursor\` until it is \`null\`.`,
|
|
16514
|
+
tags: ["Projects"],
|
|
16515
|
+
auth: "apiKeyOrJwt",
|
|
16516
|
+
scopes: READ_SCOPES,
|
|
16517
|
+
queryParams: PaginationQuerySchema,
|
|
16518
|
+
emitsRateLimitHeaders: true,
|
|
16519
|
+
responses: {
|
|
16520
|
+
200: {
|
|
16521
|
+
description: "One page of projects, ordered by `id`.",
|
|
16522
|
+
schema: ListProjectsResponseSchema
|
|
16523
|
+
},
|
|
16524
|
+
403: {
|
|
16525
|
+
description: READ_FORBIDDEN,
|
|
16526
|
+
schema: ScopeForbiddenErrorSchema
|
|
16527
|
+
},
|
|
16528
|
+
422: {
|
|
16529
|
+
description: "`limit` is out of range, or `cursor` is malformed or was issued by a different endpoint. A cursor is opaque: pass back exactly the `next_cursor` you were given.",
|
|
16530
|
+
schema: ApiErrorSchema
|
|
16531
|
+
},
|
|
16532
|
+
429: {
|
|
16533
|
+
description: "Per-user rate limit exceeded.",
|
|
16534
|
+
schema: ApiErrorSchema
|
|
16535
|
+
}
|
|
16536
|
+
},
|
|
16537
|
+
codeSample: {
|
|
16538
|
+
authToken: "b4m_live_<key>",
|
|
16539
|
+
streaming: false,
|
|
16540
|
+
body: {}
|
|
16541
|
+
}
|
|
16542
|
+
});
|
|
16543
|
+
defineEndpoint({
|
|
16544
|
+
method: "get",
|
|
16545
|
+
path: "/api/v1/projects/{id}",
|
|
16546
|
+
operationId: "getProject",
|
|
16547
|
+
summary: "Get a project",
|
|
16548
|
+
description: `Returns one project the caller can read. ${MEMBERSHIP_NOTE}`,
|
|
16549
|
+
tags: ["Projects"],
|
|
16550
|
+
auth: "apiKeyOrJwt",
|
|
16551
|
+
scopes: READ_SCOPES,
|
|
16552
|
+
pathParams: ProjectIdParamSchema,
|
|
16553
|
+
emitsRateLimitHeaders: true,
|
|
16554
|
+
responses: {
|
|
16555
|
+
200: {
|
|
16556
|
+
description: "The project.",
|
|
16557
|
+
schema: ProjectResourceSchema
|
|
16558
|
+
},
|
|
16559
|
+
403: {
|
|
16560
|
+
description: READ_FORBIDDEN,
|
|
16561
|
+
schema: ScopeForbiddenErrorSchema
|
|
16562
|
+
},
|
|
16563
|
+
404: {
|
|
16564
|
+
description: "No project with that id is visible to the caller. A project that exists but is not yours to read, a deleted project and a malformed id are all reported as 404, so project ids cannot be probed through this endpoint.",
|
|
16565
|
+
schema: ApiErrorSchema
|
|
16566
|
+
},
|
|
16567
|
+
429: {
|
|
16568
|
+
description: "Per-user rate limit exceeded.",
|
|
16569
|
+
schema: ApiErrorSchema
|
|
16570
|
+
}
|
|
16571
|
+
},
|
|
15436
16572
|
codeSample: {
|
|
15437
16573
|
authToken: "b4m_live_<key>",
|
|
15438
16574
|
streaming: false,
|
|
15439
16575
|
body: {}
|
|
15440
16576
|
}
|
|
15441
16577
|
});
|
|
16578
|
+
const CREATE_EXAMPLE = {
|
|
16579
|
+
name: "Market research",
|
|
16580
|
+
description: "Sources and notes for the Q3 market analysis.",
|
|
16581
|
+
session_ids: [EXAMPLE_SESSION_ID],
|
|
16582
|
+
file_ids: [EXAMPLE_FILE_ID]
|
|
16583
|
+
};
|
|
16584
|
+
defineEndpoint({
|
|
16585
|
+
method: "post",
|
|
16586
|
+
path: "/api/v1/projects",
|
|
16587
|
+
operationId: "createProject",
|
|
16588
|
+
summary: "Create a project",
|
|
16589
|
+
description: `Creates a project owned by the caller, optionally grouping existing sessions and files in it. Every listed session and file must be readable by the caller. ${MEMBERSHIP_NOTE} Sharing the project later shares them too. Unknown body fields are rejected.`,
|
|
16590
|
+
tags: ["Projects"],
|
|
16591
|
+
auth: "apiKeyOrJwt",
|
|
16592
|
+
scopes: ["projects:write"],
|
|
16593
|
+
request: CreateProjectRequestSchema,
|
|
16594
|
+
requestExample: CREATE_EXAMPLE,
|
|
16595
|
+
emitsRateLimitHeaders: true,
|
|
16596
|
+
responses: {
|
|
16597
|
+
201: {
|
|
16598
|
+
description: "The created project.",
|
|
16599
|
+
schema: ProjectResourceSchema
|
|
16600
|
+
},
|
|
16601
|
+
400: {
|
|
16602
|
+
description: "A listed session or file does not exist or is not readable by the caller, or the body is not valid JSON. Nothing is created.",
|
|
16603
|
+
schema: ApiErrorSchema
|
|
16604
|
+
},
|
|
16605
|
+
403: {
|
|
16606
|
+
description: "The API key lacks `projects:write`.",
|
|
16607
|
+
schema: ScopeForbiddenErrorSchema
|
|
16608
|
+
},
|
|
16609
|
+
422: {
|
|
16610
|
+
description: "Request body failed validation, or you already have a live project with this `name`.",
|
|
16611
|
+
schema: ApiErrorSchema
|
|
16612
|
+
},
|
|
16613
|
+
429: {
|
|
16614
|
+
description: "Per-user rate limit exceeded.",
|
|
16615
|
+
schema: ApiErrorSchema
|
|
16616
|
+
}
|
|
16617
|
+
},
|
|
16618
|
+
codeSample: {
|
|
16619
|
+
authToken: "b4m_live_<key>",
|
|
16620
|
+
streaming: false,
|
|
16621
|
+
body: CREATE_EXAMPLE
|
|
16622
|
+
}
|
|
16623
|
+
});
|
|
15442
16624
|
/**
|
|
15443
16625
|
* The fence language the model writes to place an inline map of search-result places in a reply.
|
|
15444
16626
|
*
|
|
@@ -16337,6 +17519,7 @@ z$1.object({
|
|
|
16337
17519
|
createdAt: z$1.union([z$1.string(), z$1.date()]).optional(),
|
|
16338
17520
|
updatedAt: z$1.union([z$1.string(), z$1.date()]).optional()
|
|
16339
17521
|
});
|
|
17522
|
+
new RegExp(`[аеорсхуіјѕԁһӏαονικρτυ]`, "g");
|
|
16340
17523
|
const OPENER_STICKY = /<artifact/iy;
|
|
16341
17524
|
const WHITESPACE$1 = /\s/;
|
|
16342
17525
|
function isSpace(ch) {
|
|
@@ -16594,6 +17777,34 @@ function stripDeliveredArtifactBlocks(text, deliveredMarkup) {
|
|
|
16594
17777
|
}
|
|
16595
17778
|
return out + text.slice(cursor);
|
|
16596
17779
|
}
|
|
17780
|
+
/**
|
|
17781
|
+
* The local token estimate counts every non-OpenAI model with tiktoken's cl100k_base, because tiktoken
|
|
17782
|
+
* has no other vendor's encoding (see TiktokenTokenizer in @bike4mind/utils). Claude's tokenizers spend
|
|
17783
|
+
* more tokens on the same text, so the raw count under-states Claude input. These multipliers scale it
|
|
17784
|
+
* back up to the model's own tokenizer.
|
|
17785
|
+
*
|
|
17786
|
+
* Measured 2026-10-01 against Bedrock input-token usage on 8 KB prose, markdown, TypeScript and JSON
|
|
17787
|
+
* samples. Each multiplier is the smallest ratio across those samples, rounded down, so a scaled estimate
|
|
17788
|
+
* stays a lower bound: it cannot over-reserve credits or reject a turn that actually fits.
|
|
17789
|
+
*/
|
|
17790
|
+
const CLAUDE_4_7_PLUS_MULTIPLIER = 1.5;
|
|
17791
|
+
const CLAUDE_4_5_MULTIPLIER = 1.09;
|
|
17792
|
+
const CLAUDE_FAMILY_VERSION = /(?:^|\.)claude-(?:opus|sonnet|haiku)-(\d+)(?:-(\d{1,2}))?(?=$|[-:])/;
|
|
17793
|
+
/**
|
|
17794
|
+
* Factor to scale a cl100k_base token count by for `modelId`. 1 for anything unmeasured: non-Claude
|
|
17795
|
+
* models, Claude before 4.5 (retired on Bedrock, could not be measured), and Fable (Bedrock rejects it
|
|
17796
|
+
* under the account's data-retention mode). Claude releases after 5.5 inherit the newest factor on the
|
|
17797
|
+
* assumption they keep its tokenizer; [BILLING_DRIFT] flags it if one does not.
|
|
17798
|
+
*/
|
|
17799
|
+
function tokenEstimateMultiplier(modelId) {
|
|
17800
|
+
const match = modelId?.match(CLAUDE_FAMILY_VERSION);
|
|
17801
|
+
if (!match) return 1;
|
|
17802
|
+
const major = Number(match[1]);
|
|
17803
|
+
const minor = Number(match[2] ?? 0);
|
|
17804
|
+
if (major > 4 || major === 4 && minor >= 7) return CLAUDE_4_7_PLUS_MULTIPLIER;
|
|
17805
|
+
if (major === 4 && minor >= 5) return CLAUDE_4_5_MULTIPLIER;
|
|
17806
|
+
return 1;
|
|
17807
|
+
}
|
|
16597
17808
|
[...IMAGE_SIZE_CONSTRAINTS.DALL_E_2.sizes, ...IMAGE_SIZE_CONSTRAINTS.DALL_E_3.sizes];
|
|
16598
17809
|
/** Generation was cut off against the output-token ceiling. */
|
|
16599
17810
|
const TRUNCATED_FINISH_REASON = "max_tokens";
|
|
@@ -16766,6 +17977,17 @@ z$1.array(triggerWordSchema).max(20, "Up to 20 trigger words allowed.").transfor
|
|
|
16766
17977
|
}
|
|
16767
17978
|
return out;
|
|
16768
17979
|
});
|
|
17980
|
+
/**
|
|
17981
|
+
* Extension sets for files a quest tool drops onto `quest.images` (image_generation,
|
|
17982
|
+
* edit_image, music_generation, audio_generation, excel_generation, ...). Single source of
|
|
17983
|
+
* truth shared by the web renderer (PromptReplies.classifyGeneratedFiles) and the API file
|
|
17984
|
+
* classifier (server/utils/generatedFiles), so the two never drift on how a generated file
|
|
17985
|
+
* renders. Browser-safe (regex literals only) - importable from either build.
|
|
17986
|
+
*/
|
|
17987
|
+
const GENERATED_IMAGE_EXTENSION_RE = /\.(png|jpe?g|webp|gif|svg|bmp|avif)$/i;
|
|
17988
|
+
const GENERATED_KEY_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
17989
|
+
new RegExp(`^${GENERATED_KEY_UUID}\\.[a-z]+$`, "i");
|
|
17990
|
+
new RegExp(`^${GENERATED_KEY_UUID}\\.(?:png|jpe?g|webp|gif)$`);
|
|
16769
17991
|
IMAGE_SIZE_CONSTRAINTS.BFL.minWidth, IMAGE_SIZE_CONSTRAINTS.BFL.maxWidth, IMAGE_SIZE_CONSTRAINTS.BFL.stepSize;
|
|
16770
17992
|
const WHITESPACE = /\s/;
|
|
16771
17993
|
const EQUALS_OPS = [
|
|
@@ -16864,7 +18086,7 @@ Array.from(new Set([
|
|
|
16864
18086
|
{
|
|
16865
18087
|
id: "opti.scheduling.problem",
|
|
16866
18088
|
section: "opti",
|
|
16867
|
-
label: "Problem
|
|
18089
|
+
label: "Scheduling Problem",
|
|
16868
18090
|
description: "Define and preview scheduling problems — job-shop matrix encoding",
|
|
16869
18091
|
navigationType: "action",
|
|
16870
18092
|
target: "scheduling.problem",
|
|
@@ -16881,7 +18103,7 @@ Array.from(new Set([
|
|
|
16881
18103
|
{
|
|
16882
18104
|
id: "opti.scheduling.solvers",
|
|
16883
18105
|
section: "opti",
|
|
16884
|
-
label: "
|
|
18106
|
+
label: "Scheduling Solvers",
|
|
16885
18107
|
description: "Configure which solvers to race across a range of optimization strategies",
|
|
16886
18108
|
navigationType: "action",
|
|
16887
18109
|
target: "scheduling.solvers",
|
|
@@ -16957,6 +18179,37 @@ Array.from(new Set([
|
|
|
16957
18179
|
"path"
|
|
16958
18180
|
]
|
|
16959
18181
|
},
|
|
18182
|
+
{
|
|
18183
|
+
id: "opti.routing.problem",
|
|
18184
|
+
section: "opti",
|
|
18185
|
+
label: "Routing Problem",
|
|
18186
|
+
description: "Define and preview routing problems: stops, vehicles, distances",
|
|
18187
|
+
navigationType: "action",
|
|
18188
|
+
target: "routing.problem",
|
|
18189
|
+
keywords: [
|
|
18190
|
+
"routing problem",
|
|
18191
|
+
"stops",
|
|
18192
|
+
"depot",
|
|
18193
|
+
"vehicles",
|
|
18194
|
+
"distances",
|
|
18195
|
+
"route editor"
|
|
18196
|
+
]
|
|
18197
|
+
},
|
|
18198
|
+
{
|
|
18199
|
+
id: "opti.routing.solvers",
|
|
18200
|
+
section: "opti",
|
|
18201
|
+
label: "Routing Solvers",
|
|
18202
|
+
description: "Choose which solvers to race on the routing problem",
|
|
18203
|
+
navigationType: "action",
|
|
18204
|
+
target: "routing.solvers",
|
|
18205
|
+
keywords: [
|
|
18206
|
+
"routing solvers",
|
|
18207
|
+
"TSP solvers",
|
|
18208
|
+
"route solvers",
|
|
18209
|
+
"configure solvers",
|
|
18210
|
+
"solver race"
|
|
18211
|
+
]
|
|
18212
|
+
},
|
|
16960
18213
|
{
|
|
16961
18214
|
id: "opti.packing",
|
|
16962
18215
|
section: "opti",
|
|
@@ -16973,6 +18226,37 @@ Array.from(new Set([
|
|
|
16973
18226
|
"space"
|
|
16974
18227
|
]
|
|
16975
18228
|
},
|
|
18229
|
+
{
|
|
18230
|
+
id: "opti.packing.problem",
|
|
18231
|
+
section: "opti",
|
|
18232
|
+
label: "Packing Problem",
|
|
18233
|
+
description: "Define and preview packing problems: items, bins, capacities",
|
|
18234
|
+
navigationType: "action",
|
|
18235
|
+
target: "packing.problem",
|
|
18236
|
+
keywords: [
|
|
18237
|
+
"packing problem",
|
|
18238
|
+
"items",
|
|
18239
|
+
"bins",
|
|
18240
|
+
"capacity",
|
|
18241
|
+
"knapsack editor",
|
|
18242
|
+
"container"
|
|
18243
|
+
]
|
|
18244
|
+
},
|
|
18245
|
+
{
|
|
18246
|
+
id: "opti.packing.solvers",
|
|
18247
|
+
section: "opti",
|
|
18248
|
+
label: "Packing Solvers",
|
|
18249
|
+
description: "Choose which solvers to race on the packing problem",
|
|
18250
|
+
navigationType: "action",
|
|
18251
|
+
target: "packing.solvers",
|
|
18252
|
+
keywords: [
|
|
18253
|
+
"packing solvers",
|
|
18254
|
+
"bin packing solvers",
|
|
18255
|
+
"knapsack solvers",
|
|
18256
|
+
"configure solvers",
|
|
18257
|
+
"solver race"
|
|
18258
|
+
]
|
|
18259
|
+
},
|
|
16976
18260
|
{
|
|
16977
18261
|
id: "opti.network",
|
|
16978
18262
|
section: "opti",
|
|
@@ -16989,6 +18273,37 @@ Array.from(new Set([
|
|
|
16989
18273
|
"graph"
|
|
16990
18274
|
]
|
|
16991
18275
|
},
|
|
18276
|
+
{
|
|
18277
|
+
id: "opti.network.problem",
|
|
18278
|
+
section: "opti",
|
|
18279
|
+
label: "Network Problem",
|
|
18280
|
+
description: "Define and preview network design problems: nodes, edges, facilities",
|
|
18281
|
+
navigationType: "action",
|
|
18282
|
+
target: "network.problem",
|
|
18283
|
+
keywords: [
|
|
18284
|
+
"network problem",
|
|
18285
|
+
"nodes",
|
|
18286
|
+
"edges",
|
|
18287
|
+
"facilities",
|
|
18288
|
+
"supply chain editor",
|
|
18289
|
+
"graph"
|
|
18290
|
+
]
|
|
18291
|
+
},
|
|
18292
|
+
{
|
|
18293
|
+
id: "opti.network.solvers",
|
|
18294
|
+
section: "opti",
|
|
18295
|
+
label: "Network Solvers",
|
|
18296
|
+
description: "Choose which solvers to race on the network design problem",
|
|
18297
|
+
navigationType: "action",
|
|
18298
|
+
target: "network.solvers",
|
|
18299
|
+
keywords: [
|
|
18300
|
+
"network solvers",
|
|
18301
|
+
"flow solvers",
|
|
18302
|
+
"facility solvers",
|
|
18303
|
+
"configure solvers",
|
|
18304
|
+
"solver race"
|
|
18305
|
+
]
|
|
18306
|
+
},
|
|
16992
18307
|
{
|
|
16993
18308
|
id: "opti.selection",
|
|
16994
18309
|
section: "opti",
|
|
@@ -17005,6 +18320,37 @@ Array.from(new Set([
|
|
|
17005
18320
|
"choose"
|
|
17006
18321
|
]
|
|
17007
18322
|
},
|
|
18323
|
+
{
|
|
18324
|
+
id: "opti.selection.problem",
|
|
18325
|
+
section: "opti",
|
|
18326
|
+
label: "Selection Problem",
|
|
18327
|
+
description: "Define and preview selection problems: candidates, values, constraints",
|
|
18328
|
+
navigationType: "action",
|
|
18329
|
+
target: "selection.problem",
|
|
18330
|
+
keywords: [
|
|
18331
|
+
"selection problem",
|
|
18332
|
+
"candidates",
|
|
18333
|
+
"portfolio editor",
|
|
18334
|
+
"subset",
|
|
18335
|
+
"values",
|
|
18336
|
+
"constraints"
|
|
18337
|
+
]
|
|
18338
|
+
},
|
|
18339
|
+
{
|
|
18340
|
+
id: "opti.selection.solvers",
|
|
18341
|
+
section: "opti",
|
|
18342
|
+
label: "Selection Solvers",
|
|
18343
|
+
description: "Choose which solvers to race on the selection problem",
|
|
18344
|
+
navigationType: "action",
|
|
18345
|
+
target: "selection.solvers",
|
|
18346
|
+
keywords: [
|
|
18347
|
+
"selection solvers",
|
|
18348
|
+
"portfolio solvers",
|
|
18349
|
+
"subset solvers",
|
|
18350
|
+
"configure solvers",
|
|
18351
|
+
"solver race"
|
|
18352
|
+
]
|
|
18353
|
+
},
|
|
17008
18354
|
{
|
|
17009
18355
|
id: "opti.economic",
|
|
17010
18356
|
section: "opti",
|
|
@@ -17021,6 +18367,37 @@ Array.from(new Set([
|
|
|
17021
18367
|
"cost"
|
|
17022
18368
|
]
|
|
17023
18369
|
},
|
|
18370
|
+
{
|
|
18371
|
+
id: "opti.economic.problem",
|
|
18372
|
+
section: "opti",
|
|
18373
|
+
label: "Economic Problem",
|
|
18374
|
+
description: "Define and preview economic problems: resources, prices, budgets",
|
|
18375
|
+
navigationType: "action",
|
|
18376
|
+
target: "economic.problem",
|
|
18377
|
+
keywords: [
|
|
18378
|
+
"economic problem",
|
|
18379
|
+
"resources",
|
|
18380
|
+
"prices",
|
|
18381
|
+
"budget editor",
|
|
18382
|
+
"allocation",
|
|
18383
|
+
"costs"
|
|
18384
|
+
]
|
|
18385
|
+
},
|
|
18386
|
+
{
|
|
18387
|
+
id: "opti.economic.solvers",
|
|
18388
|
+
section: "opti",
|
|
18389
|
+
label: "Economic Solvers",
|
|
18390
|
+
description: "Choose which solvers to race on the economic problem",
|
|
18391
|
+
navigationType: "action",
|
|
18392
|
+
target: "economic.solvers",
|
|
18393
|
+
keywords: [
|
|
18394
|
+
"economic solvers",
|
|
18395
|
+
"allocation solvers",
|
|
18396
|
+
"pricing solvers",
|
|
18397
|
+
"configure solvers",
|
|
18398
|
+
"solver race"
|
|
18399
|
+
]
|
|
18400
|
+
},
|
|
17024
18401
|
{
|
|
17025
18402
|
id: "opti.assignment",
|
|
17026
18403
|
section: "opti",
|
|
@@ -17037,6 +18414,37 @@ Array.from(new Set([
|
|
|
17037
18414
|
"assign"
|
|
17038
18415
|
]
|
|
17039
18416
|
},
|
|
18417
|
+
{
|
|
18418
|
+
id: "opti.assignment.problem",
|
|
18419
|
+
section: "opti",
|
|
18420
|
+
label: "Assignment Problem",
|
|
18421
|
+
description: "Define and preview assignment problems: agents, tasks, cost matrix",
|
|
18422
|
+
navigationType: "action",
|
|
18423
|
+
target: "assignment.problem",
|
|
18424
|
+
keywords: [
|
|
18425
|
+
"assignment problem",
|
|
18426
|
+
"agents",
|
|
18427
|
+
"tasks",
|
|
18428
|
+
"cost matrix",
|
|
18429
|
+
"matching editor",
|
|
18430
|
+
"workers"
|
|
18431
|
+
]
|
|
18432
|
+
},
|
|
18433
|
+
{
|
|
18434
|
+
id: "opti.assignment.solvers",
|
|
18435
|
+
section: "opti",
|
|
18436
|
+
label: "Assignment Solvers",
|
|
18437
|
+
description: "Choose which solvers to race on the assignment problem",
|
|
18438
|
+
navigationType: "action",
|
|
18439
|
+
target: "assignment.solvers",
|
|
18440
|
+
keywords: [
|
|
18441
|
+
"assignment solvers",
|
|
18442
|
+
"matching solvers",
|
|
18443
|
+
"workforce solvers",
|
|
18444
|
+
"configure solvers",
|
|
18445
|
+
"solver race"
|
|
18446
|
+
]
|
|
18447
|
+
},
|
|
17040
18448
|
{
|
|
17041
18449
|
id: "opti.partitioning",
|
|
17042
18450
|
section: "opti",
|
|
@@ -17053,6 +18461,37 @@ Array.from(new Set([
|
|
|
17053
18461
|
"split"
|
|
17054
18462
|
]
|
|
17055
18463
|
},
|
|
18464
|
+
{
|
|
18465
|
+
id: "opti.partitioning.problem",
|
|
18466
|
+
section: "opti",
|
|
18467
|
+
label: "Partitioning Problem",
|
|
18468
|
+
description: "Define and preview partitioning problems: graph, parts, balance",
|
|
18469
|
+
navigationType: "action",
|
|
18470
|
+
target: "partitioning.problem",
|
|
18471
|
+
keywords: [
|
|
18472
|
+
"partitioning problem",
|
|
18473
|
+
"graph",
|
|
18474
|
+
"parts",
|
|
18475
|
+
"balance",
|
|
18476
|
+
"cluster editor",
|
|
18477
|
+
"partition editor"
|
|
18478
|
+
]
|
|
18479
|
+
},
|
|
18480
|
+
{
|
|
18481
|
+
id: "opti.partitioning.solvers",
|
|
18482
|
+
section: "opti",
|
|
18483
|
+
label: "Partitioning Solvers",
|
|
18484
|
+
description: "Choose which solvers to race on the partitioning problem",
|
|
18485
|
+
navigationType: "action",
|
|
18486
|
+
target: "partitioning.solvers",
|
|
18487
|
+
keywords: [
|
|
18488
|
+
"partitioning solvers",
|
|
18489
|
+
"clustering solvers",
|
|
18490
|
+
"balancing solvers",
|
|
18491
|
+
"configure solvers",
|
|
18492
|
+
"solver race"
|
|
18493
|
+
]
|
|
18494
|
+
},
|
|
17056
18495
|
{
|
|
17057
18496
|
id: "admin.users",
|
|
17058
18497
|
section: "admin",
|
|
@@ -18736,6 +20175,7 @@ const CliConfigSchema = z$1.object({
|
|
|
18736
20175
|
* editing the config file directly.
|
|
18737
20176
|
*/
|
|
18738
20177
|
promptVariant: z$1.enum(["current", "minimal"]).optional().prefault("current"),
|
|
20178
|
+
showThoughts: z$1.boolean().optional(),
|
|
18739
20179
|
subagentHistoryTtlMs: z$1.number().optional()
|
|
18740
20180
|
}),
|
|
18741
20181
|
tools: z$1.object({
|
|
@@ -19847,4 +21287,4 @@ var ConfigStore = class {
|
|
|
19847
21287
|
}
|
|
19848
21288
|
};
|
|
19849
21289
|
//#endregion
|
|
19850
|
-
export {
|
|
21290
|
+
export { escapeThinkMarkers as $, ChatModels as A, delegationPayloadSchema as At, NotFoundError as B, ARTIFACT_REMOVED_PLACEHOLDER as C, ttsResponseTooLargeSchema as Ct, BriefcasePromptIdSchema as D, actorColorIndex as Dt, BedrockEmbeddingModel as E, DELEGATION_PAYLOAD_SCHEMA_NAME as Et, ImagePromptResolutionSchema as F, REVIEW_GATE_STATUS_VALUES as G, OpenAIEmbeddingModel as H, LOCATION_MAP_LANGUAGE as I, SupportedFabFileMimeTypes as J, SEARCH_RESULT_CARDS_LANGUAGE as K, MODEL_INFO_FIELD_GROUP_OF as L, DEGENERATE_FINISH_REASON as M, APP_NAME as Mt, GENERATED_IMAGE_EXTENSION_RE as N, WEBSITE_URL as Nt, CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS as O, actorKindMarker as Ot, ImageModels as P, createThinkMarkerEscaper as Q, McpServerName as R, ARTIFACT_DELIVERED_PLACEHOLDER as S, ttsRequestSchema as St, BRIEFCASE_CATALOG_QUERIES as T, ACTOR_COLOR_SLOTS as Tt, PROMPT_TEXT_MAX as U, OllamaEmbeddingModel as V, PermissionDeniedError as W, WORK_ITEM_STATUSES as X, VoyageAIEmbeddingModel as Y, buildPromptContext as Z, requireApiUrl as _, stripDeliveredArtifactBlocks as _t, htmlErrorTitle as a, hasDeliverablePinnedArtifact as at, AGENT_QUEST_MANIFEST as b, tokenEstimateMultiplier as bt, loadContextFiles as c, isRetryableError as ct, isReadOnlyTool as d, obfuscateApiKey as dt, filterToolArtifactMarkup as et, ApiEndpointUnconfiguredError as f, questReplyText as ft, parseApiUrl as g, splitEquals as gt, getEnvironmentName as h, signImageUrl as ht, isValidSessionId as i, googleMapsSearchUrl as it, DEFAULT_TTS_PROVIDER as j, selfClaimedActorKindSchema as jt, CREDIT_DEDUCT_TRANSACTION_TYPES as k, actorKindSchema as kt, canTrustTool as l, isUserInitiatedAbort as lt, getCreditsUrl as m, secureParameters as mt, logger as n, getMcpProviderMetadata as nt, htmlFirstH1 as o, isEarlyStop as ot, LOCAL_DEV_URL as p, replacePromptVariables as pt, SUBQUEST_STATUS_VALUES as q, SESSION_ID_PATTERN as r, getQuestErrorCode as rt, extractCompactInstructions as s, isPlaceholderImageSigningSecret as st, ConfigStore as t, generatedAudioResponseSchema as tt, getToolCategory as u, joinReplySlots as ut, resolveApiEndpoint as v, stripToolArtifactMarkup as vt, ApiKeyType as w, withRetry as wt, AGENT_QUEST_MCP_URI as x, ttsBase64ResponseSchema as xt, AGENT_QUEST_ID as y, supportedVoiceGenerationVendor as yt, ModelBackend as z };
|