@nextclaw/kernel 0.4.3 → 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) {
@@ -256,23 +277,6 @@ function shouldRefreshContextWindowImmediately(event) {
256
277
  //#region src/features/context-compaction/services/context-compaction-preflight.service.ts
257
278
  const SUMMARY_MAX_TOKENS = 4e3;
258
279
  const SUMMARY_SOURCE_MAX_CHARS = 12e4;
259
- function readRequestedAgentId$1(metadata) {
260
- return normalizeString$1(metadata.agent_id)?.toLowerCase() ?? normalizeString$1(metadata.agentId)?.toLowerCase() ?? null;
261
- }
262
- function resolveCompactionProfile(params) {
263
- const { config, requestMetadata, storedAgentId } = params;
264
- const { defaults } = config.agents;
265
- const defaultAgentId = resolveDefaultAgentProfileId(config);
266
- const profile = findEffectiveAgentProfile(config, normalizeString$1(storedAgentId)?.toLowerCase() ?? readRequestedAgentId$1(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
267
- return {
268
- contextTokens: profile?.contextTokens ?? defaults.contextTokens,
269
- model: profile?.model ?? defaults.model,
270
- reservedContextTokens: ContextWindowBudgetService.resolveReservedContextTokens({
271
- contextTokens: profile?.contextTokens ?? defaults.contextTokens,
272
- configuredReservedContextTokens: profile?.reservedContextTokens ?? defaults.reservedContextTokens
273
- })
274
- };
275
- }
276
280
  function mergeInputMessages(params) {
277
281
  const messages = params.sessionMessages.map((message) => structuredClone(message));
278
282
  const seen = new Set(messages.map((message) => message.id));
@@ -304,13 +308,13 @@ function buildContextWindowSnapshotFromBudget(params) {
304
308
  var ContextCompactionPreflightService = class {
305
309
  compactionService = new ContextCompactionService();
306
310
  contextWindowBudgetService = new ContextWindowBudgetService();
307
- constructor(options) {
308
- this.options = options;
311
+ constructor(agentManager, providerManager) {
312
+ this.agentManager = agentManager;
313
+ this.providerManager = providerManager;
309
314
  }
310
315
  preview = (params) => {
311
316
  const { requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
312
- const profile = resolveCompactionProfile({
313
- config: this.options.configManager.loadConfig(),
317
+ const profile = this.resolveCompactionProfile({
314
318
  requestMetadata,
315
319
  storedAgentId
316
320
  });
@@ -331,8 +335,7 @@ var ContextCompactionPreflightService = class {
331
335
  };
332
336
  begin = (params) => {
333
337
  const { inputMessages, requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
334
- const profile = resolveCompactionProfile({
335
- config: this.options.configManager.loadConfig(),
338
+ const profile = this.resolveCompactionProfile({
336
339
  requestMetadata,
337
340
  storedAgentId
338
341
  });
@@ -429,9 +432,9 @@ var ContextCompactionPreflightService = class {
429
432
  };
430
433
  };
431
434
  generateSummary = async (params) => {
432
- 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");
433
436
  const { messages, model } = params;
434
- const summary = (await this.options.providerManager.chat({
437
+ const summary = (await this.providerManager.chat({
435
438
  model,
436
439
  maxTokens: SUMMARY_MAX_TOKENS,
437
440
  messages: [{
@@ -458,14 +461,24 @@ var ContextCompactionPreflightService = class {
458
461
  if (!summary) throw new Error("context compaction summary is empty");
459
462
  return summary;
460
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
+ };
461
475
  };
462
476
  //#endregion
463
477
  //#region src/features/context-compaction/managers/context-compaction.manager.ts
464
478
  var ContextWindowPreviewManager = class {
465
479
  preflightService;
466
- constructor(options) {
467
- this.options = options;
468
- this.preflightService = new ContextCompactionPreflightService({ configManager: options.configManager });
480
+ constructor(agentManager) {
481
+ this.preflightService = new ContextCompactionPreflightService(agentManager);
469
482
  }
470
483
  preview = (params) => {
471
484
  const { requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
@@ -482,12 +495,9 @@ var ContextWindowPreviewManager = class {
482
495
  //#region src/managers/agent-run-context-compaction.manager.ts
483
496
  var AgentRunContextCompactionManager = class {
484
497
  preflightService;
485
- constructor(configManager, providerManager, sessionManager) {
498
+ constructor(agentManager, providerManager, sessionManager) {
486
499
  this.sessionManager = sessionManager;
487
- this.preflightService = new ContextCompactionPreflightService({
488
- configManager,
489
- providerManager
490
- });
500
+ this.preflightService = new ContextCompactionPreflightService(agentManager, providerManager);
491
501
  }
492
502
  runPreflight = async (input) => {
493
503
  const beginResult = this.preflightService.begin({
@@ -519,7 +529,7 @@ var AgentRunContextCompactionManager = class {
519
529
  //#region src/managers/agent-run-request.manager.ts
520
530
  function toAgentRunRequest(envelope) {
521
531
  const metadata = envelope.metadata ?? {};
522
- const peerId = readOptionalString$9(envelope.peerId);
532
+ const peerId = readOptionalString$10(envelope.peerId);
523
533
  const requestMetadata = {
524
534
  agentRuntimeId: metadata.agentRuntimeId,
525
535
  agentId: metadata.agentId,
@@ -532,7 +542,7 @@ function toAgentRunRequest(envelope) {
532
542
  thinkingEffort: metadata.thinkingEffort
533
543
  };
534
544
  if (Array.isArray(envelope.content)) {
535
- const sessionId = readOptionalString$9(envelope.sessionId);
545
+ const sessionId = readOptionalString$10(envelope.sessionId);
536
546
  if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
537
547
  return {
538
548
  ...requestMetadata,
@@ -550,8 +560,8 @@ function toAgentRunRequest(envelope) {
550
560
  }
551
561
  const sourceMessage = envelope.message;
552
562
  if (!sourceMessage) throw new Error("Invalid agent run send request.");
553
- const envelopeSessionId = readOptionalString$9(envelope.sessionId);
554
- const messageSessionId = readOptionalString$9(sourceMessage.sessionId);
563
+ const envelopeSessionId = readOptionalString$10(envelope.sessionId);
564
+ const messageSessionId = readOptionalString$10(sourceMessage.sessionId);
555
565
  const sessionId = envelopeSessionId ?? messageSessionId;
556
566
  if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
557
567
  const message = {
@@ -570,7 +580,7 @@ function toAgentRunRequest(envelope) {
570
580
  message
571
581
  };
572
582
  }
573
- function readOptionalString$9(value) {
583
+ function readOptionalString$10(value) {
574
584
  if (typeof value !== "string") return;
575
585
  return value.trim() || void 0;
576
586
  }
@@ -592,8 +602,9 @@ function readMessageTask(message) {
592
602
  var AgentRunRequestManager = class {
593
603
  cleanups = [];
594
604
  started = false;
595
- constructor(agentRuntimeManager, configManager, contextProviderManager, eventBus, ingress, sessionManager, sessionRunManager, toolProviderManager) {
605
+ constructor(agentRuntimeManager, agentManager, configManager, contextProviderManager, eventBus, ingress, sessionManager, sessionRunManager, toolProviderManager) {
596
606
  this.agentRuntimeManager = agentRuntimeManager;
607
+ this.agentManager = agentManager;
597
608
  this.configManager = configManager;
598
609
  this.contextProviderManager = contextProviderManager;
599
610
  this.eventBus = eventBus;
@@ -675,7 +686,7 @@ var AgentRunRequestManager = class {
675
686
  }
676
687
  })();
677
688
  const model = request.model ?? session.model ?? this.configManager.getDefaultModel();
678
- const agentId = request.agentId ?? session.agentId ?? resolveDefaultAgentProfileId(this.configManager.loadConfig());
689
+ const agentId = request.agentId ?? session.agentId ?? this.agentManager.getDefaultAgentId();
679
690
  const spec = {
680
691
  runId: activeRun.runId,
681
692
  agentId,
@@ -749,6 +760,126 @@ var AgentRunRequestManager = class {
749
760
  //#region src/configs/agent-runtime.config.ts
750
761
  const DEFAULT_AGENT_RUNTIME_ENTRY_ID = "native";
751
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
752
883
  //#region src/managers/agent-runtime.manager.ts
753
884
  var AgentRuntimeManager = class {
754
885
  providers = /* @__PURE__ */ new Map();
@@ -794,31 +925,11 @@ var AgentRuntimeManager = class {
794
925
  cache.set(cacheKey, agentRuntime);
795
926
  return agentRuntime;
796
927
  };
797
- listSessionTypes = async (_params) => {
798
- const entries = [...this.entries.values()].filter((entry) => entry.enabled !== false);
799
- const options = await Promise.all(entries.map(async (entry) => {
800
- const provider = this.providers.get(entry.type);
801
- const descriptor = provider?.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
802
- entry,
803
- describeParams: _params
804
- }) : null;
805
- return {
806
- value: entry.id,
807
- label: entry.label,
808
- icon: descriptor?.icon ?? entry.icon ?? null,
809
- ready: provider ? descriptor?.ready ?? true : false,
810
- reason: provider ? descriptor?.reason ?? null : "runtime_provider_unavailable",
811
- reasonMessage: provider ? descriptor?.reasonMessage ?? null : `Runtime provider unavailable for type "${entry.type}".`,
812
- recommendedModel: descriptor?.recommendedModel ?? null,
813
- cta: descriptor?.cta ?? null,
814
- ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
815
- };
816
- }));
817
- return {
818
- defaultType: this.entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : entries[0]?.id ?? "native",
819
- options
820
- };
821
- };
928
+ listSessionTypes = async (params) => describeAgentRuntimeSessionTypes({
929
+ entries: [...this.entries.values()],
930
+ providers: this.providers,
931
+ describeParams: params
932
+ });
822
933
  dispose = async () => {
823
934
  await this.disposeAllRuntimes();
824
935
  this.providers.clear();
@@ -1159,6 +1270,117 @@ var AutomationManager = class extends CronService {
1159
1270
  }
1160
1271
  };
1161
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
1162
1384
  //#region src/managers/config.manager.ts
1163
1385
  const hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
1164
1386
  const mergeDeep = (base, patch) => {
@@ -1769,21 +1991,6 @@ var CommandRegistry = class {
1769
1991
  };
1770
1992
  //#endregion
1771
1993
  //#region src/features/extension-runtime/services/extension-lifecycle.service.ts
1772
- function sanitizeExtensionNodeOptions(value) {
1773
- if (!value?.trim()) return;
1774
- const tokens = value.split(/\s+/).filter(Boolean);
1775
- const sanitized = [];
1776
- for (let index = 0; index < tokens.length; index += 1) {
1777
- const token = tokens[index];
1778
- if (token === "--conditions=development" || token === "-C=development") continue;
1779
- if ((token === "--conditions" || token === "-C") && tokens[index + 1] === "development") {
1780
- index += 1;
1781
- continue;
1782
- }
1783
- sanitized.push(token);
1784
- }
1785
- return sanitized.length > 0 ? sanitized.join(" ") : void 0;
1786
- }
1787
1994
  var ExtensionLifecycleService = class {
1788
1995
  processes = /* @__PURE__ */ new Map();
1789
1996
  startAll = (manifests, params) => {
@@ -1813,14 +2020,12 @@ var ExtensionLifecycleService = class {
1813
2020
  if (existing) return existing;
1814
2021
  const child = spawn(manifest.server.command === "node" || manifest.server.command === "node.exe" ? process.execPath : manifest.server.command, manifest.server.args ?? [], {
1815
2022
  cwd: manifest.rootDir,
1816
- env: {
1817
- ...process.env,
1818
- NODE_OPTIONS: sanitizeExtensionNodeOptions(process.env.NODE_OPTIONS),
2023
+ env: createRuntimeChildEnv(process.env, {
1819
2024
  ...manifest.server.env,
1820
2025
  NEXTCLAW_EXTENSION_ID: manifest.id,
1821
2026
  NEXTCLAW_EXTENSION_ENDPOINT: params.endpoint,
1822
2027
  NEXTCLAW_EXTENSION_TOKEN: params.tokenForExtension(manifest.id)
1823
- },
2028
+ }, { inheritBaseEnv: true }),
1824
2029
  stdio: [
1825
2030
  "ignore",
1826
2031
  "ignore",
@@ -1860,7 +2065,7 @@ const BUILTIN_EXTENSION_PACKAGES = [
1860
2065
  "@nextclaw/channel-extension-weixin"
1861
2066
  ];
1862
2067
  const runtimeRequire = createRequire(import.meta.url);
1863
- function readString$6(value) {
2068
+ function readString$5(value) {
1864
2069
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1865
2070
  }
1866
2071
  function readStringArray$2(value) {
@@ -1871,7 +2076,7 @@ function readStringRecord(value) {
1871
2076
  const entries = Object.entries(value);
1872
2077
  return entries.every(([, item]) => typeof item === "string") ? Object.fromEntries(entries) : void 0;
1873
2078
  }
1874
- function readRecord$3(value) {
2079
+ function readRecord$2(value) {
1875
2080
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1876
2081
  }
1877
2082
  function uniquePaths(paths) {
@@ -1908,17 +2113,17 @@ function resolveDevFirstPartyExtensionDir(explicitDir = process.env.NEXTCLAW_DEV
1908
2113
  function toManifest(value, rootDir) {
1909
2114
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("extension manifest must be an object");
1910
2115
  const record = value;
1911
- const server = readRecord$3(record.server);
1912
- const id = readString$6(record.id);
1913
- 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);
1914
2119
  if (!id) throw new Error("extension manifest id is required");
1915
2120
  if (server.type !== "stdio") throw new Error("extension server.type must be stdio");
1916
2121
  if (!command) throw new Error("extension server.command is required");
1917
2122
  return {
1918
2123
  id,
1919
2124
  rootDir,
1920
- ...readString$6(record.name) ? { name: readString$6(record.name) } : {},
1921
- ...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) } : {},
1922
2127
  server: {
1923
2128
  type: "stdio",
1924
2129
  command,
@@ -2022,19 +2227,19 @@ function listExtensionChannelIds(params) {
2022
2227
  //#region src/services/extension-runtime.service.ts
2023
2228
  const EXTENSION_REQUEST_EVENT_TYPE = "extension.request";
2024
2229
  const EXTENSION_REQUEST_TIMEOUT_MS = 6e4;
2025
- function readString$5(value) {
2230
+ function readString$4(value) {
2026
2231
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
2027
2232
  }
2028
- function readRecord$2(value) {
2233
+ function readRecord$1(value) {
2029
2234
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2030
2235
  }
2031
- function readRequiredString$4(value, name) {
2032
- const trimmed = readString$5(value);
2236
+ function readRequiredString$5(value, name) {
2237
+ const trimmed = readString$4(value);
2033
2238
  if (!trimmed) throw new Error(`${name} is required`);
2034
2239
  return trimmed;
2035
2240
  }
2036
2241
  function readTextContent(value) {
2037
- const content = readRecord$2(value);
2242
+ const content = readRecord$1(value);
2038
2243
  if (content.type !== "text" || typeof content.text !== "string") throw new Error("only text channel messages are supported by the first ingress bridge");
2039
2244
  return content.text;
2040
2245
  }
@@ -2044,35 +2249,35 @@ function readOptionalNumber(value) {
2044
2249
  function readInboundAttachments(value) {
2045
2250
  if (!Array.isArray(value)) return [];
2046
2251
  return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))).map((entry) => ({
2047
- ...readString$5(entry.id) ? { id: readString$5(entry.id) } : {},
2048
- ...readString$5(entry.name) ? { name: readString$5(entry.name) } : {},
2049
- ...readString$5(entry.path) ? { path: readString$5(entry.path) } : {},
2050
- ...readString$5(entry.url) ? { url: readString$5(entry.url) } : {},
2051
- ...readString$5(entry.assetUri) ? { assetUri: readString$5(entry.assetUri) } : {},
2052
- ...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) } : {},
2053
2258
  ...readOptionalNumber(entry.size) !== void 0 ? { size: readOptionalNumber(entry.size) } : {},
2054
- ...readString$5(entry.source) ? { source: readString$5(entry.source) } : {},
2259
+ ...readString$4(entry.source) ? { source: readString$4(entry.source) } : {},
2055
2260
  ...entry.status === "ready" || entry.status === "remote-only" ? { status: entry.status } : {},
2056
- ...readString$5(entry.errorCode) ? { errorCode: readString$5(entry.errorCode) } : {}
2261
+ ...readString$4(entry.errorCode) ? { errorCode: readString$4(entry.errorCode) } : {}
2057
2262
  }));
2058
2263
  }
2059
2264
  function toInboundMessage(value) {
2060
- const payload = readRecord$2(value);
2265
+ const payload = readRecord$1(value);
2061
2266
  return {
2062
- channel: readRequiredString$4(payload.channelId, "channelId"),
2063
- chatId: readRequiredString$4(payload.conversationId, "conversationId"),
2064
- 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"),
2065
2270
  content: readTextContent(payload.content),
2066
2271
  timestamp: /* @__PURE__ */ new Date(),
2067
2272
  attachments: readInboundAttachments(payload.attachments),
2068
- metadata: readRecord$2(payload.metadata)
2273
+ metadata: readRecord$1(payload.metadata)
2069
2274
  };
2070
2275
  }
2071
2276
  function normalizeChannelConfigResult(value) {
2072
- return readRecord$2(readRecord$2(value).channelConfig);
2277
+ return readRecord$1(readRecord$1(value).channelConfig);
2073
2278
  }
2074
2279
  function normalizeAuthLoginResult(value) {
2075
- const record = readRecord$2(value);
2280
+ const record = readRecord$1(value);
2076
2281
  return {
2077
2282
  channelConfig: normalizeChannelConfigResult(record),
2078
2283
  accountId: typeof record.accountId === "string" ? record.accountId : null,
@@ -2081,11 +2286,11 @@ function normalizeAuthLoginResult(value) {
2081
2286
  }
2082
2287
  function normalizeAuthPollResult(value) {
2083
2288
  if (!value) return null;
2084
- const record = readRecord$2(value);
2289
+ const record = readRecord$1(value);
2085
2290
  return {
2086
- channel: readRequiredString$4(record.channel, "channel"),
2291
+ channel: readRequiredString$5(record.channel, "channel"),
2087
2292
  status: record.status,
2088
- message: readString$5(record.message),
2293
+ message: readString$4(record.message),
2089
2294
  nextPollMs: readOptionalNumber(record.nextPollMs),
2090
2295
  accountId: typeof record.accountId === "string" ? record.accountId : null,
2091
2296
  notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
@@ -2181,7 +2386,7 @@ var ExtensionRuntimeService = class {
2181
2386
  if (running.length > 0) console.log(`✓ Extensions started: ${running.map((entry) => entry.manifest.id).join(", ")}`);
2182
2387
  };
2183
2388
  getExtensionProcessToken = (extensionId) => {
2184
- const id = readRequiredString$4(extensionId, "extensionId");
2389
+ const id = readRequiredString$5(extensionId, "extensionId");
2185
2390
  const current = this.extensionTokens.get(id);
2186
2391
  if (current) return current;
2187
2392
  const token = randomUUID();
@@ -2189,8 +2394,8 @@ var ExtensionRuntimeService = class {
2189
2394
  return token;
2190
2395
  };
2191
2396
  authenticateEventStreamCredential = (input) => {
2192
- const extensionId = readString$5(input.extensionId);
2193
- const token = readString$5(input.token);
2397
+ const extensionId = readString$4(input.extensionId);
2398
+ const token = readString$4(input.token);
2194
2399
  if (!extensionId || !token || token !== this.extensionTokens.get(extensionId)) return null;
2195
2400
  return { extensionId };
2196
2401
  };
@@ -2209,7 +2414,7 @@ var ExtensionRuntimeService = class {
2209
2414
  const channelBindings = [];
2210
2415
  const uiMetadata = [];
2211
2416
  for (const manifest of manifests) for (const channel of manifest.contributes?.channels ?? []) {
2212
- const channelId = readString$5(channel.id);
2417
+ const channelId = readString$4(channel.id);
2213
2418
  if (!channelId) continue;
2214
2419
  const configUiHints = this.readConfigUiHints(channel.configUiHints);
2215
2420
  channelBindings.push({
@@ -2244,7 +2449,7 @@ var ExtensionRuntimeService = class {
2244
2449
  };
2245
2450
  handleChannelConfigGet = (envelope, context) => {
2246
2451
  this.assertAuthorized(envelope, context);
2247
- const channelId = readRequiredString$4(readRecord$2(envelope.payload).channelId, "channelId");
2452
+ const channelId = readRequiredString$5(readRecord$1(envelope.payload).channelId, "channelId");
2248
2453
  return { config: this.options.getConfig().channels[channelId] ?? {} };
2249
2454
  };
2250
2455
  handleChannelMessageSubmit = async (envelope, context) => {
@@ -2258,11 +2463,11 @@ var ExtensionRuntimeService = class {
2258
2463
  };
2259
2464
  handleChannelCommandExecute = async (envelope, context) => {
2260
2465
  this.assertAuthorized(envelope, context);
2261
- const payload = readRecord$2(envelope.payload);
2262
- const channel = readRequiredString$4(payload.channelId, "channelId");
2263
- const chatId = readRequiredString$4(payload.conversationId, "conversationId");
2264
- const senderId = readRequiredString$4(payload.senderId, "senderId");
2265
- 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);
2266
2471
  const config = this.options.getConfig();
2267
2472
  const registry = new CommandRegistry(config, this.options.sessionManager);
2268
2473
  const route = new AgentRouteResolver(config).resolveInbound({
@@ -2270,15 +2475,15 @@ var ExtensionRuntimeService = class {
2270
2475
  channel,
2271
2476
  chatId,
2272
2477
  senderId,
2273
- content: readString$5(payload.rawText) ?? readString$5(payload.commandName) ?? "",
2478
+ content: readString$4(payload.rawText) ?? readString$4(payload.commandName) ?? "",
2274
2479
  timestamp: /* @__PURE__ */ new Date(),
2275
2480
  attachments: [],
2276
2481
  metadata
2277
2482
  },
2278
- forcedAgentId: readString$5(metadata.target_agent_id),
2279
- sessionKeyOverride: readString$5(metadata.session_key_override)
2483
+ forcedAgentId: readString$4(metadata.target_agent_id),
2484
+ sessionKeyOverride: readString$4(metadata.session_key_override)
2280
2485
  });
2281
- const rawText = readString$5(payload.rawText);
2486
+ const rawText = readString$4(payload.rawText);
2282
2487
  if (rawText) return await registry.executeText(rawText, {
2283
2488
  channel,
2284
2489
  chatId,
@@ -2288,7 +2493,7 @@ var ExtensionRuntimeService = class {
2288
2493
  content: "",
2289
2494
  ephemeral: true
2290
2495
  };
2291
- 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), {
2292
2497
  channel,
2293
2498
  chatId,
2294
2499
  senderId,
@@ -2297,14 +2502,14 @@ var ExtensionRuntimeService = class {
2297
2502
  };
2298
2503
  handleExtensionResponse = (envelope, context) => {
2299
2504
  this.assertAuthorized(envelope, context);
2300
- const payload = readRecord$2(envelope.payload);
2301
- const requestId = readRequiredString$4(payload.requestId, "requestId");
2505
+ const payload = readRecord$1(envelope.payload);
2506
+ const requestId = readRequiredString$5(payload.requestId, "requestId");
2302
2507
  const pending = this.pendingRequests.get(requestId);
2303
2508
  if (!pending) return { accepted: false };
2304
2509
  this.pendingRequests.delete(requestId);
2305
2510
  clearTimeout(pending.timeout);
2306
2511
  if (payload.ok === false) {
2307
- 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";
2308
2513
  pending.reject(new Error(message));
2309
2514
  return { accepted: true };
2310
2515
  }
@@ -2351,7 +2556,7 @@ var ExtensionRuntimeService = class {
2351
2556
  return await result;
2352
2557
  };
2353
2558
  assertAuthorized = (envelope, context) => {
2354
- const extensionId = readString$5(envelope.extensionId);
2559
+ const extensionId = readString$4(envelope.extensionId);
2355
2560
  if (!extensionId || context.token !== this.extensionTokens.get(extensionId)) throw new Error("Unauthorized ingress token");
2356
2561
  };
2357
2562
  };
@@ -2474,11 +2679,11 @@ var ExtensionManager = class {
2474
2679
  //#endregion
2475
2680
  //#region src/utils/model-message-vision.utils.ts
2476
2681
  const IMAGE_OMITTED_TEXT = "[Image omitted: the selected model is not configured for vision input.]";
2477
- function isRecord$11(value) {
2682
+ function isRecord$12(value) {
2478
2683
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2479
2684
  }
2480
2685
  function isImageContentPart(value) {
2481
- if (!isRecord$11(value)) return false;
2686
+ if (!isRecord$12(value)) return false;
2482
2687
  const type = value.type;
2483
2688
  return type === "image_url" || type === "input_image";
2484
2689
  }
@@ -2494,7 +2699,7 @@ function normalizeContentWithoutVision(content) {
2494
2699
  };
2495
2700
  });
2496
2701
  if (!sawImage) return content;
2497
- 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);
2498
2703
  if (textParts.length === parts.length) return textParts.join("\n\n");
2499
2704
  return parts;
2500
2705
  }
@@ -3034,11 +3239,11 @@ function createAgentPeerSessionIdentity(params) {
3034
3239
  }
3035
3240
  function resolveAgentPeerScope(params) {
3036
3241
  const metadata = params.metadata ?? {};
3037
- 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);
3038
3243
  if (explicitScope) return explicitScope;
3039
- 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"}`;
3040
3245
  }
3041
- function readOptionalString$8(value) {
3246
+ function readOptionalString$9(value) {
3042
3247
  if (typeof value !== "string") return;
3043
3248
  return value.trim() || void 0;
3044
3249
  }
@@ -3057,7 +3262,7 @@ function safeNcpSessionFilename(value) {
3057
3262
  function normalizeNcpAgentId(agentId) {
3058
3263
  return agentId?.trim().toLowerCase() || void 0;
3059
3264
  }
3060
- function isRecord$10(value) {
3265
+ function isRecord$11(value) {
3061
3266
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3062
3267
  }
3063
3268
  function toIsoString(value, fallback) {
@@ -3137,7 +3342,7 @@ function createReplayEvent(event) {
3137
3342
  return replayEvent;
3138
3343
  }
3139
3344
  function readLegacyContextCompactionMessageId(message) {
3140
- const checkpoint = isRecord$10(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3345
+ const checkpoint = isRecord$11(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3141
3346
  const checkpointId = typeof checkpoint?.id === "string" ? checkpoint.id : "";
3142
3347
  const coveredCount = checkpoint?.coveredSessionMessageCount;
3143
3348
  const legacyId = `${message?.sessionId}:service:context-compaction:${checkpointId}`;
@@ -3167,11 +3372,11 @@ function rememberReplayMessageId(event, knownMessageIds) {
3167
3372
  if (message?.id) knownMessageIds.add(message.id);
3168
3373
  }
3169
3374
  function readEventSessionId$2(event) {
3170
- 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;
3171
3376
  return typeof sessionId === "string" ? sessionId : "";
3172
3377
  }
3173
3378
  function readReplayPayloadTimestamp(event) {
3174
- 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;
3175
3380
  const timestamp = typeof payload?.timestamp === "string" ? payload.timestamp : "";
3176
3381
  return Number.isFinite(Date.parse(timestamp)) ? new Date(timestamp).toISOString() : null;
3177
3382
  }
@@ -3226,7 +3431,7 @@ function applyLimit(items, limit) {
3226
3431
  if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
3227
3432
  return items.slice(0, Math.trunc(limit));
3228
3433
  }
3229
- function readOptionalString$7(value) {
3434
+ function readOptionalString$8(value) {
3230
3435
  if (typeof value !== "string") return null;
3231
3436
  const trimmed = value.trim();
3232
3437
  return trimmed.length > 0 ? trimmed : null;
@@ -3240,8 +3445,8 @@ function readEventSessionId$1(event) {
3240
3445
  //#endregion
3241
3446
  //#region src/services/session-working-dir-resolver.service.ts
3242
3447
  var SessionWorkingDirResolver = class {
3243
- constructor(configManager) {
3244
- this.configManager = configManager;
3448
+ constructor(agentManager) {
3449
+ this.agentManager = agentManager;
3245
3450
  }
3246
3451
  withWorkingDir = (summary) => ({
3247
3452
  ...summary,
@@ -3251,12 +3456,10 @@ var SessionWorkingDirResolver = class {
3251
3456
  })
3252
3457
  });
3253
3458
  resolve = (params) => {
3254
- const config = this.configManager.loadConfig();
3255
- const defaultAgentId = resolveDefaultAgentProfileId(config);
3256
- const profile = findEffectiveAgentProfile(config, readOptionalString$7(params.agentId) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
3459
+ const profile = this.agentManager.resolveAgentProfile(readOptionalString$8(params.agentId));
3257
3460
  return resolveSessionWorkspacePath({
3258
3461
  sessionMetadata: params.metadata,
3259
- workspace: profile?.workspace ?? config.agents.defaults.workspace
3462
+ workspace: profile.workspace
3260
3463
  });
3261
3464
  };
3262
3465
  };
@@ -3268,6 +3471,7 @@ const SESSION_METADATA_LABEL_KEY = "label";
3268
3471
  const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3269
3472
  const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3270
3473
  const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3474
+ const SESSION_METADATA_PATCH_RUN_METADATA_KIND = "session_metadata_patch";
3271
3475
  function isDurableSessionEvent(event) {
3272
3476
  return event.type !== NcpEventType.ContextWindowUpdated;
3273
3477
  }
@@ -3308,7 +3512,7 @@ function mergeMetadataOverrides(metadata, overrides) {
3308
3512
  }
3309
3513
  function resolveSessionType(params) {
3310
3514
  const { metadata, runtime, sessionType } = params;
3311
- 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;
3312
3516
  }
3313
3517
  function applySessionOverrides(params) {
3314
3518
  const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
@@ -3318,15 +3522,15 @@ function applySessionOverrides(params) {
3318
3522
  metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
3319
3523
  if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
3320
3524
  if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
3321
- if (readOptionalString$7(model)) {
3525
+ if (readOptionalString$8(model)) {
3322
3526
  metadata.model = model?.trim();
3323
3527
  metadata.preferred_model = model?.trim();
3324
3528
  }
3325
- if (readOptionalString$7(thinkingLevel)) {
3529
+ if (readOptionalString$8(thinkingLevel)) {
3326
3530
  metadata.thinking = thinkingLevel?.trim();
3327
3531
  metadata.preferred_thinking = thinkingLevel?.trim();
3328
3532
  }
3329
- if (readOptionalString$7(projectRoot)) metadata.project_root = projectRoot?.trim();
3533
+ if (readOptionalString$8(projectRoot)) metadata.project_root = projectRoot?.trim();
3330
3534
  }
3331
3535
  function isSessionSummaryRefreshEvent(event) {
3332
3536
  switch (event.type) {
@@ -3338,6 +3542,13 @@ function isSessionSummaryRefreshEvent(event) {
3338
3542
  default: return false;
3339
3543
  }
3340
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
+ }
3341
3552
  var SessionManager = class {
3342
3553
  cleanups = [];
3343
3554
  contextWindowPreview;
@@ -3345,8 +3556,8 @@ var SessionManager = class {
3345
3556
  started = false;
3346
3557
  constructor(options) {
3347
3558
  this.options = options;
3348
- this.contextWindowPreview = new ContextWindowPreviewManager({ configManager: options.configManager });
3349
- this.workingDirResolver = new SessionWorkingDirResolver(options.configManager);
3559
+ this.contextWindowPreview = new ContextWindowPreviewManager(options.agentManager);
3560
+ this.workingDirResolver = new SessionWorkingDirResolver(options.agentManager);
3350
3561
  }
3351
3562
  start = () => {
3352
3563
  if (this.started) return;
@@ -3354,6 +3565,11 @@ var SessionManager = class {
3354
3565
  this.cleanups.push(this.options.eventBus.on(eventKeys.ncpEvent, async (event) => {
3355
3566
  const sessionId = readEventSessionId$1(event);
3356
3567
  if (!sessionId || !isDurableSessionEvent(event)) return;
3568
+ const metadataPatch = readRuntimeSessionMetadataPatch(event);
3569
+ if (metadataPatch) {
3570
+ await this.updateSessionMetadata(sessionId, metadataPatch);
3571
+ return;
3572
+ }
3357
3573
  await this.appendSessionEvent({
3358
3574
  event,
3359
3575
  sessionId
@@ -3368,9 +3584,9 @@ var SessionManager = class {
3368
3584
  const { agentId: requestedAgentId, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
3369
3585
  const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
3370
3586
  const metadata = cloneInheritedMetadata(sourceSessionMetadata);
3371
- const title = readOptionalString$7(requestedTitle) ?? summarizeTask(task);
3372
- const parentSessionId = readOptionalString$7(rawParentSessionId);
3373
- 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);
3374
3590
  const sessionType = resolveSessionType({
3375
3591
  runtime,
3376
3592
  sessionType: requestedSessionType,
@@ -3389,8 +3605,8 @@ var SessionManager = class {
3389
3605
  });
3390
3606
  const now = (/* @__PURE__ */ new Date()).toISOString();
3391
3607
  const nextMetadata = mergeMetadataOverrides(metadata, metadataOverrides);
3392
- const agentId = readOptionalString$7(requestedAgentId) ?? readOptionalString$7(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
3393
- 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();
3394
3610
  const record = {
3395
3611
  sessionId,
3396
3612
  ...agentId ? { agentId } : {},
@@ -3463,7 +3679,7 @@ var SessionManager = class {
3463
3679
  return await this.options.journalStore.getSession(normalizedSessionId);
3464
3680
  };
3465
3681
  listSessions = async (options) => {
3466
- const peerId = readOptionalString$7(options?.peerId);
3682
+ const peerId = readOptionalString$8(options?.peerId);
3467
3683
  return applyLimit((await this.options.journalStore.listSessionSummaries()).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), options?.limit);
3468
3684
  };
3469
3685
  listSessionMessages = async (sessionId, options) => {
@@ -3496,14 +3712,14 @@ var SessionManager = class {
3496
3712
  createAgentRunSession = async (params) => {
3497
3713
  const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, metadata, model, peerId: rawPeerId, projectRoot, sessionId, task, thinkingEffort } = params;
3498
3714
  const agentRuntimeId = requestedAgentRuntimeId ?? "native";
3499
- const peerId = readOptionalString$7(rawPeerId);
3715
+ const peerId = readOptionalString$8(rawPeerId);
3500
3716
  const peerIdentity = peerId ? createAgentPeerSessionIdentity({
3501
3717
  agentId,
3502
3718
  channel,
3503
3719
  metadata,
3504
3720
  peerId
3505
3721
  }) : void 0;
3506
- const requestedSessionId = readOptionalString$7(sessionId);
3722
+ const requestedSessionId = readOptionalString$8(sessionId);
3507
3723
  const created = await this.createSession({
3508
3724
  sourceSessionMetadata: {},
3509
3725
  sessionId: requestedSessionId ?? peerIdentity?.sessionId,
@@ -3793,12 +4009,12 @@ var PanelAppCapabilityGrantStore = class {
3793
4009
  };
3794
4010
  };
3795
4011
  function normalizeStoreData$2(value) {
3796
- 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);
3797
4013
  const grants = {};
3798
4014
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
3799
- if (!isRecord$9(callerValue) || !isRecord$9(callerValue.capabilities)) continue;
4015
+ if (!isRecord$10(callerValue) || !isRecord$10(callerValue.capabilities)) continue;
3800
4016
  const capabilities = {};
3801
- 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 };
3802
4018
  grants[callerKey] = { capabilities };
3803
4019
  }
3804
4020
  return {
@@ -3809,7 +4025,7 @@ function normalizeStoreData$2(value) {
3809
4025
  function getCallerKey(caller) {
3810
4026
  return `${caller.surface}:${caller.appId}`;
3811
4027
  }
3812
- function isRecord$9(value) {
4028
+ function isRecord$10(value) {
3813
4029
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3814
4030
  }
3815
4031
  function isMissingFileError$3(error) {
@@ -3855,19 +4071,19 @@ var PanelAppClientGrantStore = class {
3855
4071
  };
3856
4072
  };
3857
4073
  function normalizeStoreData$1(value) {
3858
- 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);
3859
4075
  const grants = {};
3860
- 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 };
3861
4077
  return {
3862
4078
  grants,
3863
4079
  version: 1
3864
4080
  };
3865
4081
  }
3866
- function isRecord$8(value) {
4082
+ function isRecord$9(value) {
3867
4083
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3868
4084
  }
3869
4085
  function isMissingFileError$2(error) {
3870
- return isRecord$8(error) && error.code === "ENOENT";
4086
+ return isRecord$9(error) && error.code === "ENOENT";
3871
4087
  }
3872
4088
  //#endregion
3873
4089
  //#region src/services/agent-run-client.service.ts
@@ -4086,7 +4302,7 @@ const PANEL_APP_AGENT_MAX_CONTEXT_CHARS = 8e4;
4086
4302
  function normalizePanelAppGenerateObjectInput(input) {
4087
4303
  const peerId = input.peerId.trim();
4088
4304
  const prompt = input.prompt.trim();
4089
- 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");
4090
4306
  if (prompt.length > PANEL_APP_AGENT_MAX_PROMPT_CHARS) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "generateObject prompt is too large");
4091
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");
4092
4308
  return {
@@ -4227,7 +4443,7 @@ function readStructuredResultEvent(event, resultToolCallId) {
4227
4443
  };
4228
4444
  }
4229
4445
  function assertToolResultContent(content) {
4230
- 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;
4231
4447
  if (content.error.code === "invalid_tool_arguments") throw new PanelAppError("AGENT_OBJECT_RESULT_SCHEMA_INVALID", "agent object result did not match the schema");
4232
4448
  throw new PanelAppError("AGENT_OBJECT_REQUEST_FAILED", typeof content.error.message === "string" ? content.error.message : "agent object request failed");
4233
4449
  }
@@ -4243,7 +4459,7 @@ function stringifyJsonValue(value) {
4243
4459
  throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "value is not JSON serializable");
4244
4460
  }
4245
4461
  }
4246
- function isRecord$7(value) {
4462
+ function isRecord$8(value) {
4247
4463
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4248
4464
  }
4249
4465
  //#endregion
@@ -4517,15 +4733,15 @@ function parsePanelAppFolderManifest(raw) {
4517
4733
  } catch (error) {
4518
4734
  throw new Error(`panel-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
4519
4735
  }
4520
- if (!isRecord$6(parsed)) throw new Error("panel-app.json must contain an object.");
4521
- 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");
4522
4738
  if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
4523
4739
  return {
4524
4740
  id,
4525
- title: readRequiredString$3(parsed, "title"),
4526
- description: readOptionalString$6(parsed, "description"),
4527
- icon: readOptionalString$6(parsed, "icon"),
4528
- 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"),
4529
4745
  capabilities: readStringArray$1(parsed.capabilities, "capabilities"),
4530
4746
  client: readOptionalBoolean$2(parsed, "client"),
4531
4747
  serviceActions: readStringArray$1(parsed.actions, "actions")
@@ -4585,12 +4801,12 @@ function parseTokenList(content) {
4585
4801
  if (!content) return [];
4586
4802
  return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
4587
4803
  }
4588
- function readRequiredString$3(record, key) {
4589
- const value = readOptionalString$6(record, key);
4804
+ function readRequiredString$4(record, key) {
4805
+ const value = readOptionalString$7(record, key);
4590
4806
  if (!value) throw new Error(`panel app ${key} is required.`);
4591
4807
  return value;
4592
4808
  }
4593
- function readOptionalString$6(record, key) {
4809
+ function readOptionalString$7(record, key) {
4594
4810
  return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
4595
4811
  }
4596
4812
  function readOptionalBoolean$2(record, key) {
@@ -4604,7 +4820,7 @@ function readStringArray$1(value, key) {
4604
4820
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`panel app ${key} must be a string array.`);
4605
4821
  return [...new Set(value.map((entry) => entry.trim()).filter(Boolean))];
4606
4822
  }
4607
- function isRecord$6(value) {
4823
+ function isRecord$7(value) {
4608
4824
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4609
4825
  }
4610
4826
  function normalizeTextValue(value) {
@@ -5322,12 +5538,12 @@ var ServiceActionGrantStore = class {
5322
5538
  };
5323
5539
  };
5324
5540
  function normalizeStoreData(value) {
5325
- 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);
5326
5542
  const grants = {};
5327
5543
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
5328
- if (!isRecord$5(callerValue) || !isRecord$5(callerValue.actions)) continue;
5544
+ if (!isRecord$6(callerValue) || !isRecord$6(callerValue.actions)) continue;
5329
5545
  const actions = {};
5330
- 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] = {
5331
5547
  grantedAt: actionValue.grantedAt,
5332
5548
  risk: actionValue.risk
5333
5549
  };
@@ -5341,11 +5557,11 @@ function normalizeStoreData(value) {
5341
5557
  function isServiceActionRisk(value) {
5342
5558
  return value === "read" || value === "write" || value === "external" || value === "dangerous";
5343
5559
  }
5344
- function isRecord$5(value) {
5560
+ function isRecord$6(value) {
5345
5561
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5346
5562
  }
5347
5563
  function isMissingFileError(error) {
5348
- return isRecord$5(error) && error.code === "ENOENT";
5564
+ return isRecord$6(error) && error.code === "ENOENT";
5349
5565
  }
5350
5566
  //#endregion
5351
5567
  //#region src/utils/service-app-manifest.utils.ts
@@ -5370,49 +5586,49 @@ function parseServiceAppManifest(raw) {
5370
5586
  } catch (error) {
5371
5587
  throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
5372
5588
  }
5373
- if (!isRecord$4(parsed)) throw new Error("service-app.json must contain an object.");
5374
- 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");
5375
5591
  if (!SERVICE_APP_ID_PATTERN.test(id)) throw new Error("service app id must be kebab-case.");
5376
- const protocol = readOptionalString$5(parsed, "protocol") ?? "mcp";
5592
+ const protocol = readOptionalString$6(parsed, "protocol") ?? "mcp";
5377
5593
  if (protocol !== "mcp") throw new Error("service app protocol must be mcp.");
5378
5594
  return {
5379
5595
  id,
5380
- title: readRequiredString$2(parsed, "title"),
5381
- description: readOptionalString$5(parsed, "description"),
5596
+ title: readRequiredString$3(parsed, "title"),
5597
+ description: readOptionalString$6(parsed, "description"),
5382
5598
  enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
5383
5599
  protocol,
5384
- command: readRequiredString$2(parsed, "command"),
5600
+ command: readRequiredString$3(parsed, "command"),
5385
5601
  args: readStringArray(parsed.args, "args"),
5386
5602
  actions: readManifestActions(parsed.actions)
5387
5603
  };
5388
5604
  }
5389
5605
  function readManifestActions(value) {
5390
5606
  if (value === void 0) throw new Error("service app actions are required.");
5391
- 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.");
5392
5608
  if (Object.keys(value).length === 0) throw new Error("service app actions cannot be empty.");
5393
5609
  const actions = {};
5394
5610
  for (const [name, action] of Object.entries(value)) {
5395
5611
  if (!name.trim()) throw new Error("service app action name cannot be empty.");
5396
- if (!isRecord$4(action)) throw new Error(`service app action ${name} must be an object.`);
5397
- 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");
5398
5614
  if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
5399
5615
  const inputSchema = action.inputSchema;
5400
- 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.`);
5401
5617
  actions[name] = {
5402
5618
  risk,
5403
- title: readOptionalString$5(action, "title"),
5404
- description: readOptionalString$5(action, "description"),
5619
+ title: readOptionalString$6(action, "title"),
5620
+ description: readOptionalString$6(action, "description"),
5405
5621
  inputSchema
5406
5622
  };
5407
5623
  }
5408
5624
  return actions;
5409
5625
  }
5410
- function readRequiredString$2(record, key) {
5411
- const value = readOptionalString$5(record, key);
5626
+ function readRequiredString$3(record, key) {
5627
+ const value = readOptionalString$6(record, key);
5412
5628
  if (!value) throw new Error(`service app ${key} is required.`);
5413
5629
  return value;
5414
5630
  }
5415
- function readOptionalString$5(record, key) {
5631
+ function readOptionalString$6(record, key) {
5416
5632
  return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
5417
5633
  }
5418
5634
  function readOptionalBoolean$1(record, key) {
@@ -5425,7 +5641,7 @@ function readStringArray(value, key) {
5425
5641
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`service app ${key} must be a string array.`);
5426
5642
  return value;
5427
5643
  }
5428
- function isRecord$4(value) {
5644
+ function isRecord$5(value) {
5429
5645
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5430
5646
  }
5431
5647
  //#endregion
@@ -5822,12 +6038,12 @@ function parseSkillFrontmatter(raw) {
5822
6038
  const summaryI18n = readLocalizedTextMap(parsed, "summaryi18n", "summary_i18n");
5823
6039
  const descriptionI18n = readLocalizedTextMap(parsed, "descriptioni18n", "description_i18n");
5824
6040
  return {
5825
- name: readString$4(parsed, "name"),
5826
- summary: readString$4(parsed, "summary"),
5827
- summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$4(parsed, "summaryzh", "summary_zh") }),
5828
- description: readString$4(parsed, "description"),
5829
- descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$4(parsed, "descriptionzh", "description_zh") }),
5830
- 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"),
5831
6047
  tags: readTags(parsed)
5832
6048
  };
5833
6049
  }
@@ -5848,19 +6064,19 @@ function parseFrontmatterBlock(raw) {
5848
6064
  function parseYamlFrontmatter(raw) {
5849
6065
  try {
5850
6066
  const parsed = parse(raw);
5851
- return isRecord$3(parsed) ? parsed : {};
6067
+ return isRecord$4(parsed) ? parsed : {};
5852
6068
  } catch (error) {
5853
6069
  const message = error instanceof Error ? error.message : String(error);
5854
6070
  throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
5855
6071
  }
5856
6072
  }
5857
- function readString$4(record, ...names) {
6073
+ function readString$3(record, ...names) {
5858
6074
  const value = readValue(record, names);
5859
6075
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
5860
6076
  }
5861
6077
  function readLocalizedTextMap(record, ...names) {
5862
6078
  const value = readValue(record, names);
5863
- if (!isRecord$3(value)) return;
6079
+ if (!isRecord$4(value)) return;
5864
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()]));
5865
6081
  return Object.keys(localized).length > 0 ? localized : void 0;
5866
6082
  }
@@ -5884,7 +6100,7 @@ function normalizeFrontmatterKey(raw) {
5884
6100
  function normalizeLocaleTag(raw) {
5885
6101
  return raw.trim().toLowerCase();
5886
6102
  }
5887
- function isRecord$3(value) {
6103
+ function isRecord$4(value) {
5888
6104
  return typeof value === "object" && value !== null && !Array.isArray(value);
5889
6105
  }
5890
6106
  //#endregion
@@ -6050,7 +6266,7 @@ var NcpAgentSessionMetadataStore = class {
6050
6266
  read = async (sessionId, activitySnapshot) => {
6051
6267
  try {
6052
6268
  const parsed = JSON.parse(await readFile(this.metadataPath(sessionId), "utf-8"));
6053
- 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}`);
6054
6270
  const createdAt = toIsoString(parsed.created_at, activitySnapshot.createdAt);
6055
6271
  const agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
6056
6272
  return {
@@ -6151,11 +6367,11 @@ var NcpAgentSessionSummaryIndexStore = class {
6151
6367
  function serializeJournalEntry(entry) {
6152
6368
  const serialized = JSON.stringify(entry);
6153
6369
  if (!serialized) throw new Error("ncp agent session journal entry serialization produced empty output");
6154
- 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");
6155
6371
  return serialized;
6156
6372
  }
6157
6373
  function attachJournalTimestamp(event, timestamp) {
6158
- if (!("payload" in event) || !isRecord$10(event.payload)) return event;
6374
+ if (!("payload" in event) || !isRecord$11(event.payload)) return event;
6159
6375
  return {
6160
6376
  ...event,
6161
6377
  payload: {
@@ -6379,15 +6595,15 @@ var NcpAgentSessionJournalStore = class {
6379
6595
  console.warn(`[ncp-agent-session-journal] skipped corrupted journal line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
6380
6596
  continue;
6381
6597
  }
6382
- if (!isRecord$10(parsed)) continue;
6598
+ if (!isRecord$11(parsed)) continue;
6383
6599
  if (parsed._type === "metadata") {
6384
- metadata = isRecord$10(parsed.metadata) ? structuredClone(parsed.metadata) : {};
6600
+ metadata = isRecord$11(parsed.metadata) ? structuredClone(parsed.metadata) : {};
6385
6601
  agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
6386
6602
  createdAt = toIsoString(parsed.created_at, createdAt);
6387
6603
  updatedAt = toIsoString(parsed.updated_at, updatedAt);
6388
6604
  continue;
6389
6605
  }
6390
- if (parsed._type === "event" && isRecord$10(parsed.event)) {
6606
+ if (parsed._type === "event" && isRecord$11(parsed.event)) {
6391
6607
  const seq = Number(parsed.seq);
6392
6608
  nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
6393
6609
  const eventTimestamp = toIsoString(parsed.timestamp, updatedAt);
@@ -6701,11 +6917,11 @@ const NARP_API_MODE_HEADER = "x-nextclaw-narp-api-mode";
6701
6917
  const NARP_HTTP_RUNTIME_KIND = "narp-http";
6702
6918
  const NARP_STDIO_RUNTIME_KIND = "narp-stdio";
6703
6919
  const BUILTIN_PROVIDER_REGISTRY = new ProviderRegistry(BUILTIN_PROVIDER_PLUGINS);
6704
- function readRecord$1(value) {
6920
+ function readRecord(value) {
6705
6921
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
6706
6922
  return value;
6707
6923
  }
6708
- function readString$3(value) {
6924
+ function readString$2(value) {
6709
6925
  if (typeof value !== "string") return;
6710
6926
  return value.trim() || void 0;
6711
6927
  }
@@ -6713,9 +6929,11 @@ function resolveEntryIcon(entry) {
6713
6929
  return entry.icon ?? null;
6714
6930
  }
6715
6931
  function resolveRequestedModel(params) {
6716
- const { configuredModel, defaultModel, input, sessionMetadata } = params;
6717
- const runMetadata = readRecord$1(input.metadata);
6718
- 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);
6719
6937
  }
6720
6938
  function resolveProviderApiMode(resolution) {
6721
6939
  const wireApi = resolution.provider?.wireApi?.trim().toLowerCase();
@@ -6762,12 +6980,14 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6762
6980
  };
6763
6981
  describeInternal = async () => {
6764
6982
  const config = new HttpRuntimeConfigResolver(this.entry.config ?? {}).resolve({ defaultModel: this.defaultModel });
6983
+ const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
6765
6984
  if (!config.baseUrl) return {
6766
6985
  icon: resolveEntryIcon(this.entry),
6767
6986
  ready: false,
6768
6987
  reason: "base_url_missing",
6769
6988
  reasonMessage: "Configure the runtime entry baseUrl before starting an HTTP runtime session.",
6770
6989
  recommendedModel: config.recommendedModel ?? null,
6990
+ modelSelectionMode,
6771
6991
  cta: {
6772
6992
  kind: "settings",
6773
6993
  label: "Configure HTTP Runtime"
@@ -6779,6 +6999,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6779
6999
  reason: null,
6780
7000
  reasonMessage: null,
6781
7001
  recommendedModel: config.recommendedModel ?? null,
7002
+ modelSelectionMode,
6782
7003
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
6783
7004
  cta: null
6784
7005
  };
@@ -6797,6 +7018,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6797
7018
  reason: "healthcheck_failed",
6798
7019
  reasonMessage: `HTTP runtime healthcheck returned HTTP ${response.status}.`,
6799
7020
  recommendedModel: config.recommendedModel ?? null,
7021
+ modelSelectionMode,
6800
7022
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
6801
7023
  cta: null
6802
7024
  };
@@ -6806,6 +7028,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6806
7028
  reason: null,
6807
7029
  reasonMessage: null,
6808
7030
  recommendedModel: config.recommendedModel ?? null,
7031
+ modelSelectionMode,
6809
7032
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
6810
7033
  cta: null
6811
7034
  };
@@ -6843,6 +7066,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6843
7066
  };
6844
7067
  describeInternal = async (describeMode) => {
6845
7068
  const resolver = new StdioRuntimeConfigResolver(this.entry.config ?? {});
7069
+ const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
6846
7070
  try {
6847
7071
  const config = resolver.resolve();
6848
7072
  if (!await resolveExecutablePath(config.command)) return {
@@ -6853,7 +7077,8 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6853
7077
  cta: {
6854
7078
  kind: "settings",
6855
7079
  label: "Configure Stdio Runtime"
6856
- }
7080
+ },
7081
+ modelSelectionMode
6857
7082
  };
6858
7083
  if (describeMode === "probe") try {
6859
7084
  await probeStdioRuntime(config);
@@ -6866,7 +7091,8 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6866
7091
  cta: {
6867
7092
  kind: "settings",
6868
7093
  label: "Repair Stdio Runtime"
6869
- }
7094
+ },
7095
+ modelSelectionMode
6870
7096
  };
6871
7097
  }
6872
7098
  return {
@@ -6874,6 +7100,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6874
7100
  ready: true,
6875
7101
  reason: null,
6876
7102
  reasonMessage: null,
7103
+ modelSelectionMode,
6877
7104
  cta: null
6878
7105
  };
6879
7106
  } catch (error) {
@@ -6885,7 +7112,8 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6885
7112
  cta: {
6886
7113
  kind: "settings",
6887
7114
  label: "Configure Stdio Runtime"
6888
- }
7115
+ },
7116
+ modelSelectionMode
6889
7117
  };
6890
7118
  }
6891
7119
  };
@@ -6932,7 +7160,7 @@ var BuiltinNarpRuntimeProviderService = class {
6932
7160
  throw new Error("[narp] runtime entry is required before creating this runtime");
6933
7161
  };
6934
7162
  createHttpRuntime = (entry, runtimeParams) => {
6935
- const config = readRecord$1(entry.config) ?? {};
7163
+ const config = readRecord(entry.config) ?? {};
6936
7164
  const resolver = new HttpRuntimeConfigResolver(config);
6937
7165
  const resolvedConfig = resolver.resolve({ defaultModel: this.configManager.loadConfig().agents.defaults.model });
6938
7166
  return new HttpRuntimeNcpAgentRuntime({
@@ -6947,12 +7175,13 @@ var BuiltinNarpRuntimeProviderService = class {
6947
7175
  input,
6948
7176
  sessionMetadata: runtimeParams.sessionMetadata,
6949
7177
  defaultModel: this.configManager.loadConfig().agents.defaults.model,
6950
- configuredModel: readString$3(config.model)
7178
+ configuredModel: readString$2(config.model),
7179
+ modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
6951
7180
  })
6952
7181
  });
6953
7182
  };
6954
7183
  createStdioRuntime = (entry, runtimeParams) => {
6955
- const config = readRecord$1(entry.config) ?? {};
7184
+ const config = readRecord(entry.config) ?? {};
6956
7185
  return new StdioRuntimeNcpAgentRuntime({
6957
7186
  ...new StdioRuntimeConfigResolver(config).resolve(),
6958
7187
  sessionId: runtimeParams.sessionId,
@@ -6963,7 +7192,8 @@ var BuiltinNarpRuntimeProviderService = class {
6963
7192
  input,
6964
7193
  sessionMetadata: runtimeParams.sessionMetadata,
6965
7194
  defaultModel: this.configManager.loadConfig().agents.defaults.model,
6966
- configuredModel: readString$3(config.model)
7195
+ configuredModel: readString$2(config.model),
7196
+ modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
6967
7197
  })
6968
7198
  });
6969
7199
  };
@@ -7050,13 +7280,13 @@ var ProviderManagerNcpLLMApi = class {
7050
7280
  };
7051
7281
  //#endregion
7052
7282
  //#region src/features/native-runtime/tools/ncp-asset.tools.ts
7053
- function readOptionalString$4(value) {
7283
+ function readOptionalString$5(value) {
7054
7284
  if (typeof value !== "string") return null;
7055
7285
  const trimmed = value.trim();
7056
7286
  return trimmed.length > 0 ? trimmed : null;
7057
7287
  }
7058
7288
  function readOptionalBase64Bytes(value) {
7059
- const base64 = readOptionalString$4(value);
7289
+ const base64 = readOptionalString$5(value);
7060
7290
  if (!base64) return null;
7061
7291
  try {
7062
7292
  return Buffer.from(base64, "base64");
@@ -7107,18 +7337,18 @@ var AssetPutTool = class {
7107
7337
  this.contentBasePath = contentBasePath;
7108
7338
  }
7109
7339
  validateArgs = (args) => {
7110
- const path = readOptionalString$4(args.path);
7111
- const bytesBase64 = readOptionalString$4(args.bytesBase64);
7112
- 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);
7113
7343
  if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
7114
7344
  if (path) return [];
7115
7345
  if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
7116
7346
  return ["Provide either path, or bytesBase64 + fileName."];
7117
7347
  };
7118
7348
  execute = async (args) => {
7119
- const path = readOptionalString$4(args?.path);
7120
- const fileName = readOptionalString$4(args?.fileName);
7121
- 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);
7122
7352
  const bytes = readOptionalBase64Bytes(args?.bytesBase64);
7123
7353
  if (path) return {
7124
7354
  ok: true,
@@ -7161,8 +7391,8 @@ var AssetExportTool = class {
7161
7391
  this.assetStore = assetStore;
7162
7392
  }
7163
7393
  execute = async (args) => {
7164
- const assetUri = readOptionalString$4(args?.assetUri);
7165
- const targetPath = readOptionalString$4(args?.targetPath);
7394
+ const assetUri = readOptionalString$5(args?.assetUri);
7395
+ const targetPath = readOptionalString$5(args?.targetPath);
7166
7396
  if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
7167
7397
  return {
7168
7398
  ok: true,
@@ -7188,7 +7418,7 @@ var AssetStatTool = class {
7188
7418
  this.contentBasePath = contentBasePath;
7189
7419
  }
7190
7420
  execute = async (args) => {
7191
- const assetUri = readOptionalString$4(args?.assetUri);
7421
+ const assetUri = readOptionalString$5(args?.assetUri);
7192
7422
  if (!assetUri) throw new Error("asset_stat requires assetUri.");
7193
7423
  const record = await this.assetStore.statRecord(assetUri);
7194
7424
  if (!record) return {
@@ -7256,10 +7486,16 @@ function resolveEffectiveModel(params) {
7256
7486
  const metadata = structuredClone(params.sessionMetadata);
7257
7487
  if (requestMetadata.clear_model === true || requestMetadata.reset_model === true) delete metadata.preferred_model;
7258
7488
  const inboundModel = readMetadataModel(requestMetadata);
7259
- 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
+ }
7260
7496
  return {
7261
7497
  metadata,
7262
- model: normalizeOptionalString(metadata.preferred_model) ?? fallbackModel
7498
+ model: (isRuntimeDefaultModelValue(metadata.preferred_model) ? void 0 : normalizeOptionalString(metadata.preferred_model)) ?? fallbackModel
7263
7499
  };
7264
7500
  }
7265
7501
  function syncSessionThinkingPreference(params) {
@@ -7290,30 +7526,6 @@ function resolveSessionChannelContext(params) {
7290
7526
  //#endregion
7291
7527
  //#region src/features/native-runtime/utils/nextclaw-ncp-run-context.utils.ts
7292
7528
  const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
7293
- function readRequestedAgentId(metadata) {
7294
- return normalizeOptionalString(metadata.agent_id)?.toLowerCase() ?? normalizeOptionalString(metadata.agentId)?.toLowerCase() ?? null;
7295
- }
7296
- function resolveAgentProfile(params) {
7297
- const { config, requestMetadata, storedAgentId } = params;
7298
- const { agents: { defaults }, search: searchConfig, tools: { restrictToWorkspace, exec: { timeout: execTimeoutSeconds } } } = config;
7299
- const defaultAgentId = resolveDefaultAgentProfileId(config);
7300
- const profile = findEffectiveAgentProfile(config, normalizeOptionalString(storedAgentId)?.toLowerCase() ?? readRequestedAgentId(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
7301
- if (!profile) throw new Error(`default agent profile not found: ${defaultAgentId}`);
7302
- const contextTokens = profile.contextTokens ?? defaults.contextTokens;
7303
- return {
7304
- agentId: profile.id,
7305
- workspace: getWorkspacePath(profile.workspace ?? defaults.workspace),
7306
- model: profile.model ?? defaults.model,
7307
- contextTokens,
7308
- reservedContextTokens: ContextWindowBudgetService.resolveReservedContextTokens({
7309
- contextTokens,
7310
- configuredReservedContextTokens: profile.reservedContextTokens ?? defaults.reservedContextTokens
7311
- }),
7312
- restrictToWorkspace,
7313
- searchConfig,
7314
- execTimeoutSeconds
7315
- };
7316
- }
7317
7529
  function resolveRequestedToolNames(metadata) {
7318
7530
  const rawValue = metadata.requested_tools ?? metadata.requestedTools;
7319
7531
  if (!Array.isArray(rawValue)) return [];
@@ -7326,17 +7538,15 @@ function mergeRunMetadata(params) {
7326
7538
  ...requestMetadata ? structuredClone(requestMetadata) : {}
7327
7539
  };
7328
7540
  }
7329
- function resolveNextclawNcpRunContext(params) {
7330
- const { configManager, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata, storedAgentId } = params;
7331
- const config = configManager.loadConfig();
7541
+ function buildNextclawNcpRunContext(params) {
7542
+ const { agentProfile, config, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata } = params;
7332
7543
  const requestMetadata = mergeRunMetadata({
7333
7544
  sessionMetadata: inputSessionMetadata,
7334
7545
  requestMetadata: inputRequestMetadata
7335
7546
  });
7336
- const profile = resolveAgentProfile({
7547
+ const profile = buildResolvedAgentProfile({
7337
7548
  config,
7338
- storedAgentId,
7339
- requestMetadata
7549
+ profile: agentProfile
7340
7550
  });
7341
7551
  const { metadata: modelMetadata, model: effectiveModel } = resolveEffectiveModel({
7342
7552
  sessionMetadata: requestMetadata,
@@ -7387,213 +7597,20 @@ function resolveNextclawNcpRunContext(params) {
7387
7597
  }
7388
7598
  };
7389
7599
  }
7390
- //#endregion
7391
- //#region src/features/runtime-registry/services/agent-runtime-registry.service.ts
7392
- function normalizeIdentifier(value) {
7393
- if (typeof value !== "string") return null;
7394
- const normalized = value.trim().toLowerCase();
7395
- return normalized.length > 0 ? normalized : null;
7396
- }
7397
- function cloneRuntimeEntry(entry) {
7600
+ function buildResolvedAgentProfile(params) {
7601
+ const { config, profile } = params;
7602
+ const { search: searchConfig, tools: { restrictToWorkspace, exec: { timeout: execTimeoutSeconds } } } = config;
7398
7603
  return {
7399
- id: entry.id,
7400
- label: entry.label,
7401
- ...entry.icon ? { icon: { ...entry.icon } } : {},
7402
- type: entry.type,
7403
- enabled: entry.enabled !== false,
7404
- config: entry.config ? { ...entry.config } : {}
7405
- };
7406
- }
7407
- function normalizeAgentRuntimeSessionTypeIcon(value) {
7408
- if (typeof value === "string") {
7409
- const src = value.trim();
7410
- return src ? {
7411
- kind: "image",
7412
- src
7413
- } : null;
7414
- }
7415
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
7416
- const iconRecord = value;
7417
- const src = typeof iconRecord.src === "string" ? iconRecord.src.trim() : "";
7418
- if (!src) return null;
7419
- const alt = typeof iconRecord.alt === "string" && iconRecord.alt.trim().length > 0 ? iconRecord.alt.trim() : null;
7420
- return {
7421
- kind: "image",
7422
- src,
7423
- ...alt ? { alt } : {}
7424
- };
7425
- }
7426
- const BUILTIN_RUNTIME_PRESENTATION = { hermes: {
7427
- label: "Hermes",
7428
- icon: {
7429
- kind: "image",
7430
- src: "app://runtime-icons/hermes-agent.png",
7431
- alt: "Hermes"
7432
- }
7433
- } };
7434
- function readString$2(value) {
7435
- if (typeof value !== "string") return;
7436
- return value.trim() || void 0;
7437
- }
7438
- function readRecord(value) {
7439
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
7440
- return value;
7441
- }
7442
- function resolveBuiltinRuntimePresentation(value) {
7443
- const normalized = readString$2(value)?.toLowerCase();
7444
- if (!normalized) return null;
7445
- if (!(normalized in BUILTIN_RUNTIME_PRESENTATION)) return null;
7446
- return BUILTIN_RUNTIME_PRESENTATION[normalized] ?? null;
7447
- }
7448
- function buildNativeRuntimeEntry(config) {
7449
- const nativeRuntimeConfig = readRecord(config.ui?.ncp?.runtimes?.native) ?? {};
7450
- return {
7451
- id: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7452
- label: "Native",
7453
- type: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7454
- enabled: nativeRuntimeConfig.enabled !== false,
7455
- config: nativeRuntimeConfig
7456
- };
7457
- }
7458
- function resolveAgentRuntimeEntries(params) {
7459
- const entries = /* @__PURE__ */ new Map();
7460
- entries.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, buildNativeRuntimeEntry(params.config));
7461
- for (const [rawId, rawEntry] of Object.entries(params.config.agents.runtimes.entries ?? {})) {
7462
- const id = rawId.trim().toLowerCase();
7463
- const type = readString$2(rawEntry.type)?.toLowerCase();
7464
- if (!id || !type) continue;
7465
- const explicitIcon = normalizeAgentRuntimeSessionTypeIcon(rawEntry.icon);
7466
- const builtinPresentation = resolveBuiltinRuntimePresentation(id) ?? resolveBuiltinRuntimePresentation(type);
7467
- entries.set(id, {
7468
- id,
7469
- label: readString$2(rawEntry.label) ?? builtinPresentation?.label ?? id,
7470
- ...explicitIcon ?? builtinPresentation?.icon ? { icon: explicitIcon ?? builtinPresentation?.icon } : {},
7471
- type,
7472
- enabled: rawEntry.enabled !== false,
7473
- config: rawEntry.config ? { ...rawEntry.config } : {}
7474
- });
7475
- }
7476
- return {
7477
- defaultEntryId: entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : [...entries.keys()][0] ?? "native",
7478
- entries: [...entries.values()]
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
7479
7612
  };
7480
7613
  }
7481
- function readRequestedRuntimeEntryId(sessionMetadata) {
7482
- return normalizeIdentifier(sessionMetadata.runtime) ?? normalizeIdentifier(sessionMetadata.session_type) ?? normalizeIdentifier(sessionMetadata.sessionType) ?? null;
7483
- }
7484
- var AgentRuntimeRegistry = class {
7485
- providers = /* @__PURE__ */ new Map();
7486
- entries = /* @__PURE__ */ new Map();
7487
- defaultEntryId = DEFAULT_AGENT_RUNTIME_ENTRY_ID;
7488
- register = (registration) => {
7489
- const normalizedKind = normalizeIdentifier(registration.kind);
7490
- if (!normalizedKind) throw new Error("agent runtime kind must be a non-empty string");
7491
- const token = Symbol(normalizedKind);
7492
- this.providers.set(normalizedKind, {
7493
- ...registration,
7494
- kind: normalizedKind,
7495
- token
7496
- });
7497
- return toDisposable(() => {
7498
- const current = this.providers.get(normalizedKind);
7499
- if (!current || current.token !== token) return;
7500
- this.providers.delete(normalizedKind);
7501
- });
7502
- };
7503
- applyEntries = (params) => {
7504
- const nextEntries = /* @__PURE__ */ new Map();
7505
- for (const rawEntry of params.entries) {
7506
- const id = normalizeIdentifier(rawEntry.id);
7507
- const type = normalizeIdentifier(rawEntry.type);
7508
- const label = rawEntry.label?.trim() ?? "";
7509
- if (!id || !type || !label) continue;
7510
- nextEntries.set(id, cloneRuntimeEntry({
7511
- ...rawEntry,
7512
- id,
7513
- type,
7514
- label
7515
- }));
7516
- }
7517
- this.entries = nextEntries;
7518
- this.defaultEntryId = normalizeIdentifier(params.defaultEntryId) ?? (nextEntries.has("native") ? "native" : [...nextEntries.keys()][0] ?? "native");
7519
- };
7520
- resolveSessionMetadata = (sessionMetadata) => {
7521
- const { entry } = this.resolveRuntimeEntry(sessionMetadata);
7522
- return {
7523
- ...sessionMetadata,
7524
- runtime: entry.id,
7525
- session_type: entry.id,
7526
- runtime_type: entry.type
7527
- };
7528
- };
7529
- createRuntime = (params) => {
7530
- const nextSessionMetadata = this.resolveSessionMetadata(params.sessionMetadata);
7531
- const { entry, provider } = this.resolveRuntimeEntry(nextSessionMetadata);
7532
- if (provider.createRuntimeForEntry) return provider.createRuntimeForEntry({
7533
- entry: cloneRuntimeEntry(entry),
7534
- runtimeParams: {
7535
- ...params,
7536
- sessionMetadata: nextSessionMetadata
7537
- }
7538
- });
7539
- return provider.createRuntime({
7540
- ...params,
7541
- sessionMetadata: nextSessionMetadata
7542
- });
7543
- };
7544
- resolveRuntimeEntry = (sessionMetadata) => {
7545
- const requestedEntryId = readRequestedRuntimeEntryId(sessionMetadata) ?? this.defaultEntryId;
7546
- const entry = this.entries.get(requestedEntryId);
7547
- if (!entry || entry.enabled === false) throw new Error(`ncp runtime unavailable: ${requestedEntryId}`);
7548
- const provider = this.providers.get(entry.type);
7549
- if (!provider) throw new Error(`ncp runtime provider unavailable: ${entry.type}`);
7550
- return {
7551
- entry,
7552
- provider
7553
- };
7554
- };
7555
- listSessionTypes = async (params) => {
7556
- const options = await Promise.all([...this.entries.values()].filter((entry) => entry.enabled !== false).map(async (entry) => {
7557
- const provider = this.providers.get(entry.type);
7558
- if (!provider) return {
7559
- value: entry.id,
7560
- label: entry.label,
7561
- icon: entry.icon ?? null,
7562
- ready: false,
7563
- reason: "runtime_provider_unavailable",
7564
- reasonMessage: `Runtime provider unavailable for type "${entry.type}".`,
7565
- recommendedModel: null,
7566
- cta: {
7567
- kind: "settings",
7568
- label: "Configure Runtime"
7569
- }
7570
- };
7571
- const descriptor = provider.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
7572
- entry: cloneRuntimeEntry(entry),
7573
- describeParams: params
7574
- }) : await provider.describeSessionType?.(params);
7575
- return {
7576
- value: entry.id,
7577
- label: entry.label,
7578
- icon: descriptor?.icon ?? entry.icon ?? null,
7579
- ready: descriptor?.ready ?? true,
7580
- reason: descriptor?.reason ?? null,
7581
- reasonMessage: descriptor?.reasonMessage ?? null,
7582
- recommendedModel: descriptor?.recommendedModel ?? null,
7583
- cta: descriptor?.cta ?? null,
7584
- ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
7585
- };
7586
- }));
7587
- return {
7588
- defaultType: this.defaultEntryId,
7589
- options: options.sort((left, right) => {
7590
- if (left.value === this.defaultEntryId) return -1;
7591
- if (right.value === this.defaultEntryId) return 1;
7592
- return left.value.localeCompare(right.value);
7593
- })
7594
- };
7595
- };
7596
- };
7597
7614
  //#endregion
7598
7615
  //#region src/services/agent-run-message-projector.service.ts
7599
7616
  var AgentRunMessageProjector = class {
@@ -7606,22 +7623,15 @@ var AgentRunMessageProjector = class {
7606
7623
  //#region src/services/agent-run-model-input-budgeter.service.ts
7607
7624
  var AgentRunModelInputBudgeter = class {
7608
7625
  inputBudgetPruner = new InputBudgetPruner();
7609
- constructor(configManager) {
7610
- this.configManager = configManager;
7626
+ constructor(agentManager) {
7627
+ this.agentManager = agentManager;
7611
7628
  }
7612
7629
  prune = async (params) => {
7613
- const config = this.configManager.loadConfig();
7614
- const defaultAgentId = resolveDefaultAgentProfileId(config);
7615
- const profile = findEffectiveAgentProfile(config, params.spec.agentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
7616
- const contextTokens = profile?.contextTokens ?? config.agents.defaults.contextTokens;
7617
- const reservedContextTokens = ContextWindowBudgetService.resolveReservedContextTokens({
7618
- contextTokens,
7619
- configuredReservedContextTokens: profile?.reservedContextTokens ?? config.agents.defaults.reservedContextTokens
7620
- });
7630
+ const profile = this.agentManager.resolveAgentProfile(params.spec.agentId);
7621
7631
  const pruned = this.inputBudgetPruner.prune({
7622
7632
  messages: params.messages.map((message) => ({ ...message })),
7623
- contextTokens,
7624
- reserveTokensFloor: reservedContextTokens,
7633
+ contextTokens: profile.contextTokens,
7634
+ reserveTokensFloor: profile.reservedContextTokens,
7625
7635
  softThresholdTokens: 0
7626
7636
  });
7627
7637
  return {
@@ -7736,18 +7746,22 @@ var AgentRunRuntimeContribution = class {
7736
7746
  modelInputBuilder;
7737
7747
  constructor(kernel) {
7738
7748
  this.kernel = kernel;
7739
- 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);
7740
7750
  }
7741
7751
  start = () => {
7742
7752
  if (this.cleanups.length > 0) return;
7743
- const { entries } = resolveAgentRuntimeEntries({ config: this.kernel.configManager.loadConfig() });
7744
- this.kernel.agentRuntimeManager.applyEntries(entries);
7753
+ this.applyRuntimeConfig(this.kernel.configManager.loadConfig());
7754
+ this.kernel.configManager.installRuntimeHooks({ applyAgentRuntimeConfig: this.applyRuntimeConfig });
7745
7755
  this.cleanups.push(this.registerNativeRuntime());
7746
7756
  for (const provider of new BuiltinNarpRuntimeProviderService(this.kernel.configManager).createProviders()) this.cleanups.push(this.registerNarpRuntime(provider));
7747
7757
  };
7748
7758
  dispose = async () => {
7749
7759
  while (this.cleanups.length > 0) await this.cleanups.pop()?.();
7750
7760
  };
7761
+ applyRuntimeConfig = (config) => {
7762
+ const { entries } = resolveAgentRuntimeEntries({ config });
7763
+ this.kernel.agentRuntimeManager.applyEntries(entries);
7764
+ };
7751
7765
  registerNativeRuntime = () => this.kernel.agentRuntimeManager.register({
7752
7766
  kind: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7753
7767
  label: "Native",
@@ -8316,12 +8330,15 @@ var ContextProviderRunContextService = class {
8316
8330
  request,
8317
8331
  session
8318
8332
  });
8319
- const runContext = resolveNextclawNcpRunContext({
8320
- 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(),
8321
8339
  sessionId,
8322
8340
  requestMetadata,
8323
- sessionMetadata: session?.metadata ?? requestMetadata,
8324
- storedAgentId: request.agentId ?? session?.agentId
8341
+ sessionMetadata: session?.metadata ?? requestMetadata
8325
8342
  });
8326
8343
  const tools = await this.kernel.toolProviderManager.buildTools(request);
8327
8344
  const sessionProjectRoot = readSessionProjectRoot(runContext.sessionMetadata);
@@ -8395,7 +8412,7 @@ var ContextWindowContribution = class {
8395
8412
  unsubscribeNcpEvent = null;
8396
8413
  constructor(kernel) {
8397
8414
  this.kernel = kernel;
8398
- this.contextWindowPreview = new ContextCompactionPreflightService({ configManager: kernel.configManager });
8415
+ this.contextWindowPreview = new ContextCompactionPreflightService(kernel.agents);
8399
8416
  }
8400
8417
  start = () => {
8401
8418
  if (this.unsubscribeNcpEvent) return;
@@ -8732,24 +8749,24 @@ const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
8732
8749
  "failed",
8733
8750
  "idle"
8734
8751
  ]);
8735
- function isRecord$2(value) {
8752
+ function isRecord$3(value) {
8736
8753
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8737
8754
  }
8738
- function readOptionalString$3(value) {
8755
+ function readOptionalString$4(value) {
8739
8756
  if (typeof value !== "string") return;
8740
8757
  const trimmed = value.trim();
8741
8758
  return trimmed.length > 0 ? trimmed : void 0;
8742
8759
  }
8743
8760
  function readSessionActivityPreviewMetadata(value) {
8744
- if (!isRecord$2(value)) return null;
8761
+ if (!isRecord$3(value)) return null;
8745
8762
  const state = value.state;
8746
- const timestamp = readOptionalString$3(value.timestamp);
8763
+ const timestamp = readOptionalString$4(value.timestamp);
8747
8764
  if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
8748
8765
  return {
8749
8766
  state,
8750
8767
  timestamp,
8751
- ...readOptionalString$3(value.statusText) ? { statusText: readOptionalString$3(value.statusText) } : {},
8752
- ...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) } : {}
8753
8770
  };
8754
8771
  }
8755
8772
  function compareIsoTimestamp(left, right) {
@@ -8845,47 +8862,20 @@ var SessionActivityPreviewContribution = class {
8845
8862
  //#endregion
8846
8863
  //#region src/contributions/tool-provider/providers/asset-tool.provider.ts
8847
8864
  var AssetToolProvider = class {
8848
- constructor(kernel) {
8849
- this.kernel = kernel;
8865
+ constructor(assetStore) {
8866
+ this.assetStore = assetStore;
8850
8867
  }
8851
- provide = async (_request) => createAssetTools({ assetStore: this.kernel.assetStore });
8868
+ provide = async (_request) => createAssetTools({ assetStore: this.assetStore });
8852
8869
  };
8853
8870
  //#endregion
8854
- //#region src/contributions/tool-provider/utils/tool-provider-run-context.utils.ts
8855
- async function resolveToolProviderRunContext(params) {
8856
- const { kernel, request } = params;
8857
- const session = request.sessionId ? await kernel.sessionManager.getAgentRunSession(request.sessionId) : null;
8858
- const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
8859
- const requestMetadata = buildAgentRunRequestMetadata({
8860
- request,
8861
- session
8862
- });
8863
- const runContext = resolveNextclawNcpRunContext({
8864
- configManager: kernel.configManager,
8865
- sessionId,
8866
- requestMetadata,
8867
- sessionMetadata: session?.metadata ?? requestMetadata,
8868
- storedAgentId: request.agentId ?? session?.agentId
8869
- });
8870
- return {
8871
- requestMetadata,
8872
- runContext,
8873
- session,
8874
- sessionId,
8875
- toolRunContext: runContext.toolRunContext
8876
- };
8877
- }
8878
- //#endregion
8879
8871
  //#region src/contributions/tool-provider/providers/core-tool.provider.ts
8880
8872
  var CoreToolProvider = class {
8881
- constructor(kernel) {
8882
- this.kernel = kernel;
8873
+ constructor(runContextService, getGatewayController) {
8874
+ this.runContextService = runContextService;
8875
+ this.getGatewayController = getGatewayController;
8883
8876
  }
8884
8877
  provide = async (request) => {
8885
- const { toolRunContext } = await resolveToolProviderRunContext({
8886
- kernel: this.kernel,
8887
- request
8888
- });
8878
+ const { toolRunContext } = await this.runContextService.resolve(request);
8889
8879
  const { channel, chatId, execTimeoutSeconds, restrictToWorkspace, searchConfig, sessionId, workspace } = toolRunContext;
8890
8880
  const allowedDir = restrictToWorkspace ? workspace : void 0;
8891
8881
  const execTool = new ExecTool({
@@ -8898,7 +8888,7 @@ var CoreToolProvider = class {
8898
8888
  chatId,
8899
8889
  sessionKey: sessionId
8900
8890
  });
8901
- const gatewayTool = new GatewayTool(this.kernel.getGatewayController());
8891
+ const gatewayTool = new GatewayTool(this.getGatewayController());
8902
8892
  gatewayTool.setContext({ sessionKey: sessionId });
8903
8893
  return [
8904
8894
  new ReadFileTool(allowedDir),
@@ -8917,15 +8907,13 @@ var CoreToolProvider = class {
8917
8907
  //#endregion
8918
8908
  //#region src/contributions/tool-provider/providers/mcp-tool.provider.ts
8919
8909
  var McpToolProvider = class {
8920
- constructor(kernel) {
8921
- this.kernel = kernel;
8910
+ constructor(runContextService, mcpManager) {
8911
+ this.runContextService = runContextService;
8912
+ this.mcpManager = mcpManager;
8922
8913
  }
8923
8914
  provide = async (request) => {
8924
- const { toolRunContext } = await resolveToolProviderRunContext({
8925
- kernel: this.kernel,
8926
- request
8927
- });
8928
- return this.kernel.mcpManager.listToolsForRun({ agentId: toolRunContext.agentId });
8915
+ const { toolRunContext } = await this.runContextService.resolve(request);
8916
+ return this.mcpManager.listToolsForRun({ agentId: toolRunContext.agentId });
8929
8917
  };
8930
8918
  };
8931
8919
  //#endregion
@@ -8938,24 +8926,24 @@ function readMetadataAccountId(metadata) {
8938
8926
  }
8939
8927
  }
8940
8928
  var MessagingToolProvider = class {
8941
- constructor(kernel) {
8942
- 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;
8943
8934
  }
8944
8935
  provide = async (request) => {
8945
- const { toolRunContext } = await resolveToolProviderRunContext({
8946
- kernel: this.kernel,
8947
- request
8948
- });
8936
+ const { toolRunContext } = await this.runContextService.resolve(request);
8949
8937
  const { channel, chatId, metadata } = toolRunContext;
8950
8938
  const accountId = readMetadataAccountId(metadata);
8951
8939
  const messageTool = new MessageTool(async (message) => {
8952
- 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`);
8953
8941
  }, { resolveChannels: this.resolveMessageChannels });
8954
8942
  messageTool.setContext(channel, chatId, accountId ?? null);
8955
- return [messageTool, new CronTool(this.kernel.automation)];
8943
+ return [messageTool, new CronTool(this.automation)];
8956
8944
  };
8957
8945
  resolveMessageChannels = () => {
8958
- const channels = this.kernel.extensions.getExtensionRegistry()?.channels ?? [];
8946
+ const channels = this.extensions.getExtensionRegistry()?.channels ?? [];
8959
8947
  return [...new Set(channels.map((registration) => registration.channel.id.trim()).filter(Boolean))].sort();
8960
8948
  };
8961
8949
  };
@@ -9094,12 +9082,12 @@ var SessionsHistoryTool = class {
9094
9082
  };
9095
9083
  //#endregion
9096
9084
  //#region src/tools/session-request.tools.ts
9097
- function readRequiredString$1(params, key) {
9085
+ function readRequiredString$2(params, key) {
9098
9086
  const value = params[key];
9099
9087
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9100
9088
  return value.trim();
9101
9089
  }
9102
- function readOptionalString$2(params, key) {
9090
+ function readOptionalString$3(params, key) {
9103
9091
  const value = params[key];
9104
9092
  if (typeof value !== "string") return;
9105
9093
  const trimmed = value.trim();
@@ -9153,16 +9141,16 @@ var SessionRequestTool = class {
9153
9141
  const params = normalizeToolParams(args);
9154
9142
  const target = params.target;
9155
9143
  if (!target || typeof target !== "object" || Array.isArray(target)) throw new Error("target must be an object.");
9156
- const task = readRequiredString$1(params, "task");
9157
- const notifyMode = readOptionalString$2(params, "notify")?.toLowerCase();
9144
+ const task = readRequiredString$2(params, "task");
9145
+ const notifyMode = readOptionalString$3(params, "notify")?.toLowerCase();
9158
9146
  if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
9159
9147
  return this.manager.requestSession({
9160
9148
  sourceSessionId: this.sourceSessionId,
9161
9149
  sourceToolCallId: context?.toolCallId,
9162
9150
  updateToolCallResult: context?.updateToolCallResult,
9163
- targetSessionId: readRequiredString$1(target, "session_id"),
9151
+ targetSessionId: readRequiredString$2(target, "session_id"),
9164
9152
  task,
9165
- title: readOptionalString$2(params, "title"),
9153
+ title: readOptionalString$3(params, "title"),
9166
9154
  notify: notifyMode,
9167
9155
  handoffDepth: this.handoffDepth
9168
9156
  });
@@ -9170,7 +9158,7 @@ var SessionRequestTool = class {
9170
9158
  };
9171
9159
  //#endregion
9172
9160
  //#region src/tools/session-search.tools.ts
9173
- function isRecord$1(value) {
9161
+ function isRecord$2(value) {
9174
9162
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9175
9163
  }
9176
9164
  function readOptionalInteger(value) {
@@ -9220,7 +9208,7 @@ var SessionSearchTool = class {
9220
9208
  return issues;
9221
9209
  };
9222
9210
  execute = async (args) => {
9223
- 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.");
9224
9212
  const issues = this.validateArgs(args);
9225
9213
  if (issues.length > 0) throw new Error(issues.join(" "));
9226
9214
  return this.queryService.search({
@@ -9233,23 +9221,23 @@ var SessionSearchTool = class {
9233
9221
  };
9234
9222
  //#endregion
9235
9223
  //#region src/tools/session-spawn.tools.ts
9236
- function readRequiredString(value, key) {
9224
+ function readRequiredString$1(value, key) {
9237
9225
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9238
9226
  return value.trim();
9239
9227
  }
9240
- function readOptionalString$1(value) {
9228
+ function readOptionalString$2(value) {
9241
9229
  if (typeof value !== "string") return;
9242
9230
  const trimmed = value.trim();
9243
9231
  return trimmed.length > 0 ? trimmed : void 0;
9244
9232
  }
9245
9233
  function readSpawnScope(value) {
9246
- const normalized = readOptionalString$1(value)?.toLowerCase();
9234
+ const normalized = readOptionalString$2(value)?.toLowerCase();
9247
9235
  if (!normalized || normalized === "standalone") return "standalone";
9248
9236
  if (normalized === "child") return "child";
9249
9237
  throw new Error("scope must be \"standalone\" or \"child\".");
9250
9238
  }
9251
9239
  function readSpawnNotify(value) {
9252
- const notifyMode = readOptionalString$1(value)?.toLowerCase();
9240
+ const notifyMode = readOptionalString$2(value)?.toLowerCase();
9253
9241
  if (!notifyMode && typeof value === "undefined") return;
9254
9242
  if (notifyMode === "none" || notifyMode === "final_reply") return notifyMode;
9255
9243
  throw new Error("notify must be \"none\" or \"final_reply\".");
@@ -9308,7 +9296,7 @@ var SessionSpawnTool = class {
9308
9296
  };
9309
9297
  execute = async (args, context) => {
9310
9298
  const { agentId: rawAgentId, model: rawModel, notify: rawNotify, runtime: rawRuntime, scope: rawScope, task: rawTask, title: rawTitle } = normalizeToolParams(args);
9311
- const task = readRequiredString(rawTask, "task");
9299
+ const task = readRequiredString$1(rawTask, "task");
9312
9300
  const scope = readSpawnScope(rawScope);
9313
9301
  const notify = readSpawnNotify(rawNotify);
9314
9302
  const parentSessionId = scope === "child" ? this.readParentSessionIdOrThrow() : void 0;
@@ -9318,10 +9306,10 @@ var SessionSpawnTool = class {
9318
9306
  updateToolCallResult: context?.updateToolCallResult,
9319
9307
  sourceSessionMetadata: this.sourceSessionMetadata,
9320
9308
  task,
9321
- title: readOptionalString$1(rawTitle),
9322
- agentId: readOptionalString$1(rawAgentId),
9323
- model: readOptionalString$1(rawModel),
9324
- runtime: readOptionalString$1(rawRuntime),
9309
+ title: readOptionalString$2(rawTitle),
9310
+ agentId: readOptionalString$2(rawAgentId),
9311
+ model: readOptionalString$2(rawModel),
9312
+ runtime: readOptionalString$2(rawRuntime),
9325
9313
  handoffDepth: this.handoffDepth,
9326
9314
  parentSessionId,
9327
9315
  notify
@@ -9329,11 +9317,11 @@ var SessionSpawnTool = class {
9329
9317
  const session = await this.sessionManager.createSession({
9330
9318
  sourceSessionId: this.sourceSessionId,
9331
9319
  task,
9332
- title: readOptionalString$1(rawTitle),
9320
+ title: readOptionalString$2(rawTitle),
9333
9321
  sourceSessionMetadata: this.sourceSessionMetadata,
9334
- agentId: readOptionalString$1(rawAgentId),
9335
- model: readOptionalString$1(rawModel),
9336
- runtime: readOptionalString$1(rawRuntime),
9322
+ agentId: readOptionalString$2(rawAgentId),
9323
+ model: readOptionalString$2(rawModel),
9324
+ runtime: readOptionalString$2(rawRuntime),
9337
9325
  parentSessionId
9338
9326
  });
9339
9327
  return {
@@ -9357,22 +9345,22 @@ var SessionSpawnTool = class {
9357
9345
  //#endregion
9358
9346
  //#region src/contributions/tool-provider/providers/session-tool.provider.ts
9359
9347
  var SessionToolProvider = class {
9360
- constructor(kernel) {
9361
- 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;
9362
9353
  }
9363
9354
  provide = async (request) => {
9364
- const { toolRunContext } = await resolveToolProviderRunContext({
9365
- kernel: this.kernel,
9366
- request
9367
- });
9355
+ const { toolRunContext } = await this.runContextService.resolve(request);
9368
9356
  const { handoffDepth, metadata, sessionId } = toolRunContext;
9369
- const sessionsSpawnTool = new SessionSpawnTool(this.kernel.sessionManager, this.kernel.sessionRequests);
9357
+ const sessionsSpawnTool = new SessionSpawnTool(this.sessionManager, this.sessionRequests);
9370
9358
  sessionsSpawnTool.setContext({
9371
9359
  sourceSessionId: sessionId,
9372
9360
  sourceSessionMetadata: metadata,
9373
9361
  handoffDepth
9374
9362
  });
9375
- const sessionsRequestTool = new SessionRequestTool(this.kernel.sessionRequests);
9363
+ const sessionsRequestTool = new SessionRequestTool(this.sessionRequests);
9376
9364
  sessionsRequestTool.setContext({
9377
9365
  sourceSessionId: sessionId,
9378
9366
  handoffDepth
@@ -9380,15 +9368,166 @@ var SessionToolProvider = class {
9380
9368
  const tools = [
9381
9369
  sessionsSpawnTool,
9382
9370
  sessionsRequestTool,
9383
- new SessionsListTool(this.kernel.sessionManager),
9384
- new SessionsHistoryTool(this.kernel.sessionManager)
9371
+ new SessionsListTool(this.sessionManager),
9372
+ new SessionsHistoryTool(this.sessionManager)
9385
9373
  ];
9386
- if (!this.kernel.sessionSearch.isReady()) return tools;
9387
- 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 }));
9388
9376
  return tools;
9389
9377
  };
9390
9378
  };
9391
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
9392
9531
  //#region src/contributions/tool-provider/providers/structured-result-tool.provider.ts
9393
9532
  var StructuredResultToolProvider = class {
9394
9533
  provide = (request) => {
@@ -9411,6 +9550,40 @@ function isRecord(value) {
9411
9550
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9412
9551
  }
9413
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
9414
9587
  //#region src/contributions/tool-provider/index.ts
9415
9588
  var ToolProviderContribution = class {
9416
9589
  cleanups = [];
@@ -9424,14 +9597,18 @@ var ToolProviderContribution = class {
9424
9597
  dispose = () => {
9425
9598
  while (this.cleanups.length > 0) this.cleanups.pop()?.();
9426
9599
  };
9427
- createToolProviders = () => [
9428
- new StructuredResultToolProvider(),
9429
- new CoreToolProvider(this.kernel),
9430
- new MessagingToolProvider(this.kernel),
9431
- new SessionToolProvider(this.kernel),
9432
- new AssetToolProvider(this.kernel),
9433
- new McpToolProvider(this.kernel)
9434
- ];
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
+ };
9435
9612
  };
9436
9613
  //#endregion
9437
9614
  //#region src/app/nextclaw-kernel.ts
@@ -9487,26 +9664,27 @@ var NextclawKernel = class {
9487
9664
  gatewayController;
9488
9665
  constructor(options = {}) {
9489
9666
  const sessionsDir = resolveKernelSessionsDir(options);
9490
- this.sessionSearch = new SessionSearchManager({
9667
+ this.sessionSearch = new SessionSearchService({
9491
9668
  databasePath: resolve(getDataDir(), "session-search.db"),
9492
9669
  sessionsDir
9493
9670
  });
9494
9671
  this.ncpAgentSessionJournalStore = new NcpAgentSessionJournalStore(resolve(sessionsDir, ".ncp-agent-journal"));
9495
9672
  this.automation = new AutomationManager({ storePath: resolveKernelAutomationStorePath(options) });
9496
9673
  this.assetStore = new LocalAssetStore({ rootDir: resolve(getDataDir(), "assets") });
9497
- this.agents = new AgentManager();
9498
9674
  this.control = new NextclawKernelControlManager();
9499
- this.channels = new ChannelManager$1({ bus: this.messageBus });
9675
+ this.channels = new ChannelManager({ bus: this.messageBus });
9500
9676
  this.configManager = new ConfigManager({
9501
9677
  configPath: options.configPath,
9502
9678
  channels: this.channels,
9503
9679
  providerManager: this.llmProviders
9504
9680
  });
9681
+ this.agents = new AgentManager(this.configManager);
9505
9682
  this.accessManager = new AccessManager({
9506
9683
  configManager: this.configManager,
9507
9684
  homeDir: options.homeDir
9508
9685
  });
9509
9686
  this.sessionManager = new SessionManager({
9687
+ agentManager: this.agents,
9510
9688
  configManager: this.configManager,
9511
9689
  eventBus: this.eventBus,
9512
9690
  journalStore: this.ncpAgentSessionJournalStore,
@@ -9539,9 +9717,9 @@ var NextclawKernel = class {
9539
9717
  ingress: this.ingress
9540
9718
  })
9541
9719
  });
9542
- this.contextCompactionManager = new AgentRunContextCompactionManager(this.configManager, this.llmProviders, this.sessionManager);
9720
+ this.contextCompactionManager = new AgentRunContextCompactionManager(this.agents, this.llmProviders, this.sessionManager);
9543
9721
  this.sessionRunManager = new SessionRunManager(this.sessionManager);
9544
- 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);
9545
9723
  this.contributions = [
9546
9724
  new ToolProviderContribution(this),
9547
9725
  new SessionActivityPreviewContribution(this),
@@ -10181,6 +10359,6 @@ function resolveLegacyEventType(message) {
10181
10359
  return `message.${role || "other"}`;
10182
10360
  }
10183
10361
  //#endregion
10184
- 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, buildContextCompactionModelInput, 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, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, 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 };
10185
10363
 
10186
10364
  //# sourceMappingURL=index.js.map