@canonry/canonry 7.46.1 → 7.47.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.
Files changed (35) hide show
  1. package/assets/assets/{AuditHistoryPanel-u65pF2eT.js → AuditHistoryPanel-BTlvVW6p.js} +1 -1
  2. package/assets/assets/{BacklinksPage-CmYpSNGB.js → BacklinksPage-DQu_3poO.js} +1 -1
  3. package/assets/assets/{HistoryPage-CqzQSAil.js → HistoryPage-D_3qu4SQ.js} +1 -1
  4. package/assets/assets/{MeasurementPropertyPage-KfpmUisb.js → MeasurementPropertyPage-FKmEMw_G.js} +1 -1
  5. package/assets/assets/{ProjectPage-BCiospUp.js → ProjectPage-H7nsLkhG.js} +1 -1
  6. package/assets/assets/{RunsPage-CzPvTnwG.js → RunsPage-CE5wFNdP.js} +1 -1
  7. package/assets/assets/{SettingsPage-CZYckyPO.js → SettingsPage-D2zKpqOv.js} +1 -1
  8. package/assets/assets/{SiteHealthSection-Bm5nWAoZ.js → SiteHealthSection-ClZRxJ-A.js} +3 -3
  9. package/assets/assets/{TrafficPage-DZw_GvaO.js → TrafficPage-BDH4Dzk0.js} +1 -1
  10. package/assets/assets/{TrafficSourceDetailPage-CD20PJ4A.js → TrafficSourceDetailPage-DaVUcHXu.js} +1 -1
  11. package/assets/assets/{extract-error-message-Cpzj_AMZ.js → extract-error-message-YXzyZAEc.js} +1 -1
  12. package/assets/assets/{index-BHLYJHa-.js → index-Zj8hd7aE.js} +3 -3
  13. package/assets/assets/{react-sigma_core.esm.min-CK2U3T7S.js → react-sigma_core.esm.min-9j5NHFWR.js} +1 -1
  14. package/assets/assets/{v2-overview-adapter-DL1IsAM2.js → v2-overview-adapter-BsKpkQvx.js} +1 -1
  15. package/assets/index.html +1 -1
  16. package/dist/{chunk-Y2QMWZT7.js → chunk-66K6U5H5.js} +3 -3
  17. package/dist/{chunk-WMG365JI.js → chunk-CIYCCA2I.js} +11 -2
  18. package/dist/{chunk-QBZPKXFW.js → chunk-DGKSQ5QD.js} +1 -1
  19. package/dist/{chunk-GWRIZSIL.js → chunk-HQS2Y7HO.js} +3 -3
  20. package/dist/{chunk-OO64BWNB.js → chunk-IYAUKA7Z.js} +251 -222
  21. package/dist/{chunk-QWLKYIQ4.js → chunk-JNBPNW7P.js} +2 -2
  22. package/dist/{chunk-IBRZ23VQ.js → chunk-QNXQHHCP.js} +36 -13
  23. package/dist/{chunk-V4TITINC.js → chunk-QS262E4F.js} +9 -1
  24. package/dist/{chunk-7R2HFAG4.js → chunk-XCS3JXN2.js} +9 -9
  25. package/dist/{chunk-PCZXWOYX.js → chunk-XHRJYIJQ.js} +1 -1
  26. package/dist/{cli-catalog-TFCCKIE4.js → cli-catalog-MRYQK7LI.js} +3 -3
  27. package/dist/cli-commands-ZX7GLZZT.js +15 -0
  28. package/dist/cli.js +10 -10
  29. package/dist/{demo-server-5TX4MJIS.js → demo-server-GPNX3EXT.js} +4 -4
  30. package/dist/index.d.ts +12 -0
  31. package/dist/index.js +6 -6
  32. package/dist/{intelligence-service-5BYJSFLW.js → intelligence-service-LZ3MC6G6.js} +2 -2
  33. package/dist/mcp.js +4 -4
  34. package/package.json +13 -13
  35. package/dist/cli-commands-JEN27DWN.js +0 -15
@@ -1,4 +1,5 @@
1
1
  import {
2
+ AGENT_REASONING_LEVELS,
2
3
  ApiClient,
3
4
  CANONRY_MCP_TIERS,
4
5
  CANONRY_MCP_TOOLKITS,
@@ -21,19 +22,19 @@ import {
21
22
  saveConfig,
22
23
  saveConfigPatch,
23
24
  sentimentInstallReadiness
24
- } from "./chunk-WMG365JI.js";
25
+ } from "./chunk-CIYCCA2I.js";
25
26
  import {
26
27
  computeFactorAverages,
27
28
  deleteSiteCrawlGraphLayout,
28
29
  persistSiteCrawlGraphLayout,
29
30
  prepareSiteCrawlGraphLayout,
30
31
  recordedSharePct
31
- } from "./chunk-QWLKYIQ4.js";
32
+ } from "./chunk-JNBPNW7P.js";
32
33
  import {
33
34
  CanonryMcpToolNames,
34
35
  PACKAGE_VERSION,
35
36
  canonryMcpTools
36
- } from "./chunk-PCZXWOYX.js";
37
+ } from "./chunk-XHRJYIJQ.js";
37
38
  import {
38
39
  CliError
39
40
  } from "./chunk-HGMYEDAQ.js";
