@nextclaw/kernel 0.10.1 → 0.10.3

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/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, getAutomaticUpdateCheckDelay, resolveAutomaticUpdateCheckIntervalMs } from "./utils/automatic-update-check.utils.js";
2
2
  import { n as getUnsignedUpdateManifest, r as serializeUnsignedUpdateManifest, t as UpdateManifestReader } from "./update-manifest.types-C0qPrjGQ.js";
3
3
  import { createRequire } from "node:module";
4
- import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, DIAGNOSTIC_CORRELATION_METADATA_KEY, DiagnosticRuntime, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderModelDiscoveryService, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, ViewImageTool, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, estimateInputTokens, evaluateSilentReply, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, isNextclawControlMessage, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeAgentProfileId, normalizeInlineSecretRefs, normalizeModelThinkingCapability, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveRuntimeCommandLaunch, resolveSessionProjectContext, resolveSessionWorkspacePath, resolveThinkingLevel, safeFilename, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
4
+ import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, DIAGNOSTIC_CORRELATION_METADATA_KEY, DiagnosticRuntime, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, LocalExecutionClaimService, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderModelDiscoveryService, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, ViewImageTool, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, estimateInputTokens, evaluateSilentReply, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, isNextclawControlMessage, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeAgentProfileId, normalizeInlineSecretRefs, normalizeModelThinkingCapability, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveRuntimeCommandLaunch, resolveSessionProjectContext, resolveSessionWorkspacePath, resolveThinkingLevel, safeFilename, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
5
5
  import { NCP_AI_EXECUTION_METADATA_KEY, NCP_INTERNAL_VISIBILITY_METADATA_KEY, NCP_RUN_TRIGGER_METADATA_KEY, NcpEventType, OBSERVATION_EVENT_EXTENSION_TYPE, createUnavailableNcpAiExecutionMetadata, isHiddenNcpMessage, normalizeAssistantText, parseNcpRunTriggerInput, readNcpAiExecutionMetadata, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
6
+ import { LocalAssetStore, buildAssetContentPath, buildOpenAiFunctionTool, isTextLikeAsset, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
6
7
  import { CHAT_CONTINUATION_TARGET_MESSAGE_METADATA_KEY, CHAT_CONVERSATION_EXCERPT_TOKEN_KIND, CHAT_INLINE_TOKENS_METADATA_KEY, CHAT_INLINE_TOKENS_SCHEMA_VERSION, CHAT_PROJECT_TOKEN_KIND, CHAT_SESSION_MATERIALIZATION_METADATA_KEY, CHAT_SYSTEM_OBJECT_TOKEN_KIND, CHAT_UI_RESOURCE_TOKEN_KIND, CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND, CHAT_WORKSPACE_EXCERPT_TOKEN_KIND, CHAT_WORKSPACE_FILE_TOKEN_KIND, Contribution as Contribution$1, EventBus, EventBus as EventBus$1, Ingress, Ingress as Ingress$1, PANEL_APP_INLINE_HOST_CONTRACT, PANEL_APP_SCROLL_RESTORATION_CONTRACT, SYSTEM_OBJECT_REFERENCE_DEFAULT_LIMIT, SYSTEM_OBJECT_REFERENCE_MAX_LIMIT, SYSTEM_OBJECT_TYPE_CRON_JOB, SYSTEM_OBJECT_TYPE_INBOX_DELIVERY, UI_CONTENT_PARAMS_HOST_CONTRACT, classifyDiagnosticError, createSystemObjectReferenceUri, createTypedKey, eventKeys, eventKeys as eventKeys$1, ingressKeys, ingressKeys as ingressKeys$1, isRuntimeDefaultModelValue, isSilentReplyNcpMessage, normalizeRuntimeModelSelectionMode, parseSystemObjectReferenceUri, readChatUiResourceReference, readInlineContentHeight, readSystemObjectResolvedReference, readUiContentParams } from "@nextclaw/shared";
7
- import { LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, isTextLikeAsset, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
8
8
  import { createHash, createHmac, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
9
9
  import { catchError, filter, from, lastValueFrom, tap } from "rxjs";
10
10
  import { DefaultNcpAgentConversationStateManager, insertMessageByTimeline, mergeToolExecutionTiming } from "@nextclaw/ncp-toolkit";
@@ -64,6 +64,7 @@ var AgentManager = class {
64
64
  return {
65
65
  ...profile,
66
66
  contextTokens,
67
+ maxToolIterations: profile.maxToolIterations ?? config.agents.defaults.maxToolIterations,
67
68
  model: profile.model ?? config.agents.defaults.model,
68
69
  reservedContextTokens: ContextWindowBudgetService.resolveReservedContextTokens({
69
70
  contextTokens,
@@ -188,135 +189,6 @@ var ContextCompactionJournalRecoveryService = class {
188
189
  };
189
190
  };
190
191
  //#endregion
191
- //#region src/utils/agent-run-metadata.utils.ts
192
- const AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY = "run_spec";
193
- const LEGACY_RUN_METADATA_KEYS = [
194
- "account_id",
195
- "agent_id",
196
- "chat_id",
197
- "preferred_model",
198
- "project_root",
199
- "runtime",
200
- "sender_id",
201
- "session_key",
202
- "session_type"
203
- ];
204
- function stripLegacyRunMetadata(metadata) {
205
- const nextMetadata = structuredClone(metadata);
206
- for (const key of LEGACY_RUN_METADATA_KEYS) delete nextMetadata[key];
207
- return nextMetadata;
208
- }
209
- function buildRunMetadata(params) {
210
- const { message, metadata, route } = params;
211
- return {
212
- ...stripLegacyRunMetadata({
213
- ...message.metadata ?? {},
214
- ...metadata ?? {}
215
- }),
216
- channel: message.channel,
217
- chatId: message.chatId,
218
- accountId: route.accountId,
219
- agentId: route.agentId,
220
- sessionKey: route.sessionKey,
221
- senderId: message.senderId
222
- };
223
- }
224
- //#endregion
225
- //#region src/utils/ncp-message-bridge.utils.ts
226
- function normalizeString$1(value) {
227
- if (typeof value !== "string") return null;
228
- const trimmed = value.trim();
229
- return trimmed.length > 0 ? trimmed : null;
230
- }
231
- function ensureIsoTimestamp(value, fallback) {
232
- if (typeof value !== "string") return fallback;
233
- const timestamp = Date.parse(value);
234
- if (!Number.isFinite(timestamp)) return fallback;
235
- return new Date(timestamp).toISOString();
236
- }
237
- function serializeToolArgs(args) {
238
- if (typeof args === "string") return args;
239
- return JSON.stringify(args ?? {});
240
- }
241
- function serializeLegacyContent(parts) {
242
- const text = parts.filter(isTextLikePart).map((part) => part.text).join("");
243
- if (text.length > 0) return text;
244
- if (parts.length === 0) return "";
245
- return structuredClone(parts);
246
- }
247
- function extractTextFromNcpMessage(message) {
248
- if (!message) return "";
249
- return (message.role === "assistant" ? sanitizeAssistantReplyTags(message) : message).parts.filter(isTextLikePart).map((part) => part.text).join("");
250
- }
251
- function isTextLikePart(part) {
252
- return part.type === "text" || part.type === "rich-text";
253
- }
254
- function buildLegacyUserContent(parts, options = {}) {
255
- const content = buildNcpUserContent(parts, { assetStore: options.assetStore });
256
- if (content === "") return serializeLegacyContent(parts);
257
- return content;
258
- }
259
- function buildLegacyAssistantMessages(message, timestamp) {
260
- const textContent = extractTextFromNcpMessage(message);
261
- const reasoningParts = message.parts.filter((part) => part.type === "reasoning");
262
- const reasoningContent = reasoningParts.map((part) => part.text).join("");
263
- const toolInvocations = message.parts.filter((part) => part.type === "tool-invocation");
264
- const assistantMessage = {
265
- role: "assistant",
266
- content: textContent,
267
- timestamp,
268
- ncp_message_id: message.id,
269
- ncp_parts: structuredClone(message.parts)
270
- };
271
- if (typeof message.metadata?.reply_to === "string" && message.metadata.reply_to.trim().length > 0) assistantMessage.reply_to = message.metadata.reply_to.trim();
272
- if (reasoningParts.length > 0) assistantMessage.reasoning_content = reasoningContent;
273
- if (toolInvocations.length > 0) assistantMessage.tool_calls = toolInvocations.map((toolInvocation, index) => ({
274
- id: toolInvocation.toolCallId ?? `${message.id}:tool:${index}`,
275
- type: "function",
276
- function: {
277
- name: toolInvocation.toolName,
278
- arguments: serializeToolArgs(toolInvocation.args)
279
- }
280
- }));
281
- const messages = [assistantMessage];
282
- for (const toolInvocation of toolInvocations) {
283
- if (toolInvocation.state !== "result") continue;
284
- messages.push({
285
- role: "tool",
286
- name: toolInvocation.toolName,
287
- tool_call_id: toolInvocation.toolCallId,
288
- content: typeof toolInvocation.result === "string" ? toolInvocation.result : JSON.stringify(toolInvocation.result ?? null),
289
- ...toolInvocation.resultContentItems ? { ncp_tool_result_content_items: structuredClone(toolInvocation.resultContentItems) } : {},
290
- timestamp,
291
- ncp_message_id: message.id
292
- });
293
- }
294
- return messages;
295
- }
296
- function buildLegacyNonAssistantMessage(message, timestamp, options) {
297
- return {
298
- role: message.role === "service" && options.serviceRole === "system" ? "system" : message.role,
299
- content: buildLegacyUserContent(message.parts, options),
300
- timestamp,
301
- ncp_message_id: message.id,
302
- ncp_parts: structuredClone(message.parts),
303
- ...message.metadata ? { ncp_metadata: structuredClone(message.metadata) } : {}
304
- };
305
- }
306
- function toLegacyMessages(messages, options = {}) {
307
- const legacyMessages = [];
308
- for (const rawMessage of messages) {
309
- const message = rawMessage.role === "assistant" ? sanitizeAssistantReplyTags(rawMessage) : rawMessage;
310
- const timestamp = ensureIsoTimestamp(message.timestamp, (/* @__PURE__ */ new Date()).toISOString());
311
- if (message.role === "assistant") {
312
- legacyMessages.push(...buildLegacyAssistantMessages(message, timestamp));
313
- continue;
314
- }
315
- legacyMessages.push(buildLegacyNonAssistantMessage(message, timestamp, options));
316
- }
317
- return legacyMessages;
318
- }
319
- //#endregion
320
192
  //#region src/utils/agent-model-input-budget.utils.ts
321
193
  function buildContextBlockInputMessages(contextBlocks = []) {
322
194
  const contextContent = contextBlocks.map((block) => block.trim()).filter(Boolean).join("\n\n");
@@ -938,6 +810,13 @@ function shouldRefreshContextWindowImmediately(event) {
938
810
  }
939
811
  //#endregion
940
812
  //#region src/features/context-compaction/services/context-compaction-preflight.service.ts
813
+ function toCompactionModelMessages(messages, assetStore) {
814
+ return messages.flatMap((message) => ncpMessageToOpenAiMessages(message, { assetStore }).map((providerMessage) => ({
815
+ ...providerMessage,
816
+ ncp_message_id: message.id,
817
+ timestamp: message.timestamp
818
+ })));
819
+ }
941
820
  function estimateCompactionProjectionOverhead(phase) {
942
821
  const summaryPlanOverhead = estimateInputTokens({
943
822
  role: "user",
@@ -1006,8 +885,9 @@ var ContextCompactionPreflightService = class {
1006
885
  compactionService = new ContextCompactionService();
1007
886
  contextWindowBudgetService = new ContextWindowBudgetService();
1008
887
  summaryGenerationService;
1009
- constructor(agentManager, providerManager) {
888
+ constructor(agentManager, providerManager, assetStore = null) {
1010
889
  this.agentManager = agentManager;
890
+ this.assetStore = assetStore;
1011
891
  this.summaryGenerationService = new ContextCompactionSummaryGenerationService(providerManager);
1012
892
  }
1013
893
  preview = (params) => {
@@ -1025,7 +905,7 @@ var ContextCompactionPreflightService = class {
1025
905
  const contextBlockInputTokens = estimateInputTokens(contextBlockMessages);
1026
906
  const toolInputTokens = estimateToolInputTokens(tools);
1027
907
  const snapshotFixedInputTokens = fixedInputTokens ?? contextBlockInputTokens + toolInputTokens;
1028
- const messages = [...fixedInputTokens === void 0 ? contextBlockMessages : [], ...toLegacyMessages(projectedMessages)];
908
+ const messages = [...fixedInputTokens === void 0 ? contextBlockMessages : [], ...toCompactionModelMessages(projectedMessages, this.assetStore)];
1029
909
  return buildContextWindowSnapshotFromBudget({
1030
910
  budget: this.contextWindowBudgetService.evaluate({
1031
911
  messages,
@@ -1057,7 +937,7 @@ var ContextCompactionPreflightService = class {
1057
937
  sessionMessages: ncpMessages
1058
938
  }).messages : ncpMessages.filter((message) => !isContextCompactionTimelineMessage(message));
1059
939
  const contextBlockMessages = buildContextBlockInputMessages(contextBlocks);
1060
- const messages = [...contextBlockMessages, ...toLegacyMessages(projectedMessages)];
940
+ const messages = [...contextBlockMessages, ...toCompactionModelMessages(projectedMessages, this.assetStore)];
1061
941
  const preservableUserMessageIds = ncpMessages.flatMap((message) => message.role === "user" ? [message.id] : []);
1062
942
  const fixedInputTokens = estimateToolInputTokens(tools);
1063
943
  const snapshotFixedInputTokens = estimateInputTokens(contextBlockMessages) + fixedInputTokens;
@@ -1069,6 +949,7 @@ var ContextCompactionPreflightService = class {
1069
949
  });
1070
950
  const plan = trigger === "automatic" && !budget.shouldCompact ? null : this.compactionService.prepareForModelInput({
1071
951
  messages,
952
+ coverLeadingSystemMessage: contextBlockMessages.length === 0 && isContextCompactionProjectionMessage(projectedMessages[0]),
1072
953
  contextTokens,
1073
954
  compactionThresholdTokens: trigger === "manual" ? 0 : budget.triggerTokens,
1074
955
  fixedInputTokens,
@@ -1156,7 +1037,7 @@ var ContextCompactionPreflightService = class {
1156
1037
  sessionMessages: [...pending.sessionMessages, timelineMessage]
1157
1038
  }).messages;
1158
1039
  const budget = this.contextWindowBudgetService.evaluate({
1159
- messages: [...pending.contextBlockMessages, ...toLegacyMessages(projectedMessages, { serviceRole: "system" })],
1040
+ messages: [...pending.contextBlockMessages, ...toCompactionModelMessages(projectedMessages, this.assetStore)],
1160
1041
  contextTokens: pending.contextTokens,
1161
1042
  fixedInputTokens: pending.plan.fixedInputTokens,
1162
1043
  reservedContextTokens: pending.reservedContextTokens
@@ -1193,11 +1074,11 @@ const MINIMUM_CONFIGURABLE_CONTEXT_TOKENS = 1e3;
1193
1074
  var AgentContextWindowManager = class {
1194
1075
  runInputBudgetBySession = /* @__PURE__ */ new Map();
1195
1076
  preflightService;
1196
- constructor(agentManager, contextProviderManager, toolProviderManager) {
1077
+ constructor(agentManager, contextProviderManager, toolProviderManager, assetStore = null) {
1197
1078
  this.agentManager = agentManager;
1198
1079
  this.contextProviderManager = contextProviderManager;
1199
1080
  this.toolProviderManager = toolProviderManager;
1200
- this.preflightService = new ContextCompactionPreflightService(agentManager);
1081
+ this.preflightService = new ContextCompactionPreflightService(agentManager, void 0, assetStore);
1201
1082
  }
1202
1083
  resolveRunSurface = async (request) => {
1203
1084
  const surface = await this.buildRunSurface(request);
@@ -1332,8 +1213,8 @@ var AgentContextWindowManager = class {
1332
1213
  //#region src/managers/agent-run-context-compaction.manager.ts
1333
1214
  var AgentRunContextCompactionManager = class {
1334
1215
  preflightService;
1335
- constructor(agentManager, providerManager) {
1336
- this.preflightService = new ContextCompactionPreflightService(agentManager, providerManager);
1216
+ constructor(agentManager, providerManager, assetStore = null) {
1217
+ this.preflightService = new ContextCompactionPreflightService(agentManager, providerManager, assetStore);
1337
1218
  }
1338
1219
  runPreflight = (input) => {
1339
1220
  return this.run(input, "automatic", input.phase ?? "pre-run");
@@ -1787,13 +1668,14 @@ var AgentRunInputDeliveryService = class {
1787
1668
  input: this.toPendingInput(moved)
1788
1669
  };
1789
1670
  };
1790
- enqueuePreferredSteeringInput = (sessionRun, request, session) => {
1671
+ promotePreferredSteeringInput = (sessionRun, queuedInputId, session) => {
1791
1672
  try {
1792
- return this.agentRuntimeManager.getOrCreate({
1673
+ if (this.agentRuntimeManager.getOrCreate({
1793
1674
  agentRuntimeId: session.agentRuntimeId,
1794
1675
  session,
1795
1676
  sessionRun
1796
- }).capabilities?.nextStepInput === true ? sessionRun.enqueueNextStepRequest(request, session) : null;
1677
+ }).capabilities?.nextStepInput !== true) return null;
1678
+ return sessionRun.moveQueuedRequestToNextStep(queuedInputId);
1797
1679
  } catch {
1798
1680
  return null;
1799
1681
  }
@@ -1964,6 +1846,40 @@ function createUnavailableAiExecutionMetadataEvent(params) {
1964
1846
  };
1965
1847
  }
1966
1848
  //#endregion
1849
+ //#region src/utils/agent-run-metadata.utils.ts
1850
+ const AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY = "run_spec";
1851
+ const LEGACY_RUN_METADATA_KEYS = [
1852
+ "account_id",
1853
+ "agent_id",
1854
+ "chat_id",
1855
+ "preferred_model",
1856
+ "project_root",
1857
+ "runtime",
1858
+ "sender_id",
1859
+ "session_key",
1860
+ "session_type"
1861
+ ];
1862
+ function stripLegacyRunMetadata(metadata) {
1863
+ const nextMetadata = structuredClone(metadata);
1864
+ for (const key of LEGACY_RUN_METADATA_KEYS) delete nextMetadata[key];
1865
+ return nextMetadata;
1866
+ }
1867
+ function buildRunMetadata(params) {
1868
+ const { message, metadata, route } = params;
1869
+ return {
1870
+ ...stripLegacyRunMetadata({
1871
+ ...message.metadata ?? {},
1872
+ ...metadata ?? {}
1873
+ }),
1874
+ channel: message.channel,
1875
+ chatId: message.chatId,
1876
+ accountId: route.accountId,
1877
+ agentId: route.agentId,
1878
+ sessionKey: route.sessionKey,
1879
+ senderId: message.senderId
1880
+ };
1881
+ }
1882
+ //#endregion
1967
1883
  //#region src/utils/agent-run-request.utils.ts
1968
1884
  function readOptionalString$12(value) {
1969
1885
  if (typeof value !== "string") return;
@@ -2101,6 +2017,7 @@ function resolveRunSpec(params) {
2101
2017
  agentId: session.agentId ?? request.agentId ?? defaultAgentId,
2102
2018
  model,
2103
2019
  requestedModel: request.model ?? null,
2020
+ maxToolIterations: params.maxToolIterations,
2104
2021
  maxTokens: request.maxTokens ?? modelMaxTokens,
2105
2022
  thinkingEffort: request.thinkingEffort ?? session.thinkingEffort ?? null,
2106
2023
  correlationId: request.correlationId
@@ -2120,6 +2037,7 @@ function attachRunSpecMetadata(params) {
2120
2037
  model: spec.model,
2121
2038
  modelSource,
2122
2039
  requestedModel: request.model ?? null,
2040
+ maxToolIterations: spec.maxToolIterations,
2123
2041
  maxTokens: spec.maxTokens,
2124
2042
  thinkingEffort: spec.thinkingEffort,
2125
2043
  projectRoot: request.projectRoot ?? session.projectRoot ?? null,
@@ -2341,16 +2259,31 @@ function createIngressRunTriggerInput(params) {
2341
2259
  }
2342
2260
  function resolveRunTriggerMetadata(params) {
2343
2261
  const { request, spec, startedAt } = params;
2262
+ return resolveTargetRunTriggerMetadata({
2263
+ request,
2264
+ targetRunId: spec.runId,
2265
+ fallbackTriggeredAt: startedAt
2266
+ });
2267
+ }
2268
+ function resolveSteeringRunTriggerMetadata(params) {
2269
+ return resolveTargetRunTriggerMetadata({
2270
+ request: params.request,
2271
+ targetRunId: params.targetRunId,
2272
+ fallbackTriggeredAt: params.acceptedAt
2273
+ });
2274
+ }
2275
+ function resolveTargetRunTriggerMetadata(params) {
2276
+ const { request } = params;
2344
2277
  const input = request.trigger ?? createIngressRunTriggerInput({
2345
2278
  request,
2346
2279
  source: "internal"
2347
2280
  });
2348
- const triggeredAt = Number.isFinite(Date.parse(input.triggeredAt)) ? new Date(input.triggeredAt).toISOString() : startedAt;
2281
+ const triggeredAt = Number.isFinite(Date.parse(input.triggeredAt)) ? new Date(input.triggeredAt).toISOString() : params.fallbackTriggeredAt;
2349
2282
  return {
2350
2283
  version: 1,
2351
2284
  ...structuredClone(input),
2352
2285
  triggeredAt,
2353
- targetRunId: spec.runId
2286
+ targetRunId: params.targetRunId
2354
2287
  };
2355
2288
  }
2356
2289
  function createRunTriggerMetadataEvent(params) {
@@ -2383,7 +2316,7 @@ var AgentRunRequestManager = class {
2383
2316
  runtimeRuns;
2384
2317
  pendingInputs;
2385
2318
  started = false;
2386
- constructor(agentRuntimeManager, agentManager, configManager, agentContextWindowManager, eventBus, ingress, sessionManager, sessionRunManager, diagnostics) {
2319
+ constructor(agentRuntimeManager, agentManager, configManager, agentContextWindowManager, eventBus, ingress, sessionManager, sessionRunManager, diagnostics, executionClaims) {
2387
2320
  this.agentRuntimeManager = agentRuntimeManager;
2388
2321
  this.agentManager = agentManager;
2389
2322
  this.configManager = configManager;
@@ -2393,6 +2326,7 @@ var AgentRunRequestManager = class {
2393
2326
  this.sessionManager = sessionManager;
2394
2327
  this.sessionRunManager = sessionRunManager;
2395
2328
  this.diagnostics = diagnostics;
2329
+ this.executionClaims = executionClaims;
2396
2330
  this.pendingInputs = new AgentRunInputDeliveryService(agentRuntimeManager, sessionManager, sessionRunManager, this.publishRunQueueUpdated);
2397
2331
  this.idempotency = new AgentRunRequestIdempotencyService(sessionManager, sessionRunManager);
2398
2332
  this.runtimeRuns = new AgentRuntimeRunObserverService({
@@ -2466,7 +2400,8 @@ var AgentRunRequestManager = class {
2466
2400
  sessionId: session.sessionId,
2467
2401
  message: baseMessage
2468
2402
  };
2469
- const steeringRequest = request.delivery === "prefer-steer" && sessionRun.isRunning() ? this.pendingInputs.enqueuePreferredSteeringInput(sessionRun, normalizedRequest, session) : null;
2403
+ const queuedRequest = sessionRun.enqueueRequest(normalizedRequest, session);
2404
+ const steeringRequest = request.delivery === "prefer-steer" && sessionRun.isRunning() ? this.pendingInputs.promotePreferredSteeringInput(sessionRun, queuedRequest.id, session) : null;
2470
2405
  if (steeringRequest) {
2471
2406
  this.publishRunQueueUpdated(session.sessionId);
2472
2407
  return {
@@ -2477,7 +2412,6 @@ var AgentRunRequestManager = class {
2477
2412
  delivery: "steered"
2478
2413
  };
2479
2414
  }
2480
- const queuedRequest = sessionRun.enqueueRequest(normalizedRequest, session);
2481
2415
  const activeRequest = sessionRun.beginNextRun();
2482
2416
  this.publishRunQueueUpdated(session.sessionId);
2483
2417
  if (activeRequest?.id === queuedRequest.id) await this.startQueuedRun(sessionRun, activeRequest);
@@ -2493,20 +2427,17 @@ var AgentRunRequestManager = class {
2493
2427
  startQueuedRun = async (sessionRun, activeRequest) => {
2494
2428
  const { request, session } = activeRequest;
2495
2429
  const requestRunStartedAt = (/* @__PURE__ */ new Date()).toISOString();
2496
- const model = request.model ?? session.model ?? this.configManager.getDefaultModel();
2497
- const { modelSource, spec } = resolveRunSpec({
2498
- defaultAgentId: this.agentManager.getDefaultAgentId(),
2499
- model,
2500
- modelMaxTokens: this.configManager.getModelMaxTokens(model),
2501
- request,
2502
- runId: activeRequest.runId,
2503
- session
2504
- });
2430
+ const { modelSource, spec } = this.resolveQueuedRunSpec(activeRequest);
2505
2431
  const trigger = resolveRunTriggerMetadata({
2506
2432
  request,
2507
2433
  spec,
2508
2434
  startedAt: requestRunStartedAt
2509
2435
  });
2436
+ const executionClaim = await this.claimSessionExecutionOrFail({
2437
+ requestRunStartedAt,
2438
+ sessionRun,
2439
+ spec
2440
+ });
2510
2441
  const message = attachRunSpecMetadata({
2511
2442
  message: {
2512
2443
  ...request.message,
@@ -2550,10 +2481,10 @@ var AgentRunRequestManager = class {
2550
2481
  spec,
2551
2482
  trigger
2552
2483
  });
2553
- await sessionRun.applyEvents([messageSentEvent, triggerEvent]);
2554
- this.publishNcpEvent(messageSentEvent);
2555
- this.publishNcpEvent(triggerEvent);
2556
2484
  try {
2485
+ await sessionRun.applyEvents([messageSentEvent, triggerEvent]);
2486
+ this.publishNcpEvent(messageSentEvent);
2487
+ this.publishNcpEvent(triggerEvent);
2557
2488
  const runtime = this.agentRuntimeManager.getOrCreate({
2558
2489
  agentRuntimeId: session.agentRuntimeId,
2559
2490
  session,
@@ -2572,9 +2503,11 @@ var AgentRunRequestManager = class {
2572
2503
  requestRunStartedAt,
2573
2504
  runtime,
2574
2505
  spec,
2575
- parentCorrelationId
2506
+ parentCorrelationId,
2507
+ executionClaim
2576
2508
  });
2577
2509
  } catch (error) {
2510
+ this.releaseExecutionClaim(executionClaim);
2578
2511
  const classification = classifyDiagnosticError(error, activeRequest.signal);
2579
2512
  this.diagnostics?.record({
2580
2513
  domain: "agent.run",
@@ -2598,10 +2531,54 @@ var AgentRunRequestManager = class {
2598
2531
  throw error;
2599
2532
  }
2600
2533
  };
2601
- startRuntimeRun = (params) => this.runtimeRuns.start({
2602
- ...params,
2603
- onSettled: this.startNextQueuedRun
2604
- });
2534
+ resolveQueuedRunSpec = (activeRequest) => {
2535
+ const { request, session } = activeRequest;
2536
+ const model = request.model ?? session.model ?? this.configManager.getDefaultModel();
2537
+ const defaultAgentId = this.agentManager.getDefaultAgentId();
2538
+ const agentId = session.agentId ?? request.agentId ?? defaultAgentId;
2539
+ const maxToolIterations = this.agentManager.resolveAgentProfileForRun({
2540
+ agentId,
2541
+ requestMetadata: request.metadata,
2542
+ storedAgentId: session.agentId
2543
+ }).maxToolIterations;
2544
+ return resolveRunSpec({
2545
+ defaultAgentId,
2546
+ model,
2547
+ modelMaxTokens: this.configManager.getModelMaxTokens(model),
2548
+ maxToolIterations,
2549
+ request,
2550
+ runId: activeRequest.runId,
2551
+ session
2552
+ });
2553
+ };
2554
+ claimSessionExecutionOrFail = async (params) => {
2555
+ const { requestRunStartedAt, sessionRun, spec } = params;
2556
+ const acquired = this.executionClaims?.tryAcquire(`session:${sessionRun.sessionId}`);
2557
+ if (!acquired || acquired.acquired) return acquired?.claim;
2558
+ const error = /* @__PURE__ */ new Error(`Session already has an active run owned by another NextClaw process: ${sessionRun.sessionId}`);
2559
+ await this.publishRunStartupFailure({
2560
+ error,
2561
+ requestRunStartedAt,
2562
+ sessionRun,
2563
+ spec
2564
+ });
2565
+ this.startNextQueuedRun(sessionRun);
2566
+ throw error;
2567
+ };
2568
+ startRuntimeRun = (params) => {
2569
+ const { executionClaim, ...runtimeParams } = params;
2570
+ this.runtimeRuns.start({
2571
+ ...runtimeParams,
2572
+ onSettled: (sessionRun) => {
2573
+ this.releaseExecutionClaim(executionClaim);
2574
+ this.startNextQueuedRun(sessionRun);
2575
+ }
2576
+ });
2577
+ };
2578
+ releaseExecutionClaim = (claim) => {
2579
+ if (!claim) return;
2580
+ claim.release();
2581
+ };
2605
2582
  publishRunStartupFailure = async (params) => {
2606
2583
  const { error, requestRunStartedAt, sessionRun, spec } = params;
2607
2584
  const metadataEvent = createUnavailableAiExecutionMetadataEvent({
@@ -3793,25 +3770,40 @@ var AppPackageManager = class {
3793
3770
  throw error;
3794
3771
  }
3795
3772
  };
3796
- listActiveComponentSources = async () => {
3773
+ listActiveComponentSources = async () => (await this.listActiveComponentSourcesWithDiagnostics()).sources;
3774
+ listActiveComponentSourcesWithDiagnostics = async () => {
3797
3775
  const records = await this.registryService.listApps();
3798
- return (await Promise.all(records.filter((record) => record.enabled).map(async (record) => {
3799
- await this.installationService.assertVersionIntegrity(record.appId, record.activeVersion);
3800
- const version = record.installedVersions[record.activeVersion];
3801
- if (!version || version.manifestSchemaVersion !== 2) return [];
3802
- return (version.components ?? []).map((component) => ({
3803
- kind: component.kind,
3804
- id: component.id,
3805
- packageId: record.appId,
3806
- packageVersion: record.activeVersion,
3807
- sourcePath: component.componentDirectory,
3808
- manifestPath: component.manifestPath,
3809
- dataDirectory: record.dataDirectory,
3810
- instanceId: record.defaultInstance.id,
3811
- storage: record.defaultInstance.storage,
3812
- ...this.resolveSecurity(version, record.appId)
3813
- }));
3814
- }))).flat();
3776
+ const results = await Promise.all(records.filter((record) => record.enabled).map(async (record) => {
3777
+ try {
3778
+ await this.installationService.assertVersionIntegrity(record.appId, record.activeVersion);
3779
+ const version = record.installedVersions[record.activeVersion];
3780
+ if (!version || version.manifestSchemaVersion !== 2) return { sources: [] };
3781
+ return { sources: (version.components ?? []).map((component) => ({
3782
+ kind: component.kind,
3783
+ id: component.id,
3784
+ packageId: record.appId,
3785
+ packageVersion: record.activeVersion,
3786
+ sourcePath: component.componentDirectory,
3787
+ manifestPath: component.manifestPath,
3788
+ dataDirectory: record.dataDirectory,
3789
+ instanceId: record.defaultInstance.id,
3790
+ storage: record.defaultInstance.storage,
3791
+ ...this.resolveSecurity(version, record.appId)
3792
+ })) };
3793
+ } catch (error) {
3794
+ return {
3795
+ sources: [],
3796
+ unavailablePackage: {
3797
+ appId: record.appId,
3798
+ message: error instanceof Error ? error.message : String(error)
3799
+ }
3800
+ };
3801
+ }
3802
+ }));
3803
+ return {
3804
+ sources: results.flatMap((result) => result.sources),
3805
+ unavailablePackages: results.flatMap((result) => result.unavailablePackage ?? [])
3806
+ };
3815
3807
  };
3816
3808
  listOperations = async () => await this.operationManager.list();
3817
3809
  startOperation = async (input) => {
@@ -8034,6 +8026,26 @@ function isMissingFileError$2(error) {
8034
8026
  return isRecord$13(error) && error.code === "ENOENT";
8035
8027
  }
8036
8028
  //#endregion
8029
+ //#region src/utils/ncp-message-bridge.utils.ts
8030
+ function normalizeString$1(value) {
8031
+ if (typeof value !== "string") return null;
8032
+ const trimmed = value.trim();
8033
+ return trimmed.length > 0 ? trimmed : null;
8034
+ }
8035
+ function ensureIsoTimestamp(value, fallback) {
8036
+ if (typeof value !== "string") return fallback;
8037
+ const timestamp = Date.parse(value);
8038
+ if (!Number.isFinite(timestamp)) return fallback;
8039
+ return new Date(timestamp).toISOString();
8040
+ }
8041
+ function extractTextFromNcpMessage(message) {
8042
+ if (!message) return "";
8043
+ return (message.role === "assistant" ? sanitizeAssistantReplyTags(message) : message).parts.filter(isTextLikePart).map((part) => part.text).join("");
8044
+ }
8045
+ function isTextLikePart(part) {
8046
+ return part.type === "text" || part.type === "rich-text";
8047
+ }
8048
+ //#endregion
8037
8049
  //#region src/services/agent-run-client.service.ts
8038
8050
  function readEventCorrelationId(event) {
8039
8051
  if (!("payload" in event)) return;
@@ -9158,7 +9170,8 @@ var PanelAppManager = class {
9158
9170
  return {
9159
9171
  workspacePath,
9160
9172
  panelsPath,
9161
- entries: (await Promise.all(sources.map(({ source, packageSource }) => this.entryPresenter.build(source, appState.apps[encodePanelAppId(source.sourceName)] ?? {}, packageSource, appState.mainSidebarAppIds)))).sort(this.entryPresenter.compare)
9173
+ entries: (await Promise.all(sources.map(({ source, packageSource }) => this.entryPresenter.build(source, appState.apps[encodePanelAppId(source.sourceName)] ?? {}, packageSource, appState.mainSidebarAppIds)))).sort(this.entryPresenter.compare),
9174
+ unavailablePackages: await this.params.listPackageComponentDiagnostics?.() ?? []
9162
9175
  };
9163
9176
  };
9164
9177
  getPanelAppContent = async (id, sourcePath) => {
@@ -9489,13 +9502,31 @@ var SessionPendingInputs = class {
9489
9502
  intendedRunId
9490
9503
  });
9491
9504
  };
9492
- moveNextRunToNextStep = (requestId, intendedRunId) => {
9505
+ moveNextRunToNextStep = (requestId, intendedRunId, activeRunSpec) => {
9493
9506
  const index = this.nextRun.findIndex(({ id }) => id === requestId);
9494
9507
  if (index < 0) return null;
9495
9508
  const [request] = this.nextRun.splice(index, 1);
9496
9509
  if (!request) return null;
9497
- this.enqueueNextStep(request, intendedRunId);
9498
- return this.toPendingRequest(request, "steering", intendedRunId);
9510
+ const steeringRequest = {
9511
+ ...request,
9512
+ request: {
9513
+ ...request.request,
9514
+ message: {
9515
+ ...request.request.message,
9516
+ metadata: {
9517
+ ...request.request.message.metadata ?? {},
9518
+ ...activeRunSpec ? { [AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY]: structuredClone(activeRunSpec) } : {},
9519
+ [NCP_RUN_TRIGGER_METADATA_KEY]: resolveSteeringRunTriggerMetadata({
9520
+ request: request.request,
9521
+ targetRunId: intendedRunId,
9522
+ acceptedAt: (/* @__PURE__ */ new Date()).toISOString()
9523
+ })
9524
+ }
9525
+ }
9526
+ }
9527
+ };
9528
+ this.enqueueNextStep(steeringRequest, intendedRunId);
9529
+ return this.toPendingRequest(steeringRequest, "steering", intendedRunId);
9499
9530
  };
9500
9531
  list = () => [...this.nextStep.map((request) => this.toPendingRequest(request, "steering", request.intendedRunId)), ...this.nextRun.map((request) => this.toPendingRequest(request, "queued", null))];
9501
9532
  listNextRun = () => structuredClone(this.nextRun);
@@ -9547,6 +9578,13 @@ var SessionPendingInputs = class {
9547
9578
  function isConversationStateEvent(event) {
9548
9579
  return event.type !== NcpEventType.ContextWindowUpdated;
9549
9580
  }
9581
+ function findRunSpec(messages, runId) {
9582
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
9583
+ const runSpec = messages[index]?.metadata?.[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY];
9584
+ if (runSpec && typeof runSpec === "object" && !Array.isArray(runSpec) && runSpec.runId === runId) return runSpec;
9585
+ }
9586
+ return null;
9587
+ }
9550
9588
  var SessionRun = class {
9551
9589
  sessionId;
9552
9590
  statusListeners = /* @__PURE__ */ new Set();
@@ -9608,23 +9646,7 @@ var SessionRun = class {
9608
9646
  };
9609
9647
  moveQueuedRequestToNextStep = (queuedRequestId) => {
9610
9648
  if (!this.activeRunId) return null;
9611
- return this.pendingInputs.moveNextRunToNextStep(queuedRequestId, this.activeRunId);
9612
- };
9613
- enqueueNextStepRequest = (request, session) => {
9614
- if (!this.activeRunId) return null;
9615
- const pendingRequest = {
9616
- id: `pending-input-${randomUUID()}`,
9617
- runId: `agent-run-${randomUUID()}`,
9618
- enqueuedAt: (/* @__PURE__ */ new Date()).toISOString(),
9619
- request: structuredClone(request),
9620
- session: structuredClone(session)
9621
- };
9622
- this.pendingInputs.enqueueNextStep(pendingRequest, this.activeRunId);
9623
- return structuredClone({
9624
- ...pendingRequest,
9625
- placement: "steering",
9626
- intendedRunId: this.activeRunId
9627
- });
9649
+ return this.pendingInputs.moveNextRunToNextStep(queuedRequestId, this.activeRunId, findRunSpec(this.getSnapshot().messages, this.activeRunId));
9628
9650
  };
9629
9651
  claimNextStepRequests = (runId) => this.pendingInputs.claimNextStep(runId).map((request) => ({
9630
9652
  ...request,
@@ -17647,6 +17669,13 @@ var SessionManager = class {
17647
17669
  const summaryReadOptions = !peerId && limit !== void 0 ? { limit } : void 0;
17648
17670
  return applyLimit((await journalStore.listSessionSummaries(summaryReadOptions)).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), limit);
17649
17671
  };
17672
+ listSessionPage = async (options) => {
17673
+ const result = await this.options.journalStore.listSessionSummaryPage(options);
17674
+ return {
17675
+ ...result,
17676
+ sessions: result.sessions.map(this.workingDirResolver.withWorkingDir)
17677
+ };
17678
+ };
17650
17679
  listSessionMessages = async (sessionId, options) => {
17651
17680
  const { cursor, limit } = options ?? {};
17652
17681
  const normalizedSessionId = normalizeSessionId(sessionId);
@@ -18890,6 +18919,28 @@ const SQLITE_DATABASE_FILE = ".ncp-agent-session-catalog.sqlite";
18890
18919
  const CATALOG_SCHEMA_VERSION = 1;
18891
18920
  const MIGRATION_STATUS_KEY = "migration_status";
18892
18921
  const MIGRATION_COMPLETE = "complete";
18922
+ function buildCatalogFilter(query) {
18923
+ const normalized = query?.trim().toLocaleLowerCase();
18924
+ if (!normalized) return {
18925
+ sql: "deleted_at IS NULL",
18926
+ params: []
18927
+ };
18928
+ const pattern = `%${normalized.replace(/[\\%_]/g, "\\$&")}%`;
18929
+ return {
18930
+ sql: `deleted_at IS NULL AND (
18931
+ LOWER(session_id) LIKE ? ESCAPE '\\' OR
18932
+ LOWER(COALESCE(peer_id, '')) LIKE ? ESCAPE '\\' OR
18933
+ LOWER(COALESCE(agent_id, '')) LIKE ? ESCAPE '\\' OR
18934
+ LOWER(metadata_json) LIKE ? ESCAPE '\\'
18935
+ )`,
18936
+ params: [
18937
+ pattern,
18938
+ pattern,
18939
+ pattern,
18940
+ pattern
18941
+ ]
18942
+ };
18943
+ }
18893
18944
  function readEventMessage(event) {
18894
18945
  if (event.type === NcpEventType.MessageSent || event.type === NcpEventType.MessageCompleted || event.type === "session.snapshot.message") return event.payload.message;
18895
18946
  }
@@ -18938,11 +18989,25 @@ var NcpAgentSessionSummaryIndexStore = class {
18938
18989
  const row = this.db().prepare("SELECT * FROM sessions WHERE session_id = ? AND deleted_at IS NULL LIMIT 1").get(normalizeNcpSessionId(sessionId));
18939
18990
  return row ? structuredClone(rowToSummary(row)) : null;
18940
18991
  };
18941
- list = async () => {
18992
+ list = async (limit) => {
18942
18993
  await this.ensureReady();
18994
+ const query = `SELECT * FROM sessions
18995
+ WHERE deleted_at IS NULL
18996
+ ORDER BY COALESCE(last_message_at, created_at, updated_at) DESC, session_id DESC`;
18997
+ return (limit === void 0 ? this.db().prepare(query).all() : this.db().prepare(`${query} LIMIT ?`).all(limit)).map((row) => structuredClone(rowToSummary(row)));
18998
+ };
18999
+ listPage = async (options) => {
19000
+ await this.ensureReady();
19001
+ const filter = buildCatalogFilter(options.query);
18943
19002
  return this.db().prepare(`SELECT * FROM sessions
18944
- WHERE deleted_at IS NULL
18945
- ORDER BY COALESCE(last_message_at, created_at, updated_at) DESC, session_id DESC`).all().map((row) => structuredClone(rowToSummary(row)));
19003
+ WHERE ${filter.sql}
19004
+ ORDER BY COALESCE(last_message_at, created_at, updated_at) DESC, session_id DESC
19005
+ LIMIT ? OFFSET ?`).all(...filter.params, options.limit, options.offset).map((row) => structuredClone(rowToSummary(row)));
19006
+ };
19007
+ count = async (query) => {
19008
+ await this.ensureReady();
19009
+ const filter = buildCatalogFilter(query);
19010
+ return this.db().prepare(`SELECT COUNT(*) AS total FROM sessions WHERE ${filter.sql}`).get(...filter.params).total;
18946
19011
  };
18947
19012
  upsert = async (summary) => {
18948
19013
  await this.ensureReady();
@@ -19119,11 +19184,25 @@ var NcpAgentSessionSummaryReadStore = class {
19119
19184
  this.options = options;
19120
19185
  }
19121
19186
  list = async (limit) => {
19122
- const summaries = await this.options.listIndexedSummaries();
19123
- return await mapWithConcurrency(limit === void 0 ? summaries : summaries.slice(0, Math.max(0, limit)), this.withMetadata);
19187
+ const normalizedLimit = limit === void 0 || limit === Number.POSITIVE_INFINITY ? void 0 : Math.max(0, Math.trunc(limit));
19188
+ const summaries = await this.options.summaryIndex.list(normalizedLimit);
19189
+ return await mapWithConcurrency(normalizedLimit === void 0 ? summaries : summaries.slice(0, normalizedLimit), this.withMetadata);
19190
+ };
19191
+ listPage = async (options) => {
19192
+ const page = Math.max(1, Math.trunc(options.page));
19193
+ const pageSize = Math.max(1, Math.trunc(options.pageSize));
19194
+ const [summaries, total] = await Promise.all([this.options.summaryIndex.listPage({
19195
+ offset: (page - 1) * pageSize,
19196
+ limit: pageSize,
19197
+ ...options.query?.trim() ? { query: options.query.trim() } : {}
19198
+ }), this.options.summaryIndex.count(options.query)]);
19199
+ return {
19200
+ sessions: await mapWithConcurrency(summaries, this.withMetadata),
19201
+ total
19202
+ };
19124
19203
  };
19125
19204
  get = async (sessionId) => {
19126
- const indexed = await this.options.getIndexedSummary(sessionId);
19205
+ const indexed = await this.options.summaryIndex.get(sessionId);
19127
19206
  if (indexed) return await this.withMetadata(indexed);
19128
19207
  const messageCount = await this.options.readProjectedMessageCount(sessionId);
19129
19208
  if (messageCount === null) return null;
@@ -19196,8 +19275,7 @@ var NcpAgentSessionJournalStore = class {
19196
19275
  }
19197
19276
  });
19198
19277
  this.summaryReadStore = new NcpAgentSessionSummaryReadStore({
19199
- getIndexedSummary: (sessionId) => this.summaryIndexStore.get(sessionId),
19200
- listIndexedSummaries: () => this.summaryIndexStore.list(),
19278
+ summaryIndex: this.summaryIndexStore,
19201
19279
  readJournalModifiedAt: async (sessionId) => (await stat(this.sessionPath(sessionId))).mtime.toISOString(),
19202
19280
  readMetadata: (sessionId, fallback) => this.metadataStore.read(sessionId, fallback),
19203
19281
  readProjectedMessageCount: async (sessionId) => (await this.messageProjectionStore.readMeta(sessionId))?.total ?? null
@@ -19228,6 +19306,7 @@ var NcpAgentSessionJournalStore = class {
19228
19306
  listSessionSummaries = async (options) => {
19229
19307
  return await this.summaryReadStore.list(options?.limit);
19230
19308
  };
19309
+ listSessionSummaryPage = (options) => this.summaryReadStore.listPage(options);
19231
19310
  getSessionSummary = async (sessionId) => {
19232
19311
  const normalizedSessionId = normalizeNcpSessionId(sessionId);
19233
19312
  if (!normalizedSessionId) return null;
@@ -19579,7 +19658,7 @@ var NextclawKernel = class {
19579
19658
  this.assetStore = new LocalAssetStore({ rootDir: resolve(getDataDir(), "assets") });
19580
19659
  this.control = new NextclawKernelControlManager();
19581
19660
  this.agents = new AgentManager(this.configManager);
19582
- this.agentContextWindowManager = new AgentContextWindowManager(this.agents, this.contextProviderManager, this.toolProviderManager);
19661
+ this.agentContextWindowManager = new AgentContextWindowManager(this.agents, this.contextProviderManager, this.toolProviderManager, this.assetStore);
19583
19662
  this.accessManager = new AccessManager({
19584
19663
  configManager: this.configManager,
19585
19664
  homeDir: options.homeDir
@@ -19608,7 +19687,8 @@ var NextclawKernel = class {
19608
19687
  configManager: this.configManager,
19609
19688
  eventBus: this.eventBus,
19610
19689
  ingress: this.ingress,
19611
- listPackageComponentSources: this.appPackageManager.listActiveComponentSources
19690
+ listPackageComponentSources: this.appPackageManager.listActiveComponentSources,
19691
+ listPackageComponentDiagnostics: async () => (await this.appPackageManager.listActiveComponentSourcesWithDiagnostics()).unavailablePackages
19612
19692
  });
19613
19693
  this.preferenceManager = new PreferenceManager({ storePath: resolveKernelPreferenceStorePath(options) });
19614
19694
  ({appDataManager: this.appDataManager, serviceAppManager: this.serviceAppManager} = createKernelServiceAppManagers({
@@ -19646,10 +19726,10 @@ var NextclawKernel = class {
19646
19726
  ingress: this.ingress
19647
19727
  })
19648
19728
  });
19649
- this.contextCompactionManager = new AgentRunContextCompactionManager(this.agents, this.llmProviders);
19729
+ this.contextCompactionManager = new AgentRunContextCompactionManager(this.agents, this.llmProviders, this.assetStore);
19650
19730
  this.sessionRunManager = new SessionRunManager(this.sessionManager, options.productActivitySink);
19651
19731
  this.sessionContextCompactionManager = new SessionContextCompactionManager(this.agentRuntimeManager, this.eventBus, this.sessionManager, this.sessionRunManager);
19652
- this.agentRunRequestManager = new AgentRunRequestManager(this.agentRuntimeManager, this.agents, this.configManager, this.agentContextWindowManager, this.eventBus, this.ingress, this.sessionManager, this.sessionRunManager, this.diagnostics);
19732
+ this.agentRunRequestManager = new AgentRunRequestManager(this.agentRuntimeManager, this.agents, this.configManager, this.agentContextWindowManager, this.eventBus, this.ingress, this.sessionManager, this.sessionRunManager, this.diagnostics, new LocalExecutionClaimService(resolve(sessionsDir, ".execution-claims", "session-runs")));
19653
19733
  this.contributions = this.createContributions();
19654
19734
  }
19655
19735
  createContributions = () => [