atlarix 15.8.1 → 15.9.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.
@@ -9587,6 +9587,10 @@ var init_schema = __esm({
9587
9587
  name: text("name").notNull(),
9588
9588
  api_base_url: text("api_base_url").notNull(),
9589
9589
  env_var_name: text("env_var_name"),
9590
+ /** Wire format: null / "openai" = OpenAI-compatible, "anthropic" = Messages API. */
9591
+ api_format: text("api_format"),
9592
+ /** How the key is sent: null = the format's usual header, or "x-api-key" / "bearer". */
9593
+ auth_header: text("auth_header"),
9590
9594
  createdAt: integer("created_at", { mode: "timestamp" }).notNull().default(sql`(unixepoch())`),
9591
9595
  updatedAt: integer("updated_at", { mode: "timestamp" }).notNull().default(sql`(unixepoch())`)
9592
9596
  }
@@ -10911,6 +10915,14 @@ var init_usage_stats = __esm({
10911
10915
  }
10912
10916
  });
10913
10917
 
10918
+ // raw-file:/home/runner/work/Atlarix/Atlarix/drizzle/0080_custom_provider_api_format.sql
10919
+ var custom_provider_api_format_default;
10920
+ var init_custom_provider_api_format = __esm({
10921
+ "raw-file:/home/runner/work/Atlarix/Atlarix/drizzle/0080_custom_provider_api_format.sql"() {
10922
+ custom_provider_api_format_default = "-- The wire format a provider the user added speaks, and how it takes the key.\n--\n-- A custom provider could only be OpenAI-compatible. Many endpoints serve the\n-- Anthropic Messages API instead (Bedrock's /anthropic, gateways, proxies), and\n-- those take the key either as `x-api-key` or as `Authorization: Bearer`.\n--\n-- Additive only (two nullable columns, null = OpenAI-compatible with its usual\n-- Bearer key): an older reader ignores them, so min_reader stays where it is.\nALTER TABLE `language_model_providers` ADD `api_format` text;--> statement-breakpoint\nALTER TABLE `language_model_providers` ADD `auth_header` text;\n";
10923
+ }
10924
+ });
10925
+
10914
10926
  // src/db/migrations/bundled.generated.ts
10915
10927
  var BUNDLED_MIGRATIONS, DRIZZLE_HASH_TO_NAME;