@@ -240,7 +241,7 @@ import {
240
241
  webhookResponseReason,
241
242
  webhookTargetRefusalReason,
242
243
  writeAuditLog
243
- } from "./chunk-IBRZ23VQ.js";
244
+ } from "./chunk-QNXQHHCP.js";
244
245
  import {
245
246
  AGENT_MEMORY_VALUE_MAX_BYTES,
246
247
  AGENT_NONE,
@@ -488,7 +489,7 @@ import {
488
489
  winnabilityClassLabel,
489
490
  withRetry,
490
491
  withSkippedProviders
491
- } from "./chunk-V4TITINC.js";
492
+ } from "./chunk-QS262E4F.js";
492
493
 
493
494
  // src/runtime-context.ts
494
495
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -3586,16 +3587,14 @@ var DefaultGoogleMarketingRuntime = class {
3586
3587
  "INVALID_INPUT"
3587
3588
  );
3588
3589
  }
3589
- const selectedWorkspace = selectedWorkspaceId ? workspaceDtos.find((candidate) => candidate.id === selectedWorkspaceId) : void 0;
3590
- if (selectedWorkspaceId && !selectedWorkspace) {
3591
- throw new GoogleMarketingRuntimeError("Selected GTM workspace was not found", "RESOURCE_NOT_FOUND");
3592
- }
3590
+ const selectedWorkspaceExists = selectedWorkspaceId !== null && workspaceDtos.some((candidate) => candidate.id === selectedWorkspaceId);
3591
+ const workspaceId = selectedWorkspaceId === null || selectedWorkspaceExists ? selectedWorkspaceId : workspaceDtos.length === 1 ? workspaceDtos[0].id : null;
3593
3592
  const snapshotReads = [
3594
3593
  client.getLiveSnapshot(selectedContainerPath)
3595
3594
  ];
3596
- if (selectedWorkspaceId) {
3595
+ if (workspaceId) {
3597
3596
  snapshotReads.push(client.getWorkspaceSnapshot(
3598
- workspacePath(selectedAccountId, selectedContainerId, selectedWorkspaceId)
3597
+ workspacePath(selectedAccountId, selectedContainerId, workspaceId)
3599
3598
  ));
3600
3599
  }
3601
3600
  const snapshots = await Promise.all(snapshotReads);
@@ -3624,7 +3623,7 @@ var DefaultGoogleMarketingRuntime = class {
3624
3623
  payload,
3625
3624
  selectedAccountId,
3626
3625
  selectedContainerId,
3627
- selectedWorkspaceId,
3626
+ workspaceId,
3628
3627
  raw,
3629
3628
  capturedAt
3630
3629
  );
@@ -3714,7 +3713,7 @@ import path10 from "path";
3714
3713
  import { isIP } from "net";
3715
3714
  import { fileURLToPath as fileURLToPath3 } from "url";
3716
3715
  import { setImmediate as yieldToEventLoop4 } from "timers/promises";
3717
- import { and as and25, eq as eq31, isNotNull as isNotNull5, isNull as isNull5, lte as lte2, max, ne as ne4, or as or3, sql as sql12 } from "drizzle-orm";
3716
+ import { and as and25, eq as eq31, isNotNull as isNotNull5, isNull as isNull5, lte as lte2, max, ne as ne4, or as or3, sql as sql13 } from "drizzle-orm";
3718
3717
 
3719
3718
  // ../integration-typesafe/src/classifier.ts
3720
3719
  import { createHash } from "crypto";
@@ -7898,6 +7897,216 @@ function resolveEmbedConfig(env, config) {
7898
7897
  };
7899
7898
  }
7900
7899
 
