@nextclaw/kernel 0.4.3 → 0.5.1-beta.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, normalizeModelThinkingCapability, 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,
@@ -692,13 +703,16 @@ var AgentRunRequestManager = class {
692
703
  const contextBlocks = await this.contextProviderManager.buildContext(providerRequest);
693
704
  const tools = await this.toolProviderManager.buildTools(providerRequest);
694
705
  let messageCompletedSeen = false;
706
+ let runtimeFailed = false;
695
707
  lastValueFrom(from(runtime.run(spec, {
696
708
  contextBlocks,
709
+ session,
697
710
  sessionRun,
698
711
  signal: activeRun.signal,
699
712
  tools
700
713
  })).pipe(tap((event) => {
701
714
  const eventsToPublish = [];
715
+ if (event.type === NcpEventType.RunError) runtimeFailed = true;
702
716
  if (event.type === NcpEventType.MessageCompleted) messageCompletedSeen = true;
703
717
  if (event.type === NcpEventType.RunFinished && !messageCompletedSeen) {
704
718
  const message = findCompletedAssistantMessage(sessionRun.getSnapshot().messages, event.payload.messageId);
@@ -719,6 +733,7 @@ var AgentRunRequestManager = class {
719
733
  source: "agent-run-request"
720
734
  });
721
735
  }), catchError(async (error) => {
736
+ runtimeFailed = true;
722
737
  const event = {
723
738
  type: NcpEventType.RunError,
724
739
  payload: {
@@ -733,7 +748,14 @@ var AgentRunRequestManager = class {
733
748
  emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
734
749
  source: "agent-run-request"
735
750
  });
736
- })), { defaultValue: void 0 });
751
+ })), { defaultValue: void 0 }).finally(() => {
752
+ if (!runtimeFailed) return;
753
+ this.agentRuntimeManager.disposeRuntime({
754
+ agentRuntimeId: session.agentRuntimeId,
755
+ session,
756
+ sessionRun
757
+ }).catch(() => void 0);
758
+ });
737
759
  return {
738
760
  sessionId: session.sessionId,
739
761
  userMessageId: message.id,
@@ -749,6 +771,128 @@ var AgentRunRequestManager = class {
749
771
  //#region src/configs/agent-runtime.config.ts
750
772
  const DEFAULT_AGENT_RUNTIME_ENTRY_ID = "native";
751
773
  //#endregion
774
+ //#region src/features/runtime-registry/utils/agent-runtime-registry.utils.ts
775
+ function normalizeIdentifier(value) {
776
+ if (typeof value !== "string") return null;
777
+ const normalized = value.trim().toLowerCase();
778
+ return normalized.length > 0 ? normalized : null;
779
+ }
780
+ function normalizeAgentRuntimeSessionTypeIcon(value) {
781
+ if (typeof value === "string") {
782
+ const src = value.trim();
783
+ return src ? {
784
+ kind: "image",
785
+ src
786
+ } : null;
787
+ }
788
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
789
+ const iconRecord = value;
790
+ const src = typeof iconRecord.src === "string" ? iconRecord.src.trim() : "";
791
+ if (!src) return null;
792
+ const alt = typeof iconRecord.alt === "string" && iconRecord.alt.trim().length > 0 ? iconRecord.alt.trim() : null;
793
+ return {
794
+ kind: "image",
795
+ src,
796
+ ...alt ? { alt } : {}
797
+ };
798
+ }
799
+ const BUILTIN_RUNTIME_PRESENTATION = { hermes: {
800
+ label: "Hermes",
801
+ icon: {
802
+ kind: "image",
803
+ src: "app://runtime-icons/hermes-agent.png",
804
+ alt: "Hermes"
805
+ }
806
+ } };
807
+ function readString$6(value) {
808
+ if (typeof value !== "string") return;
809
+ return value.trim() || void 0;
810
+ }
811
+ function readRecord$3(value) {
812
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
813
+ return value;
814
+ }
815
+ function resolveBuiltinRuntimePresentation(value) {
816
+ const normalized = readString$6(value)?.toLowerCase();
817
+ if (!normalized) return null;
818
+ if (!(normalized in BUILTIN_RUNTIME_PRESENTATION)) return null;
819
+ return BUILTIN_RUNTIME_PRESENTATION[normalized] ?? null;
820
+ }
821
+ function buildNativeRuntimeEntry(config) {
822
+ const nativeRuntimeConfig = readRecord$3(config.ui?.ncp?.runtimes?.native) ?? {};
823
+ return {
824
+ id: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
825
+ label: "Native",
826
+ type: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
827
+ enabled: nativeRuntimeConfig.enabled !== false,
828
+ config: nativeRuntimeConfig
829
+ };
830
+ }
831
+ function resolveAgentRuntimeEntries(params) {
832
+ const entries = /* @__PURE__ */ new Map();
833
+ entries.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, buildNativeRuntimeEntry(params.config));
834
+ for (const [rawId, rawEntry] of Object.entries(params.config.agents.runtimes.entries ?? {})) {
835
+ const id = rawId.trim().toLowerCase();
836
+ const type = readString$6(rawEntry.type)?.toLowerCase();
837
+ if (!id || !type) continue;
838
+ const explicitIcon = normalizeAgentRuntimeSessionTypeIcon(rawEntry.icon);
839
+ const builtinPresentation = resolveBuiltinRuntimePresentation(id) ?? resolveBuiltinRuntimePresentation(type);
840
+ entries.set(id, {
841
+ id,
842
+ label: readString$6(rawEntry.label) ?? builtinPresentation?.label ?? id,
843
+ ...explicitIcon ?? builtinPresentation?.icon ? { icon: explicitIcon ?? builtinPresentation?.icon } : {},
844
+ type,
845
+ enabled: rawEntry.enabled !== false,
846
+ config: rawEntry.config ? { ...rawEntry.config } : {}
847
+ });
848
+ }
849
+ return {
850
+ defaultEntryId: entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : [...entries.keys()][0] ?? "native",
851
+ entries: [...entries.values()]
852
+ };
853
+ }
854
+ async function describeAgentRuntimeSessionTypes(params) {
855
+ const entries = params.entries.filter((entry) => entry.enabled !== false);
856
+ return {
857
+ defaultType: normalizeIdentifier(params.defaultEntryId) ?? (entries.some((entry) => entry.id === "native") ? "native" : entries[0]?.id ?? "native"),
858
+ options: await Promise.all(entries.map(async (entry) => {
859
+ const provider = params.providers.get(entry.type);
860
+ if (!provider) return {
861
+ value: entry.id,
862
+ label: entry.label,
863
+ icon: entry.icon ?? null,
864
+ ready: false,
865
+ reason: "runtime_provider_unavailable",
866
+ reasonMessage: `Runtime provider unavailable for type "${entry.type}".`,
867
+ recommendedModel: null,
868
+ modelSelectionMode: "nextclaw",
869
+ runtimeDefaultThinking: null,
870
+ cta: {
871
+ kind: "settings",
872
+ label: "Configure Runtime"
873
+ }
874
+ };
875
+ const descriptor = provider.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
876
+ entry,
877
+ describeParams: params.describeParams
878
+ }) : await provider.describeSessionType?.(params.describeParams);
879
+ return {
880
+ value: entry.id,
881
+ label: entry.label,
882
+ icon: descriptor?.icon ?? entry.icon ?? null,
883
+ ready: descriptor?.ready ?? true,
884
+ reason: descriptor?.reason ?? null,
885
+ reasonMessage: descriptor?.reasonMessage ?? null,
886
+ recommendedModel: descriptor?.recommendedModel ?? null,
887
+ modelSelectionMode: descriptor?.modelSelectionMode ?? "nextclaw",
888
+ runtimeDefaultThinking: descriptor?.runtimeDefaultThinking ?? null,
889
+ cta: descriptor?.cta ?? null,
890
+ ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
891
+ };
892
+ }))
893
+ };
894
+ }
895
+ //#endregion
752
896
  //#region src/managers/agent-runtime.manager.ts
753
897
  var AgentRuntimeManager = class {
754
898
  providers = /* @__PURE__ */ new Map();
@@ -778,12 +922,8 @@ var AgentRuntimeManager = class {
778
922
  });
779
923
  };