10916
10928
  var init_bundled_generated = __esm({
@@ -10995,6 +11007,7 @@ var init_bundled_generated = __esm({
10995
11007
  init_automation_leases();
10996
11008
  init_mcp_headers();
10997
11009
  init_usage_stats();
11010
+ init_custom_provider_api_format();
10998
11011
  BUNDLED_MIGRATIONS = [
10999
11012
  { name: "0000_nebulous_proemial_gods", sql: nebulous_proemial_gods_default, drizzleHash: "2fd0348e72ac1429b9246311e8db17a34078771470c622a13ab09afdee0a0d31", when: 1744692127560 },
11000
11013
  { name: "0001_hesitant_roland_deschain", sql: hesitant_roland_deschain_default, drizzleHash: "b9b37284db688cf3aaaa2719dda788238fd216933d3756c0482f26b5343d0059", when: 1744999922420 },
@@ -11075,7 +11088,8 @@ var init_bundled_generated = __esm({
11075
11088
  { name: "0076_drop_installed_skills", sql: drop_installed_skills_default, drizzleHash: "b361a2b664ce74a3efeaa2f73cdf6de582509c6569a1aab54febbef507b98b3c", when: 17877024e5 },
11076
11089
  { name: "0077_automation_leases", sql: automation_leases_default, drizzleHash: "22f09427b49eb0fcdd2b62cd472735a88e5dd60974af0d0c008f6e6fddfdf545", when: 17877888e5 },
11077
11090
  { name: "0078_mcp_headers", sql: mcp_headers_default, drizzleHash: "2e2b040eac31e336e8e7662555fd8526e8cdfd59929671e9ca6e063a3f2d4004", when: 17878752e5 },
11078
- { name: "0079_usage_stats", sql: usage_stats_default, drizzleHash: "8ea9653e8339a4f4c4f0fb140766daace073443ed9e6efae3d4597b2fc6bd60d", when: 17879616e5 }
11091
+ { name: "0079_usage_stats", sql: usage_stats_default, drizzleHash: "8ea9653e8339a4f4c4f0fb140766daace073443ed9e6efae3d4597b2fc6bd60d", when: 17879616e5 },
11092
+ { name: "0080_custom_provider_api_format", sql: custom_provider_api_format_default, drizzleHash: "0c66aed1a57dea6a1e9925a9a74dc1ca4f181db3de0c8e446a860a9f3ef7b950", when: 1788048e6 }
11079
11093
  ];
11080
11094
  DRIZZLE_HASH_TO_NAME = {
11081
11095
  "2fd0348e72ac1429b9246311e8db17a34078771470c622a13ab09afdee0a0d31": "0000_nebulous_proemial_gods",
@@ -11157,7 +11171,8 @@ var init_bundled_generated = __esm({
11157
11171
  "b361a2b664ce74a3efeaa2f73cdf6de582509c6569a1aab54febbef507b98b3c": "0076_drop_installed_skills",
11158
11172
  "22f09427b49eb0fcdd2b62cd472735a88e5dd60974af0d0c008f6e6fddfdf545": "0077_automation_leases",
11159
11173
  "2e2b040eac31e336e8e7662555fd8526e8cdfd59929671e9ca6e063a3f2d4004": "0078_mcp_headers",
11160
- "8ea9653e8339a4f4c4f0fb140766daace073443ed9e6efae3d4597b2fc6bd60d": "0079_usage_stats"
11174
+ "8ea9653e8339a4f4c4f0fb140766daace073443ed9e6efae3d4597b2fc6bd60d": "0079_usage_stats",
11175
+ "0c66aed1a57dea6a1e9925a9a74dc1ca4f181db3de0c8e446a860a9f3ef7b950": "0080_custom_provider_api_format"
11161
11176
  };
11162
11177
  }
11163
11178
  });
@@ -31220,12 +31235,11 @@ You are in ${L2("debug")} mode. Hypothesis-first debugging for this chat turn.
31220
31235
 
31221
31236
  You CAN:
31222
31237
  - Investigate (read, glob, grep, run_command for repro/tests)
31223
- - Form a hypothesis (root cause + evidence + files) before any write/edit/delete/rename
31238
+ - Form a hypothesis (root cause + evidence + files) before any change
31224
31239
  - Minimal file changes that test that hypothesis only
31225
- - Delegate a scoped fix to a WRITER sub-agent once you have a hypothesis \u2014 task({write:true, ...}) or task({subagent_type:"build", ...}). It writes nothing; its edits return as per-file proposals. Review each diff with \`proposals\` and accept the ones that hold up (accepting writes its exact bytes through the normal gate) \u2014 a fix you haven't read is not a fix. Read-only helper: the explore sub-agent (code recon and web research)
31240
+ - Delegate a scoped fix to a writer sub-agent once you have a hypothesis (task with write:true), reading each proposed diff before you accept it \u2014 a fix you haven't read is not a fix. Read-only helper: the explore sub-agent
31226
31241
 
31227
31242
  You CANNOT:
31228
- - Change files before forming a hypothesis
31229
31243
  - Refactor unrelated code or add features
31230
31244
 
31231
31245
  Workflow: investigate \u2192 form hypothesis \u2192 minimal fix \u2192 run the project's own tests/checks (run_command) \u2192 revise if needed. Note the root cause when you report the fix.
@@ -31812,7 +31826,26 @@ function renderModeSystemBlock(activeMode) {
31812
31826
  lines.push("</mode_system>");
31813
31827
  return lines.join("\n");
31814
31828
  }
31815
- async function buildSystemPromptWithProjectInstructions(params) {
31829
+ function joinSystemPromptParts({ stableHeader, dynamicTail }) {
31830
+ return `${stableHeader}
31831
+
31832
+ ${dynamicTail}
31833
+ `;
31834
+ }
31835
+ function splitDynamicTail(systemPrompt, dynamicTail) {
31836
+ if (!dynamicTail?.trim()) return systemPrompt;
31837
+ const joined = `
31838
+
31839
+ ${dynamicTail}
31840
+ `;
31841
+ const at2 = systemPrompt.indexOf(joined);
31842
+ if (at2 < 0) return systemPrompt;
31843
+ return {
31844
+ systemPromptOverride: systemPrompt.slice(0, at2) + systemPrompt.slice(at2 + joined.length),
31845
+ dynamicSystemTail: dynamicTail
31846
+ };
31847
+ }
31848
+ async function buildSystemPromptPartsWithProjectInstructions(params) {
31816
31849
  const {
31817
31850
  workspacePath,
31818
31851
  workspacePromptContent,
@@ -31841,7 +31874,7 @@ async function buildSystemPromptWithProjectInstructions(params) {
31841
31874
  buildInstructionsFromLayers(layers),
31842
31875
  projectDocsHint
31843
31876
  ].filter((s3) => s3.trim().length > 0).join("\n\n");
31844
- return constructSystemPrompt({
31877
+ return constructSystemPromptParts({
31845
31878
  contextSize,
31846
31879
  chatMode,
31847
31880
  effectiveWorkMode,
@@ -31867,7 +31900,7 @@ async function buildSystemPromptWithProjectInstructions(params) {
31867
31900
  registeredToolNames
31868
31901
  });
31869
31902
  }
31870
- var import_electron_log10, logger8, cachedPromptShell, AGENTS_MD, loadAgentsFile, FALLBACK_AGENTS, getAgentsMdForContextSize, getAgentsMdForWorkMode, MODE_SYSTEM_DESCRIPTIONS, constructSystemPromptParts, constructSystemPrompt;
31903
+ var import_electron_log10, logger8, cachedPromptShell, AGENTS_MD, loadAgentsFile, FALLBACK_AGENTS, getAgentsMdForContextSize, getAgentsMdForWorkMode, MODE_SYSTEM_DESCRIPTIONS, constructSystemPromptParts;
31871
31904
  var init_system_prompt = __esm({
31872
31905
  "src/prompts/system_prompt.ts"() {
31873
31906
  import_electron_log10 = __toESM(require_src());
@@ -32048,13 +32081,6 @@ When you need clarification or a decision from the user (architecture choices, d
32048
32081
  }
32049
32082
  return { stableHeader, dynamicTail: tail };
32050
32083
  };
32051
- constructSystemPrompt = (params) => {
32052
- const { stableHeader, dynamicTail } = constructSystemPromptParts(params);
32053
- return `${stableHeader}
32054
-
32055
- ${dynamicTail}
32056
- `;
32057
- };
32058
32084
  }
32059
32085
  });
32060
32086
 
@@ -67769,7 +67795,11 @@ var init_provider_sdk_factories = __esm({
67769
67795
  const provider = createOpenAI({ apiKey, ...baseURL ? { baseURL } : {} });
67770
67796
  return baseURL ? provider(modelId) : provider.responses(modelId);
67771
67797
  },
67772
- "@ai-sdk/anthropic": ({ modelId, apiKey, baseURL }) => createAnthropic({ apiKey, ...baseURL ? { baseURL } : {} })(modelId),
67798
+ // Exactly one of apiKey / authToken: the SDK refuses both.
67799
+ "@ai-sdk/anthropic": ({ modelId, apiKey, baseURL, authHeader }) => createAnthropic({
67800
+ ...authHeader === "bearer" ? { authToken: apiKey } : { apiKey },
67801
+ ...baseURL ? { baseURL } : {}
67802
+ })(modelId),
67773
67803
  "@ai-sdk/google": ({ modelId, apiKey, baseURL }) => createGoogle({ apiKey, ...baseURL ? { baseURL } : {} })(modelId),
67774
67804
  "@ai-sdk/xai": ({ modelId, apiKey, baseURL }) => createXai({ apiKey, ...baseURL ? { baseURL } : {} })(modelId)
67775
67805
  };
@@ -68428,7 +68458,7 @@ var init_model_reasoning_profile = __esm({
68428
68458
  temperatureById = /* @__PURE__ */ new Map();
68429
68459
  effortOverrides = /* @__PURE__ */ new Map();
68430
68460
  BUDGET_LEVELS = ["low", "medium", "high"];
68431
- BUDGET_HINT = { low: "medium", medium: "high", high: "max" };
68461
+ BUDGET_HINT = { low: "low", medium: "medium", high: "max" };
68432
68462
  NO_REASONING = /* @__PURE__ */ new Set(["none", "minimal"]);
68433
68463
  AUTO_EFFORT_LEVELS = ["low", "medium", "max"];
68434
68464
  AUTO_EFFORT_CHOICES = { kind: "effort", levels: [...AUTO_EFFORT_LEVELS], defaultLevel: "medium" };
@@ -68964,6 +68994,18 @@ var init_models_dev = __esm({
68964
68994
  }
68965
68995
  });
68966
68996
 
68997
+ // src/lib/provider-key-check.ts
68998
+ function anthropicHeaders(apiKey, authHeader) {
68999
+ return {
69000
+ ...authHeader === "bearer" ? { Authorization: `Bearer ${apiKey}` } : { "x-api-key": apiKey },
69001
+ "anthropic-version": "2023-06-01"
69002
+ };
69003
+ }
69004
+ var init_provider_key_check = __esm({
69005
+ "src/lib/provider-key-check.ts"() {
69006
+ }
69007
+ });
69008
+
68967
69009
  // node_modules/isexe/windows.js
68968
69010
  var require_windows = __commonJS({
68969
69011
  "node_modules/isexe/windows.js"(exports2, module2) {
@@ -71124,21 +71166,22 @@ async function fetchModelsFromOpenAI(apiKey) {
71124
71166
  return [];
71125
71167
  }
71126
71168
  }
71127
- async function fetchModelsFromAnthropic(apiKey) {
71128
- const cached4 = fromCache("anthropic");
71169
+ async function fetchModelsFromAnthropic(apiKey, endpoint2) {
71170
+ const cacheId = endpoint2?.providerId ?? "anthropic";
71171
+ const label = endpoint2 ? endpoint2.providerId : "Anthropic";
71172
+ const cached4 = fromCache(cacheId);
71129
71173
  if (cached4) return cached4;
71130
71174
  try {
71131
71175
  const items = [];
71132
71176
  let after2;
71133
71177
  for (let page = 0; page < MAX_PAGES; page++) {
71134
- const url2 = new URL("https://api.anthropic.com/v1/models");
71178
+ const url2 = new URL(
71179
+ endpoint2 ? `${endpoint2.baseUrl.replace(/\/+$/, "")}/models` : "https://api.anthropic.com/v1/models"
71180
+ );
71135
71181
  url2.searchParams.set("limit", "1000");
71136
71182
  if (after2) url2.searchParams.set("after_id", after2);
71137
71183
  const res = await fetch(url2, {
71138
- headers: {
71139
- "x-api-key": apiKey,
71140
- "anthropic-version": "2023-06-01"
71141
- },
71184
+ headers: anthropicHeaders(apiKey, endpoint2?.authHeader),
71142
71185
  signal: AbortSignal.timeout(15e3)
71143
71186
  });
71144
71187
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
@@ -71150,18 +71193,18 @@ async function fetchModelsFromAnthropic(apiKey) {
71150
71193
  const models = items.map((m3) => ({
71151
71194
  apiName: m3.id,
71152
71195
  displayName: m3.display_name ?? m3.id,
71153
- description: "Claude model with tool support",
71196
+ description: endpoint2 ? "Chat model with tool support" : "Claude model with tool support",
71154
71197
  ...m3.max_input_tokens ? { contextWindow: m3.max_input_tokens } : {},
71155
71198
  ...m3.max_tokens ? { maxOutputTokens: m3.max_tokens } : {},
71156
71199
  type: "cloud",
71157
71200
  supportsToolChoice: true
71158
71201
  }));
71159
71202
  sortModels(models);
71160
- toCache("anthropic", models);
71161
- logger10.info(`[Anthropic] Fetched ${models.length} models`);
71203
+ toCache(cacheId, models);
71204
+ logger10.info(`[${label}] Fetched ${models.length} models`);
71162
71205
  return models;
71163
71206
  } catch (e3) {
71164
- logger10.warn("[Anthropic] Fetch failed", e3);
71207
+ logger10.warn(`[${label}] Fetch failed`, e3);
71165
71208
  return [];
71166
71209
  }
71167
71210
  }
@@ -71364,7 +71407,14 @@ async function fetchModelsFromOpenRouter(apiKey) {
71364
71407
  return [];
71365
71408
  }
71366
71409
  }
71367
- async function fetchCustomProviderModels(providerId, baseUrl, apiKey) {
71410
+ async function fetchCustomProviderModels(providerId, baseUrl, apiKey, wire = {}) {
71411
+ if (wire.apiFormat === "anthropic") {
71412
+ return fetchModelsFromAnthropic(apiKey?.trim() || "none", {
71413
+ providerId,
71414
+ baseUrl,
71415
+ authHeader: wire.authHeader
71416
+ });
71417
+ }
71368
71418
  return fetchOpenAICompatibleModels({
71369
71419
  providerId,
71370
71420
  url: `${baseUrl.replace(/\/+$/, "")}/models`,
@@ -71435,6 +71485,7 @@ var init_provider_model_fetchers = __esm({
71435
71485
  import_electron_log12 = __toESM(require_src());
71436
71486
  init_openrouter_app_headers();
71437
71487
  init_language_model_constants();
71488
+ init_provider_key_check();
71438
71489
  logger10 = import_electron_log12.default.scope("provider_fetchers");
71439
71490
  CACHE_MS = 5 * 60 * 1e3;
71440
71491
  cache = /* @__PURE__ */ new Map();
@@ -71561,6 +71612,29 @@ var init_provider_api_keys = __esm({
71561
71612
  }
71562
71613
  });
71563
71614
 
71615
+ // src/lib/routing/custom-provider-format.ts
71616
+ function rememberCustomProviderFormats(providers) {
71617
+ anthropicFormat.clear();
71618
+ for (const p2 of providers) {
71619
+ if (p2.apiFormat === "anthropic") anthropicFormat.add(p2.id);
71620
+ }
71621
+ }
71622
+ function isCustomAnthropicFormat(providerId) {
71623
+ return Boolean(providerId && anthropicFormat.has(providerId));
71624
+ }
71625
+ function anthropicFormatCapabilityId(providerId) {
71626
+ return isCustomAnthropicFormat(providerId) ? "anthropic" : providerId;
71627
+ }
71628
+ function anthropicCatalogModelId(modelId) {
71629
+ return modelId.trim().replace(/^(?:[a-z]{2,6}\.)?anthropic\./i, "").replace(/-v\d+(?::\d+)?$/i, "");
71630
+ }
71631
+ var anthropicFormat;
71632
+ var init_custom_provider_format = __esm({
71633
+ "src/lib/routing/custom-provider-format.ts"() {
71634
+ anthropicFormat = /* @__PURE__ */ new Set();
71635
+ }
71636
+ });
71637
+
71564
71638
  // src/ipc/utils/thinking_utils.ts
71565
71639
  function reasoningCeiling(providerId) {
71566
71640
  return providerId && PROVIDERS_THAT_SUPPORT_THINKING.includes(providerId) ? "max" : "high";
@@ -71584,7 +71658,7 @@ function reasoningBudgetTokens(effort, maxOutputTokens) {
71584
71658
  const max4 = Math.max(1, Math.floor(maxOutputTokens));
71585
71659
  const reserve = Math.max(Math.round(max4 * 0.15), 2048);
71586
71660
  const ceil = Math.max(1024, max4 - reserve);
71587
- const frac = effort === "max" ? 0.85 : effort === "xhigh" ? 0.7 : effort === "high" ? 0.5 : 0.33;
71661
+ const frac = effort === "max" ? 0.85 : effort === "xhigh" ? 0.7 : effort === "high" ? 0.5 : effort === "low" ? 0.15 : 0.33;
71588
71662
  return Math.min(ceil, Math.max(1024, Math.round(max4 * frac)));
71589
71663
  }
71590
71664
  function getExtraProviderOptions(providerId, settings, includeExtendedThinking = false, maxOutputTokens, modelId) {
@@ -71668,6 +71742,9 @@ function resolveReasoningCatalogModelId(effectiveModel) {
71668
71742
  if (effectiveModel.provider === "compass") {
71669
71743
  return getCoreModelsDevTargetForTier(name29)?.modelId ?? getCoreModelIdForCoreTier(name29) ?? name29;
71670
71744
  }
71745
+ if (isCustomAnthropicFormat(effectiveModel.provider)) {
71746
+ return anthropicCatalogModelId(name29);
71747
+ }
71671
71748
  return name29;
71672
71749
  }
71673
71750
  function resolveMediaModelId(effectiveModel) {
@@ -71678,13 +71755,13 @@ function resolveMediaModelId(effectiveModel) {
71678
71755
  }
71679
71756
  function resolveCapabilityProviderId(effectiveModel) {
71680
71757
  const provider = (effectiveModel.provider ?? "").trim();
71681
- if (provider !== "compass") return provider;
71758
+ if (provider !== "compass") return anthropicFormatCapabilityId(provider);
71682
71759
  return getCoreModelsDevTargetForTier(effectiveModel.name ?? "")?.providerId ?? provider;
71683
71760
  }
71684
71761
  function detectReasoningCapability(modelApiId, builtinProviderId) {
71685
71762
  const id = modelApiId.trim();
71686
71763
  const lower2 = id.toLowerCase();
71687
- const pid = builtinProviderId ?? "";
71764
+ const pid = anthropicFormatCapabilityId(builtinProviderId) ?? "";
71688
71765
  let useOpenRouterReasoning = false;
71689
71766
  if (pid === "openrouter" || pid === "compass") {
71690
71767
  const row = id.includes("/") ? getCachedOpenRouterModelRow(id) : void 0;
@@ -71738,7 +71815,7 @@ function isReasoningCapableModel(model) {
71738
71815
  return offersAChannel(capabilityProvider) || offersAChannel(model.provider ?? "");
71739
71816
  }
71740
71817
  function resolveDispatchCapabilityProviderId(effectiveModel, builtinProviderId) {
71741
- if (builtinProviderId !== "compass") return builtinProviderId;
71818
+ if (builtinProviderId !== "compass") return anthropicFormatCapabilityId(builtinProviderId);
71742
71819
  if (effectiveModel.provider !== "compass") return builtinProviderId;
71743
71820
  return resolveCapabilityProviderId(effectiveModel);
71744
71821
  }
@@ -71834,6 +71911,7 @@ var init_reasoning_detector = __esm({
71834
71911
  init_model_capability_profile();
71835
71912
  init_language_model_constants();
71836
71913
  init_model_reasoning_profile();
71914
+ init_custom_provider_format();
71837
71915
  init_thinking_utils();
71838
71916
  GEMINI_LEVELS = /* @__PURE__ */ new Set(["minimal", "low", "medium", "high"]);
71839
71917
  }
@@ -72010,11 +72088,16 @@ async function getLanguageModelProviders() {
72010
72088
  name: cp.name,
72011
72089
  apiBaseUrl: cp.api_base_url,
72012
72090
  envVarName: cp.env_var_name ?? void 0,
72091
+ // The Anthropic format dispatches through the catalog's own Anthropic SDK
72092
+ // factory (provider-sdk-factories), like any models.dev provider on it.
72093
+ ...cp.api_format === "anthropic" ? { apiFormat: "anthropic", npm: ANTHROPIC_NPM } : {},
72094
+ ...cp.auth_header === "x-api-key" || cp.auth_header === "bearer" ? { authHeader: cp.auth_header } : {},
72013
72095
  type: "custom"
72014
72096
  // hasFreeTier, websiteUrl, gatewayPrefix are not in the custom DB schema
72015
72097
  // They will be undefined unless overridden by hardcoded values if IDs match
72016
72098
  });
72017
72099
  }
72100
+ rememberCustomProviderFormats([...customProvidersMap.values()]);
72018
72101
  const catalogById = /* @__PURE__ */ new Map();
72019
72102
  try {
72020
72103
  for (const c2 of await getModelsDevProviderCatalog())
@@ -72101,15 +72184,15 @@ function providerDisplayName(providerId) {
72101
72184
  if (!providerId) return void 0;
72102
72185
  return providerNames.get(providerId) ?? providerId.replace(/^custom::/, "");
72103
72186
  }
72104
- async function liveCustomModels(providerId, baseUrl, apiKey, now2 = Date.now()) {
72187
+ async function liveCustomModels(providerId, baseUrl, apiKey, now2 = Date.now(), wire = {}) {
72105
72188
  const { createHash: createHash10 } = await import("node:crypto");
72106
72189
  const keyTag = apiKey?.trim() ? createHash10("sha256").update(apiKey.trim()).digest("hex").slice(0, 12) : "none";
72107
- const cacheKey = `${providerId}|${baseUrl}|${keyTag}`;
72190
+ const cacheKey = `${providerId}|${baseUrl}|${keyTag}|${wire.apiFormat ?? "openai"}|${wire.authHeader ?? ""}`;
72108
72191
  const hit = liveCache.get(cacheKey);
72109
72192
  if (hit && now2 - hit.at < LIVE_TTL_MS) return hit.models;
72110
72193
  const { fetchCustomProviderModels: fetchCustomProviderModels2 } = await Promise.resolve().then(() => (init_provider_model_fetchers(), provider_model_fetchers_exports));
72111
72194
  const models = Promise.race([
72112
- fetchCustomProviderModels2(providerId, baseUrl, apiKey).catch(
72195
+ fetchCustomProviderModels2(providerId, baseUrl, apiKey, wire).catch(
72113
72196
  () => []
72114
72197
  ),
72115
72198
  new Promise(
@@ -72142,7 +72225,10 @@ async function getLanguageModels({
72142
72225
  maxOutputTokens: language_models.max_output_tokens,
72143
72226
  contextWindow: language_models.context_window
72144
72227
  }).from(language_models).where(
72145
- isCustomProvider({ providerId }) ? eq(language_models.customProviderId, providerId) : eq(language_models.builtinProviderId, providerId)
72228
+ // A provider from the providers table, whatever its id: the CLI's dev
72229
+ // endpoint is `atlarix-cli-dev`, with no `custom::`, and its model row
72230
+ // was looked up as a built-in's and never found (QA B3).
72231
+ provider.type === "custom" || isCustomProvider({ providerId }) ? eq(language_models.customProviderId, providerId) : eq(language_models.builtinProviderId, providerId)
72146
72232
  );
72147
72233
  customModels = customModelsDb.map((model) => ({
72148
72234
  ...model,
@@ -72203,7 +72289,10 @@ async function getLanguageModels({
72203
72289
  key = readSettings2().providerSettings?.[providerId]?.apiKey?.value;
72204
72290
  } catch {
72205
72291
  }
72206
- const listed = await liveCustomModels(providerId, provider.apiBaseUrl, key);
72292
+ const listed = await liveCustomModels(providerId, provider.apiBaseUrl, key, Date.now(), {
72293
+ apiFormat: provider.apiFormat,
72294
+ authHeader: provider.authHeader
72295
+ });
72207
72296
  const typed = new Set(customModels.map((m3) => m3.apiName));
72208
72297
  return [...customModels, ...listed.filter((m3) => !typed.has(m3.apiName))];
72209
72298
  }
@@ -72314,7 +72403,7 @@ function stampDeepThinkingSupport(modelsByProvider) {
72314
72403
  function isCustomProvider({ providerId }) {
72315
72404
  return providerId.startsWith(CUSTOM_PROVIDER_PREFIX);
72316
72405
  }
72317
- var providerNames, LIVE_TTL_MS, liveCache, CUSTOM_PROVIDER_PREFIX;
72406
+ var ANTHROPIC_NPM, providerNames, LIVE_TTL_MS, liveCache, CUSTOM_PROVIDER_PREFIX;
72318
72407
  var init_language_model_helpers = __esm({
72319
72408
  "src/ipc/shared/language_model_helpers.ts"() {
72320
72409
  init_db2();
@@ -72329,6 +72418,8 @@ var init_language_model_helpers = __esm({
72329
72418
  init_compass_constants();
72330
72419
  init_reasoning_detector();
72331
72420
  init_model_capability_profile();
72421
+ init_custom_provider_format();
72422
+ ANTHROPIC_NPM = "@ai-sdk/anthropic";
72332
72423
  providerNames = /* @__PURE__ */ new Map();
72333
72424
  LIVE_TTL_MS = 6e4;
72334
72425
  liveCache = /* @__PURE__ */ new Map();
@@ -94587,6 +94678,7 @@ __export(supabase_client_exports, {
94587
94678
  AUTH_CALLBACK_URL: () => AUTH_CALLBACK_URL,
94588
94679
  DEEP_LINK_PROTOCOL: () => DEEP_LINK_PROTOCOL,
94589
94680
  SUPABASE_REQUEST_TIMEOUT_MS: () => SUPABASE_REQUEST_TIMEOUT_MS,
94681
+ __resetUserRowForTests: () => __resetUserRowForTests,
94590
94682
  cancelPendingOAuthTimeout: () => cancelPendingOAuthTimeout,
94591
94683
  fetchPlanSnapshot: () => fetchPlanSnapshot,
94592
94684
  fetchWithTimeout: () => fetchWithTimeout,
@@ -94958,10 +95050,44 @@ async function restoreAuthSessionOnStartup(opts) {
94958
95050
  );
94959
95051
  }
94960
95052
  }
95053
+ async function readUserRow(by, fresh = false) {
95054
+ const key = by.id ? `id:${by.id}` : `email:${(by.email ?? "").toLowerCase()}`;
95055
+ const c2 = _userRow;
95056
+ if (!fresh && c2 && Date.now() - c2.at < USER_ROW_TTL_MS && c2.keys.includes(key)) return c2.row;
95057
+ const pending3 = _userRowInFlight.get(key);
95058
+ if (pending3) return pending3;
95059
+ const p2 = (async () => {
95060
+ try {
95061
+ const q3 = getSupabaseClient().from("users").select(USER_ROW_SELECT);
95062
+ const { data, error: error51 } = await (by.id ? q3.eq("id", by.id) : q3.eq("email", by.email)).maybeSingle();
95063
+ if (error51) return void 0;
95064
+ const row = data ?? null;
95065
+ const keys2 = [key];
95066
+ if (row?.id) keys2.push(`id:${row.id}`);
95067
+ if (row?.email) keys2.push(`email:${row.email.toLowerCase()}`);
95068
+ _userRow = { keys: keys2, row, at: Date.now() };
95069
+ return row;
95070
+ } catch {
95071
+ return void 0;
95072
+ } finally {
95073
+ _userRowInFlight.delete(key);
95074
+ }
95075
+ })();
95076
+ _userRowInFlight.set(key, p2);
95077
+ return p2;
95078
+ }
95079
+ function invalidateUserRow() {
95080
+ _userRow = null;
95081
+ }
95082
+ function __resetUserRowForTests() {
95083
+ _userRow = null;
95084
+ _userRowInFlight.clear();
95085
+ }
94961
95086
  async function ensureUserExists(user) {
94962
95087
  try {
94963
95088
  const supabase = getSupabaseClient();
94964
- const { data: existingUser } = await supabase.from("users").select("id").eq("id", user.id).single();
95089
+ const shared = await readUserRow({ id: user.id });
95090
+ const existingUser = shared !== void 0 ? shared : (await supabase.from("users").select("id").eq("id", user.id).single()).data;
94965
95091
  if (!existingUser) {
94966
95092
  const { error: error51 } = await supabase.from("users").insert({
94967
95093
  id: user.id,
@@ -94969,6 +95095,7 @@ async function ensureUserExists(user) {
94969
95095
  plan: "free",
94970
95096
  onboarding_completed: false
94971
95097
  });
95098
+ invalidateUserRow();
94972
95099
  if (error51) {
94973
95100
  logger13.error("[Supabase] Failed to create user:", error51);
94974
95101
  } else {
@@ -95020,6 +95147,8 @@ function computeEntitledPlan(row) {
95020
95147
  return tier;
95021
95148
  }
95022
95149
  async function fetchPlanRowForUser(supabase, userId) {
95150
+ const shared = await readUserRow({ id: userId });
95151
+ if (shared !== void 0) return { data: shared, error: null };
95023
95152
  let data = null;
95024
95153
  let error51 = null;
95025
95154
  {
@@ -95051,6 +95180,8 @@ async function getUserPlan(userId) {
95051
95180
  }
95052
95181
  async function isUserBanned(userId) {
95053
95182
  try {
95183
+ const shared = await readUserRow({ id: userId });
95184
+ if (shared !== void 0) return !!shared?.banned_at;
95054
95185
  const supabase = getSupabaseClient();
95055
95186
  const { data, error: error51 } = await supabase.from("users").select("banned_at").eq("id", userId).maybeSingle();
95056
95187
  if (error51 || !data) return false;
@@ -95080,9 +95211,10 @@ function offlinePlanOr(fallback, userId) {
95080
95211
  function requireSettings() {
95081
95212
  return init_settings(), __toCommonJS(settings_exports);
95082
95213
  }
95083
- function invalidatePlanCaches() {
95214
+ function invalidatePlanCaches(opts = {}) {
95084
95215
  _tierCache = null;
95085
95216
  _subDetailCache = null;
95217
+ if (!opts.keepRow) invalidateUserRow();
95086
95218
  }
95087
95219
  async function getSubscriptionDetails(email3) {
95088
95220
  const c2 = _subDetailCache;
@@ -95090,8 +95222,8 @@ async function getSubscriptionDetails(email3) {
95090
95222
  return { status: c2.status, endsAt: c2.endsAt };
95091
95223
  }
95092
95224
  try {
95093
- const supabase = getSupabaseClient();
95094
- const { data } = await supabase.from("users").select("subscription_status, subscription_ends_at").eq("email", email3).single();
95225
+ const shared = await readUserRow({ email: email3 });
95226
+ const data = shared !== void 0 ? shared : (await getSupabaseClient().from("users").select("subscription_status, subscription_ends_at").eq("email", email3).single()).data;
95095
95227
  const status = data?.subscription_status ?? null;
95096
95228
  const endsAt = data?.subscription_ends_at ?? null;
95097
95229
  _subDetailCache = { email: email3, status, endsAt, at: Date.now() };
@@ -95123,6 +95255,8 @@ async function getEffectiveTier(userId, ownPlan) {
95123
95255
  }
95124
95256
  async function getOnboardingCompleted(userId) {
95125
95257
  try {
95258
+ const shared = await readUserRow({ id: userId });
95259
+ if (shared !== void 0) return shared?.onboarding_completed === true;
95126
95260
  const supabase = getSupabaseClient();
95127
95261
  const { data, error: error51 } = await supabase.from("users").select("onboarding_completed").eq("id", userId).maybeSingle();
95128
95262
  if (error51) {
@@ -95139,6 +95273,7 @@ async function setOnboardingCompleted(userId, value) {
95139
95273
  try {
95140
95274
  const supabase = getSupabaseClient();
95141
95275
  const { error: error51 } = await supabase.from("users").update({ onboarding_completed: value }).eq("id", userId);
95276
+ invalidateUserRow();
95142
95277
  if (error51) {
95143
95278
  logger13.error("[Supabase] setOnboardingCompleted error:", error51.message);
95144
95279
  } else {
@@ -95162,11 +95297,10 @@ function onAuthStateChange(callback) {
95162
95297
  });
95163
95298
  return () => subscription.unsubscribe();
95164
95299
  }
95165
- async function fetchPlanSnapshot(userEmail) {
95300
+ async function fetchPlanSnapshot(userEmail, fresh = true) {
95166
95301
  try {
95167
- const { data, error: error51 } = await getSupabaseClient().from("users").select(
95168
- "plan, subscription_status, subscription_ends_at, effective_tier, banned_at"
95169
- ).eq("email", userEmail).maybeSingle();
95302
+ const shared = await readUserRow({ email: userEmail }, fresh);
95303
+ const { data, error: error51 } = shared !== void 0 ? { data: shared, error: null } : await getSupabaseClient().from("users").select("plan, subscription_status, subscription_ends_at, effective_tier, banned_at").eq("email", userEmail).maybeSingle();
95170
95304
  if (error51 || !data) return null;
95171
95305
  const row = data;
95172
95306
  return {
@@ -95180,7 +95314,7 @@ async function fetchPlanSnapshot(userEmail) {
95180
95314
  return null;
95181
95315
  }
95182
95316
  }
95183
- var import_electron_log15, logger13, DEEP_LINK_PROTOCOL, AUTH_CALLBACK_PATH, AUTH_CALLBACK_URL, supabaseClient, fileStorage, SUPABASE_REQUEST_TIMEOUT_MS, _oauthTimeoutHandle, _authFlowStartedAt, AUTH_FLOW_MAX_AGE_MS, EMAIL_SIGN_IN_URL, _pendingAuthState, sleep4, PLAN_ROW_SELECT_BASE, PLAN_ROW_SELECT_WITH_VARIANT, EFFECTIVE_TIER_TTL_MS, _tierCache, _subDetailCache;
95317
+ var import_electron_log15, logger13, DEEP_LINK_PROTOCOL, AUTH_CALLBACK_PATH, AUTH_CALLBACK_URL, supabaseClient, fileStorage, SUPABASE_REQUEST_TIMEOUT_MS, _oauthTimeoutHandle, _authFlowStartedAt, AUTH_FLOW_MAX_AGE_MS, EMAIL_SIGN_IN_URL, _pendingAuthState, sleep4, USER_ROW_SELECT, USER_ROW_TTL_MS, _userRow, _userRowInFlight, PLAN_ROW_SELECT_BASE, PLAN_ROW_SELECT_WITH_VARIANT, EFFECTIVE_TIER_TTL_MS, _tierCache, _subDetailCache;
95184
95318
  var init_supabase_client = __esm({
95185
95319
  "src/lib/auth/supabase-client.ts"() {
95186
95320
  init_dist13();
@@ -95201,6 +95335,10 @@ var init_supabase_client = __esm({
95201
95335
  EMAIL_SIGN_IN_URL = "https://atlarix.dev/auth/app";
95202
95336
  _pendingAuthState = null;
95203
95337
  sleep4 = (ms2) => new Promise((r3) => setTimeout(r3, ms2));
95338
+ USER_ROW_SELECT = "id, email, plan, effective_tier, subscription_ends_at, subscription_status, lemon_subscription_id, lemon_variant_id, banned_at, onboarding_completed";
95339
+ USER_ROW_TTL_MS = 1e4;
95340
+ _userRow = null;
95341
+ _userRowInFlight = /* @__PURE__ */ new Map();
95204
95342
  PLAN_ROW_SELECT_BASE = "plan, effective_tier, subscription_ends_at, subscription_status, lemon_subscription_id";
95205
95343
  PLAN_ROW_SELECT_WITH_VARIANT = `${PLAN_ROW_SELECT_BASE}, lemon_variant_id`;
95206
95344
  EFFECTIVE_TIER_TTL_MS = 30 * 60 * 1e3;
@@ -95699,7 +95837,8 @@ async function resolveModelContextLimit(model, settings) {
95699
95837
  if (pid.startsWith("custom::")) {
95700
95838
  try {
95701
95839
  const { getLanguageModelProviders: getLanguageModelProviders2 } = await Promise.resolve().then(() => (init_language_model_helpers(), language_model_helpers_exports));
95702
- const base = (await getLanguageModelProviders2()).find((p2) => p2.id.toLowerCase() === pid)?.apiBaseUrl;
95840
+ const custom2 = (await getLanguageModelProviders2()).find((p2) => p2.id.toLowerCase() === pid);
95841
+ const base = custom2?.apiFormat === "anthropic" ? void 0 : custom2?.apiBaseUrl;
95703
95842
  if (base) {
95704
95843
  const { isOllamaEndpoint: isOllamaEndpoint2, ollamaOrigin: ollamaOrigin2, ollamaNumCtx: ollamaNumCtx2 } = await Promise.resolve().then(() => (init_ollama_native_fetch(), ollama_native_fetch_exports));
95705
95844
  if (await isOllamaEndpoint2(base)) {
@@ -95722,10 +95861,7 @@ async function resolveModelContextLimit(model, settings) {
95722
95861
  }
95723
95862
  try {
95724
95863
  const { getModelsDevLimits: getModelsDevLimits2 } = await Promise.resolve().then(() => (init_models_dev(), models_dev_exports));
95725
- const limits = await getModelsDevLimits2(
95726
- model.provider ?? "",
95727
- model.name ?? ""
95728
- );
95864
+ const limits = isCustomAnthropicFormat(model.provider) ? await getModelsDevLimits2("anthropic", anthropicCatalogModelId(model.name ?? "")) : await getModelsDevLimits2(model.provider ?? "", model.name ?? "");
95729
95865
  if (limits?.context && limits.context > 0) {
95730
95866
  return {
95731
95867
  tierLimit: floorSafe(limits.context * clamp),
@@ -95747,6 +95883,7 @@ var init_resolve_model_context_limit = __esm({
95747
95883
  init_compass_constants();
95748
95884
  init_findLanguageModel();
95749
95885
  import_electron_log16 = __toESM(require_src());
95886
+ init_custom_provider_format();
95750
95887
  logger14 = import_electron_log16.default.scope("context-limit");
95751
95888
  SAFETY_FACTOR = 0.8;
95752
95889
  localContextCache = /* @__PURE__ */ new Map();
@@ -214995,7 +215132,7 @@ async function getRegularModelClient(model, settings, providerConfig, options) {
214995
215132
  };
214996
215133
  }
214997
215134
  default: {
214998
- if (providerConfig.type === "custom" && providerConfig.apiBaseUrl) {
215135
+ if (providerConfig.type === "custom" && providerConfig.apiBaseUrl && providerConfig.apiFormat !== "anthropic") {
214999
215136
  const { isOllamaEndpoint: isOllamaEndpoint2, ollamaOrigin: ollamaOrigin2 } = await Promise.resolve().then(() => (init_ollama_native_fetch(), ollama_native_fetch_exports));
215000
215137
  if (await isOllamaEndpoint2(providerConfig.apiBaseUrl)) {
215001
215138
  return {
@@ -215015,7 +215152,8 @@ async function getRegularModelClient(model, settings, providerConfig, options) {
215015
215152
  modelId: model.name,
215016
215153
  apiKey,
215017
215154
  baseURL: providerConfig.apiBaseUrl,
215018
- npm: providerConfig.npm
215155
+ npm: providerConfig.npm,
215156
+ authHeader: providerConfig.authHeader
215019
215157
  }),
215020
215158
  builtinProviderId: providerConfig.id
215021
215159
  },
@@ -241827,6 +241965,7 @@ var init_dist21 = __esm({
241827
241965
  function resolveCacheMarkerPlacement(builtinProviderId, modelName) {
241828
241966
  if (builtinProviderId === "anthropic") return "message";
241829
241967
  if (!/claude|anthropic/i.test(modelName ?? "")) return "none";
241968
+ if (isCustomAnthropicFormat(builtinProviderId)) return "message";
241830
241969
  if (builtinProviderId === "bedrock" || builtinProviderId === "vertex") {
241831
241970
  return "message";
241832
241971
  }
@@ -241938,6 +242077,7 @@ function advanceCacheBreakpointsForStep(messages, placement) {
241938
242077
  var CACHE_MARKER, CACHE_MARKER_HEADER_1H, CACHE_KEY_BY_PROVIDER;
241939
242078
  var init_anthropic_cache_breakpoints = __esm({
241940
242079
  "src/lib/ai/anthropic-cache-breakpoints.ts"() {
242080
+ init_custom_provider_format();
241941
242081
  CACHE_MARKER = {
241942
242082
  anthropic: { cacheControl: { type: "ephemeral" } },
241943
242083
  openrouter: { cacheControl: { type: "ephemeral" } },
@@ -264469,7 +264609,7 @@ var init_SubscriptionManager = __esm({
264469
264609
  } catch {
264470
264610
  }
264471
264611
  if (user.email) {
264472
- await this.refreshPlanFromServer(0);
264612
+ await this.refreshPlanFromServer(0, false);
264473
264613
  }
264474
264614
  this.broadcastAuthResolved();
264475
264615
  }
@@ -264630,7 +264770,7 @@ var init_SubscriptionManager = __esm({
264630
264770
  */
264631
264771
  static lastPlanRefreshAt = 0;
264632
264772
  static planRefreshInFlight = null;
264633
- static async refreshPlanFromServer(minIntervalMs = 15e3) {
264773
+ static async refreshPlanFromServer(minIntervalMs = 15e3, fresh = true) {
264634
264774
  const email3 = this.session?.email;
264635
264775
  if (!email3) return;
264636
264776
  if (this.planRefreshInFlight) return this.planRefreshInFlight;
@@ -264640,7 +264780,7 @@ var init_SubscriptionManager = __esm({
264640
264780
  this.planRefreshInFlight = (async () => {
264641
264781
  try {
264642
264782
  const { fetchPlanSnapshot: fetchPlanSnapshot2 } = await Promise.resolve().then(() => (init_supabase_client(), supabase_client_exports));
264643
- const next = await fetchPlanSnapshot2(email3);
264783
+ const next = await fetchPlanSnapshot2(email3, fresh);
264644
264784
  if (!next) return;
264645
264785
  const prev = {
264646
264786
  plan: this.session?.plan ?? "free",
@@ -264650,7 +264790,7 @@ var init_SubscriptionManager = __esm({
264650
264790
  banned: this.session?.banned ?? false
264651
264791
  };
264652
264792
  const changed = next.plan !== prev.plan || next.effectiveTier !== prev.effectiveTier || Boolean(next.banned) !== Boolean(prev.banned);
264653
- invalidatePlanCaches();
264793
+ invalidatePlanCaches({ keepRow: true });
264654
264794
  if (changed) await this.applyPlanChange(next, prev);
264655
264795
  } catch (e3) {
264656
264796
  logger56.warn("[SubscriptionManager] plan refresh failed (non-fatal)", e3);
@@ -338350,7 +338490,8 @@ async function simpleStreamText(ctx, deps, {
338350
338490
  ...reasoningPatch.anthropic
338351
338491
  };
338352
338492
  }
338353
- const handledNatively = offByBudget || Boolean(reasoningPatch.openrouter) || Boolean(reasoningPatch.google) || Boolean(reasoningPatch.openai) || Boolean(reasoningPatch.anthropic);
338493
+ const handledNatively = offByBudget || // The Anthropic SDK reads only its own bucket, in its own shape.
338494
+ isCustomAnthropicFormat(modelClient.builtinProviderId) || Boolean(reasoningPatch.openrouter) || Boolean(reasoningPatch.google) || Boolean(reasoningPatch.openai) || Boolean(reasoningPatch.anthropic);
338354
338495
  if (modelClient.builtinProviderId && !handledNatively) {
338355
338496
  const compatibleReasoning = getExtraProviderOptions(
338356
338497
  capabilityProviderId,
@@ -338369,6 +338510,7 @@ async function simpleStreamText(ctx, deps, {
338369
338510
  }
338370
338511
  }
338371
338512
  const isAnthropic = modelClient.builtinProviderId === "anthropic";
338513
+ const speaksAnthropic = isAnthropic || isCustomAnthropicFormat(modelClient.builtinProviderId);
338372
338514
  const cacheMarkerPlacement = resolveCacheMarkerPlacement(
338373
338515
  modelClient.builtinProviderId,
338374
338516
  effectiveModel?.name
@@ -338440,7 +338582,7 @@ async function simpleStreamText(ctx, deps, {
338440
338582
  history,
338441
338583
  placement: cacheMarkerPlacement,
338442
338584
  // v13.3: header prefix survives >5min between-turn gaps.
338443
- headerTtl1h: isAnthropic
338585
+ headerTtl1h: speaksAnthropic
338444
338586
  });
338445
338587
  const completedStepMessages = [];
338446
338588
  const recordStepMessages = (msgs) => {
@@ -338889,6 +339031,7 @@ var init_simple_stream_text = __esm({
338889
339031
  init_perf_marks();
338890
339032
  init_byok_pricing();
338891
339033
  init_reasoning_detector();
339034
+ init_custom_provider_format();
338892
339035
  init_system_reminder();
338893
339036
  init_step_messages();
338894
339037
  init_texts();
@@ -342987,6 +343130,7 @@ async function runBuildBranch(ctx, deps) {
342987
343130
  modelContextResolved,
342988
343131
  placeholderAssistantMessage,
342989
343132
  systemPrompt,
343133
+ dynamicTail,
342990
343134
  taskLedgerBlock,
342991
343135
  simpleStreamTextDeps,
342992
343136
  streamTurnId,
@@ -344234,7 +344378,9 @@ async function runBuildBranch(ctx, deps) {
344234
344378
  escalationMode: effectiveWorkMode === "plan" ? "plan" : effectiveWorkMode === "build" ? "build" : "agent",
344235
344379
  tools,
344236
344380
  repetition: agenticRepetition,
344237
- buildRoundSystemPrompt: () => systemPrompt,
344381
+ // The per-turn tail in its own system message, after the cached
344382
+ // header, so the next turn reads the cache instead of rewriting it.
344383
+ buildRoundSystemPrompt: () => splitDynamicTail(systemPrompt, dynamicTail),
344238
344384
  detectTextToolCalls: (fr2) => useTextToolFallback && containsTextToolCall2(fr2) ? parseTextToolCalls2(fr2) : null,
344239
344385
  executeTextToolCalls: (calls) => execBuildTextToolCalls(
344240
344386
  calls
@@ -344377,6 +344523,7 @@ var init_build_branch = __esm({
344377
344523
  init_dist21();
344378
344524
  import_electron_log102 = __toESM(require_src());
344379
344525
  init_edit_stats2();
344526
+ init_system_prompt();
344380
344527
  logger99 = import_electron_log102.default.scope("chat_stream_handlers");
344381
344528
  }
344382
344529
  });
@@ -346424,11 +346571,11 @@ function registerChatStreamHandlers() {
346424
346571
  providerBrand: modelIdentity.providerBrand,
346425
346572
  labelWithProvider: modelIdentity.labelWithProvider
346426
346573
  };
346427
- let baseSystemPrompt;
346574
+ let baseParts;
346428
346575
  if (hasWorkspace && appPath && effectiveAppId != null) {
346429
- baseSystemPrompt = await preflight.time(
346576
+ baseParts = await preflight.time(
346430
346577
  "system-prompt",
346431
- () => buildSystemPromptWithProjectInstructions({
346578
+ () => buildSystemPromptPartsWithProjectInstructions({
346432
346579
  workspacePath: appPath,
346433
346580
  workspacePromptContent: null,
346434
346581
  contextSize,
@@ -346441,7 +346588,7 @@ function registerChatStreamHandlers() {
346441
346588
  })
346442
346589
  );
346443
346590
  } else {
346444
- baseSystemPrompt = constructSystemPrompt({
346591
+ baseParts = constructSystemPromptParts({
346445
346592
  chatMode,
346446
346593
  effectiveWorkMode: modeBlockKey,
346447
346594
  contextSize,
@@ -346451,6 +346598,8 @@ function registerChatStreamHandlers() {
346451
346598
  ...promptIdentityOpts
346452
346599
  });
346453
346600
  }
346601
+ let baseSystemPrompt = joinSystemPromptParts(baseParts);
346602
+ const baseDynamicTail = baseParts.dynamicTail;
346454
346603
  if (activeUserAgent) {
346455
346604
  const { renderUserAgentSystemBlock: renderUserAgentSystemBlock2 } = await Promise.resolve().then(() => (init_user_agents(), user_agents_exports));
346456
346605
  baseSystemPrompt = `${renderUserAgentSystemBlock2(activeUserAgent)}
@@ -346960,6 +347109,7 @@ ${baseSystemPrompt}`;
346960
347109
  modelContextResolved,
346961
347110
  placeholderAssistantMessage,
346962
347111
  systemPrompt,
347112
+ dynamicTail: baseDynamicTail,
346963
347113
  taskLedgerBlock,
346964
347114
  simpleStreamTextDeps,
346965
347115
  streamTurnId,
@@ -347893,7 +348043,7 @@ ${err2.stack}` : "";
347893
348043
  }
347894
348044
 
347895
348045
  // src/headless/atlarix-headless.mts
347896
- var VERSION15 = false ? "dev" : "15.8.1";
348046
+ var VERSION15 = false ? "dev" : "15.9.0";
347897
348047
  if (process.argv[2] === "run") process.argv.splice(2, 1);
347898
348048
  var RUN_HELP = `atlarix run: one turn without the UI, for scripts and CI
347899
348049
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atlarix",
3
- "version": "15.8.1",
3
+ "version": "15.9.0",
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.8.1",
69
- "atlarix-darwin-x64": "15.8.1",
70
- "atlarix-linux-x64": "15.8.1",
71
- "atlarix-linux-arm64": "15.8.1",
72
- "atlarix-linux-x64-musl": "15.8.1",
73
- "atlarix-linux-arm64-musl": "15.8.1",
74
- "atlarix-windows-x64": "15.8.1"
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"
75
75
  }
76
76
  }