@canonry/canonry 5.30.0 → 5.30.2

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.
@@ -26,7 +26,7 @@ import {
26
26
  persistSiteCrawlGraphLayout,
27
27
  prepareSiteCrawlGraphLayout,
28
28
  recordedSharePct
29
- } from "./chunk-TWYIUHJU.js";
29
+ } from "./chunk-YVWYQBXW.js";
30
30
  import {
31
31
  CanonryMcpToolNames,
32
32
  CliError,
@@ -214,7 +214,7 @@ import {
214
214
  siteLivenessState,
215
215
  toAlertView,
216
216
  usageCounters
217
- } from "./chunk-TPJ4MMZ6.js";
217
+ } from "./chunk-7YS62CJ4.js";
218
218
  import {
219
219
  AGENT_MEMORY_VALUE_MAX_BYTES,
220
220
  AGENT_NONE,
@@ -7136,7 +7136,9 @@ async function executeTrackedQuery6(input) {
7136
7136
  servedModel: extractServedModel6(rawResponse),
7137
7137
  groundingSources: parsed.groundingSources,
7138
7138
  searchQueries: parsed.searchQueries,
7139
- retrievalStatus: parsed.retrievalStatus
7139
+ retrievalStatus: parsed.retrievalStatus,
7140
+ usage: extractUsage(rawResponse),
7141
+ stopReason: extractStopReason(rawResponse)
7140
7142
  };
7141
7143
  } catch (err) {
7142
7144
  throw new Error(`[provider-muse] ${describeError(err)}`);
@@ -7145,6 +7147,26 @@ async function executeTrackedQuery6(input) {
7145
7147
  function extractServedModel6(rawResponse) {
7146
7148
  return normalizeServedModel(rawResponse.model);
7147
7149
  }
7150
+ function extractUsage(rawResponse) {
7151
+ const usage = asRecord(rawResponse.usage);
7152
+ if (!usage) return void 0;
7153
+ const inputTokens = usageCount(usage.input_tokens);
7154
+ const cachedInputTokens = usageCount(asRecord(usage.input_tokens_details)?.cached_tokens);
7155
+ const output = Array.isArray(rawResponse.output) ? rawResponse.output : [];
7156
+ return {
7157
+ inputTokens: Math.max(0, inputTokens - cachedInputTokens),
7158
+ cachedInputTokens,
7159
+ cacheWriteTokens: 0,
7160
+ outputTokens: usageCount(usage.output_tokens),
7161
+ searchCount: output.filter((item) => asRecord(item)?.type === "web_search_call").length
7162
+ };
7163
+ }
7164
+ function extractStopReason(rawResponse) {
7165
+ const reason = asRecord(rawResponse.incomplete_details)?.reason;
7166
+ if (typeof reason === "string" && reason.length > 0) return reason;
7167
+ const status = rawResponse.status;
7168
+ return typeof status === "string" && status.length > 0 ? status : void 0;
7169
+ }
7148
7170
  function normalizeResult7(raw) {
7149
7171
  return reparseStoredResult5(raw.rawResponse);
7150
7172
  }
@@ -7808,7 +7830,7 @@ function nonBlank(value) {
7808
7830
  return trimmed ? trimmed : void 0;
7809
7831
  }
7810
7832
  function resolveBuildCommit(env = process.env) {
7811
- const embedded = true ? "927559d4c19997a79d58c7c1c9e3d9b491a3880b" : void 0;
7833
+ const embedded = true ? "0417a856c95c1a04b86db6ede81376a8faa015ca" : void 0;
7812
7834
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
7813
7835
  }
7814
7836
  function resolveInstanceIdentity(env = process.env) {
@@ -8709,7 +8731,7 @@ var JobRunner = class {
8709
8731
  for (const provider of apiProviders) {
8710
8732
  if (frozenModes[providerKey(provider)] !== ProviderDispatchModes.batch) continue;
8711
8733
  if (adapterSupportsBatch(provider.adapter)) batchProviders.add(provider.adapter.name);
8712
- else log2.warn("run.batch-unsupported", { runId, providerName: provider.adapter.name });
8734
+ else log2.warn("run.batch-unsupported", { runId, provider: provider.adapter.name });
8713
8735
  }
8714
8736
  log2.info("run.plan-dispatch", {
8715
8737
  runId,
@@ -9128,7 +9150,7 @@ var JobRunner = class {
9128
9150
  location: unit.context ?? void 0
9129
9151
  }, { ...config, model });
9130
9152
  } catch (err) {
9131
- log2.warn("batch.build-failed", { runId: ctx.runId, providerName, executionId: unit.executionId, error: describeError(err) });
9153
+ log2.warn("batch.build-failed", { runId: ctx.runId, provider: providerName, executionId: unit.executionId, error: describeError(err) });
9132
9154
  syncUnits.push(unit);
9133
9155
  continue;
9134
9156
  }
@@ -9141,7 +9163,7 @@ var JobRunner = class {
9141
9163
  for (const [model, lines] of linesByModel) {
9142
9164
  const { chunks, oversized } = chunkBatchLines(lines, maxRequests, capability.maxBytesPerBatch);
9143
9165
  if (oversized.length > 0) {
9144
- log2.warn("batch.line-too-large", { runId: ctx.runId, providerName, model, count: oversized.length, maxBytes: capability.maxBytesPerBatch });
9166
+ log2.warn("batch.line-too-large", { runId: ctx.runId, provider: providerName, model, count: oversized.length, maxBytes: capability.maxBytesPerBatch });
9145
9167
  syncUnits.push(...oversized.map((line) => line.unit));
9146
9168
  }
9147
9169
  for (const chunk of chunks) {
@@ -9201,7 +9223,7 @@ var JobRunner = class {
9201
9223
  }
9202
9224
  });
9203
9225
  } catch (err) {
9204
- log2.warn("batch.ledger-failed", { runId: ctx.runId, providerName, requests: lines.length, error: describeError(err) });
9226
+ log2.warn("batch.ledger-failed", { runId: ctx.runId, provider: providerName, requests: lines.length, error: describeError(err) });
9205
9227
  return lines.map((line) => line.unit);
9206
9228
  }
9207
9229
  ctx.batchRowIds.push(rowId);
@@ -9220,7 +9242,7 @@ var JobRunner = class {
9220
9242
  txDb.update(providerBatches).set({ quotaReleased: lines.length, updatedAt: at }).where(eq3(providerBatches.id, rowId)).run();
9221
9243
  if (!sweepLive) releaseDailyQueryQuota(txDb, { scope: reservation.scope, period: reservation.period, count: lines.length });
9222
9244
  });
9223
- log2.warn("batch.submit-refused", { runId: ctx.runId, providerName, batchId: rowId, requests: lines.length, error: message });
9245
+ log2.warn("batch.submit-refused", { runId: ctx.runId, provider: providerName, batchId: rowId, requests: lines.length, error: message });
9224
9246
  if (!sweepLive) return [];
9225
9247
  this.countDispatched(ctx.providerDispatchCounts, providerName, -lines.length);
9226
9248
  return lines.map((line) => line.unit);
@@ -9230,7 +9252,7 @@ var JobRunner = class {
9230
9252
  error: `The provider batch of ${lines.length} answer(s) may or may not have been created, so it was not resubmitted and its answers were not recorded: ${message}`,
9231
9253
  updatedAt: at
9232
9254
  }).where(and3(eq3(providerBatches.id, rowId), eq3(providerBatches.status, ProviderBatchStatuses.submitting))).run();
9233
- log2.error("batch.submit-unknown", { runId: ctx.runId, providerName, batchId: rowId, requests: lines.length, error: message });
9255
+ log2.error("batch.submit-unknown", { runId: ctx.runId, provider: providerName, batchId: rowId, requests: lines.length, error: message });
9234
9256
  return [];
9235
9257
  }
9236
9258
  const submitted = /* @__PURE__ */ new Date();
@@ -9246,7 +9268,7 @@ var JobRunner = class {
9246
9268
  await this.cancelAtProvider([{ id: rowId, provider: providerName, providerBatchId: result2.providerBatchId }]);
9247
9269
  return [];
9248
9270
  }
9249
- log2.info("batch.submitted", { runId: ctx.runId, providerName, batchId: rowId, providerBatchId: result2.providerBatchId, model, requests: lines.length });
9271
+ log2.info("batch.submitted", { runId: ctx.runId, provider: providerName, batchId: rowId, providerBatchId: result2.providerBatchId, model, requests: lines.length });
9250
9272
  return [];
9251
9273
  }
