@nextclaw/kernel 0.4.2 → 0.5.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/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { n as getUnsignedUpdateManifest, r as serializeUnsignedUpdateManifest, t as UpdateManifestReader } from "./update-manifest.types-C0qPrjGQ.js";
2
2
  import { createRequire } from "node:module";
3
+ 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, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, evaluateSilentReply, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, isNextclawControlMessage, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeAgentProfileId, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
3
4
  import { NcpEventType, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
4
- import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, EditFileTool, ExecTool, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchManager, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, summarizeSessionRequestTask, toDisposable, toExtensionConfigView } from "@nextclaw/core";
5
5
  import { LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
6
6
  import { createHash, createHmac, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
7
- import { EventBus, Ingress, eventKeys, ingressKeys } from "@nextclaw/shared";
7
+ import { EventBus, Ingress, eventKeys, ingressKeys, isRuntimeDefaultModelValue, normalizeRuntimeModelSelectionMode } from "@nextclaw/shared";
8
8
  import { catchError, from, lastValueFrom, tap } from "rxjs";
9
9
  import { appendFileSync, chmodSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve } from "node:path";
@@ -21,34 +21,55 @@ import { StdioRuntimeConfigResolver, StdioRuntimeNcpAgentRuntime, probeStdioRunt
21
21
  import { DefaultNcpAgentRuntime } from "@nextclaw/ncp-agent-runtime-next";
22
22
  //#region src/managers/agent.manager.ts
23
23
  var AgentManager = class {
24
- listAgents = () => {
25
- throw new Error("AgentManager.listAgents is not implemented.");
26
- };
27
- getAgent = (agentId) => {
28
- throw new Error("AgentManager.getAgent is not implemented.");
29
- };
30
- requireAgent = (agentId) => {
31
- throw new Error("AgentManager.requireAgent is not implemented.");
32
- };
33
- saveAgent = (agent) => {
34
- throw new Error("AgentManager.saveAgent is not implemented.");
35
- };
36
- removeAgent = (agentId) => {
37
- throw new Error("AgentManager.removeAgent is not implemented.");
38
- };
39
- attachSkill = (agentId, skillId) => {
40
- throw new Error("AgentManager.attachSkill is not implemented.");
41
- };
42
- detachSkill = (agentId, skillId) => {
43
- throw new Error("AgentManager.detachSkill is not implemented.");
44
- };
45
- attachTool = (agentId, toolId) => {
46
- throw new Error("AgentManager.attachTool is not implemented.");
47
- };
48
- detachTool = (agentId, toolId) => {
49
- throw new Error("AgentManager.detachTool is not implemented.");
24
+ constructor(configManager, options = {}) {
25
+ this.configManager = configManager;
26
+ this.options = options;
27
+ }
28
+ listAgents = () => resolveEffectiveAgentProfiles(this.loadConfig());
29
+ getAgent = (agentId) => findEffectiveAgentProfile(this.loadConfig(), agentId);
30
+ getDefaultAgentId = () => resolveDefaultAgentProfileId(this.loadConfig());
31
+ resolveAgentProfile = (agentId) => this.resolveAgentProfileFromConfig(this.loadConfig(), agentId);
32
+ resolveAgentProfileForRun = (params = {}) => this.resolveAgentProfile(params.agentId ?? params.storedAgentId ?? readRequestedAgentId(params.requestMetadata ?? {}) ?? null);
33
+ createAgent = async (input) => {
34
+ const agent = createAgentProfile(input, {
35
+ configPath: this.options.configPath,
36
+ initializeHomeDirectory: this.options.initializeAgentHomeDirectory
37
+ });
38
+ await this.reloadLiveConfig();
39
+ return agent;
40
+ };
41
+ updateAgent = async (input) => {
42
+ const agent = updateAgentProfile(input, { configPath: this.options.configPath });
43
+ await this.reloadLiveConfig();
44
+ return agent;
45
+ };
46
+ removeAgent = async (agentId) => {
47
+ const removed = removeAgentProfile(agentId, { configPath: this.options.configPath });
48
+ if (removed) await this.reloadLiveConfig();
49
+ return removed;
50
+ };
51
+ loadConfig = () => this.configManager?.loadConfig() ?? loadConfig(this.options.configPath);
52
+ reloadLiveConfig = async () => {
53
+ await this.configManager?.applyLiveConfigReload();
54
+ };
55
+ resolveAgentProfileFromConfig = (config, agentId) => {
56
+ const profile = findEffectiveAgentProfile(config, normalizeAgentProfileId(agentId) || resolveDefaultAgentProfileId(config)) ?? findEffectiveAgentProfile(config, resolveDefaultAgentProfileId(config));
57
+ if (!profile) throw new Error(`default agent profile not found: ${BUILTIN_MAIN_AGENT_ID}`);
58
+ const contextTokens = profile.contextTokens ?? config.agents.defaults.contextTokens;
59
+ return {
60
+ ...profile,
61
+ contextTokens,
62
+ model: profile.model ?? config.agents.defaults.model,
63
+ reservedContextTokens: ContextWindowBudgetService.resolveReservedContextTokens({
64
+ contextTokens,
65
+ configuredReservedContextTokens: profile.reservedContextTokens ?? config.agents.defaults.reservedContextTokens
66
+ })
67
+ };
50
68
  };
51
69
  };
70
+ function readRequestedAgentId(metadata) {
71
+ return normalizeAgentProfileId(metadata.agent_id) || normalizeAgentProfileId(metadata.agentId) || null;
72
+ }
52
73
  //#endregion
53
74
  //#region src/utils/ncp-message-bridge.utils.ts
54
75
  function normalizeString$1(value) {
@@ -145,43 +166,39 @@ function toLegacyMessages(messages, options = {}) {
145
166
  return legacyMessages;
146
167
  }
147
168
  //#endregion
148
- //#region src/features/context-compaction/utils/context-compaction-timeline-message.utils.ts
169
+ //#region src/features/context-compaction/utils/context-compaction.utils.ts
149
170
  const NEXTCLAW_TIMELINE_KIND_METADATA_KEY = "nextclaw_timeline_kind";
150
171
  const CONTEXT_COMPACTION_TIMELINE_KIND = "context_compaction";
151
172
  function readCheckpointTimelineText(checkpoint) {
152
173
  return checkpoint.status === "compressing" ? "正在压缩较早上下文" : "较早上下文已自动压缩";
153
174
  }
154
- function createContextCompactionMessageId() {
155
- return `context-compaction-message-${randomUUID()}`;
175
+ function readContextCompactionCheckpoint(message) {
176
+ const metadata = message.metadata;
177
+ return metadata?.["nextclaw_timeline_kind"] === "context_compaction" ? readCompressedContextCompactionCheckpoint(metadata.checkpoint) : null;
156
178
  }
157
- function readTimelineMetadata(message) {
158
- const rawMetadata = message?.ncp_metadata;
159
- if (!rawMetadata || typeof rawMetadata !== "object" || Array.isArray(rawMetadata)) return null;
160
- const metadata = rawMetadata;
161
- if (metadata["nextclaw_timeline_kind"] !== "context_compaction") return null;
162
- const checkpoint = metadata.checkpoint && typeof metadata.checkpoint === "object" && !Array.isArray(metadata.checkpoint) ? metadata.checkpoint : null;
163
- if (!checkpoint) return null;
164
- return {
165
- [NEXTCLAW_TIMELINE_KIND_METADATA_KEY]: CONTEXT_COMPACTION_TIMELINE_KIND,
166
- checkpoint
167
- };
179
+ function readLatestContextCompactionMarker(sessionMessages) {
180
+ return sessionMessages.reduce((marker, message) => {
181
+ const candidateCheckpoint = readContextCompactionCheckpoint(message);
182
+ return candidateCheckpoint && (!marker || Date.parse(candidateCheckpoint.updatedAt) >= Date.parse(marker.checkpoint.updatedAt)) ? { checkpoint: candidateCheckpoint } : marker;
183
+ }, null);
168
184
  }
169
- function buildTimelineMessage(checkpoint) {
170
- const text = readCheckpointTimelineText(checkpoint);
185
+ function buildContextCompactionSummaryMessage(params) {
186
+ const { checkpoint, sessionId } = params;
171
187
  return {
172
- role: "service",
173
- content: text,
188
+ id: `${sessionId}:context-compaction-summary:${checkpoint.id}:${checkpoint.updatedAt}`,
189
+ sessionId,
190
+ role: "user",
191
+ status: "final",
174
192
  timestamp: checkpoint.updatedAt,
175
- ncp_parts: [{
193
+ parts: [{
176
194
  type: "text",
177
- text
178
- }],
179
- ncp_metadata: {
180
- [NEXTCLAW_TIMELINE_KIND_METADATA_KEY]: CONTEXT_COMPACTION_TIMELINE_KIND,
181
- checkpoint
182
- }
195
+ text: checkpoint.summary
196
+ }]
183
197
  };
184
198
  }
199
+ function createContextCompactionMessageId() {
200
+ return `context-compaction-message-${randomUUID()}`;
201
+ }
185
202
  function buildContextCompactionTimelineNcpMessage(params) {
186
203
  const { checkpoint, messageId, sessionId } = params;
187
204
  const text = readCheckpointTimelineText(checkpoint);
@@ -201,92 +218,65 @@ function buildContextCompactionTimelineNcpMessage(params) {
201
218
  }
202
219
  };
203
220
  }
204
- function upsertContextCompactionTimelineMessage(params) {
205
- const { checkpoint, insertBeforeMessageIds = [], session } = params;
206
- const nextMessage = buildTimelineMessage(checkpoint);
207
- for (let index = session.events.length - 1; index >= 0; index -= 1) {
208
- const event = session.events[index];
209
- const metadata = readTimelineMetadata(event?.data?.message && typeof event.data.message === "object" && !Array.isArray(event.data.message) ? event.data.message : null);
210
- if (!metadata) continue;
211
- event.timestamp = checkpoint.updatedAt;
212
- event.data.message = nextMessage;
213
- session.messages = session.messages.map((item) => {
214
- return readTimelineMetadata(item)?.checkpoint.id === metadata.checkpoint.id ? nextMessage : item;
215
- });
216
- session.updatedAt = new Date(checkpoint.updatedAt);
217
- return;
218
- }
219
- const event = {
220
- seq: session.nextSeq,
221
- type: "message.service",
222
- timestamp: checkpoint.updatedAt,
223
- data: { message: nextMessage }
224
- };
225
- session.nextSeq += 1;
226
- const insertionIds = new Set(insertBeforeMessageIds);
227
- const messageIndex = session.messages.findIndex((message) => typeof message.ncp_message_id === "string" && insertionIds.has(message.ncp_message_id));
228
- if (messageIndex >= 0) session.messages.splice(messageIndex, 0, nextMessage);
229
- else session.messages.push(nextMessage);
230
- const eventIndex = session.events.findIndex((candidateEvent) => {
231
- const message = candidateEvent?.data?.message && typeof candidateEvent.data.message === "object" && !Array.isArray(candidateEvent.data.message) ? candidateEvent.data.message : null;
232
- return typeof message?.ncp_message_id === "string" && insertionIds.has(message.ncp_message_id);
233
- });
234
- if (eventIndex >= 0) session.events.splice(eventIndex, 0, event);
235
- else session.events.push(event);
236
- session.updatedAt = new Date(checkpoint.updatedAt);
237
- }
238
221
  function isContextCompactionTimelineMessage(message) {
239
222
  return message?.metadata?.[NEXTCLAW_TIMELINE_KIND_METADATA_KEY] === CONTEXT_COMPACTION_TIMELINE_KIND;
240
223
  }
241
- //#endregion
242
- //#region src/features/context-compaction/utils/context-compaction-projection.utils.ts
243
- function readCompactionCheckpoint(message) {
244
- const metadata = message.metadata;
245
- return metadata?.["nextclaw_timeline_kind"] === "context_compaction" ? readCompressedContextCompactionCheckpoint(metadata.checkpoint) : null;
246
- }
247
224
  function readLatestContextCompactionCheckpoint(sessionMessages) {
248
- return sessionMessages.reduce((checkpoint, message) => {
249
- const candidateCheckpoint = readCompactionCheckpoint(message);
250
- return candidateCheckpoint && (!checkpoint || Date.parse(candidateCheckpoint.updatedAt) >= Date.parse(checkpoint.updatedAt)) ? candidateCheckpoint : checkpoint;
251
- }, null);
225
+ return readLatestContextCompactionMarker(sessionMessages)?.checkpoint ?? null;
252
226
  }
253
- function projectNcpMessagesWithContextCompaction(params) {
227
+ function buildContextCompactionModelInput(params) {
254
228
  const { sessionId, sessionMessages } = params;
255
- const checkpoint = readLatestContextCompactionCheckpoint(sessionMessages);
256
- if (!checkpoint) return sessionMessages.filter((message) => !readCompactionCheckpoint(message)).map((message) => structuredClone(message));
257
- return [{
258
- id: `${sessionId}:context-compaction-summary:${checkpoint.id}:${checkpoint.updatedAt}`,
259
- sessionId,
260
- role: "user",
261
- status: "final",
262
- timestamp: checkpoint.updatedAt,
263
- parts: [{
264
- type: "text",
265
- text: checkpoint.summary
266
- }]
267
- }, ...sessionMessages.filter((message) => !readCompactionCheckpoint(message) && Date.parse(message.timestamp) > Date.parse(checkpoint.updatedAt)).sort((left, right) => Date.parse(left.timestamp) - Date.parse(right.timestamp)).map((message) => structuredClone(message))];
229
+ const marker = readLatestContextCompactionMarker(sessionMessages);
230
+ const regularMessages = sessionMessages.filter((message) => !readContextCompactionCheckpoint(message));
231
+ if (!marker) return regularMessages.map((message) => structuredClone(message));
232
+ const { checkpoint } = marker;
233
+ return [buildContextCompactionSummaryMessage({
234
+ checkpoint,
235
+ sessionId
236
+ }), ...regularMessages.filter((message) => Date.parse(message.timestamp) > Date.parse(checkpoint.updatedAt)).sort((left, right) => Date.parse(left.timestamp) - Date.parse(right.timestamp))].map((message) => structuredClone(message));
237
+ }
238
+ function readContextWindowEventSessionId(event) {
239
+ const payload = "payload" in event ? event.payload : null;
240
+ if (!payload || typeof payload !== "object") return null;
241
+ return "sessionId" in payload && typeof payload.sessionId === "string" ? payload.sessionId.trim() || null : null;
242
+ }
243
+ function isContextWindowSnapshot(value) {
244
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
245
+ }
246
+ function createContextWindowSignature(value) {
247
+ return JSON.stringify(value);
248
+ }
249
+ function shouldRefreshContextWindowDuringStream(event) {
250
+ switch (event.type) {
251
+ case NcpEventType.MessageTextStart:
252
+ case NcpEventType.MessageTextDelta:
253
+ case NcpEventType.MessageTextEnd:
254
+ case NcpEventType.MessageReasoningStart:
255
+ case NcpEventType.MessageReasoningDelta:
256
+ case NcpEventType.MessageReasoningEnd:
257
+ case NcpEventType.MessageToolCallStart:
258
+ case NcpEventType.MessageToolCallArgs:
259
+ case NcpEventType.MessageToolCallArgsDelta:
260
+ case NcpEventType.MessageToolCallEnd:
261
+ case NcpEventType.MessageToolCallResult: return true;
262
+ default: return false;
263
+ }
264
+ }
265
+ function shouldRefreshContextWindowImmediately(event) {
266
+ switch (event.type) {
267
+ case NcpEventType.MessageSent:
268
+ case NcpEventType.MessageCompleted:
269
+ case NcpEventType.MessageFailed:
270
+ case NcpEventType.MessageAbort:
271
+ case NcpEventType.RunFinished:
272
+ case NcpEventType.RunError: return true;
273
+ default: return false;
274
+ }
268
275
  }
269
276
  //#endregion
270
277
  //#region src/features/context-compaction/services/context-compaction-preflight.service.ts
271
278
  const SUMMARY_MAX_TOKENS = 4e3;
272
279
  const SUMMARY_SOURCE_MAX_CHARS = 12e4;
273
- function readRequestedAgentId$1(metadata) {
274
- return normalizeString$1(metadata.agent_id)?.toLowerCase() ?? normalizeString$1(metadata.agentId)?.toLowerCase() ?? null;
275
- }
276
- function resolveCompactionProfile(params) {
277
- const { config, requestMetadata, storedAgentId } = params;
278
- const { defaults } = config.agents;
279
- const defaultAgentId = resolveDefaultAgentProfileId(config);
280
- const profile = findEffectiveAgentProfile(config, normalizeString$1(storedAgentId)?.toLowerCase() ?? readRequestedAgentId$1(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
281
- return {
282
- contextTokens: profile?.contextTokens ?? defaults.contextTokens,
283
- model: profile?.model ?? defaults.model,
284
- reservedContextTokens: ContextWindowBudgetService.resolveReservedContextTokens({
285
- contextTokens: profile?.contextTokens ?? defaults.contextTokens,
286
- configuredReservedContextTokens: profile?.reservedContextTokens ?? defaults.reservedContextTokens
287
- })
288
- };
289
- }
290
280
  function mergeInputMessages(params) {
291
281
  const messages = params.sessionMessages.map((message) => structuredClone(message));
292
282
  const seen = new Set(messages.map((message) => message.id));
@@ -318,18 +308,18 @@ function buildContextWindowSnapshotFromBudget(params) {
318
308
  var ContextCompactionPreflightService = class {
319
309
  compactionService = new ContextCompactionService();
320
310
  contextWindowBudgetService = new ContextWindowBudgetService();
321
- constructor(options) {
322
- this.options = options;
311
+ constructor(agentManager, providerManager) {
312
+ this.agentManager = agentManager;
313
+ this.providerManager = providerManager;
323
314
  }
324
315
  preview = (params) => {
325
316
  const { requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
326
- const profile = resolveCompactionProfile({
327
- config: this.options.configManager.loadConfig(),
317
+ const profile = this.resolveCompactionProfile({
328
318
  requestMetadata,
329
319
  storedAgentId
330
320
  });
331
321
  const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]) ?? readLatestContextCompactionCheckpoint(sessionMessages);
332
- const projectedMessages = existingCheckpoint ? projectNcpMessagesWithContextCompaction({
322
+ const projectedMessages = existingCheckpoint ? buildContextCompactionModelInput({
333
323
  sessionId,
334
324
  sessionMessages
335
325
  }) : sessionMessages.filter((message) => !isContextCompactionTimelineMessage(message));
@@ -345,8 +335,7 @@ var ContextCompactionPreflightService = class {
345
335
  };
346
336
  begin = (params) => {
347
337
  const { inputMessages, requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
348
- const profile = resolveCompactionProfile({
349
- config: this.options.configManager.loadConfig(),
338
+ const profile = this.resolveCompactionProfile({
350
339
  requestMetadata,
351
340
  storedAgentId
352
341
  });
@@ -356,7 +345,7 @@ var ContextCompactionPreflightService = class {
356
345
  sessionMessages
357
346
  });
358
347
  const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]) ?? readLatestContextCompactionCheckpoint(ncpMessages);
359
- const messages = toLegacyMessages(existingCheckpoint ? projectNcpMessagesWithContextCompaction({
348
+ const messages = toLegacyMessages(existingCheckpoint ? buildContextCompactionModelInput({
360
349
  sessionId,
361
350
  sessionMessages: ncpMessages
362
351
  }) : ncpMessages.filter((message) => !isContextCompactionTimelineMessage(message)));
@@ -366,7 +355,7 @@ var ContextCompactionPreflightService = class {
366
355
  reservedContextTokens
367
356
  });
368
357
  const plan = !budget.shouldCompact ? null : this.compactionService.prepareForModelInput({
369
- messages: budget.messages,
358
+ messages,
370
359
  contextTokens,
371
360
  compactionThresholdTokens: budget.triggerTokens
372
361
  });
@@ -443,24 +432,26 @@ var ContextCompactionPreflightService = class {
443
432
  };
444
433
  };
445
434
  generateSummary = async (params) => {
446
- if (!this.options.providerManager) throw new Error("context compaction summary generation requires a provider manager");
435
+ if (!this.providerManager) throw new Error("context compaction summary generation requires a provider manager");
447
436
  const { messages, model } = params;
448
- const summary = (await this.options.providerManager.chat({
437
+ const summary = (await this.providerManager.chat({
449
438
  model,
450
439
  maxTokens: SUMMARY_MAX_TOKENS,
451
440
  messages: [{
452
441
  role: "system",
453
442
  content: [
454
443
  "You are NextClaw's context compactor for a coding agent session.",
455
- "Create a dense, structured summary that will replace earlier conversation history in a future model request.",
456
- "Preserve user goals, explicit instructions, decisions, files touched or inspected, code changes, commands run, test results, failures, blockers, and exact next steps.",
444
+ "Create a complete compressed working context that will replace all prior conversation messages in a future model request.",
445
+ "The model will not receive a raw recent-message tail, so preserve the latest user intent and recent turns with high fidelity inside the summary.",
446
+ "Preserve user goals, explicit instructions, decisions, files touched or inspected, code changes, commands run, test results, failures, blockers, current task state, and exact next steps.",
457
447
  "Do not invent facts. If something is uncertain, mark it as uncertain.",
458
- "Return Markdown only. Start with '# Compressed Earlier Context'."
448
+ "Return Markdown only. Start with '# Compressed Working Context'."
459
449
  ].join("\n")
460
450
  }, {
461
451
  role: "user",
462
452
  content: [
463
- "Compress these earlier runtime messages into a reusable checkpoint summary.",
453
+ "Compress these runtime messages into a reusable working context.",
454
+ "Include a 'Recent High-Fidelity Context' section for the latest important user/assistant turns.",
464
455
  "",
465
456
  "Messages JSON:",
466
457
  stringifyCompactionSource(messages)
@@ -470,14 +461,24 @@ var ContextCompactionPreflightService = class {
470
461
  if (!summary) throw new Error("context compaction summary is empty");
471
462
  return summary;
472
463
  };
464
+ resolveCompactionProfile = (params) => {
465
+ const profile = this.agentManager.resolveAgentProfileForRun({
466
+ requestMetadata: params.requestMetadata,
467
+ storedAgentId: params.storedAgentId
468
+ });
469
+ return {
470
+ contextTokens: profile.contextTokens,
471
+ model: profile.model,
472
+ reservedContextTokens: profile.reservedContextTokens
473
+ };
474
+ };
473
475
  };
474
476
  //#endregion
475
477
  //#region src/features/context-compaction/managers/context-compaction.manager.ts
476
478
  var ContextWindowPreviewManager = class {
477
479
  preflightService;
478
- constructor(options) {
479
- this.options = options;
480
- this.preflightService = new ContextCompactionPreflightService({ configManager: options.configManager });
480
+ constructor(agentManager) {
481
+ this.preflightService = new ContextCompactionPreflightService(agentManager);
481
482
  }
482
483
  preview = (params) => {
483
484
  const { requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
@@ -491,55 +492,12 @@ var ContextWindowPreviewManager = class {
491
492
  };
492
493
  };
493
494
  //#endregion
494
- //#region src/features/context-compaction/utils/context-window-event.utils.ts
495
- function readContextWindowEventSessionId(event) {
496
- const payload = "payload" in event ? event.payload : null;
497
- if (!payload || typeof payload !== "object") return null;
498
- return "sessionId" in payload && typeof payload.sessionId === "string" ? payload.sessionId.trim() || null : null;
499
- }
500
- function isContextWindowSnapshot(value) {
501
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
502
- }
503
- function createContextWindowSignature(value) {
504
- return JSON.stringify(value);
505
- }
506
- function shouldRefreshContextWindowDuringStream(event) {
507
- switch (event.type) {
508
- case NcpEventType.MessageTextStart:
509
- case NcpEventType.MessageTextDelta:
510
- case NcpEventType.MessageTextEnd:
511
- case NcpEventType.MessageReasoningStart:
512
- case NcpEventType.MessageReasoningDelta:
513
- case NcpEventType.MessageReasoningEnd:
514
- case NcpEventType.MessageToolCallStart:
515
- case NcpEventType.MessageToolCallArgs:
516
- case NcpEventType.MessageToolCallArgsDelta:
517
- case NcpEventType.MessageToolCallEnd:
518
- case NcpEventType.MessageToolCallResult: return true;
519
- default: return false;
520
- }
521
- }
522
- function shouldRefreshContextWindowImmediately(event) {
523
- switch (event.type) {
524
- case NcpEventType.MessageSent:
525
- case NcpEventType.MessageCompleted:
526
- case NcpEventType.MessageFailed:
527
- case NcpEventType.MessageAbort:
528
- case NcpEventType.RunFinished:
529
- case NcpEventType.RunError: return true;
530
- default: return false;
531
- }
532
- }
533
- //#endregion
534
495
  //#region src/managers/agent-run-context-compaction.manager.ts
535
496
  var AgentRunContextCompactionManager = class {
536
497
  preflightService;
537
- constructor(configManager, providerManager, sessionManager) {
498
+ constructor(agentManager, providerManager, sessionManager) {
538
499
  this.sessionManager = sessionManager;
539
- this.preflightService = new ContextCompactionPreflightService({
540
- configManager,
541
- providerManager
542
- });
500
+ this.preflightService = new ContextCompactionPreflightService(agentManager, providerManager);
543
501
  }
544
502
  runPreflight = async (input) => {
545
503
  const beginResult = this.preflightService.begin({
@@ -571,7 +529,7 @@ var AgentRunContextCompactionManager = class {
571
529
  //#region src/managers/agent-run-request.manager.ts
572
530
  function toAgentRunRequest(envelope) {
573
531
  const metadata = envelope.metadata ?? {};
574
- const peerId = readOptionalString$9(envelope.peerId);
532
+ const peerId = readOptionalString$10(envelope.peerId);
575
533
  const requestMetadata = {
576
534
  agentRuntimeId: metadata.agentRuntimeId,
577
535
  agentId: metadata.agentId,
@@ -584,7 +542,7 @@ function toAgentRunRequest(envelope) {
584
542
  thinkingEffort: metadata.thinkingEffort
585
543
  };
586
544
  if (Array.isArray(envelope.content)) {
587
- const sessionId = readOptionalString$9(envelope.sessionId);
545
+ const sessionId = readOptionalString$10(envelope.sessionId);
588
546
  if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
589
547
  return {
590
548
  ...requestMetadata,
@@ -602,8 +560,8 @@ function toAgentRunRequest(envelope) {
602
560
  }
603
561
  const sourceMessage = envelope.message;
604
562
  if (!sourceMessage) throw new Error("Invalid agent run send request.");
605
- const envelopeSessionId = readOptionalString$9(envelope.sessionId);
606
- const messageSessionId = readOptionalString$9(sourceMessage.sessionId);
563
+ const envelopeSessionId = readOptionalString$10(envelope.sessionId);
564
+ const messageSessionId = readOptionalString$10(sourceMessage.sessionId);
607
565
  const sessionId = envelopeSessionId ?? messageSessionId;
608
566
  if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
609
567
  const message = {
@@ -622,7 +580,7 @@ function toAgentRunRequest(envelope) {
622
580
  message
623
581
  };
624
582
  }
625
- function readOptionalString$9(value) {
583
+ function readOptionalString$10(value) {
626
584
  if (typeof value !== "string") return;
627
585
  return value.trim() || void 0;
628
586
  }
@@ -644,8 +602,9 @@ function readMessageTask(message) {
644
602
  var AgentRunRequestManager = class {
645
603
  cleanups = [];
646
604
  started = false;
647
- constructor(agentRuntimeManager, configManager, contextProviderManager, eventBus, ingress, sessionManager, sessionRunManager, toolProviderManager) {
605
+ constructor(agentRuntimeManager, agentManager, configManager, contextProviderManager, eventBus, ingress, sessionManager, sessionRunManager, toolProviderManager) {
648
606
  this.agentRuntimeManager = agentRuntimeManager;
607
+ this.agentManager = agentManager;
649
608
  this.configManager = configManager;
650
609
  this.contextProviderManager = contextProviderManager;
651
610
  this.eventBus = eventBus;
@@ -727,7 +686,7 @@ var AgentRunRequestManager = class {
727
686
  }
728
687
  })();
729
688
  const model = request.model ?? session.model ?? this.configManager.getDefaultModel();
730
- const agentId = request.agentId ?? session.agentId ?? resolveDefaultAgentProfileId(this.configManager.loadConfig());
689
+ const agentId = request.agentId ?? session.agentId ?? this.agentManager.getDefaultAgentId();
731
690
  const spec = {
732
691
  runId: activeRun.runId,
733
692
  agentId,
@@ -801,6 +760,126 @@ var AgentRunRequestManager = class {
801
760
  //#region src/configs/agent-runtime.config.ts
802
761
  const DEFAULT_AGENT_RUNTIME_ENTRY_ID = "native";
803
762
  //#endregion
763
+ //#region src/features/runtime-registry/utils/agent-runtime-registry.utils.ts
764
+ function normalizeIdentifier(value) {
765
+ if (typeof value !== "string") return null;
766
+ const normalized = value.trim().toLowerCase();
767
+ return normalized.length > 0 ? normalized : null;
768
+ }
769
+ function normalizeAgentRuntimeSessionTypeIcon(value) {
770
+ if (typeof value === "string") {
771
+ const src = value.trim();
772
+ return src ? {
773
+ kind: "image",
774
+ src
775
+ } : null;
776
+ }
777
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
778
+ const iconRecord = value;
779
+ const src = typeof iconRecord.src === "string" ? iconRecord.src.trim() : "";
780
+ if (!src) return null;
781
+ const alt = typeof iconRecord.alt === "string" && iconRecord.alt.trim().length > 0 ? iconRecord.alt.trim() : null;
782
+ return {
783
+ kind: "image",
784
+ src,
785
+ ...alt ? { alt } : {}
786
+ };
787
+ }
788
+ const BUILTIN_RUNTIME_PRESENTATION = { hermes: {
789
+ label: "Hermes",
790
+ icon: {
791
+ kind: "image",
792
+ src: "app://runtime-icons/hermes-agent.png",
793
+ alt: "Hermes"
794
+ }
795
+ } };
796
+ function readString$6(value) {
797
+ if (typeof value !== "string") return;
798
+ return value.trim() || void 0;
799
+ }
800
+ function readRecord$3(value) {
801
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
802
+ return value;
803
+ }
804
+ function resolveBuiltinRuntimePresentation(value) {
805
+ const normalized = readString$6(value)?.toLowerCase();
806
+ if (!normalized) return null;
807
+ if (!(normalized in BUILTIN_RUNTIME_PRESENTATION)) return null;
808
+ return BUILTIN_RUNTIME_PRESENTATION[normalized] ?? null;
809
+ }
810
+ function buildNativeRuntimeEntry(config) {
811
+ const nativeRuntimeConfig = readRecord$3(config.ui?.ncp?.runtimes?.native) ?? {};
812
+ return {
813
+ id: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
814
+ label: "Native",
815
+ type: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
816
+ enabled: nativeRuntimeConfig.enabled !== false,
817
+ config: nativeRuntimeConfig
818
+ };
819
+ }
820
+ function resolveAgentRuntimeEntries(params) {
821
+ const entries = /* @__PURE__ */ new Map();
822
+ entries.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, buildNativeRuntimeEntry(params.config));
823
+ for (const [rawId, rawEntry] of Object.entries(params.config.agents.runtimes.entries ?? {})) {
824
+ const id = rawId.trim().toLowerCase();
825
+ const type = readString$6(rawEntry.type)?.toLowerCase();
826
+ if (!id || !type) continue;
827
+ const explicitIcon = normalizeAgentRuntimeSessionTypeIcon(rawEntry.icon);
828
+ const builtinPresentation = resolveBuiltinRuntimePresentation(id) ?? resolveBuiltinRuntimePresentation(type);
829
+ entries.set(id, {
830
+ id,
831
+ label: readString$6(rawEntry.label) ?? builtinPresentation?.label ?? id,
832
+ ...explicitIcon ?? builtinPresentation?.icon ? { icon: explicitIcon ?? builtinPresentation?.icon } : {},
833
+ type,
834
+ enabled: rawEntry.enabled !== false,
835
+ config: rawEntry.config ? { ...rawEntry.config } : {}
836
+ });
837
+ }
838
+ return {
839
+ defaultEntryId: entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : [...entries.keys()][0] ?? "native",
840
+ entries: [...entries.values()]
841
+ };
842
+ }
843
+ async function describeAgentRuntimeSessionTypes(params) {
844
+ const entries = params.entries.filter((entry) => entry.enabled !== false);
845
+ return {
846
+ defaultType: normalizeIdentifier(params.defaultEntryId) ?? (entries.some((entry) => entry.id === "native") ? "native" : entries[0]?.id ?? "native"),
847
+ options: await Promise.all(entries.map(async (entry) => {
848
+ const provider = params.providers.get(entry.type);
849
+ if (!provider) return {
850
+ value: entry.id,
851
+ label: entry.label,
852
+ icon: entry.icon ?? null,
853
+ ready: false,
854
+ reason: "runtime_provider_unavailable",
855
+ reasonMessage: `Runtime provider unavailable for type "${entry.type}".`,
856
+ recommendedModel: null,
857
+ modelSelectionMode: "nextclaw",
858
+ cta: {
859
+ kind: "settings",
860
+ label: "Configure Runtime"
861
+ }
862
+ };
863
+ const descriptor = provider.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
864
+ entry,
865
+ describeParams: params.describeParams
866
+ }) : await provider.describeSessionType?.(params.describeParams);
867
+ return {
868
+ value: entry.id,
869
+ label: entry.label,
870
+ icon: descriptor?.icon ?? entry.icon ?? null,
871
+ ready: descriptor?.ready ?? true,
872
+ reason: descriptor?.reason ?? null,
873
+ reasonMessage: descriptor?.reasonMessage ?? null,
874
+ recommendedModel: descriptor?.recommendedModel ?? null,
875
+ modelSelectionMode: descriptor?.modelSelectionMode ?? "nextclaw",
876
+ cta: descriptor?.cta ?? null,
877
+ ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
878
+ };
879
+ }))
880
+ };
881
+ }
882
+ //#endregion
804
883
  //#region src/managers/agent-runtime.manager.ts
805
884
  var AgentRuntimeManager = class {
806
885
  providers = /* @__PURE__ */ new Map();
@@ -846,31 +925,11 @@ var AgentRuntimeManager = class {
846
925
  cache.set(cacheKey, agentRuntime);
847
926
  return agentRuntime;
848
927
  };
849
- listSessionTypes = async (_params) => {
850
- const entries = [...this.entries.values()].filter((entry) => entry.enabled !== false);
851
- const options = await Promise.all(entries.map(async (entry) => {
852
- const provider = this.providers.get(entry.type);
853
- const descriptor = provider?.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
854
- entry,
855
- describeParams: _params
856
- }) : null;
857
- return {
858
- value: entry.id,
859
- label: entry.label,
860
- icon: descriptor?.icon ?? entry.icon ?? null,
861
- ready: provider ? descriptor?.ready ?? true : false,
862
- reason: provider ? descriptor?.reason ?? null : "runtime_provider_unavailable",
863
- reasonMessage: provider ? descriptor?.reasonMessage ?? null : `Runtime provider unavailable for type "${entry.type}".`,
864
- recommendedModel: descriptor?.recommendedModel ?? null,
865
- cta: descriptor?.cta ?? null,
866
- ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
867
- };
868
- }));
869
- return {
870
- defaultType: this.entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : entries[0]?.id ?? "native",
871
- options
872
- };
873
- };
928
+ listSessionTypes = async (params) => describeAgentRuntimeSessionTypes({
929
+ entries: [...this.entries.values()],
930
+ providers: this.providers,
931
+ describeParams: params
932
+ });
874
933
  dispose = async () => {
875
934
  await this.disposeAllRuntimes();
876
935
  this.providers.clear();
@@ -1211,6 +1270,117 @@ var AutomationManager = class extends CronService {
1211
1270
  }
1212
1271
  };
1213
1272
  //#endregion
1273
+ //#region src/managers/channel.manager.ts
1274
+ var ChannelManager = class {
1275
+ channels = {};
1276
+ channelConfig = null;
1277
+ dispatching = false;
1278
+ dispatchTask = null;
1279
+ extensionChannels = [];
1280
+ constructor(deps) {
1281
+ this.deps = deps;
1282
+ }
1283
+ load = (params) => {
1284
+ this.channelConfig = params.channelConfig;
1285
+ this.extensionChannels = params.extensionChannels ?? [];
1286
+ this.channels = {};
1287
+ this.initChannels();
1288
+ };
1289
+ reload = async (params) => {
1290
+ await this.stop();
1291
+ this.load(params);
1292
+ if (params.start === true) await this.start();
1293
+ };
1294
+ start = async () => {
1295
+ if (!Object.keys(this.channels).length || this.dispatching) return;
1296
+ this.dispatching = true;
1297
+ this.dispatchTask = this.dispatchOutbound();
1298
+ await Promise.allSettled(Object.entries(this.channels).map(([name, channel]) => this.startChannel(name, channel)));
1299
+ };
1300
+ stop = async () => {
1301
+ this.dispatching = false;
1302
+ if (this.dispatchTask) {
1303
+ await this.deps.bus.publishOutbound({
1304
+ channel: "__control__",
1305
+ chatId: "",
1306
+ content: "",
1307
+ media: [],
1308
+ metadata: { reason: "shutdown" }
1309
+ });
1310
+ await this.dispatchTask;
1311
+ }
1312
+ await Promise.allSettled(Object.entries(this.channels).map(async ([name, channel]) => {
1313
+ try {
1314
+ await channel.stop();
1315
+ } catch (error) {
1316
+ console.error(`Error stopping ${name}: ${String(error)}`);
1317
+ }
1318
+ }));
1319
+ this.dispatchTask = null;
1320
+ };
1321
+ status = () => Object.fromEntries(Object.entries(this.channels).map(([name, channel]) => [name, {
1322
+ enabled: true,
1323
+ running: channel.isRunning
1324
+ }]));
1325
+ get enabledChannels() {
1326
+ return Object.keys(this.channels);
1327
+ }
1328
+ getChannel = (name) => this.channels[name] ?? null;
1329
+ deliver = async (message) => {
1330
+ const channel = this.channels[message.channel];
1331
+ if (!channel) return false;
1332
+ if (isNextclawControlMessage(message)) {
1333
+ await channel.handleControlMessage(message);
1334
+ return true;
1335
+ }
1336
+ const outbound = this.normalizeOutbound(message);
1337
+ if (!outbound) return true;
1338
+ await channel.send(outbound);
1339
+ return true;
1340
+ };
1341
+ initChannels = () => {
1342
+ if (!this.channelConfig) return;
1343
+ for (const registration of this.extensionChannels) {
1344
+ const id = registration.channel.id;
1345
+ if (!id) continue;
1346
+ if (this.channels[id]) {
1347
+ console.warn(`Extension channel ignored because id already exists: ${id}`);
1348
+ continue;
1349
+ }
1350
+ this.channels[id] = new ExtensionChannelAdapter(this.channelConfig, this.deps.bus, registration);
1351
+ }
1352
+ };
1353
+ startChannel = async (name, channel) => {
1354
+ try {
1355
+ await channel.start();
1356
+ } catch (error) {
1357
+ console.error(`Failed to start channel ${name}: ${String(error)}`);
1358
+ }
1359
+ };
1360
+ normalizeOutbound = (message) => {
1361
+ const silentReplyDecision = evaluateSilentReply({
1362
+ content: sanitizeOutboundAssistantContent(message.content ?? ""),
1363
+ media: message.media
1364
+ });
1365
+ if (silentReplyDecision.shouldDrop) return null;
1366
+ if (silentReplyDecision.content === message.content) return message;
1367
+ return {
1368
+ ...message,
1369
+ content: silentReplyDecision.content
1370
+ };
1371
+ };
1372
+ dispatchOutbound = async () => {
1373
+ while (this.dispatching) {
1374
+ const message = await this.deps.bus.consumeOutbound();
1375
+ try {
1376
+ await this.deliver(message);
1377
+ } catch (error) {
1378
+ console.error(`Error sending to ${message.channel}: ${String(error)}`);
1379
+ }
1380
+ }
1381
+ };
1382
+ };
1383
+ //#endregion
1214
1384
  //#region src/managers/config.manager.ts
1215
1385
  const hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
1216
1386
  const mergeDeep = (base, patch) => {
@@ -1821,21 +1991,6 @@ var CommandRegistry = class {
1821
1991
  };
1822
1992
  //#endregion
1823
1993
  //#region src/features/extension-runtime/services/extension-lifecycle.service.ts
1824
- function sanitizeExtensionNodeOptions(value) {
1825
- if (!value?.trim()) return;
1826
- const tokens = value.split(/\s+/).filter(Boolean);
1827
- const sanitized = [];
1828
- for (let index = 0; index < tokens.length; index += 1) {
1829
- const token = tokens[index];
1830
- if (token === "--conditions=development" || token === "-C=development") continue;
1831
- if ((token === "--conditions" || token === "-C") && tokens[index + 1] === "development") {
1832
- index += 1;
1833
- continue;
1834
- }
1835
- sanitized.push(token);
1836
- }
1837
- return sanitized.length > 0 ? sanitized.join(" ") : void 0;
1838
- }
1839
1994
  var ExtensionLifecycleService = class {
1840
1995
  processes = /* @__PURE__ */ new Map();
1841
1996
  startAll = (manifests, params) => {
@@ -1865,14 +2020,12 @@ var ExtensionLifecycleService = class {
1865
2020
  if (existing) return existing;
1866
2021
  const child = spawn(manifest.server.command === "node" || manifest.server.command === "node.exe" ? process.execPath : manifest.server.command, manifest.server.args ?? [], {
1867
2022
  cwd: manifest.rootDir,
1868
- env: {
1869
- ...process.env,
1870
- NODE_OPTIONS: sanitizeExtensionNodeOptions(process.env.NODE_OPTIONS),
2023
+ env: createRuntimeChildEnv(process.env, {
1871
2024
  ...manifest.server.env,
1872
2025
  NEXTCLAW_EXTENSION_ID: manifest.id,
1873
2026
  NEXTCLAW_EXTENSION_ENDPOINT: params.endpoint,
1874
2027
  NEXTCLAW_EXTENSION_TOKEN: params.tokenForExtension(manifest.id)
1875
- },
2028
+ }, { inheritBaseEnv: true }),
1876
2029
  stdio: [
1877
2030
  "ignore",
1878
2031
  "ignore",
@@ -1912,7 +2065,7 @@ const BUILTIN_EXTENSION_PACKAGES = [
1912
2065
  "@nextclaw/channel-extension-weixin"
1913
2066
  ];
1914
2067
  const runtimeRequire = createRequire(import.meta.url);
1915
- function readString$6(value) {
2068
+ function readString$5(value) {
1916
2069
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1917
2070
  }
1918
2071
  function readStringArray$2(value) {
@@ -1923,7 +2076,7 @@ function readStringRecord(value) {
1923
2076
  const entries = Object.entries(value);
1924
2077
  return entries.every(([, item]) => typeof item === "string") ? Object.fromEntries(entries) : void 0;
1925
2078
  }
1926
- function readRecord$3(value) {
2079
+ function readRecord$2(value) {
1927
2080
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1928
2081
  }
1929
2082
  function uniquePaths(paths) {
@@ -1960,17 +2113,17 @@ function resolveDevFirstPartyExtensionDir(explicitDir = process.env.NEXTCLAW_DEV
1960
2113
  function toManifest(value, rootDir) {
1961
2114
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("extension manifest must be an object");
1962
2115
  const record = value;
1963
- const server = readRecord$3(record.server);
1964
- const id = readString$6(record.id);
1965
- const command = readString$6(server.command);
2116
+ const server = readRecord$2(record.server);
2117
+ const id = readString$5(record.id);
2118
+ const command = readString$5(server.command);
1966
2119
  if (!id) throw new Error("extension manifest id is required");
1967
2120
  if (server.type !== "stdio") throw new Error("extension server.type must be stdio");
1968
2121
  if (!command) throw new Error("extension server.command is required");
1969
2122
  return {
1970
2123
  id,
1971
2124
  rootDir,
1972
- ...readString$6(record.name) ? { name: readString$6(record.name) } : {},
1973
- ...readString$6(record.version) ? { version: readString$6(record.version) } : {},
2125
+ ...readString$5(record.name) ? { name: readString$5(record.name) } : {},
2126
+ ...readString$5(record.version) ? { version: readString$5(record.version) } : {},
1974
2127
  server: {
1975
2128
  type: "stdio",
1976
2129
  command,
@@ -2074,19 +2227,19 @@ function listExtensionChannelIds(params) {
2074
2227
  //#region src/services/extension-runtime.service.ts
2075
2228
  const EXTENSION_REQUEST_EVENT_TYPE = "extension.request";
2076
2229
  const EXTENSION_REQUEST_TIMEOUT_MS = 6e4;
2077
- function readString$5(value) {
2230
+ function readString$4(value) {
2078
2231
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
2079
2232
  }
2080
- function readRecord$2(value) {
2233
+ function readRecord$1(value) {
2081
2234
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2082
2235
  }
2083
- function readRequiredString$4(value, name) {
2084
- const trimmed = readString$5(value);
2236
+ function readRequiredString$5(value, name) {
2237
+ const trimmed = readString$4(value);
2085
2238
  if (!trimmed) throw new Error(`${name} is required`);
2086
2239
  return trimmed;
2087
2240
  }
2088
2241
  function readTextContent(value) {
2089
- const content = readRecord$2(value);
2242
+ const content = readRecord$1(value);
2090
2243
  if (content.type !== "text" || typeof content.text !== "string") throw new Error("only text channel messages are supported by the first ingress bridge");
2091
2244
  return content.text;
2092
2245
  }
@@ -2096,35 +2249,35 @@ function readOptionalNumber(value) {
2096
2249
  function readInboundAttachments(value) {
2097
2250
  if (!Array.isArray(value)) return [];
2098
2251
  return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))).map((entry) => ({
2099
- ...readString$5(entry.id) ? { id: readString$5(entry.id) } : {},
2100
- ...readString$5(entry.name) ? { name: readString$5(entry.name) } : {},
2101
- ...readString$5(entry.path) ? { path: readString$5(entry.path) } : {},
2102
- ...readString$5(entry.url) ? { url: readString$5(entry.url) } : {},
2103
- ...readString$5(entry.assetUri) ? { assetUri: readString$5(entry.assetUri) } : {},
2104
- ...readString$5(entry.mimeType) ? { mimeType: readString$5(entry.mimeType) } : {},
2252
+ ...readString$4(entry.id) ? { id: readString$4(entry.id) } : {},
2253
+ ...readString$4(entry.name) ? { name: readString$4(entry.name) } : {},
2254
+ ...readString$4(entry.path) ? { path: readString$4(entry.path) } : {},
2255
+ ...readString$4(entry.url) ? { url: readString$4(entry.url) } : {},
2256
+ ...readString$4(entry.assetUri) ? { assetUri: readString$4(entry.assetUri) } : {},
2257
+ ...readString$4(entry.mimeType) ? { mimeType: readString$4(entry.mimeType) } : {},
2105
2258
  ...readOptionalNumber(entry.size) !== void 0 ? { size: readOptionalNumber(entry.size) } : {},
2106
- ...readString$5(entry.source) ? { source: readString$5(entry.source) } : {},
2259
+ ...readString$4(entry.source) ? { source: readString$4(entry.source) } : {},
2107
2260
  ...entry.status === "ready" || entry.status === "remote-only" ? { status: entry.status } : {},
2108
- ...readString$5(entry.errorCode) ? { errorCode: readString$5(entry.errorCode) } : {}
2261
+ ...readString$4(entry.errorCode) ? { errorCode: readString$4(entry.errorCode) } : {}
2109
2262
  }));
2110
2263
  }
2111
2264
  function toInboundMessage(value) {
2112
- const payload = readRecord$2(value);
2265
+ const payload = readRecord$1(value);
2113
2266
  return {
2114
- channel: readRequiredString$4(payload.channelId, "channelId"),
2115
- chatId: readRequiredString$4(payload.conversationId, "conversationId"),
2116
- senderId: readRequiredString$4(payload.senderId, "senderId"),
2267
+ channel: readRequiredString$5(payload.channelId, "channelId"),
2268
+ chatId: readRequiredString$5(payload.conversationId, "conversationId"),
2269
+ senderId: readRequiredString$5(payload.senderId, "senderId"),
2117
2270
  content: readTextContent(payload.content),
2118
2271
  timestamp: /* @__PURE__ */ new Date(),
2119
2272
  attachments: readInboundAttachments(payload.attachments),
2120
- metadata: readRecord$2(payload.metadata)
2273
+ metadata: readRecord$1(payload.metadata)
2121
2274
  };
2122
2275
  }
2123
2276
  function normalizeChannelConfigResult(value) {
2124
- return readRecord$2(readRecord$2(value).channelConfig);
2277
+ return readRecord$1(readRecord$1(value).channelConfig);
2125
2278
  }
2126
2279
  function normalizeAuthLoginResult(value) {
2127
- const record = readRecord$2(value);
2280
+ const record = readRecord$1(value);
2128
2281
  return {
2129
2282
  channelConfig: normalizeChannelConfigResult(record),
2130
2283
  accountId: typeof record.accountId === "string" ? record.accountId : null,
@@ -2133,11 +2286,11 @@ function normalizeAuthLoginResult(value) {
2133
2286
  }
2134
2287
  function normalizeAuthPollResult(value) {
2135
2288
  if (!value) return null;
2136
- const record = readRecord$2(value);
2289
+ const record = readRecord$1(value);
2137
2290
  return {
2138
- channel: readRequiredString$4(record.channel, "channel"),
2291
+ channel: readRequiredString$5(record.channel, "channel"),
2139
2292
  status: record.status,
2140
- message: readString$5(record.message),
2293
+ message: readString$4(record.message),
2141
2294
  nextPollMs: readOptionalNumber(record.nextPollMs),
2142
2295
  accountId: typeof record.accountId === "string" ? record.accountId : null,
2143
2296
  notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
@@ -2233,7 +2386,7 @@ var ExtensionRuntimeService = class {
2233
2386
  if (running.length > 0) console.log(`✓ Extensions started: ${running.map((entry) => entry.manifest.id).join(", ")}`);
2234
2387
  };
2235
2388
  getExtensionProcessToken = (extensionId) => {
2236
- const id = readRequiredString$4(extensionId, "extensionId");
2389
+ const id = readRequiredString$5(extensionId, "extensionId");
2237
2390
  const current = this.extensionTokens.get(id);
2238
2391
  if (current) return current;
2239
2392
  const token = randomUUID();
@@ -2241,8 +2394,8 @@ var ExtensionRuntimeService = class {
2241
2394
  return token;
2242
2395
  };
2243
2396
  authenticateEventStreamCredential = (input) => {
2244
- const extensionId = readString$5(input.extensionId);
2245
- const token = readString$5(input.token);
2397
+ const extensionId = readString$4(input.extensionId);
2398
+ const token = readString$4(input.token);
2246
2399
  if (!extensionId || !token || token !== this.extensionTokens.get(extensionId)) return null;
2247
2400
  return { extensionId };
2248
2401
  };
@@ -2261,7 +2414,7 @@ var ExtensionRuntimeService = class {
2261
2414
  const channelBindings = [];
2262
2415
  const uiMetadata = [];
2263
2416
  for (const manifest of manifests) for (const channel of manifest.contributes?.channels ?? []) {
2264
- const channelId = readString$5(channel.id);
2417
+ const channelId = readString$4(channel.id);
2265
2418
  if (!channelId) continue;
2266
2419
  const configUiHints = this.readConfigUiHints(channel.configUiHints);
2267
2420
  channelBindings.push({
@@ -2296,7 +2449,7 @@ var ExtensionRuntimeService = class {
2296
2449
  };
2297
2450
  handleChannelConfigGet = (envelope, context) => {
2298
2451
  this.assertAuthorized(envelope, context);
2299
- const channelId = readRequiredString$4(readRecord$2(envelope.payload).channelId, "channelId");
2452
+ const channelId = readRequiredString$5(readRecord$1(envelope.payload).channelId, "channelId");
2300
2453
  return { config: this.options.getConfig().channels[channelId] ?? {} };
2301
2454
  };
2302
2455
  handleChannelMessageSubmit = async (envelope, context) => {
@@ -2310,11 +2463,11 @@ var ExtensionRuntimeService = class {
2310
2463
  };
2311
2464
  handleChannelCommandExecute = async (envelope, context) => {
2312
2465
  this.assertAuthorized(envelope, context);
2313
- const payload = readRecord$2(envelope.payload);
2314
- const channel = readRequiredString$4(payload.channelId, "channelId");
2315
- const chatId = readRequiredString$4(payload.conversationId, "conversationId");
2316
- const senderId = readRequiredString$4(payload.senderId, "senderId");
2317
- const metadata = readRecord$2(payload.metadata);
2466
+ const payload = readRecord$1(envelope.payload);
2467
+ const channel = readRequiredString$5(payload.channelId, "channelId");
2468
+ const chatId = readRequiredString$5(payload.conversationId, "conversationId");
2469
+ const senderId = readRequiredString$5(payload.senderId, "senderId");
2470
+ const metadata = readRecord$1(payload.metadata);
2318
2471
  const config = this.options.getConfig();
2319
2472
  const registry = new CommandRegistry(config, this.options.sessionManager);
2320
2473
  const route = new AgentRouteResolver(config).resolveInbound({
@@ -2322,15 +2475,15 @@ var ExtensionRuntimeService = class {
2322
2475
  channel,
2323
2476
  chatId,
2324
2477
  senderId,
2325
- content: readString$5(payload.rawText) ?? readString$5(payload.commandName) ?? "",
2478
+ content: readString$4(payload.rawText) ?? readString$4(payload.commandName) ?? "",
2326
2479
  timestamp: /* @__PURE__ */ new Date(),
2327
2480
  attachments: [],
2328
2481
  metadata
2329
2482
  },
2330
- forcedAgentId: readString$5(metadata.target_agent_id),
2331
- sessionKeyOverride: readString$5(metadata.session_key_override)
2483
+ forcedAgentId: readString$4(metadata.target_agent_id),
2484
+ sessionKeyOverride: readString$4(metadata.session_key_override)
2332
2485
  });
2333
- const rawText = readString$5(payload.rawText);
2486
+ const rawText = readString$4(payload.rawText);
2334
2487
  if (rawText) return await registry.executeText(rawText, {
2335
2488
  channel,
2336
2489
  chatId,
@@ -2340,7 +2493,7 @@ var ExtensionRuntimeService = class {
2340
2493
  content: "",
2341
2494
  ephemeral: true
2342
2495
  };
2343
- return await registry.execute(readRequiredString$4(payload.commandName, "commandName"), readRecord$2(payload.args), {
2496
+ return await registry.execute(readRequiredString$5(payload.commandName, "commandName"), readRecord$1(payload.args), {
2344
2497
  channel,
2345
2498
  chatId,
2346
2499
  senderId,
@@ -2349,14 +2502,14 @@ var ExtensionRuntimeService = class {
2349
2502
  };
2350
2503
  handleExtensionResponse = (envelope, context) => {
2351
2504
  this.assertAuthorized(envelope, context);
2352
- const payload = readRecord$2(envelope.payload);
2353
- const requestId = readRequiredString$4(payload.requestId, "requestId");
2505
+ const payload = readRecord$1(envelope.payload);
2506
+ const requestId = readRequiredString$5(payload.requestId, "requestId");
2354
2507
  const pending = this.pendingRequests.get(requestId);
2355
2508
  if (!pending) return { accepted: false };
2356
2509
  this.pendingRequests.delete(requestId);
2357
2510
  clearTimeout(pending.timeout);
2358
2511
  if (payload.ok === false) {
2359
- const message = readString$5(readRecord$2(payload.error).message) ?? "Extension request failed";
2512
+ const message = readString$4(readRecord$1(payload.error).message) ?? "Extension request failed";
2360
2513
  pending.reject(new Error(message));
2361
2514
  return { accepted: true };
2362
2515
  }
@@ -2403,7 +2556,7 @@ var ExtensionRuntimeService = class {
2403
2556
  return await result;
2404
2557
  };
2405
2558
  assertAuthorized = (envelope, context) => {
2406
- const extensionId = readString$5(envelope.extensionId);
2559
+ const extensionId = readString$4(envelope.extensionId);
2407
2560
  if (!extensionId || context.token !== this.extensionTokens.get(extensionId)) throw new Error("Unauthorized ingress token");
2408
2561
  };
2409
2562
  };
@@ -2526,11 +2679,11 @@ var ExtensionManager = class {
2526
2679
  //#endregion
2527
2680
  //#region src/utils/model-message-vision.utils.ts
2528
2681
  const IMAGE_OMITTED_TEXT = "[Image omitted: the selected model is not configured for vision input.]";
2529
- function isRecord$11(value) {
2682
+ function isRecord$12(value) {
2530
2683
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2531
2684
  }
2532
2685
  function isImageContentPart(value) {
2533
- if (!isRecord$11(value)) return false;
2686
+ if (!isRecord$12(value)) return false;
2534
2687
  const type = value.type;
2535
2688
  return type === "image_url" || type === "input_image";
2536
2689
  }
@@ -2546,7 +2699,7 @@ function normalizeContentWithoutVision(content) {
2546
2699
  };
2547
2700
  });
2548
2701
  if (!sawImage) return content;
2549
- const textParts = parts.filter((part) => isRecord$11(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
2702
+ const textParts = parts.filter((part) => isRecord$12(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
2550
2703
  if (textParts.length === parts.length) return textParts.join("\n\n");
2551
2704
  return parts;
2552
2705
  }
@@ -3086,11 +3239,11 @@ function createAgentPeerSessionIdentity(params) {
3086
3239
  }
3087
3240
  function resolveAgentPeerScope(params) {
3088
3241
  const metadata = params.metadata ?? {};
3089
- const explicitScope = readOptionalString$8(metadata["agent_peer_scope"]) ?? readOptionalString$8(metadata.agentPeerScope);
3242
+ const explicitScope = readOptionalString$9(metadata["agent_peer_scope"]) ?? readOptionalString$9(metadata.agentPeerScope);
3090
3243
  if (explicitScope) return explicitScope;
3091
- return `agent:${readOptionalString$8(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$8(params.channel) ?? readOptionalString$8(metadata.channel) ?? "agent-run"}:${readOptionalString$8(metadata.accountId) ?? readOptionalString$8(metadata.account_id) ?? "default"}`;
3244
+ return `agent:${readOptionalString$9(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$9(params.channel) ?? readOptionalString$9(metadata.channel) ?? "agent-run"}:${readOptionalString$9(metadata.accountId) ?? readOptionalString$9(metadata.account_id) ?? "default"}`;
3092
3245
  }
3093
- function readOptionalString$8(value) {
3246
+ function readOptionalString$9(value) {
3094
3247
  if (typeof value !== "string") return;
3095
3248
  return value.trim() || void 0;
3096
3249
  }
@@ -3109,7 +3262,7 @@ function safeNcpSessionFilename(value) {
3109
3262
  function normalizeNcpAgentId(agentId) {
3110
3263
  return agentId?.trim().toLowerCase() || void 0;
3111
3264
  }
3112
- function isRecord$10(value) {
3265
+ function isRecord$11(value) {
3113
3266
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3114
3267
  }
3115
3268
  function toIsoString(value, fallback) {
@@ -3189,7 +3342,7 @@ function createReplayEvent(event) {
3189
3342
  return replayEvent;
3190
3343
  }
3191
3344
  function readLegacyContextCompactionMessageId(message) {
3192
- const checkpoint = isRecord$10(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3345
+ const checkpoint = isRecord$11(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3193
3346
  const checkpointId = typeof checkpoint?.id === "string" ? checkpoint.id : "";
3194
3347
  const coveredCount = checkpoint?.coveredSessionMessageCount;
3195
3348
  const legacyId = `${message?.sessionId}:service:context-compaction:${checkpointId}`;
@@ -3219,11 +3372,11 @@ function rememberReplayMessageId(event, knownMessageIds) {
3219
3372
  if (message?.id) knownMessageIds.add(message.id);
3220
3373
  }
3221
3374
  function readEventSessionId$2(event) {
3222
- const sessionId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.sessionId;
3375
+ const sessionId = ("payload" in event && isRecord$11(event.payload) ? event.payload : null)?.sessionId;
3223
3376
  return typeof sessionId === "string" ? sessionId : "";
3224
3377
  }
3225
3378
  function readReplayPayloadTimestamp(event) {
3226
- const payload = "payload" in event && isRecord$10(event.payload) ? event.payload : null;
3379
+ const payload = "payload" in event && isRecord$11(event.payload) ? event.payload : null;
3227
3380
  const timestamp = typeof payload?.timestamp === "string" ? payload.timestamp : "";
3228
3381
  return Number.isFinite(Date.parse(timestamp)) ? new Date(timestamp).toISOString() : null;
3229
3382
  }
@@ -3278,7 +3431,7 @@ function applyLimit(items, limit) {
3278
3431
  if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
3279
3432
  return items.slice(0, Math.trunc(limit));
3280
3433
  }
3281
- function readOptionalString$7(value) {
3434
+ function readOptionalString$8(value) {
3282
3435
  if (typeof value !== "string") return null;
3283
3436
  const trimmed = value.trim();
3284
3437
  return trimmed.length > 0 ? trimmed : null;
@@ -3292,8 +3445,8 @@ function readEventSessionId$1(event) {
3292
3445
  //#endregion
3293
3446
  //#region src/services/session-working-dir-resolver.service.ts
3294
3447
  var SessionWorkingDirResolver = class {
3295
- constructor(configManager) {
3296
- this.configManager = configManager;
3448
+ constructor(agentManager) {
3449
+ this.agentManager = agentManager;
3297
3450
  }
3298
3451
  withWorkingDir = (summary) => ({
3299
3452
  ...summary,
@@ -3303,12 +3456,10 @@ var SessionWorkingDirResolver = class {
3303
3456
  })
3304
3457
  });
3305
3458
  resolve = (params) => {
3306
- const config = this.configManager.loadConfig();
3307
- const defaultAgentId = resolveDefaultAgentProfileId(config);
3308
- const profile = findEffectiveAgentProfile(config, readOptionalString$7(params.agentId) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
3459
+ const profile = this.agentManager.resolveAgentProfile(readOptionalString$8(params.agentId));
3309
3460
  return resolveSessionWorkspacePath({
3310
3461
  sessionMetadata: params.metadata,
3311
- workspace: profile?.workspace ?? config.agents.defaults.workspace
3462
+ workspace: profile.workspace
3312
3463
  });
3313
3464
  };
3314
3465
  };
@@ -3320,6 +3471,7 @@ const SESSION_METADATA_LABEL_KEY = "label";
3320
3471
  const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3321
3472
  const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3322
3473
  const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3474
+ const SESSION_METADATA_PATCH_RUN_METADATA_KIND = "session_metadata_patch";
3323
3475
  function isDurableSessionEvent(event) {
3324
3476
  return event.type !== NcpEventType.ContextWindowUpdated;
3325
3477
  }
@@ -3360,7 +3512,7 @@ function mergeMetadataOverrides(metadata, overrides) {
3360
3512
  }
3361
3513
  function resolveSessionType(params) {
3362
3514
  const { metadata, runtime, sessionType } = params;
3363
- return readOptionalString$7(runtime) ?? readOptionalString$7(metadata.runtime) ?? readOptionalString$7(sessionType) ?? readOptionalString$7(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
3515
+ return readOptionalString$8(runtime) ?? readOptionalString$8(metadata.runtime) ?? readOptionalString$8(sessionType) ?? readOptionalString$8(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
3364
3516
  }
3365
3517
  function applySessionOverrides(params) {
3366
3518
  const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
@@ -3370,15 +3522,15 @@ function applySessionOverrides(params) {
3370
3522
  metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
3371
3523
  if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
3372
3524
  if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
3373
- if (readOptionalString$7(model)) {
3525
+ if (readOptionalString$8(model)) {
3374
3526
  metadata.model = model?.trim();
3375
3527
  metadata.preferred_model = model?.trim();
3376
3528
  }
3377
- if (readOptionalString$7(thinkingLevel)) {
3529
+ if (readOptionalString$8(thinkingLevel)) {
3378
3530
  metadata.thinking = thinkingLevel?.trim();
3379
3531
  metadata.preferred_thinking = thinkingLevel?.trim();
3380
3532
  }
3381
- if (readOptionalString$7(projectRoot)) metadata.project_root = projectRoot?.trim();
3533
+ if (readOptionalString$8(projectRoot)) metadata.project_root = projectRoot?.trim();
3382
3534
  }
3383
3535
  function isSessionSummaryRefreshEvent(event) {
3384
3536
  switch (event.type) {
@@ -3390,6 +3542,13 @@ function isSessionSummaryRefreshEvent(event) {
3390
3542
  default: return false;
3391
3543
  }
3392
3544
  }
3545
+ function readRuntimeSessionMetadataPatch(event) {
3546
+ if (event.type !== NcpEventType.RunMetadata) return null;
3547
+ const metadata = event.payload.metadata;
3548
+ if (metadata.kind !== SESSION_METADATA_PATCH_RUN_METADATA_KIND || !metadata.sessionMetadataPatch || typeof metadata.sessionMetadataPatch !== "object" || Array.isArray(metadata.sessionMetadataPatch)) return null;
3549
+ const patch = metadata.sessionMetadataPatch;
3550
+ return Object.keys(patch).length > 0 ? structuredClone(patch) : null;
3551
+ }
3393
3552
  var SessionManager = class {
3394
3553
  cleanups = [];
3395
3554
  contextWindowPreview;
@@ -3397,8 +3556,8 @@ var SessionManager = class {
3397
3556
  started = false;
3398
3557
  constructor(options) {
3399
3558
  this.options = options;
3400
- this.contextWindowPreview = new ContextWindowPreviewManager({ configManager: options.configManager });
3401
- this.workingDirResolver = new SessionWorkingDirResolver(options.configManager);
3559
+ this.contextWindowPreview = new ContextWindowPreviewManager(options.agentManager);
3560
+ this.workingDirResolver = new SessionWorkingDirResolver(options.agentManager);
3402
3561
  }
3403
3562
  start = () => {
3404
3563
  if (this.started) return;
@@ -3406,6 +3565,11 @@ var SessionManager = class {
3406
3565
  this.cleanups.push(this.options.eventBus.on(eventKeys.ncpEvent, async (event) => {
3407
3566
  const sessionId = readEventSessionId$1(event);
3408
3567
  if (!sessionId || !isDurableSessionEvent(event)) return;
3568
+ const metadataPatch = readRuntimeSessionMetadataPatch(event);
3569
+ if (metadataPatch) {
3570
+ await this.updateSessionMetadata(sessionId, metadataPatch);
3571
+ return;
3572
+ }
3409
3573
  await this.appendSessionEvent({
3410
3574
  event,
3411
3575
  sessionId
@@ -3420,9 +3584,9 @@ var SessionManager = class {
3420
3584
  const { agentId: requestedAgentId, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
3421
3585
  const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
3422
3586
  const metadata = cloneInheritedMetadata(sourceSessionMetadata);
3423
- const title = readOptionalString$7(requestedTitle) ?? summarizeTask(task);
3424
- const parentSessionId = readOptionalString$7(rawParentSessionId);
3425
- const requestId = readOptionalString$7(rawRequestId);
3587
+ const title = readOptionalString$8(requestedTitle) ?? summarizeTask(task);
3588
+ const parentSessionId = readOptionalString$8(rawParentSessionId);
3589
+ const requestId = readOptionalString$8(rawRequestId);
3426
3590
  const sessionType = resolveSessionType({
3427
3591
  runtime,
3428
3592
  sessionType: requestedSessionType,
@@ -3441,8 +3605,8 @@ var SessionManager = class {
3441
3605
  });
3442
3606
  const now = (/* @__PURE__ */ new Date()).toISOString();
3443
3607
  const nextMetadata = mergeMetadataOverrides(metadata, metadataOverrides);
3444
- const agentId = readOptionalString$7(requestedAgentId) ?? readOptionalString$7(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
3445
- const sessionId = readOptionalString$7(requestedSessionId) ?? buildSessionId();
3608
+ const agentId = readOptionalString$8(requestedAgentId) ?? readOptionalString$8(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
3609
+ const sessionId = readOptionalString$8(requestedSessionId) ?? buildSessionId();
3446
3610
  const record = {
3447
3611
  sessionId,
3448
3612
  ...agentId ? { agentId } : {},
@@ -3515,7 +3679,7 @@ var SessionManager = class {
3515
3679
  return await this.options.journalStore.getSession(normalizedSessionId);
3516
3680
  };
3517
3681
  listSessions = async (options) => {
3518
- const peerId = readOptionalString$7(options?.peerId);
3682
+ const peerId = readOptionalString$8(options?.peerId);
3519
3683
  return applyLimit((await this.options.journalStore.listSessionSummaries()).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), options?.limit);
3520
3684
  };
3521
3685
  listSessionMessages = async (sessionId, options) => {
@@ -3548,14 +3712,14 @@ var SessionManager = class {
3548
3712
  createAgentRunSession = async (params) => {
3549
3713
  const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, metadata, model, peerId: rawPeerId, projectRoot, sessionId, task, thinkingEffort } = params;
3550
3714
  const agentRuntimeId = requestedAgentRuntimeId ?? "native";
3551
- const peerId = readOptionalString$7(rawPeerId);
3715
+ const peerId = readOptionalString$8(rawPeerId);
3552
3716
  const peerIdentity = peerId ? createAgentPeerSessionIdentity({
3553
3717
  agentId,
3554
3718
  channel,
3555
3719
  metadata,
3556
3720
  peerId
3557
3721
  }) : void 0;
3558
- const requestedSessionId = readOptionalString$7(sessionId);
3722
+ const requestedSessionId = readOptionalString$8(sessionId);
3559
3723
  const created = await this.createSession({
3560
3724
  sourceSessionMetadata: {},
3561
3725
  sessionId: requestedSessionId ?? peerIdentity?.sessionId,
@@ -3845,12 +4009,12 @@ var PanelAppCapabilityGrantStore = class {
3845
4009
  };
3846
4010
  };
3847
4011
  function normalizeStoreData$2(value) {
3848
- if (!isRecord$9(value) || value.version !== 1 || !isRecord$9(value.grants)) return structuredClone(EMPTY_GRANTS$2);
4012
+ if (!isRecord$10(value) || value.version !== 1 || !isRecord$10(value.grants)) return structuredClone(EMPTY_GRANTS$2);
3849
4013
  const grants = {};
3850
4014
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
3851
- if (!isRecord$9(callerValue) || !isRecord$9(callerValue.capabilities)) continue;
4015
+ if (!isRecord$10(callerValue) || !isRecord$10(callerValue.capabilities)) continue;
3852
4016
  const capabilities = {};
3853
- for (const [capability, grantValue] of Object.entries(callerValue.capabilities)) if (isRecord$9(grantValue) && typeof grantValue.grantedAt === "string") capabilities[capability] = { grantedAt: grantValue.grantedAt };
4017
+ for (const [capability, grantValue] of Object.entries(callerValue.capabilities)) if (isRecord$10(grantValue) && typeof grantValue.grantedAt === "string") capabilities[capability] = { grantedAt: grantValue.grantedAt };
3854
4018
  grants[callerKey] = { capabilities };
3855
4019
  }
3856
4020
  return {
@@ -3861,7 +4025,7 @@ function normalizeStoreData$2(value) {
3861
4025
  function getCallerKey(caller) {
3862
4026
  return `${caller.surface}:${caller.appId}`;
3863
4027
  }
3864
- function isRecord$9(value) {
4028
+ function isRecord$10(value) {
3865
4029
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3866
4030
  }
3867
4031
  function isMissingFileError$3(error) {
@@ -3907,19 +4071,19 @@ var PanelAppClientGrantStore = class {
3907
4071
  };
3908
4072
  };
3909
4073
  function normalizeStoreData$1(value) {
3910
- if (!isRecord$8(value) || value.version !== 1 || !isRecord$8(value.grants)) return structuredClone(EMPTY_GRANTS$1);
4074
+ if (!isRecord$9(value) || value.version !== 1 || !isRecord$9(value.grants)) return structuredClone(EMPTY_GRANTS$1);
3911
4075
  const grants = {};
3912
- for (const [appId, grant] of Object.entries(value.grants)) if (isRecord$8(grant) && typeof grant.grantedAt === "string") grants[appId] = { grantedAt: grant.grantedAt };
4076
+ for (const [appId, grant] of Object.entries(value.grants)) if (isRecord$9(grant) && typeof grant.grantedAt === "string") grants[appId] = { grantedAt: grant.grantedAt };
3913
4077
  return {
3914
4078
  grants,
3915
4079
  version: 1
3916
4080
  };
3917
4081
  }
3918
- function isRecord$8(value) {
4082
+ function isRecord$9(value) {
3919
4083
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3920
4084
  }
3921
4085
  function isMissingFileError$2(error) {
3922
- return isRecord$8(error) && error.code === "ENOENT";
4086
+ return isRecord$9(error) && error.code === "ENOENT";
3923
4087
  }
3924
4088
  //#endregion
3925
4089
  //#region src/services/agent-run-client.service.ts
@@ -4138,7 +4302,7 @@ const PANEL_APP_AGENT_MAX_CONTEXT_CHARS = 8e4;
4138
4302
  function normalizePanelAppGenerateObjectInput(input) {
4139
4303
  const peerId = input.peerId.trim();
4140
4304
  const prompt = input.prompt.trim();
4141
- if (!peerId || !prompt || !isRecord$7(input.schema)) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "invalid generateObject request");
4305
+ if (!peerId || !prompt || !isRecord$8(input.schema)) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "invalid generateObject request");
4142
4306
  if (prompt.length > PANEL_APP_AGENT_MAX_PROMPT_CHARS) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "generateObject prompt is too large");
4143
4307
  if (stringifyJsonValue(input.context ?? null).length > PANEL_APP_AGENT_MAX_CONTEXT_CHARS) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "generateObject context is too large");
4144
4308
  return {
@@ -4279,7 +4443,7 @@ function readStructuredResultEvent(event, resultToolCallId) {
4279
4443
  };
4280
4444
  }
4281
4445
  function assertToolResultContent(content) {
4282
- if (!isRecord$7(content) || content.ok !== false || !isRecord$7(content.error)) return;
4446
+ if (!isRecord$8(content) || content.ok !== false || !isRecord$8(content.error)) return;
4283
4447
  if (content.error.code === "invalid_tool_arguments") throw new PanelAppError("AGENT_OBJECT_RESULT_SCHEMA_INVALID", "agent object result did not match the schema");
4284
4448
  throw new PanelAppError("AGENT_OBJECT_REQUEST_FAILED", typeof content.error.message === "string" ? content.error.message : "agent object request failed");
4285
4449
  }
@@ -4295,7 +4459,7 @@ function stringifyJsonValue(value) {
4295
4459
  throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "value is not JSON serializable");
4296
4460
  }
4297
4461
  }
4298
- function isRecord$7(value) {
4462
+ function isRecord$8(value) {
4299
4463
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4300
4464
  }
4301
4465
  //#endregion
@@ -4569,15 +4733,15 @@ function parsePanelAppFolderManifest(raw) {
4569
4733
  } catch (error) {
4570
4734
  throw new Error(`panel-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
4571
4735
  }
4572
- if (!isRecord$6(parsed)) throw new Error("panel-app.json must contain an object.");
4573
- const id = readOptionalString$6(parsed, "id");
4736
+ if (!isRecord$7(parsed)) throw new Error("panel-app.json must contain an object.");
4737
+ const id = readOptionalString$7(parsed, "id");
4574
4738
  if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
4575
4739
  return {
4576
4740
  id,
4577
- title: readRequiredString$3(parsed, "title"),
4578
- description: readOptionalString$6(parsed, "description"),
4579
- icon: readOptionalString$6(parsed, "icon"),
4580
- entry: readRequiredString$3(parsed, "entry"),
4741
+ title: readRequiredString$4(parsed, "title"),
4742
+ description: readOptionalString$7(parsed, "description"),
4743
+ icon: readOptionalString$7(parsed, "icon"),
4744
+ entry: readRequiredString$4(parsed, "entry"),
4581
4745
  capabilities: readStringArray$1(parsed.capabilities, "capabilities"),
4582
4746
  client: readOptionalBoolean$2(parsed, "client"),
4583
4747
  serviceActions: readStringArray$1(parsed.actions, "actions")
@@ -4637,12 +4801,12 @@ function parseTokenList(content) {
4637
4801
  if (!content) return [];
4638
4802
  return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
4639
4803
  }
4640
- function readRequiredString$3(record, key) {
4641
- const value = readOptionalString$6(record, key);
4804
+ function readRequiredString$4(record, key) {
4805
+ const value = readOptionalString$7(record, key);
4642
4806
  if (!value) throw new Error(`panel app ${key} is required.`);
4643
4807
  return value;
4644
4808
  }
4645
- function readOptionalString$6(record, key) {
4809
+ function readOptionalString$7(record, key) {
4646
4810
  return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
4647
4811
  }
4648
4812
  function readOptionalBoolean$2(record, key) {
@@ -4656,7 +4820,7 @@ function readStringArray$1(value, key) {
4656
4820
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`panel app ${key} must be a string array.`);
4657
4821
  return [...new Set(value.map((entry) => entry.trim()).filter(Boolean))];
4658
4822
  }
4659
- function isRecord$6(value) {
4823
+ function isRecord$7(value) {
4660
4824
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4661
4825
  }
4662
4826
  function normalizeTextValue(value) {
@@ -5374,12 +5538,12 @@ var ServiceActionGrantStore = class {
5374
5538
  };
5375
5539
  };
5376
5540
  function normalizeStoreData(value) {
5377
- if (!isRecord$5(value) || value.version !== 1 || !isRecord$5(value.grants)) return structuredClone(EMPTY_GRANTS);
5541
+ if (!isRecord$6(value) || value.version !== 1 || !isRecord$6(value.grants)) return structuredClone(EMPTY_GRANTS);
5378
5542
  const grants = {};
5379
5543
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
5380
- if (!isRecord$5(callerValue) || !isRecord$5(callerValue.actions)) continue;
5544
+ if (!isRecord$6(callerValue) || !isRecord$6(callerValue.actions)) continue;
5381
5545
  const actions = {};
5382
- for (const [actionId, actionValue] of Object.entries(callerValue.actions)) if (isRecord$5(actionValue) && typeof actionValue.grantedAt === "string" && isServiceActionRisk(actionValue.risk)) actions[actionId] = {
5546
+ for (const [actionId, actionValue] of Object.entries(callerValue.actions)) if (isRecord$6(actionValue) && typeof actionValue.grantedAt === "string" && isServiceActionRisk(actionValue.risk)) actions[actionId] = {
5383
5547
  grantedAt: actionValue.grantedAt,
5384
5548
  risk: actionValue.risk
5385
5549
  };
@@ -5393,11 +5557,11 @@ function normalizeStoreData(value) {
5393
5557
  function isServiceActionRisk(value) {
5394
5558
  return value === "read" || value === "write" || value === "external" || value === "dangerous";
5395
5559
  }
5396
- function isRecord$5(value) {
5560
+ function isRecord$6(value) {
5397
5561
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5398
5562
  }
5399
5563
  function isMissingFileError(error) {
5400
- return isRecord$5(error) && error.code === "ENOENT";
5564
+ return isRecord$6(error) && error.code === "ENOENT";
5401
5565
  }
5402
5566
  //#endregion
5403
5567
  //#region src/utils/service-app-manifest.utils.ts
@@ -5422,49 +5586,49 @@ function parseServiceAppManifest(raw) {
5422
5586
  } catch (error) {
5423
5587
  throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
5424
5588
  }
5425
- if (!isRecord$4(parsed)) throw new Error("service-app.json must contain an object.");
5426
- const id = readRequiredString$2(parsed, "id");
5589
+ if (!isRecord$5(parsed)) throw new Error("service-app.json must contain an object.");
5590
+ const id = readRequiredString$3(parsed, "id");
5427
5591
  if (!SERVICE_APP_ID_PATTERN.test(id)) throw new Error("service app id must be kebab-case.");
5428
- const protocol = readOptionalString$5(parsed, "protocol") ?? "mcp";
5592
+ const protocol = readOptionalString$6(parsed, "protocol") ?? "mcp";
5429
5593
  if (protocol !== "mcp") throw new Error("service app protocol must be mcp.");
5430
5594
  return {
5431
5595
  id,
5432
- title: readRequiredString$2(parsed, "title"),
5433
- description: readOptionalString$5(parsed, "description"),
5596
+ title: readRequiredString$3(parsed, "title"),
5597
+ description: readOptionalString$6(parsed, "description"),
5434
5598
  enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
5435
5599
  protocol,
5436
- command: readRequiredString$2(parsed, "command"),
5600
+ command: readRequiredString$3(parsed, "command"),
5437
5601
  args: readStringArray(parsed.args, "args"),
5438
5602
  actions: readManifestActions(parsed.actions)
5439
5603
  };
5440
5604
  }
5441
5605
  function readManifestActions(value) {
5442
5606
  if (value === void 0) throw new Error("service app actions are required.");
5443
- if (!isRecord$4(value)) throw new Error("service app actions must be an object.");
5607
+ if (!isRecord$5(value)) throw new Error("service app actions must be an object.");
5444
5608
  if (Object.keys(value).length === 0) throw new Error("service app actions cannot be empty.");
5445
5609
  const actions = {};
5446
5610
  for (const [name, action] of Object.entries(value)) {
5447
5611
  if (!name.trim()) throw new Error("service app action name cannot be empty.");
5448
- if (!isRecord$4(action)) throw new Error(`service app action ${name} must be an object.`);
5449
- const risk = readOptionalString$5(action, "risk");
5612
+ if (!isRecord$5(action)) throw new Error(`service app action ${name} must be an object.`);
5613
+ const risk = readOptionalString$6(action, "risk");
5450
5614
  if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
5451
5615
  const inputSchema = action.inputSchema;
5452
- if (inputSchema !== void 0 && !isRecord$4(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
5616
+ if (inputSchema !== void 0 && !isRecord$5(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
5453
5617
  actions[name] = {
5454
5618
  risk,
5455
- title: readOptionalString$5(action, "title"),
5456
- description: readOptionalString$5(action, "description"),
5619
+ title: readOptionalString$6(action, "title"),
5620
+ description: readOptionalString$6(action, "description"),
5457
5621
  inputSchema
5458
5622
  };
5459
5623
  }
5460
5624
  return actions;
5461
5625
  }
5462
- function readRequiredString$2(record, key) {
5463
- const value = readOptionalString$5(record, key);
5626
+ function readRequiredString$3(record, key) {
5627
+ const value = readOptionalString$6(record, key);
5464
5628
  if (!value) throw new Error(`service app ${key} is required.`);
5465
5629
  return value;
5466
5630
  }
5467
- function readOptionalString$5(record, key) {
5631
+ function readOptionalString$6(record, key) {
5468
5632
  return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
5469
5633
  }
5470
5634
  function readOptionalBoolean$1(record, key) {
@@ -5477,7 +5641,7 @@ function readStringArray(value, key) {
5477
5641
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`service app ${key} must be a string array.`);
5478
5642
  return value;
5479
5643
  }
5480
- function isRecord$4(value) {
5644
+ function isRecord$5(value) {
5481
5645
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5482
5646
  }
5483
5647
  //#endregion
@@ -5874,12 +6038,12 @@ function parseSkillFrontmatter(raw) {
5874
6038
  const summaryI18n = readLocalizedTextMap(parsed, "summaryi18n", "summary_i18n");
5875
6039
  const descriptionI18n = readLocalizedTextMap(parsed, "descriptioni18n", "description_i18n");
5876
6040
  return {
5877
- name: readString$4(parsed, "name"),
5878
- summary: readString$4(parsed, "summary"),
5879
- summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$4(parsed, "summaryzh", "summary_zh") }),
5880
- description: readString$4(parsed, "description"),
5881
- descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$4(parsed, "descriptionzh", "description_zh") }),
5882
- author: readString$4(parsed, "author"),
6041
+ name: readString$3(parsed, "name"),
6042
+ summary: readString$3(parsed, "summary"),
6043
+ summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$3(parsed, "summaryzh", "summary_zh") }),
6044
+ description: readString$3(parsed, "description"),
6045
+ descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$3(parsed, "descriptionzh", "description_zh") }),
6046
+ author: readString$3(parsed, "author"),
5883
6047
  tags: readTags(parsed)
5884
6048
  };
5885
6049
  }
@@ -5900,19 +6064,19 @@ function parseFrontmatterBlock(raw) {
5900
6064
  function parseYamlFrontmatter(raw) {
5901
6065
  try {
5902
6066
  const parsed = parse(raw);
5903
- return isRecord$3(parsed) ? parsed : {};
6067
+ return isRecord$4(parsed) ? parsed : {};
5904
6068
  } catch (error) {
5905
6069
  const message = error instanceof Error ? error.message : String(error);
5906
6070
  throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
5907
6071
  }
5908
6072
  }
5909
- function readString$4(record, ...names) {
6073
+ function readString$3(record, ...names) {
5910
6074
  const value = readValue(record, names);
5911
6075
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
5912
6076
  }
5913
6077
  function readLocalizedTextMap(record, ...names) {
5914
6078
  const value = readValue(record, names);
5915
- if (!isRecord$3(value)) return;
6079
+ if (!isRecord$4(value)) return;
5916
6080
  const localized = Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0).map(([locale, text]) => [normalizeLocaleTag(locale), text.trim()]));
5917
6081
  return Object.keys(localized).length > 0 ? localized : void 0;
5918
6082
  }
@@ -5936,7 +6100,7 @@ function normalizeFrontmatterKey(raw) {
5936
6100
  function normalizeLocaleTag(raw) {
5937
6101
  return raw.trim().toLowerCase();
5938
6102
  }
5939
- function isRecord$3(value) {
6103
+ function isRecord$4(value) {
5940
6104
  return typeof value === "object" && value !== null && !Array.isArray(value);
5941
6105
  }
5942
6106
  //#endregion
@@ -6102,7 +6266,7 @@ var NcpAgentSessionMetadataStore = class {
6102
6266
  read = async (sessionId, activitySnapshot) => {
6103
6267
  try {
6104
6268
  const parsed = JSON.parse(await readFile(this.metadataPath(sessionId), "utf-8"));
6105
- if (!isRecord$10(parsed) || parsed._type !== "metadata" || !isRecord$10(parsed.metadata)) throw new Error(`invalid ncp agent session metadata sidecar: ${sessionId}`);
6269
+ if (!isRecord$11(parsed) || parsed._type !== "metadata" || !isRecord$11(parsed.metadata)) throw new Error(`invalid ncp agent session metadata sidecar: ${sessionId}`);
6106
6270
  const createdAt = toIsoString(parsed.created_at, activitySnapshot.createdAt);
6107
6271
  const agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
6108
6272
  return {
@@ -6203,11 +6367,11 @@ var NcpAgentSessionSummaryIndexStore = class {
6203
6367
  function serializeJournalEntry(entry) {
6204
6368
  const serialized = JSON.stringify(entry);
6205
6369
  if (!serialized) throw new Error("ncp agent session journal entry serialization produced empty output");
6206
- if (!isRecord$10(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
6370
+ if (!isRecord$11(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
6207
6371
  return serialized;
6208
6372
  }
6209
6373
  function attachJournalTimestamp(event, timestamp) {
6210
- if (!("payload" in event) || !isRecord$10(event.payload)) return event;
6374
+ if (!("payload" in event) || !isRecord$11(event.payload)) return event;
6211
6375
  return {
6212
6376
  ...event,
6213
6377
  payload: {
@@ -6431,15 +6595,15 @@ var NcpAgentSessionJournalStore = class {
6431
6595
  console.warn(`[ncp-agent-session-journal] skipped corrupted journal line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
6432
6596
  continue;
6433
6597
  }
6434
- if (!isRecord$10(parsed)) continue;
6598
+ if (!isRecord$11(parsed)) continue;
6435
6599
  if (parsed._type === "metadata") {
6436
- metadata = isRecord$10(parsed.metadata) ? structuredClone(parsed.metadata) : {};
6600
+ metadata = isRecord$11(parsed.metadata) ? structuredClone(parsed.metadata) : {};
6437
6601
  agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
6438
6602
  createdAt = toIsoString(parsed.created_at, createdAt);
6439
6603
  updatedAt = toIsoString(parsed.updated_at, updatedAt);
6440
6604
  continue;
6441
6605
  }
6442
- if (parsed._type === "event" && isRecord$10(parsed.event)) {
6606
+ if (parsed._type === "event" && isRecord$11(parsed.event)) {
6443
6607
  const seq = Number(parsed.seq);
6444
6608
  nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
6445
6609
  const eventTimestamp = toIsoString(parsed.timestamp, updatedAt);
@@ -6753,11 +6917,11 @@ const NARP_API_MODE_HEADER = "x-nextclaw-narp-api-mode";
6753
6917
  const NARP_HTTP_RUNTIME_KIND = "narp-http";
6754
6918
  const NARP_STDIO_RUNTIME_KIND = "narp-stdio";
6755
6919
  const BUILTIN_PROVIDER_REGISTRY = new ProviderRegistry(BUILTIN_PROVIDER_PLUGINS);
6756
- function readRecord$1(value) {
6920
+ function readRecord(value) {
6757
6921
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
6758
6922
  return value;
6759
6923
  }
6760
- function readString$3(value) {
6924
+ function readString$2(value) {
6761
6925
  if (typeof value !== "string") return;
6762
6926
  return value.trim() || void 0;
6763
6927
  }
@@ -6765,9 +6929,11 @@ function resolveEntryIcon(entry) {
6765
6929
  return entry.icon ?? null;
6766
6930
  }
6767
6931
  function resolveRequestedModel(params) {
6768
- const { configuredModel, defaultModel, input, sessionMetadata } = params;
6769
- const runMetadata = readRecord$1(input.metadata);
6770
- return readString$3(runMetadata?.preferred_model) ?? readString$3(runMetadata?.preferredModel) ?? readString$3(runMetadata?.model) ?? readString$3(sessionMetadata.preferred_model) ?? readString$3(sessionMetadata.preferredModel) ?? readString$3(sessionMetadata.model) ?? configuredModel ?? defaultModel;
6932
+ const { configuredModel, defaultModel, input, modelSelectionMode, sessionMetadata } = params;
6933
+ if (modelSelectionMode === "runtime-default") return;
6934
+ const requestedModel = readString$2(readRecord(input.metadata)?.preferred_model) ?? readString$2(readRecord(input.metadata)?.preferredModel) ?? readString$2(readRecord(input.metadata)?.model) ?? readString$2(sessionMetadata.preferred_model) ?? readString$2(sessionMetadata.preferredModel) ?? readString$2(sessionMetadata.model);
6935
+ if (isRuntimeDefaultModelValue(requestedModel)) return;
6936
+ return requestedModel ?? configuredModel ?? (modelSelectionMode === "optional" ? void 0 : defaultModel);
6771
6937
  }
6772
6938
  function resolveProviderApiMode(resolution) {
6773
6939
  const wireApi = resolution.provider?.wireApi?.trim().toLowerCase();
@@ -6814,12 +6980,14 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6814
6980
  };
6815
6981
  describeInternal = async () => {
6816
6982
  const config = new HttpRuntimeConfigResolver(this.entry.config ?? {}).resolve({ defaultModel: this.defaultModel });
6983
+ const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
6817
6984
  if (!config.baseUrl) return {
6818
6985
  icon: resolveEntryIcon(this.entry),
6819
6986
  ready: false,
6820
6987
  reason: "base_url_missing",
6821
6988
  reasonMessage: "Configure the runtime entry baseUrl before starting an HTTP runtime session.",
6822
6989
  recommendedModel: config.recommendedModel ?? null,
6990
+ modelSelectionMode,
6823
6991
  cta: {
6824
6992
  kind: "settings",
6825
6993
  label: "Configure HTTP Runtime"
@@ -6831,6 +6999,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6831
6999
  reason: null,
6832
7000
  reasonMessage: null,
6833
7001
  recommendedModel: config.recommendedModel ?? null,
7002
+ modelSelectionMode,
6834
7003
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
6835
7004
  cta: null
6836
7005
  };
@@ -6849,6 +7018,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6849
7018
  reason: "healthcheck_failed",
6850
7019
  reasonMessage: `HTTP runtime healthcheck returned HTTP ${response.status}.`,
6851
7020
  recommendedModel: config.recommendedModel ?? null,
7021
+ modelSelectionMode,
6852
7022
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
6853
7023
  cta: null
6854
7024
  };
@@ -6858,6 +7028,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6858
7028
  reason: null,
6859
7029
  reasonMessage: null,
6860
7030
  recommendedModel: config.recommendedModel ?? null,
7031
+ modelSelectionMode,
6861
7032
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
6862
7033
  cta: null
6863
7034
  };
@@ -6895,6 +7066,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6895
7066
  };
6896
7067
  describeInternal = async (describeMode) => {
6897
7068
  const resolver = new StdioRuntimeConfigResolver(this.entry.config ?? {});
7069
+ const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
6898
7070
  try {
6899
7071
  const config = resolver.resolve();
6900
7072
  if (!await resolveExecutablePath(config.command)) return {
@@ -6905,7 +7077,8 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6905
7077
  cta: {
6906
7078
  kind: "settings",
6907
7079
  label: "Configure Stdio Runtime"
6908
- }
7080
+ },
7081
+ modelSelectionMode
6909
7082
  };
6910
7083
  if (describeMode === "probe") try {
6911
7084
  await probeStdioRuntime(config);
@@ -6918,7 +7091,8 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6918
7091
  cta: {
6919
7092
  kind: "settings",
6920
7093
  label: "Repair Stdio Runtime"
6921
- }
7094
+ },
7095
+ modelSelectionMode
6922
7096
  };
6923
7097
  }
6924
7098
  return {
@@ -6926,6 +7100,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6926
7100
  ready: true,
6927
7101
  reason: null,
6928
7102
  reasonMessage: null,
7103
+ modelSelectionMode,
6929
7104
  cta: null
6930
7105
  };
6931
7106
  } catch (error) {
@@ -6937,7 +7112,8 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6937
7112
  cta: {
6938
7113
  kind: "settings",
6939
7114
  label: "Configure Stdio Runtime"
6940
- }
7115
+ },
7116
+ modelSelectionMode
6941
7117
  };
6942
7118
  }
6943
7119
  };
@@ -6984,7 +7160,7 @@ var BuiltinNarpRuntimeProviderService = class {
6984
7160
  throw new Error("[narp] runtime entry is required before creating this runtime");
6985
7161
  };
6986
7162
  createHttpRuntime = (entry, runtimeParams) => {
6987
- const config = readRecord$1(entry.config) ?? {};
7163
+ const config = readRecord(entry.config) ?? {};
6988
7164
  const resolver = new HttpRuntimeConfigResolver(config);
6989
7165
  const resolvedConfig = resolver.resolve({ defaultModel: this.configManager.loadConfig().agents.defaults.model });
6990
7166
  return new HttpRuntimeNcpAgentRuntime({
@@ -6999,12 +7175,13 @@ var BuiltinNarpRuntimeProviderService = class {
6999
7175
  input,
7000
7176
  sessionMetadata: runtimeParams.sessionMetadata,
7001
7177
  defaultModel: this.configManager.loadConfig().agents.defaults.model,
7002
- configuredModel: readString$3(config.model)
7178
+ configuredModel: readString$2(config.model),
7179
+ modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
7003
7180
  })
7004
7181
  });
7005
7182
  };
7006
7183
  createStdioRuntime = (entry, runtimeParams) => {
7007
- const config = readRecord$1(entry.config) ?? {};
7184
+ const config = readRecord(entry.config) ?? {};
7008
7185
  return new StdioRuntimeNcpAgentRuntime({
7009
7186
  ...new StdioRuntimeConfigResolver(config).resolve(),
7010
7187
  sessionId: runtimeParams.sessionId,
@@ -7015,7 +7192,8 @@ var BuiltinNarpRuntimeProviderService = class {
7015
7192
  input,
7016
7193
  sessionMetadata: runtimeParams.sessionMetadata,
7017
7194
  defaultModel: this.configManager.loadConfig().agents.defaults.model,
7018
- configuredModel: readString$3(config.model)
7195
+ configuredModel: readString$2(config.model),
7196
+ modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
7019
7197
  })
7020
7198
  });
7021
7199
  };
@@ -7102,13 +7280,13 @@ var ProviderManagerNcpLLMApi = class {
7102
7280
  };
7103
7281
  //#endregion
7104
7282
  //#region src/features/native-runtime/tools/ncp-asset.tools.ts
7105
- function readOptionalString$4(value) {
7283
+ function readOptionalString$5(value) {
7106
7284
  if (typeof value !== "string") return null;
7107
7285
  const trimmed = value.trim();
7108
7286
  return trimmed.length > 0 ? trimmed : null;
7109
7287
  }
7110
7288
  function readOptionalBase64Bytes(value) {
7111
- const base64 = readOptionalString$4(value);
7289
+ const base64 = readOptionalString$5(value);
7112
7290
  if (!base64) return null;
7113
7291
  try {
7114
7292
  return Buffer.from(base64, "base64");
@@ -7159,18 +7337,18 @@ var AssetPutTool = class {
7159
7337
  this.contentBasePath = contentBasePath;
7160
7338
  }
7161
7339
  validateArgs = (args) => {
7162
- const path = readOptionalString$4(args.path);
7163
- const bytesBase64 = readOptionalString$4(args.bytesBase64);
7164
- const fileName = readOptionalString$4(args.fileName);
7340
+ const path = readOptionalString$5(args.path);
7341
+ const bytesBase64 = readOptionalString$5(args.bytesBase64);
7342
+ const fileName = readOptionalString$5(args.fileName);
7165
7343
  if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
7166
7344
  if (path) return [];
7167
7345
  if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
7168
7346
  return ["Provide either path, or bytesBase64 + fileName."];
7169
7347
  };
7170
7348
  execute = async (args) => {
7171
- const path = readOptionalString$4(args?.path);
7172
- const fileName = readOptionalString$4(args?.fileName);
7173
- const mimeType = readOptionalString$4(args?.mimeType);
7349
+ const path = readOptionalString$5(args?.path);
7350
+ const fileName = readOptionalString$5(args?.fileName);
7351
+ const mimeType = readOptionalString$5(args?.mimeType);
7174
7352
  const bytes = readOptionalBase64Bytes(args?.bytesBase64);
7175
7353
  if (path) return {
7176
7354
  ok: true,
@@ -7213,8 +7391,8 @@ var AssetExportTool = class {
7213
7391
  this.assetStore = assetStore;
7214
7392
  }
7215
7393
  execute = async (args) => {
7216
- const assetUri = readOptionalString$4(args?.assetUri);
7217
- const targetPath = readOptionalString$4(args?.targetPath);
7394
+ const assetUri = readOptionalString$5(args?.assetUri);
7395
+ const targetPath = readOptionalString$5(args?.targetPath);
7218
7396
  if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
7219
7397
  return {
7220
7398
  ok: true,
@@ -7240,7 +7418,7 @@ var AssetStatTool = class {
7240
7418
  this.contentBasePath = contentBasePath;
7241
7419
  }
7242
7420
  execute = async (args) => {
7243
- const assetUri = readOptionalString$4(args?.assetUri);
7421
+ const assetUri = readOptionalString$5(args?.assetUri);
7244
7422
  if (!assetUri) throw new Error("asset_stat requires assetUri.");
7245
7423
  const record = await this.assetStore.statRecord(assetUri);
7246
7424
  if (!record) return {
@@ -7308,10 +7486,16 @@ function resolveEffectiveModel(params) {
7308
7486
  const metadata = structuredClone(params.sessionMetadata);
7309
7487
  if (requestMetadata.clear_model === true || requestMetadata.reset_model === true) delete metadata.preferred_model;
7310
7488
  const inboundModel = readMetadataModel(requestMetadata);
7311
- if (inboundModel) metadata.preferred_model = inboundModel;
7489
+ if (inboundModel && isRuntimeDefaultModelValue(inboundModel)) {
7490
+ delete metadata.preferred_model;
7491
+ delete metadata.model;
7492
+ } else if (inboundModel) {
7493
+ metadata.preferred_model = inboundModel;
7494
+ metadata.model = inboundModel;
7495
+ }
7312
7496
  return {
7313
7497
  metadata,
7314
- model: normalizeOptionalString(metadata.preferred_model) ?? fallbackModel
7498
+ model: (isRuntimeDefaultModelValue(metadata.preferred_model) ? void 0 : normalizeOptionalString(metadata.preferred_model)) ?? fallbackModel
7315
7499
  };
7316
7500
  }
7317
7501
  function syncSessionThinkingPreference(params) {
@@ -7342,314 +7526,95 @@ function resolveSessionChannelContext(params) {
7342
7526
  //#endregion
7343
7527
  //#region src/features/native-runtime/utils/nextclaw-ncp-run-context.utils.ts
7344
7528
  const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
7345
- function readRequestedAgentId(metadata) {
7346
- return normalizeOptionalString(metadata.agent_id)?.toLowerCase() ?? normalizeOptionalString(metadata.agentId)?.toLowerCase() ?? null;
7347
- }
7348
- function resolveAgentProfile(params) {
7349
- const { config, requestMetadata, storedAgentId } = params;
7350
- const { agents: { defaults }, search: searchConfig, tools: { restrictToWorkspace, exec: { timeout: execTimeoutSeconds } } } = config;
7351
- const defaultAgentId = resolveDefaultAgentProfileId(config);
7352
- const profile = findEffectiveAgentProfile(config, normalizeOptionalString(storedAgentId)?.toLowerCase() ?? readRequestedAgentId(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
7353
- if (!profile) throw new Error(`default agent profile not found: ${defaultAgentId}`);
7354
- const contextTokens = profile.contextTokens ?? defaults.contextTokens;
7355
- return {
7356
- agentId: profile.id,
7357
- workspace: getWorkspacePath(profile.workspace ?? defaults.workspace),
7358
- model: profile.model ?? defaults.model,
7359
- contextTokens,
7360
- reservedContextTokens: ContextWindowBudgetService.resolveReservedContextTokens({
7361
- contextTokens,
7362
- configuredReservedContextTokens: profile.reservedContextTokens ?? defaults.reservedContextTokens
7363
- }),
7364
- restrictToWorkspace,
7365
- searchConfig,
7366
- execTimeoutSeconds
7367
- };
7368
- }
7369
7529
  function resolveRequestedToolNames(metadata) {
7370
7530
  const rawValue = metadata.requested_tools ?? metadata.requestedTools;
7371
7531
  if (!Array.isArray(rawValue)) return [];
7372
7532
  return Array.from(new Set(rawValue.map((item) => normalizeOptionalString(item)).filter((item) => Boolean(item))));
7373
- }
7374
- function mergeRunMetadata(params) {
7375
- const { requestMetadata, sessionMetadata } = params;
7376
- return {
7377
- ...sessionMetadata ? structuredClone(sessionMetadata) : {},
7378
- ...requestMetadata ? structuredClone(requestMetadata) : {}
7379
- };
7380
- }
7381
- function resolveNextclawNcpRunContext(params) {
7382
- const { configManager, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata, storedAgentId } = params;
7383
- const config = configManager.loadConfig();
7384
- const requestMetadata = mergeRunMetadata({
7385
- sessionMetadata: inputSessionMetadata,
7386
- requestMetadata: inputRequestMetadata
7387
- });
7388
- const profile = resolveAgentProfile({
7389
- config,
7390
- storedAgentId,
7391
- requestMetadata
7392
- });
7393
- const { metadata: modelMetadata, model: effectiveModel } = resolveEffectiveModel({
7394
- sessionMetadata: requestMetadata,
7395
- requestMetadata,
7396
- fallbackModel: profile.model
7397
- });
7398
- const effectiveWorkspace = resolveSessionWorkspacePath({
7399
- sessionMetadata: modelMetadata,
7400
- workspace: profile.workspace
7401
- });
7402
- const channelContext = resolveSessionChannelContext({
7403
- sessionMetadata: modelMetadata,
7404
- requestMetadata
7405
- });
7406
- const sessionMetadata = channelContext.metadata;
7407
- const requestedSkills = REQUESTED_SKILLS_METADATA_READER.readSelection(requestMetadata);
7408
- const runtimeThinking = resolveThinkingLevel({
7409
- config,
7410
- agentId: profile.agentId,
7411
- model: effectiveModel,
7412
- sessionThinkingLevel: parseThinkingLevel(sessionMetadata.preferred_thinking) ?? null
7413
- });
7414
- return {
7415
- channel: channelContext.channel,
7416
- chatId: channelContext.chatId,
7417
- config,
7418
- effectiveModel,
7419
- effectiveWorkspace,
7420
- profile,
7421
- requestMetadata,
7422
- requestedSkills,
7423
- requestedToolNames: resolveRequestedToolNames(requestMetadata),
7424
- runtimeThinking,
7425
- sessionKey: sessionId,
7426
- sessionMetadata,
7427
- toolRunContext: {
7428
- sessionId,
7429
- channel: channelContext.channel,
7430
- chatId: channelContext.chatId,
7431
- agentId: profile.agentId,
7432
- config,
7433
- execTimeoutSeconds: profile.execTimeoutSeconds,
7434
- handoffDepth: resolveAgentHandoffDepth(requestMetadata),
7435
- metadata: requestMetadata,
7436
- restrictToWorkspace: profile.restrictToWorkspace,
7437
- searchConfig: profile.searchConfig,
7438
- workspace: effectiveWorkspace
7439
- }
7440
- };
7441
- }
7442
- //#endregion
7443
- //#region src/features/runtime-registry/services/agent-runtime-registry.service.ts
7444
- function normalizeIdentifier(value) {
7445
- if (typeof value !== "string") return null;
7446
- const normalized = value.trim().toLowerCase();
7447
- return normalized.length > 0 ? normalized : null;
7448
- }
7449
- function cloneRuntimeEntry(entry) {
7450
- return {
7451
- id: entry.id,
7452
- label: entry.label,
7453
- ...entry.icon ? { icon: { ...entry.icon } } : {},
7454
- type: entry.type,
7455
- enabled: entry.enabled !== false,
7456
- config: entry.config ? { ...entry.config } : {}
7457
- };
7458
- }
7459
- function normalizeAgentRuntimeSessionTypeIcon(value) {
7460
- if (typeof value === "string") {
7461
- const src = value.trim();
7462
- return src ? {
7463
- kind: "image",
7464
- src
7465
- } : null;
7466
- }
7467
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
7468
- const iconRecord = value;
7469
- const src = typeof iconRecord.src === "string" ? iconRecord.src.trim() : "";
7470
- if (!src) return null;
7471
- const alt = typeof iconRecord.alt === "string" && iconRecord.alt.trim().length > 0 ? iconRecord.alt.trim() : null;
7472
- return {
7473
- kind: "image",
7474
- src,
7475
- ...alt ? { alt } : {}
7476
- };
7477
- }
7478
- const BUILTIN_RUNTIME_PRESENTATION = { hermes: {
7479
- label: "Hermes",
7480
- icon: {
7481
- kind: "image",
7482
- src: "app://runtime-icons/hermes-agent.png",
7483
- alt: "Hermes"
7484
- }
7485
- } };
7486
- function readString$2(value) {
7487
- if (typeof value !== "string") return;
7488
- return value.trim() || void 0;
7489
- }
7490
- function readRecord(value) {
7491
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
7492
- return value;
7493
- }
7494
- function resolveBuiltinRuntimePresentation(value) {
7495
- const normalized = readString$2(value)?.toLowerCase();
7496
- if (!normalized) return null;
7497
- if (!(normalized in BUILTIN_RUNTIME_PRESENTATION)) return null;
7498
- return BUILTIN_RUNTIME_PRESENTATION[normalized] ?? null;
7499
- }
7500
- function buildNativeRuntimeEntry(config) {
7501
- const nativeRuntimeConfig = readRecord(config.ui?.ncp?.runtimes?.native) ?? {};
7502
- return {
7503
- id: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7504
- label: "Native",
7505
- type: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7506
- enabled: nativeRuntimeConfig.enabled !== false,
7507
- config: nativeRuntimeConfig
7508
- };
7509
- }
7510
- function resolveAgentRuntimeEntries(params) {
7511
- const entries = /* @__PURE__ */ new Map();
7512
- entries.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, buildNativeRuntimeEntry(params.config));
7513
- for (const [rawId, rawEntry] of Object.entries(params.config.agents.runtimes.entries ?? {})) {
7514
- const id = rawId.trim().toLowerCase();
7515
- const type = readString$2(rawEntry.type)?.toLowerCase();
7516
- if (!id || !type) continue;
7517
- const explicitIcon = normalizeAgentRuntimeSessionTypeIcon(rawEntry.icon);
7518
- const builtinPresentation = resolveBuiltinRuntimePresentation(id) ?? resolveBuiltinRuntimePresentation(type);
7519
- entries.set(id, {
7520
- id,
7521
- label: readString$2(rawEntry.label) ?? builtinPresentation?.label ?? id,
7522
- ...explicitIcon ?? builtinPresentation?.icon ? { icon: explicitIcon ?? builtinPresentation?.icon } : {},
7523
- type,
7524
- enabled: rawEntry.enabled !== false,
7525
- config: rawEntry.config ? { ...rawEntry.config } : {}
7526
- });
7527
- }
7533
+ }
7534
+ function mergeRunMetadata(params) {
7535
+ const { requestMetadata, sessionMetadata } = params;
7528
7536
  return {
7529
- defaultEntryId: entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : [...entries.keys()][0] ?? "native",
7530
- entries: [...entries.values()]
7537
+ ...sessionMetadata ? structuredClone(sessionMetadata) : {},
7538
+ ...requestMetadata ? structuredClone(requestMetadata) : {}
7531
7539
  };
7532
7540
  }
7533
- function readRequestedRuntimeEntryId(sessionMetadata) {
7534
- return normalizeIdentifier(sessionMetadata.runtime) ?? normalizeIdentifier(sessionMetadata.session_type) ?? normalizeIdentifier(sessionMetadata.sessionType) ?? null;
7535
- }
7536
- var AgentRuntimeRegistry = class {
7537
- providers = /* @__PURE__ */ new Map();
7538
- entries = /* @__PURE__ */ new Map();
7539
- defaultEntryId = DEFAULT_AGENT_RUNTIME_ENTRY_ID;
7540
- register = (registration) => {
7541
- const normalizedKind = normalizeIdentifier(registration.kind);
7542
- if (!normalizedKind) throw new Error("agent runtime kind must be a non-empty string");
7543
- const token = Symbol(normalizedKind);
7544
- this.providers.set(normalizedKind, {
7545
- ...registration,
7546
- kind: normalizedKind,
7547
- token
7548
- });
7549
- return toDisposable(() => {
7550
- const current = this.providers.get(normalizedKind);
7551
- if (!current || current.token !== token) return;
7552
- this.providers.delete(normalizedKind);
7553
- });
7554
- };
7555
- applyEntries = (params) => {
7556
- const nextEntries = /* @__PURE__ */ new Map();
7557
- for (const rawEntry of params.entries) {
7558
- const id = normalizeIdentifier(rawEntry.id);
7559
- const type = normalizeIdentifier(rawEntry.type);
7560
- const label = rawEntry.label?.trim() ?? "";
7561
- if (!id || !type || !label) continue;
7562
- nextEntries.set(id, cloneRuntimeEntry({
7563
- ...rawEntry,
7564
- id,
7565
- type,
7566
- label
7567
- }));
7541
+ function buildNextclawNcpRunContext(params) {
7542
+ const { agentProfile, config, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata } = params;
7543
+ const requestMetadata = mergeRunMetadata({
7544
+ sessionMetadata: inputSessionMetadata,
7545
+ requestMetadata: inputRequestMetadata
7546
+ });
7547
+ const profile = buildResolvedAgentProfile({
7548
+ config,
7549
+ profile: agentProfile
7550
+ });
7551
+ const { metadata: modelMetadata, model: effectiveModel } = resolveEffectiveModel({
7552
+ sessionMetadata: requestMetadata,
7553
+ requestMetadata,
7554
+ fallbackModel: profile.model
7555
+ });
7556
+ const effectiveWorkspace = resolveSessionWorkspacePath({
7557
+ sessionMetadata: modelMetadata,
7558
+ workspace: profile.workspace
7559
+ });
7560
+ const channelContext = resolveSessionChannelContext({
7561
+ sessionMetadata: modelMetadata,
7562
+ requestMetadata
7563
+ });
7564
+ const sessionMetadata = channelContext.metadata;
7565
+ const requestedSkills = REQUESTED_SKILLS_METADATA_READER.readSelection(requestMetadata);
7566
+ const runtimeThinking = resolveThinkingLevel({
7567
+ config,
7568
+ agentId: profile.agentId,
7569
+ model: effectiveModel,
7570
+ sessionThinkingLevel: parseThinkingLevel(sessionMetadata.preferred_thinking) ?? null
7571
+ });
7572
+ return {
7573
+ channel: channelContext.channel,
7574
+ chatId: channelContext.chatId,
7575
+ config,
7576
+ effectiveModel,
7577
+ effectiveWorkspace,
7578
+ profile,
7579
+ requestMetadata,
7580
+ requestedSkills,
7581
+ requestedToolNames: resolveRequestedToolNames(requestMetadata),
7582
+ runtimeThinking,
7583
+ sessionKey: sessionId,
7584
+ sessionMetadata,
7585
+ toolRunContext: {
7586
+ sessionId,
7587
+ channel: channelContext.channel,
7588
+ chatId: channelContext.chatId,
7589
+ agentId: profile.agentId,
7590
+ config,
7591
+ execTimeoutSeconds: profile.execTimeoutSeconds,
7592
+ handoffDepth: resolveAgentHandoffDepth(requestMetadata),
7593
+ metadata: requestMetadata,
7594
+ restrictToWorkspace: profile.restrictToWorkspace,
7595
+ searchConfig: profile.searchConfig,
7596
+ workspace: effectiveWorkspace
7568
7597
  }
7569
- this.entries = nextEntries;
7570
- this.defaultEntryId = normalizeIdentifier(params.defaultEntryId) ?? (nextEntries.has("native") ? "native" : [...nextEntries.keys()][0] ?? "native");
7571
- };
7572
- resolveSessionMetadata = (sessionMetadata) => {
7573
- const { entry } = this.resolveRuntimeEntry(sessionMetadata);
7574
- return {
7575
- ...sessionMetadata,
7576
- runtime: entry.id,
7577
- session_type: entry.id,
7578
- runtime_type: entry.type
7579
- };
7580
- };
7581
- createRuntime = (params) => {
7582
- const nextSessionMetadata = this.resolveSessionMetadata(params.sessionMetadata);
7583
- const { entry, provider } = this.resolveRuntimeEntry(nextSessionMetadata);
7584
- if (provider.createRuntimeForEntry) return provider.createRuntimeForEntry({
7585
- entry: cloneRuntimeEntry(entry),
7586
- runtimeParams: {
7587
- ...params,
7588
- sessionMetadata: nextSessionMetadata
7589
- }
7590
- });
7591
- return provider.createRuntime({
7592
- ...params,
7593
- sessionMetadata: nextSessionMetadata
7594
- });
7595
- };
7596
- resolveRuntimeEntry = (sessionMetadata) => {
7597
- const requestedEntryId = readRequestedRuntimeEntryId(sessionMetadata) ?? this.defaultEntryId;
7598
- const entry = this.entries.get(requestedEntryId);
7599
- if (!entry || entry.enabled === false) throw new Error(`ncp runtime unavailable: ${requestedEntryId}`);
7600
- const provider = this.providers.get(entry.type);
7601
- if (!provider) throw new Error(`ncp runtime provider unavailable: ${entry.type}`);
7602
- return {
7603
- entry,
7604
- provider
7605
- };
7606
7598
  };
7607
- listSessionTypes = async (params) => {
7608
- const options = await Promise.all([...this.entries.values()].filter((entry) => entry.enabled !== false).map(async (entry) => {
7609
- const provider = this.providers.get(entry.type);
7610
- if (!provider) return {
7611
- value: entry.id,
7612
- label: entry.label,
7613
- icon: entry.icon ?? null,
7614
- ready: false,
7615
- reason: "runtime_provider_unavailable",
7616
- reasonMessage: `Runtime provider unavailable for type "${entry.type}".`,
7617
- recommendedModel: null,
7618
- cta: {
7619
- kind: "settings",
7620
- label: "Configure Runtime"
7621
- }
7622
- };
7623
- const descriptor = provider.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
7624
- entry: cloneRuntimeEntry(entry),
7625
- describeParams: params
7626
- }) : await provider.describeSessionType?.(params);
7627
- return {
7628
- value: entry.id,
7629
- label: entry.label,
7630
- icon: descriptor?.icon ?? entry.icon ?? null,
7631
- ready: descriptor?.ready ?? true,
7632
- reason: descriptor?.reason ?? null,
7633
- reasonMessage: descriptor?.reasonMessage ?? null,
7634
- recommendedModel: descriptor?.recommendedModel ?? null,
7635
- cta: descriptor?.cta ?? null,
7636
- ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
7637
- };
7638
- }));
7639
- return {
7640
- defaultType: this.defaultEntryId,
7641
- options: options.sort((left, right) => {
7642
- if (left.value === this.defaultEntryId) return -1;
7643
- if (right.value === this.defaultEntryId) return 1;
7644
- return left.value.localeCompare(right.value);
7645
- })
7646
- };
7599
+ }
7600
+ function buildResolvedAgentProfile(params) {
7601
+ const { config, profile } = params;
7602
+ const { search: searchConfig, tools: { restrictToWorkspace, exec: { timeout: execTimeoutSeconds } } } = config;
7603
+ return {
7604
+ agentId: profile.id,
7605
+ workspace: getWorkspacePath(profile.workspace),
7606
+ model: profile.model,
7607
+ contextTokens: profile.contextTokens,
7608
+ reservedContextTokens: profile.reservedContextTokens,
7609
+ restrictToWorkspace,
7610
+ searchConfig,
7611
+ execTimeoutSeconds
7647
7612
  };
7648
- };
7613
+ }
7649
7614
  //#endregion
7650
7615
  //#region src/services/agent-run-message-projector.service.ts
7651
7616
  var AgentRunMessageProjector = class {
7652
- project = (params) => projectNcpMessagesWithContextCompaction({
7617
+ project = (params) => buildContextCompactionModelInput({
7653
7618
  sessionId: params.sessionId,
7654
7619
  sessionMessages: params.messages
7655
7620
  });
@@ -7658,22 +7623,15 @@ var AgentRunMessageProjector = class {
7658
7623
  //#region src/services/agent-run-model-input-budgeter.service.ts
7659
7624
  var AgentRunModelInputBudgeter = class {
7660
7625
  inputBudgetPruner = new InputBudgetPruner();
7661
- constructor(configManager) {
7662
- this.configManager = configManager;
7626
+ constructor(agentManager) {
7627
+ this.agentManager = agentManager;
7663
7628
  }
7664
7629
  prune = async (params) => {
7665
- const config = this.configManager.loadConfig();
7666
- const defaultAgentId = resolveDefaultAgentProfileId(config);
7667
- const profile = findEffectiveAgentProfile(config, params.spec.agentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
7668
- const contextTokens = profile?.contextTokens ?? config.agents.defaults.contextTokens;
7669
- const reservedContextTokens = ContextWindowBudgetService.resolveReservedContextTokens({
7670
- contextTokens,
7671
- configuredReservedContextTokens: profile?.reservedContextTokens ?? config.agents.defaults.reservedContextTokens
7672
- });
7630
+ const profile = this.agentManager.resolveAgentProfile(params.spec.agentId);
7673
7631
  const pruned = this.inputBudgetPruner.prune({
7674
7632
  messages: params.messages.map((message) => ({ ...message })),
7675
- contextTokens,
7676
- reserveTokensFloor: reservedContextTokens,
7633
+ contextTokens: profile.contextTokens,
7634
+ reserveTokensFloor: profile.reservedContextTokens,
7677
7635
  softThresholdTokens: 0
7678
7636
  });
7679
7637
  return {
@@ -7788,18 +7746,22 @@ var AgentRunRuntimeContribution = class {
7788
7746
  modelInputBuilder;
7789
7747
  constructor(kernel) {
7790
7748
  this.kernel = kernel;
7791
- this.modelInputBuilder = new AgentRunModelInputBuilder(new AgentRunMessageProjector(), new AgentRunModelInputBudgeter(kernel.configManager), kernel.assetStore);
7749
+ this.modelInputBuilder = new AgentRunModelInputBuilder(new AgentRunMessageProjector(), new AgentRunModelInputBudgeter(kernel.agents), kernel.assetStore);
7792
7750
  }
7793
7751
  start = () => {
7794
7752
  if (this.cleanups.length > 0) return;
7795
- const { entries } = resolveAgentRuntimeEntries({ config: this.kernel.configManager.loadConfig() });
7796
- this.kernel.agentRuntimeManager.applyEntries(entries);
7753
+ this.applyRuntimeConfig(this.kernel.configManager.loadConfig());
7754
+ this.kernel.configManager.installRuntimeHooks({ applyAgentRuntimeConfig: this.applyRuntimeConfig });
7797
7755
  this.cleanups.push(this.registerNativeRuntime());
7798
7756
  for (const provider of new BuiltinNarpRuntimeProviderService(this.kernel.configManager).createProviders()) this.cleanups.push(this.registerNarpRuntime(provider));
7799
7757
  };
7800
7758
  dispose = async () => {
7801
7759
  while (this.cleanups.length > 0) await this.cleanups.pop()?.();
7802
7760
  };
7761
+ applyRuntimeConfig = (config) => {
7762
+ const { entries } = resolveAgentRuntimeEntries({ config });
7763
+ this.kernel.agentRuntimeManager.applyEntries(entries);
7764
+ };
7803
7765
  registerNativeRuntime = () => this.kernel.agentRuntimeManager.register({
7804
7766
  kind: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7805
7767
  label: "Native",
@@ -8157,11 +8119,7 @@ var ProjectContextProvider = class {
8157
8119
  //#endregion
8158
8120
  //#region src/contributions/context-provider/providers/reply-format-context.provider.ts
8159
8121
  var ReplyFormatContextProvider = class {
8160
- provide = (_request) => [[
8161
- "## Reply Formatting",
8162
- "- When mentioning a local project file in a user-visible reply, prefer a Markdown link such as `[AGENTS.md](AGENTS.md)` or `[file](packages/example/file.ts)` so the user can open it.",
8163
- "- Use project-relative links for files under the active/session-bound project root; use absolute links only for files outside it."
8164
- ].join("\n")];
8122
+ provide = (_request) => ["## Reply Formatting Contract\nGoal: local openable files mentioned in user-visible replies must be clickable.\nAllowed form: use Markdown links only, with a plain text label and an openable href: [MEMORY.md](MEMORY.md), [file](packages/example/file.ts), [notes.md](/Users/example/Documents/notes.md).\nPath choice: use project-relative hrefs for files under the active/session project root, and absolute hrefs for local files outside it.\nForbidden forms: bare file names or paths, inline-code file names, bold-only file names, code-styled link labels, code blocks for file references, and unlinked comma-separated file lists.\nExamples: bad `MEMORY.md` -> good [MEMORY.md](MEMORY.md); bad `memory/` -> good [memory/](memory/); bad `2026-03-07.md` / `feishu-notes.md` -> good [2026-03-07.md](memory/2026-03-07.md) / [feishu-notes.md](memory/feishu-notes.md).\nSelf-check before sending: scan the final visible reply for local file names or paths. If every concrete file cannot be linked, remove the exact names and summarize instead."];
8165
8123
  };
8166
8124
  //#endregion
8167
8125
  //#region src/contributions/context-provider/providers/skills-context.provider.ts
@@ -8372,12 +8330,15 @@ var ContextProviderRunContextService = class {
8372
8330
  request,
8373
8331
  session
8374
8332
  });
8375
- const runContext = resolveNextclawNcpRunContext({
8376
- configManager: this.kernel.configManager,
8333
+ const runContext = buildNextclawNcpRunContext({
8334
+ agentProfile: this.kernel.agents.resolveAgentProfileForRun({
8335
+ requestMetadata,
8336
+ storedAgentId: request.agentId ?? session?.agentId
8337
+ }),
8338
+ config: this.kernel.configManager.loadConfig(),
8377
8339
  sessionId,
8378
8340
  requestMetadata,
8379
- sessionMetadata: session?.metadata ?? requestMetadata,
8380
- storedAgentId: request.agentId ?? session?.agentId
8341
+ sessionMetadata: session?.metadata ?? requestMetadata
8381
8342
  });
8382
8343
  const tools = await this.kernel.toolProviderManager.buildTools(request);
8383
8344
  const sessionProjectRoot = readSessionProjectRoot(runContext.sessionMetadata);
@@ -8451,7 +8412,7 @@ var ContextWindowContribution = class {
8451
8412
  unsubscribeNcpEvent = null;
8452
8413
  constructor(kernel) {
8453
8414
  this.kernel = kernel;
8454
- this.contextWindowPreview = new ContextCompactionPreflightService({ configManager: kernel.configManager });
8415
+ this.contextWindowPreview = new ContextCompactionPreflightService(kernel.agents);
8455
8416
  }
8456
8417
  start = () => {
8457
8418
  if (this.unsubscribeNcpEvent) return;
@@ -8788,24 +8749,24 @@ const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
8788
8749
  "failed",
8789
8750
  "idle"
8790
8751
  ]);
8791
- function isRecord$2(value) {
8752
+ function isRecord$3(value) {
8792
8753
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8793
8754
  }
8794
- function readOptionalString$3(value) {
8755
+ function readOptionalString$4(value) {
8795
8756
  if (typeof value !== "string") return;
8796
8757
  const trimmed = value.trim();
8797
8758
  return trimmed.length > 0 ? trimmed : void 0;
8798
8759
  }
8799
8760
  function readSessionActivityPreviewMetadata(value) {
8800
- if (!isRecord$2(value)) return null;
8761
+ if (!isRecord$3(value)) return null;
8801
8762
  const state = value.state;
8802
- const timestamp = readOptionalString$3(value.timestamp);
8763
+ const timestamp = readOptionalString$4(value.timestamp);
8803
8764
  if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
8804
8765
  return {
8805
8766
  state,
8806
8767
  timestamp,
8807
- ...readOptionalString$3(value.statusText) ? { statusText: readOptionalString$3(value.statusText) } : {},
8808
- ...readOptionalString$3(value.replyText) ? { replyText: readOptionalString$3(value.replyText) } : {}
8768
+ ...readOptionalString$4(value.statusText) ? { statusText: readOptionalString$4(value.statusText) } : {},
8769
+ ...readOptionalString$4(value.replyText) ? { replyText: readOptionalString$4(value.replyText) } : {}
8809
8770
  };
8810
8771
  }
8811
8772
  function compareIsoTimestamp(left, right) {
@@ -8901,47 +8862,20 @@ var SessionActivityPreviewContribution = class {
8901
8862
  //#endregion
8902
8863
  //#region src/contributions/tool-provider/providers/asset-tool.provider.ts
8903
8864
  var AssetToolProvider = class {
8904
- constructor(kernel) {
8905
- this.kernel = kernel;
8865
+ constructor(assetStore) {
8866
+ this.assetStore = assetStore;
8906
8867
  }
8907
- provide = async (_request) => createAssetTools({ assetStore: this.kernel.assetStore });
8868
+ provide = async (_request) => createAssetTools({ assetStore: this.assetStore });
8908
8869
  };
8909
8870
  //#endregion
8910
- //#region src/contributions/tool-provider/utils/tool-provider-run-context.utils.ts
8911
- async function resolveToolProviderRunContext(params) {
8912
- const { kernel, request } = params;
8913
- const session = request.sessionId ? await kernel.sessionManager.getAgentRunSession(request.sessionId) : null;
8914
- const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
8915
- const requestMetadata = buildAgentRunRequestMetadata({
8916
- request,
8917
- session
8918
- });
8919
- const runContext = resolveNextclawNcpRunContext({
8920
- configManager: kernel.configManager,
8921
- sessionId,
8922
- requestMetadata,
8923
- sessionMetadata: session?.metadata ?? requestMetadata,
8924
- storedAgentId: request.agentId ?? session?.agentId
8925
- });
8926
- return {
8927
- requestMetadata,
8928
- runContext,
8929
- session,
8930
- sessionId,
8931
- toolRunContext: runContext.toolRunContext
8932
- };
8933
- }
8934
- //#endregion
8935
8871
  //#region src/contributions/tool-provider/providers/core-tool.provider.ts
8936
8872
  var CoreToolProvider = class {
8937
- constructor(kernel) {
8938
- this.kernel = kernel;
8873
+ constructor(runContextService, getGatewayController) {
8874
+ this.runContextService = runContextService;
8875
+ this.getGatewayController = getGatewayController;
8939
8876
  }
8940
8877
  provide = async (request) => {
8941
- const { toolRunContext } = await resolveToolProviderRunContext({
8942
- kernel: this.kernel,
8943
- request
8944
- });
8878
+ const { toolRunContext } = await this.runContextService.resolve(request);
8945
8879
  const { channel, chatId, execTimeoutSeconds, restrictToWorkspace, searchConfig, sessionId, workspace } = toolRunContext;
8946
8880
  const allowedDir = restrictToWorkspace ? workspace : void 0;
8947
8881
  const execTool = new ExecTool({
@@ -8954,7 +8888,7 @@ var CoreToolProvider = class {
8954
8888
  chatId,
8955
8889
  sessionKey: sessionId
8956
8890
  });
8957
- const gatewayTool = new GatewayTool(this.kernel.getGatewayController());
8891
+ const gatewayTool = new GatewayTool(this.getGatewayController());
8958
8892
  gatewayTool.setContext({ sessionKey: sessionId });
8959
8893
  return [
8960
8894
  new ReadFileTool(allowedDir),
@@ -8973,15 +8907,13 @@ var CoreToolProvider = class {
8973
8907
  //#endregion
8974
8908
  //#region src/contributions/tool-provider/providers/mcp-tool.provider.ts
8975
8909
  var McpToolProvider = class {
8976
- constructor(kernel) {
8977
- this.kernel = kernel;
8910
+ constructor(runContextService, mcpManager) {
8911
+ this.runContextService = runContextService;
8912
+ this.mcpManager = mcpManager;
8978
8913
  }
8979
8914
  provide = async (request) => {
8980
- const { toolRunContext } = await resolveToolProviderRunContext({
8981
- kernel: this.kernel,
8982
- request
8983
- });
8984
- return this.kernel.mcpManager.listToolsForRun({ agentId: toolRunContext.agentId });
8915
+ const { toolRunContext } = await this.runContextService.resolve(request);
8916
+ return this.mcpManager.listToolsForRun({ agentId: toolRunContext.agentId });
8985
8917
  };
8986
8918
  };
8987
8919
  //#endregion
@@ -8994,24 +8926,24 @@ function readMetadataAccountId(metadata) {
8994
8926
  }
8995
8927
  }
8996
8928
  var MessagingToolProvider = class {
8997
- constructor(kernel) {
8998
- this.kernel = kernel;
8929
+ constructor(runContextService, channels, automation, extensions) {
8930
+ this.runContextService = runContextService;
8931
+ this.channels = channels;
8932
+ this.automation = automation;
8933
+ this.extensions = extensions;
8999
8934
  }
9000
8935
  provide = async (request) => {
9001
- const { toolRunContext } = await resolveToolProviderRunContext({
9002
- kernel: this.kernel,
9003
- request
9004
- });
8936
+ const { toolRunContext } = await this.runContextService.resolve(request);
9005
8937
  const { channel, chatId, metadata } = toolRunContext;
9006
8938
  const accountId = readMetadataAccountId(metadata);
9007
8939
  const messageTool = new MessageTool(async (message) => {
9008
- if (!await this.kernel.channels.deliver(message)) throw new Error(`channel "${message.channel}" is not available`);
8940
+ if (!await this.channels.deliver(message)) throw new Error(`channel "${message.channel}" is not available`);
9009
8941
  }, { resolveChannels: this.resolveMessageChannels });
9010
8942
  messageTool.setContext(channel, chatId, accountId ?? null);
9011
- return [messageTool, new CronTool(this.kernel.automation)];
8943
+ return [messageTool, new CronTool(this.automation)];
9012
8944
  };
9013
8945
  resolveMessageChannels = () => {
9014
- const channels = this.kernel.extensions.getExtensionRegistry()?.channels ?? [];
8946
+ const channels = this.extensions.getExtensionRegistry()?.channels ?? [];
9015
8947
  return [...new Set(channels.map((registration) => registration.channel.id.trim()).filter(Boolean))].sort();
9016
8948
  };
9017
8949
  };
@@ -9150,12 +9082,12 @@ var SessionsHistoryTool = class {
9150
9082
  };
9151
9083
  //#endregion
9152
9084
  //#region src/tools/session-request.tools.ts
9153
- function readRequiredString$1(params, key) {
9085
+ function readRequiredString$2(params, key) {
9154
9086
  const value = params[key];
9155
9087
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9156
9088
  return value.trim();
9157
9089
  }
9158
- function readOptionalString$2(params, key) {
9090
+ function readOptionalString$3(params, key) {
9159
9091
  const value = params[key];
9160
9092
  if (typeof value !== "string") return;
9161
9093
  const trimmed = value.trim();
@@ -9209,16 +9141,16 @@ var SessionRequestTool = class {
9209
9141
  const params = normalizeToolParams(args);
9210
9142
  const target = params.target;
9211
9143
  if (!target || typeof target !== "object" || Array.isArray(target)) throw new Error("target must be an object.");
9212
- const task = readRequiredString$1(params, "task");
9213
- const notifyMode = readOptionalString$2(params, "notify")?.toLowerCase();
9144
+ const task = readRequiredString$2(params, "task");
9145
+ const notifyMode = readOptionalString$3(params, "notify")?.toLowerCase();
9214
9146
  if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
9215
9147
  return this.manager.requestSession({
9216
9148
  sourceSessionId: this.sourceSessionId,
9217
9149
  sourceToolCallId: context?.toolCallId,
9218
9150
  updateToolCallResult: context?.updateToolCallResult,
9219
- targetSessionId: readRequiredString$1(target, "session_id"),
9151
+ targetSessionId: readRequiredString$2(target, "session_id"),
9220
9152
  task,
9221
- title: readOptionalString$2(params, "title"),
9153
+ title: readOptionalString$3(params, "title"),
9222
9154
  notify: notifyMode,
9223
9155
  handoffDepth: this.handoffDepth
9224
9156
  });
@@ -9226,7 +9158,7 @@ var SessionRequestTool = class {
9226
9158
  };
9227
9159
  //#endregion
9228
9160
  //#region src/tools/session-search.tools.ts
9229
- function isRecord$1(value) {
9161
+ function isRecord$2(value) {
9230
9162
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9231
9163
  }
9232
9164
  function readOptionalInteger(value) {
@@ -9276,7 +9208,7 @@ var SessionSearchTool = class {
9276
9208
  return issues;
9277
9209
  };
9278
9210
  execute = async (args) => {
9279
- if (!isRecord$1(args)) throw new Error("session_search requires an object argument.");
9211
+ if (!isRecord$2(args)) throw new Error("session_search requires an object argument.");
9280
9212
  const issues = this.validateArgs(args);
9281
9213
  if (issues.length > 0) throw new Error(issues.join(" "));
9282
9214
  return this.queryService.search({
@@ -9289,23 +9221,23 @@ var SessionSearchTool = class {
9289
9221
  };
9290
9222
  //#endregion
9291
9223
  //#region src/tools/session-spawn.tools.ts
9292
- function readRequiredString(value, key) {
9224
+ function readRequiredString$1(value, key) {
9293
9225
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9294
9226
  return value.trim();
9295
9227
  }
9296
- function readOptionalString$1(value) {
9228
+ function readOptionalString$2(value) {
9297
9229
  if (typeof value !== "string") return;
9298
9230
  const trimmed = value.trim();
9299
9231
  return trimmed.length > 0 ? trimmed : void 0;
9300
9232
  }
9301
9233
  function readSpawnScope(value) {
9302
- const normalized = readOptionalString$1(value)?.toLowerCase();
9234
+ const normalized = readOptionalString$2(value)?.toLowerCase();
9303
9235
  if (!normalized || normalized === "standalone") return "standalone";
9304
9236
  if (normalized === "child") return "child";
9305
9237
  throw new Error("scope must be \"standalone\" or \"child\".");
9306
9238
  }
9307
9239
  function readSpawnNotify(value) {
9308
- const notifyMode = readOptionalString$1(value)?.toLowerCase();
9240
+ const notifyMode = readOptionalString$2(value)?.toLowerCase();
9309
9241
  if (!notifyMode && typeof value === "undefined") return;
9310
9242
  if (notifyMode === "none" || notifyMode === "final_reply") return notifyMode;
9311
9243
  throw new Error("notify must be \"none\" or \"final_reply\".");
@@ -9364,7 +9296,7 @@ var SessionSpawnTool = class {
9364
9296
  };
9365
9297
  execute = async (args, context) => {
9366
9298
  const { agentId: rawAgentId, model: rawModel, notify: rawNotify, runtime: rawRuntime, scope: rawScope, task: rawTask, title: rawTitle } = normalizeToolParams(args);
9367
- const task = readRequiredString(rawTask, "task");
9299
+ const task = readRequiredString$1(rawTask, "task");
9368
9300
  const scope = readSpawnScope(rawScope);
9369
9301
  const notify = readSpawnNotify(rawNotify);
9370
9302
  const parentSessionId = scope === "child" ? this.readParentSessionIdOrThrow() : void 0;
@@ -9374,10 +9306,10 @@ var SessionSpawnTool = class {
9374
9306
  updateToolCallResult: context?.updateToolCallResult,
9375
9307
  sourceSessionMetadata: this.sourceSessionMetadata,
9376
9308
  task,
9377
- title: readOptionalString$1(rawTitle),
9378
- agentId: readOptionalString$1(rawAgentId),
9379
- model: readOptionalString$1(rawModel),
9380
- runtime: readOptionalString$1(rawRuntime),
9309
+ title: readOptionalString$2(rawTitle),
9310
+ agentId: readOptionalString$2(rawAgentId),
9311
+ model: readOptionalString$2(rawModel),
9312
+ runtime: readOptionalString$2(rawRuntime),
9381
9313
  handoffDepth: this.handoffDepth,
9382
9314
  parentSessionId,
9383
9315
  notify
@@ -9385,11 +9317,11 @@ var SessionSpawnTool = class {
9385
9317
  const session = await this.sessionManager.createSession({
9386
9318
  sourceSessionId: this.sourceSessionId,
9387
9319
  task,
9388
- title: readOptionalString$1(rawTitle),
9320
+ title: readOptionalString$2(rawTitle),
9389
9321
  sourceSessionMetadata: this.sourceSessionMetadata,
9390
- agentId: readOptionalString$1(rawAgentId),
9391
- model: readOptionalString$1(rawModel),
9392
- runtime: readOptionalString$1(rawRuntime),
9322
+ agentId: readOptionalString$2(rawAgentId),
9323
+ model: readOptionalString$2(rawModel),
9324
+ runtime: readOptionalString$2(rawRuntime),
9393
9325
  parentSessionId
9394
9326
  });
9395
9327
  return {
@@ -9413,22 +9345,22 @@ var SessionSpawnTool = class {
9413
9345
  //#endregion
9414
9346
  //#region src/contributions/tool-provider/providers/session-tool.provider.ts
9415
9347
  var SessionToolProvider = class {
9416
- constructor(kernel) {
9417
- this.kernel = kernel;
9348
+ constructor(runContextService, sessionManager, sessionRequests, sessionSearch) {
9349
+ this.runContextService = runContextService;
9350
+ this.sessionManager = sessionManager;
9351
+ this.sessionRequests = sessionRequests;
9352
+ this.sessionSearch = sessionSearch;
9418
9353
  }
9419
9354
  provide = async (request) => {
9420
- const { toolRunContext } = await resolveToolProviderRunContext({
9421
- kernel: this.kernel,
9422
- request
9423
- });
9355
+ const { toolRunContext } = await this.runContextService.resolve(request);
9424
9356
  const { handoffDepth, metadata, sessionId } = toolRunContext;
9425
- const sessionsSpawnTool = new SessionSpawnTool(this.kernel.sessionManager, this.kernel.sessionRequests);
9357
+ const sessionsSpawnTool = new SessionSpawnTool(this.sessionManager, this.sessionRequests);
9426
9358
  sessionsSpawnTool.setContext({
9427
9359
  sourceSessionId: sessionId,
9428
9360
  sourceSessionMetadata: metadata,
9429
9361
  handoffDepth
9430
9362
  });
9431
- const sessionsRequestTool = new SessionRequestTool(this.kernel.sessionRequests);
9363
+ const sessionsRequestTool = new SessionRequestTool(this.sessionRequests);
9432
9364
  sessionsRequestTool.setContext({
9433
9365
  sourceSessionId: sessionId,
9434
9366
  handoffDepth
@@ -9436,15 +9368,166 @@ var SessionToolProvider = class {
9436
9368
  const tools = [
9437
9369
  sessionsSpawnTool,
9438
9370
  sessionsRequestTool,
9439
- new SessionsListTool(this.kernel.sessionManager),
9440
- new SessionsHistoryTool(this.kernel.sessionManager)
9371
+ new SessionsListTool(this.sessionManager),
9372
+ new SessionsHistoryTool(this.sessionManager)
9441
9373
  ];
9442
- if (!this.kernel.sessionSearch.isReady()) return tools;
9443
- tools.push(new SessionSearchTool({ search: this.kernel.sessionSearch.search }, { currentSessionId: sessionId }));
9374
+ if (!this.sessionSearch.isReady()) return tools;
9375
+ tools.push(new SessionSearchTool({ search: this.sessionSearch.search }, { currentSessionId: sessionId }));
9444
9376
  return tools;
9445
9377
  };
9446
9378
  };
9447
9379
  //#endregion
9380
+ //#region src/tools/show-content.tools.ts
9381
+ const SHOW_CONTENT_TOOL_NAME = "show_content";
9382
+ function isRecord$1(value) {
9383
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9384
+ }
9385
+ function readRequiredString(value, key) {
9386
+ if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9387
+ return value.trim();
9388
+ }
9389
+ function readOptionalString$1(value) {
9390
+ if (typeof value !== "string") return;
9391
+ const trimmed = value.trim();
9392
+ return trimmed.length > 0 ? trimmed : void 0;
9393
+ }
9394
+ function readOptionalPositiveInteger(value, key) {
9395
+ if (typeof value === "undefined") return;
9396
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) throw new Error(`${key} must be a positive integer.`);
9397
+ return value;
9398
+ }
9399
+ function readPurpose(value) {
9400
+ const normalized = readOptionalString$1(value);
9401
+ if (!normalized) return;
9402
+ if (normalized === "read" || normalized === "preview" || normalized === "edit" || normalized === "interact") return normalized;
9403
+ throw new Error("purpose must be \"read\", \"preview\", \"edit\", or \"interact\".");
9404
+ }
9405
+ function readPayload(params) {
9406
+ if (!isRecord$1(params.payload)) throw new Error("payload must be an object.");
9407
+ return params.payload;
9408
+ }
9409
+ function readUrl(value) {
9410
+ const url = readRequiredString(value, "payload.url");
9411
+ let parsed;
9412
+ try {
9413
+ parsed = new URL(url);
9414
+ } catch {
9415
+ throw new Error("payload.url must be a valid URL.");
9416
+ }
9417
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("payload.url must use http or https.");
9418
+ return parsed.toString();
9419
+ }
9420
+ function normalizeShowContentArgs(args) {
9421
+ const params = normalizeToolParams(args);
9422
+ const type = readRequiredString(params.type, "type");
9423
+ const payload = readPayload(params);
9424
+ const title = readOptionalString$1(params.title);
9425
+ const purpose = readPurpose(params.purpose);
9426
+ if (type === "file") return {
9427
+ target: {
9428
+ type,
9429
+ payload: {
9430
+ path: readRequiredString(payload.path, "payload.path"),
9431
+ line: readOptionalPositiveInteger(payload.line, "payload.line"),
9432
+ column: readOptionalPositiveInteger(payload.column, "payload.column")
9433
+ }
9434
+ },
9435
+ title,
9436
+ purpose
9437
+ };
9438
+ if (type === "url") return {
9439
+ target: {
9440
+ type,
9441
+ payload: { url: readUrl(payload.url) }
9442
+ },
9443
+ title,
9444
+ purpose
9445
+ };
9446
+ if (type === "panel_app") return {
9447
+ target: {
9448
+ type,
9449
+ payload: { appId: readRequiredString(payload.appId, "payload.appId") }
9450
+ },
9451
+ title,
9452
+ purpose
9453
+ };
9454
+ throw new Error("type must be \"file\", \"url\", or \"panel_app\".");
9455
+ }
9456
+ function summarizeTarget(target) {
9457
+ if (target.type === "file") return target.payload.path;
9458
+ if (target.type === "url") return target.payload.url;
9459
+ return target.payload.appId;
9460
+ }
9461
+ function createShowContentEventPayload(request, context) {
9462
+ const toolCallId = readOptionalString$1(context?.toolCallId);
9463
+ return {
9464
+ id: toolCallId ? `tool:${toolCallId}:show-content` : `show-content:${request.target.type}:${summarizeTarget(request.target)}`,
9465
+ toolCallId,
9466
+ target: request.target,
9467
+ title: request.title,
9468
+ purpose: request.purpose
9469
+ };
9470
+ }
9471
+ var ShowContentTool = class {
9472
+ name = SHOW_CONTENT_TOOL_NAME;
9473
+ description = "Show file, URL, or panel app content in the current chat UI.";
9474
+ parameters = {
9475
+ type: "object",
9476
+ properties: {
9477
+ type: {
9478
+ type: "string",
9479
+ enum: [
9480
+ "file",
9481
+ "url",
9482
+ "panel_app"
9483
+ ],
9484
+ description: "Content target type."
9485
+ },
9486
+ title: {
9487
+ type: "string",
9488
+ description: "Optional title for the shown content."
9489
+ },
9490
+ purpose: {
9491
+ type: "string",
9492
+ enum: [
9493
+ "read",
9494
+ "preview",
9495
+ "edit",
9496
+ "interact"
9497
+ ],
9498
+ description: "Optional user intent for the content."
9499
+ },
9500
+ payload: {
9501
+ type: "object",
9502
+ description: "Type-specific fields: file={path,line,column}; url={url}; panel_app={appId}.",
9503
+ additionalProperties: true
9504
+ }
9505
+ },
9506
+ required: ["type", "payload"],
9507
+ additionalProperties: false
9508
+ };
9509
+ constructor(eventBus) {
9510
+ this.eventBus = eventBus;
9511
+ }
9512
+ execute = async (args, context) => {
9513
+ const request = normalizeShowContentArgs(args);
9514
+ this.eventBus.emit(eventKeys.uiShowContent, createShowContentEventPayload(request, context), { source: "kernel" });
9515
+ return {
9516
+ ok: true,
9517
+ action: "showContent",
9518
+ request
9519
+ };
9520
+ };
9521
+ };
9522
+ //#endregion
9523
+ //#region src/contributions/tool-provider/providers/show-content-tool.provider.ts
9524
+ var ShowContentToolProvider = class {
9525
+ constructor(eventBus) {
9526
+ this.eventBus = eventBus;
9527
+ }
9528
+ provide = () => [new ShowContentTool(this.eventBus)];
9529
+ };
9530
+ //#endregion
9448
9531
  //#region src/contributions/tool-provider/providers/structured-result-tool.provider.ts
9449
9532
  var StructuredResultToolProvider = class {
9450
9533
  provide = (request) => {
@@ -9467,6 +9550,40 @@ function isRecord(value) {
9467
9550
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9468
9551
  }
9469
9552
  //#endregion
9553
+ //#region src/contributions/tool-provider/services/tool-provider-run-context.service.ts
9554
+ var ToolProviderRunContextService = class {
9555
+ constructor(sessionManager, agentManager, configManager) {
9556
+ this.sessionManager = sessionManager;
9557
+ this.agentManager = agentManager;
9558
+ this.configManager = configManager;
9559
+ }
9560
+ resolve = async (request) => {
9561
+ const session = request.sessionId ? await this.sessionManager.getAgentRunSession(request.sessionId) : null;
9562
+ const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
9563
+ const requestMetadata = buildAgentRunRequestMetadata({
9564
+ request,
9565
+ session
9566
+ });
9567
+ const runContext = buildNextclawNcpRunContext({
9568
+ agentProfile: this.agentManager.resolveAgentProfileForRun({
9569
+ requestMetadata,
9570
+ storedAgentId: request.agentId ?? session?.agentId
9571
+ }),
9572
+ config: this.configManager.loadConfig(),
9573
+ sessionId,
9574
+ requestMetadata,
9575
+ sessionMetadata: session?.metadata ?? requestMetadata
9576
+ });
9577
+ return {
9578
+ requestMetadata,
9579
+ runContext,
9580
+ session,
9581
+ sessionId,
9582
+ toolRunContext: runContext.toolRunContext
9583
+ };
9584
+ };
9585
+ };
9586
+ //#endregion
9470
9587
  //#region src/contributions/tool-provider/index.ts
9471
9588
  var ToolProviderContribution = class {
9472
9589
  cleanups = [];
@@ -9480,14 +9597,18 @@ var ToolProviderContribution = class {
9480
9597
  dispose = () => {
9481
9598
  while (this.cleanups.length > 0) this.cleanups.pop()?.();
9482
9599
  };
9483
- createToolProviders = () => [
9484
- new StructuredResultToolProvider(),
9485
- new CoreToolProvider(this.kernel),
9486
- new MessagingToolProvider(this.kernel),
9487
- new SessionToolProvider(this.kernel),
9488
- new AssetToolProvider(this.kernel),
9489
- new McpToolProvider(this.kernel)
9490
- ];
9600
+ createToolProviders = () => {
9601
+ const runContextService = new ToolProviderRunContextService(this.kernel.sessionManager, this.kernel.agents, this.kernel.configManager);
9602
+ return [
9603
+ new StructuredResultToolProvider(),
9604
+ new ShowContentToolProvider(this.kernel.eventBus),
9605
+ new CoreToolProvider(runContextService, this.kernel.getGatewayController),
9606
+ new MessagingToolProvider(runContextService, this.kernel.channels, this.kernel.automation, this.kernel.extensions),
9607
+ new SessionToolProvider(runContextService, this.kernel.sessionManager, this.kernel.sessionRequests, this.kernel.sessionSearch),
9608
+ new AssetToolProvider(this.kernel.assetStore),
9609
+ new McpToolProvider(runContextService, this.kernel.mcpManager)
9610
+ ];
9611
+ };
9491
9612
  };
9492
9613
  //#endregion
9493
9614
  //#region src/app/nextclaw-kernel.ts
@@ -9543,26 +9664,27 @@ var NextclawKernel = class {
9543
9664
  gatewayController;
9544
9665
  constructor(options = {}) {
9545
9666
  const sessionsDir = resolveKernelSessionsDir(options);
9546
- this.sessionSearch = new SessionSearchManager({
9667
+ this.sessionSearch = new SessionSearchService({
9547
9668
  databasePath: resolve(getDataDir(), "session-search.db"),
9548
9669
  sessionsDir
9549
9670
  });
9550
9671
  this.ncpAgentSessionJournalStore = new NcpAgentSessionJournalStore(resolve(sessionsDir, ".ncp-agent-journal"));
9551
9672
  this.automation = new AutomationManager({ storePath: resolveKernelAutomationStorePath(options) });
9552
9673
  this.assetStore = new LocalAssetStore({ rootDir: resolve(getDataDir(), "assets") });
9553
- this.agents = new AgentManager();
9554
9674
  this.control = new NextclawKernelControlManager();
9555
- this.channels = new ChannelManager$1({ bus: this.messageBus });
9675
+ this.channels = new ChannelManager({ bus: this.messageBus });
9556
9676
  this.configManager = new ConfigManager({
9557
9677
  configPath: options.configPath,
9558
9678
  channels: this.channels,
9559
9679
  providerManager: this.llmProviders
9560
9680
  });
9681
+ this.agents = new AgentManager(this.configManager);
9561
9682
  this.accessManager = new AccessManager({
9562
9683
  configManager: this.configManager,
9563
9684
  homeDir: options.homeDir
9564
9685
  });
9565
9686
  this.sessionManager = new SessionManager({
9687
+ agentManager: this.agents,
9566
9688
  configManager: this.configManager,
9567
9689
  eventBus: this.eventBus,
9568
9690
  journalStore: this.ncpAgentSessionJournalStore,
@@ -9595,9 +9717,9 @@ var NextclawKernel = class {
9595
9717
  ingress: this.ingress
9596
9718
  })
9597
9719
  });
9598
- this.contextCompactionManager = new AgentRunContextCompactionManager(this.configManager, this.llmProviders, this.sessionManager);
9720
+ this.contextCompactionManager = new AgentRunContextCompactionManager(this.agents, this.llmProviders, this.sessionManager);
9599
9721
  this.sessionRunManager = new SessionRunManager(this.sessionManager);
9600
- this.agentRunRequestManager = new AgentRunRequestManager(this.agentRuntimeManager, this.configManager, this.contextProviderManager, this.eventBus, this.ingress, this.sessionManager, this.sessionRunManager, this.toolProviderManager);
9722
+ this.agentRunRequestManager = new AgentRunRequestManager(this.agentRuntimeManager, this.agents, this.configManager, this.contextProviderManager, this.eventBus, this.ingress, this.sessionManager, this.sessionRunManager, this.toolProviderManager);
9601
9723
  this.contributions = [
9602
9724
  new ToolProviderContribution(this),
9603
9725
  new SessionActivityPreviewContribution(this),
@@ -10237,6 +10359,6 @@ function resolveLegacyEventType(message) {
10237
10359
  return `message.${role || "other"}`;
10238
10360
  }
10239
10361
  //#endregion
10240
- export { AccessManager, AgentManager, AgentRunClient, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppAssetTokenService, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildServiceActionId, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
10362
+ export { AccessManager, AgentManager, AgentRunClient, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppAssetTokenService, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionModelInput, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildNextclawNcpRunContext, buildServiceActionId, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, describeAgentRuntimeSessionTypes, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, waitForAgentRuntimeSessionReply };
10241
10363
 
10242
10364
  //# sourceMappingURL=index.js.map