@canonry/canonry 5.10.0 → 5.12.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.
Files changed (33) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +13 -2
  2. package/assets/assets/{AuditHistoryPanel-C1mws7FA.js → AuditHistoryPanel-DL_NSpfm.js} +1 -1
  3. package/assets/assets/{BacklinksPage-DP9BUn0y.js → BacklinksPage-BtcBybtX.js} +1 -1
  4. package/assets/assets/{HistoryPage-Bmo40fKZ.js → HistoryPage-jXj-qi9c.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-DyqZVFEx.js → MeasurementPropertyPage-DKw401ok.js} +1 -1
  6. package/assets/assets/{ProjectPage-DBJvI-H1.js → ProjectPage-og4qfFFD.js} +1 -1
  7. package/assets/assets/{RunRow-BSZcQ0v6.js → RunRow-nK5iaZe1.js} +1 -1
  8. package/assets/assets/{RunsPage-CIkLV-XY.js → RunsPage-CMgr3YSF.js} +1 -1
  9. package/assets/assets/{SettingsPage-TJ6l-L5i.js → SettingsPage-QtElCcew.js} +1 -1
  10. package/assets/assets/{SiteHealthSection-CKvDNoSp.js → SiteHealthSection-DNdVVl30.js} +3 -3
  11. package/assets/assets/{TrafficPage-BNaCL4v4.js → TrafficPage-C0WgvfRj.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-WQu7Tf56.js → TrafficSourceDetailPage-jOTedQtt.js} +1 -1
  13. package/assets/assets/{extract-error-message-DMgow2EC.js → extract-error-message-DO_053o0.js} +1 -1
  14. package/assets/assets/index-CnVwWE3V.js +86 -0
  15. package/assets/assets/{index-DQw9KQwS.css → index-EJC8PSbh.css} +1 -1
  16. package/assets/assets/{react-sigma_core.esm.min-YECPUDRj.js → react-sigma_core.esm.min-DJttq2UK.js} +1 -1
  17. package/assets/assets/{v2-overview-adapter-BFf9y-xb.js → v2-overview-adapter-BC_oa__K.js} +1 -1
  18. package/assets/assets/{vendor-lucide-2cuPDw3H.js → vendor-lucide-N6vOpZmh.js} +1 -1
  19. package/assets/index.html +3 -3
  20. package/dist/{chunk-KBPSOB55.js → chunk-DOC4QQLS.js} +2110 -1871
  21. package/dist/{chunk-W67ORZUR.js → chunk-KBSAEALE.js} +123 -32
  22. package/dist/{chunk-S7D23FEE.js → chunk-LWGYRN3T.js} +2 -2
  23. package/dist/{chunk-KEMMVSAQ.js → chunk-NYRRWWEE.js} +50 -2
  24. package/dist/{chunk-HF6MAKWE.js → chunk-S4BIBUCK.js} +2 -2
  25. package/dist/{chunk-GQ37ALYP.js → chunk-WJGUBZSW.js} +209 -52
  26. package/dist/cli.js +106 -14
  27. package/dist/{demo-server-DKH73GRD.js → demo-server-OTXS6ZHS.js} +3 -3
  28. package/dist/index.d.ts +28 -1
  29. package/dist/index.js +5 -5
  30. package/dist/{intelligence-service-7PVUFJTX.js → intelligence-service-K4U55A2J.js} +2 -2
  31. package/dist/mcp.js +3 -3
  32. package/package.json +13 -13
  33. package/assets/assets/index-BHIRnvQi.js +0 -86
@@ -17,12 +17,12 @@ import {
17
17
  resolveOperatorApiKeyIds,
18
18
  runWithUsageTags,
19
19
  saveConfigPatch
20
- } from "./chunk-GQ37ALYP.js";
20
+ } from "./chunk-WJGUBZSW.js";
21
21
  import {
22
22
  deleteSiteCrawlGraphLayout,
23
23
  persistSiteCrawlGraphLayout,
24
24
  prepareSiteCrawlGraphLayout
25
- } from "./chunk-S7D23FEE.js";
25
+ } from "./chunk-LWGYRN3T.js";
26
26
  import {
27
27
  PACKAGE_VERSION
28
28
  } from "./chunk-AOJU5LKX.js";