9252
9274
  countDispatched(counts, providerName, sent) {
@@ -9287,14 +9309,14 @@ var JobRunner = class {
9287
9309
  if (!row.providerBatchId) continue;
9288
9310
  const registered = this.registry.get(row.provider);
9289
9311
  if (!registered?.adapter.batch) {
9290
- log2.warn("batch.cancel-unavailable", { batchId: row.id, providerName: row.provider });
9312
+ log2.warn("batch.cancel-unavailable", { batchId: row.id, provider: row.provider });
9291
9313
  continue;
9292
9314
  }
9293
9315
  try {
9294
9316
  await registered.adapter.batch.cancel(row.providerBatchId, registered.config);
9295
- log2.info("batch.cancelled", { batchId: row.id, providerName: row.provider, providerBatchId: row.providerBatchId });
9317
+ log2.info("batch.cancelled", { batchId: row.id, provider: row.provider, providerBatchId: row.providerBatchId });
9296
9318
  } catch (err) {
9297
- log2.warn("batch.cancel-failed", { batchId: row.id, providerName: row.provider, error: describeError(err) });
9319
+ log2.warn("batch.cancel-failed", { batchId: row.id, provider: row.provider, error: describeError(err) });
9298
9320
  }
9299
9321
  }
9300
9322
  }
