atlarix 15.9.0 → 15.9.1

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.
@@ -11697,7 +11697,8 @@ var init_compass_product_copy = __esm({
11697
11697
  { id: "core-1", label: "Core 1", description: "" },
11698
11698
  { id: "core-2", label: "Core 2", description: "" },
11699
11699
  { id: "core-3", label: "Core 3", description: "" },
11700
- { id: "core-4", label: "Core 4", description: "" }
11700
+ { id: "core-4", label: "Core 4", description: "" },
11701
+ { id: "core-5", label: "Core 5", description: "" }
11701
11702
  ];
11702
11703
  }
11703
11704
  });
@@ -11843,6 +11844,7 @@ __export(compass_constants_exports, {
11843
11844
  CORE_TIER_2: () => CORE_TIER_2,
11844
11845
  CORE_TIER_3: () => CORE_TIER_3,
11845
11846
  CORE_TIER_4: () => CORE_TIER_4,
11847
+ CORE_TIER_5: () => CORE_TIER_5,
11846
11848
  CORE_TIER_AUTO: () => CORE_TIER_AUTO,
11847
11849
  CORE_TIER_ORDER: () => CORE_TIER_ORDER,
11848
11850
  DEFAULT_NEW_USER_CORE_TIER: () => DEFAULT_NEW_USER_CORE_TIER,
@@ -11864,6 +11866,7 @@ __export(compass_constants_exports, {
11864
11866
  getOpenRouterModelIdForCoreTier: () => getOpenRouterModelIdForCoreTier,
11865
11867
  isCompassBuildConfigured: () => isCompassBuildConfigured,
11866
11868
  isCoreAutoTier: () => isCoreAutoTier,
11869
+ isCoreTierFromNewerBuild: () => isCoreTierFromNewerBuild,
11867
11870
  isCoreTierId: () => isCoreTierId,
11868
11871
  normalizeCoreTierId: () => normalizeCoreTierId,
11869
11872
  resolveConfiguredCoreTier: () => resolveConfiguredCoreTier
@@ -11885,6 +11888,10 @@ function isCoreTierId(internalTierId) {
11885
11888
  const norm = normalizeCoreTierId(internalTierId);
11886
11889
  return CORE_TIER_ORDER.includes(norm) || norm === CORE_TIER_AUTO;
11887
11890
  }
11891
+ function isCoreTierFromNewerBuild(internalTierId) {
11892
+ const norm = normalizeCoreTierId(internalTierId);
11893
+ return /^core-\d+$/.test(norm) && !CORE_TIER_ORDER.includes(norm);
11894
+ }
11888
11895
  function isCoreAutoTier(internalTierId) {
11889
11896
  return !!internalTierId && normalizeCoreTierId(internalTierId) === CORE_TIER_AUTO;
11890
11897
  }
@@ -11962,6 +11969,8 @@ function getCoreModelIdForCoreTier(internalTierId) {
11962
11969
  return trimEnv(process.env.ATLARIX_CORE_MODEL_3);
11963
11970
  case CORE_TIER_4:
11964
11971
  return trimEnv(process.env.ATLARIX_CORE_MODEL_4);
11972
+ case CORE_TIER_5:
11973
+ return trimEnv(process.env.ATLARIX_CORE_MODEL_5);
11965
11974
  default:
11966
11975
  return void 0;
11967
11976
  }
@@ -11975,6 +11984,7 @@ function getFirstConfiguredCoreTier() {
11975
11984
  }
11976
11985
  function resolveConfiguredCoreTier(internalTierId) {
11977
11986
  const norm = normalizeCoreTierId(internalTierId);
11987
+ if (isCoreTierFromNewerBuild(norm)) return void 0;
11978
11988
  if (getCoreModelIdForCoreTier(norm)?.trim())
11979
11989
  return { tier: norm, substituted: false };
11980
11990
  if (norm === CORE_TIER_AUTO) return void 0;
@@ -12005,7 +12015,7 @@ function isCompassBuildConfigured() {
12005
12015
  function compassExhaustedUserMessage(_tier) {
12006
12016
  return coreExhaustedUserMessage();
12007
12017
  }
12008
- var COMPASS_PROVIDER_ID, CORE_TIER_1, CORE_TIER_2, CORE_TIER_3, CORE_TIER_4, CORE_TIER_AUTO, ATLARIX_AUTO_CONSENT_VERSION, CORE_TIER_ORDER, LEGACY_COMPASS_TIER_ALIASES, EMPTY_SLOT_SENTINELS, devCoreKeyProvider, getOpenRouterModelIdForCoreTier, DEFAULT_CORE_TIER_ORDER, DEFAULT_PAID_CORE_TIER, DEFAULT_NEW_USER_CORE_TIER;
12018
+ var COMPASS_PROVIDER_ID, CORE_TIER_1, CORE_TIER_2, CORE_TIER_3, CORE_TIER_4, CORE_TIER_5, CORE_TIER_AUTO, ATLARIX_AUTO_CONSENT_VERSION, CORE_TIER_ORDER, LEGACY_COMPASS_TIER_ALIASES, EMPTY_SLOT_SENTINELS, devCoreKeyProvider, getOpenRouterModelIdForCoreTier, DEFAULT_CORE_TIER_ORDER, DEFAULT_PAID_CORE_TIER, DEFAULT_NEW_USER_CORE_TIER;
12009
12019
  var init_compass_constants = __esm({
12010
12020
  "src/ipc/shared/compass_constants.ts"() {
12011
12021
  init_format_openrouter_model_label();
@@ -12019,13 +12029,15 @@ var init_compass_constants = __esm({
12019
12029
  CORE_TIER_2 = "core-2";
12020
12030
  CORE_TIER_3 = "core-3";
12021
12031
  CORE_TIER_4 = "core-4";
12032
+ CORE_TIER_5 = "core-5";
12022
12033
  CORE_TIER_AUTO = "core-auto";
12023
12034
  ATLARIX_AUTO_CONSENT_VERSION = 2;
12024
12035
  CORE_TIER_ORDER = [
12025
12036
  CORE_TIER_1,
12026
12037
  CORE_TIER_2,
12027
12038
  CORE_TIER_3,
12028
- CORE_TIER_4
12039
+ CORE_TIER_4,
12040
+ CORE_TIER_5
12029
12041
  ];
12030
12042
  LEGACY_COMPASS_TIER_ALIASES = {
12031
12043
  "compass-fast": CORE_TIER_1,
@@ -71783,11 +71795,13 @@ function detectReasoningCapability(modelApiId, builtinProviderId) {
71783
71795
  }
71784
71796
  const useOpenAiReasoningSummary = pid === "openai";
71785
71797
  const useAnthropicThinking = pid === "anthropic" && catalogSaysReasons(pid, id) === true;
71798
+ const anthropicAdaptive = useAnthropicThinking && rawEffortValues(reasoningProfileFor(pid, id)?.options ?? []).length > 0;
71786
71799
  return {
71787
71800
  useOpenRouterReasoning,
71788
71801
  useGoogleThoughts,
71789
71802
  useOpenAiReasoningSummary,
71790
- useAnthropicThinking
71803
+ useAnthropicThinking,
71804
+ anthropicAdaptive
71791
71805
  };
71792
71806
  }
71793
71807
  function effortChoicesForModel(model) {
@@ -71893,7 +71907,13 @@ function buildReasoningProviderOptions(cap, thinkingTier, effort = "medium", max
71893
71907
  reasoningEffort: exactEffort ?? effort
71894
71908
  };
71895
71909
  }
71896
- if (cap.useAnthropicThinking) {
71910
+ if (cap.useAnthropicThinking && cap.anthropicAdaptive) {
71911
+ const level = exactEffort?.toLowerCase();
71912
+ patch.anthropic = {
71913
+ thinking: { type: "adaptive", display: "summarized" },
71914
+ ...level && ANTHROPIC_EFFORTS.has(level) ? { effort: level } : {}
71915
+ };
71916
+ } else if (cap.useAnthropicThinking) {
71897
71917
  patch.anthropic = {
71898
71918
  thinking: {
71899
71919
  type: "enabled",
@@ -71903,7 +71923,7 @@ function buildReasoningProviderOptions(cap, thinkingTier, effort = "medium", max
71903
71923
  }
71904
71924
  return patch;
71905
71925
  }
71906
- var GEMINI_LEVELS;
71926
+ var GEMINI_LEVELS, ANTHROPIC_EFFORTS;
71907
71927
  var init_reasoning_detector = __esm({
71908
71928
  "src/lib/routing/reasoning-detector.ts"() {
71909
71929
  init_tier_context_limits();
@@ -71914,6 +71934,7 @@ var init_reasoning_detector = __esm({
71914
71934
  init_custom_provider_format();
71915
71935
  init_thinking_utils();
71916
71936
  GEMINI_LEVELS = /* @__PURE__ */ new Set(["minimal", "low", "medium", "high"]);
71937
+ ANTHROPIC_EFFORTS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
71917
71938
  }
71918
71939
  });
71919
71940
 
@@ -96004,8 +96025,9 @@ async function getMaxTokensWithFloor(model, opts) {
96004
96025
  return opts?.reasoningCapable ? MAX_OUTPUT_TOKENS_FLOOR_REASONING : MAX_OUTPUT_TOKENS_FLOOR;
96005
96026
  }
96006
96027
  async function getTemperature(model) {
96007
- const providerId = model.provider === "compass" ? getCoreModelsDevTargetForTier(model.name)?.providerId ?? model.provider : model.provider;
96008
- const modelId = model.provider === "compass" ? getCoreModelsDevTargetForTier(model.name)?.modelId ?? model.name : model.name;
96028
+ const anthropicFormat2 = isCustomAnthropicFormat(model.provider);
96029
+ const providerId = model.provider === "compass" ? getCoreModelsDevTargetForTier(model.name)?.providerId ?? model.provider : anthropicFormat2 ? "anthropic" : model.provider;
96030
+ const modelId = model.provider === "compass" ? getCoreModelsDevTargetForTier(model.name)?.modelId ?? model.name : anthropicFormat2 ? anthropicCatalogModelId(model.name ?? "") : model.name;
96009
96031
  const allowed = model.provider === "compass" ? catalogAllowsTemperature(providerId, modelId ?? "") : supportsTemperatureParam(providerId, modelId ?? "");
96010
96032
  if (!allowed) return void 0;
96011
96033
  const modelOption = await findLanguageModel(model);
@@ -96020,6 +96042,7 @@ var init_token_utils = __esm({
96020
96042
  init_compass_constants();
96021
96043
  init_models_dev();
96022
96044
  init_model_reasoning_profile();
96045
+ init_custom_provider_format();
96023
96046
  estimateTokens = (text3) => {
96024
96047
  return exactTokenCountText(text3);
96025
96048
  };
@@ -214708,6 +214731,61 @@ var init_analytics = __esm({
214708
214731
  }
214709
214732
  });
214710
214733
 
214734
+ // src/shared/texts.ts
214735
+ function providerSaid(reason) {
214736
+ const m3 = /"message"\s*:\s*"([^"]{1,300})"/.exec(reason);
214737
+ const text3 = (m3?.[1] ?? reason).replace(/\s+/g, " ").replace(/(\S{0,12}?)\*{4,}(\S{0,8})/g, (_m, head2, tail) => `${head2}\u2026${tail}`).trim();
214738
+ if (text3.length <= 200) return text3;
214739
+ const cut = text3.slice(0, 200);
214740
+ const sentence = cut.lastIndexOf(". ");
214741
+ if (sentence > 80) return cut.slice(0, sentence + 1);
214742
+ const word = cut.lastIndexOf(" ");
214743
+ return `${cut.slice(0, word > 80 ? word : 200)}\u2026`;
214744
+ }
214745
+ function byokLimitUserMessage(reason, providerId) {
214746
+ const who = providerId ? `Your ${providerId} account` : "Your provider account";
214747
+ const said = providerSaid(reason);
214748
+ if (CREDIT_RE.test(reason)) {
214749
+ return `${who} ${BYOK_CREDIT_MARKER}, so it refused this request. Add credit on the provider's billing page, or switch model: Atlarix Auto is free. (It said: "${said}")`;
214750
+ }
214751
+ if (KEY_RE.test(reason)) {
214752
+ return `${providerId ?? "The provider"} ${BYOK_KEY_MARKER}. Check the key (it may have been revoked or mistyped), or switch model. (It said: "${said}")`;
214753
+ }
214754
+ if (RATE_RE.test(reason)) {
214755
+ return `${providerId ?? "The provider"} ${BYOK_RATE_MARKER} right now. Wait a moment and resend, or switch model. (It said: "${said}")`;
214756
+ }
214757
+ return null;
214758
+ }
214759
+ function modelFailureUserMessage(reason) {
214760
+ if (reason.includes(CORE_TIER_NEWER_BUILD)) return CORE_TIER_NEWER_BUILD;
214761
+ const said = providerSaid(reason.replace(/\bDetails:\s*/g, "")) || "the request failed";
214762
+ if (/model ['"`]?[^'"`\s]+['"`]? not found|model_not_found|no such model|unknown model/i.test(reason)) {
214763
+ return `The provider doesn't have that model. Check the model's id, or switch model. (It said: "${said}")`;
214764
+ }
214765
+ if (/\b404\b|not found/i.test(reason)) {
214766
+ return `The provider's address answered "not found". Check its base URL (most end in /v1), or switch model. (It said: "${said}")`;
214767
+ }
214768
+ if (/cannot connect|unable to connect|econnrefused|fetch failed|connection refused|enotfound/i.test(reason)) {
214769
+ return `Couldn't reach the provider. Is its server running, and is the address right? Or switch model. (It said: "${said}")`;
214770
+ }
214771
+ return `This model failed: "${said}". Try again, or switch model.`;
214772
+ }
214773
+ var AI_STREAMING_ERROR_MESSAGE_PREFIX, AI_STREAM_EMPTY_RESPONSE_FALLBACK, SAFETY_FILTER_BLOCKED_MESSAGE, BYOK_CREDIT_MARKER, BYOK_RATE_MARKER, BYOK_KEY_MARKER, CREDIT_RE, RATE_RE, KEY_RE, CORE_TIER_NEWER_BUILD;
214774
+ var init_texts = __esm({
214775
+ "src/shared/texts.ts"() {
214776
+ AI_STREAMING_ERROR_MESSAGE_PREFIX = "Sorry, there was an error from the AI: ";
214777
+ AI_STREAM_EMPTY_RESPONSE_FALLBACK = "Something went wrong \u2014 please try again.";
214778
+ SAFETY_FILTER_BLOCKED_MESSAGE = "Message blocked by safety filter.";
214779
+ BYOK_CREDIT_MARKER = "is out of credit or over its quota";
214780
+ BYOK_RATE_MARKER = "is rate-limiting your key";
214781
+ BYOK_KEY_MARKER = "rejected your API key";
214782
+ CREDIT_RE = /insufficient[_ ]?(quota|balance|credits?|funds)|credit balance is too low|exceeded your current quota|out of credits?|payment required|billing (hard )?limit|\b402\b|quota[_ ]exceeded|no credits/i;
214783
+ RATE_RE = /rate[_ -]?limit|too many requests|\b429\b|overloaded|resource[_ ]exhausted/i;
214784
+ KEY_RE = /invalid[_ ]?(api[_ ]?)?key|incorrect api key|api key not valid|unauthori[sz]ed|authentication[_ ]?(error|failed)|\b401\b|permission[_ ]denied/i;
214785
+ CORE_TIER_NEWER_BUILD = "That Atlarix Core model comes from a newer version of Atlarix. Update this one, or pick another model.";
214786
+ }
214787
+ });
214788
+
214711
214789
  // src/ipc/utils/get_model_client.ts
214712
214790
  var get_model_client_exports = {};
214713
214791
  __export(get_model_client_exports, {
@@ -214902,6 +214980,9 @@ async function getRegularModelClient(model, settings, providerConfig, options) {
214902
214980
  "Atlarix Auto isn't offered right now. Pick a Core model above, or add your own API key in Settings."
214903
214981
  );
214904
214982
  }
214983
+ if (!resolvedTier && isCoreTierFromNewerBuild(model.name)) {
214984
+ throw new Error(CORE_TIER_NEWER_BUILD);
214985
+ }
214905
214986
  if (!resolvedTier) {
214906
214987
  throw new Error(
214907
214988
  `No Atlarix Core model is configured for this build. Add your own API keys in Settings, or use a release build.`
@@ -215202,6 +215283,7 @@ var init_get_model_client = __esm({
215202
215283
  init_analytics();
215203
215284
  init_local_model_ollama_handler();
215204
215285
  init_model_reasoning_profile();
215286
+ init_texts();
215205
215287
  logger19 = import_electron_log21.default.scope("getModelClient");
215206
215288
  }
215207
215289
  });
@@ -250417,59 +250499,6 @@ var init_delivered_results = __esm({
250417
250499
  }
250418
250500
  });
250419
250501
 
250420
- // src/shared/texts.ts
250421
- function providerSaid(reason) {
250422
- const m3 = /"message"\s*:\s*"([^"]{1,300})"/.exec(reason);
250423
- const text3 = (m3?.[1] ?? reason).replace(/\s+/g, " ").replace(/(\S{0,12}?)\*{4,}(\S{0,8})/g, (_m, head2, tail) => `${head2}\u2026${tail}`).trim();
250424
- if (text3.length <= 200) return text3;
250425
- const cut = text3.slice(0, 200);
250426
- const sentence = cut.lastIndexOf(". ");
250427
- if (sentence > 80) return cut.slice(0, sentence + 1);
250428
- const word = cut.lastIndexOf(" ");
250429
- return `${cut.slice(0, word > 80 ? word : 200)}\u2026`;
250430
- }
250431
- function byokLimitUserMessage(reason, providerId) {
250432
- const who = providerId ? `Your ${providerId} account` : "Your provider account";
250433
- const said = providerSaid(reason);
250434
- if (CREDIT_RE.test(reason)) {
250435
- return `${who} ${BYOK_CREDIT_MARKER}, so it refused this request. Add credit on the provider's billing page, or switch model: Atlarix Auto is free. (It said: "${said}")`;
250436
- }
250437
- if (KEY_RE.test(reason)) {
250438
- return `${providerId ?? "The provider"} ${BYOK_KEY_MARKER}. Check the key (it may have been revoked or mistyped), or switch model. (It said: "${said}")`;
250439
- }
250440
- if (RATE_RE.test(reason)) {
250441
- return `${providerId ?? "The provider"} ${BYOK_RATE_MARKER} right now. Wait a moment and resend, or switch model. (It said: "${said}")`;
250442
- }
250443
- return null;
250444
- }
250445
- function modelFailureUserMessage(reason) {
250446
- const said = providerSaid(reason.replace(/\bDetails:\s*/g, "")) || "the request failed";
250447
- if (/model ['"`]?[^'"`\s]+['"`]? not found|model_not_found|no such model|unknown model/i.test(reason)) {
250448
- return `The provider doesn't have that model. Check the model's id, or switch model. (It said: "${said}")`;
250449
- }
250450
- if (/\b404\b|not found/i.test(reason)) {
250451
- return `The provider's address answered "not found". Check its base URL (most end in /v1), or switch model. (It said: "${said}")`;
250452
- }
250453
- if (/cannot connect|unable to connect|econnrefused|fetch failed|connection refused|enotfound/i.test(reason)) {
250454
- return `Couldn't reach the provider. Is its server running, and is the address right? Or switch model. (It said: "${said}")`;
250455
- }
250456
- return `This model failed: "${said}". Try again, or switch model.`;
250457
- }
250458
- var AI_STREAMING_ERROR_MESSAGE_PREFIX, AI_STREAM_EMPTY_RESPONSE_FALLBACK, SAFETY_FILTER_BLOCKED_MESSAGE, BYOK_CREDIT_MARKER, BYOK_RATE_MARKER, BYOK_KEY_MARKER, CREDIT_RE, RATE_RE, KEY_RE;
250459
- var init_texts = __esm({
250460
- "src/shared/texts.ts"() {
250461
- AI_STREAMING_ERROR_MESSAGE_PREFIX = "Sorry, there was an error from the AI: ";
250462
- AI_STREAM_EMPTY_RESPONSE_FALLBACK = "Something went wrong \u2014 please try again.";
250463
- SAFETY_FILTER_BLOCKED_MESSAGE = "Message blocked by safety filter.";
250464
- BYOK_CREDIT_MARKER = "is out of credit or over its quota";
250465
- BYOK_RATE_MARKER = "is rate-limiting your key";
250466
- BYOK_KEY_MARKER = "rejected your API key";
250467
- CREDIT_RE = /insufficient[_ ]?(quota|balance|credits?|funds)|credit balance is too low|exceeded your current quota|out of credits?|payment required|billing (hard )?limit|\b402\b|quota[_ ]exceeded|no credits/i;
250468
- RATE_RE = /rate[_ -]?limit|too many requests|\b429\b|overloaded|resource[_ ]exhausted/i;
250469
- KEY_RE = /invalid[_ ]?(api[_ ]?)?key|incorrect api key|api key not valid|unauthori[sz]ed|authentication[_ ]?(error|failed)|\b401\b|permission[_ ]denied/i;
250470
- }
250471
- });
250472
-
250473
250502
  // src/lib/security/prompt-hygiene.ts
250474
250503
  function sanitizePromptInput(raw) {
250475
250504
  if (typeof raw !== "string") {
@@ -284977,6 +285006,8 @@ __export(paid_search_exports, {
284977
285006
  paidWebSearch: () => paidWebSearch
284978
285007
  });
284979
285008
  async function paidWebSearch(query, limit, chatId) {
285009
+ const { isBrowserSearchAvailable: isBrowserSearchAvailable2 } = await Promise.resolve().then(() => (init_browser_search(), browser_search_exports));
285010
+ if (isBrowserSearchAvailable2()) return null;
284980
285011
  const { paidCoreForChat: paidCoreForChat2, coreProxyPost: coreProxyPost2 } = await Promise.resolve().then(() => (init_paid_core(), paid_core_exports));
284981
285012
  if (!await paidCoreForChat2(chatId).catch(() => false)) return null;
284982
285013
  try {
@@ -284985,6 +285016,7 @@ async function paidWebSearch(query, limit, chatId) {
284985
285016
  { json: { query, num_results: limit } },
284986
285017
  { signal: AbortSignal.timeout(6e4) }
284987
285018
  );
285019
+ if (res?.status === 402) return { blocked: "balance" };
284988
285020
  if (!res?.ok) return null;
284989
285021
  const body = await res.json();
284990
285022
  const rows = (body.results ?? []).filter(
@@ -285321,7 +285353,7 @@ function optimizeSearchQueryKeywords(rawQuery) {
285321
285353
  const optimized = [...quoted, ...keywords.slice(0, 6)].join(" ").trim();
285322
285354
  return optimized || rawQuery;
285323
285355
  }
285324
- var import_turndown, WEB_SEARCH_SETUP_HINT, CLI_WEB_SEARCH_UNAVAILABLE, READ_URL_DEFAULT_MAX, READ_URL_MAX_CAP, FETCH_TIMEOUT_MS, FETCH_TIMEOUT_MAX_MS, BROWSER_USER_AGENT, _turndown, READER_PARTITION, BROWSER_ESCALATION_STATUSES, JS_SHELL_MAX_TEXT_CHARS, JS_SHELL_MIN_HTML_BYTES, EXTERNAL_SCRIPT_RE, BROWSER_EXTRACT_TIMEOUT_MS, POST_RENDER_MIN_CHARS, READER_HTML_SCRIPT, RELEVANCE_STOP_WORDS, WEB_SEARCH_GLOBAL_CACHE, WEB_SEARCH_GLOBAL_IN_FLIGHT, WEB_SEARCH_CACHE_TTL, READ_URL_CACHE, READ_URL_IN_FLIGHT, READ_URL_CACHE_TTL, READ_URL_CACHE_MAX_CHARS, WEB_SEARCH_DEFAULT_RESULTS, WEB_SEARCH_MAX_RESULTS, SITE_ROOT_FETCH_MAX, WebSearchAggregator;
285356
+ var import_turndown, WEB_SEARCH_SETUP_HINT, CLI_WEB_SEARCH_UNAVAILABLE, WEB_SEARCH_NO_BALANCE, READ_URL_DEFAULT_MAX, READ_URL_MAX_CAP, FETCH_TIMEOUT_MS, FETCH_TIMEOUT_MAX_MS, BROWSER_USER_AGENT, _turndown, READER_PARTITION, BROWSER_ESCALATION_STATUSES, JS_SHELL_MAX_TEXT_CHARS, JS_SHELL_MIN_HTML_BYTES, EXTERNAL_SCRIPT_RE, BROWSER_EXTRACT_TIMEOUT_MS, POST_RENDER_MIN_CHARS, READER_HTML_SCRIPT, RELEVANCE_STOP_WORDS, WEB_SEARCH_GLOBAL_CACHE, WEB_SEARCH_GLOBAL_IN_FLIGHT, WEB_SEARCH_CACHE_TTL, READ_URL_CACHE, READ_URL_IN_FLIGHT, READ_URL_CACHE_TTL, READ_URL_CACHE_MAX_CHARS, WEB_SEARCH_DEFAULT_RESULTS, WEB_SEARCH_MAX_RESULTS, SITE_ROOT_FETCH_MAX, WebSearchAggregator;
285325
285357
  var init_web = __esm({
285326
285358
  "src/lib/tools/web.ts"() {
285327
285359
  init_registry();
@@ -285332,6 +285364,7 @@ var init_web = __esm({
285332
285364
  import_turndown = __toESM(require_turndown_cjs());
285333
285365
  WEB_SEARCH_SETUP_HINT = "\n\n**If this keeps coming up empty:** search already runs through Atlarix's own browser, so there is nothing to install \u2014 try rephrasing as keywords rather than a question. If one site or domain is consistently thin, the user can connect a **search/web MCP** in Settings \u2192 Tools & MCP.";
285334
285366
  CLI_WEB_SEARCH_UNAVAILABLE = (query) => `**No web results for "${query}". In the Atlarix CLI, web search runs through the Atlarix Chrome extension** (install it and open its side panel once). Without it, add a search MCP server (any search API works that way). Tell the user so. \`read_url\` still works for a page whose address you know.`;
285367
+ WEB_SEARCH_NO_BALANCE = (query) => `**No web results for "${query}". Web search here is billed to the Atlarix account, and the balance can't cover it.** Tell the user to add credit (\`/billing\` in the terminal), or to connect a search MCP server. \`read_url\` still works for a page whose address you know.`;
285335
285368
  READ_URL_DEFAULT_MAX = 2e4;
285336
285369
  READ_URL_MAX_CAP = 5e4;
285337
285370
  FETCH_TIMEOUT_MS = 2e4;
@@ -285468,7 +285501,9 @@ ${fetched.content}`
285468
285501
  };
285469
285502
  }
285470
285503
  const { paidWebSearch: paidWebSearch2 } = await Promise.resolve().then(() => (init_paid_search(), paid_search_exports));
285471
- const paid = await paidWebSearch2(query, maxResults, args2._chatSessionId);
285504
+ const paidReply = await paidWebSearch2(query, maxResults, args2._chatSessionId);
285505
+ const noBalance = paidReply !== null && "blocked" in paidReply;
285506
+ const paid = noBalance ? null : paidReply;
285472
285507
  if (paid && paid.results.length > 0) {
285473
285508
  const lines = [`**Search results for: "${query}"**
285474
285509
  `];
@@ -285499,6 +285534,9 @@ ${fetched.content}`
285499
285534
  maxResults
285500
285535
  );
285501
285536
  console.log(`[web_search] Found ${searchResults.sources.length} results`);
285537
+ if (noBalance && searchResults.sources.length === 0) {
285538
+ return { text: WEB_SEARCH_NO_BALANCE(query), sources: [] };
285539
+ }
285502
285540
  return {
285503
285541
  // Remote search content is untrusted — data, not instructions.
285504
285542
  text: searchResults.sources.length > 0 ? wrapUntrustedData("web_search", searchResults.formattedText) : searchResults.formattedText,
@@ -348043,7 +348081,7 @@ ${err2.stack}` : "";
348043
348081
  }
348044
348082
 
348045
348083
  // src/headless/atlarix-headless.mts
348046
- var VERSION15 = false ? "dev" : "15.9.0";
348084
+ var VERSION15 = false ? "dev" : "15.9.1";
348047
348085
  if (process.argv[2] === "run") process.argv.splice(2, 1);
348048
348086
  var RUN_HELP = `atlarix run: one turn without the UI, for scripts and CI
348049
348087
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atlarix",
3
- "version": "15.9.0",
3
+ "version": "15.9.1",
4
4
  "description": "Atlarix CLI: an AI coding agent in your terminal. Works with any model (Atlarix Auto, your own API key, or a local model) and runs unattended with `atlarix run` for CI.",
5
5
  "license": "PROPRIETARY",
6
6
  "author": {
@@ -65,12 +65,12 @@
65
65
  "provenance": false
66
66
  },
67
67
  "optionalDependencies": {
68
- "atlarix-darwin-arm64": "15.9.0",
69
- "atlarix-darwin-x64": "15.9.0",
70
- "atlarix-linux-x64": "15.9.0",
71
- "atlarix-linux-arm64": "15.9.0",
72
- "atlarix-linux-x64-musl": "15.9.0",
73
- "atlarix-linux-arm64-musl": "15.9.0",
74
- "atlarix-windows-x64": "15.9.0"
68
+ "atlarix-darwin-arm64": "15.9.1",
69
+ "atlarix-darwin-x64": "15.9.1",
70
+ "atlarix-linux-x64": "15.9.1",
71
+ "atlarix-linux-arm64": "15.9.1",
72
+ "atlarix-linux-x64-musl": "15.9.1",
73
+ "atlarix-linux-arm64-musl": "15.9.1",
74
+ "atlarix-windows-x64": "15.9.1"
75
75
  }
76
76
  }