@bike4mind/cli 3.1.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.
- package/dist/{AgentHistoryStore-O2gKB5YG.mjs → AgentHistoryStore-CLidbOHG.mjs} +6214 -5711
- package/dist/{ConfigStore-RHqyXcSS.mjs → ConfigStore-DUATzLxB.mjs} +897 -345
- package/dist/{WorkItemsClient-cmw7WYBy.mjs → WorkItemsClient-BSoOblGp.mjs} +1 -1
- package/dist/{buildAgent-C0jmyDL4.mjs → buildAgent-DyZWK0LW.mjs} +39 -216
- package/dist/commands/acpCommand.mjs +25 -17
- 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 +73 -41
- package/dist/commands/mcpCommand.mjs +3 -3
- package/dist/commands/pluginCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/{dist-B1bGf-yn.mjs → dist-DPP7UmK9.mjs} +2 -2
- package/dist/index.mjs +41 -19
- package/dist/{package-DsG8Tgvs.mjs → package-DYPVrada.mjs} +1 -1
- package/dist/{serve-CAfCQose.mjs → serve-w6v3rZiR.mjs} +2 -2
- package/package.json +11 -11
|
@@ -250,6 +250,19 @@ const StorageLimitErrorInfoSchema = z$1.object({
|
|
|
250
250
|
requested_bytes: z$1.number().nonnegative().describe("Size of the refused upload, in bytes."),
|
|
251
251
|
owner: z$1.enum(["user", "org"]).describe("Whose limit was hit: `user` or `org`. Always `user` for `file_too_large`, a platform-wide cap.")
|
|
252
252
|
});
|
|
253
|
+
/**
|
|
254
|
+
* The refusal a caller gets when the limit belongs to someone else (an update-share editor growing
|
|
255
|
+
* another user's file): the code and whose limit, without that owner's byte counts.
|
|
256
|
+
*/
|
|
257
|
+
const RedactedStorageLimitErrorInfoSchema = StorageLimitErrorInfoSchema.pick({
|
|
258
|
+
errorCode: true,
|
|
259
|
+
owner: true
|
|
260
|
+
}).extend({
|
|
261
|
+
used_bytes: z$1.never().optional(),
|
|
262
|
+
limit_bytes: z$1.never().optional(),
|
|
263
|
+
requested_bytes: z$1.never().optional()
|
|
264
|
+
});
|
|
265
|
+
z$1.union([StorageLimitErrorInfoSchema, RedactedStorageLimitErrorInfoSchema]);
|
|
253
266
|
function isZodError(err) {
|
|
254
267
|
return Boolean(err && (err instanceof ZodError || err.name === "ZodError"));
|
|
255
268
|
}
|
|
@@ -950,6 +963,7 @@ let ChatModels = /* @__PURE__ */ function(ChatModels) {
|
|
|
950
963
|
ChatModels["GPT5_2_CHAT_LATEST"] = "gpt-5.2-chat-latest";
|
|
951
964
|
ChatModels["GPT5_4"] = "gpt-5.4";
|
|
952
965
|
ChatModels["GPT5_4_MINI"] = "gpt-5.4-mini";
|
|
966
|
+
ChatModels["GPT5_4_MINI_2026_03_17"] = "gpt-5.4-mini-2026-03-17";
|
|
953
967
|
ChatModels["GPT5_4_NANO"] = "gpt-5.4-nano";
|
|
954
968
|
ChatModels["GPT5_5"] = "gpt-5.5";
|
|
955
969
|
ChatModels["GPT5_6_SOL"] = "gpt-5.6-sol";
|
|
@@ -1045,8 +1059,8 @@ let ChatModels = /* @__PURE__ */ function(ChatModels) {
|
|
|
1045
1059
|
ChatModels["DEEPSEEK_V4_PRO"] = "deepseek-v4-pro";
|
|
1046
1060
|
return ChatModels;
|
|
1047
1061
|
}({});
|
|
1048
|
-
const
|
|
1049
|
-
const
|
|
1062
|
+
const supportedChatModels = z$1.enum(ChatModels).exclude(["GPT5_4_MINI_2026_03_17"]);
|
|
1063
|
+
const CHAT_MODELS = [...supportedChatModels.options];
|
|
1050
1064
|
new RegExp(`^${BEDROCK_ANTHROPIC_PREFIX}claude-`);
|
|
1051
1065
|
/**
|
|
1052
1066
|
* Models that support OpenAI's `reasoning_effort` request parameter.
|
|
@@ -1068,6 +1082,7 @@ const REASONING_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
|
1068
1082
|
"gpt-5.2",
|
|
1069
1083
|
"gpt-5.4",
|
|
1070
1084
|
"gpt-5.4-mini",
|
|
1085
|
+
"gpt-5.4-mini-2026-03-17",
|
|
1071
1086
|
"gpt-5.4-nano",
|
|
1072
1087
|
"gpt-5.6-sol",
|
|
1073
1088
|
"gpt-5.6-luna",
|
|
@@ -2893,6 +2908,105 @@ const WORK_ITEM_STATUSES = [
|
|
|
2893
2908
|
"blocked",
|
|
2894
2909
|
"closed"
|
|
2895
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
|
+
});
|
|
2896
3010
|
let SupportedFabFileMimeTypes = /* @__PURE__ */ function(SupportedFabFileMimeTypes) {
|
|
2897
3011
|
SupportedFabFileMimeTypes["PDF"] = "application/pdf";
|
|
2898
3012
|
SupportedFabFileMimeTypes["DOCX"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
@@ -3121,6 +3235,21 @@ const CREDITS_PER_USD_COST = (() => {
|
|
|
3121
3235
|
console.warn(`[pricing] Env-configured margin/rate derive ${derived} credits per USD cost; using defaults`);
|
|
3122
3236
|
return Math.round(DEFAULT_PRICE_MARGIN / DEFAULT_USD_TO_CREDITS_RATE);
|
|
3123
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))}`;
|
|
3124
3253
|
z.enum([
|
|
3125
3254
|
"openai",
|
|
3126
3255
|
"test",
|
|
@@ -3643,6 +3772,220 @@ z$1.enum([
|
|
|
3643
3772
|
"investigate_soon",
|
|
3644
3773
|
"immediate_action"
|
|
3645
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;
|
|
3781
|
+
const CompletionReasoningEffortSchema = z$1.enum([
|
|
3782
|
+
"none",
|
|
3783
|
+
"minimal",
|
|
3784
|
+
"low",
|
|
3785
|
+
"medium",
|
|
3786
|
+
"high",
|
|
3787
|
+
"xhigh"
|
|
3788
|
+
]);
|
|
3789
|
+
/**
|
|
3790
|
+
* Tool schema matching ICompletionOptionTools.toolSchema. The Zod surface only
|
|
3791
|
+
* covers wire-format fields (toolFn is server-side). Replaces the historical
|
|
3792
|
+
* z.array(z.any()) so client-side bugs (typos in name, missing type) surface
|
|
3793
|
+
* at parse time instead of failing silently inside the backend.
|
|
3794
|
+
*/
|
|
3795
|
+
const CompletionCustomToolSchema = z$1.object({
|
|
3796
|
+
toolSchema: z$1.object({
|
|
3797
|
+
name: z$1.string(),
|
|
3798
|
+
description: z$1.string(),
|
|
3799
|
+
parameters: z$1.object({
|
|
3800
|
+
type: z$1.literal("object"),
|
|
3801
|
+
properties: z$1.record(z$1.string(), z$1.any()).optional(),
|
|
3802
|
+
additionalProperties: z$1.boolean().optional(),
|
|
3803
|
+
required: z$1.array(z$1.string()).optional()
|
|
3804
|
+
}).passthrough(),
|
|
3805
|
+
strict: z$1.boolean().optional(),
|
|
3806
|
+
defer_loading: z$1.boolean().optional().describe("Keep this definition out of the model context until the tool search server tool (or a `tool_reference`) loads it. Honoured only on models served by the direct Anthropic API whose `supports_tool_search` is true; on every other model (including Bedrock-served Claude, for now) it is ignored and the tool is sent as usual. At least one tool, or a `serverTool` entry, must stay non-deferred (`errorCode: \"all_tools_deferred\"`)."),
|
|
3807
|
+
cache_control: z$1.unknown().optional().describe("Accepted for validation only and not forwarded. Rejected on a deferred tool (`errorCode: \"deferred_tool_cache_control\"`).")
|
|
3808
|
+
}),
|
|
3809
|
+
_isMcpTool: z$1.boolean().optional()
|
|
3810
|
+
});
|
|
3811
|
+
/** Anthropic's tool search server tools; `name` is fixed by `type`. */
|
|
3812
|
+
const ToolSearchServerToolSchema = z$1.discriminatedUnion("type", [z$1.object({
|
|
3813
|
+
type: z$1.literal("tool_search_tool_regex_20251119"),
|
|
3814
|
+
name: z$1.literal("tool_search_tool_regex")
|
|
3815
|
+
}), z$1.object({
|
|
3816
|
+
type: z$1.literal("tool_search_tool_bm25_20251119"),
|
|
3817
|
+
name: z$1.literal("tool_search_tool_bm25")
|
|
3818
|
+
})]);
|
|
3819
|
+
const CompletionServerToolSchema = z$1.object({ serverTool: ToolSearchServerToolSchema.describe("A provider-run tool, sent to the provider as `{ type, name }`. Only the Anthropic tool search tools exist today, and only on models served by the direct Anthropic API whose `supports_tool_search` is true; any other model, Bedrock-served Claude included, is refused with `errorCode: \"tool_search_unsupported\"` rather than run without it.") });
|
|
3820
|
+
/** One `tools[]` entry: a caller-defined tool, or a provider-run server tool. */
|
|
3821
|
+
const CompletionToolSchema = z$1.union([CompletionCustomToolSchema, CompletionServerToolSchema]);
|
|
3822
|
+
/**
|
|
3823
|
+
* The `errorCode`s of the completions 400s for tool search requests (CONVENTIONS.md section 1).
|
|
3824
|
+
* Assigned in services/cliCompletionsToolSearch.ts.
|
|
3825
|
+
*/
|
|
3826
|
+
const COMPLETION_TOOL_ERROR_CODES = [
|
|
3827
|
+
"tool_search_unsupported",
|
|
3828
|
+
"all_tools_deferred",
|
|
3829
|
+
"deferred_tool_cache_control",
|
|
3830
|
+
"unknown_tool_reference",
|
|
3831
|
+
"tool_changes_unsupported",
|
|
3832
|
+
"invalid_tool_change"
|
|
3833
|
+
];
|
|
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
|
+
/**
|
|
3848
|
+
* JSON Schema definition for structured output. The `schema` field is a full
|
|
3849
|
+
* JSON Schema document (we don't try to validate JSON Schema with Zod - that's
|
|
3850
|
+
* the caller's contract with the model). `strict: true` is the default, matching
|
|
3851
|
+
* OpenAI's strict-mode subset semantics.
|
|
3852
|
+
*/
|
|
3853
|
+
const ResponseFormatSchema = z$1.discriminatedUnion("type", [z$1.object({ type: z$1.literal("text") }), z$1.object({
|
|
3854
|
+
type: z$1.literal("json_schema"),
|
|
3855
|
+
json_schema: z$1.object({
|
|
3856
|
+
name: z$1.string(),
|
|
3857
|
+
description: z$1.string().optional(),
|
|
3858
|
+
schema: z$1.record(z$1.string(), z$1.any()),
|
|
3859
|
+
strict: z$1.boolean().optional().default(true)
|
|
3860
|
+
})
|
|
3861
|
+
})]);
|
|
3862
|
+
/**
|
|
3863
|
+
* Wire-format message for /api/ai/v1/completions. The optional `cache: true`
|
|
3864
|
+
* flag is honored by Anthropic (translated to `cache_control: { type: 'ephemeral' }`
|
|
3865
|
+
* with the appropriate beta header) and silently ignored by other providers.
|
|
3866
|
+
*/
|
|
3867
|
+
const CompletionMessageSchema = z$1.object({
|
|
3868
|
+
role: z$1.enum([
|
|
3869
|
+
"user",
|
|
3870
|
+
"assistant",
|
|
3871
|
+
"system"
|
|
3872
|
+
]),
|
|
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)."),
|
|
3874
|
+
cache: z$1.boolean().optional()
|
|
3875
|
+
});
|
|
3876
|
+
/**
|
|
3877
|
+
* Schema for CLI LLM completion requests
|
|
3878
|
+
* Shared between Next.js API route (dev) and Lambda function (production)
|
|
3879
|
+
*
|
|
3880
|
+
* `response_format`, `stream`, `tools`, `temperature`, and `max_tokens` are all
|
|
3881
|
+
* accepted at the top level (OpenAI-compatible, matching how every major LLM
|
|
3882
|
+
* SDK shapes a completion request) AND nested under `options` (legacy shape).
|
|
3883
|
+
* Use `normalizeCompletionRequest()` to collapse both surfaces into the
|
|
3884
|
+
* canonical `options.<field>` location before downstream consumption.
|
|
3885
|
+
*/
|
|
3886
|
+
const CompletionRequestSchema = z$1.object({
|
|
3887
|
+
model: z$1.string().max(256),
|
|
3888
|
+
messages: z$1.array(CompletionMessageSchema),
|
|
3889
|
+
response_format: ResponseFormatSchema.optional(),
|
|
3890
|
+
stream: z$1.boolean().optional(),
|
|
3891
|
+
tools: z$1.array(CompletionToolSchema).optional(),
|
|
3892
|
+
temperature: z$1.number().optional(),
|
|
3893
|
+
max_tokens: z$1.number().optional(),
|
|
3894
|
+
options: z$1.object({
|
|
3895
|
+
temperature: z$1.number().optional(),
|
|
3896
|
+
maxTokens: z$1.number().optional(),
|
|
3897
|
+
stream: z$1.boolean().optional(),
|
|
3898
|
+
tools: z$1.array(CompletionToolSchema).optional(),
|
|
3899
|
+
response_format: ResponseFormatSchema.optional(),
|
|
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."),
|
|
3901
|
+
thinking: z$1.object({
|
|
3902
|
+
enabled: z$1.boolean(),
|
|
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.")
|
|
3905
|
+
}).optional()
|
|
3906
|
+
});
|
|
3907
|
+
const CompletionUsageSchema = z$1.object({
|
|
3908
|
+
inputTokens: z$1.number().optional(),
|
|
3909
|
+
outputTokens: z$1.number().optional(),
|
|
3910
|
+
reasoningTokens: z$1.number().optional().describe("Reasoning/thinking tokens the provider reported. A subset of outputTokens, not additive and not billed on top. Absent when the provider or adapter reports no count."),
|
|
3911
|
+
cacheReadInputTokens: z$1.number().optional(),
|
|
3912
|
+
cacheCreationInputTokens: z$1.number().optional()
|
|
3913
|
+
});
|
|
3914
|
+
const CompletionMetaEventSchema = z$1.object({
|
|
3915
|
+
type: z$1.literal("meta"),
|
|
3916
|
+
requestId: z$1.string()
|
|
3917
|
+
});
|
|
3918
|
+
const CompletionContentEventSchema = z$1.object({
|
|
3919
|
+
type: z$1.enum(["content", "tool_use"]),
|
|
3920
|
+
text: z$1.string(),
|
|
3921
|
+
tools: z$1.array(z$1.object({
|
|
3922
|
+
name: z$1.string(),
|
|
3923
|
+
arguments: z$1.string().optional(),
|
|
3924
|
+
id: z$1.string().optional()
|
|
3925
|
+
})).optional(),
|
|
3926
|
+
usage: CompletionUsageSchema.optional(),
|
|
3927
|
+
credits: z$1.object({
|
|
3928
|
+
used: z$1.number().optional(),
|
|
3929
|
+
usdCost: z$1.number().optional()
|
|
3930
|
+
}).optional(),
|
|
3931
|
+
responseFormatMode: z$1.enum([
|
|
3932
|
+
"native",
|
|
3933
|
+
"tool_use",
|
|
3934
|
+
"best-effort"
|
|
3935
|
+
]).optional(),
|
|
3936
|
+
stopReason: z$1.string().optional(),
|
|
3937
|
+
thinking: z$1.array(z$1.any()).optional(),
|
|
3938
|
+
toolStarted: z$1.object({
|
|
3939
|
+
name: z$1.string(),
|
|
3940
|
+
id: z$1.string().optional()
|
|
3941
|
+
}).optional()
|
|
3942
|
+
});
|
|
3943
|
+
/**
|
|
3944
|
+
* Classifiers the completions `error` frame may carry: the persisted quest codes plus the two
|
|
3945
|
+
* provider codes. A separate tuple because QUEST_ERROR_CODES is stored on quests and must not widen.
|
|
3946
|
+
*/
|
|
3947
|
+
const COMPLETION_SSE_ERROR_CODES = [
|
|
3948
|
+
...QUEST_ERROR_CODES,
|
|
3949
|
+
"provider_error",
|
|
3950
|
+
"provider_rejected",
|
|
3951
|
+
"content_blocked"
|
|
3952
|
+
];
|
|
3953
|
+
/**
|
|
3954
|
+
* The in-band terminal failure frame, sent only once the stream has opened. Failures found before
|
|
3955
|
+
* the provider call (auth, scope, validation, rate limit, model, credits) are JSON errors with a
|
|
3956
|
+
* real status instead; see completions.contract.ts.
|
|
3957
|
+
*
|
|
3958
|
+
* `code` is the machine-readable classifier: a billing code when settlement runs out mid-generation,
|
|
3959
|
+
* `provider_rejected` / `provider_error` when the model provider fails, `content_blocked` when the
|
|
3960
|
+
* model's safety classifier declined the request. Optional; callers must never match on the prose
|
|
3961
|
+
* `message`.
|
|
3962
|
+
*
|
|
3963
|
+
* The field is `code` rather than the conventions' `errorCode` because this frame shipped that way
|
|
3964
|
+
* and is a published wire shape.
|
|
3965
|
+
*/
|
|
3966
|
+
const CompletionSseErrorEventSchema = z$1.object({
|
|
3967
|
+
type: z$1.literal("error"),
|
|
3968
|
+
message: z$1.string(),
|
|
3969
|
+
requestId: z$1.string().optional(),
|
|
3970
|
+
code: z$1.enum(COMPLETION_SSE_ERROR_CODES).optional()
|
|
3971
|
+
});
|
|
3972
|
+
/**
|
|
3973
|
+
* A provider content block the caller must echo back verbatim, in stream order, in the assistant
|
|
3974
|
+
* `messages` content of the next request: today the Anthropic tool search `server_tool_use` and
|
|
3975
|
+
* `tool_search_tool_result` blocks. Never executed by the caller and never answered with a tool_result.
|
|
3976
|
+
*/
|
|
3977
|
+
const CompletionProviderBlockEventSchema = z$1.object({
|
|
3978
|
+
type: z$1.literal("provider_block"),
|
|
3979
|
+
provider: z$1.literal("anthropic"),
|
|
3980
|
+
block: z$1.record(z$1.string(), z$1.unknown())
|
|
3981
|
+
});
|
|
3982
|
+
/** One `data:` event in the `text/event-stream` completions response. */
|
|
3983
|
+
const CompletionStreamEventSchema = z$1.union([
|
|
3984
|
+
CompletionMetaEventSchema,
|
|
3985
|
+
CompletionContentEventSchema,
|
|
3986
|
+
CompletionProviderBlockEventSchema,
|
|
3987
|
+
CompletionSseErrorEventSchema
|
|
3988
|
+
]);
|
|
3646
3989
|
/** Splits on the marker tokens, keeping them in the result so a scan can track nesting depth. */
|
|
3647
3990
|
const THINK_TAG_TOKENS = /(<think>|<\/think>)/g;
|
|
3648
3991
|
/**
|
|
@@ -3712,7 +4055,7 @@ function createThinkMarkerEscaper() {
|
|
|
3712
4055
|
* The visible remainder of one reply slot, with hidden reasoning removed.
|
|
3713
4056
|
*
|
|
3714
4057
|
* This is the rule the chat transcript renders by - `extractReplies` in
|
|
3715
|
-
*
|
|
4058
|
+
* packages/server-utils/src/shared/replyUtils.ts calls straight into it, so the two cannot drift.
|
|
3716
4059
|
* Anything deriving "did the user see something yet" (latency metrics in particular) must
|
|
3717
4060
|
* use this and not a looser non-empty check: a metric built on a looser rule reports text
|
|
3718
4061
|
* as seen while the UI is still hiding it.
|
|
@@ -3780,8 +4123,8 @@ const invalid = (reason) => ({
|
|
|
3780
4123
|
status: "invalid",
|
|
3781
4124
|
reason
|
|
3782
4125
|
});
|
|
3783
|
-
const FENCE_OPEN_LINE = /^[ \t]*(`{3,}|~{3,})(.*)$/;
|
|
3784
|
-
const FENCE_CLOSE_LINE = /^[ \t]*(`{3,}|~{3,})[ \t]*$/;
|
|
4126
|
+
const FENCE_OPEN_LINE$1 = /^[ \t]*(`{3,}|~{3,})(.*)$/;
|
|
4127
|
+
const FENCE_CLOSE_LINE$1 = /^[ \t]*(`{3,}|~{3,})[ \t]*$/;
|
|
3785
4128
|
/**
|
|
3786
4129
|
* Offset where a slot's visible answer starts: just past its last top-level `</think>`, 0 when it
|
|
3787
4130
|
* has none, or null while a `<think>` is still open. Depth-tracked to match visibleReplyText in
|
|
@@ -3811,7 +4154,7 @@ function findLastChoicesFence(text) {
|
|
|
3811
4154
|
const lineEnd = newline === -1 ? text.length : newline;
|
|
3812
4155
|
const line = text.slice(lineStart, lineEnd).replace(/\r$/, "");
|
|
3813
4156
|
if (!open) {
|
|
3814
|
-
const match = line.match(FENCE_OPEN_LINE);
|
|
4157
|
+
const match = line.match(FENCE_OPEN_LINE$1);
|
|
3815
4158
|
if (match && !(match[1][0] === "`" && match[2].includes("`"))) open = {
|
|
3816
4159
|
start: lineStart,
|
|
3817
4160
|
bodyStart: newline === -1 ? text.length : newline + 1,
|
|
@@ -3819,7 +4162,7 @@ function findLastChoicesFence(text) {
|
|
|
3819
4162
|
isChoices: match[1] === "```" && match[2].trim().toLowerCase() === "choices"
|
|
3820
4163
|
};
|
|
3821
4164
|
} else {
|
|
3822
|
-
const match = line.match(FENCE_CLOSE_LINE);
|
|
4165
|
+
const match = line.match(FENCE_CLOSE_LINE$1);
|
|
3823
4166
|
if (match && match[1][0] === open.marker[0] && match[1].length >= open.marker.length) {
|
|
3824
4167
|
if (open.isChoices) last = {
|
|
3825
4168
|
start: open.start,
|
|
@@ -4826,6 +5169,13 @@ z$1.object({
|
|
|
4826
5169
|
reason: z$1.enum(REPLY_CHOICES_INVALID_REASONS).optional()
|
|
4827
5170
|
}).optional(),
|
|
4828
5171
|
/**
|
|
5172
|
+
* Set when finalize stripped a tool call the model wrote into its reply as text instead of
|
|
5173
|
+
* calling it (see ../utils/narratedToolCalls.ts). The call never ran; `toolNames` are the
|
|
5174
|
+
* offered tools it named. Absent when nothing was stripped. Consumers read this rather than
|
|
5175
|
+
* matching the reply text, which no longer carries the call.
|
|
5176
|
+
*/
|
|
5177
|
+
narratedToolCall: z$1.object({ toolNames: z$1.array(z$1.string()) }).optional(),
|
|
5178
|
+
/**
|
|
4829
5179
|
* Set when an emitted artifact looks voluntarily abbreviated - placeholder comments in
|
|
4830
5180
|
* place of real code, or calls into functions that were never defined. The complement to
|
|
4831
5181
|
* `finishReason === 'max_tokens'`: truncation is a hard stop the provider reports, elision
|
|
@@ -5064,8 +5414,11 @@ const ChatWaitTimeoutErrorSchema = ApiErrorSchema.extend({
|
|
|
5064
5414
|
const StorageLimitErrorSchema = ApiErrorSchema.extend(StorageLimitErrorInfoSchema.partial().shape);
|
|
5065
5415
|
/** 503 when this deployment has no usable key for a provider the request needs (data-lake search, voice). */
|
|
5066
5416
|
const ProviderNotConfiguredErrorSchema = ApiErrorSchema.extend({ errorCode: z$1.literal("provider_not_configured").optional() });
|
|
5067
|
-
/**
|
|
5068
|
-
|
|
5417
|
+
/**
|
|
5418
|
+
* 400 for a `model` the caller cannot use, or a refused tool search request; `errorCode` is absent on the
|
|
5419
|
+
* other 400s (e.g. malformed JSON).
|
|
5420
|
+
*/
|
|
5421
|
+
const CompletionsBadRequestErrorSchema = ApiErrorSchema.extend({ errorCode: z$1.enum([UNKNOWN_MODEL_ERROR_CODE, ...COMPLETION_TOOL_ERROR_CODES]).optional() });
|
|
5069
5422
|
/**
|
|
5070
5423
|
* Error envelope for the 403 apiKeyAuth (apps/client/server/middlewares/apiKeyAuth.ts)
|
|
5071
5424
|
* throws when an API key lacks a route's scopes. It names what the ROUTE requires,
|
|
@@ -5106,6 +5459,7 @@ const ttsRequestSchema = z.object({
|
|
|
5106
5459
|
stability: z.number().min(0).max(1).optional(),
|
|
5107
5460
|
similarityBoost: z.number().min(0).max(1).optional(),
|
|
5108
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`)."),
|
|
5109
5463
|
...generatedAudioRequestFields
|
|
5110
5464
|
});
|
|
5111
5465
|
/**
|
|
@@ -5121,6 +5475,21 @@ const ttsBase64ResponseSchema = extendGeneratedAudioResponseSchema({
|
|
|
5121
5475
|
fallbackFrom: supportedVoiceGenerationVendor.optional()
|
|
5122
5476
|
});
|
|
5123
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
|
+
/**
|
|
5124
5493
|
* Error body for `POST /api/ai/tts`, shared by the 401, 422, 429 and 502; the 413
|
|
5125
5494
|
* has a shape of its own (`ttsResponseTooLargeSchema`). `errorCode` is present only
|
|
5126
5495
|
* on the conditions that carry a classifier; an ordinary validation 422 has none.
|
|
@@ -5146,13 +5515,11 @@ const ttsBase64ResponseSchema = extendGeneratedAudioResponseSchema({
|
|
|
5146
5515
|
* this handler's written bodies is a gap in the handler rather than something to
|
|
5147
5516
|
* enshrine in a schema.
|
|
5148
5517
|
*/
|
|
5518
|
+
/** 403 body: the `ai:generate` scope refusal (`required_scopes`), or a billing refusal. */
|
|
5519
|
+
const ttsForbiddenResponseSchema = BillingOrganizationForbiddenErrorSchema.extend({ provider: supportedVoiceGenerationVendor.optional() });
|
|
5149
5520
|
const ttsErrorResponseSchema = ApiErrorSchema.extend({
|
|
5150
5521
|
provider: supportedVoiceGenerationVendor.optional(),
|
|
5151
|
-
errorCode: z.enum(
|
|
5152
|
-
"insufficient_credits",
|
|
5153
|
-
"provider_not_configured",
|
|
5154
|
-
"provider_rejected"
|
|
5155
|
-
]).optional()
|
|
5522
|
+
errorCode: z.enum(TTS_ERROR_CODES).optional()
|
|
5156
5523
|
});
|
|
5157
5524
|
/**
|
|
5158
5525
|
* TTS 413 body: `generatedAudioTooLargeSchema` plus the provider. The handler never
|
|
@@ -5246,6 +5613,8 @@ const MUSIC_VALIDATION_ERROR_CODES = [
|
|
|
5246
5613
|
"lyrics_with_instrumental",
|
|
5247
5614
|
"lyrics_too_long"
|
|
5248
5615
|
];
|
|
5616
|
+
const SECONDS = String.raw`\d+(?:\.\d+)?`;
|
|
5617
|
+
String.raw`\[(?:${SECONDS}:${SECONDS}|:)\]`;
|
|
5249
5618
|
/**
|
|
5250
5619
|
* Building blocks for entity response schemas held to an entity's key list (see
|
|
5251
5620
|
* selfUserResponseSchema in ./user.ts for the full rationale). A passthrough value is
|
|
@@ -5989,34 +6358,95 @@ function parseCidr(raw) {
|
|
|
5989
6358
|
prefix: Number(value.slice(slash + 1))
|
|
5990
6359
|
};
|
|
5991
6360
|
}
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
6361
|
+
/**
|
|
6362
|
+
* Networks a private-network opt-in never reaches, whatever the operator lists, self-host included.
|
|
6363
|
+
* One list for both sides: the settings validator refuses any range that overlaps an entry, and the
|
|
6364
|
+
* fetch path (`buildNeverAdmitted` in fab-pipeline's pinnedFetch.ts) refuses these at connect time.
|
|
6365
|
+
* IPv4 entries also cover their IPv4-mapped IPv6 forms (`::ffff:0:0/96`) on both sides.
|
|
6366
|
+
*/
|
|
6367
|
+
const NEVER_ADMITTED_NETWORKS = [
|
|
6368
|
+
{
|
|
6369
|
+
cidr: "0.0.0.0/8",
|
|
6370
|
+
label: "this network"
|
|
6371
|
+
},
|
|
6372
|
+
{
|
|
6373
|
+
cidr: "127.0.0.0/8",
|
|
6374
|
+
label: "loopback"
|
|
6375
|
+
},
|
|
6376
|
+
{
|
|
6377
|
+
cidr: "169.254.0.0/16",
|
|
6378
|
+
label: "link-local, including cloud metadata"
|
|
6379
|
+
},
|
|
6380
|
+
{
|
|
6381
|
+
cidr: "100.100.100.200/32",
|
|
6382
|
+
label: "cloud metadata"
|
|
6383
|
+
},
|
|
6384
|
+
{
|
|
6385
|
+
cidr: "fd00:ec2::254/128",
|
|
6386
|
+
label: "cloud metadata"
|
|
6387
|
+
},
|
|
6388
|
+
{
|
|
6389
|
+
cidr: "64:ff9b::a9fe:a9fe/128",
|
|
6390
|
+
label: "cloud metadata"
|
|
6391
|
+
},
|
|
6392
|
+
{
|
|
6393
|
+
cidr: "::/128",
|
|
6394
|
+
label: "unspecified"
|
|
6395
|
+
},
|
|
6396
|
+
{
|
|
6397
|
+
cidr: "::1/128",
|
|
6398
|
+
label: "loopback"
|
|
6399
|
+
},
|
|
6400
|
+
{
|
|
6401
|
+
cidr: "fe80::/10",
|
|
6402
|
+
label: "link-local"
|
|
6403
|
+
}
|
|
6404
|
+
];
|
|
6405
|
+
const IPV4_MAPPED_PREFIX = [
|
|
6406
|
+
0,
|
|
6407
|
+
0,
|
|
6408
|
+
0,
|
|
6409
|
+
0,
|
|
6410
|
+
0,
|
|
6411
|
+
0,
|
|
6412
|
+
0,
|
|
6413
|
+
0,
|
|
6414
|
+
0,
|
|
6415
|
+
0,
|
|
6416
|
+
255,
|
|
6417
|
+
255
|
|
6418
|
+
];
|
|
6419
|
+
/** An IPv4 CIDR in its IPv4-mapped IPv6 form; other CIDRs unchanged. */
|
|
6420
|
+
function asIpv6(cidr) {
|
|
6421
|
+
if (cidr.version === 6) return cidr;
|
|
6422
|
+
return {
|
|
6423
|
+
version: 6,
|
|
6424
|
+
bytes: [...IPV4_MAPPED_PREFIX, ...cidr.bytes],
|
|
6425
|
+
prefix: cidr.prefix + 96
|
|
6426
|
+
};
|
|
6427
|
+
}
|
|
6428
|
+
function cidrsOverlap(a, b) {
|
|
6429
|
+
const [left, right] = a.version === b.version ? [a, b] : [asIpv6(a), asIpv6(b)];
|
|
6430
|
+
const prefix = Math.min(left.prefix, right.prefix);
|
|
6431
|
+
for (let bit = 0; bit < prefix; bit++) {
|
|
5996
6432
|
const byte = bit >> 3;
|
|
5997
6433
|
const mask = 128 >> (bit & 7);
|
|
5998
|
-
if (((
|
|
6434
|
+
if (((left.bytes[byte] ?? 0) & mask) !== ((right.bytes[byte] ?? 0) & mask)) return false;
|
|
5999
6435
|
}
|
|
6000
6436
|
return true;
|
|
6001
6437
|
}
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
const CLOUD_METADATA_ADDRESSES = [
|
|
6007
|
-
"169.254.169.254",
|
|
6008
|
-
"fd00:ec2::254",
|
|
6009
|
-
"::ffff:169.254.169.254",
|
|
6010
|
-
"64:ff9b::169.254.169.254"
|
|
6011
|
-
];
|
|
6438
|
+
const NEVER_ADMITTED_PARSED = NEVER_ADMITTED_NETWORKS.map((entry) => ({
|
|
6439
|
+
...entry,
|
|
6440
|
+
parsed: parseCidr(entry.cidr)
|
|
6441
|
+
}));
|
|
6012
6442
|
/** Why `raw` may not be allowed as a private network, or null when it may. */
|
|
6013
6443
|
function customMcpPrivateCidrProblem(raw) {
|
|
6014
6444
|
const cidr = parseCidr(raw);
|
|
6015
6445
|
if (!cidr) return "Must be a CIDR such as 10.0.0.0/8 or fd12:3456::/32";
|
|
6016
6446
|
const minPrefix = CUSTOM_MCP_MIN_CIDR_PREFIX[cidr.version];
|
|
6017
6447
|
if (cidr.prefix < minPrefix) return `IPv${cidr.version} ranges must be /${minPrefix} or narrower`;
|
|
6018
|
-
const
|
|
6019
|
-
if (
|
|
6448
|
+
const blocked = NEVER_ADMITTED_PARSED.find((entry) => cidrsOverlap(cidr, entry.parsed));
|
|
6449
|
+
if (blocked) return `Range overlaps ${blocked.cidr} (${blocked.label}), which is never reachable`;
|
|
6020
6450
|
return null;
|
|
6021
6451
|
}
|
|
6022
6452
|
const CustomMcpPrivateCidrSchema = z$1.string().trim().toLowerCase().superRefine((value, ctx) => {
|
|
@@ -6427,8 +6857,11 @@ If the full deliverable genuinely will not fit, do NOT stub the difference. REDU
|
|
|
6427
6857
|
* public "Help Center" data lake, so when the knowledge-base search tool is available the model
|
|
6428
6858
|
* can GROUND its answer in the real docs; the prompt still forbids inventing UI paths it can't
|
|
6429
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.
|
|
6430
6863
|
*/
|
|
6431
|
-
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
|
|
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.`;
|
|
6432
6865
|
/**
|
|
6433
6866
|
* Default text for the abstention licence. Single source of truth used BOTH as the
|
|
6434
6867
|
* `AbstentionPrompt` admin setting's default AND as the runtime fallback in ChatCompletionProcess -
|
|
@@ -6592,6 +7025,7 @@ z$1.enum([
|
|
|
6592
7025
|
"BedrockGuardrailId",
|
|
6593
7026
|
"BedrockGuardrailVersion",
|
|
6594
7027
|
"ImageModerationEnabled",
|
|
7028
|
+
"ImageModerationReviewerEmails",
|
|
6595
7029
|
"tagLineMain",
|
|
6596
7030
|
"tagLineSub",
|
|
6597
7031
|
"defaultTags",
|
|
@@ -7020,8 +7454,8 @@ const CustomMcpPolicySchema = z$1.object({
|
|
|
7020
7454
|
const CustomMcpBlockedHostsSchema = z$1.object({ hosts: McpHostPatternListSchema.default([]) });
|
|
7021
7455
|
/**
|
|
7022
7456
|
* Self-host only; hosted deployments never reach private networks regardless of this value. Each
|
|
7023
|
-
* CIDR is strictly parsed, at least /8 (IPv4) or /16 (IPv6), and never
|
|
7024
|
-
*
|
|
7457
|
+
* CIDR is strictly parsed, at least /8 (IPv4) or /16 (IPv6), and never overlaps a network the fetch
|
|
7458
|
+
* path refuses anyway (NEVER_ADMITTED_NETWORKS in customMcpHosts.ts).
|
|
7025
7459
|
*/
|
|
7026
7460
|
const CustomMcpAllowPrivateNetworksSchema = z$1.object({
|
|
7027
7461
|
cidrs: z$1.array(CustomMcpPrivateCidrSchema).max(100).default([]),
|
|
@@ -9091,6 +9525,14 @@ const settingsMap = {
|
|
|
9091
9525
|
description: "Whether to run generated images through content moderation (Rekognition) and block explicit content. Legal-safety control (#9776) — default ON.",
|
|
9092
9526
|
category: "AI Moderation"
|
|
9093
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
|
+
}),
|
|
9094
9536
|
SkillMarketHighRiskTools: makeStringSetting({
|
|
9095
9537
|
key: "SkillMarketHighRiskTools",
|
|
9096
9538
|
name: "Skill Market High-Risk Tools",
|
|
@@ -9236,7 +9678,7 @@ const settingsMap = {
|
|
|
9236
9678
|
userReadable: true,
|
|
9237
9679
|
name: "Price Per Credit",
|
|
9238
9680
|
defaultValue: 50,
|
|
9239
|
-
description:
|
|
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.`,
|
|
9240
9682
|
category: "Users",
|
|
9241
9683
|
group: API_SERVICE_GROUPS.CREDITS.id,
|
|
9242
9684
|
order: 1
|
|
@@ -9668,7 +10110,7 @@ const settingsMap = {
|
|
|
9668
10110
|
userReadable: true,
|
|
9669
10111
|
name: "Default Free Credits",
|
|
9670
10112
|
defaultValue: 0,
|
|
9671
|
-
description:
|
|
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.",
|
|
9672
10114
|
group: API_SERVICE_GROUPS.CREDITS.id,
|
|
9673
10115
|
category: "Users"
|
|
9674
10116
|
}),
|
|
@@ -11493,6 +11935,17 @@ z$1.looseObject({
|
|
|
11493
11935
|
param: z$1.string().optional()
|
|
11494
11936
|
});
|
|
11495
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
|
+
/**
|
|
11496
11949
|
* Supported sound-effects generation vendors. Currently only ElevenLabs.
|
|
11497
11950
|
* New vendors are added here and in the `aiSoundService` factory.
|
|
11498
11951
|
*/
|
|
@@ -11511,6 +11964,7 @@ const soundEffectsRequestSchema = z.object({
|
|
|
11511
11964
|
durationSeconds: z.number().min(.5).max(30).optional(),
|
|
11512
11965
|
promptInfluence: z.number().min(0).max(1).optional(),
|
|
11513
11966
|
format: z.string().optional(),
|
|
11967
|
+
organization_id: BillingOrganizationIdSchema,
|
|
11514
11968
|
...generatedAudioRequestFields
|
|
11515
11969
|
});
|
|
11516
11970
|
/**
|
|
@@ -11733,16 +12187,8 @@ const CliCompletionRequestAction = z$1.object({
|
|
|
11733
12187
|
temperature: z$1.number().optional(),
|
|
11734
12188
|
maxTokens: z$1.number().optional(),
|
|
11735
12189
|
stream: z$1.boolean().optional(),
|
|
11736
|
-
tools: z$1.array(
|
|
11737
|
-
response_format:
|
|
11738
|
-
type: z$1.literal("json_schema"),
|
|
11739
|
-
json_schema: z$1.object({
|
|
11740
|
-
name: z$1.string(),
|
|
11741
|
-
description: z$1.string().optional(),
|
|
11742
|
-
schema: z$1.record(z$1.string(), z$1.any()),
|
|
11743
|
-
strict: z$1.boolean().optional().default(true)
|
|
11744
|
-
})
|
|
11745
|
-
})]).optional()
|
|
12190
|
+
tools: z$1.array(CompletionToolSchema).optional(),
|
|
12191
|
+
response_format: ResponseFormatSchema.optional()
|
|
11746
12192
|
}).optional()
|
|
11747
12193
|
});
|
|
11748
12194
|
/**
|
|
@@ -12231,7 +12677,7 @@ const VoiceCreditsExhaustedAction = z$1.object({
|
|
|
12231
12677
|
const CliCompletionChunkAction = z$1.object({
|
|
12232
12678
|
action: z$1.literal("cli_completion_chunk"),
|
|
12233
12679
|
requestId: z$1.string(),
|
|
12234
|
-
chunk: z$1.object({
|
|
12680
|
+
chunk: z$1.union([z$1.object({
|
|
12235
12681
|
type: z$1.enum(["content", "tool_use"]),
|
|
12236
12682
|
text: z$1.string(),
|
|
12237
12683
|
toolStarted: z$1.object({
|
|
@@ -12244,7 +12690,7 @@ const CliCompletionChunkAction = z$1.object({
|
|
|
12244
12690
|
outputTokens: z$1.number().optional()
|
|
12245
12691
|
}).optional(),
|
|
12246
12692
|
thinking: z$1.array(z$1.unknown()).optional()
|
|
12247
|
-
})
|
|
12693
|
+
}), CompletionProviderBlockEventSchema])
|
|
12248
12694
|
});
|
|
12249
12695
|
/**
|
|
12250
12696
|
* CLI Completion stream finished successfully
|
|
@@ -12261,7 +12707,9 @@ const CliCompletionErrorAction = z$1.object({
|
|
|
12261
12707
|
requestId: z$1.string(),
|
|
12262
12708
|
error: z$1.string(),
|
|
12263
12709
|
/** Seconds until the caller's rate-limit window reopens; present only on a rate-limit refusal. */
|
|
12264
|
-
retryAfter: z$1.number().optional()
|
|
12710
|
+
retryAfter: z$1.number().optional(),
|
|
12711
|
+
/** Machine-readable reason on a request the caller must fix (a 4xx), e.g. `tool_search_unsupported`. */
|
|
12712
|
+
errorCode: z$1.string().optional()
|
|
12265
12713
|
});
|
|
12266
12714
|
/**
|
|
12267
12715
|
* CLI Tool execution response over WebSocket
|
|
@@ -12912,7 +13360,12 @@ const AgentProgressAction = z$1.object({
|
|
|
12912
13360
|
generationJobs: z$1.array(z$1.object({
|
|
12913
13361
|
id: z$1.string(),
|
|
12914
13362
|
kind: z$1.enum(GENERATION_JOB_KINDS)
|
|
12915
|
-
})).optional()
|
|
13363
|
+
})).optional(),
|
|
13364
|
+
pendingAction: z$1.object({
|
|
13365
|
+
tool: z$1.string(),
|
|
13366
|
+
params: z$1.record(z$1.string(), z$1.unknown()),
|
|
13367
|
+
ts: z$1.number()
|
|
13368
|
+
}).optional()
|
|
12916
13369
|
});
|
|
12917
13370
|
const AgentCompletedAction = z$1.object({
|
|
12918
13371
|
action: z$1.literal("completed"),
|
|
@@ -13277,8 +13730,7 @@ const AgentExecutionStartRequestSchema = z$1.object({
|
|
|
13277
13730
|
max_tokens: z$1.number().int().positive().optional(),
|
|
13278
13731
|
thinking: z$1.object({
|
|
13279
13732
|
enabled: z$1.boolean(),
|
|
13280
|
-
|
|
13281
|
-
budget_tokens: z$1.number().int().positive().max(32e3).optional()
|
|
13733
|
+
budget_tokens: z$1.number().int().positive().max(MAX_THINKING_BUDGET_TOKENS).optional()
|
|
13282
13734
|
}).optional(),
|
|
13283
13735
|
/** Per-message file attachments (fabFile ids), materialized into the first iteration. */
|
|
13284
13736
|
file_ids: z$1.array(z$1.string()).optional(),
|
|
@@ -13376,171 +13828,12 @@ const AgentExecutionStatusResponseSchema = z$1.object({
|
|
|
13376
13828
|
});
|
|
13377
13829
|
/** Path parameter for `GET /api/v1/agent-executions/{id}`. */
|
|
13378
13830
|
const AgentExecutionIdParamSchema = z$1.object({ id: z$1.string().min(1) });
|
|
13379
|
-
const CompletionReasoningEffortSchema = z$1.enum([
|
|
13380
|
-
"none",
|
|
13381
|
-
"minimal",
|
|
13382
|
-
"low",
|
|
13383
|
-
"medium",
|
|
13384
|
-
"high",
|
|
13385
|
-
"xhigh"
|
|
13386
|
-
]);
|
|
13387
|
-
/**
|
|
13388
|
-
* Tool schema matching ICompletionOptionTools.toolSchema. The Zod surface only
|
|
13389
|
-
* covers wire-format fields (toolFn is server-side). Replaces the historical
|
|
13390
|
-
* z.array(z.any()) so client-side bugs (typos in name, missing type) surface
|
|
13391
|
-
* at parse time instead of failing silently inside the backend.
|
|
13392
|
-
*/
|
|
13393
|
-
const CompletionToolSchema = z$1.object({
|
|
13394
|
-
toolSchema: z$1.object({
|
|
13395
|
-
name: z$1.string(),
|
|
13396
|
-
description: z$1.string(),
|
|
13397
|
-
parameters: z$1.object({
|
|
13398
|
-
type: z$1.literal("object"),
|
|
13399
|
-
properties: z$1.record(z$1.string(), z$1.any()).optional(),
|
|
13400
|
-
additionalProperties: z$1.boolean().optional(),
|
|
13401
|
-
required: z$1.array(z$1.string()).optional()
|
|
13402
|
-
}).passthrough(),
|
|
13403
|
-
strict: z$1.boolean().optional()
|
|
13404
|
-
}),
|
|
13405
|
-
_isMcpTool: z$1.boolean().optional()
|
|
13406
|
-
});
|
|
13407
|
-
/**
|
|
13408
|
-
* JSON Schema definition for structured output. The `schema` field is a full
|
|
13409
|
-
* JSON Schema document (we don't try to validate JSON Schema with Zod - that's
|
|
13410
|
-
* the caller's contract with the model). `strict: true` is the default, matching
|
|
13411
|
-
* OpenAI's strict-mode subset semantics.
|
|
13412
|
-
*/
|
|
13413
|
-
const ResponseFormatSchema = z$1.discriminatedUnion("type", [z$1.object({ type: z$1.literal("text") }), z$1.object({
|
|
13414
|
-
type: z$1.literal("json_schema"),
|
|
13415
|
-
json_schema: z$1.object({
|
|
13416
|
-
name: z$1.string(),
|
|
13417
|
-
description: z$1.string().optional(),
|
|
13418
|
-
schema: z$1.record(z$1.string(), z$1.any()),
|
|
13419
|
-
strict: z$1.boolean().optional().default(true)
|
|
13420
|
-
})
|
|
13421
|
-
})]);
|
|
13422
|
-
/**
|
|
13423
|
-
* Wire-format message for /api/ai/v1/completions. The optional `cache: true`
|
|
13424
|
-
* flag is honored by Anthropic (translated to `cache_control: { type: 'ephemeral' }`
|
|
13425
|
-
* with the appropriate beta header) and silently ignored by other providers.
|
|
13426
|
-
*/
|
|
13427
|
-
const CompletionMessageSchema = z$1.object({
|
|
13428
|
-
role: z$1.enum([
|
|
13429
|
-
"user",
|
|
13430
|
-
"assistant",
|
|
13431
|
-
"system"
|
|
13432
|
-
]),
|
|
13433
|
-
content: z$1.union([z$1.string(), z$1.array(z$1.any())]),
|
|
13434
|
-
cache: z$1.boolean().optional()
|
|
13435
|
-
});
|
|
13436
|
-
/**
|
|
13437
|
-
* Schema for CLI LLM completion requests
|
|
13438
|
-
* Shared between Next.js API route (dev) and Lambda function (production)
|
|
13439
|
-
*
|
|
13440
|
-
* `response_format`, `stream`, `tools`, `temperature`, and `max_tokens` are all
|
|
13441
|
-
* accepted at the top level (OpenAI-compatible, matching how every major LLM
|
|
13442
|
-
* SDK shapes a completion request) AND nested under `options` (legacy shape).
|
|
13443
|
-
* Use `normalizeCompletionRequest()` to collapse both surfaces into the
|
|
13444
|
-
* canonical `options.<field>` location before downstream consumption.
|
|
13445
|
-
*/
|
|
13446
|
-
const CompletionRequestSchema = z$1.object({
|
|
13447
|
-
model: z$1.string().max(256),
|
|
13448
|
-
messages: z$1.array(CompletionMessageSchema),
|
|
13449
|
-
response_format: ResponseFormatSchema.optional(),
|
|
13450
|
-
stream: z$1.boolean().optional(),
|
|
13451
|
-
tools: z$1.array(CompletionToolSchema).optional(),
|
|
13452
|
-
temperature: z$1.number().optional(),
|
|
13453
|
-
max_tokens: z$1.number().optional(),
|
|
13454
|
-
options: z$1.object({
|
|
13455
|
-
temperature: z$1.number().optional(),
|
|
13456
|
-
maxTokens: z$1.number().optional(),
|
|
13457
|
-
stream: z$1.boolean().optional(),
|
|
13458
|
-
tools: z$1.array(CompletionToolSchema).optional(),
|
|
13459
|
-
response_format: ResponseFormatSchema.optional(),
|
|
13460
|
-
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."),
|
|
13461
|
-
thinking: z$1.object({
|
|
13462
|
-
enabled: z$1.boolean(),
|
|
13463
|
-
budget_tokens: z$1.number().int().min(1024).optional()
|
|
13464
|
-
}).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.")
|
|
13465
|
-
}).optional()
|
|
13466
|
-
});
|
|
13467
|
-
const CompletionUsageSchema = z$1.object({
|
|
13468
|
-
inputTokens: z$1.number().optional(),
|
|
13469
|
-
outputTokens: z$1.number().optional(),
|
|
13470
|
-
reasoningTokens: z$1.number().optional().describe("Reasoning/thinking tokens the provider reported. A subset of outputTokens, not additive and not billed on top. Absent when the provider or adapter reports no count."),
|
|
13471
|
-
cacheReadInputTokens: z$1.number().optional(),
|
|
13472
|
-
cacheCreationInputTokens: z$1.number().optional()
|
|
13473
|
-
});
|
|
13474
|
-
const CompletionMetaEventSchema = z$1.object({
|
|
13475
|
-
type: z$1.literal("meta"),
|
|
13476
|
-
requestId: z$1.string()
|
|
13477
|
-
});
|
|
13478
|
-
const CompletionContentEventSchema = z$1.object({
|
|
13479
|
-
type: z$1.enum(["content", "tool_use"]),
|
|
13480
|
-
text: z$1.string(),
|
|
13481
|
-
tools: z$1.array(z$1.object({
|
|
13482
|
-
name: z$1.string(),
|
|
13483
|
-
arguments: z$1.string().optional(),
|
|
13484
|
-
id: z$1.string().optional()
|
|
13485
|
-
})).optional(),
|
|
13486
|
-
usage: CompletionUsageSchema.optional(),
|
|
13487
|
-
credits: z$1.object({
|
|
13488
|
-
used: z$1.number().optional(),
|
|
13489
|
-
usdCost: z$1.number().optional()
|
|
13490
|
-
}).optional(),
|
|
13491
|
-
responseFormatMode: z$1.enum([
|
|
13492
|
-
"native",
|
|
13493
|
-
"tool_use",
|
|
13494
|
-
"best-effort"
|
|
13495
|
-
]).optional(),
|
|
13496
|
-
stopReason: z$1.string().optional(),
|
|
13497
|
-
thinking: z$1.array(z$1.any()).optional(),
|
|
13498
|
-
toolStarted: z$1.object({
|
|
13499
|
-
name: z$1.string(),
|
|
13500
|
-
id: z$1.string().optional()
|
|
13501
|
-
}).optional()
|
|
13502
|
-
});
|
|
13503
|
-
/**
|
|
13504
|
-
* Classifiers the completions `error` frame may carry: the persisted quest codes plus the two
|
|
13505
|
-
* provider codes. A separate tuple because QUEST_ERROR_CODES is stored on quests and must not widen.
|
|
13506
|
-
*/
|
|
13507
|
-
const COMPLETION_SSE_ERROR_CODES = [
|
|
13508
|
-
...QUEST_ERROR_CODES,
|
|
13509
|
-
"provider_error",
|
|
13510
|
-
"provider_rejected",
|
|
13511
|
-
"content_blocked"
|
|
13512
|
-
];
|
|
13513
|
-
/**
|
|
13514
|
-
* The in-band terminal failure frame, sent only once the stream has opened. Failures found before
|
|
13515
|
-
* the provider call (auth, scope, validation, rate limit, model, credits) are JSON errors with a
|
|
13516
|
-
* real status instead; see completions.contract.ts.
|
|
13517
|
-
*
|
|
13518
|
-
* `code` is the machine-readable classifier: a billing code when settlement runs out mid-generation,
|
|
13519
|
-
* `provider_rejected` / `provider_error` when the model provider fails, `content_blocked` when the
|
|
13520
|
-
* model's safety classifier declined the request. Optional; callers must never match on the prose
|
|
13521
|
-
* `message`.
|
|
13522
|
-
*
|
|
13523
|
-
* The field is `code` rather than the conventions' `errorCode` because this frame shipped that way
|
|
13524
|
-
* and is a published wire shape.
|
|
13525
|
-
*/
|
|
13526
|
-
const CompletionSseErrorEventSchema = z$1.object({
|
|
13527
|
-
type: z$1.literal("error"),
|
|
13528
|
-
message: z$1.string(),
|
|
13529
|
-
requestId: z$1.string().optional(),
|
|
13530
|
-
code: z$1.enum(COMPLETION_SSE_ERROR_CODES).optional()
|
|
13531
|
-
});
|
|
13532
|
-
/** One `data:` event in the `text/event-stream` completions response. */
|
|
13533
|
-
const CompletionStreamEventSchema = z$1.union([
|
|
13534
|
-
CompletionMetaEventSchema,
|
|
13535
|
-
CompletionContentEventSchema,
|
|
13536
|
-
CompletionSseErrorEventSchema
|
|
13537
|
-
]);
|
|
13538
13831
|
/**
|
|
13539
13832
|
* Server-side tool execution schemas for POST /api/ai/v1/tools.
|
|
13540
13833
|
*
|
|
13541
13834
|
* Plain Zod (no `.openapi()`) so any runtime can import them; the OpenAPI layer
|
|
13542
13835
|
* annotates them via the contract. The tool-name enum MUST stay in sync with
|
|
13543
|
-
* SUPPORTED_TOOLS in
|
|
13836
|
+
* SUPPORTED_TOOLS in packages/server-utils/src/cli/toolsHandler.shared.ts.
|
|
13544
13837
|
*/
|
|
13545
13838
|
const ToolExecutionRequestSchema = z$1.object({
|
|
13546
13839
|
toolName: z$1.enum([
|
|
@@ -14196,7 +14489,7 @@ const ChatCompletionCreateInputSchema = z$1.object({
|
|
|
14196
14489
|
stream: z$1.boolean().optional(),
|
|
14197
14490
|
thinking: z$1.object({
|
|
14198
14491
|
enabled: z$1.boolean(),
|
|
14199
|
-
budget_tokens: z$1.number().optional()
|
|
14492
|
+
budget_tokens: z$1.number().int().positive().max(MAX_THINKING_BUDGET_TOKENS).optional()
|
|
14200
14493
|
}).optional(),
|
|
14201
14494
|
messages: z$1.array(z$1.object({
|
|
14202
14495
|
role: z$1.enum([
|
|
@@ -14855,7 +15148,7 @@ const CreateSessionRequestSchema = z$1.object({
|
|
|
14855
15148
|
retrievalVectorizedOnly: z$1.boolean().optional(),
|
|
14856
15149
|
citationStyle: z$1.enum(["named", "indexed"]).optional(),
|
|
14857
15150
|
temperature: z$1.number().optional(),
|
|
14858
|
-
maxToolCalls: z$1.number().int().positive().optional(),
|
|
15151
|
+
maxToolCalls: z$1.number().int().positive().max(50).optional(),
|
|
14859
15152
|
autoNamePlaceholder: z$1.string().optional(),
|
|
14860
15153
|
tags: z$1.array(SessionTagSchema).optional(),
|
|
14861
15154
|
lastUsedModel: z$1.string().nullish()
|
|
@@ -14921,6 +15214,47 @@ z$2.object(passthroughShape({
|
|
|
14921
15214
|
uiSideEffects: true,
|
|
14922
15215
|
jupyterNotebook: true
|
|
14923
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
|
+
});
|
|
14924
15258
|
const questMasterPlanResponseSchema = z$2.object(passthroughShape({
|
|
14925
15259
|
id: true,
|
|
14926
15260
|
createdAt: true,
|
|
@@ -14943,6 +15277,10 @@ const questMasterPlanResponseSchema = z$2.object(passthroughShape({
|
|
|
14943
15277
|
decisions: true
|
|
14944
15278
|
}));
|
|
14945
15279
|
z$2.array(questMasterPlanResponseSchema);
|
|
15280
|
+
z$2.object({
|
|
15281
|
+
success: z$2.literal(true),
|
|
15282
|
+
plan: questMasterPlanResponseSchema
|
|
15283
|
+
}).extend({ metrics: passthroughField });
|
|
14946
15284
|
z$1.preprocess((val) => {
|
|
14947
15285
|
if (typeof val === "string") {
|
|
14948
15286
|
if (val.toLowerCase() === "true") return true;
|
|
@@ -15082,7 +15420,10 @@ const CreateFileUploadRequestSchema = z$1.object({
|
|
|
15082
15420
|
file_name: z$1.string().min(1),
|
|
15083
15421
|
/** Declared MIME type, e.g. `image/png`. Unsupported types are rejected with 400. */
|
|
15084
15422
|
mime_type: z$1.string().min(1),
|
|
15085
|
-
/**
|
|
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
|
+
*/
|
|
15086
15427
|
file_size: z$1.number().int().positive()
|
|
15087
15428
|
});
|
|
15088
15429
|
const FILE_MODERATION_STATUSES = [
|
|
@@ -16249,8 +16590,8 @@ const ListModelsResponseSchema = paginatedResponseSchema(z$1.object({
|
|
|
16249
16590
|
reasons_within_output_budget: z$1.boolean().describe("Whether reasoning tokens are spent inside `max_output_tokens` on every turn. When true, a small `max_tokens` can be used up by reasoning alone and return an empty reply, so leave room above the answer you expect."),
|
|
16250
16591
|
reasoning_efforts: z$1.array(CompletionReasoningEffortSchema).describe("The `reasoningEffort` levels this model acts on, lowest first; empty when it ignores the option. `none` is listed only where it turns reasoning off. Each level is mapped to the nearest one the provider offers. A listed level can still be dropped on one request: some OpenAI models drop it on tool turns, and Claude models with a fixed thinking budget drop it when `max_tokens` leaves no room for the budget plus the answer."),
|
|
16251
16592
|
supports_tools: z$1.boolean(),
|
|
16252
|
-
supports_tool_search: z$1.boolean().describe("Whether the model accepts the tool search server tool and `defer_loading: true` on tool definitions, so a large tool catalog is searched on demand instead of loaded into context up front. Describes the model
|
|
16253
|
-
supports_tool_changes: z$1.boolean().describe("Whether a system-role message can carry `tool_addition` and `tool_removal` blocks, which add or remove a declared tool mid-conversation. Describes the model only: `/api/ai/v1/completions` does not accept these blocks yet
|
|
16593
|
+
supports_tool_search: z$1.boolean().describe("Whether the model accepts the tool search server tool and `defer_loading: true` on tool definitions, so a large tool catalog is searched on demand instead of loaded into context up front. Describes the model: `/api/ai/v1/completions` honours it only for models whose `backend` is `anthropic`. A `bedrock` model with this flag set is not served with tool search there yet: a `serverTool` entry is refused with `errorCode: \"tool_search_unsupported\"` and `defer_loading` is ignored."),
|
|
16594
|
+
supports_tool_changes: z$1.boolean().describe("Whether a system-role message can carry `tool_addition` and `tool_removal` blocks, which add or remove a declared tool mid-conversation. Describes the model only: `/api/ai/v1/completions` does not accept these blocks yet, and will accept them first for models whose `backend` is `anthropic`."),
|
|
16254
16595
|
supports_vision: z$1.boolean(),
|
|
16255
16596
|
deprecation_date: z$1.string().nullable().describe("`YYYY-MM-DD`; null when no retirement is scheduled."),
|
|
16256
16597
|
replaced_by: z$1.string().nullable().describe("The id of the recommended successor, when there is one."),
|
|
@@ -16315,17 +16656,6 @@ const GENERATION_CALLBACK_DESCRIPTION = "Optional `callbackUrl`: an https URL th
|
|
|
16315
16656
|
* in sync with the rejections in apps/client/server/generationCallback/armGenerationCallback.ts.
|
|
16316
16657
|
*/
|
|
16317
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.";
|
|
16318
|
-
/**
|
|
16319
|
-
* The client-chosen billing organization on the v1 media request bodies (image generations and edits,
|
|
16320
|
-
* video and music generations). Blank is a 422 rather than an omission: billing must never fall
|
|
16321
|
-
* through to a different payer on an empty string. The server side of this contract is
|
|
16322
|
-
* resolveMediaBillingOrgId (apps/client/server/billing); keep these descriptions in step with it.
|
|
16323
|
-
*/
|
|
16324
|
-
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}\`).`);
|
|
16325
|
-
/** The billing-organization clause of a v1 media create route's 403 description. */
|
|
16326
|
-
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}\`).`;
|
|
16327
|
-
/** A v1 media create route's 400 for an org-billed key that no longer speaks for its organization. */
|
|
16328
|
-
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.";
|
|
16329
16659
|
const DashboardParamsSchema = z$1.object({
|
|
16330
16660
|
dashboardDataSources: z$1.array(z$1.object({
|
|
16331
16661
|
sourceName: z$1.string(),
|
|
@@ -16366,7 +16696,7 @@ const PromptIntentSchema = z$1.enum(["fresh", "continuation"]);
|
|
|
16366
16696
|
* (pages/api/v1/image-generations.ts); `literal` sends it unchanged apart from truncation to the model's prompt limit.
|
|
16367
16697
|
*/
|
|
16368
16698
|
const ImagePromptResolutionSchema = z$1.enum(["auto", "literal"]);
|
|
16369
|
-
const
|
|
16699
|
+
const GenerateImageIvokeParamsSchema = OpenAIImageGenerationInput.extend({
|
|
16370
16700
|
sessionId: z$1.string(),
|
|
16371
16701
|
questId: z$1.string().optional(),
|
|
16372
16702
|
organizationId: z$1.string().nullable().optional(),
|
|
@@ -16399,13 +16729,21 @@ const GenerateImageRequestBodySchema = OpenAIImageGenerationInput.extend({
|
|
|
16399
16729
|
/** Resolver intent - drives the banner's framing (continuation = "context applied" vs fresh = "enhanced"). */
|
|
16400
16730
|
intent: PromptIntentSchema.optional()
|
|
16401
16731
|
}).optional()
|
|
16402
|
-
})
|
|
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({
|
|
16403
16740
|
intent: true,
|
|
16404
16741
|
promptEnhancement: true
|
|
16405
16742
|
}).extend({
|
|
16406
16743
|
sessionId: z$1.string().optional(),
|
|
16407
16744
|
sessionName: z$1.string().optional(),
|
|
16408
16745
|
organizationId: BillingOrganizationIdSchema,
|
|
16746
|
+
organization_id: BillingOrgIdAliasSchema,
|
|
16409
16747
|
callbackUrl: GenerationCallbackUrlSchema.optional(),
|
|
16410
16748
|
projectId: z$1.string().optional(),
|
|
16411
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.")
|
|
@@ -16448,6 +16786,7 @@ const EditImageRequestBodySchema = OpenAIImageGenerationInput.extend({
|
|
|
16448
16786
|
sessionId: z$1.string(),
|
|
16449
16787
|
questId: z$1.string().optional(),
|
|
16450
16788
|
organizationId: BillingOrganizationIdSchema,
|
|
16789
|
+
organization_id: BillingOrgIdAliasSchema,
|
|
16451
16790
|
aspect_ratio: z$1.string().optional(),
|
|
16452
16791
|
fabFileIds: z$1.array(z$1.string()).prefault([]),
|
|
16453
16792
|
/**
|
|
@@ -16482,8 +16821,8 @@ z$1.object({
|
|
|
16482
16821
|
imageConfig: GenerateImageToolCallSchema.optional(),
|
|
16483
16822
|
audioConfig: AudioGenerationToolCallSchema.optional(),
|
|
16484
16823
|
deepResearchConfig: z$1.object({
|
|
16485
|
-
maxDepth: z$1.number().optional(),
|
|
16486
|
-
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(),
|
|
16487
16826
|
searchers: z$1.array(z$1.any()).optional()
|
|
16488
16827
|
}).optional(),
|
|
16489
16828
|
fabFileIds: z$1.array(z$1.string()),
|
|
@@ -16644,7 +16983,12 @@ z$1.object({
|
|
|
16644
16983
|
* Session-creation input, not a completion parameter, so it is applied only when `sessionId`
|
|
16645
16984
|
* is absent; ignored when an existing session is resolved.
|
|
16646
16985
|
*/
|
|
16647
|
-
agentIds: z$1.array(z$1.string()).optional()
|
|
16986
|
+
agentIds: z$1.array(z$1.string()).optional(),
|
|
16987
|
+
/**
|
|
16988
|
+
* The subset of `messageFileIds` the user scoped to this message only. Every other notebook-scope
|
|
16989
|
+
* message attachment is pinned to the session so it stays in context on later turns.
|
|
16990
|
+
*/
|
|
16991
|
+
messageOnlyFileIds: z$1.array(z$1.string()).optional()
|
|
16648
16992
|
});
|
|
16649
16993
|
/**
|
|
16650
16994
|
* Response shapes for the public image endpoints (`generateImage` / `editImage`,
|
|
@@ -17311,7 +17655,7 @@ defineEndpoint({
|
|
|
17311
17655
|
path: "/api/ai/v1/completions",
|
|
17312
17656
|
operationId: "createCompletion",
|
|
17313
17657
|
summary: "Create a chat completion",
|
|
17314
|
-
description: "OpenAI-compatible completion. A successful request is ALWAYS answered with an SSE stream (`text/event-stream`), regardless of the `stream` flag: a `meta` event, then `content`/`tool_use` events carrying `usage`/`credits`, terminated by `data: [DONE]`. The terminal event carries `stopReason`; treat `max_tokens` as a TRUNCATED reply rather than a complete one, and note that omitting `max_tokens` on the request lets the server size the output ceiling for the model (recommended for reasoning models, which spend thinking tokens inside that ceiling). A message `content` may be a string or an array of parts; image parts are accepted in OpenAI Chat (`image_url`), OpenAI Responses (`input_image`) or Anthropic (`image` with a `source`) form and are translated to whatever the target model speaks. Authenticate with an API key (`b4m_live_`) or a JWT.\n\nERRORS. Everything checked before the model provider is called fails with a JSON error body and a real HTTP status, before any stream opens: a malformed or otherwise invalid request or an unknown `model` `400` (`errorCode: \"unknown_model\"` for the latter), a bad credential `401`, a key without a required scope `403` (with `required_scopes`), a body over 25 MB `413`, a body that fails schema validation `422`, insufficient credits `422` with `errorCode: \"insufficient_credits\"` (personal or org balance, or an org per-member credit cap), a rate limit `429` with `Retry-After`, and a catalogued model whose provider is not configured on this deployment `503` with `errorCode: \"provider_not_configured\"` (retryable). Once the stream has opened the status stays `200` and a failure arrives as one terminal in-band `error` event. Branch on that event's `code`, never on `message`, which is prose and may change: `insufficient_credits` (buy credits) when credits run out mid-generation, `provider_rejected` when the model provider refused our credentials, `content_blocked` when the model declined the request (do not retry it unchanged), and `provider_error` for any other provider failure. Treat `code` as optional.",
|
|
17658
|
+
description: "OpenAI-compatible completion. A successful request is ALWAYS answered with an SSE stream (`text/event-stream`), regardless of the `stream` flag: a `meta` event, then `content`/`tool_use` events carrying `usage`/`credits`, terminated by `data: [DONE]`. The terminal event carries `stopReason`; treat `max_tokens` as a TRUNCATED reply rather than a complete one, and note that omitting `max_tokens` on the request lets the server size the output ceiling for the model (recommended for reasoning models, which spend thinking tokens inside that ceiling). A message `content` may be a string or an array of parts; image parts are accepted in OpenAI Chat (`image_url`), OpenAI Responses (`input_image`) or Anthropic (`image` with a `source`) form and are translated to whatever the target model speaks. Authenticate with an API key (`b4m_live_`) or a JWT.\n\nTOOL SEARCH. On a model whose `GET /api/v1/models` row has `supports_tool_search: true` and `backend: \"anthropic\"`, a `tools` entry may set `toolSchema.defer_loading: true`, and a `{ \"serverTool\": { \"type\": \"tool_search_tool_regex_20251119\", \"name\": \"tool_search_tool_regex\" } }` (or the `bm25` pair) entry adds Anthropic's tool search, so deferred definitions load only when the model searches for them. The stream then carries `provider_block` events (`{ type, provider: \"anthropic\", block }`) for the server-run search; echo each block back verbatim, in order, in the assistant `messages` content of the next request, and never answer one with a `tool_result`. When the server-run search loop hits its iteration limit the stream ends with `stopReason: \"pause_turn\"`; continue by re-sending the conversation with that assistant turn's provider blocks echoed. A client-side search may return `{ \"type\": \"tool_reference\", \"tool_name\": \"...\" }` blocks inside a `tool_result`'s content. On every other model, Bedrock-served Claude included, `defer_loading` is ignored (every tool is sent as usual) and a server tool, a `tool_reference` or an echoed tool search block is refused with a `400` rather than run without it.\n\nERRORS. Everything checked before the model provider is called fails with a JSON error body and a real HTTP status, before any stream opens: a malformed or otherwise invalid request or an unknown `model` `400` (`errorCode: \"unknown_model\"` for the latter), a bad credential `401`, a key without a required scope `403` (with `required_scopes`), a body over 25 MB `413`, a body that fails schema validation `422`, insufficient credits `422` with `errorCode: \"insufficient_credits\"` (personal or org balance, or an org per-member credit cap), a rate limit `429` with `Retry-After`, and a catalogued model whose provider is not configured on this deployment `503` with `errorCode: \"provider_not_configured\"` (retryable). Once the stream has opened the status stays `200` and a failure arrives as one terminal in-band `error` event. Branch on that event's `code`, never on `message`, which is prose and may change: `insufficient_credits` (buy credits) when credits run out mid-generation, `provider_rejected` when the model provider refused our credentials, `content_blocked` when the model declined the request (do not retry it unchanged), and `provider_error` for any other provider failure. Treat `code` as optional.",
|
|
17315
17659
|
tags: ["AI"],
|
|
17316
17660
|
auth: "apiKeyOrJwt",
|
|
17317
17661
|
scopes: ["ai:chat", "ai:generate"],
|
|
@@ -17345,8 +17689,8 @@ defineEndpoint({
|
|
|
17345
17689
|
}
|
|
17346
17690
|
},
|
|
17347
17691
|
400: {
|
|
17348
|
-
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`.",
|
|
17349
|
-
schema:
|
|
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`).",
|
|
17693
|
+
schema: CompletionsBadRequestErrorSchema
|
|
17350
17694
|
},
|
|
17351
17695
|
413: {
|
|
17352
17696
|
description: "Request body over 25 MB.",
|
|
@@ -17442,7 +17786,7 @@ defineEndpoint({
|
|
|
17442
17786
|
path: "/api/ai/tts",
|
|
17443
17787
|
operationId: "synthesizeSpeech",
|
|
17444
17788
|
summary: "Synthesize speech from text",
|
|
17445
|
-
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,
|
|
17446
17790
|
tags: ["Audio"],
|
|
17447
17791
|
auth: "apiKeyOrJwt",
|
|
17448
17792
|
scopes: ["ai:generate"],
|
|
@@ -17485,6 +17829,18 @@ defineEndpoint({
|
|
|
17485
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`).",
|
|
17486
17830
|
schema: ttsErrorResponseSchema
|
|
17487
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
|
+
},
|
|
17488
17844
|
422: {
|
|
17489
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.",
|
|
17490
17846
|
schema: ttsErrorResponseSchema
|
|
@@ -17578,7 +17934,7 @@ defineEndpoint({
|
|
|
17578
17934
|
path: "/api/ai/sound-effects",
|
|
17579
17935
|
operationId: "generateSoundEffect",
|
|
17580
17936
|
summary: "Generate a sound effect",
|
|
17581
|
-
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,
|
|
17582
17938
|
tags: ["Audio"],
|
|
17583
17939
|
auth: "apiKeyOrJwt",
|
|
17584
17940
|
scopes: ["ai:generate"],
|
|
@@ -17604,7 +17960,15 @@ defineEndpoint({
|
|
|
17604
17960
|
tooLargeSchema: generatedAudioTooLargeSchema
|
|
17605
17961
|
}),
|
|
17606
17962
|
400: {
|
|
17607
|
-
description:
|
|
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`.",
|
|
17608
17972
|
schema: ApiErrorSchema
|
|
17609
17973
|
},
|
|
17610
17974
|
422: {
|
|
@@ -17745,9 +18109,9 @@ defineEndpoint({
|
|
|
17745
18109
|
replaced_by: null,
|
|
17746
18110
|
image: null,
|
|
17747
18111
|
credits_per_1m_tokens: {
|
|
17748
|
-
input:
|
|
17749
|
-
output:
|
|
17750
|
-
cached_input:
|
|
18112
|
+
input: 4e3,
|
|
18113
|
+
output: 2e4,
|
|
18114
|
+
cached_input: 400
|
|
17751
18115
|
}
|
|
17752
18116
|
}, {
|
|
17753
18117
|
id: "gpt-image-1",
|
|
@@ -17829,7 +18193,7 @@ defineEndpoint({
|
|
|
17829
18193
|
path: "/api/v1/image-generations",
|
|
17830
18194
|
operationId: "generateImage",
|
|
17831
18195
|
summary: "Generate an image",
|
|
17832
|
-
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,
|
|
17833
18197
|
tags: ["Images"],
|
|
17834
18198
|
auth: "apiKeyOrJwt",
|
|
17835
18199
|
scopes: ["ai:generate"],
|
|
@@ -17856,6 +18220,10 @@ defineEndpoint({
|
|
|
17856
18220
|
404: {
|
|
17857
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.",
|
|
17858
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
|
|
17859
18227
|
}
|
|
17860
18228
|
},
|
|
17861
18229
|
emitsRateLimitHeaders: true,
|
|
@@ -17874,7 +18242,7 @@ defineEndpoint({
|
|
|
17874
18242
|
path: "/api/v1/image-edits",
|
|
17875
18243
|
operationId: "editImage",
|
|
17876
18244
|
summary: "Edit an image",
|
|
17877
|
-
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,
|
|
17878
18246
|
tags: ["Images"],
|
|
17879
18247
|
auth: "apiKeyOrJwt",
|
|
17880
18248
|
scopes: ["ai:generate"],
|
|
@@ -17903,6 +18271,10 @@ defineEndpoint({
|
|
|
17903
18271
|
404: {
|
|
17904
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.",
|
|
17905
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
|
|
17906
18278
|
}
|
|
17907
18279
|
},
|
|
17908
18280
|
emitsRateLimitHeaders: true,
|
|
@@ -17934,7 +18306,7 @@ defineEndpoint({
|
|
|
17934
18306
|
path: "/api/v1/files",
|
|
17935
18307
|
operationId: "createFileUpload",
|
|
17936
18308
|
summary: "Start a file upload",
|
|
17937
|
-
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.",
|
|
17938
18310
|
tags: ["Files"],
|
|
17939
18311
|
auth: "apiKeyOrJwt",
|
|
17940
18312
|
scopes: ["files:write"],
|
|
@@ -21088,6 +21460,11 @@ const INCIDENT_REVIEW_STATUSES = [
|
|
|
21088
21460
|
"reported"
|
|
21089
21461
|
];
|
|
21090
21462
|
const INCIDENT_REPORT_CHANNELS = ["manual"];
|
|
21463
|
+
const INCIDENT_SURFACES = [
|
|
21464
|
+
"generation",
|
|
21465
|
+
"edit",
|
|
21466
|
+
"upload"
|
|
21467
|
+
];
|
|
21091
21468
|
const ModerationLabelHitSchema = z$1.object({
|
|
21092
21469
|
name: z$1.string(),
|
|
21093
21470
|
parentName: z$1.string(),
|
|
@@ -21101,6 +21478,7 @@ z$1.object({
|
|
|
21101
21478
|
fabFileId: z$1.string().optional(),
|
|
21102
21479
|
provider: z$1.string(),
|
|
21103
21480
|
model: z$1.string(),
|
|
21481
|
+
surface: z$1.enum(INCIDENT_SURFACES).optional(),
|
|
21104
21482
|
labels: z$1.array(ModerationLabelHitSchema),
|
|
21105
21483
|
reviewStatus: z$1.enum(INCIDENT_REVIEW_STATUSES).optional(),
|
|
21106
21484
|
ncmecReportId: z$1.string().optional(),
|
|
@@ -21110,9 +21488,11 @@ z$1.object({
|
|
|
21110
21488
|
previousReviewStatus: z$1.literal("false_positive").optional(),
|
|
21111
21489
|
falsePositiveBy: z$1.string().optional(),
|
|
21112
21490
|
falsePositiveAt: z$1.union([z$1.string(), z$1.date()]).optional(),
|
|
21491
|
+
alertedAt: z$1.union([z$1.string(), z$1.date()]).optional(),
|
|
21113
21492
|
createdAt: z$1.union([z$1.string(), z$1.date()]).optional(),
|
|
21114
21493
|
updatedAt: z$1.union([z$1.string(), z$1.date()]).optional()
|
|
21115
21494
|
});
|
|
21495
|
+
z$1.string().email();
|
|
21116
21496
|
new RegExp(`[аеорсхуіјѕԁһӏαονικρτυ]`, "g");
|
|
21117
21497
|
const OPENER_STICKY = /<artifact/iy;
|
|
21118
21498
|
const WHITESPACE$1 = /\s/;
|
|
@@ -21178,7 +21558,7 @@ function scanArtifactOpenTag(text, at, leading, memo) {
|
|
|
21178
21558
|
end: close + 1
|
|
21179
21559
|
};
|
|
21180
21560
|
}
|
|
21181
|
-
const OPENER = /<artifact(?=\s)/gi;
|
|
21561
|
+
const OPENER$1 = /<artifact(?=\s)/gi;
|
|
21182
21562
|
const LEADING_WS = /\s+/y;
|
|
21183
21563
|
const CLOSER = /<\/artifact>/gi;
|
|
21184
21564
|
const GT = />/g;
|
|
@@ -21193,9 +21573,9 @@ function scanArtifactTags(text, attrsMayCrossLines) {
|
|
|
21193
21573
|
const stop = attrsMayCrossLines ? GT : GT_OR_LINE_TERMINATOR;
|
|
21194
21574
|
const out = [];
|
|
21195
21575
|
let termAt = -1;
|
|
21196
|
-
OPENER.lastIndex = 0;
|
|
21576
|
+
OPENER$1.lastIndex = 0;
|
|
21197
21577
|
let opener;
|
|
21198
|
-
while ((opener = OPENER.exec(text)) !== null) {
|
|
21578
|
+
while ((opener = OPENER$1.exec(text)) !== null) {
|
|
21199
21579
|
LEADING_WS.lastIndex = opener.index + opener[0].length;
|
|
21200
21580
|
LEADING_WS.exec(text);
|
|
21201
21581
|
const attrsStart = LEADING_WS.lastIndex;
|
|
@@ -21215,7 +21595,7 @@ function scanArtifactTags(text, attrsMayCrossLines) {
|
|
|
21215
21595
|
attrs: text.slice(attrsStart, termAt),
|
|
21216
21596
|
body: text.slice(termAt + 1, closer.index)
|
|
21217
21597
|
});
|
|
21218
|
-
OPENER.lastIndex = end;
|
|
21598
|
+
OPENER$1.lastIndex = end;
|
|
21219
21599
|
}
|
|
21220
21600
|
return out;
|
|
21221
21601
|
}
|
|
@@ -23793,111 +24173,283 @@ function getEnvironmentName(configApiConfig) {
|
|
|
23793
24173
|
return "Self-Hosted";
|
|
23794
24174
|
}
|
|
23795
24175
|
//#endregion
|
|
23796
|
-
//#region src/
|
|
24176
|
+
//#region src/tools/gateway/coreToolDescriptors.ts
|
|
24177
|
+
const CORE = { kind: "core" };
|
|
24178
|
+
const CLI = { kind: "cli" };
|
|
24179
|
+
const pureCompute = () => ({
|
|
24180
|
+
source: CORE,
|
|
24181
|
+
effect: "none",
|
|
24182
|
+
approval: "auto_approve"
|
|
24183
|
+
});
|
|
24184
|
+
const sessionTool = () => ({
|
|
24185
|
+
source: CLI,
|
|
24186
|
+
effect: "session",
|
|
24187
|
+
approval: "auto_approve"
|
|
24188
|
+
});
|
|
24189
|
+
const reader = (source = CORE, extra = {}) => ({
|
|
24190
|
+
source,
|
|
24191
|
+
effect: "read",
|
|
24192
|
+
approval: "prompt_default",
|
|
24193
|
+
...extra
|
|
24194
|
+
});
|
|
24195
|
+
const fileWriter = () => ({
|
|
24196
|
+
source: CORE,
|
|
24197
|
+
effect: "write",
|
|
24198
|
+
approval: "prompt_always",
|
|
24199
|
+
writePathArg: "path"
|
|
24200
|
+
});
|
|
24201
|
+
const lattice = () => ({
|
|
24202
|
+
source: CORE,
|
|
24203
|
+
effect: "none",
|
|
24204
|
+
approval: "prompt_default"
|
|
24205
|
+
});
|
|
24206
|
+
/**
|
|
24207
|
+
* Descriptors for every tool the CLI builds itself or gets from @bike4mind/services:
|
|
24208
|
+
* generateCliTools, buildCliToolList and the subagent-injected tools. A tool missing here
|
|
24209
|
+
* resolves to the unknown fallback in toolCatalog.ts; coreToolCompleteness.test.ts
|
|
24210
|
+
* fails when a generated tool has no entry.
|
|
24211
|
+
*/
|
|
24212
|
+
const CORE_TOOL_DESCRIPTORS = new Map(Object.entries({
|
|
24213
|
+
math_evaluate: pureCompute(),
|
|
24214
|
+
current_datetime: pureCompute(),
|
|
24215
|
+
dice_roll: pureCompute(),
|
|
24216
|
+
prompt_enhancement: pureCompute(),
|
|
24217
|
+
find_definition: {
|
|
24218
|
+
source: CLI,
|
|
24219
|
+
effect: "read",
|
|
24220
|
+
approval: "auto_approve"
|
|
24221
|
+
},
|
|
24222
|
+
ask_user_question: {
|
|
24223
|
+
source: CORE,
|
|
24224
|
+
effect: "session",
|
|
24225
|
+
approval: "auto_approve"
|
|
24226
|
+
},
|
|
24227
|
+
agent_delegate: sessionTool(),
|
|
24228
|
+
check_agent_status: sessionTool(),
|
|
24229
|
+
list_background_agents: sessionTool(),
|
|
24230
|
+
cancel_background_agent: sessionTool(),
|
|
24231
|
+
resume_agent: sessionTool(),
|
|
24232
|
+
create_dynamic_agent: sessionTool(),
|
|
24233
|
+
coordinate_task: sessionTool(),
|
|
24234
|
+
decompose_task: sessionTool(),
|
|
24235
|
+
shared_context_read: sessionTool(),
|
|
24236
|
+
shared_context_write: sessionTool(),
|
|
24237
|
+
write_todos: sessionTool(),
|
|
24238
|
+
read_prior_todos: sessionTool(),
|
|
24239
|
+
log_decision: sessionTool(),
|
|
24240
|
+
track_blocker: sessionTool(),
|
|
24241
|
+
resolve_blocker: sessionTool(),
|
|
24242
|
+
request_review_gate: sessionTool(),
|
|
24243
|
+
work_item_create: sessionTool(),
|
|
24244
|
+
work_item_update: sessionTool(),
|
|
24245
|
+
work_item_close: sessionTool(),
|
|
24246
|
+
work_item_ready: sessionTool(),
|
|
24247
|
+
work_item_graph: sessionTool(),
|
|
24248
|
+
tool_search: sessionTool(),
|
|
24249
|
+
create_file: fileWriter(),
|
|
24250
|
+
edit_local_file: fileWriter(),
|
|
24251
|
+
delete_file: fileWriter(),
|
|
24252
|
+
edit_file: {
|
|
24253
|
+
source: CORE,
|
|
24254
|
+
effect: "write",
|
|
24255
|
+
approval: "prompt_always"
|
|
24256
|
+
},
|
|
24257
|
+
bash_execute: {
|
|
24258
|
+
source: CORE,
|
|
24259
|
+
effect: "execute",
|
|
24260
|
+
approval: "prompt_always",
|
|
24261
|
+
openWorld: true,
|
|
24262
|
+
commandArg: "command",
|
|
24263
|
+
sandbox: "command"
|
|
24264
|
+
},
|
|
24265
|
+
shell_execute: {
|
|
24266
|
+
source: CORE,
|
|
24267
|
+
effect: "execute",
|
|
24268
|
+
approval: "prompt_always",
|
|
24269
|
+
openWorld: true
|
|
24270
|
+
},
|
|
24271
|
+
write_shell_stdin: {
|
|
24272
|
+
source: CORE,
|
|
24273
|
+
effect: "execute",
|
|
24274
|
+
approval: "prompt_always",
|
|
24275
|
+
commandArg: "chars"
|
|
24276
|
+
},
|
|
24277
|
+
kill_background_shell: {
|
|
24278
|
+
source: CORE,
|
|
24279
|
+
effect: "execute",
|
|
24280
|
+
approval: "prompt_always"
|
|
24281
|
+
},
|
|
24282
|
+
git_commit: {
|
|
24283
|
+
source: CORE,
|
|
24284
|
+
effect: "write",
|
|
24285
|
+
approval: "prompt_always"
|
|
24286
|
+
},
|
|
24287
|
+
git_push: {
|
|
24288
|
+
source: CORE,
|
|
24289
|
+
effect: "write",
|
|
24290
|
+
approval: "prompt_always",
|
|
24291
|
+
openWorld: true
|
|
24292
|
+
},
|
|
24293
|
+
skill: {
|
|
24294
|
+
source: CLI,
|
|
24295
|
+
effect: "execute",
|
|
24296
|
+
approval: "prompt_always"
|
|
24297
|
+
},
|
|
24298
|
+
weather_info: reader(CORE, { openWorld: true }),
|
|
24299
|
+
web_search: reader(CORE, { openWorld: true }),
|
|
24300
|
+
web_fetch: reader(CORE, { openWorld: true }),
|
|
24301
|
+
deep_research: reader(CORE, { openWorld: true }),
|
|
24302
|
+
check_shell_output: reader(),
|
|
24303
|
+
list_background_shells: reader(),
|
|
24304
|
+
file_read: reader(),
|
|
24305
|
+
grep_search: reader(),
|
|
24306
|
+
glob_files: reader(),
|
|
24307
|
+
get_file_tree: reader(),
|
|
24308
|
+
get_file_structure: reader(CLI),
|
|
24309
|
+
recent_changes: reader(),
|
|
24310
|
+
git_status: reader(),
|
|
24311
|
+
git_diff: reader(),
|
|
24312
|
+
git_log: reader(),
|
|
24313
|
+
git_branch: reader(),
|
|
24314
|
+
lattice_create_model: lattice(),
|
|
24315
|
+
lattice_add_entity: lattice(),
|
|
24316
|
+
lattice_set_value: lattice(),
|
|
24317
|
+
lattice_create_rule: lattice(),
|
|
24318
|
+
lattice_query: lattice(),
|
|
24319
|
+
lattice_explain: lattice()
|
|
24320
|
+
}));
|
|
24321
|
+
//#endregion
|
|
24322
|
+
//#region src/tools/gateway/toolPolicy.ts
|
|
23797
24323
|
/**
|
|
23798
|
-
*
|
|
24324
|
+
* Every policy decision about a tool, derived from its descriptor. `undefined` is a tool the
|
|
24325
|
+
* catalog could not resolve; it keeps the pre-descriptor fallback (prompt_default, read-only)
|
|
24326
|
+
* because feature-module and plugin tools do not register descriptors yet.
|
|
23799
24327
|
*/
|
|
23800
|
-
const
|
|
23801
|
-
|
|
23802
|
-
"
|
|
23803
|
-
"
|
|
24328
|
+
const UNKNOWN_TOOL_CATEGORY = "prompt_default";
|
|
24329
|
+
const READ_ONLY_EFFECTS = /* @__PURE__ */ new Set([
|
|
24330
|
+
"none",
|
|
24331
|
+
"session",
|
|
24332
|
+
"read"
|
|
23804
24333
|
]);
|
|
23805
|
-
z$1.object({
|
|
23806
|
-
categories: z$1.record(z$1.string(), ToolCategorySchema),
|
|
23807
|
-
trustedTools: z$1.array(z$1.string())
|
|
23808
|
-
});
|
|
23809
24334
|
/**
|
|
23810
|
-
*
|
|
23811
|
-
*
|
|
23812
|
-
*
|
|
23813
|
-
*
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
23817
|
-
|
|
23818
|
-
|
|
23819
|
-
|
|
23820
|
-
|
|
23821
|
-
|
|
23822
|
-
|
|
23823
|
-
|
|
23824
|
-
|
|
23825
|
-
|
|
23826
|
-
|
|
23827
|
-
|
|
23828
|
-
|
|
23829
|
-
|
|
23830
|
-
|
|
23831
|
-
|
|
23832
|
-
|
|
23833
|
-
|
|
23834
|
-
|
|
23835
|
-
|
|
23836
|
-
|
|
23837
|
-
|
|
23838
|
-
|
|
23839
|
-
|
|
23840
|
-
|
|
23841
|
-
|
|
23842
|
-
|
|
23843
|
-
|
|
23844
|
-
|
|
23845
|
-
|
|
23846
|
-
|
|
23847
|
-
edit_file: "prompt_always",
|
|
23848
|
-
edit_local_file: "prompt_always",
|
|
23849
|
-
create_file: "prompt_always",
|
|
23850
|
-
delete_file: "prompt_always",
|
|
23851
|
-
shell_execute: "prompt_always",
|
|
23852
|
-
bash_execute: "prompt_always",
|
|
23853
|
-
write_shell_stdin: "prompt_always",
|
|
23854
|
-
kill_background_shell: "prompt_always",
|
|
23855
|
-
git_commit: "prompt_always",
|
|
23856
|
-
git_push: "prompt_always",
|
|
23857
|
-
skill: "prompt_always",
|
|
23858
|
-
web_search: "prompt_default",
|
|
23859
|
-
check_shell_output: "prompt_default",
|
|
23860
|
-
list_background_shells: "prompt_default",
|
|
23861
|
-
web_fetch: "prompt_default",
|
|
23862
|
-
deep_research: "prompt_default",
|
|
23863
|
-
file_read: "prompt_default",
|
|
23864
|
-
grep_search: "prompt_default",
|
|
23865
|
-
glob_files: "prompt_default",
|
|
23866
|
-
get_file_tree: "prompt_default",
|
|
23867
|
-
get_file_structure: "prompt_default",
|
|
23868
|
-
git_status: "prompt_default",
|
|
23869
|
-
git_diff: "prompt_default",
|
|
23870
|
-
git_log: "prompt_default",
|
|
23871
|
-
git_branch: "prompt_default"
|
|
23872
|
-
};
|
|
24335
|
+
* How far a source's own declarations are believed. Core, cli and builtin-module tools ship in
|
|
24336
|
+
* this repo and are reviewed, so their descriptor is taken as written. A plugin is third-party
|
|
24337
|
+
* code the user installed and enabled: it can be trusted per tool after a prompt, but cannot
|
|
24338
|
+
* skip the first prompt or claim to be read-only. MCP tools and lifecycle hooks always prompt.
|
|
24339
|
+
*/
|
|
24340
|
+
function categoryCeiling(source) {
|
|
24341
|
+
switch (source.kind) {
|
|
24342
|
+
case "mcp":
|
|
24343
|
+
case "hook": return "prompt_always";
|
|
24344
|
+
case "plugin": return "prompt_default";
|
|
24345
|
+
default: return;
|
|
24346
|
+
}
|
|
24347
|
+
}
|
|
24348
|
+
function believesDeclaredEffect(source) {
|
|
24349
|
+
return categoryCeiling(source) === void 0;
|
|
24350
|
+
}
|
|
24351
|
+
function toolCategory(descriptor) {
|
|
24352
|
+
if (!descriptor) return UNKNOWN_TOOL_CATEGORY;
|
|
24353
|
+
const ceiling = categoryCeiling(descriptor.source);
|
|
24354
|
+
if (ceiling === "prompt_always") return ceiling;
|
|
24355
|
+
if (ceiling === "prompt_default" && descriptor.approval === "auto_approve") return ceiling;
|
|
24356
|
+
return descriptor.approval;
|
|
24357
|
+
}
|
|
24358
|
+
/** Whether a prompt_default trust decision can be persisted for the tool. */
|
|
24359
|
+
function canTrustTool(descriptor) {
|
|
24360
|
+
return toolCategory(descriptor) !== "prompt_always";
|
|
24361
|
+
}
|
|
24362
|
+
/** Read-only tools run in plan mode and in parallel batches; the rest are blocked / sequential. */
|
|
24363
|
+
function isReadOnlyTool(descriptor) {
|
|
24364
|
+
if (!descriptor) return true;
|
|
24365
|
+
if (!believesDeclaredEffect(descriptor.source)) return false;
|
|
24366
|
+
return READ_ONLY_EFFECTS.has(descriptor.effect);
|
|
24367
|
+
}
|
|
24368
|
+
/** The shell command text the risk gate classifies, when the tool has one in `args`. */
|
|
24369
|
+
function commandTextOf(descriptor, args) {
|
|
24370
|
+
return stringArg(args, descriptor?.commandArg);
|
|
24371
|
+
}
|
|
23873
24372
|
/**
|
|
23874
|
-
*
|
|
23875
|
-
*
|
|
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.
|
|
23876
24376
|
*/
|
|
23877
|
-
function
|
|
23878
|
-
if (
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
|
|
23882
|
-
|
|
24377
|
+
function sandboxedCommandArg(descriptor) {
|
|
24378
|
+
if (descriptor?.sandbox !== "command" || descriptor.source.kind !== "core") return void 0;
|
|
24379
|
+
return descriptor.commandArg;
|
|
24380
|
+
}
|
|
24381
|
+
/** The path a file-writing tool will write, when the tool declares one and `args` carries it. */
|
|
24382
|
+
function writePathOf(descriptor, args) {
|
|
24383
|
+
const writePath = stringArg(args, descriptor?.writePathArg);
|
|
24384
|
+
return writePath ? writePath : void 0;
|
|
24385
|
+
}
|
|
24386
|
+
function stringArg(args, field) {
|
|
24387
|
+
if (!field || args === null || typeof args !== "object") return void 0;
|
|
24388
|
+
const value = args[field];
|
|
24389
|
+
return typeof value === "string" ? value : void 0;
|
|
24390
|
+
}
|
|
24391
|
+
//#endregion
|
|
24392
|
+
//#region src/tools/gateway/toolCatalog.ts
|
|
24393
|
+
const MCP_PREFIX = "mcp__";
|
|
24394
|
+
const HOOK_PREFIXES = ["agent_hook:", "skill_hook:"];
|
|
24395
|
+
function isHookName(toolName) {
|
|
24396
|
+
return HOOK_PREFIXES.some((prefix) => toolName.startsWith(prefix));
|
|
23883
24397
|
}
|
|
23884
24398
|
/**
|
|
23885
|
-
*
|
|
23886
|
-
|
|
23887
|
-
|
|
23888
|
-
|
|
24399
|
+
* Resolve a tool name without a catalog instance: the core table, then the MCP namespace
|
|
24400
|
+
* (`mcp__<server>__<tool>`), then the lifecycle-hook namespaces. Undefined means unknown.
|
|
24401
|
+
* ToolCatalog.resolve falls back to this after its registered descriptors.
|
|
24402
|
+
*/
|
|
24403
|
+
function resolveStaticToolDescriptor(toolName) {
|
|
24404
|
+
const core = CORE_TOOL_DESCRIPTORS.get(toolName);
|
|
24405
|
+
if (core) return core;
|
|
24406
|
+
if (toolName.startsWith(MCP_PREFIX)) return {
|
|
24407
|
+
source: {
|
|
24408
|
+
kind: "mcp",
|
|
24409
|
+
server: toolName.slice(5).split("__")[0]
|
|
24410
|
+
},
|
|
24411
|
+
effect: "execute",
|
|
24412
|
+
approval: "prompt_always"
|
|
24413
|
+
};
|
|
24414
|
+
if (isHookName(toolName)) return {
|
|
24415
|
+
source: { kind: "hook" },
|
|
24416
|
+
effect: "execute",
|
|
24417
|
+
approval: "prompt_always"
|
|
24418
|
+
};
|
|
23889
24419
|
}
|
|
23890
24420
|
/**
|
|
23891
|
-
*
|
|
23892
|
-
*
|
|
23893
|
-
*
|
|
23894
|
-
* @param toolName - Name of the tool to check
|
|
23895
|
-
* @param customCategories - Optional custom category overrides
|
|
23896
|
-
* @returns true if the tool is read-only, false if it's a write tool
|
|
24421
|
+
* Name -> descriptor lookup for one CLI process or ACP stack. Entry points create one and hand
|
|
24422
|
+
* it to their PermissionManager, which the permission gateway and the agent's read-only
|
|
24423
|
+
* predicate read it through.
|
|
23897
24424
|
*/
|
|
23898
|
-
|
|
23899
|
-
|
|
23900
|
-
|
|
24425
|
+
var ToolCatalog = class {
|
|
24426
|
+
constructor() {
|
|
24427
|
+
this.registered = /* @__PURE__ */ new Map();
|
|
24428
|
+
}
|
|
24429
|
+
/**
|
|
24430
|
+
* Add a descriptor for a tool the core table does not know. Core names and the MCP and hook
|
|
24431
|
+
* namespaces are reserved: nothing can re-declare a core tool, or declare itself into a
|
|
24432
|
+
* namespace whose descriptor comes from the name alone, with a lower tier.
|
|
24433
|
+
*/
|
|
24434
|
+
register(toolName, descriptor) {
|
|
24435
|
+
if (toolName.startsWith(MCP_PREFIX) || isHookName(toolName)) throw new Error(`Tool name "${toolName}" is in a reserved namespace and cannot be registered`);
|
|
24436
|
+
if (CORE_TOOL_DESCRIPTORS.has(toolName)) throw new Error(`Tool "${toolName}" is a core tool and already has a descriptor`);
|
|
24437
|
+
if (this.registered.has(toolName)) throw new Error(`Tool "${toolName}" already has a registered descriptor`);
|
|
24438
|
+
this.registered.set(toolName, descriptor);
|
|
24439
|
+
}
|
|
24440
|
+
resolve(toolName) {
|
|
24441
|
+
return this.registered.get(toolName) ?? resolveStaticToolDescriptor(toolName);
|
|
24442
|
+
}
|
|
24443
|
+
category(toolName) {
|
|
24444
|
+
return toolCategory(this.resolve(toolName));
|
|
24445
|
+
}
|
|
24446
|
+
canTrust(toolName) {
|
|
24447
|
+
return canTrustTool(this.resolve(toolName));
|
|
24448
|
+
}
|
|
24449
|
+
isReadOnly(toolName) {
|
|
24450
|
+
return isReadOnlyTool(this.resolve(toolName));
|
|
24451
|
+
}
|
|
24452
|
+
};
|
|
23901
24453
|
const PROJECT_CONTEXT_FILES = [
|
|
23902
24454
|
"CLAUDE.local.md",
|
|
23903
24455
|
"CLAUDE.md",
|
|
@@ -24638,7 +25190,7 @@ function mergeConfigs(global, project, local) {
|
|
|
24638
25190
|
enabled: merged.tools.enabled.filter((t) => !disabledSet.has(t))
|
|
24639
25191
|
};
|
|
24640
25192
|
const globalTrusted = new Set(global.trustedTools || []);
|
|
24641
|
-
merged.trustedTools = (merged.trustedTools || []).filter((t) => globalTrusted.has(t) || canTrustTool(t) && !disabledSet.has(t));
|
|
25193
|
+
merged.trustedTools = (merged.trustedTools || []).filter((t) => globalTrusted.has(t) || canTrustTool(resolveStaticToolDescriptor(t)) && !disabledSet.has(t));
|
|
24642
25194
|
return merged;
|
|
24643
25195
|
}
|
|
24644
25196
|
/**
|
|
@@ -25315,4 +25867,4 @@ var ConfigStore = class {
|
|
|
25315
25867
|
}
|
|
25316
25868
|
};
|
|
25317
25869
|
//#endregion
|
|
25318
|
-
export {
|
|
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 };
|