@@ -9355,7 +9377,7 @@ var JobRunner = class {
9355
9377
  for await (const line of capability.results(batch.providerBatchId, registered.config)) {
9356
9378
  const request = requests.get(line.customId);
9357
9379
  if (!request) {
9358
- log2.warn("batch.unknown-line", { batchId: batch.id, providerName: batch.provider, customId: line.customId });
9380
+ log2.warn("batch.unknown-line", { batchId: batch.id, provider: batch.provider, customId: line.customId });
9359
9381
  continue;
9360
9382
  }
9361
9383
  if (request.outcome !== null) continue;
@@ -9382,7 +9404,7 @@ var JobRunner = class {
9382
9404
  raw = adapter.parseTrackedQueryResponse(line.body, resolveProviderModel(adapter.name, request.requestedModel));
9383
9405
  } catch (err) {
9384
9406
  const error = describeError(err);
9385
- log2.warn("batch.parse-failed", { runId: batch.runId, batchId: batch.id, providerName: batch.provider, executionId: request.executionId, error });
9407
+ log2.warn("batch.parse-failed", { runId: batch.runId, batchId: batch.id, provider: batch.provider, executionId: request.executionId, error });
9386
9408
  return { outcome: ProviderBatchRequestOutcomes.parse_failed, error };
9387
9409
  }
9388
9410
  const unit = {
@@ -9425,7 +9447,7 @@ var JobRunner = class {
9425
9447
  updatedAt: at
9426
9448
  }).where(and3(eq3(providerBatches.id, batch.id), eq3(providerBatches.status, ProviderBatchStatuses.ended))).run();
9427
9449
  const { recordedCount: recorded, notRecorded } = tally;
9428
- log2.info("batch.ingested", { runId: batch.runId, batchId: batch.id, providerName: batch.provider, recorded, notRecorded, released });
9450
+ log2.info("batch.ingested", { runId: batch.runId, batchId: batch.id, provider: batch.provider, recorded, notRecorded, released });
9429
9451
  return { kind: "ingested", recorded, notRecorded, released };
9430
9452
  });
9431
9453
  }