7900
+ // src/agent/providers.ts
7901
+ import "@earendil-works/pi-ai";
7902
+
7903
+ // src/agent/pi-models.ts
7904
+ import "@earendil-works/pi-ai";
7905
+ import { builtinModels } from "@earendil-works/pi-ai/providers/all";
7906
+ var aeroModels = builtinModels();
7907
+ var DEFAULT_MAX_RETRIES = 2;
7908
+ var DEFAULT_MAX_OUTPUT_TOKENS = 32e3;
7909
+ var CANONRY_USER_AGENT = "canonry";
7910
+ var STAINLESS_HOST_HEADERS = {
7911
+ "X-Stainless-OS": null,
7912
+ "X-Stainless-Arch": null,
7913
+ "X-Stainless-Runtime-Version": null
7914
+ };
7915
+ var HOST_HEADERS = {
7916
+ "anthropic-messages": STAINLESS_HOST_HEADERS,
7917
+ "openai-responses": STAINLESS_HOST_HEADERS,
7918
+ "openai-completions": STAINLESS_HOST_HEADERS,
7919
+ "google-generative-ai": { "x-goog-api-client": CANONRY_USER_AGENT }
7920
+ };
7921
+ function outputCap(model) {
7922
+ return Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS);
7923
+ }
7924
+ function canonryDefaults(model, options) {
7925
+ return {
7926
+ ...options,
7927
+ maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES,
7928
+ maxTokens: options?.maxTokens ?? outputCap(model),
7929
+ headers: { "User-Agent": CANONRY_USER_AGENT, ...HOST_HEADERS[model.api], ...options?.headers }
7930
+ };
7931
+ }
7932
+ var aeroStreamFn = (model, context, options) => aeroModels.streamSimple(model, context, canonryDefaults(model, options));
7933
+ function completeOnce(model, context, options = {}) {
7934
+ return aeroModels.complete(model, context, canonryDefaults(model, options));
7935
+ }
7936
+
7937
+ // src/agent/providers.ts
7938
+ var PROVIDER_MODELS = {
7939
+ [AgentProviderIds.claude]: {
7940
+ [LlmCapabilities.agent]: "claude-opus-4-7",
7941
+ [LlmCapabilities.analyze]: "claude-sonnet-4-6",
7942
+ [LlmCapabilities.classify]: "claude-haiku-4-5"
7943
+ },
7944
+ [AgentProviderIds.openai]: {
7945
+ [LlmCapabilities.agent]: "gpt-5.1",
7946
+ [LlmCapabilities.analyze]: "gpt-5-mini",
7947
+ [LlmCapabilities.classify]: "gpt-5-nano"
7948
+ },
7949
+ [AgentProviderIds.gemini]: {
7950
+ // Gemini's Flash is already cheap + capable; Flash-Lite is the
7951
+ // dedicated micro tier for classify. Analyze stays on flash because
7952
+ // flash-lite drops too much quality for structured synthesis.
7953
+ // Exact IDs, never Google's `-latest` aliases: pi-ai derives request
7954
+ // options (thinking level) from the catalog entry for the ID it is given,
7955
+ // and an alias entry can lag the model it serves. `gemini-flash-latest`
7956
+ // allows MINIMAL thinking while the 3.8 Flash it resolves to rejects it,
7957
+ // so every Aero turn failed. Sweeps can use the alias; Aero cannot.
7958
+ [LlmCapabilities.agent]: "gemini-3.8-flash",
7959
+ [LlmCapabilities.analyze]: "gemini-3.8-flash",
7960
+ [LlmCapabilities.classify]: "gemini-3.5-flash-lite"
7961
+ },
7962
+ [AgentProviderIds.zai]: {
7963
+ // GLM lineage: 5.2 replaced 5.1, which pi-ai 0.87 dropped from its
7964
+ // catalog; 5-turbo is the cheaper tier good for structured tasks and
7965
+ // classification.
7966
+ [LlmCapabilities.agent]: "glm-5.2",
7967
+ [LlmCapabilities.analyze]: "glm-5-turbo",
7968
+ [LlmCapabilities.classify]: "glm-5-turbo"
7969
+ }
7970
+ };
7971
+ var PROVIDER_DEFAULT_REASONING = {
7972
+ [AgentProviderIds.claude]: "off",
7973
+ [AgentProviderIds.openai]: "low",
7974
+ [AgentProviderIds.gemini]: "off",
7975
+ [AgentProviderIds.zai]: "off"
7976
+ };
7977
+ var AGENT_PROVIDERS = {
7978
+ [AgentProviderIds.claude]: {
7979
+ piAiProvider: "anthropic",
7980
+ label: "Anthropic (Claude)",
7981
+ defaultModel: PROVIDER_MODELS[AgentProviderIds.claude][LlmCapabilities.agent],
7982
+ autoDetectPriority: 0
7983
+ },
7984
+ [AgentProviderIds.openai]: {
7985
+ piAiProvider: "openai",
7986
+ label: "OpenAI",
7987
+ defaultModel: PROVIDER_MODELS[AgentProviderIds.openai][LlmCapabilities.agent],
7988
+ autoDetectPriority: 1
7989
+ },
7990
+ [AgentProviderIds.gemini]: {
7991
+ piAiProvider: "google",
7992
+ label: "Google (Gemini)",
7993
+ defaultModel: PROVIDER_MODELS[AgentProviderIds.gemini][LlmCapabilities.agent],
7994
+ autoDetectPriority: 2
7995
+ },
7996
+ [AgentProviderIds.zai]: {
7997
+ piAiProvider: "zai",
7998
+ label: "Z.ai (GLM)",
7999
+ defaultModel: PROVIDER_MODELS[AgentProviderIds.zai][LlmCapabilities.agent],
8000
+ autoDetectPriority: 3
8001
+ }
8002
+ };
8003
+ function agentProvidersByPriority() {
8004
+ return Object.keys(AGENT_PROVIDERS).slice().sort((a, b) => AGENT_PROVIDERS[a].autoDetectPriority - AGENT_PROVIDERS[b].autoDetectPriority);
8005
+ }
8006
+ function listAgentProviders() {
8007
+ return AGENT_PROVIDER_IDS;
8008
+ }
8009
+ function getAgentProvider(name) {
8010
+ return AGENT_PROVIDERS[name];
8011
+ }
8012
+ function coerceAgentProvider(value) {
8013
+ if (!value) return void 0;
8014
+ return isAgentProviderId(value) ? value : void 0;
8015
+ }
8016
+ function resolveModelForProvider(provider, modelId) {
8017
+ return resolveModelForCapability(provider, LlmCapabilities.agent, modelId);
8018
+ }
8019
+ function resolveModelForCapability(provider, capability, modelIdOverride) {
8020
+ const entry = AGENT_PROVIDERS[provider];
8021
+ const id = modelIdOverride ?? PROVIDER_MODELS[provider][capability];
8022
+ const model = aeroModels.getModel(entry.piAiProvider, id);
8023
+ if (!model) {
8024
+ throw new Error(
8025
+ `Model '${id}' not found for pi-ai provider '${entry.piAiProvider}'. Verify PROVIDER_MODELS[${provider}][${capability}] against the installed @earendil-works/pi-ai catalog.`
8026
+ );
8027
+ }
8028
+ if (provider === AgentProviderIds.gemini && process.env.GEMINI_BASE_URL) {
8029
+ const base = process.env.GEMINI_BASE_URL.replace(/\/+$/, "");
8030
+ const baseUrl = base.endsWith("/v1beta") ? base : `${base}/v1beta`;
8031
+ return { ...model, baseUrl };
8032
+ }
8033
+ if (provider === AgentProviderIds.zai && process.env.ZAI_BASE_URL) {
8034
+ const baseUrl = process.env.ZAI_BASE_URL.replace(/\/+$/, "");
8035
+ return { ...model, baseUrl };
8036
+ }
8037
+ return model;
8038
+ }
8039
+ function isAgentModelAvailable(provider, id) {
8040
+ return !!aeroModels.getModel(AGENT_PROVIDERS[provider].piAiProvider, id);
8041
+ }
8042
+ function validateAgentProviderRegistry() {
8043
+ for (const provider of listAgentProviders()) {
8044
+ for (const capability of LLM_CAPABILITIES) {
8045
+ resolveModelForCapability(provider, capability);
8046
+ }
8047
+ const entry = AGENT_PROVIDERS[provider];
8048
+ const agentModel = PROVIDER_MODELS[provider][LlmCapabilities.agent];
8049
+ if (entry.defaultModel !== agentModel) {
8050
+ throw new Error(
8051
+ `AGENT_PROVIDERS[${provider}].defaultModel ('${entry.defaultModel}') does not match PROVIDER_MODELS[${provider}].agent ('${agentModel}'). The two must stay in sync \u2014 defaultModel is a backward-compat shortcut to the agent-tier model.`
8052
+ );
8053
+ }
8054
+ }
8055
+ }
8056
+ function resolveApiKeyFor(providerOrPiAi, config) {
8057
+ return resolveApiKeySource(providerOrPiAi, config)?.key;
8058
+ }
8059
+ function resolveApiKeySource(providerOrPiAi, config) {
8060
+ const id = resolveAgentId(providerOrPiAi);
8061
+ if (!id) return void 0;
8062
+ const fromConfig = config.providers?.[id]?.apiKey;
8063
+ if (fromConfig) return { key: fromConfig, source: "config" };
8064
+ const fromEnv = agentProviderApiKeyEnvVars(id).map((name) => process.env[name]).find((value) => !!value);
8065
+ if (fromEnv) return { key: fromEnv, source: "env" };
8066
+ return void 0;
8067
+ }
8068
+ var CATALOG_API_KEY_ENV_VARS = {
8069
+ anthropic: ["ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"],
8070
+ openai: ["OPENAI_API_KEY"],
8071
+ google: ["GEMINI_API_KEY"],
8072
+ zai: ["ZAI_API_KEY"]
8073
+ };
8074
+ function agentProviderApiKeyEnvVars(id) {
8075
+ const entry = AGENT_PROVIDERS[id];
8076
+ return CATALOG_API_KEY_ENV_VARS[entry.piAiProvider] ?? [`${entry.piAiProvider.toUpperCase()}_API_KEY`];
8077
+ }
8078
+ function agentProviderApiKeyEnvVar(id) {
8079
+ const names = agentProviderApiKeyEnvVars(id);
8080
+ return names[names.length - 1];
8081
+ }
8082
+ function resolveAgentId(providerOrPiAi) {
8083
+ if (isAgentProviderId(providerOrPiAi)) return providerOrPiAi;
8084
+ for (const id of AGENT_PROVIDER_IDS) {
8085
+ if (AGENT_PROVIDERS[id].piAiProvider === providerOrPiAi) return id;
8086
+ }
8087
+ return void 0;
8088
+ }
8089
+ function buildAgentProvidersResponse(config) {
8090
+ const pinned = coerceAgentProvider(config.agent?.provider ?? void 0);
8091
+ const pinnedModel = pinned ? config.agent?.model ?? void 0 : void 0;
8092
+ const providers = listAgentProviders().map((id) => {
8093
+ const entry = AGENT_PROVIDERS[id];
8094
+ const source = resolveApiKeySource(id, config);
8095
+ return {
8096
+ id,
8097
+ label: entry.label,
8098
+ defaultModel: id === pinned && pinnedModel ? pinnedModel : entry.defaultModel,
8099
+ configured: source !== void 0,
8100
+ keySource: source?.source ?? null
8101
+ };
8102
+ });
8103
+ const firstConfigured = agentProvidersByPriority().find((p) => resolveApiKeySource(p, config));
8104
+ return {
8105
+ providers,
8106
+ defaultProvider: pinned ?? firstConfigured ?? null
8107
+ };
8108
+ }
8109
+
7901
8110
  // src/agent-config.ts
