@bike4mind/cli 3.2.0 → 3.3.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.
@@ -963,6 +963,7 @@ let ChatModels = /* @__PURE__ */ function(ChatModels) {
963
963
  ChatModels["GPT5_2_CHAT_LATEST"] = "gpt-5.2-chat-latest";
964
964
  ChatModels["GPT5_4"] = "gpt-5.4";
965
965
  ChatModels["GPT5_4_MINI"] = "gpt-5.4-mini";
966
+ ChatModels["GPT5_4_MINI_2026_03_17"] = "gpt-5.4-mini-2026-03-17";
966
967
  ChatModels["GPT5_4_NANO"] = "gpt-5.4-nano";
967
968
  ChatModels["GPT5_5"] = "gpt-5.5";
968
969
  ChatModels["GPT5_6_SOL"] = "gpt-5.6-sol";
@@ -1058,8 +1059,8 @@ let ChatModels = /* @__PURE__ */ function(ChatModels) {
1058
1059
  ChatModels["DEEPSEEK_V4_PRO"] = "deepseek-v4-pro";
1059
1060
  return ChatModels;
1060
1061
  }({});
1061
- const CHAT_MODELS = Object.values(ChatModels);
1062
- const supportedChatModels = z$1.enum(ChatModels);
1062
+ const supportedChatModels = z$1.enum(ChatModels).exclude(["GPT5_4_MINI_2026_03_17"]);
1063
+ const CHAT_MODELS = [...supportedChatModels.options];
1063
1064
  new RegExp(`^${BEDROCK_ANTHROPIC_PREFIX}claude-`);
1064
1065
  /**
1065
1066
  * Models that support OpenAI's `reasoning_effort` request parameter.
@@ -1081,6 +1082,7 @@ const REASONING_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
1081
1082
  "gpt-5.2",
1082
1083
  "gpt-5.4",
1083
1084
  "gpt-5.4-mini",
1085
+ "gpt-5.4-mini-2026-03-17",
1084
1086
  "gpt-5.4-nano",
1085
1087
  "gpt-5.6-sol",
1086
1088
  "gpt-5.6-luna",
@@ -2906,6 +2908,105 @@ const WORK_ITEM_STATUSES = [
2906
2908
  "blocked",
2907
2909
  "closed"
2908
2910
  ];
2911
+ const AuditActorSchema = z$1.object({
2912
+ kind: z$1.enum([
2913
+ "user",
2914
+ "apiKey",
2915
+ "system",
2916
+ "script"
2917
+ ]),
2918
+ scope: z$1.enum(["platform", "organization"]),
2919
+ userId: z$1.string().optional(),
2920
+ apiKeyId: z$1.string().optional(),
2921
+ email: z$1.string().optional(),
2922
+ name: z$1.string(),
2923
+ wasAdmin: z$1.boolean(),
2924
+ impersonatedUserId: z$1.string().optional()
2925
+ });
2926
+ const AuditTargetSchema = z$1.object({
2927
+ kind: z$1.enum([
2928
+ "user",
2929
+ "organization",
2930
+ "settings",
2931
+ "oauthClient",
2932
+ "apiKey",
2933
+ "system"
2934
+ ]),
2935
+ id: z$1.string(),
2936
+ displayName: z$1.string()
2937
+ });
2938
+ const AuditChangeSchema = z$1.object({
2939
+ field: z$1.string(),
2940
+ before: z$1.unknown(),
2941
+ after: z$1.unknown()
2942
+ });
2943
+ const AuditContextSchema = z$1.object({
2944
+ ip: z$1.string().optional(),
2945
+ userAgent: z$1.string().optional(),
2946
+ requestId: z$1.string().optional(),
2947
+ source: z$1.enum([
2948
+ "admin_ui",
2949
+ "api_key",
2950
+ "script",
2951
+ "worker"
2952
+ ]),
2953
+ route: z$1.string().optional()
2954
+ });
2955
+ const AdminAuditCategorySchema = z$1.enum([
2956
+ "credits",
2957
+ "access",
2958
+ "identity",
2959
+ "account",
2960
+ "org",
2961
+ "settings",
2962
+ "support"
2963
+ ]);
2964
+ const AdminAuditSeveritySchema = z$1.enum([
2965
+ "info",
2966
+ "notice",
2967
+ "critical"
2968
+ ]);
2969
+ z$1.object({
2970
+ id: z$1.string(),
2971
+ source: z$1.enum([
2972
+ "admin",
2973
+ "auth",
2974
+ "apiKey",
2975
+ "supportAccess"
2976
+ ]),
2977
+ occurredAt: z$1.date(),
2978
+ action: z$1.string(),
2979
+ category: AdminAuditCategorySchema,
2980
+ severity: AdminAuditSeveritySchema,
2981
+ actor: AuditActorSchema,
2982
+ target: AuditTargetSchema,
2983
+ organizationId: z$1.string().optional(),
2984
+ summary: z$1.string(),
2985
+ reason: z$1.string().optional(),
2986
+ changes: z$1.array(AuditChangeSchema).optional(),
2987
+ details: z$1.record(z$1.string(), z$1.unknown()).optional(),
2988
+ context: AuditContextSchema,
2989
+ related: z$1.object({
2990
+ creditTransactionId: z$1.string().optional(),
2991
+ impersonationSessionId: z$1.string().optional()
2992
+ }).optional(),
2993
+ backfilled: z$1.boolean().optional()
2994
+ });
2995
+ z$1.object({
2996
+ category: AdminAuditCategorySchema.optional(),
2997
+ severity: AdminAuditSeveritySchema.optional(),
2998
+ action: z$1.string().regex(/^[a-z_]+(\.[a-z_]+)+$/).optional(),
2999
+ verb: z$1.string().regex(/^[a-z_]+$/).optional(),
3000
+ actorUserId: z$1.string().min(1).optional(),
3001
+ targetKind: AuditTargetSchema.shape.kind.optional(),
3002
+ targetId: z$1.string().min(1).optional(),
3003
+ source: AuditContextSchema.shape.source.optional(),
3004
+ actorScope: AuditActorSchema.shape.scope.optional(),
3005
+ from: z$1.iso.datetime().optional(),
3006
+ to: z$1.iso.datetime().optional(),
3007
+ requestId: z$1.string().min(1).optional(),
3008
+ impersonationSessionId: z$1.string().min(1).optional()
3009
+ });
2909
3010
  let SupportedFabFileMimeTypes = /* @__PURE__ */ function(SupportedFabFileMimeTypes) {
2910
3011
  SupportedFabFileMimeTypes["PDF"] = "application/pdf";
2911
3012
  SupportedFabFileMimeTypes["DOCX"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
@@ -3134,6 +3235,21 @@ const CREDITS_PER_USD_COST = (() => {
3134
3235
  console.warn(`[pricing] Env-configured margin/rate derive ${derived} credits per USD cost; using defaults`);
3135
3236
  return Math.round(DEFAULT_PRICE_MARGIN / DEFAULT_USD_TO_CREDITS_RATE);
3136
3237
  })();
3238
+ const DEFAULT_PROVIDER_COST_PER_CREDIT_USD = 1 / Math.round(DEFAULT_PRICE_MARGIN / DEFAULT_USD_TO_CREDITS_RATE);
3239
+ /**
3240
+ * Lowest USD price a credit may be sold for: the provider cost one credit stands for, times the
3241
+ * markup - the same sale price usage is billed at - and never less than what a credit costs us at
3242
+ * the built-in rate. The admin `pricePerCredit` save (apps/client/pages/api/settings/update.ts)
3243
+ * refuses a price below it, and per-credit purchases re-check it at charge time
3244
+ * (apps/client/lib/credits/utils.ts).
3245
+ */
3246
+ const MIN_PRICE_PER_CREDIT_USD = (() => {
3247
+ const derived = PRICE_MARGIN / CREDITS_PER_USD_COST;
3248
+ if (!Number.isFinite(derived)) return DEFAULT_USD_TO_CREDITS_RATE;
3249
+ return Math.max(derived, DEFAULT_PROVIDER_COST_PER_CREDIT_USD);
3250
+ })();
3251
+ /** USD price per credit for display, without float noise (0.0006, not 0.0006000000000000001). */
3252
+ const formatUsdPerCredit = (usd) => `$${Number(usd.toPrecision(6))}`;
3137
3253
  z.enum([
3138
3254
  "openai",
3139
3255
  "test",
@@ -3656,6 +3772,12 @@ z$1.enum([
3656
3772
  "investigate_soon",
3657
3773
  "immediate_action"
3658
3774
  ]);
3775
+ /**
3776
+ * Largest legacy thinking budget (`budget_tokens`) a request may ask for. Anthropic rejects rather
3777
+ * than clamps an oversized budget, and the budget raises the max_tokens a turn is sent with, so it
3778
+ * is bounded both at the request schemas and where the adapter consumes it (buildThinkingParams).
3779
+ */
3780
+ const MAX_THINKING_BUDGET_TOKENS = 32e3;
3659
3781
  const CompletionReasoningEffortSchema = z$1.enum([
3660
3782
  "none",
3661
3783
  "minimal",
@@ -3705,9 +3827,24 @@ const COMPLETION_TOOL_ERROR_CODES = [
3705
3827
  "tool_search_unsupported",
3706
3828
  "all_tools_deferred",
3707
3829
  "deferred_tool_cache_control",
3708
- "unknown_tool_reference"
3830
+ "unknown_tool_reference",
3831
+ "tool_changes_unsupported",
3832
+ "invalid_tool_change"
3709
3833
  ];
3710
3834
  /**
3835
+ * One block of a mid-conversation tool change: a `system`-role message whose content holds only these.
3836
+ * Strict on purpose: the provider takes a name reference to a tool already in `tools`, never an inline
3837
+ * definition or an MCP reference.
3838
+ */
3839
+ const ToolChangeBlockSchema = z$1.object({
3840
+ type: z$1.enum(["tool_addition", "tool_removal"]),
3841
+ tool: z$1.object({
3842
+ type: z$1.literal("tool_reference"),
3843
+ name: z$1.string().min(1)
3844
+ }).strict()
3845
+ }).strict();
3846
+ z$1.array(ToolChangeBlockSchema).min(1);
3847
+ /**
3711
3848
  * JSON Schema definition for structured output. The `schema` field is a full
3712
3849
  * JSON Schema document (we don't try to validate JSON Schema with Zod - that's
3713
3850
  * the caller's contract with the model). `strict: true` is the default, matching
@@ -3733,7 +3870,7 @@ const CompletionMessageSchema = z$1.object({
3733
3870
  "assistant",
3734
3871
  "system"
3735
3872
  ]),
3736
- content: z$1.union([z$1.string(), z$1.array(z$1.any())]),
3873
+ content: z$1.union([z$1.string(), z$1.array(z$1.any())]).describe("A string, or an array of content blocks. A `system` message may instead hold only `tool_addition` / `tool_removal` blocks (`{ type, tool: { type: \"tool_reference\", name } }`) to load or unload a tool named in `tools` mid-conversation without invalidating the prompt cache. It must follow a user turn or an assistant turn ending in a tool search result, and be the last message or precede an assistant turn. Only on models whose `supports_tool_changes` is true and that are served by the direct Anthropic API; otherwise refused with `errorCode: \"tool_changes_unsupported\"` (or `invalid_tool_change` / `unknown_tool_reference` when malformed)."),
3737
3874
  cache: z$1.boolean().optional()
3738
3875
  });
3739
3876
  /**
@@ -3763,8 +3900,8 @@ const CompletionRequestSchema = z$1.object({
3763
3900
  reasoningEffort: CompletionReasoningEffortSchema.optional().describe("Reasoning effort hint. Honoured by the OpenAI (reasoning models only, and not alongside tools on some of them), Kimi (K3 only), DeepSeek and Anthropic Claude (direct and Bedrock) adapters; each maps it onto its own scale. On Claude, `none` turns thinking off where the model allows it (otherwise it runs at the lowest effort), so short `max_tokens` replies stream visible text from the start; `minimal` maps to `low`. When `thinking.enabled` is also set on a Claude model, thinking stays on and this sets its effort instead, with `none` and `minimal` mapping to `low`. Claude models that reason inside `max_tokens` never have that ceiling raised, and on older Claude models any level above `none` turns thinking on (it is off by default there), forces temperature to 1 and drops top_p, and a thinking budget that cannot fit under `max_tokens` is skipped. On the direct Anthropic API, a json_schema `response_format` with no tools is served by a forced tool on models that support forced tool use, and that tool cannot run alongside thinking, so there only `none` is honoured; models served by native structured outputs honour every level. Silently ignored by every other adapter (Gemini, xAI, Ollama) and by non-reasoning models, so sending it there is a no-op."),
3764
3901
  thinking: z$1.object({
3765
3902
  enabled: z$1.boolean(),
3766
- budget_tokens: z$1.number().int().min(1024).optional()
3767
- }).optional().describe("Ask a model that can think to think on this turn. On Claude, `reasoningEffort` then sets how much it thinks, and `budget_tokens` (default 16000, minimum 1024) sizes thinking on older Claude models. Ignored by models that cannot think, and on the direct Anthropic API when a json_schema `response_format` is served by a forced tool, which cannot run alongside thinking.")
3903
+ budget_tokens: z$1.number().int().min(1024).max(MAX_THINKING_BUDGET_TOKENS).optional()
3904
+ }).optional().describe("Ask a model that can think to think on this turn. On Claude, `reasoningEffort` then sets how much it thinks, and `budget_tokens` (default 16000, minimum 1024, maximum 32000) sizes thinking on older Claude models. Ignored by models that cannot think, and on the direct Anthropic API when a json_schema `response_format` is served by a forced tool, which cannot run alongside thinking.")
3768
3905
  }).optional()
3769
3906
  });
3770
3907
  const CompletionUsageSchema = z$1.object({
@@ -3918,7 +4055,7 @@ function createThinkMarkerEscaper() {
3918
4055
  * The visible remainder of one reply slot, with hidden reasoning removed.
3919
4056
  *
3920
4057
  * This is the rule the chat transcript renders by - `extractReplies` in
3921
- * apps/client/shared/replyUtils.ts calls straight into it, so the two cannot drift.
4058
+ * packages/server-utils/src/shared/replyUtils.ts calls straight into it, so the two cannot drift.
3922
4059
  * Anything deriving "did the user see something yet" (latency metrics in particular) must
3923
4060
  * use this and not a looser non-empty check: a metric built on a looser rule reports text
3924
4061
  * as seen while the UI is still hiding it.
@@ -5322,6 +5459,7 @@ const ttsRequestSchema = z.object({
5322
5459
  stability: z.number().min(0).max(1).optional(),
5323
5460
  similarityBoost: z.number().min(0).max(1).optional(),
5324
5461
  languageCode: ttsLanguageCodeSchema.optional(),
5462
+ organization_id: z.string().trim().min(1).nullable().optional().describe("The organization to bill: one you belong to, or null for your personal credits. Omitted bills your personal credits, as this endpoint always has. An organization-billed API key always bills its own organization: omit this or set it to the key's organization; any other value, null included, is rejected with a 403 (`errorCode: billing_organization_mismatch`)."),
5325
5463
  ...generatedAudioRequestFields
5326
5464
  });
5327
5465
  /**
@@ -5337,6 +5475,21 @@ const ttsBase64ResponseSchema = extendGeneratedAudioResponseSchema({
5337
5475
  fallbackFrom: supportedVoiceGenerationVendor.optional()
5338
5476
  });
5339
5477
  /**
5478
+ * The classifiers `POST /api/ai/tts` can emit - a narrowing of the platform-wide
5479
+ * `API_ERROR_CODES`, not a parallel vocabulary (CONVENTIONS.md section 1). The
5480
+ * `satisfies` fails the build if a code here is not in the shared union.
5481
+ *
5482
+ * `insufficient_credits` rides the 422 and means the same thing it does on
5483
+ * /api/ai/music and every other credit-metered endpoint. The two provider codes
5484
+ * are easy to invert: `provider_not_configured` means WE have no usable key,
5485
+ * `provider_rejected` means the provider REFUSED the key we sent.
5486
+ */
5487
+ const TTS_ERROR_CODES = [
5488
+ "insufficient_credits",
5489
+ "provider_not_configured",
5490
+ "provider_rejected"
5491
+ ];
5492
+ /**
5340
5493
  * Error body for `POST /api/ai/tts`, shared by the 401, 422, 429 and 502; the 413
5341
5494
  * has a shape of its own (`ttsResponseTooLargeSchema`). `errorCode` is present only
5342
5495
  * on the conditions that carry a classifier; an ordinary validation 422 has none.
@@ -5362,13 +5515,11 @@ const ttsBase64ResponseSchema = extendGeneratedAudioResponseSchema({
5362
5515
  * this handler's written bodies is a gap in the handler rather than something to
5363
5516
  * enshrine in a schema.
5364
5517
  */
5518
+ /** 403 body: the `ai:generate` scope refusal (`required_scopes`), or a billing refusal. */
5519
+ const ttsForbiddenResponseSchema = BillingOrganizationForbiddenErrorSchema.extend({ provider: supportedVoiceGenerationVendor.optional() });
5365
5520
  const ttsErrorResponseSchema = ApiErrorSchema.extend({
5366
5521
  provider: supportedVoiceGenerationVendor.optional(),
5367
- errorCode: z.enum([
5368
- "insufficient_credits",
5369
- "provider_not_configured",
5370
- "provider_rejected"
5371
- ]).optional()
5522
+ errorCode: z.enum(TTS_ERROR_CODES).optional()
5372
5523
  });
5373
5524
  /**
5374
5525
  * TTS 413 body: `generatedAudioTooLargeSchema` plus the provider. The handler never
@@ -5462,6 +5613,8 @@ const MUSIC_VALIDATION_ERROR_CODES = [
5462
5613
  "lyrics_with_instrumental",
5463
5614
  "lyrics_too_long"
5464
5615
  ];
5616
+ const SECONDS = String.raw`\d+(?:\.\d+)?`;
5617
+ String.raw`\[(?:${SECONDS}:${SECONDS}|:)\]`;
5465
5618
  /**
5466
5619
  * Building blocks for entity response schemas held to an entity's key list (see
5467
5620
  * selfUserResponseSchema in ./user.ts for the full rationale). A passthrough value is
@@ -6704,8 +6857,11 @@ If the full deliverable genuinely will not fit, do NOT stub the difference. REDU
6704
6857
  * public "Help Center" data lake, so when the knowledge-base search tool is available the model
6705
6858
  * can GROUND its answer in the real docs; the prompt still forbids inventing UI paths it can't
6706
6859
  * verify (relevant when that tool isn't enabled for the session).
6860
+ *
6861
+ * Ships in open-core builds too, so it names only host surfaces, never an overlay feature. A quoted
6862
+ * name in a sentence about the sidebar must be a real sidenav row: SidenavNav.test.tsx enforces it.
6707
6863
  */
6708
- const HELP_CENTER_PROMPT = `HELP CENTER: Bike4Mind has a built-in Help Center that documents how to use the app. Users reach it from the "Help Center" item in the left sidebar, the help (?) icons beside feature titles, or the ? keyboard shortcut. When the user is clearly asking how to DO something in Bike4Mind itself (navigation, settings, files, the data lake, OptiHashi, agents, projects, sharing, billing, etc.) — as opposed to asking you to perform a task — give a brief, helpful answer and point them to the Help Center for full, up-to-date steps. If a knowledge-base/help search tool is available, use it to ground your answer in the actual help docs first. Do NOT invent menu paths, button names, or features you are not sure exist; if unsure, say so and direct them to the Help Center rather than guessing.`;
6864
+ const HELP_CENTER_PROMPT = `HELP CENTER: Bike4Mind has a built-in Help Center that documents how to use the app. Users reach it from the Help Center button on the "Gears" page (open "Gears" in the left sidebar), the help (?) icons beside feature titles, or the ? keyboard shortcut. When the user is clearly asking how to DO something in Bike4Mind itself (navigation, settings, files, the data lake, agents, projects, sharing, billing, etc.) - as opposed to asking you to perform a task - give a brief, helpful answer and point them to the Help Center for full, up-to-date steps. If a knowledge-base/help search tool is available, use it to ground your answer in the actual help docs first. Do NOT invent menu paths, button names, or features you are not sure exist; if unsure, say so and direct them to the Help Center rather than guessing.`;
6709
6865
  /**
6710
6866
  * Default text for the abstention licence. Single source of truth used BOTH as the
6711
6867
  * `AbstentionPrompt` admin setting's default AND as the runtime fallback in ChatCompletionProcess -
@@ -6869,6 +7025,7 @@ z$1.enum([
6869
7025
  "BedrockGuardrailId",
6870
7026
  "BedrockGuardrailVersion",
6871
7027
  "ImageModerationEnabled",
7028
+ "ImageModerationReviewerEmails",
6872
7029
  "tagLineMain",
6873
7030
  "tagLineSub",
6874
7031
  "defaultTags",
@@ -9368,6 +9525,14 @@ const settingsMap = {
9368
9525
  description: "Whether to run generated images through content moderation (Rekognition) and block explicit content. Legal-safety control (#9776) — default ON.",
9369
9526
  category: "AI Moderation"
9370
9527
  }),
9528
+ ImageModerationReviewerEmails: makeObjectSetting({
9529
+ key: "ImageModerationReviewerEmails",
9530
+ name: "Image Moderation Reviewer Emails",
9531
+ defaultValue: [],
9532
+ description: "Email addresses alerted when an image moderation incident needs review, one per line. The alert carries incident metadata and an admin link only, never the image or user content. Empty sends no alert.",
9533
+ category: "AI Moderation",
9534
+ schema: z$1.array(z$1.string())
9535
+ }),
9371
9536
  SkillMarketHighRiskTools: makeStringSetting({
9372
9537
  key: "SkillMarketHighRiskTools",
9373
9538
  name: "Skill Market High-Risk Tools",
@@ -9513,7 +9678,7 @@ const settingsMap = {
9513
9678
  userReadable: true,
9514
9679
  name: "Price Per Credit",
9515
9680
  defaultValue: 50,
9516
- description: "The price per credit for purchasing credits.",
9681
+ description: `The price in USD of one credit bought pay-as-you-go. Cannot be set below ${formatUsdPerCredit(MIN_PRICE_PER_CREDIT_USD)}, the per-credit sale price including markup.`,
9517
9682
  category: "Users",
9518
9683
  group: API_SERVICE_GROUPS.CREDITS.id,
9519
9684
  order: 1
@@ -9945,7 +10110,7 @@ const settingsMap = {
9945
10110
  userReadable: true,
9946
10111
  name: "Default Free Credits",
9947
10112
  defaultValue: 0,
9948
- description: `Credits granted to a user who registers WITHOUT an invite code (only applies when Allow Open Registration is ON). Granted after the user verifies their email, NOT at signup - an unverified throwaway account gets 0 credits (anti-spam). A free user can never spend more than this - their hard ceiling of real model cost is roughly credits / ${CREDITS_PER_USD_COST} USD.`,
10113
+ description: "Base credits granted after email verification to a user who registers WITHOUT an invite code, including eligible partner signups when Allow Open Registration is OFF. Partner-rule credits are added on top of this amount. An unverified account receives no credits. A free user cannot spend beyond their total granted balance.",
9949
10114
  group: API_SERVICE_GROUPS.CREDITS.id,
9950
10115
  category: "Users"
9951
10116
  }),
@@ -11770,6 +11935,17 @@ z$1.looseObject({
11770
11935
  param: z$1.string().optional()
11771
11936
  });
11772
11937
  /**
11938
+ * The client-chosen billing organization on the v1 media request bodies (image generations and edits,
11939
+ * video and music generations). Blank is a 422 rather than an omission: billing must never fall
11940
+ * through to a different payer on an empty string. The server side of this contract is
11941
+ * resolveMediaBillingOrgId (apps/client/server/billing); keep these descriptions in step with it.
11942
+ */
11943
+ const BillingOrganizationIdSchema = z$1.string().trim().min(1).nullable().optional().describe(`The organization to bill: one you belong to, or null for your personal credits. Omitted bills your home organization, or your personal credits if you have none. An organization-billed API key always bills its own organization: omit this or set it to the key's organization; any other value, null included, is rejected with a 403 (\`errorCode: ${BILLING_ORGANIZATION_MISMATCH_ERROR_CODE}\`).`);
11944
+ /** The billing-organization clause of a v1 media create route's 403 description. */
11945
+ const BILLING_ORGANIZATION_FORBIDDEN_DESCRIPTION = `the billing organization names one you do not belong to (or is not a valid id), or an organization-billed API key names any organization but its own (\`errorCode: ${BILLING_ORGANIZATION_MISMATCH_ERROR_CODE}\`).`;
11946
+ /** A v1 media create route's 400 for an org-billed key that no longer speaks for its organization. */
11947
+ const BILLING_ORGANIZATION_STALE_KEY_DESCRIPTION = "An organization-billed API key bills an organization that no longer exists, or one its owner is no longer a member of; re-mint the key.";
11948
+ /**
11773
11949
  * Supported sound-effects generation vendors. Currently only ElevenLabs.
11774
11950
  * New vendors are added here and in the `aiSoundService` factory.
11775
11951
  */
@@ -11788,6 +11964,7 @@ const soundEffectsRequestSchema = z.object({
11788
11964
  durationSeconds: z.number().min(.5).max(30).optional(),
11789
11965
  promptInfluence: z.number().min(0).max(1).optional(),
11790
11966
  format: z.string().optional(),
11967
+ organization_id: BillingOrganizationIdSchema,
11791
11968
  ...generatedAudioRequestFields
11792
11969
  });
11793
11970
  /**
@@ -13553,8 +13730,7 @@ const AgentExecutionStartRequestSchema = z$1.object({
13553
13730
  max_tokens: z$1.number().int().positive().optional(),
13554
13731
  thinking: z$1.object({
13555
13732
  enabled: z$1.boolean(),
13556
- /** Bounded at 32000: Anthropic rejects rather than clamps an oversized budget. */
13557
- budget_tokens: z$1.number().int().positive().max(32e3).optional()
13733
+ budget_tokens: z$1.number().int().positive().max(MAX_THINKING_BUDGET_TOKENS).optional()
13558
13734
  }).optional(),
13559
13735
  /** Per-message file attachments (fabFile ids), materialized into the first iteration. */
13560
13736
  file_ids: z$1.array(z$1.string()).optional(),
@@ -13657,7 +13833,7 @@ const AgentExecutionIdParamSchema = z$1.object({ id: z$1.string().min(1) });
13657
13833
  *
13658
13834
  * Plain Zod (no `.openapi()`) so any runtime can import them; the OpenAPI layer
13659
13835
  * annotates them via the contract. The tool-name enum MUST stay in sync with
13660
- * SUPPORTED_TOOLS in apps/client/server/cli/toolsHandler.shared.ts.
13836
+ * SUPPORTED_TOOLS in packages/server-utils/src/cli/toolsHandler.shared.ts.
13661
13837
  */
13662
13838
  const ToolExecutionRequestSchema = z$1.object({
13663
13839
  toolName: z$1.enum([
@@ -14313,7 +14489,7 @@ const ChatCompletionCreateInputSchema = z$1.object({
14313
14489
  stream: z$1.boolean().optional(),
14314
14490
  thinking: z$1.object({
14315
14491
  enabled: z$1.boolean(),
14316
- budget_tokens: z$1.number().optional()
14492
+ budget_tokens: z$1.number().int().positive().max(MAX_THINKING_BUDGET_TOKENS).optional()
14317
14493
  }).optional(),
14318
14494
  messages: z$1.array(z$1.object({
14319
14495
  role: z$1.enum([
@@ -14972,7 +15148,7 @@ const CreateSessionRequestSchema = z$1.object({
14972
15148
  retrievalVectorizedOnly: z$1.boolean().optional(),
14973
15149
  citationStyle: z$1.enum(["named", "indexed"]).optional(),
14974
15150
  temperature: z$1.number().optional(),
14975
- maxToolCalls: z$1.number().int().positive().optional(),
15151
+ maxToolCalls: z$1.number().int().positive().max(50).optional(),
14976
15152
  autoNamePlaceholder: z$1.string().optional(),
14977
15153
  tags: z$1.array(SessionTagSchema).optional(),
14978
15154
  lastUsedModel: z$1.string().nullish()
@@ -15038,6 +15214,47 @@ z$2.object(passthroughShape({
15038
15214
  uiSideEffects: true,
15039
15215
  jupyterNotebook: true
15040
15216
  }));
15217
+ const ENV_VARIABLE_RESPONSE_FIELDS = { key: z$2.string() };
15218
+ const envVariableResponseSchema = z$2.preprocess((value) => Array.isArray(value) ? value.flatMap((item) => {
15219
+ const key = item?.key;
15220
+ return typeof key === "string" ? [{ key }] : [];
15221
+ }) : [], z$2.array(z$2.object(ENV_VARIABLE_RESPONSE_FIELDS)));
15222
+ const GITHUB_WEBHOOK_RESPONSE_FIELDS = {
15223
+ routingToken: true,
15224
+ subscribedEvents: true,
15225
+ repos: true,
15226
+ createdAt: true,
15227
+ lastDeliveryAt: true
15228
+ };
15229
+ const metadataResponseSchema = z$2.object({
15230
+ ...passthroughShape({
15231
+ githubLogin: true,
15232
+ githubUserId: true,
15233
+ scope: true,
15234
+ connectedAt: true,
15235
+ disconnectedAt: true,
15236
+ selectedRepositories: true,
15237
+ webhooks: true
15238
+ }),
15239
+ webhooks: z$2.object({ github: z$2.object(passthroughShape(GITHUB_WEBHOOK_RESPONSE_FIELDS)).nullish() }).nullish()
15240
+ });
15241
+ z$2.object({
15242
+ ...passthroughShape({
15243
+ id: true,
15244
+ createdAt: true,
15245
+ updatedAt: true,
15246
+ name: true,
15247
+ userId: true,
15248
+ envVariables: true,
15249
+ tools: true,
15250
+ toolSchemas: true,
15251
+ toolSchemasFetchedAt: true,
15252
+ enabled: true,
15253
+ metadata: true
15254
+ }),
15255
+ envVariables: envVariableResponseSchema,
15256
+ metadata: metadataResponseSchema.nullish()
15257
+ });
15041
15258
  const questMasterPlanResponseSchema = z$2.object(passthroughShape({
15042
15259
  id: true,
15043
15260
  createdAt: true,
@@ -15203,7 +15420,10 @@ const CreateFileUploadRequestSchema = z$1.object({
15203
15420
  file_name: z$1.string().min(1),
15204
15421
  /** Declared MIME type, e.g. `image/png`. Unsupported types are rejected with 400. */
15205
15422
  mime_type: z$1.string().min(1),
15206
- /** Size in bytes of the file you will PUT. Checked against the upload limit and your storage quota. */
15423
+ /**
15424
+ * Size in bytes of the file you will PUT. Checked against the upload limit and your storage quota,
15425
+ * and bound into `upload_url`: a PUT of any other length is refused.
15426
+ */
15207
15427
  file_size: z$1.number().int().positive()
15208
15428
  });
15209
15429
  const FILE_MODERATION_STATUSES = [
@@ -16436,17 +16656,6 @@ const GENERATION_CALLBACK_DESCRIPTION = "Optional `callbackUrl`: an https URL th
16436
16656
  * in sync with the rejections in apps/client/server/generationCallback/armGenerationCallback.ts.
16437
16657
  */
16438
16658
  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.";
16439
- /**
16440
- * The client-chosen billing organization on the v1 media request bodies (image generations and edits,
16441
- * video and music generations). Blank is a 422 rather than an omission: billing must never fall
16442
- * through to a different payer on an empty string. The server side of this contract is
16443
- * resolveMediaBillingOrgId (apps/client/server/billing); keep these descriptions in step with it.
16444
- */
16445
- const BillingOrganizationIdSchema = z$1.string().trim().min(1).nullable().optional().describe(`The organization to bill: one you belong to, or null for your personal credits. Omitted bills your home organization, or your personal credits if you have none. An organization-billed API key always bills its own organization: omit this or set it to the key's organization; any other value, null included, is rejected with a 403 (\`errorCode: ${BILLING_ORGANIZATION_MISMATCH_ERROR_CODE}\`).`);
16446
- /** The billing-organization clause of a v1 media create route's 403 description. */
16447
- const BILLING_ORGANIZATION_FORBIDDEN_DESCRIPTION = `the billing organization names one you do not belong to (or is not a valid id), or an organization-billed API key names any organization but its own (\`errorCode: ${BILLING_ORGANIZATION_MISMATCH_ERROR_CODE}\`).`;
16448
- /** A v1 media create route's 400 for an org-billed key that no longer speaks for its organization. */
16449
- const BILLING_ORGANIZATION_STALE_KEY_DESCRIPTION = "An organization-billed API key bills an organization that no longer exists, or one its owner is no longer a member of; re-mint the key.";
16450
16659
  const DashboardParamsSchema = z$1.object({
16451
16660
  dashboardDataSources: z$1.array(z$1.object({
16452
16661
  sourceName: z$1.string(),
@@ -16487,7 +16696,7 @@ const PromptIntentSchema = z$1.enum(["fresh", "continuation"]);
16487
16696
  * (pages/api/v1/image-generations.ts); `literal` sends it unchanged apart from truncation to the model's prompt limit.
16488
16697
  */
16489
16698
  const ImagePromptResolutionSchema = z$1.enum(["auto", "literal"]);
16490
- const GenerateImageRequestBodySchema = OpenAIImageGenerationInput.extend({
16699
+ const GenerateImageIvokeParamsSchema = OpenAIImageGenerationInput.extend({
16491
16700
  sessionId: z$1.string(),
16492
16701
  questId: z$1.string().optional(),
16493
16702
  organizationId: z$1.string().nullable().optional(),
@@ -16520,13 +16729,21 @@ const GenerateImageRequestBodySchema = OpenAIImageGenerationInput.extend({
16520
16729
  /** Resolver intent - drives the banner's framing (continuation = "context applied" vs fresh = "enhanced"). */
16521
16730
  intent: PromptIntentSchema.optional()
16522
16731
  }).optional()
16523
- }).omit({
16732
+ });
16733
+ /**
16734
+ * snake_case alias of `organizationId` on the public image request bodies. The route maps it
16735
+ * (`resolveBillingOrgInput`) rather than the schema, which a public request schema may not
16736
+ * `.transform()`. Same rules as `organizationId`: null bills personal, blank is a 422.
16737
+ */
16738
+ const BillingOrgIdAliasSchema = BillingOrganizationIdSchema.describe("Alias of `organizationId`, for callers used to the snake_case video and music bodies. Sending both with different values is a 422.");
16739
+ const GenerateImageRequestBodySchema = GenerateImageIvokeParamsSchema.omit({
16524
16740
  intent: true,
16525
16741
  promptEnhancement: true
16526
16742
  }).extend({
16527
16743
  sessionId: z$1.string().optional(),
16528
16744
  sessionName: z$1.string().optional(),
16529
16745
  organizationId: BillingOrganizationIdSchema,
16746
+ organization_id: BillingOrgIdAliasSchema,
16530
16747
  callbackUrl: GenerationCallbackUrlSchema.optional(),
16531
16748
  projectId: z$1.string().optional(),
16532
16749
  prompt_resolution: ImagePromptResolutionSchema.optional().describe("How the prompt is treated before it reaches the image model. `\"auto\"` (the default) resolves it against the session history, so a follow-up such as \"make it darker\" is rewritten to carry the previous subject and the prior image is fed back as input. `\"literal\"` skips that step: the prompt is sent unchanged (apart from truncation to the model's prompt limit), `intent` is `\"fresh\"`, `promptWasEnhanced` is `false`, and a prior session image is carried forward only for models that cannot run without an input image. Use `\"literal\"` when the prompt is already self-contained, for example when an agent or pipeline builds it.")
@@ -16569,6 +16786,7 @@ const EditImageRequestBodySchema = OpenAIImageGenerationInput.extend({
16569
16786
  sessionId: z$1.string(),
16570
16787
  questId: z$1.string().optional(),
16571
16788
  organizationId: BillingOrganizationIdSchema,
16789
+ organization_id: BillingOrgIdAliasSchema,
16572
16790
  aspect_ratio: z$1.string().optional(),
16573
16791
  fabFileIds: z$1.array(z$1.string()).prefault([]),
16574
16792
  /**
@@ -16603,8 +16821,8 @@ z$1.object({
16603
16821
  imageConfig: GenerateImageToolCallSchema.optional(),
16604
16822
  audioConfig: AudioGenerationToolCallSchema.optional(),
16605
16823
  deepResearchConfig: z$1.object({
16606
- maxDepth: z$1.number().optional(),
16607
- duration: z$1.number().optional(),
16824
+ maxDepth: z$1.number().int().min(1).max(10).optional(),
16825
+ duration: z$1.number().positive().max(10).optional(),
16608
16826
  searchers: z$1.array(z$1.any()).optional()
16609
16827
  }).optional(),
16610
16828
  fabFileIds: z$1.array(z$1.string()),
@@ -17471,7 +17689,7 @@ defineEndpoint({
17471
17689
  }
17472
17690
  },
17473
17691
  400: {
17474
- description: "Malformed or otherwise invalid request (no `errorCode`), or a `model` the caller cannot use (`errorCode: \"unknown_model\"`): not in the catalog or not available to the caller. List valid ids with `GET /api/v1/models`. Tool search requests are refused with: `tool_search_unsupported` (a server tool, `tool_reference` or echoed tool search block on a model that cannot serve tool search here), `all_tools_deferred` (every tool deferred and no server tool), `deferred_tool_cache_control` (`cache_control` on a deferred tool), `unknown_tool_reference` (a `tool_reference` naming a tool not in `tools`, or carrying no string `tool_name`).",
17692
+ description: "Malformed or otherwise invalid request (no `errorCode`), or a `model` the caller cannot use (`errorCode: \"unknown_model\"`): not in the catalog or not available to the caller. List valid ids with `GET /api/v1/models`. Tool search requests are refused with: `tool_search_unsupported` (a server tool, `tool_reference` or echoed tool search block on a model that cannot serve tool search here), `all_tools_deferred` (every tool deferred and no server tool), `deferred_tool_cache_control` (`cache_control` on a deferred tool), `unknown_tool_reference` (a `tool_reference` naming a tool not in `tools`, or carrying no string `tool_name`). Mid-conversation tool changes are refused with: `tool_changes_unsupported` (a `tool_addition` / `tool_removal` system message on a model that cannot serve it here), `invalid_tool_change` (a malformed block, or one placed where the provider does not accept it), and `unknown_tool_reference` (a changed tool not in `tools`).",
17475
17693
  schema: CompletionsBadRequestErrorSchema
17476
17694
  },
17477
17695
  413: {
@@ -17568,7 +17786,7 @@ defineEndpoint({
17568
17786
  path: "/api/ai/tts",
17569
17787
  operationId: "synthesizeSpeech",
17570
17788
  summary: "Synthesize speech from text",
17571
- description: "Generates speech from text using OpenAI or ElevenLabs. When the requested provider has no usable key (or the provider rejects it), another configured provider stands in and the substitution is reported via `provider`/`fallbackFrom` and the `X-B4M-Tts-Provider*` headers. Input length is capped per provider (OpenAI 4096 characters, ElevenLabs 10000), and an output `format` the chosen provider cannot produce is rejected with a 422 before any provider cost is incurred. " + GENERATED_AUDIO_DESCRIPTION,
17789
+ description: "Generates speech from text using OpenAI or ElevenLabs. When the requested provider has no usable key (or the provider rejects it), another configured provider stands in and the substitution is reported via `provider`/`fallbackFrom` and the `X-B4M-Tts-Provider*` headers. Input length is capped per provider (OpenAI 4096 characters, ElevenLabs 10000), and an output `format` the chosen provider cannot produce is rejected with a 422 before any provider cost is incurred. `organization_id` picks the payer: an organization you belong to, or null for your personal credits; omitted bills your personal credits, as this endpoint always has. " + GENERATED_AUDIO_DESCRIPTION,
17572
17790
  tags: ["Audio"],
17573
17791
  auth: "apiKeyOrJwt",
17574
17792
  scopes: ["ai:generate"],
@@ -17611,6 +17829,18 @@ defineEndpoint({
17611
17829
  description: "Missing/invalid credentials, no provider has a usable key (`provider_not_configured`), or the provider refused the key we sent and no alternate could stand in (`provider_rejected`).",
17612
17830
  schema: ttsErrorResponseSchema
17613
17831
  },
17832
+ 400: {
17833
+ description: `The billing organization could not be resolved. ${BILLING_ORGANIZATION_STALE_KEY_DESCRIPTION}`,
17834
+ schema: ttsErrorResponseSchema
17835
+ },
17836
+ 403: {
17837
+ description: `The API key lacks the \`ai:generate\` scope (\`required_scopes\` names it), or ${BILLING_ORGANIZATION_FORBIDDEN_DESCRIPTION}`,
17838
+ schema: ttsForbiddenResponseSchema
17839
+ },
17840
+ 404: {
17841
+ description: "A nonexistent `organization_id`, for an admin caller; for anyone else it is `403`.",
17842
+ schema: ttsErrorResponseSchema
17843
+ },
17614
17844
  422: {
17615
17845
  description: "Request body failed validation, the text exceeds the provider character limit, the provider cannot produce the requested `format`, the provider rejected the request (e.g. an unknown voice), or the caller cannot afford the synthesis - the last of those is the only one tagged `errorCode: \"insufficient_credits\"`, so match on the classifier rather than the status to tell a billing failure from a bad request.",
17616
17846
  schema: ttsErrorResponseSchema
@@ -17704,7 +17934,7 @@ defineEndpoint({
17704
17934
  path: "/api/ai/sound-effects",
17705
17935
  operationId: "generateSoundEffect",
17706
17936
  summary: "Generate a sound effect",
17707
- description: "Generates a short sound effect from a text description. Omitting `durationSeconds` lets the provider pick the length (and bills at its default); `promptInfluence` trades prompt fidelity (1) against variation (0). Credits are reserved before generation and refunded if it fails. " + GENERATED_AUDIO_DESCRIPTION,
17937
+ description: "Generates a short sound effect from a text description. Omitting `durationSeconds` lets the provider pick the length (and bills at its default); `promptInfluence` trades prompt fidelity (1) against variation (0). Credits are reserved before generation and refunded if it fails. `organization_id` picks the payer: an organization you belong to, or null for your personal credits; omitted bills your home organization (or personal credits if you have none). " + GENERATED_AUDIO_DESCRIPTION,
17708
17938
  tags: ["Audio"],
17709
17939
  auth: "apiKeyOrJwt",
17710
17940
  scopes: ["ai:generate"],
@@ -17730,7 +17960,15 @@ defineEndpoint({
17730
17960
  tooLargeSchema: generatedAudioTooLargeSchema
17731
17961
  }),
17732
17962
  400: {
17733
- description: "The billing user or organization could not be resolved.",
17963
+ description: `The billing user or organization could not be resolved. ${BILLING_ORGANIZATION_STALE_KEY_DESCRIPTION}`,
17964
+ schema: ApiErrorSchema
17965
+ },
17966
+ 403: {
17967
+ description: `The API key lacks the \`ai:generate\` scope (\`required_scopes\` names it), or ${BILLING_ORGANIZATION_FORBIDDEN_DESCRIPTION}`,
17968
+ schema: BillingOrganizationForbiddenErrorSchema
17969
+ },
17970
+ 404: {
17971
+ description: "A nonexistent `organization_id`, for an admin caller; for anyone else it is `403`.",
17734
17972
  schema: ApiErrorSchema
17735
17973
  },
17736
17974
  422: {
@@ -17871,9 +18109,9 @@ defineEndpoint({
17871
18109
  replaced_by: null,
17872
18110
  image: null,
17873
18111
  credits_per_1m_tokens: {
17874
- input: 6e3,
17875
- output: 3e4,
17876
- cached_input: 600
18112
+ input: 4e3,
18113
+ output: 2e4,
18114
+ cached_input: 400
17877
18115
  }
17878
18116
  }, {
17879
18117
  id: "gpt-image-1",
@@ -17955,7 +18193,7 @@ defineEndpoint({
17955
18193
  path: "/api/v1/image-generations",
17956
18194
  operationId: "generateImage",
17957
18195
  summary: "Generate an image",
17958
- 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 15 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\n" + GENERATION_CALLBACK_DESCRIPTION,
18196
+ 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 15 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. `organization_id` is accepted as an alias of `organizationId`, for callers used to the snake_case video and music bodies; `null` bills the personal account. `POST /api/ai/generate-image` is a legacy alias of this endpoint. Authenticate with an API key (`b4m_live_`) or a JWT.\n\n" + GENERATION_CALLBACK_DESCRIPTION,
17959
18197
  tags: ["Images"],
17960
18198
  auth: "apiKeyOrJwt",
17961
18199
  scopes: ["ai:generate"],
@@ -17982,6 +18220,10 @@ defineEndpoint({
17982
18220
  404: {
17983
18221
  description: "The session, or the quest being retried, does not exist or is not accessible to the caller. A nonexistent billing `organizationId` is `404` only for an admin caller; for anyone else, an invalid or inaccessible `organizationId` is `403` instead.",
17984
18222
  schema: ApiErrorSchema
18223
+ },
18224
+ 422: {
18225
+ description: "The body is malformed, or it names the billing organization ambiguously. Both `organizationId` and `organization_id` sent with different values is a `422`; so is an empty or blank value for either (a blank is never treated as an omission, which would bill a different payer), and so is any other billing-org-shaped key such as `billing_org_id` or `payerOrgId`, which would otherwise be stripped and silently bill the caller's home organization.",
18226
+ schema: ApiErrorSchema
17985
18227
  }
17986
18228
  },
17987
18229
  emitsRateLimitHeaders: true,
@@ -18000,7 +18242,7 @@ defineEndpoint({
18000
18242
  path: "/api/v1/image-edits",
18001
18243
  operationId: "editImage",
18002
18244
  summary: "Edit an image",
18003
- description: "Queues an edit of an existing image and returns the quest that will carry the result, before the render runs. Poll `GET /api/v1/quests/{id}` until `status` is `\"done\"` (see the `editImage200PollResult` schema). `image` is the URL of the source image; `fabFileIds` must name at least one file, and the first is the inpainting mask. `referenceImageFabFileIds` adds up to 15 style anchors after the source image, so the mask always applies to the source; only gpt-image models accept them, and sending any with another model is rejected with a 400 rather than ignored. Both id fields take ids from `POST /api/v1/files`: upload each file, poll `GET /api/v1/files/{id}` until `moderation_status` is `clean`, then pass its `id`. An id that is not yet `clean` fails the edit on the polled quest. `image` takes a URL rather than an id, so a source uploaded the same way is passed as its `download_url`, which must still be unexpired when the render runs. The edited image is not a file id: read it from `files[].url` on the polled quest, not from `GET /api/v1/files/{id}`. `seed` makes an edit reproducible on BFL (FLUX) models only; gpt-image and Gemini models ignore it. Credits are checked when the render runs, so insufficient credits arrive on the polled quest rather than as a 422. `POST /api/ai/edit-image` is a legacy alias of this endpoint. Authenticate with an API key (`b4m_live_`) or a JWT.\n\n" + GENERATION_CALLBACK_DESCRIPTION,
18245
+ description: "Queues an edit of an existing image and returns the quest that will carry the result, before the render runs. Poll `GET /api/v1/quests/{id}` until `status` is `\"done\"` (see the `editImage200PollResult` schema). `image` is the URL of the source image; `fabFileIds` must name at least one file, and the first is the inpainting mask. `referenceImageFabFileIds` adds up to 15 style anchors after the source image, so the mask always applies to the source; only gpt-image models accept them, and sending any with another model is rejected with a 400 rather than ignored. Both id fields take ids from `POST /api/v1/files`: upload each file, poll `GET /api/v1/files/{id}` until `moderation_status` is `clean`, then pass its `id`. An id that is not yet `clean` fails the edit on the polled quest. `image` takes a URL rather than an id, so a source uploaded the same way is passed as its `download_url`, which must still be unexpired when the render runs. The edited image is not a file id: read it from `files[].url` on the polled quest, not from `GET /api/v1/files/{id}`. `seed` makes an edit reproducible on BFL (FLUX) models only; gpt-image and Gemini models ignore it. Credits are checked when the render runs, so insufficient credits arrive on the polled quest rather than as a 422. `organization_id` is accepted as an alias of `organizationId`, for callers used to the snake_case video and music bodies; `null` bills the personal account. `POST /api/ai/edit-image` is a legacy alias of this endpoint. Authenticate with an API key (`b4m_live_`) or a JWT.\n\n" + GENERATION_CALLBACK_DESCRIPTION,
18004
18246
  tags: ["Images"],
18005
18247
  auth: "apiKeyOrJwt",
18006
18248
  scopes: ["ai:generate"],
@@ -18029,6 +18271,10 @@ defineEndpoint({
18029
18271
  404: {
18030
18272
  description: "The session, or the quest being retried, does not exist or is not accessible to the caller. A nonexistent billing `organizationId` is `404` only for an admin caller; for anyone else, an invalid or inaccessible `organizationId` is `403` instead.",
18031
18273
  schema: ApiErrorSchema
18274
+ },
18275
+ 422: {
18276
+ description: "The body is malformed, or it names the billing organization ambiguously. Both `organizationId` and `organization_id` sent with different values is a `422`; so is an empty or blank value for either (a blank is never treated as an omission, which would bill a different payer), and so is any other billing-org-shaped key such as `billing_org_id` or `payerOrgId`, which would otherwise be stripped and silently bill the caller's home organization.",
18277
+ schema: ApiErrorSchema
18032
18278
  }
18033
18279
  },
18034
18280
  emitsRateLimitHeaders: true,
@@ -18060,7 +18306,7 @@ defineEndpoint({
18060
18306
  path: "/api/v1/files",
18061
18307
  operationId: "createFileUpload",
18062
18308
  summary: "Start a file upload",
18063
- description: "Registers a file and returns a presigned `upload_url`. Uploading is three steps: (1) call this endpoint with the file name, MIME type, and size in bytes; (2) `PUT` the raw bytes to `upload_url` before `upload_url_expires_at` - send no `Authorization` header, the URL signature is the credential, and do send a `Content-Type` matching `mime_type`; (3) poll `GET /api/v1/files/{id}` until `moderation_status` is `clean` (usually a few seconds after the PUT), then pass `id` wherever an endpoint takes a file id (for example `fabFileIds` and `referenceImageFabFileIds` on `POST /api/v1/image-edits`). Unsupported types, a size over the upload limit, or a size that would exceed your storage quota are rejected with 400 before any URL is issued. Authenticate with an API key (`b4m_live_`) carrying `files:write`, or a JWT.",
18309
+ description: "Registers a file and returns a presigned `upload_url`. Uploading is three steps: (1) call this endpoint with the file name, MIME type, and size in bytes; (2) `PUT` the raw bytes to `upload_url` before `upload_url_expires_at` - send no `Authorization` header, the URL signature is the credential, and do send a `Content-Type` matching `mime_type`; the URL is bound to `file_size`, so the body must be exactly that many bytes or storage refuses it with 403; (3) poll `GET /api/v1/files/{id}` until `moderation_status` is `clean` (usually a few seconds after the PUT), then pass `id` wherever an endpoint takes a file id (for example `fabFileIds` and `referenceImageFabFileIds` on `POST /api/v1/image-edits`). Unsupported types, a size over the upload limit, or a size that would exceed your storage quota are rejected with 400 before any URL is issued. Authenticate with an API key (`b4m_live_`) carrying `files:write`, or a JWT.",
18064
18310
  tags: ["Files"],
18065
18311
  auth: "apiKeyOrJwt",
18066
18312
  scopes: ["files:write"],
@@ -21214,6 +21460,11 @@ const INCIDENT_REVIEW_STATUSES = [
21214
21460
  "reported"
21215
21461
  ];
21216
21462
  const INCIDENT_REPORT_CHANNELS = ["manual"];
21463
+ const INCIDENT_SURFACES = [
21464
+ "generation",
21465
+ "edit",
21466
+ "upload"
21467
+ ];
21217
21468
  const ModerationLabelHitSchema = z$1.object({
21218
21469
  name: z$1.string(),
21219
21470
  parentName: z$1.string(),
@@ -21227,6 +21478,7 @@ z$1.object({
21227
21478
  fabFileId: z$1.string().optional(),
21228
21479
  provider: z$1.string(),
21229
21480
  model: z$1.string(),
21481
+ surface: z$1.enum(INCIDENT_SURFACES).optional(),
21230
21482
  labels: z$1.array(ModerationLabelHitSchema),
21231
21483
  reviewStatus: z$1.enum(INCIDENT_REVIEW_STATUSES).optional(),
21232
21484
  ncmecReportId: z$1.string().optional(),
@@ -21236,9 +21488,11 @@ z$1.object({
21236
21488
  previousReviewStatus: z$1.literal("false_positive").optional(),
21237
21489
  falsePositiveBy: z$1.string().optional(),
21238
21490
  falsePositiveAt: z$1.union([z$1.string(), z$1.date()]).optional(),
21491
+ alertedAt: z$1.union([z$1.string(), z$1.date()]).optional(),
21239
21492
  createdAt: z$1.union([z$1.string(), z$1.date()]).optional(),
21240
21493
  updatedAt: z$1.union([z$1.string(), z$1.date()]).optional()
21241
21494
  });
21495
+ z$1.string().email();
21242
21496
  new RegExp(`[аеорсхуіјѕԁһӏαονικρτυ]`, "g");
21243
21497
  const OPENER_STICKY = /<artifact/iy;
21244
21498
  const WHITESPACE$1 = /\s/;
@@ -24005,7 +24259,8 @@ const CORE_TOOL_DESCRIPTORS = new Map(Object.entries({
24005
24259
  effect: "execute",
24006
24260
  approval: "prompt_always",
24007
24261
  openWorld: true,
24008
- commandArg: "command"
24262
+ commandArg: "command",
24263
+ sandbox: "command"
24009
24264
  },
24010
24265
  shell_execute: {
24011
24266
  source: CORE,
@@ -24114,6 +24369,15 @@ function isReadOnlyTool(descriptor) {
24114
24369
  function commandTextOf(descriptor, args) {
24115
24370
  return stringArg(args, descriptor?.commandArg);
24116
24371
  }
24372
+ /**
24373
+ * The argument holding the command the OS sandbox wraps, or undefined when the tool is not
24374
+ * sandboxed. Only core tools may declare it: a sandboxed call can skip the prompt in
24375
+ * auto-allow mode, so a plugin or MCP descriptor must not be able to claim it.
24376
+ */
24377
+ function sandboxedCommandArg(descriptor) {
24378
+ if (descriptor?.sandbox !== "command" || descriptor.source.kind !== "core") return void 0;
24379
+ return descriptor.commandArg;
24380
+ }
24117
24381
  /** The path a file-writing tool will write, when the tool declares one and `args` carries it. */
24118
24382
  function writePathOf(descriptor, args) {
24119
24383
  const writePath = stringArg(args, descriptor?.writePathArg);
@@ -25603,4 +25867,4 @@ var ConfigStore = class {
25603
25867
  }
25604
25868
  };
25605
25869
  //#endregion
25606
- export { PermissionDeniedError as $, ApiKeyType as A, stripToolArtifactMarkup as At, DEFAULT_TTS_PROVIDER as B, actorKindMarker as Bt, htmlFirstH1 as C, obfuscateApiKey as Ct, AGENT_QUEST_MCP_URI as D, signImageUrl as Dt, AGENT_QUEST_MANIFEST as E, secureParameters as Et, CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS as F, ttsResponseTooLargeSchema as Ft, LOCATION_MAP_LANGUAGE as G, WEBSITE_URL as Gt, GENERATED_IMAGE_EXTENSION_RE as H, delegationPayloadSchema as Ht, CREDIT_DEDUCT_TRANSACTION_TYPES as I, withRetry as It, ModelBackend as J, MODEL_INFO_FIELD_GROUP_OF as K, ChatModels as L, ACTOR_COLOR_SLOTS as Lt, BRIEFCASE_CATALOG_QUERIES as M, tokenEstimateMultiplier as Mt, BedrockEmbeddingModel as N, ttsBase64ResponseSchema as Nt, ARTIFACT_DELIVERED_PLACEHOLDER as O, splitEquals as Ot, BriefcasePromptIdSchema as P, ttsRequestSchema as Pt, PROMPT_TEXT_MAX as Q, CompletionReasoningEffortSchema as R, DELEGATION_PAYLOAD_SCHEMA_NAME as Rt, htmlErrorTitle as S, joinReplySlots as St, AGENT_QUEST_ID as T, replacePromptVariables as Tt, ImageModels as U, selfClaimedActorKindSchema as Ut, DEGENERATE_FINISH_REASON as V, actorKindSchema as Vt, ImagePromptResolutionSchema as W, APP_NAME as Wt, OllamaEmbeddingModel as X, NotFoundError as Y, OpenAIEmbeddingModel as Z, NotAuthenticatedError as _, hasDeliverablePinnedArtifact as _t, commandTextOf as a, VisibilitySchema as at, SESSION_ID_PATTERN as b, isRetryableError as bt, writePathOf as c, assertAuthOriginMatchesApiKey as ct, getEnvironmentName as d, escapeThinkMarkers as dt, REVIEW_GATE_STATUS_VALUES as et, requireApiUrl as f, filterToolArtifactMarkup as ft, LOCAL_DEV_URL as g, googleMapsSearchUrl as gt, DeviceFlowClient as h, getQuestErrorCode as ht, ToolCatalog as i, SupportedFabFileMimeTypes as it, ArtifactTypeSchema as j, supportedVoiceGenerationVendor as jt, ARTIFACT_REMOVED_PLACEHOLDER as k, stripDeliveredArtifactBlocks as kt, ApiEndpointUnconfiguredError as l, buildPromptContext as lt, AuthenticatedApiClient as m, getMcpProviderMetadata as mt, extractCompactInstructions as n, SLUG_OWNED_BY_OTHER as nt, isReadOnlyTool as o, VoyageAIEmbeddingModel as ot, resolveApiEndpoint as p, generatedAudioResponseSchema as pt, McpServerName as q, loadContextFiles as r, SUBQUEST_STATUS_VALUES as rt, toolCategory as s, WORK_ITEM_STATUSES as st, ConfigStore as t, SEARCH_RESULT_CARDS_LANGUAGE as tt, getCreditsUrl as u, createThinkMarkerEscaper as ut, parseApiUrl as v, isEarlyStop as vt, escapeArtifactBodyJson as w, questReplyText as wt, isValidSessionId as x, isUserInitiatedAbort as xt, logger as y, isPlaceholderImageSigningSecret as yt, CreateArtifactRequestSchema as z, actorColorIndex as zt };
25870
+ export { PROMPT_TEXT_MAX as $, ARTIFACT_REMOVED_PLACEHOLDER as A, splitEquals as At, CreateArtifactRequestSchema as B, DELEGATION_PAYLOAD_SCHEMA_NAME as Bt, htmlErrorTitle as C, isUserInitiatedAbort as Ct, AGENT_QUEST_MANIFEST as D, replacePromptVariables as Dt, AGENT_QUEST_ID as E, questReplyText as Et, BriefcasePromptIdSchema as F, ttsBase64ResponseSchema as Ft, ImagePromptResolutionSchema as G, selfClaimedActorKindSchema as Gt, DEGENERATE_FINISH_REASON as H, actorKindMarker as Ht, CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS as I, ttsRequestSchema as It, McpServerName as J, LOCATION_MAP_LANGUAGE as K, APP_NAME as Kt, CREDIT_DEDUCT_TRANSACTION_TYPES as L, ttsResponseTooLargeSchema as Lt, ArtifactTypeSchema as M, stripToolArtifactMarkup as Mt, BRIEFCASE_CATALOG_QUERIES as N, supportedVoiceGenerationVendor as Nt, AGENT_QUEST_MCP_URI as O, secureParameters as Ot, BedrockEmbeddingModel as P, tokenEstimateMultiplier as Pt, OpenAIEmbeddingModel as Q, ChatModels as R, withRetry as Rt, isValidSessionId as S, isRetryableError as St, escapeArtifactBodyJson as T, obfuscateApiKey as Tt, GENERATED_IMAGE_EXTENSION_RE as U, actorKindSchema as Ut, DEFAULT_TTS_PROVIDER as V, actorColorIndex as Vt, ImageModels as W, delegationPayloadSchema as Wt, NotFoundError as X, ModelBackend as Y, OllamaEmbeddingModel as Z, LOCAL_DEV_URL as _, getQuestErrorCode as _t, commandTextOf as a, SupportedFabFileMimeTypes as at, logger as b, isEarlyStop as bt, toolCategory as c, VoyageAIEmbeddingModel as ct, getCreditsUrl as d, buildPromptContext as dt, PermissionDeniedError as et, getEnvironmentName as f, createThinkMarkerEscaper as ft, DeviceFlowClient as g, getMcpProviderMetadata as gt, AuthenticatedApiClient as h, generatedAudioResponseSchema as ht, ToolCatalog as i, SUBQUEST_STATUS_VALUES as it, ApiKeyType as j, stripDeliveredArtifactBlocks as jt, ARTIFACT_DELIVERED_PLACEHOLDER as k, signImageUrl as kt, writePathOf as l, WORK_ITEM_STATUSES as lt, resolveApiEndpoint as m, filterToolArtifactMarkup as mt, extractCompactInstructions as n, SEARCH_RESULT_CARDS_LANGUAGE as nt, isReadOnlyTool as o, UnprocessableEntityError as ot, requireApiUrl as p, escapeThinkMarkers as pt, MODEL_INFO_FIELD_GROUP_OF as q, WEBSITE_URL as qt, loadContextFiles as r, SLUG_OWNED_BY_OTHER as rt, sandboxedCommandArg as s, VisibilitySchema as st, ConfigStore as t, REVIEW_GATE_STATUS_VALUES as tt, ApiEndpointUnconfiguredError as u, assertAuthOriginMatchesApiKey as ut, NotAuthenticatedError as v, googleMapsSearchUrl as vt, htmlFirstH1 as w, joinReplySlots as wt, SESSION_ID_PATTERN as x, isPlaceholderImageSigningSecret as xt, parseApiUrl as y, hasDeliverablePinnedArtifact as yt, CompletionReasoningEffortSchema as z, ACTOR_COLOR_SLOTS as zt };