@@ -9455,7 +9477,7 @@ var JobRunner = class {
9455
9477
  log2.warn("batch.abandoned-unreadable", {
9456
9478
  runId: batch.runId,
9457
9479
  batchId: batch.id,
9458
- providerName: batch.provider,
9480
+ provider: batch.provider,
9459
9481
  recorded: tally.recordedCount,
9460
9482
  unread: batch.requestCount - tally.ingestedCount,
9461
9483
  released
@@ -14430,7 +14452,7 @@ function readStoredGroundingSources(rawResponse) {
14430
14452
  return result2;
14431
14453
  }
14432
14454
  async function backfillInsightsCommand(project, opts) {
14433
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-SUFG6ICC.js");
14455
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-PULUYOPR.js");
14434
14456
  const config = loadConfig();
14435
14457
  const db = createClient(config.database);
14436
14458
  migrate(db);
@@ -15588,8 +15610,7 @@ var Scheduler = class {
15588
15610
  log15.warn("run.dispatch-sync-fallback", {
15589
15611
  runId,
15590
15612
  projectName: project.name,
15591
- // Not `provider`: the log redactor drops that key as a payload graph.
15592
- providerName: provider,
15613
+ provider,
15593
15614
  reason,
15594
15615
  message: `${provider} is set to batch for this project but runs sync on this sweep: ${describeBatchIneligibility(provider, reason)}`
15595
15616
  });
@@ -15674,7 +15695,7 @@ var ProviderBatchPoller = class {
15674
15695
  try {
15675
15696
  if (await this.advance(row)) settledRuns.set(row.runId, row.projectId);
15676
15697
  } catch (err) {
15677
- log17.warn("batch.advance-failed", { batchId: row.id, runId: row.runId, providerName: row.provider, error: describeError(err) });
15698
+ log17.warn("batch.advance-failed", { batchId: row.id, runId: row.runId, provider: row.provider, error: describeError(err) });
15678
15699
  this.reschedule(row.id, null);
15679
15700
  }
15680
15701
  }
@@ -15714,10 +15735,10 @@ var ProviderBatchPoller = class {
15714
15735
  return ended ? this.ingest({ ...row, status: ProviderBatchStatuses.ended, resultsExpireAt: poll.resultsExpireAt ?? null }) : false;
15715
15736
  }
15716
15737
  } catch (err) {
15717
- log17.warn("batch.poll-failed", { batchId: row.id, runId: row.runId, providerName: row.provider, error: describeError(err) });
15738
+ log17.warn("batch.poll-failed", { batchId: row.id, runId: row.runId, provider: row.provider, error: describeError(err) });
15718
15739
  }
15719
15740
  } else {
15720
- log17.warn("batch.poll-unavailable", { batchId: row.id, runId: row.runId, providerName: row.provider });
15741
+ log17.warn("batch.poll-unavailable", { batchId: row.id, runId: row.runId, provider: row.provider });
15721
15742
  }
15722
15743
  this.reschedule(row.id, status);
15723
15744
  return this.enforceDeadline(row, registered);
@@ -15739,12 +15760,12 @@ var ProviderBatchPoller = class {
15739
15760
  isNull3(providerBatches.cancelRequestedAt)
15740
15761
  )).run().changes === 1;
15741
15762
  if (!claimed) return false;
15742
- log17.warn("batch.deadline-passed", { batchId: row.id, runId: row.runId, providerName: row.provider, deadlineAt: row.deadlineAt });
15763
+ log17.warn("batch.deadline-passed", { batchId: row.id, runId: row.runId, provider: row.provider, deadlineAt: row.deadlineAt });
15743
15764
  if (registered?.adapter.batch && row.providerBatchId) {
15744
15765
  try {
15745
15766
  await registered.adapter.batch.cancel(row.providerBatchId, registered.config);
15746
15767
  } catch (err) {
15747
- log17.warn("batch.cancel-failed", { batchId: row.id, providerName: row.provider, error: describeError(err) });
15768
+ log17.warn("batch.cancel-failed", { batchId: row.id, provider: row.provider, error: describeError(err) });
15748
15769
  }
15749
15770
  }
15750
15771
  return false;
@@ -15756,7 +15777,7 @@ var ProviderBatchPoller = class {
15756
15777
  updatedAt: at
15757
15778
  }).where(and17(eq19(providerBatches.id, row.id), eq19(providerBatches.status, ProviderBatchStatuses.submitted))).run().changes === 1;
15758
15779
  this.schedule.delete(row.id);
15759
- if (gaveUp) log17.warn("batch.abandoned-after-deadline", { batchId: row.id, runId: row.runId, providerName: row.provider });
15780
+ if (gaveUp) log17.warn("batch.abandoned-after-deadline", { batchId: row.id, runId: row.runId, provider: row.provider });
15760
15781
  return gaveUp;
15761
15782
  }