7902
8111
  function resolveAgentEnabled(env, config) {
7903
8112
  const raw = env.CANONRY_AGENT_DISABLED?.trim();
@@ -7918,6 +8127,11 @@ function resolveAgentAllowViewers(env, config) {
7918
8127
  if (raw) return raw === "1" || raw.toLowerCase() === "true";
7919
8128
  return config.agent?.allowViewers === true;
7920
8129
  }
8130
+ function resolveAgentReasoning(env, config, provider) {
8131
+ const raw = env.CANONRY_AGENT_REASONING?.trim().toLowerCase();
8132
+ if (raw && AGENT_REASONING_LEVELS.includes(raw)) return raw;
8133
+ return config.agent?.reasoning ?? PROVIDER_DEFAULT_REASONING[provider];
8134
+ }
7921
8135
 
7922
8136
  // src/places-config.ts
7923
8137
  var DEFAULT_TIER = "atmosphere";
@@ -8379,7 +8593,7 @@ function nonBlank(value) {
8379
8593
  return trimmed ? trimmed : void 0;
8380
8594
  }
8381
8595
  function resolveBuildCommit(env = process.env) {
8382
- const embedded = true ? "d2f4f0349b43d56e3cb425dfe64da3dcefa565ea" : void 0;
8596
+ const embedded = true ? "6f65fc00d407b63da0801a4f151064d5f7065440" : void 0;
8383
8597
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
8384
8598
  }
8385
8599
  function resolveInstanceIdentity(env = process.env) {
@@ -15433,210 +15647,6 @@ function recordLlmUsageEvent(args) {
15433
15647
  }
15434
15648
  }
15435
15649
 
15436
- // src/agent/providers.ts
15437
- import "@earendil-works/pi-ai";
15438
-
15439
- // src/agent/pi-models.ts
15440
- import "@earendil-works/pi-ai";
15441
- import { builtinModels } from "@earendil-works/pi-ai/providers/all";
15442
- var aeroModels = builtinModels();
15443
- var DEFAULT_MAX_RETRIES = 2;
15444
- var DEFAULT_MAX_OUTPUT_TOKENS = 32e3;
15445
- var CANONRY_USER_AGENT = "canonry";
15446
- var STAINLESS_HOST_HEADERS = {
15447
- "X-Stainless-OS": null,
15448
- "X-Stainless-Arch": null,
15449
- "X-Stainless-Runtime-Version": null
15450
- };
15451
- var HOST_HEADERS = {
15452
- "anthropic-messages": STAINLESS_HOST_HEADERS,
15453
- "openai-responses": STAINLESS_HOST_HEADERS,
15454
- "openai-completions": STAINLESS_HOST_HEADERS,
15455
- "google-generative-ai": { "x-goog-api-client": CANONRY_USER_AGENT }
15456
- };
15457
- function outputCap(model) {
15458
- return Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS);
15459
- }
15460
- function canonryDefaults(model, options) {
15461
- return {
15462
- ...options,
15463
- maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES,
15464
- maxTokens: options?.maxTokens ?? outputCap(model),
15465
- headers: { "User-Agent": CANONRY_USER_AGENT, ...HOST_HEADERS[model.api], ...options?.headers }
15466
- };
15467
- }
15468
- var aeroStreamFn = (model, context, options) => aeroModels.streamSimple(model, context, canonryDefaults(model, options));
15469
- function completeOnce(model, context, options = {}) {
15470
- return aeroModels.complete(model, context, canonryDefaults(model, options));
15471
- }
15472
-
15473
- // src/agent/providers.ts
15474
- var PROVIDER_MODELS = {
15475
- [AgentProviderIds.claude]: {
15476
- [LlmCapabilities.agent]: "claude-opus-4-7",
15477
- [LlmCapabilities.analyze]: "claude-sonnet-4-6",
15478
- [LlmCapabilities.classify]: "claude-haiku-4-5"
15479
- },
15480
- [AgentProviderIds.openai]: {
15481
- [LlmCapabilities.agent]: "gpt-5.1",
15482
- [LlmCapabilities.analyze]: "gpt-5-mini",
15483
- [LlmCapabilities.classify]: "gpt-5-nano"
15484
- },
15485
- [AgentProviderIds.gemini]: {
15486
- // Gemini's Flash is already cheap + capable; Flash-Lite is the
15487
- // dedicated micro tier for classify. Analyze stays on flash because
15488
- // flash-lite drops too much quality for structured synthesis.
15489
- // Exact IDs, never Google's `-latest` aliases: pi-ai derives request
15490
- // options (thinking level) from the catalog entry for the ID it is given,
15491
- // and an alias entry can lag the model it serves. `gemini-flash-latest`
15492
- // allows MINIMAL thinking while the 3.8 Flash it resolves to rejects it,
15493
- // so every Aero turn failed. Sweeps can use the alias; Aero cannot.
15494
- [LlmCapabilities.agent]: "gemini-3.8-flash",
15495
- [LlmCapabilities.analyze]: "gemini-3.8-flash",
15496
- [LlmCapabilities.classify]: "gemini-3.5-flash-lite"
15497
- },
15498
- [AgentProviderIds.zai]: {
15499
- // GLM lineage: 5.2 replaced 5.1, which pi-ai 0.87 dropped from its
15500
- // catalog; 5-turbo is the cheaper tier good for structured tasks and
15501
- // classification.
15502
- [LlmCapabilities.agent]: "glm-5.2",
15503
- [LlmCapabilities.analyze]: "glm-5-turbo",
15504
- [LlmCapabilities.classify]: "glm-5-turbo"
15505
- }
15506
- };
15507
- var AGENT_PROVIDERS = {
15508
- [AgentProviderIds.claude]: {
15509
- piAiProvider: "anthropic",
15510
- label: "Anthropic (Claude)",
15511
- defaultModel: PROVIDER_MODELS[AgentProviderIds.claude][LlmCapabilities.agent],
15512
- autoDetectPriority: 0
15513
- },
15514
- [AgentProviderIds.openai]: {
15515
- piAiProvider: "openai",
15516
- label: "OpenAI",
15517
- defaultModel: PROVIDER_MODELS[AgentProviderIds.openai][LlmCapabilities.agent],
15518
- autoDetectPriority: 1
15519
- },
15520
- [AgentProviderIds.gemini]: {
15521
- piAiProvider: "google",
15522
- label: "Google (Gemini)",
15523
- defaultModel: PROVIDER_MODELS[AgentProviderIds.gemini][LlmCapabilities.agent],
15524
- autoDetectPriority: 2
15525
- },
15526
- [AgentProviderIds.zai]: {
15527
- piAiProvider: "zai",
15528
- label: "Z.ai (GLM)",
15529
- defaultModel: PROVIDER_MODELS[AgentProviderIds.zai][LlmCapabilities.agent],
15530
- autoDetectPriority: 3
15531
- }
15532
- };
15533
- function agentProvidersByPriority() {
15534
- return Object.keys(AGENT_PROVIDERS).slice().sort((a, b) => AGENT_PROVIDERS[a].autoDetectPriority - AGENT_PROVIDERS[b].autoDetectPriority);
15535
- }
15536
- function listAgentProviders() {
15537
- return AGENT_PROVIDER_IDS;
15538
- }
15539
- function getAgentProvider(name) {
15540
- return AGENT_PROVIDERS[name];
15541
- }
15542
- function coerceAgentProvider(value) {
15543
- if (!value) return void 0;
15544
- return isAgentProviderId(value) ? value : void 0;
15545
- }
15546
- function resolveModelForProvider(provider, modelId) {
15547
- return resolveModelForCapability(provider, LlmCapabilities.agent, modelId);
15548
- }
15549
- function resolveModelForCapability(provider, capability, modelIdOverride) {
15550
- const entry = AGENT_PROVIDERS[provider];
15551
- const id = modelIdOverride ?? PROVIDER_MODELS[provider][capability];
15552
- const model = aeroModels.getModel(entry.piAiProvider, id);
15553
- if (!model) {
15554
- throw new Error(
15555
- `Model '${id}' not found for pi-ai provider '${entry.piAiProvider}'. Verify PROVIDER_MODELS[${provider}][${capability}] against the installed @earendil-works/pi-ai catalog.`
15556
- );
15557
- }
15558
- if (provider === AgentProviderIds.gemini && process.env.GEMINI_BASE_URL) {
15559
- const base = process.env.GEMINI_BASE_URL.replace(/\/+$/, "");
15560
- const baseUrl = base.endsWith("/v1beta") ? base : `${base}/v1beta`;
15561
- return { ...model, baseUrl };
15562
- }
15563
- if (provider === AgentProviderIds.zai && process.env.ZAI_BASE_URL) {
15564
- const baseUrl = process.env.ZAI_BASE_URL.replace(/\/+$/, "");
15565
- return { ...model, baseUrl };
15566
- }
15567
- return model;
15568
- }
15569
- function isAgentModelAvailable(provider, id) {
15570
- return !!aeroModels.getModel(AGENT_PROVIDERS[provider].piAiProvider, id);
15571
- }
15572
- function validateAgentProviderRegistry() {
15573
- for (const provider of listAgentProviders()) {
15574
- for (const capability of LLM_CAPABILITIES) {
15575
- resolveModelForCapability(provider, capability);
15576
- }
15577
- const entry = AGENT_PROVIDERS[provider];
15578
- const agentModel = PROVIDER_MODELS[provider][LlmCapabilities.agent];
15579
- if (entry.defaultModel !== agentModel) {
15580
- throw new Error(
15581
- `AGENT_PROVIDERS[${provider}].defaultModel ('${entry.defaultModel}') does not match PROVIDER_MODELS[${provider}].agent ('${agentModel}'). The two must stay in sync \u2014 defaultModel is a backward-compat shortcut to the agent-tier model.`
15582
- );
15583
- }
15584
- }
15585
- }
15586
- function resolveApiKeyFor(providerOrPiAi, config) {
15587
- return resolveApiKeySource(providerOrPiAi, config)?.key;
15588
- }
15589
- function resolveApiKeySource(providerOrPiAi, config) {
15590
- const id = resolveAgentId(providerOrPiAi);
15591
- if (!id) return void 0;
15592
- const fromConfig = config.providers?.[id]?.apiKey;
15593
- if (fromConfig) return { key: fromConfig, source: "config" };
15594
- const fromEnv = agentProviderApiKeyEnvVars(id).map((name) => process.env[name]).find((value) => !!value);
15595
- if (fromEnv) return { key: fromEnv, source: "env" };
15596
- return void 0;
15597
- }
15598
- var CATALOG_API_KEY_ENV_VARS = {
15599
- anthropic: ["ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"],
15600
- openai: ["OPENAI_API_KEY"],
15601
- google: ["GEMINI_API_KEY"],
15602
- zai: ["ZAI_API_KEY"]
15603
- };
15604
- function agentProviderApiKeyEnvVars(id) {
15605
- const entry = AGENT_PROVIDERS[id];
15606
- return CATALOG_API_KEY_ENV_VARS[entry.piAiProvider] ?? [`${entry.piAiProvider.toUpperCase()}_API_KEY`];
15607
- }
15608
- function agentProviderApiKeyEnvVar(id) {
15609
- const names = agentProviderApiKeyEnvVars(id);
15610
- return names[names.length - 1];
15611
- }
15612
- function resolveAgentId(providerOrPiAi) {
15613
- if (isAgentProviderId(providerOrPiAi)) return providerOrPiAi;
15614
- for (const id of AGENT_PROVIDER_IDS) {
15615
- if (AGENT_PROVIDERS[id].piAiProvider === providerOrPiAi) return id;
15616
- }
15617
- return void 0;
15618
- }
15619
- function buildAgentProvidersResponse(config) {
15620
- const pinned = coerceAgentProvider(config.agent?.provider ?? void 0);
15621
- const pinnedModel = pinned ? config.agent?.model ?? void 0 : void 0;
15622
- const providers = listAgentProviders().map((id) => {
15623
- const entry = AGENT_PROVIDERS[id];
15624
- const source = resolveApiKeySource(id, config);
15625
- return {
15626
- id,
15627
- label: entry.label,
15628
- defaultModel: id === pinned && pinnedModel ? pinnedModel : entry.defaultModel,
15629
- configured: source !== void 0,
15630
- keySource: source?.source ?? null
15631
- };
15632
- });
15633
- const firstConfigured = agentProvidersByPriority().find((p) => resolveApiKeySource(p, config));
15634
- return {
15635
- providers,
15636
- defaultProvider: pinned ?? firstConfigured ?? null
15637
- };
15638
- }
15639
-
15640
15650
  // src/agent/session.ts