@@ -151,6 +151,7 @@ import {
151
151
  readInstalledVersion,
152
152
  redactNotificationUrl,
153
153
  refreshAccessToken,
154
+ registerAgentConversationRoutes,
154
155
  registerOAuthAdminRoutes,
155
156
  registerOAuthRoutes,
156
157
  requireInstanceAdministrator,
@@ -178,7 +179,7 @@ import {
178
179
  siteLivenessState,
179
180
  toAlertView,
180
181
  usageCounters
181
- } from "./chunk-KBPSOB55.js";
182
+ } from "./chunk-DOC4QQLS.js";
182
183
  import {
183
184
  AGENT_MEMORY_VALUE_MAX_BYTES,
184
185
  AGENT_NONE,
@@ -299,6 +300,7 @@ import {
299
300
  isVertexGroundingRedirect,
300
301
  mapWithConcurrency,
301
302
  maskTelemetryAnonymousId,
303
+ missingDependency,
302
304
  nextScheduleUpdatedAt,
303
305
  normalizeAgentSlug,
304
306
  normalizeIdTokens,
@@ -335,7 +337,7 @@ import {
335
337
  visibilityReportRequestSchema,
336
338
  winnabilityClassLabel,
337
339
  withRetry
338
- } from "./chunk-KEMMVSAQ.js";
340
+ } from "./chunk-NYRRWWEE.js";
339
341
 
340
342
  // src/runtime-context.ts
341
343
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -6481,7 +6483,7 @@ function nonBlank(value) {
6481
6483
  return trimmed ? trimmed : void 0;
6482
6484
  }
6483
6485
  function resolveBuildCommit(env = process.env) {
6484
- const embedded = true ? "f55491f2af7978e1e202050de7dd986e7c888d8c" : void 0;
6486
+ const embedded = true ? "3cbbec137ff9c498f0b59f30a5e2b84c99af6f40" : void 0;
6485
6487
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
6486
6488
  }
6487
6489
  function resolveInstanceIdentity(env = process.env) {
@@ -11775,7 +11777,7 @@ function readStoredGroundingSources(rawResponse) {
11775
11777
  return result2;
11776
11778
  }
11777
11779
  async function backfillInsightsCommand(project, opts) {
11778
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-7PVUFJTX.js");
11780
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-K4U55A2J.js");
11779
11781
  const config = loadConfig();
11780
11782
  const db = createClient(config.database);
11781
11783
  migrate(db);
@@ -13864,13 +13866,15 @@ function resolveAgentId(providerOrPiAi) {
13864
13866
  return void 0;
13865
13867
  }
13866
13868
  function buildAgentProvidersResponse(config) {
13869
+ const pinned = coerceAgentProvider(config.agent?.provider ?? void 0);
13870
+ const pinnedModel = pinned ? config.agent?.model ?? void 0 : void 0;
13867
13871
  const providers = listAgentProviders().map((id) => {
13868
13872
  const entry = AGENT_PROVIDERS[id];
13869
13873
  const source = resolveApiKeySource(id, config);
13870
13874
  return {
13871
13875
  id,
13872
13876
  label: entry.label,
13873
- defaultModel: entry.defaultModel,
13877
+ defaultModel: id === pinned && pinnedModel ? pinnedModel : entry.defaultModel,
13874
13878
  configured: source !== void 0,
13875
13879
  keySource: source?.source ?? null
13876
13880
  };
@@ -13878,7 +13882,7 @@ function buildAgentProvidersResponse(config) {
13878
13882
  const firstConfigured = agentProvidersByPriority().find((p) => resolveApiKeySource(p, config));
13879
13883
  return {
13880
13884
  providers,
13881
- defaultProvider: firstConfigured ?? null
13885
+ defaultProvider: pinned ?? firstConfigured ?? null
13882
13886
  };
13883
13887
  }
13884
13888
 
@@ -14174,6 +14178,9 @@ function mcpToAgentTool(tool, ctx) {
14174
14178
  }
14175
14179
  var AERO_EXCLUDED_MCP_TOOLS = /* @__PURE__ */ new Set([
14176
14180
  CanonryMcpToolNames.canonry_agent_clear,
14181
+ CanonryMcpToolNames.canonry_agent_conversations_new,
14182
+ CanonryMcpToolNames.canonry_agent_conversations_resume,
14183
+ CanonryMcpToolNames.canonry_agent_conversations_delete,
14177
14184
  CanonryMcpToolNames.canonry_results_clear
14178
14185
  ]);
14179
14186
  function buildMcpAgentTools(registry, ctx, opts = {}) {
@@ -14841,6 +14848,27 @@ function missingProviderMessage() {
14841
14848
  const envHints = agentProvidersByPriority().map(agentProviderApiKeyEnvVar).join(" / ");
14842
14849
  return `No agent LLM provider configured. Add an API key for one of: ${configHints} in ~/.canonry/config.yaml, or export ${envHints}.`;
14843
14850
  }
14851
+ function resolveConfiguredAgentProvider(config) {
14852
+ return coerceAgentProvider(config.agent?.provider);
14853
+ }
14854
+ function describeAgentPin(config) {
14855
+ const provider = resolveConfiguredAgentProvider(config);
14856
+ if (!provider) return null;
14857
+ const model = config.agent?.model ?? getAgentProvider(provider).defaultModel;
14858
+ let modelError = null;
14859
+ try {
14860
+ resolveAeroModel(provider, model);
14861
+ } catch (err) {
14862
+ modelError = err instanceof Error ? err.message : String(err);
14863
+ }
14864
+ return {
14865
+ provider,
14866
+ model,
14867
+ configured: Boolean(resolveApiKeyFor(provider, config)),
14868
+ envVar: agentProviderApiKeyEnvVar(provider),
14869
+ modelError
14870
+ };
14871
+ }
14844
14872
  function detectAgentProvider(config) {
14845
14873
  for (const provider of agentProvidersByPriority()) {
14846
14874
  if (resolveApiKeyFor(provider, config)) return provider;
@@ -14911,9 +14939,11 @@ function createAeroSession(opts) {
14911
14939
  return agent;
14912
14940
  }
14913
14941
  function resolveSessionProviderAndModel(config, opts) {
14914
- const provider = opts?.provider ?? detectAgentProvider(config);
14942
+ const pinned = resolveConfiguredAgentProvider(config);
14943
+ const provider = opts?.provider ?? pinned ?? detectAgentProvider(config);
14915
14944
  if (!provider) throw new Error(missingProviderMessage());
14916
- const modelId = opts?.modelId ?? getAgentProvider(provider).defaultModel;
14945
+ const pinnedModelId = provider === pinned ? config.agent?.model : void 0;
14946
+ const modelId = opts?.modelId ?? pinnedModelId ?? getAgentProvider(provider).defaultModel;
14917
14947
  return { provider, modelId };
14918
14948
  }
14919
14949
 
@@ -15006,7 +15036,7 @@ async function loadExternalMcpTools(servers, opts = {}) {
15006
15036
 
15007
15037
  // src/agent/memory-store.ts
15008
15038
  import crypto23 from "crypto";
15009
- import { and as and16, desc as desc7, eq as eq19, like, sql as sql8 } from "drizzle-orm";
15039
+ import { and as and16, desc as desc7, eq as eq19, like, sql as sql8, or as or2 } from "drizzle-orm";
15010
15040
  var COMPACTION_KEY_PREFIX = "compaction:";
15011
15041
  var COMPACTION_NOTES_PER_SESSION = 3;
15012
15042
  function rowToDto(row) {
@@ -15060,8 +15090,13 @@ function deleteMemoryEntry(db, projectId, key) {
15060
15090
  const changes = result2.changes ?? 0;
15061
15091
  return changes > 0;
15062
15092
  }
15063
- function loadRecentForHydrate(db, projectId, limit) {
15064
- return listMemoryEntries(db, projectId, { limit });
15093
+ function loadRecentForHydrate(db, projectId, limit, sessionId) {
15094
+ if (sessionId === void 0) return listMemoryEntries(db, projectId, { limit });
15095
+ const sessionPrefix = `compaction:${sessionId ?? ""}:`;
15096
+ return db.select().from(agentMemory).where(and16(
15097
+ eq19(agentMemory.projectId, projectId),
15098
+ or2(sql8`substr(${agentMemory.key}, 1, ${COMPACTION_KEY_PREFIX.length}) <> ${COMPACTION_KEY_PREFIX}`, sessionId ? sql8`substr(${agentMemory.key}, 1, ${sessionPrefix.length}) = ${sessionPrefix}` : void 0)
15099
+ )).orderBy(desc7(agentMemory.updatedAt)).limit(limit).all().map(rowToDto);
15065
15100
  }
15066
15101
  function writeCompactionNote(db, args) {
15067
15102
  if (Buffer.byteLength(args.summary, "utf8") > AGENT_MEMORY_VALUE_MAX_BYTES) {
@@ -15337,9 +15372,8 @@ var SessionRegistry = class {
15337
15372
  if (row.systemPrompt !== systemPrompt) {
15338
15373
  this.persistPromptSnapshot(projectId, systemPrompt);
15339
15374
  }
15340
- const effectiveProvider = preferences?.provider ?? row.modelProvider;
15341
- const effectiveModelId = preferences?.modelId ?? row.modelId;
15342
- if (preferences?.provider || preferences?.modelId) {
15375
+ const { provider: effectiveProvider, modelId: effectiveModelId } = this.resolveTurnModel(preferences, { provider: row.modelProvider, modelId: row.modelId });
15376
+ if (effectiveProvider !== row.modelProvider || effectiveModelId !== row.modelId) {
15343
15377
  this.opts.db.update(agentSessions).set({
15344
15378
  modelProvider: effectiveProvider,
15345
15379
  modelId: effectiveModelId,
@@ -15418,7 +15452,7 @@ var SessionRegistry = class {
15418
15452
  * escape the `<memory>` wrapper are neutralized before interpolation.
15419
15453
  */
15420
15454
  buildHydratedSystemPrompt(projectId, basePrompt) {
15421
- const entries = loadRecentForHydrate(this.opts.db, projectId, MAX_HYDRATE_NOTES);
15455
+ const entries = loadRecentForHydrate(this.opts.db, projectId, MAX_HYDRATE_NOTES, this.loadRow(projectId)?.id ?? null);
15422
15456
  if (entries.length === 0) return basePrompt;
15423
15457
  let totalBytes = 0;
15424
15458
  const kept = [];
@@ -15472,17 +15506,19 @@ ${lines.join("\n")}
15472
15506
  * - align `state.tools` to the requested scope/profile (CLI full vs
15473
15507
  * dashboard read-only share the same cached Agent; each request
15474
15508
  * re-scopes it).
15475
- * - align `state.model` when the caller passes `provider` or `modelId`,
15476
- * honoring `--provider` / `--model` on hot sessions (not just on
15477
- * fresh/hydrated construction).
15509
+ * - align `state.model` on every turn (see `resolveTurnModel`): an
15510
+ * explicit `provider` / `modelId` wins for this turn, then the
15511
+ * `agent.provider` pin, then the session's stored model.
15512
+ * - refuse, naming `agent.provider`, a pinned provider that has no key.
15478
15513
  *
15479
- * Persists the new model choice to the DB row so subsequent invocations
15480
- * stay on it unless overridden again.
15514
+ * Persists the resolved model to the DB row as provenance. Without a pin an
15515
+ * override therefore sticks, as it always has; with a pin, the next turn
15516
+ * that names no provider returns to it.
15481
15517
  */
15482
15518
  async acquireForTurn(projectName, preferences) {
15483
15519
  preferences?.signal?.throwIfAborted();
15484
15520
  if (this.acquisitions.has(projectName)) throw agentBusy(projectName);
15485
- const agent = this.getOrCreate(projectName);
15521
+ const agent = this.getOrCreate(projectName, preferences);
15486
15522
  if (agent.state.isStreaming) {
15487
15523
  throw agentBusy(projectName);
15488
15524
  }
@@ -15499,9 +15535,8 @@ ${lines.join("\n")}
15499
15535
  scope: preferences?.toolScope ?? AeroToolScopes.all,
15500
15536
  profile: preferences?.toolProfile ?? AeroToolProfiles.default
15501
15537
  });
15502
- if (preferences?.provider || preferences?.modelId) {
15503
- this.alignModel(projectName, agent, preferences);
15504
- }
15538
+ this.alignModel(projectName, agent, preferences ?? {});
15539
+ this.assertTurnProviderUsable(projectId);
15505
15540
  await this.mergeExternalTools(agent);
15506
15541
  const view = { client: this.opts.client, projectName, basePath: this.opts.config.basePath, context: preferences?.context };
15507
15542
  const evidence = preferences?.context ? await readAeroViewEvidence(view) : void 0;
@@ -15580,15 +15615,56 @@ ${lines.join("\n")}
15580
15615
  this.scopes.set(projectName, want.scope);
15581
15616
  this.profiles.set(projectName, want.profile);
15582
15617
  }
15618
+ /**
15619
+ * Throw a named, actionable error when the `agent.provider` pin chose this
15620
+ * turn's provider and that provider has no key. Auto-detection only ever
15621
+ * picks a keyed provider, so the pin is the one path that can land a turn on
15622
+ * a keyless one without anything saying so. An explicitly requested provider
15623
+ * keeps its existing behaviour: the caller named it, and the provider's own
15624
+ * error reports the missing key when the prompt is sent.
15625
+ */
15626
+ assertTurnProviderUsable(projectId) {
15627
+ const provider = coerceAgentProvider(this.loadRow(projectId)?.modelProvider ?? void 0);
15628
+ if (!provider || provider !== resolveConfiguredAgentProvider(this.opts.config)) return;
15629
+ if (resolveApiKeyFor(provider, this.opts.config)) return;
15630
+ throw missingDependency(
15631
+ `Aero is pinned to ${provider} by agent.provider, but no key is configured for it. Set providers.${provider}.apiKey in config.yaml or export ${agentProviderApiKeyEnvVar(provider)}, or change agent.provider.`,
15632
+ { provider, pinned: true }
15633
+ );
15634
+ }
15635
+ /**
15636
+ * Resolve the provider/model a turn should use: an explicit request outranks
15637
+ * the `agent.provider` pin, which outranks whatever the row last recorded.
15638
+ *
15639
+ * The row is provenance (what answered), not policy (what answers next), so
15640
+ * a configured pin reasserts itself every turn instead of being frozen at
15641
+ * whatever the first session happened to pick -- and survives the
15642
+ * conversation-delete path, which drops the row entirely. With a pin, an
15643
+ * explicit request therefore lasts one turn.
15644
+ *
15645
+ * The model is a function of the request and the config, never of which
15646
+ * provider ran last: naming the pinned provider gets `agent.model` whether or
15647
+ * not the session just came back from another one. The row's model is used
15648
+ * only when nothing is pinned and nothing was requested, which keeps an
15649
+ * unpinned install's override sticky as it always was. A model id is never
15650
+ * forwarded across providers: any other case takes the provider's default.
15651
+ */
15652
+ resolveTurnModel(preferences, current) {
15653
+ const pinned = resolveConfiguredAgentProvider(this.opts.config);
15654
+ const provider = preferences?.provider ?? pinned ?? current.provider ?? AgentProviderIds.claude;
15655
+ const carried = !preferences?.provider && !pinned && provider === current.provider ? current.modelId ?? void 0 : void 0;
15656
+ const pinnedModelId = provider === pinned ? this.opts.config.agent?.model ?? void 0 : void 0;
15657
+ const modelId = preferences?.modelId ?? pinnedModelId ?? carried ?? getAgentProvider(provider).defaultModel;
15658
+ return { provider, modelId };
15659
+ }
15583
15660
  alignModel(projectName, agent, preferences) {
15584
15661
  const projectId = this.tryResolveProjectId(projectName);
15585
15662
  if (!projectId) return;
15586
15663
  const row = this.loadRow(projectId);
15587
- const currentProvider = row?.modelProvider ?? AgentProviderIds.claude;
15588
- const currentModelId = row?.modelId;
15589
- const nextProvider = preferences.provider ?? currentProvider;
15590
- const nextModelId = preferences.modelId ?? (preferences.provider ? getAgentProvider(nextProvider).defaultModel : currentModelId);
15591
- if (!nextModelId) return;
15664
+ if (!row) return;
15665
+ const currentProvider = row.modelProvider;
15666
+ const currentModelId = row.modelId;
15667
+ const { provider: nextProvider, modelId: nextModelId } = this.resolveTurnModel(preferences, { provider: row.modelProvider, modelId: row.modelId });
15592
15668
  if (nextProvider === currentProvider && nextModelId === currentModelId) return;
15593
15669
  agent.state.model = resolveAeroModel(nextProvider, nextModelId);
15594
15670
  this.opts.db.update(agentSessions).set({
@@ -15597,6 +15673,13 @@ ${lines.join("\n")}
15597
15673
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
15598
15674
  }).where(eq20(agentSessions.projectId, projectId)).run();
15599
15675
  }
15676
+ /** Snapshot pending work without consuming it before an atomic conversation switch. */
15677
+ prepareConversationChange(projectName) {
15678
+ if (this.isBusy(projectName)) throw agentBusy(projectName);
15679
+ this.save(projectName);
15680
+ const pending = this.pending.get(projectName);
15681
+ if (pending?.length) this.updateRow(this.resolveProjectId(projectName), { followUpQueue: JSON.stringify(pending) });
15682
+ }
15600
15683
  /** Persist a session's transcript back to the DB. Call after any run settles. */
15601
15684
  save(projectName) {
15602
15685
  const agent = this.live.get(projectName);
@@ -16011,6 +16094,7 @@ function resolveProject(db, name) {
16011
16094
  return row;
16012
16095
  }
16013
16096
  function registerAgentRoutes(app, opts) {
16097
+ registerAgentConversationRoutes(app, { db: opts.db, runtime: opts.sessionRegistry });
16014
16098
  app.get(
16015
16099
  "/projects/:name/agent/transcript",
16016
16100
  async (request) => {
@@ -16018,11 +16102,12 @@ function registerAgentRoutes(app, opts) {
16018
16102
  const project = resolveProject(opts.db, request.params.name);
16019
16103
  const row = opts.db.select().from(agentSessions).where(eq22(agentSessions.projectId, project.id)).get();
16020
16104
  if (!row) {
16021
- return { messages: [], modelProvider: null, modelId: null, updatedAt: null };
16105
+ return { conversationId: null, messages: [], modelProvider: null, modelId: null, updatedAt: null };
16022
16106
  }
16023
16107
  const messages = parseJsonColumn(row.messages, []);
16024
16108
  return {
16025
16109
  messages,
16110
+ conversationId: row.id,
16026
16111
  isStreaming: opts.sessionRegistry.isBusy(project.name),
16027
16112
  modelProvider: row.modelProvider,
16028
16113
  modelId: row.modelId,
@@ -16043,6 +16128,7 @@ function registerAgentRoutes(app, opts) {
16043
16128
  async (request) => {
16044
16129
  requireInstanceAdministrator(request);
16045
16130
  const project = resolveProject(opts.db, request.params.name);
16131
+ if (opts.sessionRegistry.isBusy(project.name)) throw agentBusy(project.name);
16046
16132
  opts.sessionRegistry.reset(project.name);
16047
16133
  opts.db.update(agentSessions).set({ messages: "[]", followUpQueue: "[]", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq22(agentSessions.projectId, project.id)).run();
16048
16134
  return { status: "reset" };
@@ -16054,6 +16140,10 @@ function registerAgentRoutes(app, opts) {
16054
16140
  const parsed = agentPromptRequestSchema.safeParse(request.body);
16055
16141
  if (!parsed.success) throw validationError(parsed.error.issues.map((issue) => issue.message).join("; "));
16056
16142
  const body = parsed.data;
16143
+ if (body.conversationId !== void 0) {
16144
+ const current = opts.db.select({ id: agentSessions.id }).from(agentSessions).where(eq22(agentSessions.projectId, project.id)).get();
16145
+ if ((current?.id ?? null) !== body.conversationId) throw validationError("The active conversation changed. Reload the conversation before sending.");
16146
+ }
16057
16147
  const promptText = body.prompt;
16058
16148
  const requestedScope = body?.scope === AeroToolScopes.all ? AeroToolScopes.all : AeroToolScopes.readOnly;
16059
16149
  const requestedProfile = isAeroToolProfile(body?.profile) ? body.profile : AeroToolProfiles.default;
@@ -18958,6 +19048,7 @@ async function createServer(opts) {
18958
19048
  // Resolved fresh each call so a key added at runtime (settings API) shows
18959
19049
  // up immediately in the `config.agent-providers` doctor check.
18960
19050
  getAgentProviderSummary: () => buildAgentProvidersResponse(opts.config).providers,
19051
+ getAgentPin: () => describeAgentPin(opts.config),
18961
19052
  getGoogleMarketingDoctorInput: (ctx) => {
18962
19053
  if (!ctx.project) return null;
18963
19054
  const googleAds = opts.db.select().from(googleAdsConnections).where(eq25(googleAdsConnections.projectId, ctx.project.id)).get();
@@ -5,12 +5,12 @@ import {
5
5
  siteCrawlGraphNodes,
6
6
  siteCrawlPages,
7
7
  siteCrawlSnapshots
8
- } from "./chunk-KBPSOB55.js";
8
+ } from "./chunk-DOC4QQLS.js";
9
9
  import {
10
10
  SITE_CRAWL_GRAPH_MAX_EDGES,
11
11
  SITE_CRAWL_GRAPH_MAX_NODES,
12
12
  TEMPLATE_LINK_RATIO_THRESHOLD
13
- } from "./chunk-KEMMVSAQ.js";
13
+ } from "./chunk-NYRRWWEE.js";
14
14
 
15
15
  // src/site-crawl-graph-layout.ts
16
16
  import crypto from "crypto";
@@ -13962,8 +13962,11 @@ var agentProvidersResponseDtoSchema = z45.object({
13962
13962
  */
13963
13963
  providers: z45.array(agentProviderOptionDtoSchema).default([]),
13964
13964
  /**
13965
- * Provider Aero auto-picks when no explicit override is passed. Null if
13966
- * nothing is configured (install never exchanged a key).
13965
+ * Provider a new session uses when the caller names none: the
13966
+ * `agent.provider` pin when set (reported even without a key, as its
13967
+ * `configured: false` entry), else the first configured provider by
13968
+ * priority. An existing unpinned session keeps its stored provider. Null
13969
+ * when nothing is pinned and nothing is configured.
13967
13970
  */
13968
13971
  defaultProvider: agentProviderIdSchema.nullable()
13969
13972
  });
@@ -13980,6 +13983,7 @@ var agentMemoryDeleteRequestSchema = z45.object({
13980
13983
  });
13981
13984
  var agentPromptRequestSchema = z45.object({
13982
13985
  prompt: z45.string().trim().min(1),
13986
+ conversationId: z45.string().min(1).nullable().optional(),
13983
13987
  provider: agentProviderIdSchema.optional(),
13984
13988
  modelId: z45.string().trim().min(1).optional(),
13985
13989
  scope: z45.enum(["all", "read-only"]).optional(),
@@ -13987,6 +13991,43 @@ var agentPromptRequestSchema = z45.object({
13987
13991
  context: agentViewContextSchema.optional(),
13988
13992
  limits: agentTurnLimitsSchema.optional()
13989
13993
  });
13994
+ var agentConversationMessageSchema = z45.looseObject({ role: z45.string(), content: z45.unknown().optional() });
13995
+ var agentConversationSummarySchema = z45.object({
13996
+ id: z45.string(),
13997
+ title: z45.string(),
13998
+ active: z45.boolean(),
13999
+ modelProvider: z45.string(),
14000
+ modelId: z45.string(),
14001
+ createdAt: z45.string(),
14002
+ updatedAt: z45.string()
14003
+ });
14004
+ var agentConversationSchema = agentConversationSummarySchema.extend({
14005
+ messages: z45.array(agentConversationMessageSchema),
14006
+ isStreaming: z45.boolean()
14007
+ });
14008
+ var agentConversationListSchema = z45.object({
14009
+ conversations: z45.array(agentConversationSummarySchema),
14010
+ currentConversationId: z45.string().nullable(),
14011
+ nextOffset: z45.number().int().nullable()
14012
+ });
14013
+ var agentConversationCreateSchema = z45.object({
14014
+ id: z45.uuid()
14015
+ }).strict();
14016
+ var agentConversationDeleteSchema = z45.object({ id: z45.string(), status: z45.literal("deleted") });
14017
+ function agentConversationTitle(messages) {
14018
+ for (const message of messages) {
14019
+ if (message.role !== "user") continue;
14020
+ const content = message.content;
14021
+ const text = typeof content === "string" ? content : Array.isArray(content) ? content.flatMap((block) => typeof block === "object" && block !== null && "type" in block && block.type === "text" && "text" in block && typeof block.text === "string" ? [block.text] : []).join(" ") : "";
14022
+ const title = text.replace(/\s+/g, " ").trim();
14023
+ if (title && !title.startsWith("[system]")) return title.length > 80 ? title.slice(0, 79) + "\u2026" : title;
14024
+ }
14025
+ return "New conversation";
14026
+ }
14027
+ var agentConversationListQuerySchema = z45.object({
14028
+ offset: z45.coerce.number().int().min(0).default(0),
14029
+ limit: z45.coerce.number().int().min(1).max(100).default(50)
14030
+ }).strict();
13990
14031
 
13991
14032
  // ../contracts/src/backlinks.ts
13992
14033
  import { z as z46 } from "zod";
@@ -19673,6 +19714,7 @@ export {
19673
19714
  agentViewContextSchema,
19674
19715
  agentTurnLimitsSchema,
19675
19716
  agentVisibilityEvidence,
19717
+ agentProviderIdSchema,
19676
19718
  agentProvidersResponseDtoSchema,
19677
19719
  MemorySources,
19678
19720
  AGENT_MEMORY_VALUE_MAX_BYTES,
@@ -19680,6 +19722,12 @@ export {
19680
19722
  agentMemoryUpsertRequestSchema,
19681
19723
  agentMemoryDeleteRequestSchema,
19682
19724
  agentPromptRequestSchema,
19725
+ agentConversationSchema,
19726
+ agentConversationListSchema,
19727
+ agentConversationCreateSchema,
19728
+ agentConversationDeleteSchema,
19729
+ agentConversationTitle,
19730
+ agentConversationListQuerySchema,
19683
19731
  backlinkSourceSchema,
19684
19732
  BacklinkSources,
19685
19733
  computeBacklinkSummaryMetrics,
@@ -4,14 +4,14 @@ import {
4
4
  installSkills,
5
5
  loadConfigRaw,
6
6
  saveConfigPatch
7
- } from "./chunk-GQ37ALYP.js";
7
+ } from "./chunk-WJGUBZSW.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
10
  } from "./chunk-AOJU5LKX.js";
11
11
  import {
12
12
  SKILL_MANIFEST_FILENAME,
13
13
  SkillsClients
14
- } from "./chunk-KEMMVSAQ.js";
14
+ } from "./chunk-NYRRWWEE.js";
15
15
 
16
16
  // src/skills-autosync.ts
17
17
  import fs from "fs";