780
924
  getOrCreate = (params) => {
781
- const { agentRuntimeId, session, sessionRun } = params;
782
- const entry = this.getEntry(agentRuntimeId);
783
- const provider = this.getProvider(entry.type);
784
- const reuseScope = this.resolveReuseScope(entry, provider);
785
- const cacheKey = reuseScope === "global" ? entry.id : `${entry.id}:${session.sessionId}`;
786
- const cache = reuseScope === "global" ? this.globalRuntimes : this.sessionRuntimes;
925
+ const { session, sessionRun } = params;
926
+ const { cache, cacheKey, entry, provider } = this.resolveRuntimeCache(params);
787
927
  const existing = cache.get(cacheKey);
788
928
  if (existing) return existing;
789
929
  const agentRuntime = provider.createRuntime({
@@ -794,31 +934,19 @@ var AgentRuntimeManager = class {
794
934
  cache.set(cacheKey, agentRuntime);
795
935
  return agentRuntime;
796
936
  };
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
- };
937
+ disposeRuntime = async (params) => {
938
+ const { cache, cacheKey } = this.resolveRuntimeCache(params);
939
+ const runtime = cache.get(cacheKey);
940
+ if (!runtime) return false;
941
+ cache.delete(cacheKey);
942
+ await runtime.dispose?.();
943
+ return true;
821
944
  };
945
+ listSessionTypes = async (params) => describeAgentRuntimeSessionTypes({
946
+ entries: [...this.entries.values()],
947
+ providers: this.providers,
948
+ describeParams: params
949
+ });
822
950
  dispose = async () => {
823
951
  await this.disposeAllRuntimes();
824
952
  this.providers.clear();
@@ -843,6 +971,19 @@ var AgentRuntimeManager = class {
843
971
  resolveReuseScope = (entry, provider) => {
844
972
  return entry.config?.reuseScope === "session" || entry.config?.reuseScope === "global" ? entry.config.reuseScope : provider.defaultReuseScope;
845
973
  };
974
+ resolveRuntimeCache = (params) => {
975
+ const { agentRuntimeId, session } = params;
976
+ const entry = this.getEntry(agentRuntimeId);
977
+ const provider = this.getProvider(entry.type);
978
+ const reuseScope = this.resolveReuseScope(entry, provider);
979
+ const cacheKey = reuseScope === "global" ? entry.id : `${entry.id}:${session.sessionId}`;
980
+ return {
981
+ cache: reuseScope === "global" ? this.globalRuntimes : this.sessionRuntimes,
982
+ cacheKey,
983
+ entry,
984
+ provider
985
+ };
986
+ };
846
987
  disposeAllRuntimes = async () => {
847
988
  for (const runtime of [...this.globalRuntimes.values(), ...this.sessionRuntimes.values()]) await runtime.dispose?.();
848
989
  this.globalRuntimes.clear();
@@ -1159,6 +1300,117 @@ var AutomationManager = class extends CronService {
1159
1300
  }
1160
1301
  };
1161
1302
  //#endregion
1303
+ //#region src/managers/channel.manager.ts
1304
+ var ChannelManager = class {
1305
+ channels = {};
1306
+ channelConfig = null;
1307
+ dispatching = false;
1308
+ dispatchTask = null;
1309
+ extensionChannels = [];
1310
+ constructor(deps) {
1311
+ this.deps = deps;
1312
+ }
1313
+ load = (params) => {
1314
+ this.channelConfig = params.channelConfig;
1315
+ this.extensionChannels = params.extensionChannels ?? [];
1316
+ this.channels = {};
1317
+ this.initChannels();
1318
+ };
1319
+ reload = async (params) => {
1320
+ await this.stop();
1321
+ this.load(params);
1322
+ if (params.start === true) await this.start();
1323
+ };
1324
+ start = async () => {
1325
+ if (!Object.keys(this.channels).length || this.dispatching) return;
1326
+ this.dispatching = true;
1327
+ this.dispatchTask = this.dispatchOutbound();
1328
+ await Promise.allSettled(Object.entries(this.channels).map(([name, channel]) => this.startChannel(name, channel)));
1329
+ };
1330
+ stop = async () => {
1331
+ this.dispatching = false;
1332
+ if (this.dispatchTask) {
1333
+ await this.deps.bus.publishOutbound({
1334
+ channel: "__control__",
1335
+ chatId: "",
1336
+ content: "",
1337
+ media: [],
1338
+ metadata: { reason: "shutdown" }
1339
+ });
1340
+ await this.dispatchTask;
1341
+ }
1342
+ await Promise.allSettled(Object.entries(this.channels).map(async ([name, channel]) => {
1343
+ try {
1344
+ await channel.stop();
1345
+ } catch (error) {
1346
+ console.error(`Error stopping ${name}: ${String(error)}`);
1347
+ }
1348
+ }));
1349
+ this.dispatchTask = null;
1350
+ };
1351
+ status = () => Object.fromEntries(Object.entries(this.channels).map(([name, channel]) => [name, {
1352
+ enabled: true,
1353
+ running: channel.isRunning
1354
+ }]));
1355
+ get enabledChannels() {
1356
+ return Object.keys(this.channels);
1357
+ }
1358
+ getChannel = (name) => this.channels[name] ?? null;
1359
+ deliver = async (message) => {
1360
+ const channel = this.channels[message.channel];
1361
+ if (!channel) return false;
1362
+ if (isNextclawControlMessage(message)) {
1363
+ await channel.handleControlMessage(message);
1364
+ return true;
1365
+ }
1366
+ const outbound = this.normalizeOutbound(message);
1367
+ if (!outbound) return true;
1368
+ await channel.send(outbound);
1369
+ return true;
1370
+ };
1371
+ initChannels = () => {
1372
+ if (!this.channelConfig) return;
1373
+ for (const registration of this.extensionChannels) {
1374
+ const id = registration.channel.id;
1375
+ if (!id) continue;
1376
+ if (this.channels[id]) {
1377
+ console.warn(`Extension channel ignored because id already exists: ${id}`);
1378
+ continue;
1379
+ }
1380
+ this.channels[id] = new ExtensionChannelAdapter(this.channelConfig, this.deps.bus, registration);
1381
+ }
1382
+ };
1383
+ startChannel = async (name, channel) => {
1384
+ try {
1385
+ await channel.start();
1386
+ } catch (error) {
1387
+ console.error(`Failed to start channel ${name}: ${String(error)}`);
1388
+ }
1389
+ };
1390
+ normalizeOutbound = (message) => {
1391
+ const silentReplyDecision = evaluateSilentReply({
1392
+ content: sanitizeOutboundAssistantContent(message.content ?? ""),
1393
+ media: message.media
1394
+ });
1395
+ if (silentReplyDecision.shouldDrop) return null;
1396
+ if (silentReplyDecision.content === message.content) return message;
1397
+ return {
1398
+ ...message,
1399
+ content: silentReplyDecision.content
1400
+ };
1401
+ };
1402
+ dispatchOutbound = async () => {
1403
+ while (this.dispatching) {
1404
+ const message = await this.deps.bus.consumeOutbound();
1405
+ try {
1406
+ await this.deliver(message);
1407
+ } catch (error) {
1408
+ console.error(`Error sending to ${message.channel}: ${String(error)}`);
1409
+ }
1410
+ }
1411
+ };
1412
+ };
1413
+ //#endregion
1162
1414
  //#region src/managers/config.manager.ts
1163
1415
  const hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
1164
1416
  const mergeDeep = (base, patch) => {
@@ -1769,21 +2021,6 @@ var CommandRegistry = class {
1769
2021
  };
1770
2022
  //#endregion
1771
2023
  //#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
2024
  var ExtensionLifecycleService = class {
1788
2025
  processes = /* @__PURE__ */ new Map();
1789
2026
  startAll = (manifests, params) => {
@@ -1813,14 +2050,12 @@ var ExtensionLifecycleService = class {
1813
2050
  if (existing) return existing;
1814
2051
  const child = spawn(manifest.server.command === "node" || manifest.server.command === "node.exe" ? process.execPath : manifest.server.command, manifest.server.args ?? [], {
1815
2052
  cwd: manifest.rootDir,
1816
- env: {
1817
- ...process.env,
1818
- NODE_OPTIONS: sanitizeExtensionNodeOptions(process.env.NODE_OPTIONS),
2053
+ env: createRuntimeChildEnv(process.env, {
1819
2054
  ...manifest.server.env,
1820
2055
  NEXTCLAW_EXTENSION_ID: manifest.id,
1821
2056
  NEXTCLAW_EXTENSION_ENDPOINT: params.endpoint,
1822
2057
  NEXTCLAW_EXTENSION_TOKEN: params.tokenForExtension(manifest.id)
1823
- },
2058
+ }, { inheritBaseEnv: true }),
1824
2059
  stdio: [
1825
2060
  "ignore",
1826
2061
  "ignore",
@@ -1860,7 +2095,7 @@ const BUILTIN_EXTENSION_PACKAGES = [
1860
2095
  "@nextclaw/channel-extension-weixin"
1861
2096
  ];
1862
2097
  const runtimeRequire = createRequire(import.meta.url);
1863
- function readString$6(value) {
2098
+ function readString$5(value) {
1864
2099
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1865
2100
  }
1866
2101
  function readStringArray$2(value) {
@@ -1871,7 +2106,7 @@ function readStringRecord(value) {
1871
2106
  const entries = Object.entries(value);
1872
2107
  return entries.every(([, item]) => typeof item === "string") ? Object.fromEntries(entries) : void 0;
1873
2108
  }
1874
- function readRecord$3(value) {
2109
+ function readRecord$2(value) {
1875
2110
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1876
2111
  }
1877
2112
  function uniquePaths(paths) {
@@ -1908,17 +2143,17 @@ function resolveDevFirstPartyExtensionDir(explicitDir = process.env.NEXTCLAW_DEV
1908
2143
  function toManifest(value, rootDir) {
1909
2144
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("extension manifest must be an object");
1910
2145
  const record = value;
1911
- const server = readRecord$3(record.server);
1912
- const id = readString$6(record.id);
1913
- const command = readString$6(server.command);
2146
+ const server = readRecord$2(record.server);
2147
+ const id = readString$5(record.id);
2148
+ const command = readString$5(server.command);
1914
2149
  if (!id) throw new Error("extension manifest id is required");
1915
2150
  if (server.type !== "stdio") throw new Error("extension server.type must be stdio");
1916
2151
  if (!command) throw new Error("extension server.command is required");
1917
2152
  return {
1918
2153
  id,
1919
2154
  rootDir,
1920
- ...readString$6(record.name) ? { name: readString$6(record.name) } : {},
1921
- ...readString$6(record.version) ? { version: readString$6(record.version) } : {},
2155
+ ...readString$5(record.name) ? { name: readString$5(record.name) } : {},
2156
+ ...readString$5(record.version) ? { version: readString$5(record.version) } : {},
1922
2157
  server: {
1923
2158
  type: "stdio",
1924
2159
  command,
@@ -2022,19 +2257,19 @@ function listExtensionChannelIds(params) {
2022
2257
  //#region src/services/extension-runtime.service.ts
2023
2258
  const EXTENSION_REQUEST_EVENT_TYPE = "extension.request";
2024
2259
  const EXTENSION_REQUEST_TIMEOUT_MS = 6e4;
2025
- function readString$5(value) {
2260
+ function readString$4(value) {
2026
2261
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
2027
2262
  }
2028
- function readRecord$2(value) {
2263
+ function readRecord$1(value) {
2029
2264
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2030
2265
  }
2031
- function readRequiredString$4(value, name) {
2032
- const trimmed = readString$5(value);
2266
+ function readRequiredString$5(value, name) {
2267
+ const trimmed = readString$4(value);
2033
2268
  if (!trimmed) throw new Error(`${name} is required`);
2034
2269
  return trimmed;
2035
2270
  }
2036
2271
  function readTextContent(value) {
2037
- const content = readRecord$2(value);
2272
+ const content = readRecord$1(value);
2038
2273
  if (content.type !== "text" || typeof content.text !== "string") throw new Error("only text channel messages are supported by the first ingress bridge");
2039
2274
  return content.text;
2040
2275
  }
@@ -2044,35 +2279,35 @@ function readOptionalNumber(value) {
2044
2279
  function readInboundAttachments(value) {
2045
2280
  if (!Array.isArray(value)) return [];
2046
2281
  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) } : {},
2282
+ ...readString$4(entry.id) ? { id: readString$4(entry.id) } : {},
2283
+ ...readString$4(entry.name) ? { name: readString$4(entry.name) } : {},
2284
+ ...readString$4(entry.path) ? { path: readString$4(entry.path) } : {},
2285
+ ...readString$4(entry.url) ? { url: readString$4(entry.url) } : {},
2286
+ ...readString$4(entry.assetUri) ? { assetUri: readString$4(entry.assetUri) } : {},
2287
+ ...readString$4(entry.mimeType) ? { mimeType: readString$4(entry.mimeType) } : {},
2053
2288
  ...readOptionalNumber(entry.size) !== void 0 ? { size: readOptionalNumber(entry.size) } : {},
2054
- ...readString$5(entry.source) ? { source: readString$5(entry.source) } : {},
2289
+ ...readString$4(entry.source) ? { source: readString$4(entry.source) } : {},
2055
2290
  ...entry.status === "ready" || entry.status === "remote-only" ? { status: entry.status } : {},
2056
- ...readString$5(entry.errorCode) ? { errorCode: readString$5(entry.errorCode) } : {}
2291
+ ...readString$4(entry.errorCode) ? { errorCode: readString$4(entry.errorCode) } : {}
2057
2292
  }));
2058
2293
  }
2059
2294
  function toInboundMessage(value) {
2060
- const payload = readRecord$2(value);
2295
+ const payload = readRecord$1(value);
2061
2296
  return {
2062
- channel: readRequiredString$4(payload.channelId, "channelId"),
2063
- chatId: readRequiredString$4(payload.conversationId, "conversationId"),
2064
- senderId: readRequiredString$4(payload.senderId, "senderId"),
2297
+ channel: readRequiredString$5(payload.channelId, "channelId"),
2298
+ chatId: readRequiredString$5(payload.conversationId, "conversationId"),
2299
+ senderId: readRequiredString$5(payload.senderId, "senderId"),
2065
2300
  content: readTextContent(payload.content),
2066
2301
  timestamp: /* @__PURE__ */ new Date(),
2067
2302
  attachments: readInboundAttachments(payload.attachments),
2068
- metadata: readRecord$2(payload.metadata)
2303
+ metadata: readRecord$1(payload.metadata)
2069
2304
  };
2070
2305
  }
2071
2306
  function normalizeChannelConfigResult(value) {
2072
- return readRecord$2(readRecord$2(value).channelConfig);
2307
+ return readRecord$1(readRecord$1(value).channelConfig);
2073
2308
  }
2074
2309
  function normalizeAuthLoginResult(value) {
2075
- const record = readRecord$2(value);
2310
+ const record = readRecord$1(value);
2076
2311
  return {
2077
2312
  channelConfig: normalizeChannelConfigResult(record),
2078
2313
  accountId: typeof record.accountId === "string" ? record.accountId : null,
@@ -2081,11 +2316,11 @@ function normalizeAuthLoginResult(value) {
2081
2316
  }
2082
2317
  function normalizeAuthPollResult(value) {
2083
2318
  if (!value) return null;
2084
- const record = readRecord$2(value);
2319
+ const record = readRecord$1(value);
2085
2320
  return {
2086
- channel: readRequiredString$4(record.channel, "channel"),
2321
+ channel: readRequiredString$5(record.channel, "channel"),
2087
2322
  status: record.status,
2088
- message: readString$5(record.message),
2323
+ message: readString$4(record.message),
2089
2324
  nextPollMs: readOptionalNumber(record.nextPollMs),
2090
2325
  accountId: typeof record.accountId === "string" ? record.accountId : null,
2091
2326
  notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
@@ -2181,7 +2416,7 @@ var ExtensionRuntimeService = class {
2181
2416
  if (running.length > 0) console.log(`✓ Extensions started: ${running.map((entry) => entry.manifest.id).join(", ")}`);
2182
2417
  };
2183
2418
  getExtensionProcessToken = (extensionId) => {
2184
- const id = readRequiredString$4(extensionId, "extensionId");
2419
+ const id = readRequiredString$5(extensionId, "extensionId");
2185
2420
  const current = this.extensionTokens.get(id);
2186
2421
  if (current) return current;
2187
2422
  const token = randomUUID();
@@ -2189,8 +2424,8 @@ var ExtensionRuntimeService = class {
2189
2424
  return token;
2190
2425
  };
2191
2426
  authenticateEventStreamCredential = (input) => {
2192
- const extensionId = readString$5(input.extensionId);
2193
- const token = readString$5(input.token);
2427
+ const extensionId = readString$4(input.extensionId);
2428
+ const token = readString$4(input.token);
2194
2429
  if (!extensionId || !token || token !== this.extensionTokens.get(extensionId)) return null;
2195
2430
  return { extensionId };
2196
2431
  };
@@ -2209,7 +2444,7 @@ var ExtensionRuntimeService = class {
2209
2444
  const channelBindings = [];
2210
2445
  const uiMetadata = [];
2211
2446
  for (const manifest of manifests) for (const channel of manifest.contributes?.channels ?? []) {
2212
- const channelId = readString$5(channel.id);
2447
+ const channelId = readString$4(channel.id);
2213
2448
  if (!channelId) continue;
2214
2449
  const configUiHints = this.readConfigUiHints(channel.configUiHints);
2215
2450
  channelBindings.push({
@@ -2244,7 +2479,7 @@ var ExtensionRuntimeService = class {
2244
2479
  };
2245
2480
  handleChannelConfigGet = (envelope, context) => {
2246
2481
  this.assertAuthorized(envelope, context);
2247
- const channelId = readRequiredString$4(readRecord$2(envelope.payload).channelId, "channelId");
2482
+ const channelId = readRequiredString$5(readRecord$1(envelope.payload).channelId, "channelId");
2248
2483
  return { config: this.options.getConfig().channels[channelId] ?? {} };
2249
2484
  };
2250
2485
  handleChannelMessageSubmit = async (envelope, context) => {
@@ -2258,11 +2493,11 @@ var ExtensionRuntimeService = class {
2258
2493
  };
2259
2494
  handleChannelCommandExecute = async (envelope, context) => {
2260
2495
  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);
2496
+ const payload = readRecord$1(envelope.payload);
2497
+ const channel = readRequiredString$5(payload.channelId, "channelId");
2498
+ const chatId = readRequiredString$5(payload.conversationId, "conversationId");
2499
+ const senderId = readRequiredString$5(payload.senderId, "senderId");
2500
+ const metadata = readRecord$1(payload.metadata);
2266
2501
  const config = this.options.getConfig();
2267
2502
  const registry = new CommandRegistry(config, this.options.sessionManager);
2268
2503
  const route = new AgentRouteResolver(config).resolveInbound({
@@ -2270,15 +2505,15 @@ var ExtensionRuntimeService = class {
2270
2505
  channel,
2271
2506
  chatId,
2272
2507
  senderId,
2273
- content: readString$5(payload.rawText) ?? readString$5(payload.commandName) ?? "",
2508
+ content: readString$4(payload.rawText) ?? readString$4(payload.commandName) ?? "",
2274
2509
  timestamp: /* @__PURE__ */ new Date(),
2275
2510
  attachments: [],
2276
2511
  metadata
2277
2512
  },
2278
- forcedAgentId: readString$5(metadata.target_agent_id),
2279
- sessionKeyOverride: readString$5(metadata.session_key_override)
2513
+ forcedAgentId: readString$4(metadata.target_agent_id),
2514
+ sessionKeyOverride: readString$4(metadata.session_key_override)
2280
2515
  });
2281
- const rawText = readString$5(payload.rawText);
2516
+ const rawText = readString$4(payload.rawText);
2282
2517
  if (rawText) return await registry.executeText(rawText, {
2283
2518
  channel,
2284
2519
  chatId,
@@ -2288,7 +2523,7 @@ var ExtensionRuntimeService = class {
2288
2523
  content: "",
2289
2524
  ephemeral: true
2290
2525
  };
2291
- return await registry.execute(readRequiredString$4(payload.commandName, "commandName"), readRecord$2(payload.args), {
2526
+ return await registry.execute(readRequiredString$5(payload.commandName, "commandName"), readRecord$1(payload.args), {
2292
2527
  channel,
2293
2528
  chatId,
2294
2529
  senderId,
@@ -2297,14 +2532,14 @@ var ExtensionRuntimeService = class {
2297
2532
  };
2298
2533
  handleExtensionResponse = (envelope, context) => {
2299
2534
  this.assertAuthorized(envelope, context);
2300
- const payload = readRecord$2(envelope.payload);
2301
- const requestId = readRequiredString$4(payload.requestId, "requestId");
2535
+ const payload = readRecord$1(envelope.payload);
2536
+ const requestId = readRequiredString$5(payload.requestId, "requestId");
2302
2537
  const pending = this.pendingRequests.get(requestId);
2303
2538
  if (!pending) return { accepted: false };
2304
2539
  this.pendingRequests.delete(requestId);
2305
2540
  clearTimeout(pending.timeout);
2306
2541
  if (payload.ok === false) {
2307
- const message = readString$5(readRecord$2(payload.error).message) ?? "Extension request failed";
2542
+ const message = readString$4(readRecord$1(payload.error).message) ?? "Extension request failed";
2308
2543
  pending.reject(new Error(message));
2309
2544
  return { accepted: true };
2310
2545
  }
@@ -2351,7 +2586,7 @@ var ExtensionRuntimeService = class {
2351
2586
  return await result;
2352
2587
  };
2353
2588
  assertAuthorized = (envelope, context) => {
2354
- const extensionId = readString$5(envelope.extensionId);
2589
+ const extensionId = readString$4(envelope.extensionId);
2355
2590
  if (!extensionId || context.token !== this.extensionTokens.get(extensionId)) throw new Error("Unauthorized ingress token");
2356
2591
  };
2357
2592
  };
@@ -2474,11 +2709,11 @@ var ExtensionManager = class {
2474
2709
  //#endregion
2475
2710
  //#region src/utils/model-message-vision.utils.ts
2476
2711
  const IMAGE_OMITTED_TEXT = "[Image omitted: the selected model is not configured for vision input.]";
2477
- function isRecord$11(value) {
2712
+ function isRecord$12(value) {
2478
2713
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2479
2714
  }
2480
2715
  function isImageContentPart(value) {
2481
- if (!isRecord$11(value)) return false;
2716
+ if (!isRecord$12(value)) return false;
2482
2717
  const type = value.type;
2483
2718
  return type === "image_url" || type === "input_image";
2484
2719
  }
@@ -2494,7 +2729,7 @@ function normalizeContentWithoutVision(content) {
2494
2729
  };
2495
2730
  });
2496
2731
  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);
2732
+ const textParts = parts.filter((part) => isRecord$12(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
2498
2733
  if (textParts.length === parts.length) return textParts.join("\n\n");
2499
2734
  return parts;
2500
2735
  }
@@ -3034,11 +3269,11 @@ function createAgentPeerSessionIdentity(params) {
3034
3269
  }
3035
3270
  function resolveAgentPeerScope(params) {
3036
3271
  const metadata = params.metadata ?? {};
3037
- const explicitScope = readOptionalString$8(metadata["agent_peer_scope"]) ?? readOptionalString$8(metadata.agentPeerScope);
3272
+ const explicitScope = readOptionalString$9(metadata["agent_peer_scope"]) ?? readOptionalString$9(metadata.agentPeerScope);
3038
3273
  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"}`;
3274
+ 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
3275
  }
3041
- function readOptionalString$8(value) {
3276
+ function readOptionalString$9(value) {
3042
3277
  if (typeof value !== "string") return;
3043
3278
  return value.trim() || void 0;
3044
3279
  }
@@ -3057,7 +3292,7 @@ function safeNcpSessionFilename(value) {
3057
3292
  function normalizeNcpAgentId(agentId) {
3058
3293
  return agentId?.trim().toLowerCase() || void 0;
3059
3294
  }
3060
- function isRecord$10(value) {
3295
+ function isRecord$11(value) {
3061
3296
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3062
3297
  }
3063
3298
  function toIsoString(value, fallback) {
@@ -3137,7 +3372,7 @@ function createReplayEvent(event) {
3137
3372
  return replayEvent;
3138
3373
  }
3139
3374
  function readLegacyContextCompactionMessageId(message) {
3140
- const checkpoint = isRecord$10(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3375
+ const checkpoint = isRecord$11(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3141
3376
  const checkpointId = typeof checkpoint?.id === "string" ? checkpoint.id : "";
3142
3377
  const coveredCount = checkpoint?.coveredSessionMessageCount;
3143
3378
  const legacyId = `${message?.sessionId}:service:context-compaction:${checkpointId}`;
@@ -3167,11 +3402,11 @@ function rememberReplayMessageId(event, knownMessageIds) {
3167
3402
  if (message?.id) knownMessageIds.add(message.id);
3168
3403
  }
3169
3404
  function readEventSessionId$2(event) {
3170
- const sessionId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.sessionId;
3405
+ const sessionId = ("payload" in event && isRecord$11(event.payload) ? event.payload : null)?.sessionId;
3171
3406
  return typeof sessionId === "string" ? sessionId : "";
3172
3407
  }
3173
3408
  function readReplayPayloadTimestamp(event) {
3174
- const payload = "payload" in event && isRecord$10(event.payload) ? event.payload : null;
3409
+ const payload = "payload" in event && isRecord$11(event.payload) ? event.payload : null;
3175
3410
  const timestamp = typeof payload?.timestamp === "string" ? payload.timestamp : "";
3176
3411
  return Number.isFinite(Date.parse(timestamp)) ? new Date(timestamp).toISOString() : null;
3177
3412
  }
@@ -3226,7 +3461,7 @@ function applyLimit(items, limit) {
3226
3461
  if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
3227
3462
  return items.slice(0, Math.trunc(limit));
3228
3463
  }
3229
- function readOptionalString$7(value) {
3464
+ function readOptionalString$8(value) {
3230
3465
  if (typeof value !== "string") return null;
3231
3466
  const trimmed = value.trim();
3232
3467
  return trimmed.length > 0 ? trimmed : null;
@@ -3238,43 +3473,294 @@ function readEventSessionId$1(event) {
3238
3473
  return "payload" in event && "sessionId" in event.payload ? readOptionalMetadataString(event.payload.sessionId) : void 0;
3239
3474
  }
3240
3475
  //#endregion
3241
- //#region src/services/session-working-dir-resolver.service.ts
3242
- var SessionWorkingDirResolver = class {
3243
- constructor(configManager) {
3244
- this.configManager = configManager;
3245
- }
3246
- withWorkingDir = (summary) => ({
3247
- ...summary,
3248
- workingDir: this.resolve({
3249
- agentId: summary.agentId,
3250
- metadata: summary.metadata
3251
- })
3252
- });
3253
- 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);
3257
- return resolveSessionWorkspacePath({
3258
- sessionMetadata: params.metadata,
3259
- workspace: profile?.workspace ?? config.agents.defaults.workspace
3260
- });
3261
- };
3262
- };
3263
- //#endregion
3264
- //#region src/managers/session.manager.ts
3265
- const DEFAULT_SESSION_TYPE = "native";
3266
- const DEFAULT_LIFECYCLE = "persistent";
3267
- const SESSION_METADATA_LABEL_KEY = "label";
3268
- const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3269
- const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3270
- const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3271
- function isDurableSessionEvent(event) {
3272
- return event.type !== NcpEventType.ContextWindowUpdated;
3273
- }
3274
- function readThinkingEffort(metadata) {
3275
- return readOptionalMetadataString(metadata?.thinkingEffort) ?? null;
3276
- }
3277
- function readProjectRoot(metadata) {
3476
+ //#region src/contributions/session-activity-preview/utils/session-activity-preview-ncp-event.utils.ts
3477
+ const PREVIEW_TEXT_MAX_LENGTH = 160;
3478
+ function readSessionId(value) {
3479
+ if (typeof value !== "string") return null;
3480
+ const trimmed = value.trim();
3481
+ return trimmed.length > 0 ? trimmed : null;
3482
+ }
3483
+ function compactPreviewText(value) {
3484
+ return value.replace(/\s+/g, " ").trim();
3485
+ }
3486
+ function truncatePreviewText(value) {
3487
+ const compacted = compactPreviewText(value);
3488
+ if (compacted.length <= PREVIEW_TEXT_MAX_LENGTH) return compacted;
3489
+ return compacted.slice(0, PREVIEW_TEXT_MAX_LENGTH - 1).trimEnd();
3490
+ }
3491
+ function readSessionActivityPreviewText(message) {
3492
+ const chunks = [];
3493
+ for (const part of message.parts) if ((part.type === "text" || part.type === "rich-text") && part.text.trim()) chunks.push(part.text);
3494
+ const previewText = truncatePreviewText(chunks.join(" "));
3495
+ return previewText.length > 0 ? previewText : null;
3496
+ }
3497
+ function createProjection(sessionId, preview) {
3498
+ if (!sessionId) return null;
3499
+ return {
3500
+ sessionId,
3501
+ preview
3502
+ };
3503
+ }
3504
+ function formatErrorStatus(error) {
3505
+ if (typeof error === "string" && error.trim()) return `运行出错:${truncatePreviewText(error)}`;
3506
+ if (error && typeof error === "object" && "message" in error) {
3507
+ const message = error.message;
3508
+ if (typeof message === "string" && message.trim()) return `运行出错:${truncatePreviewText(message)}`;
3509
+ }
3510
+ return "运行出错";
3511
+ }
3512
+ function readToolCallId(value) {
3513
+ if (typeof value !== "string") return null;
3514
+ const trimmed = value.trim();
3515
+ return trimmed.length > 0 ? trimmed : null;
3516
+ }
3517
+ function formatToolDoneStatus(toolName) {
3518
+ return toolName ? `工具调用完成:${toolName}` : "工具调用完成";
3519
+ }
3520
+ function createSessionActivityPreviewFromNcpEvent(event, timestamp, options = {}) {
3521
+ switch (event.type) {
3522
+ case NcpEventType.RunStarted: return createProjection(readSessionId(event.payload.sessionId), {
3523
+ state: "running",
3524
+ statusText: "正在思考",
3525
+ timestamp
3526
+ });
3527
+ case NcpEventType.RunFinished: return createProjection(readSessionId(event.payload.sessionId), {
3528
+ state: "completed",
3529
+ timestamp
3530
+ });
3531
+ case NcpEventType.RunError: return createProjection(readSessionId(event.payload.sessionId), {
3532
+ state: "failed",
3533
+ statusText: formatErrorStatus(event.payload.error),
3534
+ timestamp
3535
+ });
3536
+ case NcpEventType.MessageSent: {
3537
+ const text = readSessionActivityPreviewText(event.payload.message);
3538
+ if (!text || event.payload.message.role !== "user") return null;
3539
+ return createProjection(readSessionId(event.payload.sessionId), {
3540
+ state: "running",
3541
+ statusText: text,
3542
+ timestamp: event.payload.message.timestamp || timestamp
3543
+ });
3544
+ }
3545
+ case NcpEventType.MessageCompleted: {
3546
+ const text = readSessionActivityPreviewText(event.payload.message);
3547
+ if (!text || event.payload.message.role !== "assistant") return null;
3548
+ return createProjection(readSessionId(event.payload.sessionId), {
3549
+ state: "completed",
3550
+ replyText: text,
3551
+ timestamp: event.payload.message.timestamp || timestamp
3552
+ });
3553
+ }
3554
+ case NcpEventType.MessageFailed: return createProjection(readSessionId(event.payload.sessionId), {
3555
+ state: "failed",
3556
+ statusText: formatErrorStatus(event.payload.error),
3557
+ timestamp
3558
+ });
3559
+ case NcpEventType.MessageToolCallStart: return createProjection(readSessionId(event.payload.sessionId), {
3560
+ state: "running",
3561
+ statusText: `正在调用工具:${event.payload.toolName}`,
3562
+ timestamp
3563
+ });
3564
+ case NcpEventType.MessageToolCallEnd:
3565
+ case NcpEventType.MessageToolCallResult: {
3566
+ const sessionId = readSessionId(event.payload.sessionId);
3567
+ const toolCallId = readToolCallId(event.payload.toolCallId);
3568
+ return createProjection(sessionId, {
3569
+ state: "running",
3570
+ statusText: formatToolDoneStatus(sessionId && toolCallId ? options.readToolName?.(sessionId, toolCallId) ?? null : null),
3571
+ timestamp
3572
+ });
3573
+ }
3574
+ default: return null;
3575
+ }
3576
+ }
3577
+ //#endregion
3578
+ //#region src/contributions/session-activity-preview/utils/session-activity-preview-metadata.utils.ts
3579
+ const SESSION_ACTIVITY_PREVIEW_METADATA_KEY = "last_activity_preview";
3580
+ const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
3581
+ "running",
3582
+ "completed",
3583
+ "failed",
3584
+ "idle"
3585
+ ]);
3586
+ function isRecord$10(value) {
3587
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3588
+ }
3589
+ function readOptionalString$7(value) {
3590
+ if (typeof value !== "string") return;
3591
+ const trimmed = value.trim();
3592
+ return trimmed.length > 0 ? trimmed : void 0;
3593
+ }
3594
+ function readSessionActivityPreviewMetadata(value) {
3595
+ if (!isRecord$10(value)) return null;
3596
+ const state = value.state;
3597
+ const timestamp = readOptionalString$7(value.timestamp);
3598
+ if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
3599
+ return {
3600
+ state,
3601
+ timestamp,
3602
+ ...readOptionalString$7(value.statusText) ? { statusText: readOptionalString$7(value.statusText) } : {},
3603
+ ...readOptionalString$7(value.replyText) ? { replyText: readOptionalString$7(value.replyText) } : {}
3604
+ };
3605
+ }
3606
+ function compareIsoTimestamp(left, right) {
3607
+ const leftTime = Date.parse(left);
3608
+ const rightTime = Date.parse(right);
3609
+ if (!Number.isFinite(leftTime) || !Number.isFinite(rightTime)) return left.localeCompare(right);
3610
+ return leftTime - rightTime;
3611
+ }
3612
+ function mergeSessionActivityPreview(current, incoming) {
3613
+ if (current && compareIsoTimestamp(incoming.timestamp, current.timestamp) < 0) return incoming.replyText && !current.replyText ? {
3614
+ ...current,
3615
+ replyText: incoming.replyText
3616
+ } : current;
3617
+ return {
3618
+ state: incoming.state,
3619
+ timestamp: incoming.timestamp,
3620
+ ...incoming.statusText ?? (incoming.state === "completed" ? current?.statusText : void 0) ? { statusText: incoming.statusText ?? current?.statusText } : {},
3621
+ ...incoming.replyText ?? (incoming.state === "completed" ? current?.replyText : void 0) ? { replyText: incoming.replyText ?? current?.replyText } : {}
3622
+ };
3623
+ }
3624
+ function areSessionActivityPreviewsEqual(left, right) {
3625
+ return Boolean(left) && left?.state === right.state && left.timestamp === right.timestamp && left.statusText === right.statusText && left.replyText === right.replyText;
3626
+ }
3627
+ function writeSessionActivityPreviewMetadata(metadata, projection) {
3628
+ const current = readSessionActivityPreviewMetadata(metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY]);
3629
+ const next = mergeSessionActivityPreview(current, projection.preview);
3630
+ if (areSessionActivityPreviewsEqual(current, next)) return null;
3631
+ return {
3632
+ ...metadata ?? {},
3633
+ [SESSION_ACTIVITY_PREVIEW_METADATA_KEY]: next
3634
+ };
3635
+ }
3636
+ //#endregion
3637
+ //#region src/contributions/session-activity-preview/services/session-activity-preview-event.service.ts
3638
+ var SessionActivityPreviewEventService = class {
3639
+ toolNames = /* @__PURE__ */ new Map();
3640
+ constructor(options) {
3641
+ this.options = options;
3642
+ }
3643
+ projectEvent = (event, timestamp) => {
3644
+ this.rememberToolName(event);
3645
+ const projection = createSessionActivityPreviewFromNcpEvent(event, timestamp, { readToolName: this.readToolName });
3646
+ this.clearFinishedRunToolNames(event);
3647
+ return projection;
3648
+ };
3649
+ updatePreview = async (projection) => {
3650
+ const session = await this.options.getSessionRecord(projection.sessionId);
3651
+ const replyText = projection.preview.replyText ?? (projection.preview.state === "completed" ? this.readLatestAssistantPreviewText(session?.messages) : void 0);
3652
+ const nextMetadata = writeSessionActivityPreviewMetadata(session?.metadata, {
3653
+ ...projection,
3654
+ preview: {
3655
+ ...projection.preview,
3656
+ replyText
3657
+ }
3658
+ });
3659
+ if (nextMetadata) await this.options.updateSessionMetadata(projection.sessionId, nextMetadata);
3660
+ };
3661
+ clear = () => {
3662
+ this.toolNames.clear();
3663
+ };
3664
+ rememberToolName = (event) => {
3665
+ if (event.type !== NcpEventType.MessageToolCallStart) return;
3666
+ const { sessionId, toolCallId, toolName } = event.payload;
3667
+ if (sessionId && toolCallId && toolName) this.toolNames.set(this.createToolNameKey(sessionId, toolCallId), toolName);
3668
+ };
3669
+ readToolName = (sessionId, toolCallId) => this.toolNames.get(this.createToolNameKey(sessionId, toolCallId)) ?? null;
3670
+ clearFinishedRunToolNames = (event) => {
3671
+ if (event.type !== NcpEventType.RunFinished && event.type !== NcpEventType.RunError) return;
3672
+ const sessionId = event.payload.sessionId;
3673
+ for (const key of this.toolNames.keys()) if (key.startsWith(`${sessionId}:`)) this.toolNames.delete(key);
3674
+ };
3675
+ createToolNameKey = (sessionId, toolCallId) => `${sessionId}:${toolCallId}`;
3676
+ readLatestAssistantPreviewText = (messages) => {
3677
+ for (let index = (messages?.length ?? 0) - 1; index >= 0; index -= 1) {
3678
+ const message = messages?.[index];
3679
+ if (message?.role === "assistant") return readSessionActivityPreviewText(message) ?? void 0;
3680
+ }
3681
+ };
3682
+ };
3683
+ //#endregion
3684
+ //#region src/services/session-event-ingestion.service.ts
3685
+ const SESSION_METADATA_PATCH_RUN_METADATA_KIND = "session_metadata_patch";
3686
+ function isDurableSessionEvent(event) {
3687
+ return event.type !== NcpEventType.ContextWindowUpdated;
3688
+ }
3689
+ function readRuntimeSessionMetadataPatch(event) {
3690
+ if (event.type !== NcpEventType.RunMetadata) return null;
3691
+ const metadata = event.payload.metadata;
3692
+ if (metadata.kind !== SESSION_METADATA_PATCH_RUN_METADATA_KIND || !metadata.sessionMetadataPatch || typeof metadata.sessionMetadataPatch !== "object" || Array.isArray(metadata.sessionMetadataPatch)) return null;
3693
+ const patch = metadata.sessionMetadataPatch;
3694
+ return Object.keys(patch).length > 0 ? structuredClone(patch) : null;
3695
+ }
3696
+ var SessionEventIngestionService = class {
3697
+ activityPreview;
3698
+ chains = /* @__PURE__ */ new Map();
3699
+ constructor(options) {
3700
+ this.options = options;
3701
+ this.activityPreview = new SessionActivityPreviewEventService({
3702
+ getSessionRecord: options.getSessionRecord,
3703
+ updateSessionMetadata: options.updateSessionMetadata
3704
+ });
3705
+ }
3706
+ handleEvent = (event) => {
3707
+ const sessionId = readEventSessionId$1(event);
3708
+ if (!sessionId || !isDurableSessionEvent(event)) return;
3709
+ const next = (this.chains.get(sessionId) ?? Promise.resolve()).then(() => this.handleDurableEvent(sessionId, event));
3710
+ this.chains.set(sessionId, next.catch(() => void 0));
3711
+ next.catch((error) => this.options.onError(sessionId, error));
3712
+ };
3713
+ clear = () => {
3714
+ this.chains.clear();
3715
+ this.activityPreview.clear();
3716
+ };
3717
+ handleDurableEvent = async (sessionId, event) => {
3718
+ const preview = this.activityPreview.projectEvent(event, (/* @__PURE__ */ new Date()).toISOString());
3719
+ const metadataPatch = readRuntimeSessionMetadataPatch(event);
3720
+ if (metadataPatch) {
3721
+ await this.options.updateSessionMetadata(sessionId, metadataPatch);
3722
+ return;
3723
+ }
3724
+ await this.options.appendSessionEvent({
3725
+ event,
3726
+ sessionId
3727
+ });
3728
+ if (preview) await this.activityPreview.updatePreview(preview);
3729
+ };
3730
+ };
3731
+ //#endregion
3732
+ //#region src/services/session-working-dir-resolver.service.ts
3733
+ var SessionWorkingDirResolver = class {
3734
+ constructor(agentManager) {
3735
+ this.agentManager = agentManager;
3736
+ }
3737
+ withWorkingDir = (summary) => ({
3738
+ ...summary,
3739
+ workingDir: this.resolve({
3740
+ agentId: summary.agentId,
3741
+ metadata: summary.metadata
3742
+ })
3743
+ });
3744
+ resolve = (params) => {
3745
+ const profile = this.agentManager.resolveAgentProfile(readOptionalString$8(params.agentId));
3746
+ return resolveSessionWorkspacePath({
3747
+ sessionMetadata: params.metadata,
3748
+ workspace: profile.workspace
3749
+ });
3750
+ };
3751
+ };
3752
+ //#endregion
3753
+ //#region src/managers/session.manager.ts
3754
+ const DEFAULT_SESSION_TYPE = "native";
3755
+ const DEFAULT_LIFECYCLE = "persistent";
3756
+ const SESSION_METADATA_LABEL_KEY = "label";
3757
+ const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3758
+ const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3759
+ const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3760
+ function readThinkingEffort(metadata) {
3761
+ return readOptionalMetadataString(metadata?.thinkingEffort) ?? null;
3762
+ }
3763
+ function readProjectRoot(metadata) {
3278
3764
  return readOptionalMetadataString(metadata?.project_root) ?? readOptionalMetadataString(metadata?.projectRoot);
3279
3765
  }
3280
3766
  function summarizeTask(task) {
@@ -3308,7 +3794,7 @@ function mergeMetadataOverrides(metadata, overrides) {
3308
3794
  }
3309
3795
  function resolveSessionType(params) {
3310
3796
  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;
3797
+ return readOptionalString$8(runtime) ?? readOptionalString$8(metadata.runtime) ?? readOptionalString$8(sessionType) ?? readOptionalString$8(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
3312
3798
  }
3313
3799
  function applySessionOverrides(params) {
3314
3800
  const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
@@ -3318,15 +3804,15 @@ function applySessionOverrides(params) {
3318
3804
  metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
3319
3805
  if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
3320
3806
  if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
3321
- if (readOptionalString$7(model)) {
3807
+ if (readOptionalString$8(model)) {
3322
3808
  metadata.model = model?.trim();
3323
3809
  metadata.preferred_model = model?.trim();
3324
3810
  }
3325
- if (readOptionalString$7(thinkingLevel)) {
3811
+ if (readOptionalString$8(thinkingLevel)) {
3326
3812
  metadata.thinking = thinkingLevel?.trim();
3327
3813
  metadata.preferred_thinking = thinkingLevel?.trim();
3328
3814
  }
3329
- if (readOptionalString$7(projectRoot)) metadata.project_root = projectRoot?.trim();
3815
+ if (readOptionalString$8(projectRoot)) metadata.project_root = projectRoot?.trim();
3330
3816
  }
3331
3817
  function isSessionSummaryRefreshEvent(event) {
3332
3818
  switch (event.type) {
@@ -3341,36 +3827,40 @@ function isSessionSummaryRefreshEvent(event) {
3341
3827
  var SessionManager = class {
3342
3828
  cleanups = [];
3343
3829
  contextWindowPreview;
3830
+ eventIngestion;
3344
3831
  workingDirResolver;
3345
3832
  started = false;
3346
3833
  constructor(options) {
3347
3834
  this.options = options;
3348
- this.contextWindowPreview = new ContextWindowPreviewManager({ configManager: options.configManager });
3349
- this.workingDirResolver = new SessionWorkingDirResolver(options.configManager);
3835
+ this.eventIngestion = new SessionEventIngestionService({
3836
+ appendSessionEvent: (params) => this.appendSessionEvent(params),
3837
+ getSessionRecord: (sessionId) => this.getSessionRecord(sessionId),
3838
+ onError: (sessionId, error) => {
3839
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
3840
+ console.error(`[session-manager] failed to handle ncp event for ${sessionId}: ${message}`);
3841
+ },
3842
+ updateSessionMetadata: (sessionId, metadata) => this.updateSessionMetadata(sessionId, metadata)
3843
+ });
3844
+ this.contextWindowPreview = new ContextWindowPreviewManager(options.agentManager);
3845
+ this.workingDirResolver = new SessionWorkingDirResolver(options.agentManager);
3350
3846
  }
3351
3847
  start = () => {
3352
3848
  if (this.started) return;
3353
3849
  this.started = true;
3354
- this.cleanups.push(this.options.eventBus.on(eventKeys.ncpEvent, async (event) => {
3355
- const sessionId = readEventSessionId$1(event);
3356
- if (!sessionId || !isDurableSessionEvent(event)) return;
3357
- await this.appendSessionEvent({
3358
- event,
3359
- sessionId
3360
- });
3361
- }));
3850
+ this.cleanups.push(this.options.eventBus.on(eventKeys.ncpEvent, this.eventIngestion.handleEvent));
3362
3851
  };
3363
3852
  dispose = () => {
3364
3853
  while (this.cleanups.length > 0) this.cleanups.pop()?.();
3854
+ this.eventIngestion.clear();
3365
3855
  this.started = false;
3366
3856
  };
3367
3857
  createSession = async (params) => {
3368
3858
  const { agentId: requestedAgentId, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
3369
3859
  const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
3370
3860
  const metadata = cloneInheritedMetadata(sourceSessionMetadata);
3371
- const title = readOptionalString$7(requestedTitle) ?? summarizeTask(task);
3372
- const parentSessionId = readOptionalString$7(rawParentSessionId);
3373
- const requestId = readOptionalString$7(rawRequestId);
3861
+ const title = readOptionalString$8(requestedTitle) ?? summarizeTask(task);
3862
+ const parentSessionId = readOptionalString$8(rawParentSessionId);
3863
+ const requestId = readOptionalString$8(rawRequestId);
3374
3864
  const sessionType = resolveSessionType({
3375
3865
  runtime,
3376
3866
  sessionType: requestedSessionType,
@@ -3389,8 +3879,8 @@ var SessionManager = class {
3389
3879
  });
3390
3880
  const now = (/* @__PURE__ */ new Date()).toISOString();
3391
3881
  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();
3882
+ const agentId = readOptionalString$8(requestedAgentId) ?? readOptionalString$8(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
3883
+ const sessionId = readOptionalString$8(requestedSessionId) ?? buildSessionId();
3394
3884
  const record = {
3395
3885
  sessionId,
3396
3886
  ...agentId ? { agentId } : {},
@@ -3463,7 +3953,7 @@ var SessionManager = class {
3463
3953
  return await this.options.journalStore.getSession(normalizedSessionId);
3464
3954
  };
3465
3955
  listSessions = async (options) => {
3466
- const peerId = readOptionalString$7(options?.peerId);
3956
+ const peerId = readOptionalString$8(options?.peerId);
3467
3957
  return applyLimit((await this.options.journalStore.listSessionSummaries()).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), options?.limit);
3468
3958
  };
3469
3959
  listSessionMessages = async (sessionId, options) => {
@@ -3490,20 +3980,24 @@ var SessionManager = class {
3490
3980
  metadata: structuredClone(record.metadata ?? {}),
3491
3981
  model,
3492
3982
  projectRoot: readProjectRoot(record.metadata),
3983
+ workingDir: this.workingDirResolver.resolve({
3984
+ agentId: record.agentId,
3985
+ metadata: record.metadata
3986
+ }),
3493
3987
  thinkingEffort: readThinkingEffort(record.metadata)
3494
3988
  };
3495
3989
  };
3496
3990
  createAgentRunSession = async (params) => {
3497
3991
  const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, metadata, model, peerId: rawPeerId, projectRoot, sessionId, task, thinkingEffort } = params;
3498
3992
  const agentRuntimeId = requestedAgentRuntimeId ?? "native";
3499
- const peerId = readOptionalString$7(rawPeerId);
3993
+ const peerId = readOptionalString$8(rawPeerId);
3500
3994
  const peerIdentity = peerId ? createAgentPeerSessionIdentity({
3501
3995
  agentId,
3502
3996
  channel,
3503
3997
  metadata,
3504
3998
  peerId
3505
3999
  }) : void 0;
3506
- const requestedSessionId = readOptionalString$7(sessionId);
4000
+ const requestedSessionId = readOptionalString$8(sessionId);
3507
4001
  const created = await this.createSession({
3508
4002
  sourceSessionMetadata: {},
3509
4003
  sessionId: requestedSessionId ?? peerIdentity?.sessionId,
@@ -3526,6 +4020,10 @@ var SessionManager = class {
3526
4020
  metadata: structuredClone(created.metadata ?? {}),
3527
4021
  model,
3528
4022
  projectRoot,
4023
+ workingDir: this.workingDirResolver.resolve({
4024
+ agentId,
4025
+ metadata: created.metadata
4026
+ }),
3529
4027
  thinkingEffort: thinkingEffort ?? null
3530
4028
  };
3531
4029
  };
@@ -4522,10 +5020,10 @@ function parsePanelAppFolderManifest(raw) {
4522
5020
  if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
4523
5021
  return {
4524
5022
  id,
4525
- title: readRequiredString$3(parsed, "title"),
5023
+ title: readRequiredString$4(parsed, "title"),
4526
5024
  description: readOptionalString$6(parsed, "description"),
4527
5025
  icon: readOptionalString$6(parsed, "icon"),
4528
- entry: readRequiredString$3(parsed, "entry"),
5026
+ entry: readRequiredString$4(parsed, "entry"),
4529
5027
  capabilities: readStringArray$1(parsed.capabilities, "capabilities"),
4530
5028
  client: readOptionalBoolean$2(parsed, "client"),
4531
5029
  serviceActions: readStringArray$1(parsed.actions, "actions")
@@ -4585,7 +5083,7 @@ function parseTokenList(content) {
4585
5083
  if (!content) return [];
4586
5084
  return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
4587
5085
  }
4588
- function readRequiredString$3(record, key) {
5086
+ function readRequiredString$4(record, key) {
4589
5087
  const value = readOptionalString$6(record, key);
4590
5088
  if (!value) throw new Error(`panel app ${key} is required.`);
4591
5089
  return value;
@@ -5371,17 +5869,17 @@ function parseServiceAppManifest(raw) {
5371
5869
  throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
5372
5870
  }
5373
5871
  if (!isRecord$4(parsed)) throw new Error("service-app.json must contain an object.");
5374
- const id = readRequiredString$2(parsed, "id");
5872
+ const id = readRequiredString$3(parsed, "id");
5375
5873
  if (!SERVICE_APP_ID_PATTERN.test(id)) throw new Error("service app id must be kebab-case.");
5376
5874
  const protocol = readOptionalString$5(parsed, "protocol") ?? "mcp";
5377
5875
  if (protocol !== "mcp") throw new Error("service app protocol must be mcp.");
5378
5876
  return {
5379
5877
  id,
5380
- title: readRequiredString$2(parsed, "title"),
5878
+ title: readRequiredString$3(parsed, "title"),
5381
5879
  description: readOptionalString$5(parsed, "description"),
5382
5880
  enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
5383
5881
  protocol,
5384
- command: readRequiredString$2(parsed, "command"),
5882
+ command: readRequiredString$3(parsed, "command"),
5385
5883
  args: readStringArray(parsed.args, "args"),
5386
5884
  actions: readManifestActions(parsed.actions)
5387
5885
  };
@@ -5407,7 +5905,7 @@ function readManifestActions(value) {
5407
5905
  }
5408
5906
  return actions;
5409
5907
  }
5410
- function readRequiredString$2(record, key) {
5908
+ function readRequiredString$3(record, key) {
5411
5909
  const value = readOptionalString$5(record, key);
5412
5910
  if (!value) throw new Error(`service app ${key} is required.`);
5413
5911
  return value;
@@ -5822,12 +6320,12 @@ function parseSkillFrontmatter(raw) {
5822
6320
  const summaryI18n = readLocalizedTextMap(parsed, "summaryi18n", "summary_i18n");
5823
6321
  const descriptionI18n = readLocalizedTextMap(parsed, "descriptioni18n", "description_i18n");
5824
6322
  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"),
6323
+ name: readString$3(parsed, "name"),
6324
+ summary: readString$3(parsed, "summary"),
6325
+ summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$3(parsed, "summaryzh", "summary_zh") }),
6326
+ description: readString$3(parsed, "description"),
6327
+ descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$3(parsed, "descriptionzh", "description_zh") }),
6328
+ author: readString$3(parsed, "author"),
5831
6329
  tags: readTags(parsed)
5832
6330
  };
5833
6331
  }
@@ -5854,7 +6352,7 @@ function parseYamlFrontmatter(raw) {
5854
6352
  throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
5855
6353
  }
5856
6354
  }
5857
- function readString$4(record, ...names) {
6355
+ function readString$3(record, ...names) {
5858
6356
  const value = readValue(record, names);
5859
6357
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
5860
6358
  }
@@ -6050,7 +6548,7 @@ var NcpAgentSessionMetadataStore = class {
6050
6548
  read = async (sessionId, activitySnapshot) => {
6051
6549
  try {
6052
6550
  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}`);
6551
+ if (!isRecord$11(parsed) || parsed._type !== "metadata" || !isRecord$11(parsed.metadata)) throw new Error(`invalid ncp agent session metadata sidecar: ${sessionId}`);
6054
6552
  const createdAt = toIsoString(parsed.created_at, activitySnapshot.createdAt);
6055
6553
  const agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
6056
6554
  return {
@@ -6151,11 +6649,11 @@ var NcpAgentSessionSummaryIndexStore = class {
6151
6649
  function serializeJournalEntry(entry) {
6152
6650
  const serialized = JSON.stringify(entry);
6153
6651
  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");
6652
+ if (!isRecord$11(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
6155
6653
  return serialized;
6156
6654
  }
6157
6655
  function attachJournalTimestamp(event, timestamp) {
6158
- if (!("payload" in event) || !isRecord$10(event.payload)) return event;
6656
+ if (!("payload" in event) || !isRecord$11(event.payload)) return event;
6159
6657
  return {
6160
6658
  ...event,
6161
6659
  payload: {
@@ -6379,15 +6877,15 @@ var NcpAgentSessionJournalStore = class {
6379
6877
  console.warn(`[ncp-agent-session-journal] skipped corrupted journal line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
6380
6878
  continue;
6381
6879
  }
6382
- if (!isRecord$10(parsed)) continue;
6880
+ if (!isRecord$11(parsed)) continue;
6383
6881
  if (parsed._type === "metadata") {
6384
- metadata = isRecord$10(parsed.metadata) ? structuredClone(parsed.metadata) : {};
6882
+ metadata = isRecord$11(parsed.metadata) ? structuredClone(parsed.metadata) : {};
6385
6883
  agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
6386
6884
  createdAt = toIsoString(parsed.created_at, createdAt);
6387
6885
  updatedAt = toIsoString(parsed.updated_at, updatedAt);
6388
6886
  continue;
6389
6887
  }
6390
- if (parsed._type === "event" && isRecord$10(parsed.event)) {
6888
+ if (parsed._type === "event" && isRecord$11(parsed.event)) {
6391
6889
  const seq = Number(parsed.seq);
6392
6890
  nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
6393
6891
  const eventTimestamp = toIsoString(parsed.timestamp, updatedAt);
@@ -6701,21 +7199,20 @@ const NARP_API_MODE_HEADER = "x-nextclaw-narp-api-mode";
6701
7199
  const NARP_HTTP_RUNTIME_KIND = "narp-http";
6702
7200
  const NARP_STDIO_RUNTIME_KIND = "narp-stdio";
6703
7201
  const BUILTIN_PROVIDER_REGISTRY = new ProviderRegistry(BUILTIN_PROVIDER_PLUGINS);
6704
- function readRecord$1(value) {
7202
+ function readRecord(value) {
6705
7203
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
6706
7204
  return value;
6707
7205
  }
6708
- function readString$3(value) {
7206
+ function readString$2(value) {
6709
7207
  if (typeof value !== "string") return;
6710
7208
  return value.trim() || void 0;
6711
7209
  }
6712
- function resolveEntryIcon(entry) {
6713
- return entry.icon ?? null;
6714
- }
6715
7210
  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;
7211
+ const { configuredModel, defaultModel, input, modelSelectionMode, sessionMetadata } = params;
7212
+ if (modelSelectionMode === "runtime-default") return;
7213
+ 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);
7214
+ if (isRuntimeDefaultModelValue(requestedModel)) return;
7215
+ return requestedModel ?? configuredModel ?? (modelSelectionMode === "optional" ? void 0 : defaultModel);
6719
7216
  }
6720
7217
  function resolveProviderApiMode(resolution) {
6721
7218
  const wireApi = resolution.provider?.wireApi?.trim().toLowerCase();
@@ -6762,8 +7259,14 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6762
7259
  };
6763
7260
  describeInternal = async () => {
6764
7261
  const config = new HttpRuntimeConfigResolver(this.entry.config ?? {}).resolve({ defaultModel: this.defaultModel });
7262
+ const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
7263
+ const baseDescriptor = {
7264
+ icon: this.entry.icon ?? null,
7265
+ modelSelectionMode,
7266
+ runtimeDefaultThinking: normalizeModelThinkingCapability(this.entry.config?.runtimeDefaultThinking)
7267
+ };
6765
7268
  if (!config.baseUrl) return {
6766
- icon: resolveEntryIcon(this.entry),
7269
+ ...baseDescriptor,
6767
7270
  ready: false,
6768
7271
  reason: "base_url_missing",
6769
7272
  reasonMessage: "Configure the runtime entry baseUrl before starting an HTTP runtime session.",
@@ -6774,7 +7277,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6774
7277
  }
6775
7278
  };
6776
7279
  if (!((config.capabilityProbe ?? true) && Boolean(config.healthcheckUrl))) return {
6777
- icon: resolveEntryIcon(this.entry),
7280
+ ...baseDescriptor,
6778
7281
  ready: true,
6779
7282
  reason: null,
6780
7283
  reasonMessage: null,
@@ -6792,7 +7295,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6792
7295
  signal: controller.signal
6793
7296
  });
6794
7297
  if (!response.ok) return {
6795
- icon: resolveEntryIcon(this.entry),
7298
+ ...baseDescriptor,
6796
7299
  ready: false,
6797
7300
  reason: "healthcheck_failed",
6798
7301
  reasonMessage: `HTTP runtime healthcheck returned HTTP ${response.status}.`,
@@ -6801,7 +7304,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6801
7304
  cta: null
6802
7305
  };
6803
7306
  return {
6804
- icon: resolveEntryIcon(this.entry),
7307
+ ...baseDescriptor,
6805
7308
  ready: true,
6806
7309
  reason: null,
6807
7310
  reasonMessage: null,
@@ -6811,7 +7314,7 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6811
7314
  };
6812
7315
  } catch (error) {
6813
7316
  return {
6814
- icon: resolveEntryIcon(this.entry),
7317
+ ...baseDescriptor,
6815
7318
  ready: false,
6816
7319
  reason: "healthcheck_unreachable",
6817
7320
  reasonMessage: error instanceof Error ? error.message : "Failed to reach the configured HTTP runtime healthcheck.",
@@ -6843,10 +7346,16 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6843
7346
  };
6844
7347
  describeInternal = async (describeMode) => {
6845
7348
  const resolver = new StdioRuntimeConfigResolver(this.entry.config ?? {});
7349
+ const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
7350
+ const baseDescriptor = {
7351
+ icon: this.entry.icon ?? null,
7352
+ modelSelectionMode,
7353
+ runtimeDefaultThinking: normalizeModelThinkingCapability(this.entry.config?.runtimeDefaultThinking)
7354
+ };
6846
7355
  try {
6847
7356
  const config = resolver.resolve();
6848
7357
  if (!await resolveExecutablePath(config.command)) return {
6849
- icon: resolveEntryIcon(this.entry),
7358
+ ...baseDescriptor,
6850
7359
  ready: false,
6851
7360
  reason: "command_missing",
6852
7361
  reasonMessage: `Configured stdio command "${config.command}" is not available. Update the runtime entry command or install the required launcher first.`,
@@ -6859,7 +7368,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6859
7368
  await probeStdioRuntime(config);
6860
7369
  } catch (error) {
6861
7370
  return {
6862
- icon: resolveEntryIcon(this.entry),
7371
+ ...baseDescriptor,
6863
7372
  ready: false,
6864
7373
  reason: "probe_failed",
6865
7374
  reasonMessage: error instanceof Error ? error.message : "Configured stdio runtime could not complete the ACP probe.",
@@ -6870,7 +7379,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6870
7379
  };
6871
7380
  }
6872
7381
  return {
6873
- icon: resolveEntryIcon(this.entry),
7382
+ ...baseDescriptor,
6874
7383
  ready: true,
6875
7384
  reason: null,
6876
7385
  reasonMessage: null,
@@ -6878,7 +7387,7 @@ var BuiltinStdioRuntimeSessionTypeService = class {
6878
7387
  };
6879
7388
  } catch (error) {
6880
7389
  return {
6881
- icon: resolveEntryIcon(this.entry),
7390
+ ...baseDescriptor,
6882
7391
  ready: false,
6883
7392
  reason: "command_missing",
6884
7393
  reasonMessage: error instanceof Error ? error.message : "Configure a stdio command before starting this runtime.",
@@ -6932,7 +7441,7 @@ var BuiltinNarpRuntimeProviderService = class {
6932
7441
  throw new Error("[narp] runtime entry is required before creating this runtime");
6933
7442
  };
6934
7443
  createHttpRuntime = (entry, runtimeParams) => {
6935
- const config = readRecord$1(entry.config) ?? {};
7444
+ const config = readRecord(entry.config) ?? {};
6936
7445
  const resolver = new HttpRuntimeConfigResolver(config);
6937
7446
  const resolvedConfig = resolver.resolve({ defaultModel: this.configManager.loadConfig().agents.defaults.model });
6938
7447
  return new HttpRuntimeNcpAgentRuntime({
@@ -6947,15 +7456,15 @@ var BuiltinNarpRuntimeProviderService = class {
6947
7456
  input,
6948
7457
  sessionMetadata: runtimeParams.sessionMetadata,
6949
7458
  defaultModel: this.configManager.loadConfig().agents.defaults.model,
6950
- configuredModel: readString$3(config.model)
7459
+ configuredModel: readString$2(config.model),
7460
+ modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
6951
7461
  })
6952
7462
  });
6953
7463
  };
6954
7464
  createStdioRuntime = (entry, runtimeParams) => {
6955
- const config = readRecord$1(entry.config) ?? {};
7465
+ const config = readRecord(entry.config) ?? {};
6956
7466
  return new StdioRuntimeNcpAgentRuntime({
6957
7467
  ...new StdioRuntimeConfigResolver(config).resolve(),
6958
- sessionId: runtimeParams.sessionId,
6959
7468
  resolveTools: runtimeParams.resolveTools,
6960
7469
  stateManager: runtimeParams.stateManager,
6961
7470
  resolveProviderRoute: (input) => buildProviderRoute({
@@ -6963,7 +7472,8 @@ var BuiltinNarpRuntimeProviderService = class {
6963
7472
  input,
6964
7473
  sessionMetadata: runtimeParams.sessionMetadata,
6965
7474
  defaultModel: this.configManager.loadConfig().agents.defaults.model,
6966
- configuredModel: readString$3(config.model)
7475
+ configuredModel: readString$2(config.model),
7476
+ modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
6967
7477
  })
6968
7478
  });
6969
7479
  };
@@ -7256,10 +7766,16 @@ function resolveEffectiveModel(params) {
7256
7766
  const metadata = structuredClone(params.sessionMetadata);
7257
7767
  if (requestMetadata.clear_model === true || requestMetadata.reset_model === true) delete metadata.preferred_model;
7258
7768
  const inboundModel = readMetadataModel(requestMetadata);
7259
- if (inboundModel) metadata.preferred_model = inboundModel;
7769
+ if (inboundModel && isRuntimeDefaultModelValue(inboundModel)) {
7770
+ delete metadata.preferred_model;
7771
+ delete metadata.model;
7772
+ } else if (inboundModel) {
7773
+ metadata.preferred_model = inboundModel;
7774
+ metadata.model = inboundModel;
7775
+ }
7260
7776
  return {
7261
7777
  metadata,
7262
- model: normalizeOptionalString(metadata.preferred_model) ?? fallbackModel
7778
+ model: (isRuntimeDefaultModelValue(metadata.preferred_model) ? void 0 : normalizeOptionalString(metadata.preferred_model)) ?? fallbackModel
7263
7779
  };
7264
7780
  }
7265
7781
  function syncSessionThinkingPreference(params) {
@@ -7290,30 +7806,6 @@ function resolveSessionChannelContext(params) {
7290
7806
  //#endregion
7291
7807
  //#region src/features/native-runtime/utils/nextclaw-ncp-run-context.utils.ts
7292
7808
  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
7809
  function resolveRequestedToolNames(metadata) {
7318
7810
  const rawValue = metadata.requested_tools ?? metadata.requestedTools;
7319
7811
  if (!Array.isArray(rawValue)) return [];
@@ -7326,17 +7818,15 @@ function mergeRunMetadata(params) {
7326
7818
  ...requestMetadata ? structuredClone(requestMetadata) : {}
7327
7819
  };
7328
7820
  }
7329
- function resolveNextclawNcpRunContext(params) {
7330
- const { configManager, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata, storedAgentId } = params;
7331
- const config = configManager.loadConfig();
7821
+ function buildNextclawNcpRunContext(params) {
7822
+ const { agentProfile, config, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata } = params;
7332
7823
  const requestMetadata = mergeRunMetadata({
7333
7824
  sessionMetadata: inputSessionMetadata,
7334
7825
  requestMetadata: inputRequestMetadata
7335
7826
  });
7336
- const profile = resolveAgentProfile({
7827
+ const profile = buildResolvedAgentProfile({
7337
7828
  config,
7338
- storedAgentId,
7339
- requestMetadata
7829
+ profile: agentProfile
7340
7830
  });
7341
7831
  const { metadata: modelMetadata, model: effectiveModel } = resolveEffectiveModel({
7342
7832
  sessionMetadata: requestMetadata,
@@ -7387,213 +7877,20 @@ function resolveNextclawNcpRunContext(params) {
7387
7877
  }
7388
7878
  };
7389
7879
  }
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) {
7398
- 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) ?? {};
7880
+ function buildResolvedAgentProfile(params) {
7881
+ const { config, profile } = params;
7882
+ const { search: searchConfig, tools: { restrictToWorkspace, exec: { timeout: execTimeoutSeconds } } } = config;
7450
7883
  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()]
7884
+ agentId: profile.id,
7885
+ workspace: getWorkspacePath(profile.workspace),
7886
+ model: profile.model,
7887
+ contextTokens: profile.contextTokens,
7888
+ reservedContextTokens: profile.reservedContextTokens,
7889
+ restrictToWorkspace,
7890
+ searchConfig,
7891
+ execTimeoutSeconds
7479
7892
  };
7480
7893
  }
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
7894
  //#endregion
7598
7895
  //#region src/services/agent-run-message-projector.service.ts
7599
7896
  var AgentRunMessageProjector = class {
@@ -7606,22 +7903,15 @@ var AgentRunMessageProjector = class {
7606
7903
  //#region src/services/agent-run-model-input-budgeter.service.ts
7607
7904
  var AgentRunModelInputBudgeter = class {
7608
7905
  inputBudgetPruner = new InputBudgetPruner();
7609
- constructor(configManager) {
7610
- this.configManager = configManager;
7906
+ constructor(agentManager) {
7907
+ this.agentManager = agentManager;
7611
7908
  }
7612
7909
  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
- });
7910
+ const profile = this.agentManager.resolveAgentProfile(params.spec.agentId);
7621
7911
  const pruned = this.inputBudgetPruner.prune({
7622
7912
  messages: params.messages.map((message) => ({ ...message })),
7623
- contextTokens,
7624
- reserveTokensFloor: reservedContextTokens,
7913
+ contextTokens: profile.contextTokens,
7914
+ reserveTokensFloor: profile.reservedContextTokens,
7625
7915
  softThresholdTokens: 0
7626
7916
  });
7627
7917
  return {
@@ -7685,7 +7975,8 @@ var NcpAgentRuntimeWrapper = class {
7685
7975
  runId: spec.runId,
7686
7976
  messages,
7687
7977
  correlationId: spec.correlationId,
7688
- metadata: this.buildMetadata(spec)
7978
+ metadata: this.buildMetadata(options.session, spec),
7979
+ executionContext: { cwd: options.session.workingDir }
7689
7980
  };
7690
7981
  for await (const event of this.getRuntime().run(input, { signal: options.signal })) yield await this.applyEvent(sessionRun, event);
7691
7982
  this.currentTools = [];
@@ -7710,10 +8001,10 @@ var NcpAgentRuntimeWrapper = class {
7710
8001
  correlationId: spec.correlationId
7711
8002
  }
7712
8003
  }));
7713
- buildMetadata = (spec) => ({
7714
- ...this.params.session.metadata,
8004
+ buildMetadata = (session, spec) => ({
8005
+ ...session.metadata,
7715
8006
  agentId: spec.agentId,
7716
- agentRuntimeId: this.params.session.agentRuntimeId,
8007
+ agentRuntimeId: session.agentRuntimeId,
7717
8008
  maxTokens: spec.maxTokens,
7718
8009
  model: spec.model,
7719
8010
  preferred_model: spec.model,
@@ -7736,18 +8027,22 @@ var AgentRunRuntimeContribution = class {
7736
8027
  modelInputBuilder;
7737
8028
  constructor(kernel) {
7738
8029
  this.kernel = kernel;
7739
- this.modelInputBuilder = new AgentRunModelInputBuilder(new AgentRunMessageProjector(), new AgentRunModelInputBudgeter(kernel.configManager), kernel.assetStore);
8030
+ this.modelInputBuilder = new AgentRunModelInputBuilder(new AgentRunMessageProjector(), new AgentRunModelInputBudgeter(kernel.agents), kernel.assetStore);
7740
8031
  }
7741
8032
  start = () => {
7742
8033
  if (this.cleanups.length > 0) return;
7743
- const { entries } = resolveAgentRuntimeEntries({ config: this.kernel.configManager.loadConfig() });
7744
- this.kernel.agentRuntimeManager.applyEntries(entries);
8034
+ this.applyRuntimeConfig(this.kernel.configManager.loadConfig());
8035
+ this.kernel.configManager.installRuntimeHooks({ applyAgentRuntimeConfig: this.applyRuntimeConfig });
7745
8036
  this.cleanups.push(this.registerNativeRuntime());
7746
8037
  for (const provider of new BuiltinNarpRuntimeProviderService(this.kernel.configManager).createProviders()) this.cleanups.push(this.registerNarpRuntime(provider));
7747
8038
  };
7748
8039
  dispose = async () => {
7749
8040
  while (this.cleanups.length > 0) await this.cleanups.pop()?.();
7750
8041
  };
8042
+ applyRuntimeConfig = (config) => {
8043
+ const { entries } = resolveAgentRuntimeEntries({ config });
8044
+ this.kernel.agentRuntimeManager.applyEntries(entries);
8045
+ };
7751
8046
  registerNativeRuntime = () => this.kernel.agentRuntimeManager.register({
7752
8047
  kind: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
7753
8048
  label: "Native",
@@ -7773,20 +8068,16 @@ var AgentRunRuntimeContribution = class {
7773
8068
  describeSessionTypeForEntry: provider.describeSessionTypeForEntry,
7774
8069
  createRuntime: ({ entry, session }) => {
7775
8070
  if (!provider.createRuntimeForEntry) throw new Error(`Agent runtime provider does not support entries: ${provider.kind}`);
7776
- return new NcpAgentRuntimeWrapper({
7777
- session,
7778
- createRuntime: ({ resolveTools, stateManager }) => provider.createRuntimeForEntry({
7779
- entry,
7780
- runtimeParams: {
7781
- sessionId: session.sessionId,
7782
- ...session.agentId ? { agentId: session.agentId } : {},
7783
- resolveAssetContentPath: (assetUri) => this.kernel.assetStore.resolveContentPath(assetUri),
7784
- resolveTools,
7785
- sessionMetadata: session.metadata,
7786
- stateManager
7787
- }
7788
- })
7789
- });
8071
+ return new NcpAgentRuntimeWrapper({ createRuntime: ({ resolveTools, stateManager }) => provider.createRuntimeForEntry({
8072
+ entry,
8073
+ runtimeParams: {
8074
+ ...session.agentId ? { agentId: session.agentId } : {},
8075
+ resolveAssetContentPath: (assetUri) => this.kernel.assetStore.resolveContentPath(assetUri),
8076
+ resolveTools,
8077
+ sessionMetadata: session.metadata,
8078
+ stateManager
8079
+ }
8080
+ }) });
7790
8081
  }
7791
8082
  });
7792
8083
  };
@@ -7952,6 +8243,13 @@ const createToolCallStyleContextProvider = () => staticBlock([
7952
8243
  "Keep narration brief and value-dense; avoid repeating obvious steps.",
7953
8244
  "Use plain human language for narration unless in a technical context."
7954
8245
  ]);
8246
+ const createInlineInteractiveSurfaceContextProvider = () => staticBlock([
8247
+ "## Inline Interactive Surfaces",
8248
+ "Do not make every UI an inline card. Choose inline only when the intended result is a compact, immediately usable card or short interaction; use the side panel for normal Panel Apps, long reading, rich editing, file browsing, large tables, multi-page workflows, or sustained workspaces.",
8249
+ "When you choose an inline card, call `show_content` with `type=\"panel_app\"` and `placement=\"inline\"` so the user can try it directly in the chat. Do not wait for the user to say \"inline\" or \"placement\" after you have already chosen the card form.",
8250
+ "A Panel Card must be designed card-first: prefer a landscape composition where width carries the main information and the card is wider than it is tall; collapse to one column only in narrow containers. Core value must be visible in the first 220-420px, with no horizontal scrolling, no reliance on document-level internal scrolling, compact controls, at most one primary action, clear loading/empty/error states, and an obvious expand path for details.",
8251
+ "Typical Panel Card fits: weather cards, calculators, timers, checklists, pickers, compact forms, previews, and small dashboards. If the UI needs more space than a card, choose `placement=\"side_panel\"` instead. Inline hosts may pass `nextclawDisplayMode=card` and `nextclawPlacement=inline`; use those hints to render a compact card layout instead of a full page."
8252
+ ]);
7955
8253
  const createChatComposerTokensContextProvider = () => staticBlock([
7956
8254
  "## Chat Composer Tokens",
7957
8255
  "When a user message contains tokens like `$weather` or `$web-search`, treat each `$<skill-spec>` token as a user-visible marker that the corresponding skill was explicitly selected in the chat composer.",
@@ -8316,12 +8614,15 @@ var ContextProviderRunContextService = class {
8316
8614
  request,
8317
8615
  session
8318
8616
  });
8319
- const runContext = resolveNextclawNcpRunContext({
8320
- configManager: this.kernel.configManager,
8617
+ const runContext = buildNextclawNcpRunContext({
8618
+ agentProfile: this.kernel.agents.resolveAgentProfileForRun({
8619
+ requestMetadata,
8620
+ storedAgentId: request.agentId ?? session?.agentId
8621
+ }),
8622
+ config: this.kernel.configManager.loadConfig(),
8321
8623
  sessionId,
8322
8624
  requestMetadata,
8323
- sessionMetadata: session?.metadata ?? requestMetadata,
8324
- storedAgentId: request.agentId ?? session?.agentId
8625
+ sessionMetadata: session?.metadata ?? requestMetadata
8325
8626
  });
8326
8627
  const tools = await this.kernel.toolProviderManager.buildTools(request);
8327
8628
  const sessionProjectRoot = readSessionProjectRoot(runContext.sessionMetadata);
@@ -8355,6 +8656,7 @@ var ContextProviderContribution = class {
8355
8656
  createAssistantIdentityContextProvider(),
8356
8657
  new ToolingContextProvider(context),
8357
8658
  createToolCallStyleContextProvider(),
8659
+ createInlineInteractiveSurfaceContextProvider(),
8358
8660
  createChatComposerTokensContextProvider(),
8359
8661
  createSafetyContextProvider(),
8360
8662
  createCliQuickReferenceContextProvider(),
@@ -8395,7 +8697,7 @@ var ContextWindowContribution = class {
8395
8697
  unsubscribeNcpEvent = null;
8396
8698
  constructor(kernel) {
8397
8699
  this.kernel = kernel;
8398
- this.contextWindowPreview = new ContextCompactionPreflightService({ configManager: kernel.configManager });
8700
+ this.contextWindowPreview = new ContextCompactionPreflightService(kernel.agents);
8399
8701
  }
8400
8702
  start = () => {
8401
8703
  if (this.unsubscribeNcpEvent) return;
@@ -8622,270 +8924,22 @@ var LearningLoopContribution = class {
8622
8924
  };
8623
8925
  };
8624
8926
  //#endregion
8625
- //#region src/contributions/session-activity-preview/utils/session-activity-preview-ncp-event.utils.ts
8626
- const PREVIEW_TEXT_MAX_LENGTH = 160;
8627
- function readSessionId(value) {
8628
- if (typeof value !== "string") return null;
8629
- const trimmed = value.trim();
8630
- return trimmed.length > 0 ? trimmed : null;
8631
- }
8632
- function compactPreviewText(value) {
8633
- return value.replace(/\s+/g, " ").trim();
8634
- }
8635
- function truncatePreviewText(value) {
8636
- const compacted = compactPreviewText(value);
8637
- if (compacted.length <= PREVIEW_TEXT_MAX_LENGTH) return compacted;
8638
- return compacted.slice(0, PREVIEW_TEXT_MAX_LENGTH - 1).trimEnd();
8639
- }
8640
- function readMessagePreviewText(message) {
8641
- const chunks = [];
8642
- for (const part of message.parts) if ((part.type === "text" || part.type === "rich-text") && part.text.trim()) chunks.push(part.text);
8643
- const previewText = truncatePreviewText(chunks.join(" "));
8644
- return previewText.length > 0 ? previewText : null;
8645
- }
8646
- function createProjection(sessionId, preview) {
8647
- if (!sessionId) return null;
8648
- return {
8649
- sessionId,
8650
- preview
8651
- };
8652
- }
8653
- function formatErrorStatus(error) {
8654
- if (typeof error === "string" && error.trim()) return `运行出错:${truncatePreviewText(error)}`;
8655
- if (error && typeof error === "object" && "message" in error) {
8656
- const message = error.message;
8657
- if (typeof message === "string" && message.trim()) return `运行出错:${truncatePreviewText(message)}`;
8658
- }
8659
- return "运行出错";
8660
- }
8661
- function readToolCallId(value) {
8662
- if (typeof value !== "string") return null;
8663
- const trimmed = value.trim();
8664
- return trimmed.length > 0 ? trimmed : null;
8665
- }
8666
- function formatToolDoneStatus(toolName) {
8667
- return toolName ? `工具调用完成:${toolName}` : "工具调用完成";
8668
- }
8669
- function createSessionActivityPreviewFromNcpEvent(event, timestamp, options = {}) {
8670
- switch (event.type) {
8671
- case NcpEventType.RunStarted: return createProjection(readSessionId(event.payload.sessionId), {
8672
- state: "running",
8673
- statusText: "正在思考",
8674
- timestamp
8675
- });
8676
- case NcpEventType.RunFinished: return createProjection(readSessionId(event.payload.sessionId), {
8677
- state: "completed",
8678
- timestamp
8679
- });
8680
- case NcpEventType.RunError: return createProjection(readSessionId(event.payload.sessionId), {
8681
- state: "failed",
8682
- statusText: formatErrorStatus(event.payload.error),
8683
- timestamp
8684
- });
8685
- case NcpEventType.MessageSent: {
8686
- const text = readMessagePreviewText(event.payload.message);
8687
- if (!text || event.payload.message.role !== "user") return null;
8688
- return createProjection(readSessionId(event.payload.sessionId), {
8689
- state: "running",
8690
- statusText: text,
8691
- timestamp: event.payload.message.timestamp || timestamp
8692
- });
8693
- }
8694
- case NcpEventType.MessageCompleted: {
8695
- const text = readMessagePreviewText(event.payload.message);
8696
- if (!text || event.payload.message.role !== "assistant") return null;
8697
- return createProjection(readSessionId(event.payload.sessionId), {
8698
- state: "completed",
8699
- replyText: text,
8700
- timestamp: event.payload.message.timestamp || timestamp
8701
- });
8702
- }
8703
- case NcpEventType.MessageFailed: return createProjection(readSessionId(event.payload.sessionId), {
8704
- state: "failed",
8705
- statusText: formatErrorStatus(event.payload.error),
8706
- timestamp
8707
- });
8708
- case NcpEventType.MessageToolCallStart: return createProjection(readSessionId(event.payload.sessionId), {
8709
- state: "running",
8710
- statusText: `正在调用工具:${event.payload.toolName}`,
8711
- timestamp
8712
- });
8713
- case NcpEventType.MessageToolCallEnd:
8714
- case NcpEventType.MessageToolCallResult: {
8715
- const sessionId = readSessionId(event.payload.sessionId);
8716
- const toolCallId = readToolCallId(event.payload.toolCallId);
8717
- return createProjection(sessionId, {
8718
- state: "running",
8719
- statusText: formatToolDoneStatus(sessionId && toolCallId ? options.readToolName?.(sessionId, toolCallId) ?? null : null),
8720
- timestamp
8721
- });
8722
- }
8723
- default: return null;
8724
- }
8725
- }
8726
- //#endregion
8727
- //#region src/contributions/session-activity-preview/utils/session-activity-preview-metadata.utils.ts
8728
- const SESSION_ACTIVITY_PREVIEW_METADATA_KEY = "last_activity_preview";
8729
- const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
8730
- "running",
8731
- "completed",
8732
- "failed",
8733
- "idle"
8734
- ]);
8735
- function isRecord$2(value) {
8736
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8737
- }
8738
- function readOptionalString$3(value) {
8739
- if (typeof value !== "string") return;
8740
- const trimmed = value.trim();
8741
- return trimmed.length > 0 ? trimmed : void 0;
8742
- }
8743
- function readSessionActivityPreviewMetadata(value) {
8744
- if (!isRecord$2(value)) return null;
8745
- const state = value.state;
8746
- const timestamp = readOptionalString$3(value.timestamp);
8747
- if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
8748
- return {
8749
- state,
8750
- timestamp,
8751
- ...readOptionalString$3(value.statusText) ? { statusText: readOptionalString$3(value.statusText) } : {},
8752
- ...readOptionalString$3(value.replyText) ? { replyText: readOptionalString$3(value.replyText) } : {}
8753
- };
8754
- }
8755
- function compareIsoTimestamp(left, right) {
8756
- const leftTime = Date.parse(left);
8757
- const rightTime = Date.parse(right);
8758
- if (!Number.isFinite(leftTime) || !Number.isFinite(rightTime)) return left.localeCompare(right);
8759
- return leftTime - rightTime;
8760
- }
8761
- function mergeSessionActivityPreview(current, incoming) {
8762
- if (current && compareIsoTimestamp(incoming.timestamp, current.timestamp) < 0) return incoming.replyText && !current.replyText ? {
8763
- ...current,
8764
- replyText: incoming.replyText
8765
- } : current;
8766
- return {
8767
- state: incoming.state,
8768
- timestamp: incoming.timestamp,
8769
- ...incoming.statusText ?? (incoming.state === "completed" ? current?.statusText : void 0) ? { statusText: incoming.statusText ?? current?.statusText } : {},
8770
- ...incoming.replyText ?? current?.replyText ? { replyText: incoming.replyText ?? current?.replyText } : {}
8771
- };
8772
- }
8773
- function areSessionActivityPreviewsEqual(left, right) {
8774
- return Boolean(left) && left?.state === right.state && left.timestamp === right.timestamp && left.statusText === right.statusText && left.replyText === right.replyText;
8775
- }
8776
- function writeSessionActivityPreviewMetadata(metadata, projection) {
8777
- const current = readSessionActivityPreviewMetadata(metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY]);
8778
- const next = mergeSessionActivityPreview(current, projection.preview);
8779
- if (areSessionActivityPreviewsEqual(current, next)) return null;
8780
- return {
8781
- ...metadata ?? {},
8782
- [SESSION_ACTIVITY_PREVIEW_METADATA_KEY]: next
8783
- };
8784
- }
8785
- //#endregion
8786
- //#region src/contributions/session-activity-preview/index.ts
8787
- var SessionActivityPreviewContribution = class {
8788
- unsubscribeNcpEvent = null;
8789
- metadataWriteChains = /* @__PURE__ */ new Map();
8790
- toolNames = /* @__PURE__ */ new Map();
8791
- constructor(kernel) {
8792
- this.kernel = kernel;
8793
- }
8794
- start = () => {
8795
- if (this.unsubscribeNcpEvent) return;
8796
- this.unsubscribeNcpEvent = this.kernel.eventBus.on(eventKeys.ncpEvent, (event) => {
8797
- this.rememberToolName(event);
8798
- const projection = createSessionActivityPreviewFromNcpEvent(event, (/* @__PURE__ */ new Date()).toISOString(), { readToolName: this.readToolName });
8799
- this.clearFinishedRunToolNames(event);
8800
- if (!projection) return;
8801
- this.updatePreview(projection);
8802
- });
8803
- };
8804
- dispose = () => {
8805
- this.unsubscribeNcpEvent?.();
8806
- this.unsubscribeNcpEvent = null;
8807
- this.metadataWriteChains.clear();
8808
- this.toolNames.clear();
8809
- };
8810
- rememberToolName = (event) => {
8811
- if (event.type !== NcpEventType.MessageToolCallStart) return;
8812
- const sessionId = event.payload.sessionId.trim();
8813
- const toolCallId = event.payload.toolCallId.trim();
8814
- const toolName = event.payload.toolName.trim();
8815
- if (!sessionId || !toolCallId || !toolName) return;
8816
- this.toolNames.set(this.createToolNameKey(sessionId, toolCallId), toolName);
8817
- };
8818
- readToolName = (sessionId, toolCallId) => this.toolNames.get(this.createToolNameKey(sessionId, toolCallId)) ?? null;
8819
- clearFinishedRunToolNames = (event) => {
8820
- if (event.type !== NcpEventType.RunFinished && event.type !== NcpEventType.RunError) return;
8821
- const sessionId = this.readNonEmptyString(event.payload.sessionId);
8822
- if (!sessionId) return;
8823
- for (const key of this.toolNames.keys()) if (key.startsWith(`${sessionId}:`)) this.toolNames.delete(key);
8824
- };
8825
- readNonEmptyString = (value) => {
8826
- if (typeof value !== "string") return null;
8827
- const trimmed = value.trim();
8828
- return trimmed.length > 0 ? trimmed : null;
8829
- };
8830
- createToolNameKey = (sessionId, toolCallId) => `${sessionId}:${toolCallId}`;
8831
- updatePreview = (projection) => {
8832
- const next = (this.metadataWriteChains.get(projection.sessionId) ?? Promise.resolve()).then(() => this.updatePreviewMetadata(projection));
8833
- this.metadataWriteChains.set(projection.sessionId, next.catch(() => void 0));
8834
- next.catch((error) => {
8835
- const message = error instanceof Error ? error.stack ?? error.message : String(error);
8836
- console.error(`[session-activity-preview] failed to update ${projection.sessionId}: ${message}`);
8837
- });
8838
- };
8839
- updatePreviewMetadata = async (projection) => {
8840
- const nextMetadata = writeSessionActivityPreviewMetadata((await this.kernel.sessionManager.getSessionRecord(projection.sessionId))?.metadata, projection);
8841
- if (!nextMetadata) return;
8842
- await this.kernel.sessionManager.updateSessionMetadata(projection.sessionId, nextMetadata);
8843
- };
8844
- };
8845
- //#endregion
8846
8927
  //#region src/contributions/tool-provider/providers/asset-tool.provider.ts
8847
8928
  var AssetToolProvider = class {
8848
- constructor(kernel) {
8849
- this.kernel = kernel;
8929
+ constructor(assetStore) {
8930
+ this.assetStore = assetStore;
8850
8931
  }
8851
- provide = async (_request) => createAssetTools({ assetStore: this.kernel.assetStore });
8932
+ provide = async (_request) => createAssetTools({ assetStore: this.assetStore });
8852
8933
  };
8853
8934
  //#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
8935
  //#region src/contributions/tool-provider/providers/core-tool.provider.ts
8880
8936
  var CoreToolProvider = class {
8881
- constructor(kernel) {
8882
- this.kernel = kernel;
8937
+ constructor(runContextService, getGatewayController) {
8938
+ this.runContextService = runContextService;
8939
+ this.getGatewayController = getGatewayController;
8883
8940
  }
8884
8941
  provide = async (request) => {
8885
- const { toolRunContext } = await resolveToolProviderRunContext({
8886
- kernel: this.kernel,
8887
- request
8888
- });
8942
+ const { toolRunContext } = await this.runContextService.resolve(request);
8889
8943
  const { channel, chatId, execTimeoutSeconds, restrictToWorkspace, searchConfig, sessionId, workspace } = toolRunContext;
8890
8944
  const allowedDir = restrictToWorkspace ? workspace : void 0;
8891
8945
  const execTool = new ExecTool({
@@ -8898,7 +8952,7 @@ var CoreToolProvider = class {
8898
8952
  chatId,
8899
8953
  sessionKey: sessionId
8900
8954
  });
8901
- const gatewayTool = new GatewayTool(this.kernel.getGatewayController());
8955
+ const gatewayTool = new GatewayTool(this.getGatewayController());
8902
8956
  gatewayTool.setContext({ sessionKey: sessionId });
8903
8957
  return [
8904
8958
  new ReadFileTool(allowedDir),
@@ -8917,15 +8971,13 @@ var CoreToolProvider = class {
8917
8971
  //#endregion
8918
8972
  //#region src/contributions/tool-provider/providers/mcp-tool.provider.ts
8919
8973
  var McpToolProvider = class {
8920
- constructor(kernel) {
8921
- this.kernel = kernel;
8974
+ constructor(runContextService, mcpManager) {
8975
+ this.runContextService = runContextService;
8976
+ this.mcpManager = mcpManager;
8922
8977
  }
8923
8978
  provide = async (request) => {
8924
- const { toolRunContext } = await resolveToolProviderRunContext({
8925
- kernel: this.kernel,
8926
- request
8927
- });
8928
- return this.kernel.mcpManager.listToolsForRun({ agentId: toolRunContext.agentId });
8979
+ const { toolRunContext } = await this.runContextService.resolve(request);
8980
+ return this.mcpManager.listToolsForRun({ agentId: toolRunContext.agentId });
8929
8981
  };
8930
8982
  };
8931
8983
  //#endregion
@@ -8938,24 +8990,24 @@ function readMetadataAccountId(metadata) {
8938
8990
  }
8939
8991
  }
8940
8992
  var MessagingToolProvider = class {
8941
- constructor(kernel) {
8942
- this.kernel = kernel;
8993
+ constructor(runContextService, channels, automation, extensions) {
8994
+ this.runContextService = runContextService;
8995
+ this.channels = channels;
8996
+ this.automation = automation;
8997
+ this.extensions = extensions;
8943
8998
  }
8944
8999
  provide = async (request) => {
8945
- const { toolRunContext } = await resolveToolProviderRunContext({
8946
- kernel: this.kernel,
8947
- request
8948
- });
9000
+ const { toolRunContext } = await this.runContextService.resolve(request);
8949
9001
  const { channel, chatId, metadata } = toolRunContext;
8950
9002
  const accountId = readMetadataAccountId(metadata);
8951
9003
  const messageTool = new MessageTool(async (message) => {
8952
- if (!await this.kernel.channels.deliver(message)) throw new Error(`channel "${message.channel}" is not available`);
9004
+ if (!await this.channels.deliver(message)) throw new Error(`channel "${message.channel}" is not available`);
8953
9005
  }, { resolveChannels: this.resolveMessageChannels });
8954
9006
  messageTool.setContext(channel, chatId, accountId ?? null);
8955
- return [messageTool, new CronTool(this.kernel.automation)];
9007
+ return [messageTool, new CronTool(this.automation)];
8956
9008
  };
8957
9009
  resolveMessageChannels = () => {
8958
- const channels = this.kernel.extensions.getExtensionRegistry()?.channels ?? [];
9010
+ const channels = this.extensions.getExtensionRegistry()?.channels ?? [];
8959
9011
  return [...new Set(channels.map((registration) => registration.channel.id.trim()).filter(Boolean))].sort();
8960
9012
  };
8961
9013
  };
@@ -9094,12 +9146,12 @@ var SessionsHistoryTool = class {
9094
9146
  };
9095
9147
  //#endregion
9096
9148
  //#region src/tools/session-request.tools.ts
9097
- function readRequiredString$1(params, key) {
9149
+ function readRequiredString$2(params, key) {
9098
9150
  const value = params[key];
9099
9151
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9100
9152
  return value.trim();
9101
9153
  }
9102
- function readOptionalString$2(params, key) {
9154
+ function readOptionalString$3(params, key) {
9103
9155
  const value = params[key];
9104
9156
  if (typeof value !== "string") return;
9105
9157
  const trimmed = value.trim();
@@ -9153,16 +9205,16 @@ var SessionRequestTool = class {
9153
9205
  const params = normalizeToolParams(args);
9154
9206
  const target = params.target;
9155
9207
  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();
9208
+ const task = readRequiredString$2(params, "task");
9209
+ const notifyMode = readOptionalString$3(params, "notify")?.toLowerCase();
9158
9210
  if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
9159
9211
  return this.manager.requestSession({
9160
9212
  sourceSessionId: this.sourceSessionId,
9161
9213
  sourceToolCallId: context?.toolCallId,
9162
9214
  updateToolCallResult: context?.updateToolCallResult,
9163
- targetSessionId: readRequiredString$1(target, "session_id"),
9215
+ targetSessionId: readRequiredString$2(target, "session_id"),
9164
9216
  task,
9165
- title: readOptionalString$2(params, "title"),
9217
+ title: readOptionalString$3(params, "title"),
9166
9218
  notify: notifyMode,
9167
9219
  handoffDepth: this.handoffDepth
9168
9220
  });
@@ -9170,7 +9222,7 @@ var SessionRequestTool = class {
9170
9222
  };
9171
9223
  //#endregion
9172
9224
  //#region src/tools/session-search.tools.ts
9173
- function isRecord$1(value) {
9225
+ function isRecord$2(value) {
9174
9226
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9175
9227
  }
9176
9228
  function readOptionalInteger(value) {
@@ -9220,7 +9272,7 @@ var SessionSearchTool = class {
9220
9272
  return issues;
9221
9273
  };
9222
9274
  execute = async (args) => {
9223
- if (!isRecord$1(args)) throw new Error("session_search requires an object argument.");
9275
+ if (!isRecord$2(args)) throw new Error("session_search requires an object argument.");
9224
9276
  const issues = this.validateArgs(args);
9225
9277
  if (issues.length > 0) throw new Error(issues.join(" "));
9226
9278
  return this.queryService.search({
@@ -9233,23 +9285,23 @@ var SessionSearchTool = class {
9233
9285
  };
9234
9286
  //#endregion
9235
9287
  //#region src/tools/session-spawn.tools.ts
9236
- function readRequiredString(value, key) {
9288
+ function readRequiredString$1(value, key) {
9237
9289
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9238
9290
  return value.trim();
9239
9291
  }
9240
- function readOptionalString$1(value) {
9292
+ function readOptionalString$2(value) {
9241
9293
  if (typeof value !== "string") return;
9242
9294
  const trimmed = value.trim();
9243
9295
  return trimmed.length > 0 ? trimmed : void 0;
9244
9296
  }
9245
9297
  function readSpawnScope(value) {
9246
- const normalized = readOptionalString$1(value)?.toLowerCase();
9298
+ const normalized = readOptionalString$2(value)?.toLowerCase();
9247
9299
  if (!normalized || normalized === "standalone") return "standalone";
9248
9300
  if (normalized === "child") return "child";
9249
9301
  throw new Error("scope must be \"standalone\" or \"child\".");
9250
9302
  }
9251
9303
  function readSpawnNotify(value) {
9252
- const notifyMode = readOptionalString$1(value)?.toLowerCase();
9304
+ const notifyMode = readOptionalString$2(value)?.toLowerCase();
9253
9305
  if (!notifyMode && typeof value === "undefined") return;
9254
9306
  if (notifyMode === "none" || notifyMode === "final_reply") return notifyMode;
9255
9307
  throw new Error("notify must be \"none\" or \"final_reply\".");
@@ -9308,7 +9360,7 @@ var SessionSpawnTool = class {
9308
9360
  };
9309
9361
  execute = async (args, context) => {
9310
9362
  const { agentId: rawAgentId, model: rawModel, notify: rawNotify, runtime: rawRuntime, scope: rawScope, task: rawTask, title: rawTitle } = normalizeToolParams(args);
9311
- const task = readRequiredString(rawTask, "task");
9363
+ const task = readRequiredString$1(rawTask, "task");
9312
9364
  const scope = readSpawnScope(rawScope);
9313
9365
  const notify = readSpawnNotify(rawNotify);
9314
9366
  const parentSessionId = scope === "child" ? this.readParentSessionIdOrThrow() : void 0;
@@ -9318,10 +9370,10 @@ var SessionSpawnTool = class {
9318
9370
  updateToolCallResult: context?.updateToolCallResult,
9319
9371
  sourceSessionMetadata: this.sourceSessionMetadata,
9320
9372
  task,
9321
- title: readOptionalString$1(rawTitle),
9322
- agentId: readOptionalString$1(rawAgentId),
9323
- model: readOptionalString$1(rawModel),
9324
- runtime: readOptionalString$1(rawRuntime),
9373
+ title: readOptionalString$2(rawTitle),
9374
+ agentId: readOptionalString$2(rawAgentId),
9375
+ model: readOptionalString$2(rawModel),
9376
+ runtime: readOptionalString$2(rawRuntime),
9325
9377
  handoffDepth: this.handoffDepth,
9326
9378
  parentSessionId,
9327
9379
  notify
@@ -9329,11 +9381,11 @@ var SessionSpawnTool = class {
9329
9381
  const session = await this.sessionManager.createSession({
9330
9382
  sourceSessionId: this.sourceSessionId,
9331
9383
  task,
9332
- title: readOptionalString$1(rawTitle),
9384
+ title: readOptionalString$2(rawTitle),
9333
9385
  sourceSessionMetadata: this.sourceSessionMetadata,
9334
- agentId: readOptionalString$1(rawAgentId),
9335
- model: readOptionalString$1(rawModel),
9336
- runtime: readOptionalString$1(rawRuntime),
9386
+ agentId: readOptionalString$2(rawAgentId),
9387
+ model: readOptionalString$2(rawModel),
9388
+ runtime: readOptionalString$2(rawRuntime),
9337
9389
  parentSessionId
9338
9390
  });
9339
9391
  return {
@@ -9357,22 +9409,22 @@ var SessionSpawnTool = class {
9357
9409
  //#endregion
9358
9410
  //#region src/contributions/tool-provider/providers/session-tool.provider.ts
9359
9411
  var SessionToolProvider = class {
9360
- constructor(kernel) {
9361
- this.kernel = kernel;
9412
+ constructor(runContextService, sessionManager, sessionRequests, sessionSearch) {
9413
+ this.runContextService = runContextService;
9414
+ this.sessionManager = sessionManager;
9415
+ this.sessionRequests = sessionRequests;
9416
+ this.sessionSearch = sessionSearch;
9362
9417
  }
9363
9418
  provide = async (request) => {
9364
- const { toolRunContext } = await resolveToolProviderRunContext({
9365
- kernel: this.kernel,
9366
- request
9367
- });
9419
+ const { toolRunContext } = await this.runContextService.resolve(request);
9368
9420
  const { handoffDepth, metadata, sessionId } = toolRunContext;
9369
- const sessionsSpawnTool = new SessionSpawnTool(this.kernel.sessionManager, this.kernel.sessionRequests);
9421
+ const sessionsSpawnTool = new SessionSpawnTool(this.sessionManager, this.sessionRequests);
9370
9422
  sessionsSpawnTool.setContext({
9371
9423
  sourceSessionId: sessionId,
9372
9424
  sourceSessionMetadata: metadata,
9373
9425
  handoffDepth
9374
9426
  });
9375
- const sessionsRequestTool = new SessionRequestTool(this.kernel.sessionRequests);
9427
+ const sessionsRequestTool = new SessionRequestTool(this.sessionRequests);
9376
9428
  sessionsRequestTool.setContext({
9377
9429
  sourceSessionId: sessionId,
9378
9430
  handoffDepth
@@ -9380,15 +9432,188 @@ var SessionToolProvider = class {
9380
9432
  const tools = [
9381
9433
  sessionsSpawnTool,
9382
9434
  sessionsRequestTool,
9383
- new SessionsListTool(this.kernel.sessionManager),
9384
- new SessionsHistoryTool(this.kernel.sessionManager)
9435
+ new SessionsListTool(this.sessionManager),
9436
+ new SessionsHistoryTool(this.sessionManager)
9385
9437
  ];
9386
- if (!this.kernel.sessionSearch.isReady()) return tools;
9387
- tools.push(new SessionSearchTool({ search: this.kernel.sessionSearch.search }, { currentSessionId: sessionId }));
9438
+ if (!this.sessionSearch.isReady()) return tools;
9439
+ tools.push(new SessionSearchTool({ search: this.sessionSearch.search }, { currentSessionId: sessionId }));
9388
9440
  return tools;
9389
9441
  };
9390
9442
  };
9391
9443
  //#endregion
9444
+ //#region src/tools/show-content.tools.ts
9445
+ const SHOW_CONTENT_TOOL_NAME = "show_content";
9446
+ function isRecord$1(value) {
9447
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9448
+ }
9449
+ function readRequiredString(value, key) {
9450
+ if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9451
+ return value.trim();
9452
+ }
9453
+ function readOptionalString$1(value) {
9454
+ if (typeof value !== "string") return;
9455
+ const trimmed = value.trim();
9456
+ return trimmed.length > 0 ? trimmed : void 0;
9457
+ }
9458
+ function readOptionalPositiveInteger(value, key) {
9459
+ if (typeof value === "undefined") return;
9460
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) throw new Error(`${key} must be a positive integer.`);
9461
+ return value;
9462
+ }
9463
+ function readPurpose(value) {
9464
+ const normalized = readOptionalString$1(value);
9465
+ if (!normalized) return;
9466
+ if (normalized === "read" || normalized === "preview" || normalized === "edit" || normalized === "interact") return normalized;
9467
+ throw new Error("purpose must be \"read\", \"preview\", \"edit\", or \"interact\".");
9468
+ }
9469
+ function readPlacement(value) {
9470
+ const normalized = readOptionalString$1(value);
9471
+ if (!normalized) return;
9472
+ if (normalized === "inline" || normalized === "side_panel") return normalized;
9473
+ throw new Error("placement must be \"inline\" or \"side_panel\".");
9474
+ }
9475
+ function readPayload(params) {
9476
+ if (!isRecord$1(params.payload)) throw new Error("payload must be an object.");
9477
+ return params.payload;
9478
+ }
9479
+ function readUrl(value) {
9480
+ const url = readRequiredString(value, "payload.url");
9481
+ let parsed;
9482
+ try {
9483
+ parsed = new URL(url);
9484
+ } catch {
9485
+ throw new Error("payload.url must be a valid URL.");
9486
+ }
9487
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("payload.url must use http or https.");
9488
+ return parsed.toString();
9489
+ }
9490
+ function normalizeShowContentArgs(args) {
9491
+ const params = normalizeToolParams(args);
9492
+ const type = readRequiredString(params.type, "type");
9493
+ const payload = readPayload(params);
9494
+ const title = readOptionalString$1(params.title);
9495
+ const purpose = readPurpose(params.purpose);
9496
+ const placement = readPlacement(params.placement);
9497
+ if (type === "file") return {
9498
+ target: {
9499
+ type,
9500
+ payload: {
9501
+ path: readRequiredString(payload.path, "payload.path"),
9502
+ line: readOptionalPositiveInteger(payload.line, "payload.line"),
9503
+ column: readOptionalPositiveInteger(payload.column, "payload.column")
9504
+ }
9505
+ },
9506
+ title,
9507
+ purpose,
9508
+ placement
9509
+ };
9510
+ if (type === "url") return {
9511
+ target: {
9512
+ type,
9513
+ payload: { url: readUrl(payload.url) }
9514
+ },
9515
+ title,
9516
+ purpose,
9517
+ placement
9518
+ };
9519
+ if (type === "panel_app") return {
9520
+ target: {
9521
+ type,
9522
+ payload: { appId: readRequiredString(payload.appId, "payload.appId") }
9523
+ },
9524
+ title,
9525
+ purpose,
9526
+ placement
9527
+ };
9528
+ throw new Error("type must be \"file\", \"url\", or \"panel_app\".");
9529
+ }
9530
+ function summarizeTarget(target) {
9531
+ if (target.type === "file") return target.payload.path;
9532
+ if (target.type === "url") return target.payload.url;
9533
+ return target.payload.appId;
9534
+ }
9535
+ function createShowContentEventPayload(request, context) {
9536
+ const toolCallId = readOptionalString$1(context?.toolCallId);
9537
+ return {
9538
+ id: toolCallId ? `tool:${toolCallId}:show-content` : `show-content:${request.target.type}:${summarizeTarget(request.target)}`,
9539
+ toolCallId,
9540
+ target: request.target,
9541
+ title: request.title,
9542
+ purpose: request.purpose,
9543
+ placement: request.placement
9544
+ };
9545
+ }
9546
+ var ShowContentTool = class {
9547
+ name = SHOW_CONTENT_TOOL_NAME;
9548
+ description = [
9549
+ "Show file, URL, or panel app content in the current chat UI.",
9550
+ "placement=\"inline\" embeds a lightweight panel_app as an interactive chat card so the user can try it directly in the conversation.",
9551
+ "placement=\"side_panel\" opens content in the right side panel for larger reading, editing, or sustained workflows.",
9552
+ "Choose the placement yourself: after creating a lightweight Panel App such as a weather card, calculator, timer, checklist, picker, form, preview, or small dashboard, call this tool with placement=\"inline\" without waiting for the user to ask to see it.",
9553
+ "Omit placement only when preserving the existing default side panel behavior is intentional."
9554
+ ].join(" ");
9555
+ parameters = {
9556
+ type: "object",
9557
+ properties: {
9558
+ type: {
9559
+ type: "string",
9560
+ enum: [
9561
+ "file",
9562
+ "url",
9563
+ "panel_app"
9564
+ ],
9565
+ description: "Content target type."
9566
+ },
9567
+ title: {
9568
+ type: "string",
9569
+ description: "Optional title for the shown content."
9570
+ },
9571
+ purpose: {
9572
+ type: "string",
9573
+ enum: [
9574
+ "read",
9575
+ "preview",
9576
+ "edit",
9577
+ "interact"
9578
+ ],
9579
+ description: "Optional user intent for the content."
9580
+ },
9581
+ placement: {
9582
+ type: "string",
9583
+ enum: ["inline", "side_panel"],
9584
+ description: "Optional display placement. \"inline\" embeds a lightweight panel app as an interactive chat card; \"side_panel\" opens it in the right panel for larger workflows. Choose the appropriate placement yourself; defaults to the existing side panel behavior when omitted."
9585
+ },
9586
+ payload: {
9587
+ type: "object",
9588
+ description: "Type-specific fields: file={path,line,column}; url={url}; panel_app={appId}.",
9589
+ additionalProperties: true
9590
+ }
9591
+ },
9592
+ required: ["type", "payload"],
9593
+ additionalProperties: false
9594
+ };
9595
+ constructor(eventBus) {
9596
+ this.eventBus = eventBus;
9597
+ }
9598
+ execute = async (args, context) => {
9599
+ const request = normalizeShowContentArgs(args);
9600
+ this.eventBus.emit(eventKeys.uiShowContent, createShowContentEventPayload(request, context), { source: "kernel" });
9601
+ return {
9602
+ ok: true,
9603
+ action: "showContent",
9604
+ request
9605
+ };
9606
+ };
9607
+ };
9608
+ //#endregion
9609
+ //#region src/contributions/tool-provider/providers/show-content-tool.provider.ts
9610
+ var ShowContentToolProvider = class {
9611
+ constructor(eventBus) {
9612
+ this.eventBus = eventBus;
9613
+ }
9614
+ provide = () => [new ShowContentTool(this.eventBus)];
9615
+ };
9616
+ //#endregion
9392
9617
  //#region src/contributions/tool-provider/providers/structured-result-tool.provider.ts
9393
9618
  var StructuredResultToolProvider = class {
9394
9619
  provide = (request) => {
@@ -9411,6 +9636,40 @@ function isRecord(value) {
9411
9636
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9412
9637
  }
9413
9638
  //#endregion
9639
+ //#region src/contributions/tool-provider/services/tool-provider-run-context.service.ts
9640
+ var ToolProviderRunContextService = class {
9641
+ constructor(sessionManager, agentManager, configManager) {
9642
+ this.sessionManager = sessionManager;
9643
+ this.agentManager = agentManager;
9644
+ this.configManager = configManager;
9645
+ }
9646
+ resolve = async (request) => {
9647
+ const session = request.sessionId ? await this.sessionManager.getAgentRunSession(request.sessionId) : null;
9648
+ const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
9649
+ const requestMetadata = buildAgentRunRequestMetadata({
9650
+ request,
9651
+ session
9652
+ });
9653
+ const runContext = buildNextclawNcpRunContext({
9654
+ agentProfile: this.agentManager.resolveAgentProfileForRun({
9655
+ requestMetadata,
9656
+ storedAgentId: request.agentId ?? session?.agentId
9657
+ }),
9658
+ config: this.configManager.loadConfig(),
9659
+ sessionId,
9660
+ requestMetadata,
9661
+ sessionMetadata: session?.metadata ?? requestMetadata
9662
+ });
9663
+ return {
9664
+ requestMetadata,
9665
+ runContext,
9666
+ session,
9667
+ sessionId,
9668
+ toolRunContext: runContext.toolRunContext
9669
+ };
9670
+ };
9671
+ };
9672
+ //#endregion
9414
9673
  //#region src/contributions/tool-provider/index.ts
9415
9674
  var ToolProviderContribution = class {
9416
9675
  cleanups = [];
@@ -9424,14 +9683,18 @@ var ToolProviderContribution = class {
9424
9683
  dispose = () => {
9425
9684
  while (this.cleanups.length > 0) this.cleanups.pop()?.();
9426
9685
  };
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
- ];
9686
+ createToolProviders = () => {
9687
+ const runContextService = new ToolProviderRunContextService(this.kernel.sessionManager, this.kernel.agents, this.kernel.configManager);
9688
+ return [
9689
+ new StructuredResultToolProvider(),
9690
+ new ShowContentToolProvider(this.kernel.eventBus),
9691
+ new CoreToolProvider(runContextService, this.kernel.getGatewayController),
9692
+ new MessagingToolProvider(runContextService, this.kernel.channels, this.kernel.automation, this.kernel.extensions),
9693
+ new SessionToolProvider(runContextService, this.kernel.sessionManager, this.kernel.sessionRequests, this.kernel.sessionSearch),
9694
+ new AssetToolProvider(this.kernel.assetStore),
9695
+ new McpToolProvider(runContextService, this.kernel.mcpManager)
9696
+ ];
9697
+ };
9435
9698
  };
9436
9699
  //#endregion
9437
9700
  //#region src/app/nextclaw-kernel.ts
@@ -9487,26 +9750,27 @@ var NextclawKernel = class {
9487
9750
  gatewayController;
9488
9751
  constructor(options = {}) {
9489
9752
  const sessionsDir = resolveKernelSessionsDir(options);
9490
- this.sessionSearch = new SessionSearchManager({
9753
+ this.sessionSearch = new SessionSearchService({
9491
9754
  databasePath: resolve(getDataDir(), "session-search.db"),
9492
9755
  sessionsDir
9493
9756
  });
9494
9757
  this.ncpAgentSessionJournalStore = new NcpAgentSessionJournalStore(resolve(sessionsDir, ".ncp-agent-journal"));
9495
9758
  this.automation = new AutomationManager({ storePath: resolveKernelAutomationStorePath(options) });
9496
9759
  this.assetStore = new LocalAssetStore({ rootDir: resolve(getDataDir(), "assets") });
9497
- this.agents = new AgentManager();
9498
9760
  this.control = new NextclawKernelControlManager();
9499
- this.channels = new ChannelManager$1({ bus: this.messageBus });
9761
+ this.channels = new ChannelManager({ bus: this.messageBus });
9500
9762
  this.configManager = new ConfigManager({
9501
9763
  configPath: options.configPath,
9502
9764
  channels: this.channels,
9503
9765
  providerManager: this.llmProviders
9504
9766
  });
9767
+ this.agents = new AgentManager(this.configManager);
9505
9768
  this.accessManager = new AccessManager({
9506
9769
  configManager: this.configManager,
9507
9770
  homeDir: options.homeDir
9508
9771
  });
9509
9772
  this.sessionManager = new SessionManager({
9773
+ agentManager: this.agents,
9510
9774
  configManager: this.configManager,
9511
9775
  eventBus: this.eventBus,
9512
9776
  journalStore: this.ncpAgentSessionJournalStore,
@@ -9539,12 +9803,11 @@ var NextclawKernel = class {
9539
9803
  ingress: this.ingress
9540
9804
  })
9541
9805
  });
9542
- this.contextCompactionManager = new AgentRunContextCompactionManager(this.configManager, this.llmProviders, this.sessionManager);
9806
+ this.contextCompactionManager = new AgentRunContextCompactionManager(this.agents, this.llmProviders, this.sessionManager);
9543
9807
  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);
9808
+ this.agentRunRequestManager = new AgentRunRequestManager(this.agentRuntimeManager, this.agents, this.configManager, this.contextProviderManager, this.eventBus, this.ingress, this.sessionManager, this.sessionRunManager, this.toolProviderManager);
9545
9809
  this.contributions = [
9546
9810
  new ToolProviderContribution(this),
9547
- new SessionActivityPreviewContribution(this),
9548
9811
  new LearningLoopContribution(this),
9549
9812
  new ContextProviderContribution(this),
9550
9813
  new AgentRunRuntimeContribution(this),
@@ -10181,6 +10444,6 @@ function resolveLegacyEventType(message) {
10181
10444
  return `message.${role || "other"}`;
10182
10445
  }
10183
10446
  //#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 };
10447
+ 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
10448
 
10186
10449
  //# sourceMappingURL=index.js.map