15762
15783
  async ingest(row) {
@@ -15765,7 +15786,7 @@ var ProviderBatchPoller = class {
15765
15786
  return result2.kind !== "skipped";
15766
15787
  } catch (err) {
15767
15788
  const error = describeError(err);
15768
- log17.warn("batch.ingest-failed", { batchId: row.id, runId: row.runId, providerName: row.provider, error });
15789
+ log17.warn("batch.ingest-failed", { batchId: row.id, runId: row.runId, provider: row.provider, error });
15769
15790
  const now = this.now();
15770
15791
  const unreadable = row.resultsExpireAt !== null && now >= Date.parse(row.resultsExpireAt);
15771
15792
  if (unreadable || now >= Date.parse(row.deadlineAt) + PROVIDER_BATCH_CANCEL_GRACE_MS) {
@@ -21890,7 +21911,7 @@ async function createServer(opts) {
21890
21911
  }
21891
21912
  for (const name of providersWithUnsupportedBatch(providers, (provider) => adapterMap[provider])) {
21892
21913
  log24.warn("provider.batch.unsupported", {
21893
- providerName: name,
21914
+ provider: name,
21894
21915
  message: `providers.${name}.batch.enabled is true, but the ${name} adapter has no batch API; its sweeps run sync.`
21895
21916
  });
21896
21917
  }
@@ -2732,7 +2732,8 @@ var llmUsageEvents = sqliteTable("llm_usage_events", {
2732
2732
  id: text("id").primaryKey(),
2733
2733
  projectId: text("project_id").references(() => projects.id, { onDelete: "cascade" }),
2734
2734
  runId: text("run_id").references(() => runs.id, { onDelete: "set null" }),
2735
- agentSessionId: text("agent_session_id").references(() => agentSessions.id, { onDelete: "set null" }),
2735
+ /** The Aero conversation id: `agent_sessions.id` while active, `agent_conversations.id` once archived. Not a foreign key (v165). */
2736
+ agentSessionId: text("agent_session_id"),
2736
2737
  feature: text("feature").notNull(),
2737
2738
  provider: text("provider").notNull(),
2738
2739
  model: text("model").notNull(),
@@ -2756,7 +2757,8 @@ var llmUsageEvents = sqliteTable("llm_usage_events", {
2756
2757
  var agentToolEvents = sqliteTable("agent_tool_events", {
2757
2758
  id: text("id").primaryKey(),
2758
2759
  projectId: text("project_id").references(() => projects.id, { onDelete: "cascade" }),
2759
- agentSessionId: text("agent_session_id").references(() => agentSessions.id, { onDelete: "set null" }),
2760
+ /** The Aero conversation id, as on `llm_usage_events`. Not a foreign key (v165). */
2761
+ agentSessionId: text("agent_session_id"),
2760
2762
  toolCallId: text("tool_call_id").notNull(),
2761
2763
  toolName: text("tool_name").notNull(),
2762
2764
  assistantResponseId: text("assistant_response_id"),
@@ -8157,8 +8159,106 @@ var MIGRATION_VERSIONS = [
8157
8159
  `CREATE UNIQUE INDEX IF NOT EXISTS idx_sentiment_attempt_number ON sentiment_attempts(work_item_id, attempt_number)`,
8158
8160
  `CREATE INDEX IF NOT EXISTS idx_sentiment_attempt_dispatch ON sentiment_attempts(dispatched_at)`
8159
8161
  ]
8162
+ },
8163
+ {
8164
+ // An Aero conversation id lives in `agent_sessions` while it is active and
8165
+ // in `agent_conversations` once archived, and one foreign key can reference
8166
+ // only one of them. Keyed to `agent_sessions`, the usage and tool ledgers
8167
+ // made "new conversation" fail after any turn (the handler re-keyed the
8168
+ // active row) and nulled a conversation's rows when another was resumed.
8169
+ // The hook rebuilds both tables with `agent_session_id` as a plain indexed
8170
+ // id; see `dropAeroLedgerConversationKeys`.
8171
+ version: 165,
8172
+ name: "aero-ledger-conversation-ids",
8173
+ statements: [],
8174
+ run: dropAeroLedgerConversationKeys
8160
8175
  }
8161
8176
  ];
8177
+ var AERO_LEDGER_REBUILDS = [
8178
+ {
8179
+ table: "llm_usage_events",
8180
+ statements: [
8181
+ `CREATE TABLE llm_usage_events_v165 (
8182
+ id TEXT PRIMARY KEY,
8183
+ project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
8184
+ run_id TEXT REFERENCES runs(id) ON DELETE SET NULL,
8185
+ agent_session_id TEXT,
8186
+ feature TEXT NOT NULL,
8187
+ provider TEXT NOT NULL,
8188
+ model TEXT NOT NULL,
8189
+ response_id TEXT,
8190
+ input_tokens INTEGER NOT NULL DEFAULT 0,
8191
+ output_tokens INTEGER NOT NULL DEFAULT 0,
8192
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
8193
+ cache_write_tokens INTEGER NOT NULL DEFAULT 0,
8194
+ total_tokens INTEGER NOT NULL DEFAULT 0,
8195
+ cost_millicents INTEGER NOT NULL DEFAULT 0,
8196
+ prompt_family TEXT,
8197
+ prompt_version TEXT,
8198
+ metadata TEXT,
8199
+ created_at TEXT NOT NULL
8200
+ )`,
8201
+ `INSERT INTO llm_usage_events_v165 (
8202
+ id, project_id, run_id, agent_session_id, feature, provider, model, response_id, input_tokens, output_tokens,
8203
+ cache_read_tokens, cache_write_tokens, total_tokens, cost_millicents, prompt_family, prompt_version, metadata, created_at
8204
+ )
8205
+ SELECT u.id, p.id, r.id, u.agent_session_id, u.feature, u.provider, u.model, u.response_id, u.input_tokens, u.output_tokens,
8206
+ u.cache_read_tokens, u.cache_write_tokens, u.total_tokens, u.cost_millicents, u.prompt_family, u.prompt_version, u.metadata, u.created_at
8207
+ FROM llm_usage_events u
8208
+ LEFT JOIN projects p ON p.id = u.project_id
8209
+ LEFT JOIN runs r ON r.id = u.run_id`,
8210
+ `DROP TABLE llm_usage_events`,
8211
+ `ALTER TABLE llm_usage_events_v165 RENAME TO llm_usage_events`,
8212
+ `CREATE INDEX IF NOT EXISTS idx_llm_usage_project_created ON llm_usage_events(project_id, created_at)`,
8213
+ `CREATE INDEX IF NOT EXISTS idx_llm_usage_feature_created ON llm_usage_events(feature, created_at)`,
8214
+ `CREATE INDEX IF NOT EXISTS idx_llm_usage_session_created ON llm_usage_events(agent_session_id, created_at)`,
8215
+ `CREATE INDEX IF NOT EXISTS idx_llm_usage_run_created ON llm_usage_events(run_id, created_at)`
8216
+ ]
8217
+ },
8218
+ {
8219
+ table: "agent_tool_events",
8220
+ statements: [
8221
+ `CREATE TABLE agent_tool_events_v165 (
8222
+ id TEXT PRIMARY KEY,
8223
+ project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
8224
+ agent_session_id TEXT,
8225
+ tool_call_id TEXT NOT NULL,
8226
+ tool_name TEXT NOT NULL,
8227
+ assistant_response_id TEXT,
8228
+ provider TEXT,
8229
+ model TEXT,
8230
+ status TEXT NOT NULL,
8231
+ duration_ms INTEGER NOT NULL DEFAULT 0,
8232
+ args_bytes INTEGER NOT NULL DEFAULT 0,
8233
+ result_text_chars INTEGER NOT NULL DEFAULT 0,
8234
+ result_bytes INTEGER NOT NULL DEFAULT 0,
8235
+ metadata TEXT,
8236
+ created_at TEXT NOT NULL
8237
+ )`,
8238
+ `INSERT INTO agent_tool_events_v165 (
8239
+ id, project_id, agent_session_id, tool_call_id, tool_name, assistant_response_id, provider, model, status,
8240
+ duration_ms, args_bytes, result_text_chars, result_bytes, metadata, created_at
8241
+ )
8242
+ SELECT t.id, p.id, t.agent_session_id, t.tool_call_id, t.tool_name, t.assistant_response_id, t.provider, t.model, t.status,
8243
+ t.duration_ms, t.args_bytes, t.result_text_chars, t.result_bytes, t.metadata, t.created_at
8244
+ FROM agent_tool_events t
8245
+ LEFT JOIN projects p ON p.id = t.project_id`,
8246
+ `DROP TABLE agent_tool_events`,
8247
+ `ALTER TABLE agent_tool_events_v165 RENAME TO agent_tool_events`,
8248
+ `CREATE INDEX IF NOT EXISTS idx_agent_tool_events_project_created ON agent_tool_events(project_id, created_at)`,
8249
+ `CREATE INDEX IF NOT EXISTS idx_agent_tool_events_session_created ON agent_tool_events(agent_session_id, created_at)`,
8250
+ `CREATE INDEX IF NOT EXISTS idx_agent_tool_events_tool_created ON agent_tool_events(tool_name, created_at)`,
8251
+ `CREATE INDEX IF NOT EXISTS idx_agent_tool_events_status_created ON agent_tool_events(status, created_at)`
8252
+ ]
8253
+ }
8254
+ ];
8255
+ function dropAeroLedgerConversationKeys(tx) {
8256
+ for (const ledger of AERO_LEDGER_REBUILDS) {
8257
+ const keys = tx.all(sql2.raw(`PRAGMA foreign_key_list('${ledger.table}')`));
8258
+ if (!keys.some((key) => key.table === "agent_sessions")) continue;
8259
+ for (const statement of ledger.statements) tx.run(sql2.raw(statement));
8260
+ }
8261
+ }
8162
8262
  function addRunsMeasurementPlanVersionForeignKey(tx) {
8163
8263
  const tableSqlRow = tx.all(sql2.raw("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'runs'"));
8164
8264
  const tableSql = tableSqlRow[0]?.sql;
@@ -13218,11 +13318,17 @@ function registerAgentConversationRoutes(app, opts) {
13218
13318
  prepare(project.name);
13219
13319
  const existing = activeRow(project.id);
13220
13320
  if (!existing) runtime.getOrCreate(project.name);
13321
+ if (!activeRow(project.id)) {
13322
+ runtime.reset(project.name);
13323
+ runtime.getOrCreate(project.name);
13324
+ }
13221
13325
  const current = activeRow(project.id);
13326
+ if (!current) throw notFound("conversation", id);
13222
13327
  const now = (/* @__PURE__ */ new Date()).toISOString();
13223
13328
  db.transaction((tx) => {
13224
13329
  if (existing) archive(tx, current);
13225
- tx.update(agentSessions).set({ id, messages: "[]", followUpQueue: "[]", createdAt: now, updatedAt: now }).where(eq6(agentSessions.projectId, project.id)).run();
13330
+ tx.delete(agentSessions).where(eq6(agentSessions.projectId, project.id)).run();
13331
+ tx.insert(agentSessions).values({ ...current, id, messages: "[]", followUpQueue: "[]", createdAt: now, updatedAt: now }).run();
13226
13332
  writeAuditLog(tx, auditFromRequest(request, { projectId: project.id, actor: "api", action: "agent.conversation.created", entityType: "agent-conversation", entityId: id }));
13227
13333
  });
13228
13334
  runtime.reset(project.name);
@@ -13268,6 +13374,8 @@ function registerAgentConversationRoutes(app, opts) {
13268
13374
  db.transaction((tx) => {
13269
13375
  tx.delete(agentConversations).where(and2(eq6(agentConversations.projectId, project.id), eq6(agentConversations.id, id))).run();
13270
13376
  if (isActive) tx.delete(agentSessions).where(eq6(agentSessions.projectId, project.id)).run();
13377
+ tx.update(llmUsageEvents).set({ agentSessionId: null }).where(and2(eq6(llmUsageEvents.projectId, project.id), eq6(llmUsageEvents.agentSessionId, id))).run();
13378
+ tx.update(agentToolEvents).set({ agentSessionId: null }).where(and2(eq6(agentToolEvents.projectId, project.id), eq6(agentToolEvents.agentSessionId, id))).run();
13271
13379
  const prefix = `compaction:${id}:`;
13272
13380
  const notes = tx.select().from(agentMemory).where(and2(eq6(agentMemory.projectId, project.id), like(agentMemory.key, "compaction:%"))).all();
13273
13381
  for (const note of notes) if (note.key.startsWith(prefix)) tx.delete(agentMemory).where(eq6(agentMemory.id, note.id)).run();
@@ -5,7 +5,7 @@ import {
5
5
  siteCrawlGraphNodes,
6
6
  siteCrawlPages,
7
7
  siteCrawlSnapshots
8
- } from "./chunk-TPJ4MMZ6.js";
8
+ } from "./chunk-7YS62CJ4.js";
9
9
  import {
10
10
  SITE_CRAWL_GRAPH_MAX_EDGES,
11
11
  SITE_CRAWL_GRAPH_MAX_NODES,
package/dist/cli.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-T3MTYL7I.js";
38
+ } from "./chunk-7YRGVXR5.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
@@ -62,7 +62,7 @@ import {
62
62
  trustedProxiesProblem,
63
63
  trustedProxyProblem
64
64
  } from "./chunk-RB2F4D3Z.js";
65
- import "./chunk-TWYIUHJU.js";
65
+ import "./chunk-YVWYQBXW.js";
66
66
  import {
67
67
  CliError,
68
68
  EXIT_SYSTEM_ERROR,
@@ -89,7 +89,7 @@ import {
89
89
  queries,
90
90
  renderReportHtml,
91
91
  runs
92
- } from "./chunk-TPJ4MMZ6.js";
92
+ } from "./chunk-7YS62CJ4.js";
93
93
  import {
94
94
  AdsDeliverySnapshotStatuses,
95
95
  AdsHistoricalCampaignRollupStatuses,
@@ -720,7 +720,7 @@ function parseDemoTrustedProxies(values) {
720
720
  async function demoCommand(options) {
721
721
  const { host, port } = parseDemoListenOptions(options);
722
722
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
723
- const { createDemoServer } = await import("./demo-server-EU5DGFB3.js");
723
+ const { createDemoServer } = await import("./demo-server-ERFY4Q2P.js");
724
724
  const app = await createDemoServer({ trustProxy });
725
725
  let stopping = false;
726
726
  const stop = () => {
@@ -5,7 +5,7 @@ import {
5
5
  computeFactorAverages,
6
6
  layoutSiteCrawlGraphInput,
7
7
  persistSiteCrawlGraphLayout
8
- } from "./chunk-TWYIUHJU.js";
8
+ } from "./chunk-YVWYQBXW.js";
9
9
  import {
10
10
  PACKAGE_VERSION,
11
11
  canonryMcpTools
@@ -85,7 +85,7 @@ import {
85
85
  siteCrawlPages,
86
86
  siteCrawlSnapshots,
87
87
  trafficSources
88
- } from "./chunk-TPJ4MMZ6.js";
88
+ } from "./chunk-7YS62CJ4.js";
89
89
  import {
90
90
  RunKinds,
91
91
  SiteCrawlFetchStates,
package/dist/index.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-T3MTYL7I.js";
6
+ } from "./chunk-7YRGVXR5.js";
7
7
  import {
8
8
  loadConfig
9
9
  } from "./chunk-WZL73LY3.js";
10
- import "./chunk-TWYIUHJU.js";
10
+ import "./chunk-YVWYQBXW.js";
11
11
  import "./chunk-DFIK6IPP.js";
12
- import "./chunk-TPJ4MMZ6.js";
12
+ import "./chunk-7YS62CJ4.js";
13
13
  import "./chunk-RCX6I3DX.js";
14
14
  export {
15
15
  GoogleMarketingRuntimeError,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-TPJ4MMZ6.js";
4
+ } from "./chunk-7YS62CJ4.js";
5
5
  import "./chunk-RCX6I3DX.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "5.30.0",
3
+ "version": "5.30.2",
4
4
  "type": "module",
5
5
  "description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
6
6
  "keywords": [
@@ -86,34 +86,34 @@
86
86
  "@types/node-cron": "^3.0.11",
87
87
  "tsup": "^8.5.1",
88
88
  "tsx": "^4.19.0",
89
- "@ainyc/canonry-api-client": "0.0.0",
90
89
  "@ainyc/canonry-web": "0.0.0",
91
- "@ainyc/canonry-api-routes": "0.0.0",
92
- "@ainyc/canonry-contracts": "0.0.0",
90
+ "@ainyc/canonry-api-client": "0.0.0",
93
91
  "@ainyc/canonry-config": "0.0.0",
92
+ "@ainyc/canonry-contracts": "0.0.0",
93
+ "@ainyc/canonry-api-routes": "0.0.0",
94
94
  "@ainyc/canonry-db": "0.0.0",
95
95
  "@ainyc/canonry-integration-bing": "0.0.0",
96
96
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
97
97
  "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
98
- "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
99
98
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
100
- "@ainyc/canonry-integration-google-ads": "0.0.0",
99
+ "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
101
100
  "@ainyc/canonry-integration-google": "0.0.0",
101
+ "@ainyc/canonry-integration-google-ads": "0.0.0",
102
102
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
103
- "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
104
103
  "@ainyc/canonry-integration-google-places": "0.0.0",
104
+ "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
105
105
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
106
106
  "@ainyc/canonry-integration-traffic": "0.0.0",
107
- "@ainyc/canonry-intelligence": "0.0.0",
108
107
  "@ainyc/canonry-integration-wordpress": "0.0.0",
109
- "@ainyc/canonry-provider-cdp": "0.0.0",
110
- "@ainyc/canonry-provider-claude": "0.0.0",
108
+ "@ainyc/canonry-intelligence": "0.0.0",
111
109
  "@ainyc/canonry-provider-gemini": "0.0.0",
110
+ "@ainyc/canonry-provider-claude": "0.0.0",
112
111
  "@ainyc/canonry-provider-local": "0.0.0",
113
112
  "@ainyc/canonry-provider-muse": "0.0.0",
114
- "@ainyc/canonry-provider-perplexity": "0.0.0",
115
113
  "@ainyc/canonry-provider-openai": "0.0.0",
116
- "@ainyc/canonry-integration-typesafe": "0.0.0"
114
+ "@ainyc/canonry-integration-typesafe": "0.0.0",
115
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
116
+ "@ainyc/canonry-provider-cdp": "0.0.0"
117
117
  },
118
118
  "scripts": {
119
119
  "build": "pnpm run build:cli && pnpm run build:web",