@canonry/canonry 5.30.1 → 5.32.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.
- package/assets/assets/{AuditHistoryPanel-8GPJdEWL.js → AuditHistoryPanel-DW2aeqJP.js} +1 -1
- package/assets/assets/{BacklinksPage-8-KPXFtA.js → BacklinksPage-DroPpjd3.js} +1 -1
- package/assets/assets/{HistoryPage-CKgF71m5.js → HistoryPage-2o6p-ZDF.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-nfGYHl6C.js → MeasurementPropertyPage-VTGLyVuD.js} +1 -1
- package/assets/assets/{ProjectPage-BPtdO-Gp.js → ProjectPage-CXV64SBB.js} +1 -1
- package/assets/assets/{RunRow-C3CRRfb4.js → RunRow-CIhSIAoR.js} +1 -1
- package/assets/assets/{RunsPage-BvCCjtqM.js → RunsPage-lO9xMTSl.js} +1 -1
- package/assets/assets/{SettingsPage-B1QuP6Cv.js → SettingsPage-CBwns7cb.js} +1 -1
- package/assets/assets/{SiteHealthSection-DgM3aTd-.js → SiteHealthSection-C372wrfT.js} +3 -3
- package/assets/assets/{TrafficPage-DEUDhBXG.js → TrafficPage-DGyS-IjJ.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-gpgLsGA1.js → TrafficSourceDetailPage-BBaz_ivE.js} +1 -1
- package/assets/assets/{extract-error-message-CH4G5kw6.js → extract-error-message-QcHrDOjc.js} +1 -1
- package/assets/assets/{index-B2qeAPfR.js → index-CbnQjcJj.js} +3 -3
- package/assets/assets/{react-sigma_core.esm.min-CG4hSMQ3.js → react-sigma_core.esm.min-D9tjGma4.js} +1 -1
- package/assets/assets/{v2-overview-adapter-QNwqt0UG.js → v2-overview-adapter-CLlJkExr.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-LLVE7B3V.js → chunk-6UO23AKO.js} +150 -67
- package/dist/{chunk-TPJ4MMZ6.js → chunk-7YS62CJ4.js} +111 -3
- package/dist/{chunk-TWYIUHJU.js → chunk-YVWYQBXW.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/{demo-server-EU5DGFB3.js → demo-server-ERFY4Q2P.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/{intelligence-service-SUFG6ICC.js → intelligence-service-PULUYOPR.js} +1 -1
- package/package.json +12 -13
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
persistSiteCrawlGraphLayout,
|
|
27
27
|
prepareSiteCrawlGraphLayout,
|
|
28
28
|
recordedSharePct
|
|
29
|
-
} from "./chunk-
|
|
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-
|
|
217
|
+
} from "./chunk-7YS62CJ4.js";
|
|
218
218
|
import {
|
|
219
219
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
220
220
|
AGENT_NONE,
|
|
@@ -7830,7 +7830,7 @@ function nonBlank(value) {
|
|
|
7830
7830
|
return trimmed ? trimmed : void 0;
|
|
7831
7831
|
}
|
|
7832
7832
|
function resolveBuildCommit(env = process.env) {
|
|
7833
|
-
const embedded = true ? "
|
|
7833
|
+
const embedded = true ? "b5129303a169ae8903dbf5febfcb10067f0507a1" : void 0;
|
|
7834
7834
|
return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
|
|
7835
7835
|
}
|
|
7836
7836
|
function resolveInstanceIdentity(env = process.env) {
|
|
@@ -9655,9 +9655,9 @@ var JobRunner = class {
|
|
|
9655
9655
|
const parent = txDb.select({ projectId: runs.projectId, createdAt: runs.createdAt, error: runs.error }).from(runs).where(eq3(runs.id, input.runId)).get();
|
|
9656
9656
|
const superseded = input.superseded || parent !== void 0 && newerFullSweep(txDb, { id: input.runId, projectId: parent.projectId, createdAt: parent.createdAt }) !== void 0;
|
|
9657
9657
|
const state = measurementRunSlotState(txDb, input.runId);
|
|
9658
|
-
const
|
|
9658
|
+
const complete = state.planned && state.readable && state.missing.length === 0 && !state.hasUnboundSnapshot;
|
|
9659
9659
|
let justCompleted = false;
|
|
9660
|
-
if (
|
|
9660
|
+
if (complete) {
|
|
9661
9661
|
justCompleted = txDb.update(runs).set({ status: "completed", error: null }).where(and3(eq3(runs.id, input.runId), eq3(runs.status, "partial"))).run().changes === 1;
|
|
9662
9662
|
if (justCompleted && parent) recordSentimentCompletion(tx, { projectId: parent.projectId, runId: input.runId, completionKey: input.fillId, completedAt: finishedAt, fillOrigin: input.fillId });
|
|
9663
9663
|
} else if (state.readable && !input.fatal) {
|
|
@@ -9671,9 +9671,9 @@ var JobRunner = class {
|
|
|
9671
9671
|
}
|
|
9672
9672
|
txDb.update(runs).set({ error: serializeRunError({ providers }) }).where(and3(eq3(runs.id, input.runId), eq3(runs.status, "partial"))).run();
|
|
9673
9673
|
}
|
|
9674
|
-
const status =
|
|
9674
|
+
const status = complete ? "completed" : input.filled > 0 ? "partial" : "failed";
|
|
9675
9675
|
const reason = input.fatal ?? (superseded ? "Stopped because a newer sweep started; no answers were added behind it." : null) ?? (input.providerErrors.size > 0 ? formatRunErrorOneLine(buildRunErrorFromMessages(input.providerErrors)) : null);
|
|
9676
|
-
txDb.update(runFills).set({ status, filled: input.filled, error:
|
|
9676
|
+
txDb.update(runFills).set({ status, filled: input.filled, error: complete ? null : reason, finishedAt }).where(eq3(runFills.id, input.fillId)).run();
|
|
9677
9677
|
return { justCompleted, superseded };
|
|
9678
9678
|
});
|
|
9679
9679
|
}
|
|
@@ -14452,7 +14452,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
14452
14452
|
return result2;
|
|
14453
14453
|
}
|
|
14454
14454
|
async function backfillInsightsCommand(project, opts) {
|
|
14455
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
14455
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-PULUYOPR.js");
|
|
14456
14456
|
const config = loadConfig();
|
|
14457
14457
|
const db = createClient(config.database);
|
|
14458
14458
|
migrate(db);
|
|
@@ -16679,14 +16679,45 @@ import { eq as eq24 } from "drizzle-orm";
|
|
|
16679
16679
|
// src/agent/session.ts
|
|
16680
16680
|
import fs8 from "fs";
|
|
16681
16681
|
import path7 from "path";
|
|
16682
|
-
import { Agent } from "@
|
|
16683
|
-
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
|
|
16682
|
+
import { Agent } from "@earendil-works/pi-agent-core";
|
|
16684
16683
|
|
|
16685
16684
|
// src/agent/providers.ts
|
|
16685
|
+
import "@earendil-works/pi-ai";
|
|
16686
|
+
|
|
16687
|
+
// src/agent/pi-models.ts
|
|
16686
16688
|
import {
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
} from "@
|
|
16689
|
+
createProvider,
|
|
16690
|
+
envApiKeyAuth
|
|
16691
|
+
} from "@earendil-works/pi-ai";
|
|
16692
|
+
import { builtinModels } from "@earendil-works/pi-ai/providers/all";
|
|
16693
|
+
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
16694
|
+
var aeroModels = builtinModels();
|
|
16695
|
+
aeroModels.setProvider(createProvider({
|
|
16696
|
+
id: "deepinfra",
|
|
16697
|
+
auth: { apiKey: envApiKeyAuth("DeepInfra", ["DEEPINFRA_TOKEN"]) },
|
|
16698
|
+
models: [],
|
|
16699
|
+
api: openAICompletionsApi()
|
|
16700
|
+
}));
|
|
16701
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
16702
|
+
var DEFAULT_MAX_OUTPUT_TOKENS = 32e3;
|
|
16703
|
+
var CANONRY_USER_AGENT = "canonry";
|
|
16704
|
+
function outputCap(model) {
|
|
16705
|
+
return Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS);
|
|
16706
|
+
}
|
|
16707
|
+
function canonryDefaults(model, options) {
|
|
16708
|
+
return {
|
|
16709
|
+
...options,
|
|
16710
|
+
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
16711
|
+
maxTokens: options?.maxTokens ?? outputCap(model),
|
|
16712
|
+
headers: { "User-Agent": CANONRY_USER_AGENT, ...options?.headers }
|
|
16713
|
+
};
|
|
16714
|
+
}
|
|
16715
|
+
var aeroStreamFn = (model, context, options) => aeroModels.streamSimple(model, context, canonryDefaults(model, options));
|
|
16716
|
+
function completeOnce(model, context, options = {}) {
|
|
16717
|
+
return aeroModels.complete(model, context, canonryDefaults(model, options));
|
|
16718
|
+
}
|
|
16719
|
+
|
|
16720
|
+
// src/agent/providers.ts
|
|
16690
16721
|
var PROVIDER_MODELS = {
|
|
16691
16722
|
[AgentProviderIds.claude]: {
|
|
16692
16723
|
[LlmCapabilities.agent]: "claude-opus-4-7",
|
|
@@ -16707,9 +16738,10 @@ var PROVIDER_MODELS = {
|
|
|
16707
16738
|
[LlmCapabilities.classify]: "gemini-2.5-flash-lite"
|
|
16708
16739
|
},
|
|
16709
16740
|
[AgentProviderIds.zai]: {
|
|
16710
|
-
// GLM lineage: 5.
|
|
16711
|
-
// cheaper tier good for structured tasks and
|
|
16712
|
-
|
|
16741
|
+
// GLM lineage: 5.2 replaced 5.1, which pi-ai 0.87 dropped from its
|
|
16742
|
+
// catalog; 5-turbo is the cheaper tier good for structured tasks and
|
|
16743
|
+
// classification.
|
|
16744
|
+
[LlmCapabilities.agent]: "glm-5.2",
|
|
16713
16745
|
[LlmCapabilities.analyze]: "glm-5-turbo",
|
|
16714
16746
|
[LlmCapabilities.classify]: "glm-5-turbo"
|
|
16715
16747
|
},
|
|
@@ -16811,9 +16843,10 @@ var AGENT_PROVIDERS = {
|
|
|
16811
16843
|
},
|
|
16812
16844
|
// Fallback for arbitrary `--model` slugs we don't ship as tiers. cost is
|
|
16813
16845
|
// 0, so an unknown slug isn't cost-tracked by pi-ai's `calculateCost`;
|
|
16814
|
-
// contextWindow
|
|
16846
|
+
// contextWindow is 0 (unknown) because a guessed window would clamp a long
|
|
16847
|
+
// turn's output cap toward 1 token; the host enforces its real window.
|
|
16815
16848
|
defaultModelMeta: {
|
|
16816
|
-
contextWindow:
|
|
16849
|
+
contextWindow: 0,
|
|
16817
16850
|
maxTokens: 32768,
|
|
16818
16851
|
reasoning: false,
|
|
16819
16852
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
@@ -16844,10 +16877,10 @@ function resolveModelForCapability(provider, capability, modelIdOverride) {
|
|
|
16844
16877
|
const suppressThinking = capability !== LlmCapabilities.agent;
|
|
16845
16878
|
return buildOpenAiCompatibleModel(entry, id, suppressThinking);
|
|
16846
16879
|
}
|
|
16847
|
-
const model = getModel(entry.piAiProvider, id);
|
|
16880
|
+
const model = aeroModels.getModel(entry.piAiProvider, id);
|
|
16848
16881
|
if (!model) {
|
|
16849
16882
|
throw new Error(
|
|
16850
|
-
`Model '${id}' not found for pi-ai provider '${entry.piAiProvider}'. Verify PROVIDER_MODELS[${provider}][${capability}] against the installed @
|
|
16883
|
+
`Model '${id}' not found for pi-ai provider '${entry.piAiProvider}'. Verify PROVIDER_MODELS[${provider}][${capability}] against the installed @earendil-works/pi-ai catalog.`
|
|
16851
16884
|
);
|
|
16852
16885
|
}
|
|
16853
16886
|
if (provider === AgentProviderIds.gemini && process.env.GEMINI_BASE_URL) {
|
|
@@ -16864,7 +16897,7 @@ function buildOpenAiCompatibleModel(entry, id, suppressThinking = false) {
|
|
|
16864
16897
|
}
|
|
16865
16898
|
const meta = host.knownModels[id] ?? host.defaultModelMeta;
|
|
16866
16899
|
const baseUrl = (host.baseUrlEnvVar ? process.env[host.baseUrlEnvVar] : void 0) || host.baseUrl;
|
|
16867
|
-
const compat = suppressThinking ? { ...host.compat, thinkingFormat: "
|
|
16900
|
+
const compat = suppressThinking ? { ...host.compat, thinkingFormat: "chat-template", chatTemplateKwargs: { enable_thinking: { $var: "thinking.enabled" } } } : host.compat;
|
|
16868
16901
|
return {
|
|
16869
16902
|
id,
|
|
16870
16903
|
name: id,
|
|
@@ -16879,6 +16912,10 @@ function buildOpenAiCompatibleModel(entry, id, suppressThinking = false) {
|
|
|
16879
16912
|
...compat ? { compat } : {}
|
|
16880
16913
|
};
|
|
16881
16914
|
}
|
|
16915
|
+
function isAgentModelAvailable(provider, id) {
|
|
16916
|
+
const entry = AGENT_PROVIDERS[provider];
|
|
16917
|
+
return !!entry.openaiCompatible || !!aeroModels.getModel(entry.piAiProvider, id);
|
|
16918
|
+
}
|
|
16882
16919
|
function validateAgentProviderRegistry() {
|
|
16883
16920
|
for (const provider of listAgentProviders()) {
|
|
16884
16921
|
for (const capability of LLM_CAPABILITIES) {
|
|
@@ -16899,16 +16936,26 @@ function resolveApiKeyFor(providerOrPiAi, config) {
|
|
|
16899
16936
|
function resolveApiKeySource(providerOrPiAi, config) {
|
|
16900
16937
|
const id = resolveAgentId(providerOrPiAi);
|
|
16901
16938
|
if (!id) return void 0;
|
|
16902
|
-
const entry = AGENT_PROVIDERS[id];
|
|
16903
16939
|
const fromConfig = config.providers?.[id]?.apiKey;
|
|
16904
16940
|
if (fromConfig) return { key: fromConfig, source: "config" };
|
|
16905
|
-
const fromEnv =
|
|
16941
|
+
const fromEnv = agentProviderApiKeyEnvVars(id).map((name) => process.env[name]).find((value) => !!value);
|
|
16906
16942
|
if (fromEnv) return { key: fromEnv, source: "env" };
|
|
16907
16943
|
return void 0;
|
|
16908
16944
|
}
|
|
16909
|
-
|
|
16945
|
+
var CATALOG_API_KEY_ENV_VARS = {
|
|
16946
|
+
anthropic: ["ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"],
|
|
16947
|
+
openai: ["OPENAI_API_KEY"],
|
|
16948
|
+
google: ["GEMINI_API_KEY"],
|
|
16949
|
+
zai: ["ZAI_API_KEY"]
|
|
16950
|
+
};
|
|
16951
|
+
function agentProviderApiKeyEnvVars(id) {
|
|
16910
16952
|
const entry = AGENT_PROVIDERS[id];
|
|
16911
|
-
|
|
16953
|
+
if (entry.openaiCompatible) return [entry.openaiCompatible.apiKeyEnvVar];
|
|
16954
|
+
return CATALOG_API_KEY_ENV_VARS[entry.piAiProvider] ?? [`${entry.piAiProvider.toUpperCase()}_API_KEY`];
|
|
16955
|
+
}
|
|
16956
|
+
function agentProviderApiKeyEnvVar(id) {
|
|
16957
|
+
const names = agentProviderApiKeyEnvVars(id);
|
|
16958
|
+
return names[names.length - 1];
|
|
16912
16959
|
}
|
|
16913
16960
|
function resolveAgentId(providerOrPiAi) {
|
|
16914
16961
|
if (isAgentProviderId(providerOrPiAi)) return providerOrPiAi;
|
|
@@ -16959,7 +17006,7 @@ function resolveAeroSkillDir(pkgDir) {
|
|
|
16959
17006
|
// src/agent/skill-tools.ts
|
|
16960
17007
|
import fs7 from "fs";
|
|
16961
17008
|
import path6 from "path";
|
|
16962
|
-
import { Type } from "@
|
|
17009
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
16963
17010
|
var MAX_DOC_CHARS = 2e4;
|
|
16964
17011
|
function textResult(details) {
|
|
16965
17012
|
return {
|
|
@@ -17050,10 +17097,10 @@ function buildSkillDocTools() {
|
|
|
17050
17097
|
}
|
|
17051
17098
|
|
|
17052
17099
|
// src/agent/tools.ts
|
|
17053
|
-
import { Type as Type3 } from "@
|
|
17100
|
+
import { Type as Type3 } from "@earendil-works/pi-ai";
|
|
17054
17101
|
|
|
17055
17102
|
// src/agent/mcp-to-agent-tool.ts
|
|
17056
|
-
import { Type as Type2 } from "@
|
|
17103
|
+
import { Type as Type2 } from "@earendil-works/pi-ai";
|
|
17057
17104
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
17058
17105
|
|
|
17059
17106
|
// src/agent/tool-result-units.ts
|
|
@@ -18076,7 +18123,12 @@ function splitAeroAnthropicSystemCachePayload(payload, model) {
|
|
|
18076
18123
|
|
|
18077
18124
|
// src/agent/runtime.ts
|
|
18078
18125
|
import { z } from "zod";
|
|
18079
|
-
import {
|
|
18126
|
+
import {
|
|
18127
|
+
Type as Type4,
|
|
18128
|
+
createInitialSystemMessage,
|
|
18129
|
+
getCurrentTools,
|
|
18130
|
+
toToolDeclaration
|
|
18131
|
+
} from "@earendil-works/pi-ai";
|
|
18080
18132
|
var DISCOVER = "aero_list_toolkits";
|
|
18081
18133
|
var MAX_VISIBLE_TOOLS = 128;
|
|
18082
18134
|
var LOAD = "aero_load_toolkit";
|
|
@@ -18209,20 +18261,23 @@ function configureAeroRuntime(agent, allowed, limits, progressive = true, pinned
|
|
|
18209
18261
|
runtime = { allowed, loaded: /* @__PURE__ */ new Set(), limits: agentTurnLimitsSchema.parse(limits ?? {}), calls: 0, rounds: 0, startedAt: 0, reason: "completed", progressive, pinned: new Set(pinned), corrected: /* @__PURE__ */ new Map() };
|
|
18210
18262
|
runtimes.set(agent, runtime);
|
|
18211
18263
|
const state = runtime;
|
|
18212
|
-
const stream = agent.
|
|
18213
|
-
agent.
|
|
18264
|
+
const stream = agent.streamFunction;
|
|
18265
|
+
agent.streamFunction = (model, context, options) => {
|
|
18214
18266
|
options?.signal?.throwIfAborted();
|
|
18215
18267
|
state.rounds++;
|
|
18216
|
-
const visible = new Set((context.
|
|
18268
|
+
const visible = new Set(getCurrentTools(context.messages).map((tool) => tool.name));
|
|
18217
18269
|
const response = stream(model, context, options);
|
|
18218
18270
|
return response instanceof Promise ? response.then((ready) => withCorrectedToolNames(state, ready, visible)) : withCorrectedToolNames(state, response, visible);
|
|
18219
18271
|
};
|
|
18220
18272
|
const before = agent.beforeToolCall;
|
|
18221
18273
|
const after = agent.afterToolCall;
|
|
18274
|
+
const overLimit = /* @__PURE__ */ new Set();
|
|
18222
18275
|
agent.beforeToolCall = async (event, signal) => {
|
|
18223
|
-
if (signal?.aborted) return { block: true, reason: "Turn stopped." };
|
|
18276
|
+
if (signal?.aborted || overLimit.has(event.toolCall.id)) return { block: true, reason: "Turn stopped." };
|
|
18224
18277
|
return before?.(event, signal);
|
|
18225
18278
|
};
|
|
18279
|
+
const finish = agent.finishTurn;
|
|
18280
|
+
agent.finishTurn = (turn, signal) => state.reason === "tool-limit" ? { action: "end" } : finish?.(turn, signal);
|
|
18226
18281
|
agent.afterToolCall = async (event, signal) => {
|
|
18227
18282
|
const override = await after?.(event, signal);
|
|
18228
18283
|
if (event.toolCall.name === LOAD && !event.isError) {
|
|
@@ -18233,31 +18288,39 @@ function configureAeroRuntime(agent, allowed, limits, progressive = true, pinned
|
|
|
18233
18288
|
return override;
|
|
18234
18289
|
};
|
|
18235
18290
|
const toolStarts = /* @__PURE__ */ new Map();
|
|
18291
|
+
const toolDurations = /* @__PURE__ */ new Map();
|
|
18236
18292
|
agent.subscribe((event) => {
|
|
18237
18293
|
if (event.type === "tool_execution_start") {
|
|
18238
18294
|
if (state.calls >= state.limits.maxToolCalls) {
|
|
18239
18295
|
state.reason = "tool-limit";
|
|
18240
|
-
|
|
18296
|
+
overLimit.add(event.toolCallId);
|
|
18241
18297
|
} else if (!agent.signal?.aborted) {
|
|
18242
18298
|
state.calls++;
|
|
18243
|
-
toolStarts.set(event.toolCallId, Date.now());
|
|
18244
18299
|
}
|
|
18300
|
+
toolStarts.set(event.toolCallId, Date.now());
|
|
18301
|
+
}
|
|
18302
|
+
if (event.type === "tool_execution_end") {
|
|
18303
|
+
const startedAt = toolStarts.get(event.toolCallId);
|
|
18304
|
+
if (startedAt !== void 0) toolDurations.set(event.toolCallId, Date.now() - startedAt);
|
|
18305
|
+
toolStarts.delete(event.toolCallId);
|
|
18245
18306
|
}
|
|
18246
18307
|
if (event.type === "message_end" && event.message.role === "toolResult") {
|
|
18247
18308
|
const message = event.message;
|
|
18248
18309
|
explainMissingTool(state, message);
|
|
18249
|
-
const
|
|
18310
|
+
const durationMs = toolDurations.get(message.toolCallId);
|
|
18250
18311
|
const requested = state.corrected.get(message.toolCallId);
|
|
18251
18312
|
Object.assign(message, {
|
|
18252
18313
|
aeroToolLabel: state.allowed.find((tool) => tool.name === message.toolName)?.label,
|
|
18253
|
-
...
|
|
18314
|
+
...durationMs === void 0 ? {} : { aeroDurationMs: durationMs },
|
|
18254
18315
|
...requested === void 0 ? {} : { aeroRequestedToolName: requested }
|
|
18255
18316
|
});
|
|
18256
|
-
|
|
18317
|
+
toolDurations.delete(message.toolCallId);
|
|
18257
18318
|
state.corrected.delete(message.toolCallId);
|
|
18258
18319
|
}
|
|
18259
18320
|
if (event.type === "agent_start") {
|
|
18260
18321
|
toolStarts.clear();
|
|
18322
|
+
toolDurations.clear();
|
|
18323
|
+
overLimit.clear();
|
|
18261
18324
|
state.corrected.clear();
|
|
18262
18325
|
state.calls = 0;
|
|
18263
18326
|
state.rounds = 0;
|
|
@@ -18283,6 +18346,22 @@ function configureAeroRuntime(agent, allowed, limits, progressive = true, pinned
|
|
|
18283
18346
|
runtime.progressive = progressive;
|
|
18284
18347
|
runtime.pinned = new Set(pinned);
|
|
18285
18348
|
agent.state.tools = visibleTools(runtime);
|
|
18349
|
+
setAeroSystemPrompt(agent);
|
|
18350
|
+
}
|
|
18351
|
+
function isSystemMessage(message) {
|
|
18352
|
+
return !!message && typeof message === "object" && message.role === "system";
|
|
18353
|
+
}
|
|
18354
|
+
function isRunFailureMessage(message) {
|
|
18355
|
+
if (!message || typeof message !== "object") return false;
|
|
18356
|
+
const m = message;
|
|
18357
|
+
if (m.role !== "assistant" || m.stopReason !== "aborted" && m.stopReason !== "error" || m.responseId) return false;
|
|
18358
|
+
const content = Array.isArray(m.content) ? m.content : [];
|
|
18359
|
+
return content.length === 1 && content[0].type === "text" && content[0].text === "" && m.usage?.totalTokens === 0;
|
|
18360
|
+
}
|
|
18361
|
+
function setAeroSystemPrompt(agent, prompt = agent.state.systemPrompt) {
|
|
18362
|
+
const system = createInitialSystemMessage(prompt, agent.state.tools.map(toToolDeclaration));
|
|
18363
|
+
const rest = agent.state.messages.filter((message) => message.role !== "system");
|
|
18364
|
+
agent.state.messages = system ? [system, ...rest] : rest;
|
|
18286
18365
|
}
|
|
18287
18366
|
function aeroTurnStatus(agent) {
|
|
18288
18367
|
const runtime = runtimes.get(agent);
|
|
@@ -18296,7 +18375,7 @@ function aeroTurnStatus(agent) {
|
|
|
18296
18375
|
}
|
|
18297
18376
|
|
|
18298
18377
|
// src/agent/view-context.ts
|
|
18299
|
-
import { Type as Type5 } from "@
|
|
18378
|
+
import { Type as Type5 } from "@earendil-works/pi-ai";
|
|
18300
18379
|
async function readAeroViewEvidence(options) {
|
|
18301
18380
|
const { client, projectName, context } = options;
|
|
18302
18381
|
if (context?.unavailableReason) throw validationError(context.unavailableReason);
|
|
@@ -18424,7 +18503,6 @@ function recordAgentToolEvent(args) {
|
|
|
18424
18503
|
var builtinsRegistered = false;
|
|
18425
18504
|
function ensureBuiltinsRegistered() {
|
|
18426
18505
|
if (!builtinsRegistered) {
|
|
18427
|
-
registerBuiltInApiProviders();
|
|
18428
18506
|
validateAgentProviderRegistry();
|
|
18429
18507
|
builtinsRegistered = true;
|
|
18430
18508
|
}
|
|
@@ -18528,7 +18606,7 @@ function createAeroSession(opts) {
|
|
|
18528
18606
|
tools,
|
|
18529
18607
|
...opts.initialMessages ? { messages: opts.initialMessages } : {}
|
|
18530
18608
|
},
|
|
18531
|
-
streamFn: opts.streamFn,
|
|
18609
|
+
streamFn: opts.streamFn ?? aeroStreamFn,
|
|
18532
18610
|
sessionId: buildAeroProviderSessionId(opts),
|
|
18533
18611
|
onPayload: splitAeroAnthropicSystemCachePayload,
|
|
18534
18612
|
...toolUsageHooks,
|
|
@@ -18540,6 +18618,7 @@ function createAeroSession(opts) {
|
|
|
18540
18618
|
agent.subscribe((event) => {
|
|
18541
18619
|
if (event.type !== "turn_end") return;
|
|
18542
18620
|
if (event.message.role !== "assistant") return;
|
|
18621
|
+
if (isRunFailureMessage(event.message)) return;
|
|
18543
18622
|
recordLlmUsageEvent({
|
|
18544
18623
|
db: telemetryDb,
|
|
18545
18624
|
projectId: opts.projectId,
|
|
@@ -18564,7 +18643,7 @@ function resolveSessionProviderAndModel(config, opts) {
|
|
|
18564
18643
|
}
|
|
18565
18644
|
|
|
18566
18645
|
// src/agent/remote-mcp.ts
|
|
18567
|
-
import { Type as Type6 } from "@
|
|
18646
|
+
import { Type as Type6 } from "@earendil-works/pi-ai";
|
|
18568
18647
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
18569
18648
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
18570
18649
|
var log21 = createLogger("RemoteMcp");
|
|
@@ -18821,9 +18900,6 @@ Project shape: a Simple project with ${tracked} tracked queries and no measureme
|
|
|
18821
18900
|
}
|
|
18822
18901
|
}
|
|
18823
18902
|
|
|
18824
|
-
// src/agent/compaction.ts
|
|
18825
|
-
import { complete } from "@mariozechner/pi-ai";
|
|
18826
|
-
|
|
18827
18903
|
// src/agent/compaction-config.ts
|
|
18828
18904
|
var COMPACTION_TOKEN_THRESHOLD = 6e4;
|
|
18829
18905
|
var COMPACTION_TARGET_RATIO = 0.5;
|
|
@@ -18875,8 +18951,12 @@ function estimateTranscriptTokens(messages) {
|
|
|
18875
18951
|
|
|
18876
18952
|
// src/agent/compaction.ts
|
|
18877
18953
|
function shouldCompact(messages) {
|
|
18878
|
-
|
|
18879
|
-
|
|
18954
|
+
const turns = conversationMessages(messages);
|
|
18955
|
+
if (turns.length >= COMPACTION_MAX_MESSAGES) return true;
|
|
18956
|
+
return estimateTranscriptTokens(turns) >= COMPACTION_TOKEN_THRESHOLD;
|
|
18957
|
+
}
|
|
18958
|
+
function conversationMessages(messages) {
|
|
18959
|
+
return messages.filter((message) => message.role !== "system");
|
|
18880
18960
|
}
|
|
18881
18961
|
function findSafeSplit(messages, targetIndex) {
|
|
18882
18962
|
const maxSplit = messages.length - COMPACTION_PRESERVE_TAIL_MESSAGES;
|
|
@@ -18922,18 +19002,19 @@ async function runSummaryLlm(args) {
|
|
|
18922
19002
|
messages: toLlmMessages(args.chunk)
|
|
18923
19003
|
};
|
|
18924
19004
|
const apiKey = args.getApiKey?.(args.model.provider);
|
|
18925
|
-
const resp = await
|
|
19005
|
+
const resp = await completeOnce(args.model, context, apiKey ? { apiKey } : {});
|
|
18926
19006
|
const parts = resp.content.filter((p) => p.type === "text");
|
|
18927
19007
|
const text = parts.map((p) => p.text).join("\n").trim();
|
|
18928
19008
|
if (!text) throw new Error("summary LLM returned no text content");
|
|
18929
19009
|
return text;
|
|
18930
19010
|
}
|
|
18931
19011
|
async function compactMessages(args) {
|
|
18932
|
-
const
|
|
18933
|
-
const
|
|
19012
|
+
const messages = conversationMessages(args.messages);
|
|
19013
|
+
const target = Math.floor(messages.length * COMPACTION_TARGET_RATIO);
|
|
19014
|
+
const split = findSafeSplit(messages, target);
|
|
18934
19015
|
if (split === 0) return null;
|
|
18935
|
-
const chunk =
|
|
18936
|
-
const suffix =
|
|
19016
|
+
const chunk = messages.slice(0, split);
|
|
19017
|
+
const suffix = messages.slice(split);
|
|
18937
19018
|
const summarize = args.summarize ?? runSummaryLlm;
|
|
18938
19019
|
const rawSummary = await summarize({ model: args.model, chunk, getApiKey: args.getApiKey });
|
|
18939
19020
|
const summary = truncateToByteLimit(rawSummary, AGENT_MEMORY_VALUE_MAX_BYTES);
|
|
@@ -18954,7 +19035,7 @@ function escapeMemoryFragment(value) {
|
|
|
18954
19035
|
return value.replace(/<(\/?)memory>/gi, "<$1\u200Cmemory>");
|
|
18955
19036
|
}
|
|
18956
19037
|
function withoutPersistedToolDetails(messages) {
|
|
18957
|
-
return messages.map((message) => {
|
|
19038
|
+
return messages.filter((message) => !isSystemMessage(message)).map((message) => {
|
|
18958
19039
|
if (!message || typeof message !== "object") return message;
|
|
18959
19040
|
const row = message;
|
|
18960
19041
|
if (row.role !== "toolResult" || !("details" in row)) return message;
|
|
@@ -19182,7 +19263,8 @@ ${lines.join("\n")}
|
|
|
19182
19263
|
if (!projectId) return;
|
|
19183
19264
|
const row = this.loadRow(projectId);
|
|
19184
19265
|
if (!row) return;
|
|
19185
|
-
agent.state.
|
|
19266
|
+
if (agent.state.isStreaming) return;
|
|
19267
|
+
setAeroSystemPrompt(agent, this.buildHydratedSystemPrompt(projectId, row.systemPrompt));
|
|
19186
19268
|
}
|
|
19187
19269
|
/**
|
|
19188
19270
|
* Acquire the Agent for an upcoming prompt/turn.
|
|
@@ -19214,10 +19296,7 @@ ${lines.join("\n")}
|
|
|
19214
19296
|
const projectId = this.resolveProjectId(projectName);
|
|
19215
19297
|
const row = this.loadRow(projectId);
|
|
19216
19298
|
const systemPrompt = loadAeroSystemPrompt();
|
|
19217
|
-
if (row && row.systemPrompt !== systemPrompt)
|
|
19218
|
-
this.persistPromptSnapshot(projectId, systemPrompt);
|
|
19219
|
-
agent.state.systemPrompt = this.buildHydratedSystemPrompt(projectId, systemPrompt);
|
|
19220
|
-
}
|
|
19299
|
+
if (row && row.systemPrompt !== systemPrompt) this.persistPromptSnapshot(projectId, systemPrompt);
|
|
19221
19300
|
this.alignToolSurface(projectName, agent, {
|
|
19222
19301
|
scope: preferences?.toolScope ?? AeroToolScopes.all,
|
|
19223
19302
|
profile: preferences?.toolProfile ?? AeroToolProfiles.default
|
|
@@ -19232,7 +19311,7 @@ ${lines.join("\n")}
|
|
|
19232
19311
|
preferences?.signal?.throwIfAborted();
|
|
19233
19312
|
const progressive = (preferences?.toolProfile ?? AeroToolProfiles.default) === AeroToolProfiles.default;
|
|
19234
19313
|
const shape = aeroProjectShape(this.opts.db, projectId);
|
|
19235
|
-
agent
|
|
19314
|
+
setAeroSystemPrompt(agent, this.buildHydratedSystemPrompt(projectId, systemPrompt) + shape.prompt + aeroViewPrompt(preferences?.context));
|
|
19236
19315
|
configureAeroRuntime(agent, [...agent.state.tools, ...progressive ? [buildAeroViewTool(view, evidence)] : []], preferences?.limits, progressive, shape.pinned);
|
|
19237
19316
|
return agent;
|
|
19238
19317
|
} finally {
|
|
@@ -19280,7 +19359,7 @@ ${lines.join("\n")}
|
|
|
19280
19359
|
});
|
|
19281
19360
|
if (!result2) return;
|
|
19282
19361
|
agent.state.messages = result2.messages;
|
|
19283
|
-
agent
|
|
19362
|
+
setAeroSystemPrompt(agent, this.buildHydratedSystemPrompt(projectId, row.systemPrompt));
|
|
19284
19363
|
this.save(projectName);
|
|
19285
19364
|
log22.info("compaction.completed", {
|
|
19286
19365
|
projectName,
|
|
@@ -19340,7 +19419,7 @@ ${lines.join("\n")}
|
|
|
19340
19419
|
resolveTurnModel(preferences, current) {
|
|
19341
19420
|
const pinned = resolveConfiguredAgentProvider(this.opts.config);
|
|
19342
19421
|
const provider = preferences?.provider ?? pinned ?? current.provider ?? AgentProviderIds.claude;
|
|
19343
|
-
const carried = !preferences?.provider && !pinned && provider === current.provider
|
|
19422
|
+
const carried = !preferences?.provider && !pinned && provider === current.provider && current.modelId && isAgentModelAvailable(provider, current.modelId) ? current.modelId : void 0;
|
|
19344
19423
|
const pinnedModelId = provider === pinned ? this.opts.config.agent?.model ?? void 0 : void 0;
|
|
19345
19424
|
const modelId = preferences?.modelId ?? pinnedModelId ?? carried ?? getAgentProvider(provider).defaultModel;
|
|
19346
19425
|
return { provider, modelId };
|
|
@@ -19692,12 +19771,12 @@ var ViewerAeroSessions = class {
|
|
|
19692
19771
|
try {
|
|
19693
19772
|
const client = new ApiClient(this.opts.selfApiUrl, minted.raw, { skipProbe: true, surface: "aero" });
|
|
19694
19773
|
const agent = this.sessions.get(key)?.agent ?? this.createAgent(project, client);
|
|
19695
|
-
agent.state.messages = trimViewerTranscript(agent.state.messages);
|
|
19774
|
+
agent.state.messages = trimViewerTranscript(agent.state.messages.filter((message) => message.role !== "system"));
|
|
19696
19775
|
const view = { client, projectName: project.name, basePath: this.opts.config.basePath, context: preferences.context };
|
|
19697
19776
|
const evidence = preferences.context ? await readAeroViewEvidence(view) : void 0;
|
|
19698
19777
|
preferences.signal?.throwIfAborted();
|
|
19699
19778
|
const shape = aeroProjectShape(this.opts.db, project.id);
|
|
19700
|
-
agent
|
|
19779
|
+
setAeroSystemPrompt(agent, loadAeroSystemPrompt(void 0, { extras: false }) + VIEWER_AERO_PROMPT + shape.prompt + aeroViewPrompt(preferences.context));
|
|
19701
19780
|
configureAeroRuntime(agent, [...buildViewerAeroTools(client, project.name, this.opts.managedSweeps), buildAeroViewTool(view, evidence)], void 0, true, shape.pinned);
|
|
19702
19781
|
this.sessions.set(key, { agent, lastUsedAt: this.now(), updatedAt: this.sessions.get(key)?.updatedAt ?? null });
|
|
19703
19782
|
this.turnsToday.set(key, { date: today, count: count3 + 1 });
|
|
@@ -19988,7 +20067,7 @@ function viewerAeroCaller(request, opts) {
|
|
|
19988
20067
|
const principal = request.principal;
|
|
19989
20068
|
return principal?.kind === "user" && principal.role === UserRoles.viewer ? principal.id : null;
|
|
19990
20069
|
}
|
|
19991
|
-
var VIEWER_HIDDEN_ASSISTANT_KEYS = ["api", "provider", "model", "responseId", "usage"];
|
|
20070
|
+
var VIEWER_HIDDEN_ASSISTANT_KEYS = ["api", "provider", "model", "responseId", "usage", "responseModel", "diagnostics", "providerThinkingLevel", "rawStopReason"];
|
|
19992
20071
|
var VIEWER_ERROR_MESSAGE = "Aero could not finish this answer. Try again, or ask an administrator if it keeps happening.";
|
|
19993
20072
|
function viewerRedact(_key, value) {
|
|
19994
20073
|
if (!value || typeof value !== "object" || value.role !== "assistant") return value;
|
|
@@ -20043,6 +20122,11 @@ async function streamAgentTurn(reply, agent, turn) {
|
|
|
20043
20122
|
};
|
|
20044
20123
|
write({ type: "stream_open" });
|
|
20045
20124
|
const unsubscribe = agent.subscribe((event) => {
|
|
20125
|
+
if ("message" in event && (isSystemMessage(event.message) || isRunFailureMessage(event.message))) return;
|
|
20126
|
+
if (event.type === "agent_end") {
|
|
20127
|
+
write({ ...event, messages: event.messages.filter((message) => !isSystemMessage(message)) });
|
|
20128
|
+
return;
|
|
20129
|
+
}
|
|
20046
20130
|
if (event.type === "tool_execution_start") {
|
|
20047
20131
|
const labelled = { ...event, label: agent.state.tools.find((tool) => tool.name === event.toolName)?.label };
|
|
20048
20132
|
write(labelled);
|
|
@@ -20281,7 +20365,6 @@ function registerAgentRoutes(app, opts) {
|
|
|
20281
20365
|
}
|
|
20282
20366
|
|
|
20283
20367
|
// src/agent/recommendation-explainer.ts
|
|
20284
|
-
import { complete as complete2 } from "@mariozechner/pi-ai";
|
|
20285
20368
|
var RECOMMENDATION_EXPLAIN_PROMPT_VERSION = "v1";
|
|
20286
20369
|
var SYSTEM_PROMPT = `You are an AEO (Answer Engine Optimization) analyst explaining why a specific content recommendation matters for a website. Your audience is the site owner or their agency \u2014 practical, time-poor, allergic to jargon.
|
|
20287
20370
|
|
|
@@ -20388,7 +20471,7 @@ function createRecommendationExplainer(opts) {
|
|
|
20388
20471
|
]
|
|
20389
20472
|
};
|
|
20390
20473
|
const apiKey = resolveApiKeyFor(provider, opts.config);
|
|
20391
|
-
const resp = await
|
|
20474
|
+
const resp = await completeOnce(model, context, apiKey ? { apiKey } : {});
|
|
20392
20475
|
const parts = resp.content.filter((p) => p.type === "text");
|
|
20393
20476
|
const text = parts.map((p) => p.text).join("\n").trim();
|
|
20394
20477
|
if (!text) {
|
|
@@ -20466,7 +20549,7 @@ Your previous reply was not valid JSON. Return ONLY a JSON object with exactly t
|
|
|
20466
20549
|
systemPrompt: BRIEF_SYSTEM_PROMPT,
|
|
20467
20550
|
messages: [{ role: "user", content: userContent, timestamp: Date.now() }]
|
|
20468
20551
|
};
|
|
20469
|
-
const resp = await
|
|
20552
|
+
const resp = await completeOnce(model, context, apiKey ? { apiKey } : {});
|
|
20470
20553
|
totalCostDollars += Number.isFinite(resp.usage.cost.total) ? resp.usage.cost.total : 0;
|
|
20471
20554
|
const parts = resp.content.filter((p) => p.type === "text");
|
|
20472
20555
|
const text = parts.map((p) => p.text).join("\n").trim();
|