15641
15651
  import fs10 from "fs";
15642
15652
  import path9 from "path";
@@ -17614,6 +17624,7 @@ function createAeroSession(opts) {
17614
17624
  const provider = opts.provider ?? detectAgentProvider(opts.config);
17615
17625
  if (!provider) throw new Error(missingProviderMessage());
17616
17626
  const model = resolveAeroModel(provider, opts.modelId);
17627
+ const thinkingLevel = resolveAgentReasoning(process.env, opts.config, provider);
17617
17628
  const toolScope = opts.toolScope ?? AeroToolScopes.all;
17618
17629
  const toolProfile = opts.toolProfile ?? AeroToolProfiles.default;
17619
17630
  const toolCtx = {
@@ -17633,6 +17644,7 @@ function createAeroSession(opts) {
17633
17644
  initialState: {
17634
17645
  systemPrompt,
17635
17646
  model,
17647
+ thinkingLevel,
17636
17648
  tools,
17637
17649
  ...opts.initialMessages ? { messages: opts.initialMessages } : {}
17638
17650
  },
@@ -20966,6 +20978,7 @@ ${lines.join("\n")}
20966
20978
  const { provider: nextProvider, modelId: nextModelId } = this.resolveTurnModel(preferences, { provider: row.modelProvider, modelId: row.modelId });
20967
20979
  if (nextProvider === currentProvider && nextModelId === currentModelId) return;
20968
20980
  agent.state.model = resolveAeroModel(nextProvider, nextModelId);
20981
+ agent.state.thinkingLevel = resolveAgentReasoning(process.env, this.opts.config, nextProvider);
20969
20982
  this.opts.db.update(agentSessions).set({
20970
20983
  modelProvider: nextProvider,
20971
20984
  modelId: nextModelId,
@@ -22917,7 +22930,7 @@ function finalizeResearchRun(db, runId, fatalError) {
22917
22930
  }
22918
22931
 
22919
22932
  // src/google-marketing-sync.ts
22920
- import { and as and24, eq as eq30, isNull as isNull4 } from "drizzle-orm";
22933
+ import { and as and24, eq as eq30, isNull as isNull4, sql as sql12 } from "drizzle-orm";
22921
22934
  var RUNTIME_FAILURE_REASONS = {
22922
22935
  INVALID_INPUT: OutcomeReasonCodes.VALIDATION,
22923
22936
  NOT_CONFIGURED: OutcomeReasonCodes.NOT_CONNECTED,
@@ -23146,10 +23159,12 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
23146
23159
  throw new Error("Google Marketing runtime returned the wrong GTM snapshot kind.");
23147
23160
  }
23148
23161
  const graph = snapshot.payload.data;
23149
- if (snapshot.metadata.accountId !== connection.selectedAccountId || snapshot.metadata.containerId !== connection.selectedContainerId || snapshot.metadata.workspaceId !== connection.selectedWorkspaceId) {
23162
+ const workspaceId = snapshot.metadata.workspaceId;
23163
+ const workspaceReplaced = connection.selectedWorkspaceId !== null && workspaceId !== connection.selectedWorkspaceId && !graph.workspaces.some((workspace) => workspace.id === connection.selectedWorkspaceId) && (workspaceId === null || graph.workspaces.length === 1 && graph.workspaces[0].id === workspaceId);
23164
+ if (snapshot.metadata.accountId !== connection.selectedAccountId || snapshot.metadata.containerId !== connection.selectedContainerId || workspaceId !== connection.selectedWorkspaceId && !workspaceReplaced) {
23150
23165
  throw new Error("GTM returned evidence for a different account, container, or workspace.");
23151
23166
  }
23152
- const selectedWorkspace = connection.selectedWorkspaceId ? graph.workspaces.find((workspace) => workspace.id === connection.selectedWorkspaceId) : null;
23167
+ const selectedWorkspace = workspaceId ? graph.workspaces.find((workspace) => workspace.id === workspaceId) : null;
23153
23168
  const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
23154
23169
  db.transaction((tx) => {
23155
23170
  const terminalClaim = tx.update(runs).set({
@@ -23173,6 +23188,10 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
23173
23188
  selectedContainerName: graph.container.name,
23174
23189
  selectedContainerPublicId: graph.container.publicId,
23175
23190
  selectedWorkspaceName: selectedWorkspace?.name ?? null,
23191
+ ...workspaceReplaced ? {
23192
+ selectedWorkspaceId: workspaceId,
23193
+ selectionGeneration: sql12`${gtmConnections.selectionGeneration} + 1`
23194
+ } : {},
23176
23195
  lastValidatedAt: snapshot.metadata.capturedAt,
23177
23196
  lastSnapshotAt: snapshot.metadata.capturedAt,
23178
23197
  lastSnapshotId: snapshot.metadata.id,
@@ -23192,6 +23211,16 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
23192
23211
  );
23193
23212
  }
23194
23213
  tx.insert(gtmRawSnapshots).values(gtmSnapshotValues(snapshot)).run();
23214
+ if (workspaceReplaced) {
23215
+ writeAuditLog(tx, {
23216
+ projectId,
23217
+ actor: "system",
23218
+ action: "gtm.workspace-followed",
23219
+ entityType: "gtm-connection",
23220
+ entityId: connection.id,
23221
+ diff: { from: connection.selectedWorkspaceId, to: workspaceId }
23222
+ });
23223
+ }
23195
23224
  });
23196
23225
  reportOutcome({ status: OutcomeStatuses.succeeded, counts: { items: (graph.live ?? graph.draft)?.graph.tags.length ?? 0 } });
23197
23226
  } catch (error) {
@@ -24826,7 +24855,7 @@ async function createServer(opts) {
24826
24855
  const recomputeDebts = /* @__PURE__ */ new Map();
24827
24856
  let recomputeSequence = 0;
24828
24857
  const markAnswerFieldRecompute = (projectId, full) => {
24829
- opts.db.update(projects).set({ answerFieldsRecompute: full ? "full" : sql12`CASE WHEN ${projects.answerFieldsRecompute} = 'full' THEN 'full' ELSE 'competitors' END` }).where(eq31(projects.id, projectId)).run();
24858
+ opts.db.update(projects).set({ answerFieldsRecompute: full ? "full" : sql13`CASE WHEN ${projects.answerFieldsRecompute} = 'full' THEN 'full' ELSE 'competitors' END` }).where(eq31(projects.id, projectId)).run();
24830
24859
  };
24831
24860
  const requestAnswerFieldRecompute = (projectId, projectName, scope, reason) => {
24832
24861
  const sequence = ++recomputeSequence;
@@ -5,7 +5,7 @@ import {
5
5
  siteCrawlGraphNodes,
6
6
  siteCrawlPages,
7
7
  siteCrawlSnapshots
8
- } from "./chunk-IBRZ23VQ.js";
8
+ } from "./chunk-QNXQHHCP.js";
9
9
  import {
10
10
  SITE_CRAWL_GRAPH_MAX_EDGES,
11
11
  SITE_CRAWL_GRAPH_MAX_NODES,
@@ -15,7 +15,7 @@ import {
15
15
  factorStatusFromDistribution,
16
16
  factorStatusFromScore,
17
17
  roundPreservingTotal
18
- } from "./chunk-V4TITINC.js";
18
+ } from "./chunk-QS262E4F.js";
19
19
 
20
20
  // src/site-audit-factors.ts
21
21
  function recordedSharePct(factor) {