@nextclaw/kernel 0.1.14 → 0.1.15-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.d.ts +250 -170
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2103 -1119
- package/dist/index.js.map +1 -1
- package/package.json +15 -14
package/dist/index.js
CHANGED
|
@@ -3,21 +3,22 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { EventBus, Ingress, eventKeys, ingressKeys } from "@nextclaw/shared";
|
|
5
5
|
import { NcpEventType, isHiddenNcpMessage, readAssistantReasoningNormalizationMode, readAssistantReasoningNormalizationModeFromMetadata, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
|
|
6
|
-
import { DefaultNcpAgentRuntime, LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool } from "@nextclaw/ncp-agent-runtime";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, CommandRegistry, ConfigSchema, ContextBuilder, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_SESSION_SEARCH_LIMIT, EditFileTool, ExecTool, ExtensionToolAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SessionManager, SessionSearchManager, SkillsLoader, Tool, ToolRegistry, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createToolExecutionContext, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile,
|
|
10
|
-
import { discoverPluginStatusReport, getPackageManifestExtensions, getPluginChannelBindings, getPluginUiMetadataFromRegistry, loadOpenClawPlugins, loadOpenClawPluginsProgressively, loadPluginManifest, mergePluginConfigView, toPluginConfigView } from "@nextclaw/openclaw-compat";
|
|
6
|
+
import { DefaultNcpAgentRuntime, LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, ncpMessageToOpenAiMessages } from "@nextclaw/ncp-agent-runtime";
|
|
7
|
+
import { appendFileSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { basename, delimiter, dirname, join, relative, resolve } from "node:path";
|
|
9
|
+
import { AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, CommandRegistry, ConfigSchema, ContextBuilder, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_SESSION_SEARCH_LIMIT, EditFileTool, ExecTool, ExtensionToolAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SessionManager, SessionSearchManager, SkillsLoader, Tool, ToolRegistry, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createToolExecutionContext, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeInlineSecretRefs, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, summarizeSessionRequestTask, toDisposable, toExtensionConfigView } from "@nextclaw/core";
|
|
11
10
|
import { spawn } from "node:child_process";
|
|
12
11
|
import { access, appendFile, mkdir, readFile, readdir, rename, rm, unlink, writeFile } from "node:fs/promises";
|
|
13
12
|
import { fileURLToPath } from "node:url";
|
|
14
|
-
import { BUILTIN_PROVIDER_PLUGINS
|
|
13
|
+
import { BUILTIN_PROVIDER_PLUGINS } from "@nextclaw/runtime";
|
|
15
14
|
import { McpRegistryService, McpServerLifecycleManager } from "@nextclaw/mcp";
|
|
16
15
|
import { McpNcpToolRegistryAdapter } from "@nextclaw/ncp-mcp";
|
|
17
16
|
import { DefaultNcpAgentConversationStateManager } from "@nextclaw/ncp-toolkit";
|
|
18
17
|
import { parse } from "yaml";
|
|
18
|
+
import { catchError, from, lastValueFrom, tap } from "rxjs";
|
|
19
19
|
import { HttpRuntimeConfigResolver, HttpRuntimeNcpAgentRuntime } from "@nextclaw/nextclaw-ncp-runtime-http-client";
|
|
20
20
|
import { StdioRuntimeConfigResolver, StdioRuntimeNcpAgentRuntime, probeStdioRuntime } from "@nextclaw/nextclaw-ncp-runtime-stdio-client";
|
|
21
|
+
import { DefaultNcpAgentRuntime as DefaultNcpAgentRuntime$1 } from "@nextclaw/ncp-agent-runtime-next";
|
|
21
22
|
//#region src/managers/agent.manager.ts
|
|
22
23
|
var AgentManager = class {
|
|
23
24
|
listAgents = () => {
|
|
@@ -50,54 +51,6 @@ var AgentManager = class {
|
|
|
50
51
|
};
|
|
51
52
|
//#endregion
|
|
52
53
|
//#region src/utils/session-run.utils.ts
|
|
53
|
-
var AsyncEventQueue = class {
|
|
54
|
-
items = [];
|
|
55
|
-
waiters = [];
|
|
56
|
-
closed = false;
|
|
57
|
-
push = (item) => {
|
|
58
|
-
const waiter = this.waiters.shift();
|
|
59
|
-
if (waiter) {
|
|
60
|
-
waiter({
|
|
61
|
-
value: item,
|
|
62
|
-
done: false
|
|
63
|
-
});
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
this.items.push(item);
|
|
67
|
-
};
|
|
68
|
-
close = () => {
|
|
69
|
-
if (this.closed) return;
|
|
70
|
-
this.closed = true;
|
|
71
|
-
while (this.waiters.length > 0) this.waiters.shift()?.({
|
|
72
|
-
value: void 0,
|
|
73
|
-
done: true
|
|
74
|
-
});
|
|
75
|
-
};
|
|
76
|
-
iterate = () => {
|
|
77
|
-
const nextItem = this.next;
|
|
78
|
-
return (async function* iterateQueuedEvents() {
|
|
79
|
-
while (true) {
|
|
80
|
-
const next = await nextItem();
|
|
81
|
-
if (next.done) return;
|
|
82
|
-
yield next.value;
|
|
83
|
-
}
|
|
84
|
-
})();
|
|
85
|
-
};
|
|
86
|
-
next = async () => {
|
|
87
|
-
const item = this.items.shift();
|
|
88
|
-
if (item) return {
|
|
89
|
-
value: item,
|
|
90
|
-
done: false
|
|
91
|
-
};
|
|
92
|
-
if (this.closed) return {
|
|
93
|
-
value: void 0,
|
|
94
|
-
done: true
|
|
95
|
-
};
|
|
96
|
-
return new Promise((resolve) => {
|
|
97
|
-
this.waiters.push(resolve);
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
54
|
function readString$8(value) {
|
|
102
55
|
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
103
56
|
}
|
|
@@ -470,7 +423,7 @@ var LlmUsageManager = class {
|
|
|
470
423
|
};
|
|
471
424
|
//#endregion
|
|
472
425
|
//#region src/utils/ncp-message-bridge.utils.ts
|
|
473
|
-
function normalizeString(value) {
|
|
426
|
+
function normalizeString$1(value) {
|
|
474
427
|
if (typeof value !== "string") return null;
|
|
475
428
|
const trimmed = value.trim();
|
|
476
429
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -567,80 +520,6 @@ function toLegacyMessages(messages, options = {}) {
|
|
|
567
520
|
return legacyMessages;
|
|
568
521
|
}
|
|
569
522
|
//#endregion
|
|
570
|
-
//#region src/features/native-runtime/utils/nextclaw-ncp-session-preferences.utils.ts
|
|
571
|
-
function normalizeOptionalString(value) {
|
|
572
|
-
if (typeof value !== "string") return;
|
|
573
|
-
const trimmed = value.trim();
|
|
574
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
575
|
-
}
|
|
576
|
-
function readMetadataModel(metadata) {
|
|
577
|
-
const candidates = [
|
|
578
|
-
metadata.model,
|
|
579
|
-
metadata.llm_model,
|
|
580
|
-
metadata.agent_model,
|
|
581
|
-
metadata.session_model
|
|
582
|
-
];
|
|
583
|
-
for (const candidate of candidates) {
|
|
584
|
-
const normalized = normalizeOptionalString(candidate);
|
|
585
|
-
if (normalized) return normalized;
|
|
586
|
-
}
|
|
587
|
-
return null;
|
|
588
|
-
}
|
|
589
|
-
function readMetadataThinking(metadata) {
|
|
590
|
-
const candidates = [
|
|
591
|
-
metadata.thinking,
|
|
592
|
-
metadata.thinking_level,
|
|
593
|
-
metadata.thinkingLevel,
|
|
594
|
-
metadata.thinking_effort,
|
|
595
|
-
metadata.thinkingEffort
|
|
596
|
-
];
|
|
597
|
-
for (const candidate of candidates) {
|
|
598
|
-
if (typeof candidate !== "string") continue;
|
|
599
|
-
const normalized = candidate.trim().toLowerCase();
|
|
600
|
-
if (!normalized) continue;
|
|
601
|
-
if (normalized === "clear" || normalized === "reset" || normalized === "off!") return "__clear__";
|
|
602
|
-
const level = parseThinkingLevel(normalized);
|
|
603
|
-
if (level) return level;
|
|
604
|
-
}
|
|
605
|
-
return null;
|
|
606
|
-
}
|
|
607
|
-
function resolveEffectiveModel(params) {
|
|
608
|
-
const { fallbackModel, requestMetadata } = params;
|
|
609
|
-
const metadata = structuredClone(params.sessionMetadata);
|
|
610
|
-
if (requestMetadata.clear_model === true || requestMetadata.reset_model === true) delete metadata.preferred_model;
|
|
611
|
-
const inboundModel = readMetadataModel(requestMetadata);
|
|
612
|
-
if (inboundModel) metadata.preferred_model = inboundModel;
|
|
613
|
-
return {
|
|
614
|
-
metadata,
|
|
615
|
-
model: normalizeOptionalString(metadata.preferred_model) ?? fallbackModel
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
function syncSessionThinkingPreference(params) {
|
|
619
|
-
const { requestMetadata } = params;
|
|
620
|
-
const metadata = structuredClone(params.sessionMetadata);
|
|
621
|
-
if (requestMetadata.clear_thinking === true || requestMetadata.reset_thinking === true) delete metadata.preferred_thinking;
|
|
622
|
-
const inboundThinking = readMetadataThinking(requestMetadata);
|
|
623
|
-
if (inboundThinking === "__clear__") {
|
|
624
|
-
delete metadata.preferred_thinking;
|
|
625
|
-
return metadata;
|
|
626
|
-
}
|
|
627
|
-
if (inboundThinking) metadata.preferred_thinking = inboundThinking;
|
|
628
|
-
return metadata;
|
|
629
|
-
}
|
|
630
|
-
function resolveSessionChannelContext(params) {
|
|
631
|
-
const { requestMetadata } = params;
|
|
632
|
-
const metadata = structuredClone(params.sessionMetadata);
|
|
633
|
-
const channel = normalizeOptionalString(requestMetadata.channel) ?? normalizeOptionalString(metadata.last_channel) ?? "ui";
|
|
634
|
-
const chatId = normalizeOptionalString(requestMetadata.chatId) ?? normalizeOptionalString(requestMetadata.chat_id) ?? normalizeOptionalString(metadata.last_to) ?? "web-ui";
|
|
635
|
-
metadata.last_channel = channel;
|
|
636
|
-
metadata.last_to = chatId;
|
|
637
|
-
return {
|
|
638
|
-
channel,
|
|
639
|
-
chatId,
|
|
640
|
-
metadata
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
//#endregion
|
|
644
523
|
//#region src/features/native-runtime/utils/nextclaw-ncp-current-turn.utils.ts
|
|
645
524
|
function isTextLikePart(part) {
|
|
646
525
|
return part.type === "text" || part.type === "rich-text";
|
|
@@ -833,17 +712,17 @@ function projectNcpMessagesWithContextCompaction(params) {
|
|
|
833
712
|
}, ...sessionMessages.slice(checkpointIndex + 1).filter((message) => !readCompactionSummary(message)).map((message) => structuredClone(message))];
|
|
834
713
|
}
|
|
835
714
|
//#endregion
|
|
836
|
-
//#region src/features/context-compaction/
|
|
715
|
+
//#region src/features/context-compaction/services/context-compaction-preflight.service.ts
|
|
837
716
|
const SUMMARY_MAX_TOKENS = 4e3;
|
|
838
717
|
const SUMMARY_SOURCE_MAX_CHARS = 12e4;
|
|
839
718
|
function readRequestedAgentId$1(metadata) {
|
|
840
|
-
return normalizeString(metadata.agent_id)?.toLowerCase() ?? normalizeString(metadata.agentId)?.toLowerCase() ?? null;
|
|
719
|
+
return normalizeString$1(metadata.agent_id)?.toLowerCase() ?? normalizeString$1(metadata.agentId)?.toLowerCase() ?? null;
|
|
841
720
|
}
|
|
842
721
|
function resolveCompactionProfile(params) {
|
|
843
722
|
const { config, requestMetadata, storedAgentId } = params;
|
|
844
723
|
const { defaults } = config.agents;
|
|
845
724
|
const defaultAgentId = resolveDefaultAgentProfileId(config);
|
|
846
|
-
const profile = findEffectiveAgentProfile(config, normalizeString(storedAgentId)?.toLowerCase() ?? readRequestedAgentId$1(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
|
|
725
|
+
const profile = findEffectiveAgentProfile(config, normalizeString$1(storedAgentId)?.toLowerCase() ?? readRequestedAgentId$1(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
|
|
847
726
|
return {
|
|
848
727
|
contextTokens: profile?.contextTokens ?? defaults.contextTokens,
|
|
849
728
|
model: profile?.model ?? defaults.model,
|
|
@@ -898,20 +777,20 @@ function buildContextWindowSnapshotForMessages(contextWindowBudgetService, param
|
|
|
898
777
|
totalContextTokens: contextTokens
|
|
899
778
|
});
|
|
900
779
|
}
|
|
901
|
-
var
|
|
780
|
+
var ContextCompactionPreflightService = class {
|
|
781
|
+
compactionService = new ContextCompactionService();
|
|
902
782
|
contextWindowBudgetService = new ContextWindowBudgetService();
|
|
903
783
|
constructor(options) {
|
|
904
784
|
this.options = options;
|
|
905
785
|
}
|
|
906
786
|
preview = (params) => {
|
|
907
787
|
const { requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
|
|
908
|
-
const metadata = storedMetadata;
|
|
909
788
|
const profile = resolveCompactionProfile({
|
|
910
789
|
config: this.options.configManager.loadConfig(),
|
|
911
790
|
requestMetadata,
|
|
912
791
|
storedAgentId
|
|
913
792
|
});
|
|
914
|
-
const existingCheckpoint = readCompressedContextCompactionCheckpoint(
|
|
793
|
+
const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]);
|
|
915
794
|
return buildContextWindowSnapshotForMessages(this.contextWindowBudgetService, {
|
|
916
795
|
checkpoint: existingCheckpoint,
|
|
917
796
|
contextTokens: profile.contextTokens,
|
|
@@ -920,39 +799,6 @@ var ContextWindowPreviewManager = class {
|
|
|
920
799
|
sessionMessages
|
|
921
800
|
});
|
|
922
801
|
};
|
|
923
|
-
};
|
|
924
|
-
var ContextCompactionManager = class {
|
|
925
|
-
compactionService = new ContextCompactionService();
|
|
926
|
-
contextWindowBudgetService = new ContextWindowBudgetService();
|
|
927
|
-
constructor(options) {
|
|
928
|
-
this.options = options;
|
|
929
|
-
}
|
|
930
|
-
runLivePreflight = async function* (params) {
|
|
931
|
-
const sessionRunManager = this.options.sessionRunManager;
|
|
932
|
-
const { input, session } = params;
|
|
933
|
-
const beginResult = this.begin({
|
|
934
|
-
inputMessages: input.messages,
|
|
935
|
-
requestMetadata: input.metadata ?? {},
|
|
936
|
-
sessionId: input.sessionId,
|
|
937
|
-
sessionMessages: session.stateManager.getSnapshot().messages,
|
|
938
|
-
...session.agentId ? { storedAgentId: session.agentId } : {},
|
|
939
|
-
storedMetadata: input.metadata ?? {}
|
|
940
|
-
});
|
|
941
|
-
yield* this.applyLivePreflightResult({
|
|
942
|
-
input,
|
|
943
|
-
result: beginResult,
|
|
944
|
-
session,
|
|
945
|
-
sessionRunManager
|
|
946
|
-
});
|
|
947
|
-
if (!beginResult.pendingCompaction) return;
|
|
948
|
-
const finishResult = await this.finish(beginResult.pendingCompaction);
|
|
949
|
-
yield* this.applyLivePreflightResult({
|
|
950
|
-
input,
|
|
951
|
-
result: finishResult,
|
|
952
|
-
session,
|
|
953
|
-
sessionRunManager
|
|
954
|
-
});
|
|
955
|
-
};
|
|
956
802
|
begin = (params) => {
|
|
957
803
|
const { inputMessages, requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
|
|
958
804
|
const profile = resolveCompactionProfile({
|
|
@@ -1003,7 +849,6 @@ var ContextCompactionManager = class {
|
|
|
1003
849
|
pendingCompaction: plan && checkpoint ? {
|
|
1004
850
|
checkpoint,
|
|
1005
851
|
contextTokens,
|
|
1006
|
-
inputMessageIds: inputMessages.map((message) => message.id),
|
|
1007
852
|
model: profile.model,
|
|
1008
853
|
plan,
|
|
1009
854
|
reservedContextTokens,
|
|
@@ -1075,6 +920,61 @@ var ContextCompactionManager = class {
|
|
|
1075
920
|
if (!summary) throw new Error("context compaction summary is empty");
|
|
1076
921
|
return summary;
|
|
1077
922
|
};
|
|
923
|
+
};
|
|
924
|
+
//#endregion
|
|
925
|
+
//#region src/features/context-compaction/managers/context-compaction.manager.ts
|
|
926
|
+
var ContextWindowPreviewManager = class {
|
|
927
|
+
preflightService;
|
|
928
|
+
constructor(options) {
|
|
929
|
+
this.options = options;
|
|
930
|
+
this.preflightService = new ContextCompactionPreflightService({ configManager: options.configManager });
|
|
931
|
+
}
|
|
932
|
+
preview = (params) => {
|
|
933
|
+
const { requestMetadata, sessionId, sessionMessages, storedAgentId, storedMetadata } = params;
|
|
934
|
+
return this.preflightService.preview({
|
|
935
|
+
requestMetadata,
|
|
936
|
+
sessionId,
|
|
937
|
+
sessionMessages,
|
|
938
|
+
storedAgentId,
|
|
939
|
+
storedMetadata
|
|
940
|
+
});
|
|
941
|
+
};
|
|
942
|
+
};
|
|
943
|
+
var ContextCompactionManager = class {
|
|
944
|
+
preflightService;
|
|
945
|
+
constructor(options) {
|
|
946
|
+
this.options = options;
|
|
947
|
+
this.preflightService = new ContextCompactionPreflightService({
|
|
948
|
+
configManager: options.configManager,
|
|
949
|
+
providerManager: options.providerManager
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
runLivePreflight = async function* (params) {
|
|
953
|
+
const sessionRunManager = this.options.sessionRunManager;
|
|
954
|
+
const { input, session } = params;
|
|
955
|
+
const beginResult = this.preflightService.begin({
|
|
956
|
+
inputMessages: input.messages,
|
|
957
|
+
requestMetadata: input.metadata ?? {},
|
|
958
|
+
sessionId: input.sessionId,
|
|
959
|
+
sessionMessages: session.stateManager.getSnapshot().messages,
|
|
960
|
+
...session.agentId ? { storedAgentId: session.agentId } : {},
|
|
961
|
+
storedMetadata: input.metadata ?? {}
|
|
962
|
+
});
|
|
963
|
+
yield* this.applyLivePreflightResult({
|
|
964
|
+
input,
|
|
965
|
+
result: beginResult,
|
|
966
|
+
session,
|
|
967
|
+
sessionRunManager
|
|
968
|
+
});
|
|
969
|
+
if (!beginResult.pendingCompaction) return;
|
|
970
|
+
const finishResult = await this.preflightService.finish(beginResult.pendingCompaction);
|
|
971
|
+
yield* this.applyLivePreflightResult({
|
|
972
|
+
input,
|
|
973
|
+
result: finishResult,
|
|
974
|
+
session,
|
|
975
|
+
sessionRunManager
|
|
976
|
+
});
|
|
977
|
+
};
|
|
1078
978
|
applyLivePreflightResult = async function* (params) {
|
|
1079
979
|
const { input, result, session, sessionRunManager } = params;
|
|
1080
980
|
if (Object.keys(result.metadataPatch).length > 0) await sessionRunManager.updateSessionMetadata(session.sessionId, result.metadataPatch);
|
|
@@ -1107,6 +1007,46 @@ var ContextCompactionManager = class {
|
|
|
1107
1007
|
};
|
|
1108
1008
|
};
|
|
1109
1009
|
//#endregion
|
|
1010
|
+
//#region src/features/context-compaction/utils/context-window-event.utils.ts
|
|
1011
|
+
function readContextWindowEventSessionId(event) {
|
|
1012
|
+
const payload = "payload" in event ? event.payload : null;
|
|
1013
|
+
if (!payload || typeof payload !== "object") return null;
|
|
1014
|
+
return "sessionId" in payload && typeof payload.sessionId === "string" ? payload.sessionId.trim() || null : null;
|
|
1015
|
+
}
|
|
1016
|
+
function isContextWindowSnapshot(value) {
|
|
1017
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1018
|
+
}
|
|
1019
|
+
function createContextWindowSignature(value) {
|
|
1020
|
+
return JSON.stringify(value);
|
|
1021
|
+
}
|
|
1022
|
+
function shouldRefreshContextWindowDuringStream(event) {
|
|
1023
|
+
switch (event.type) {
|
|
1024
|
+
case NcpEventType.MessageTextStart:
|
|
1025
|
+
case NcpEventType.MessageTextDelta:
|
|
1026
|
+
case NcpEventType.MessageTextEnd:
|
|
1027
|
+
case NcpEventType.MessageReasoningStart:
|
|
1028
|
+
case NcpEventType.MessageReasoningDelta:
|
|
1029
|
+
case NcpEventType.MessageReasoningEnd:
|
|
1030
|
+
case NcpEventType.MessageToolCallStart:
|
|
1031
|
+
case NcpEventType.MessageToolCallArgs:
|
|
1032
|
+
case NcpEventType.MessageToolCallArgsDelta:
|
|
1033
|
+
case NcpEventType.MessageToolCallEnd:
|
|
1034
|
+
case NcpEventType.MessageToolCallResult: return true;
|
|
1035
|
+
default: return false;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
function shouldRefreshContextWindowImmediately(event) {
|
|
1039
|
+
switch (event.type) {
|
|
1040
|
+
case NcpEventType.MessageSent:
|
|
1041
|
+
case NcpEventType.MessageCompleted:
|
|
1042
|
+
case NcpEventType.MessageFailed:
|
|
1043
|
+
case NcpEventType.MessageAbort:
|
|
1044
|
+
case NcpEventType.RunFinished:
|
|
1045
|
+
case NcpEventType.RunError: return true;
|
|
1046
|
+
default: return false;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
//#endregion
|
|
1110
1050
|
//#region src/managers/tool.manager.ts
|
|
1111
1051
|
function toToolParams(args) {
|
|
1112
1052
|
if (isRecord$7(args)) return args;
|
|
@@ -1229,36 +1169,94 @@ function resolveAgentHandoffDepth(metadata) {
|
|
|
1229
1169
|
return Math.trunc(rawDepth);
|
|
1230
1170
|
}
|
|
1231
1171
|
//#endregion
|
|
1232
|
-
//#region src/features/native-runtime/
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
function mergeInputMetadata(input) {
|
|
1238
|
-
const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$6(message.metadata))?.metadata;
|
|
1239
|
-
return {
|
|
1240
|
-
...isRecord$6(messageMetadata) ? structuredClone(messageMetadata) : {},
|
|
1241
|
-
...isRecord$6(input.metadata) ? structuredClone(input.metadata) : {}
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
|
|
1245
|
-
function resolveRequestedToolNames(metadata) {
|
|
1246
|
-
const rawValue = metadata.requested_tools ?? metadata.requestedTools;
|
|
1247
|
-
if (!Array.isArray(rawValue)) return [];
|
|
1248
|
-
return Array.from(new Set(rawValue.map((item) => normalizeString(item)).filter((item) => Boolean(item))));
|
|
1172
|
+
//#region src/features/native-runtime/utils/nextclaw-ncp-session-preferences.utils.ts
|
|
1173
|
+
function normalizeOptionalString(value) {
|
|
1174
|
+
if (typeof value !== "string") return;
|
|
1175
|
+
const trimmed = value.trim();
|
|
1176
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1249
1177
|
}
|
|
1250
|
-
function
|
|
1251
|
-
|
|
1178
|
+
function readMetadataModel(metadata) {
|
|
1179
|
+
const candidates = [
|
|
1180
|
+
metadata.model,
|
|
1181
|
+
metadata.llm_model,
|
|
1182
|
+
metadata.agent_model,
|
|
1183
|
+
metadata.session_model
|
|
1184
|
+
];
|
|
1185
|
+
for (const candidate of candidates) {
|
|
1186
|
+
const normalized = normalizeOptionalString(candidate);
|
|
1187
|
+
if (normalized) return normalized;
|
|
1188
|
+
}
|
|
1189
|
+
return null;
|
|
1252
1190
|
}
|
|
1253
|
-
function
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1191
|
+
function readMetadataThinking(metadata) {
|
|
1192
|
+
const candidates = [
|
|
1193
|
+
metadata.thinking,
|
|
1194
|
+
metadata.thinking_level,
|
|
1195
|
+
metadata.thinkingLevel,
|
|
1196
|
+
metadata.thinking_effort,
|
|
1197
|
+
metadata.thinkingEffort
|
|
1198
|
+
];
|
|
1199
|
+
for (const candidate of candidates) {
|
|
1200
|
+
if (typeof candidate !== "string") continue;
|
|
1201
|
+
const normalized = candidate.trim().toLowerCase();
|
|
1202
|
+
if (!normalized) continue;
|
|
1203
|
+
if (normalized === "clear" || normalized === "reset" || normalized === "off!") return "__clear__";
|
|
1204
|
+
const level = parseThinkingLevel(normalized);
|
|
1205
|
+
if (level) return level;
|
|
1206
|
+
}
|
|
1207
|
+
return null;
|
|
1208
|
+
}
|
|
1209
|
+
function resolveEffectiveModel(params) {
|
|
1210
|
+
const { fallbackModel, requestMetadata } = params;
|
|
1211
|
+
const metadata = structuredClone(params.sessionMetadata);
|
|
1212
|
+
if (requestMetadata.clear_model === true || requestMetadata.reset_model === true) delete metadata.preferred_model;
|
|
1213
|
+
const inboundModel = readMetadataModel(requestMetadata);
|
|
1214
|
+
if (inboundModel) metadata.preferred_model = inboundModel;
|
|
1215
|
+
return {
|
|
1216
|
+
metadata,
|
|
1217
|
+
model: normalizeOptionalString(metadata.preferred_model) ?? fallbackModel
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function syncSessionThinkingPreference(params) {
|
|
1221
|
+
const { requestMetadata } = params;
|
|
1222
|
+
const metadata = structuredClone(params.sessionMetadata);
|
|
1223
|
+
if (requestMetadata.clear_thinking === true || requestMetadata.reset_thinking === true) delete metadata.preferred_thinking;
|
|
1224
|
+
const inboundThinking = readMetadataThinking(requestMetadata);
|
|
1225
|
+
if (inboundThinking === "__clear__") {
|
|
1226
|
+
delete metadata.preferred_thinking;
|
|
1227
|
+
return metadata;
|
|
1228
|
+
}
|
|
1229
|
+
if (inboundThinking) metadata.preferred_thinking = inboundThinking;
|
|
1230
|
+
return metadata;
|
|
1231
|
+
}
|
|
1232
|
+
function resolveSessionChannelContext(params) {
|
|
1233
|
+
const { requestMetadata } = params;
|
|
1234
|
+
const metadata = structuredClone(params.sessionMetadata);
|
|
1235
|
+
const channel = normalizeOptionalString(requestMetadata.channel) ?? normalizeOptionalString(metadata.last_channel) ?? "ui";
|
|
1236
|
+
const chatId = normalizeOptionalString(requestMetadata.chatId) ?? normalizeOptionalString(requestMetadata.chat_id) ?? normalizeOptionalString(metadata.last_to) ?? "web-ui";
|
|
1237
|
+
metadata.last_channel = channel;
|
|
1238
|
+
metadata.last_to = chatId;
|
|
1239
|
+
return {
|
|
1240
|
+
channel,
|
|
1241
|
+
chatId,
|
|
1242
|
+
metadata
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
//#endregion
|
|
1246
|
+
//#region src/features/native-runtime/utils/nextclaw-ncp-run-context.utils.ts
|
|
1247
|
+
const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
|
|
1248
|
+
function readRequestedAgentId(metadata) {
|
|
1249
|
+
return normalizeOptionalString(metadata.agent_id)?.toLowerCase() ?? normalizeOptionalString(metadata.agentId)?.toLowerCase() ?? null;
|
|
1250
|
+
}
|
|
1251
|
+
function resolveAgentProfile(params) {
|
|
1252
|
+
const { config, requestMetadata, storedAgentId } = params;
|
|
1253
|
+
const { agents: { defaults }, search: searchConfig, tools: { restrictToWorkspace, exec: { timeout: execTimeoutSeconds } } } = config;
|
|
1254
|
+
const defaultAgentId = resolveDefaultAgentProfileId(config);
|
|
1255
|
+
const profile = findEffectiveAgentProfile(config, normalizeOptionalString(storedAgentId)?.toLowerCase() ?? readRequestedAgentId(requestMetadata) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
|
|
1256
|
+
if (!profile) throw new Error(`default agent profile not found: ${defaultAgentId}`);
|
|
1257
|
+
const contextTokens = profile.contextTokens ?? defaults.contextTokens;
|
|
1258
|
+
return {
|
|
1259
|
+
agentId: profile.id,
|
|
1262
1260
|
workspace: getWorkspacePath(profile.workspace ?? defaults.workspace),
|
|
1263
1261
|
model: profile.model ?? defaults.model,
|
|
1264
1262
|
contextTokens,
|
|
@@ -1271,6 +1269,105 @@ function resolveAgentProfile(params) {
|
|
|
1271
1269
|
execTimeoutSeconds
|
|
1272
1270
|
};
|
|
1273
1271
|
}
|
|
1272
|
+
function resolveRequestedToolNames(metadata) {
|
|
1273
|
+
const rawValue = metadata.requested_tools ?? metadata.requestedTools;
|
|
1274
|
+
if (!Array.isArray(rawValue)) return [];
|
|
1275
|
+
return Array.from(new Set(rawValue.map((item) => normalizeOptionalString(item)).filter((item) => Boolean(item))));
|
|
1276
|
+
}
|
|
1277
|
+
function mergeRunMetadata(params) {
|
|
1278
|
+
const { requestMetadata, sessionMetadata } = params;
|
|
1279
|
+
return {
|
|
1280
|
+
...sessionMetadata ? structuredClone(sessionMetadata) : {},
|
|
1281
|
+
...requestMetadata ? structuredClone(requestMetadata) : {}
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
function buildSessionOrchestrationSection() {
|
|
1285
|
+
return [
|
|
1286
|
+
"## Session Orchestration",
|
|
1287
|
+
"- Before passing a non-default `runtime` to `sessions_spawn` or agent creation/update flows, inspect the installed runtime kinds with `nextclaw agents runtimes --json`.",
|
|
1288
|
+
"- `sessions_spawn` is the unified session-creation tool. Omit `scope` or use `scope=\"standalone\"` for a regular session, and use `scope=\"child\"` when the new session should be a child session of the current flow.",
|
|
1289
|
+
"- `sessions_spawn` only creates the session by default. Add top-level `notify: \"none\" | \"final_reply\"` when the new session should start working immediately.",
|
|
1290
|
+
"- When `sessions_spawn.scope=\"child\"` and `sessions_spawn.notify=\"final_reply\"`, the new child session starts right away and this session automatically continues after that child reaches its final reply.",
|
|
1291
|
+
"- Use `sessions_spawn` without `notify` when the user wants a separate thread created now but does not need it to start working yet.",
|
|
1292
|
+
"- Use `sessions_request` to send one task to an existing session, including a session that was just created by `sessions_spawn` or a previously created child session.",
|
|
1293
|
+
"- `sessions_request.target` must be an object shaped like `{ \"session_id\": \"<target-session-id>\" }`. Do not pass a bare string.",
|
|
1294
|
+
"- Prefer `notify=\"final_reply\"` when the current session should continue after the target session produces its final reply. Use `notify=\"none\"` when you only want the target session to run independently."
|
|
1295
|
+
].join("\n");
|
|
1296
|
+
}
|
|
1297
|
+
function resolveNextclawNcpRunContext(params) {
|
|
1298
|
+
const { configManager, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata, storedAgentId } = params;
|
|
1299
|
+
const config = configManager.loadConfig();
|
|
1300
|
+
const requestMetadata = mergeRunMetadata({
|
|
1301
|
+
sessionMetadata: inputSessionMetadata,
|
|
1302
|
+
requestMetadata: inputRequestMetadata
|
|
1303
|
+
});
|
|
1304
|
+
const profile = resolveAgentProfile({
|
|
1305
|
+
config,
|
|
1306
|
+
storedAgentId,
|
|
1307
|
+
requestMetadata
|
|
1308
|
+
});
|
|
1309
|
+
const { metadata: modelMetadata, model: effectiveModel } = resolveEffectiveModel({
|
|
1310
|
+
sessionMetadata: requestMetadata,
|
|
1311
|
+
requestMetadata,
|
|
1312
|
+
fallbackModel: profile.model
|
|
1313
|
+
});
|
|
1314
|
+
const effectiveWorkspace = resolveSessionWorkspacePath({
|
|
1315
|
+
sessionMetadata: modelMetadata,
|
|
1316
|
+
workspace: profile.workspace
|
|
1317
|
+
});
|
|
1318
|
+
const channelContext = resolveSessionChannelContext({
|
|
1319
|
+
sessionMetadata: modelMetadata,
|
|
1320
|
+
requestMetadata
|
|
1321
|
+
});
|
|
1322
|
+
const sessionMetadata = channelContext.metadata;
|
|
1323
|
+
const requestedSkills = REQUESTED_SKILLS_METADATA_READER.readSelection(requestMetadata);
|
|
1324
|
+
const runtimeThinking = resolveThinkingLevel({
|
|
1325
|
+
config,
|
|
1326
|
+
agentId: profile.agentId,
|
|
1327
|
+
model: effectiveModel,
|
|
1328
|
+
sessionThinkingLevel: parseThinkingLevel(sessionMetadata.preferred_thinking) ?? null
|
|
1329
|
+
});
|
|
1330
|
+
return {
|
|
1331
|
+
channel: channelContext.channel,
|
|
1332
|
+
chatId: channelContext.chatId,
|
|
1333
|
+
config,
|
|
1334
|
+
effectiveModel,
|
|
1335
|
+
effectiveWorkspace,
|
|
1336
|
+
profile,
|
|
1337
|
+
requestMetadata,
|
|
1338
|
+
requestedSkills,
|
|
1339
|
+
requestedToolNames: resolveRequestedToolNames(requestMetadata),
|
|
1340
|
+
runtimeThinking,
|
|
1341
|
+
sessionKey: sessionId,
|
|
1342
|
+
sessionMetadata,
|
|
1343
|
+
toolRunContext: {
|
|
1344
|
+
sessionId,
|
|
1345
|
+
channel: channelContext.channel,
|
|
1346
|
+
chatId: channelContext.chatId,
|
|
1347
|
+
agentId: profile.agentId,
|
|
1348
|
+
config,
|
|
1349
|
+
execTimeoutSeconds: profile.execTimeoutSeconds,
|
|
1350
|
+
handoffDepth: resolveAgentHandoffDepth(requestMetadata),
|
|
1351
|
+
metadata: requestMetadata,
|
|
1352
|
+
restrictToWorkspace: profile.restrictToWorkspace,
|
|
1353
|
+
searchConfig: profile.searchConfig,
|
|
1354
|
+
workspace: effectiveWorkspace
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
//#endregion
|
|
1359
|
+
//#region src/features/native-runtime/services/nextclaw-ncp-context-builder.service.ts
|
|
1360
|
+
const TIME_HINT_TRIGGER_PATTERNS = [/\b(now|right now|current time|what time|today|tonight|tomorrow|yesterday|this morning|this afternoon|this evening|date)\b/i, /(现在|此刻|当前时间|现在几点|几点了|今天|今晚|今早|今晨|明天|昨天|日期)/];
|
|
1361
|
+
function isRecord$6(value) {
|
|
1362
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1363
|
+
}
|
|
1364
|
+
function mergeInputMetadata(input) {
|
|
1365
|
+
const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$6(message.metadata))?.metadata;
|
|
1366
|
+
return {
|
|
1367
|
+
...isRecord$6(messageMetadata) ? structuredClone(messageMetadata) : {},
|
|
1368
|
+
...isRecord$6(input.metadata) ? structuredClone(input.metadata) : {}
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1274
1371
|
function shouldAppendTimeHint(content) {
|
|
1275
1372
|
const normalized = content.trim();
|
|
1276
1373
|
if (!normalized) return false;
|
|
@@ -1295,19 +1392,6 @@ function prependRequestedSkills(content, requestedSkillSelectors) {
|
|
|
1295
1392
|
if (requestedSkillSelectors.length === 0) return content;
|
|
1296
1393
|
return `[Requested skills for this turn: ${requestedSkillSelectors.join(", ")}]\n\n${content}`;
|
|
1297
1394
|
}
|
|
1298
|
-
function buildSessionOrchestrationSection() {
|
|
1299
|
-
return [
|
|
1300
|
-
"## Session Orchestration",
|
|
1301
|
-
"- Before passing a non-default `runtime` to `sessions_spawn` or agent creation/update flows, inspect the installed runtime kinds with `nextclaw agents runtimes --json`.",
|
|
1302
|
-
"- `sessions_spawn` is the unified session-creation tool. Omit `scope` or use `scope=\"standalone\"` for a regular session, and use `scope=\"child\"` when the new session should be a child session of the current flow.",
|
|
1303
|
-
"- `sessions_spawn` only creates the session by default. Add top-level `notify: \"none\" | \"final_reply\"` when the new session should start working immediately.",
|
|
1304
|
-
"- When `sessions_spawn.scope=\"child\"` and `sessions_spawn.notify=\"final_reply\"`, the new child session starts right away and this session automatically continues after that child reaches its final reply.",
|
|
1305
|
-
"- Use `sessions_spawn` without `notify` when the user wants a separate thread created now but does not need it to start working yet.",
|
|
1306
|
-
"- Use `sessions_request` to send one task to an existing session, including a session that was just created by `sessions_spawn` or a previously created child session.",
|
|
1307
|
-
"- `sessions_request.target` must be an object shaped like `{ \"session_id\": \"<target-session-id>\" }`. Do not pass a bare string.",
|
|
1308
|
-
"- Prefer `notify=\"final_reply\"` when the current session should continue after the target session produces its final reply. Use `notify=\"none\"` when you only want the target session to run independently."
|
|
1309
|
-
].join("\n");
|
|
1310
|
-
}
|
|
1311
1395
|
function buildRequestedOpenAiTools(toolDefinitions, requestedToolNames) {
|
|
1312
1396
|
const tools = toolDefinitions.map(buildOpenAiFunctionTool);
|
|
1313
1397
|
if (tools.length === 0) return;
|
|
@@ -1332,68 +1416,25 @@ var NextclawNcpContextBuilder = class {
|
|
|
1332
1416
|
};
|
|
1333
1417
|
};
|
|
1334
1418
|
prepareRunContext = (input) => {
|
|
1335
|
-
const config = this.options.configManager.loadConfig();
|
|
1336
1419
|
const requestMetadata = mergeInputMetadata(input);
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
storedAgentId: this.options.agentId,
|
|
1341
|
-
requestMetadata
|
|
1342
|
-
});
|
|
1343
|
-
let { model: effectiveModel } = resolveEffectiveModel({
|
|
1344
|
-
sessionMetadata,
|
|
1420
|
+
const resolved = resolveNextclawNcpRunContext({
|
|
1421
|
+
configManager: this.options.configManager,
|
|
1422
|
+
sessionId: input.sessionId,
|
|
1345
1423
|
requestMetadata,
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
const effectiveWorkspace = resolveSessionWorkspacePath({
|
|
1349
|
-
sessionMetadata,
|
|
1350
|
-
workspace: profile.workspace
|
|
1351
|
-
});
|
|
1352
|
-
const { channel, chatId } = resolveSessionChannelContext({
|
|
1353
|
-
sessionMetadata,
|
|
1354
|
-
requestMetadata
|
|
1424
|
+
sessionMetadata: requestMetadata,
|
|
1425
|
+
storedAgentId: this.options.agentId
|
|
1355
1426
|
});
|
|
1356
|
-
const requestedSkills = REQUESTED_SKILLS_METADATA_READER.readSelection(requestMetadata);
|
|
1357
1427
|
const currentTurn = buildCurrentTurnState({
|
|
1358
1428
|
input,
|
|
1359
|
-
currentModel: effectiveModel,
|
|
1360
|
-
formatPrompt: ({ text, timestamp }) => appendTimeHintForPrompt(prependRequestedSkills(text, requestedSkills.selectors), timestamp),
|
|
1429
|
+
currentModel: resolved.effectiveModel,
|
|
1430
|
+
formatPrompt: ({ text, timestamp }) => appendTimeHintForPrompt(prependRequestedSkills(text, resolved.requestedSkills.selectors), timestamp),
|
|
1361
1431
|
assetStore: this.options.assetStore
|
|
1362
1432
|
});
|
|
1363
|
-
|
|
1364
|
-
const runtimeThinking = resolveThinkingLevel({
|
|
1365
|
-
config,
|
|
1366
|
-
agentId: profile.agentId,
|
|
1367
|
-
model: effectiveModel,
|
|
1368
|
-
sessionThinkingLevel: parseThinkingLevel(sessionMetadata.preferred_thinking) ?? null
|
|
1369
|
-
});
|
|
1370
|
-
this.options.toolRegistry.prepareForRun({
|
|
1371
|
-
sessionId: input.sessionId,
|
|
1372
|
-
channel,
|
|
1373
|
-
chatId,
|
|
1374
|
-
agentId: profile.agentId,
|
|
1375
|
-
config,
|
|
1376
|
-
execTimeoutSeconds: profile.execTimeoutSeconds,
|
|
1377
|
-
handoffDepth: resolveAgentHandoffDepth(requestMetadata),
|
|
1378
|
-
metadata: requestMetadata,
|
|
1379
|
-
restrictToWorkspace: profile.restrictToWorkspace,
|
|
1380
|
-
searchConfig: profile.searchConfig,
|
|
1381
|
-
workspace: effectiveWorkspace
|
|
1382
|
-
});
|
|
1433
|
+
this.options.toolRegistry.prepareForRun(resolved.toolRunContext);
|
|
1383
1434
|
return {
|
|
1384
|
-
|
|
1385
|
-
chatId,
|
|
1386
|
-
config,
|
|
1435
|
+
...resolved,
|
|
1387
1436
|
currentTurn,
|
|
1388
|
-
effectiveModel
|
|
1389
|
-
effectiveWorkspace,
|
|
1390
|
-
profile,
|
|
1391
|
-
requestMetadata,
|
|
1392
|
-
requestedSkills,
|
|
1393
|
-
requestedToolNames: resolveRequestedToolNames(requestMetadata),
|
|
1394
|
-
runtimeThinking,
|
|
1395
|
-
sessionMetadata,
|
|
1396
|
-
sessionKey: input.sessionId
|
|
1437
|
+
effectiveModel: currentTurn.effectiveModel
|
|
1397
1438
|
};
|
|
1398
1439
|
};
|
|
1399
1440
|
buildModelMessages = (input, _options, runContext) => {
|
|
@@ -1564,13 +1605,13 @@ var NativeAgentRuntimeFactory = class {
|
|
|
1564
1605
|
};
|
|
1565
1606
|
//#endregion
|
|
1566
1607
|
//#region src/features/native-runtime/tools/ncp-asset.tools.ts
|
|
1567
|
-
function readOptionalString$
|
|
1608
|
+
function readOptionalString$5(value) {
|
|
1568
1609
|
if (typeof value !== "string") return null;
|
|
1569
1610
|
const trimmed = value.trim();
|
|
1570
1611
|
return trimmed.length > 0 ? trimmed : null;
|
|
1571
1612
|
}
|
|
1572
1613
|
function readOptionalBase64Bytes(value) {
|
|
1573
|
-
const base64 = readOptionalString$
|
|
1614
|
+
const base64 = readOptionalString$5(value);
|
|
1574
1615
|
if (!base64) return null;
|
|
1575
1616
|
try {
|
|
1576
1617
|
return Buffer.from(base64, "base64");
|
|
@@ -1621,18 +1662,18 @@ var AssetPutTool = class {
|
|
|
1621
1662
|
this.contentBasePath = contentBasePath;
|
|
1622
1663
|
}
|
|
1623
1664
|
validateArgs = (args) => {
|
|
1624
|
-
const path = readOptionalString$
|
|
1625
|
-
const bytesBase64 = readOptionalString$
|
|
1626
|
-
const fileName = readOptionalString$
|
|
1665
|
+
const path = readOptionalString$5(args.path);
|
|
1666
|
+
const bytesBase64 = readOptionalString$5(args.bytesBase64);
|
|
1667
|
+
const fileName = readOptionalString$5(args.fileName);
|
|
1627
1668
|
if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
|
|
1628
1669
|
if (path) return [];
|
|
1629
1670
|
if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
|
|
1630
1671
|
return ["Provide either path, or bytesBase64 + fileName."];
|
|
1631
1672
|
};
|
|
1632
1673
|
execute = async (args) => {
|
|
1633
|
-
const path = readOptionalString$
|
|
1634
|
-
const fileName = readOptionalString$
|
|
1635
|
-
const mimeType = readOptionalString$
|
|
1674
|
+
const path = readOptionalString$5(args?.path);
|
|
1675
|
+
const fileName = readOptionalString$5(args?.fileName);
|
|
1676
|
+
const mimeType = readOptionalString$5(args?.mimeType);
|
|
1636
1677
|
const bytes = readOptionalBase64Bytes(args?.bytesBase64);
|
|
1637
1678
|
if (path) return {
|
|
1638
1679
|
ok: true,
|
|
@@ -1675,8 +1716,8 @@ var AssetExportTool = class {
|
|
|
1675
1716
|
this.assetStore = assetStore;
|
|
1676
1717
|
}
|
|
1677
1718
|
execute = async (args) => {
|
|
1678
|
-
const assetUri = readOptionalString$
|
|
1679
|
-
const targetPath = readOptionalString$
|
|
1719
|
+
const assetUri = readOptionalString$5(args?.assetUri);
|
|
1720
|
+
const targetPath = readOptionalString$5(args?.targetPath);
|
|
1680
1721
|
if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
|
|
1681
1722
|
return {
|
|
1682
1723
|
ok: true,
|
|
@@ -1702,7 +1743,7 @@ var AssetStatTool = class {
|
|
|
1702
1743
|
this.contentBasePath = contentBasePath;
|
|
1703
1744
|
}
|
|
1704
1745
|
execute = async (args) => {
|
|
1705
|
-
const assetUri = readOptionalString$
|
|
1746
|
+
const assetUri = readOptionalString$5(args?.assetUri);
|
|
1706
1747
|
if (!assetUri) throw new Error("asset_stat requires assetUri.");
|
|
1707
1748
|
const record = await this.assetStore.statRecord(assetUri);
|
|
1708
1749
|
if (!record) return {
|
|
@@ -1938,8 +1979,10 @@ var AgentRunRequestManager = class {
|
|
|
1938
1979
|
};
|
|
1939
1980
|
};
|
|
1940
1981
|
//#endregion
|
|
1941
|
-
//#region src/
|
|
1982
|
+
//#region src/configs/agent-runtime.config.ts
|
|
1942
1983
|
const DEFAULT_AGENT_RUNTIME_ENTRY_ID = "native";
|
|
1984
|
+
//#endregion
|
|
1985
|
+
//#region src/features/runtime-registry/services/agent-runtime-registry.service.ts
|
|
1943
1986
|
function normalizeIdentifier(value) {
|
|
1944
1987
|
if (typeof value !== "string") return null;
|
|
1945
1988
|
const normalized = value.trim().toLowerCase();
|
|
@@ -2232,6 +2275,11 @@ var ConfigManager = class {
|
|
|
2232
2275
|
return this.currentConfig;
|
|
2233
2276
|
}
|
|
2234
2277
|
loadConfig = () => resolveConfigSecrets(loadConfig(this.configPath), { configPath: this.configPath });
|
|
2278
|
+
getDefaultModel = () => this.loadConfig().agents.defaults.model;
|
|
2279
|
+
getModelMaxTokens = (model) => {
|
|
2280
|
+
const value = this.loadConfig().agents.defaults.models[model]?.params?.max_tokens;
|
|
2281
|
+
return typeof value === "number" ? Math.trunc(value) : void 0;
|
|
2282
|
+
};
|
|
2235
2283
|
installRuntimeHooks = (hooks) => {
|
|
2236
2284
|
this.hooks = {
|
|
2237
2285
|
...this.hooks,
|
|
@@ -2246,14 +2294,6 @@ var ConfigManager = class {
|
|
|
2246
2294
|
if (!changedPaths.length) return;
|
|
2247
2295
|
this.currentConfig = nextConfig;
|
|
2248
2296
|
const plan = buildReloadPlan(changedPaths);
|
|
2249
|
-
let reloadPluginsResult = void 0;
|
|
2250
|
-
if (plan.reloadPlugins) {
|
|
2251
|
-
reloadPluginsResult = await this.reloadPlugins({
|
|
2252
|
-
config: nextConfig,
|
|
2253
|
-
changedPaths
|
|
2254
|
-
});
|
|
2255
|
-
console.log("Config reload: plugins reloaded.");
|
|
2256
|
-
}
|
|
2257
2297
|
if (plan.reloadMcp) {
|
|
2258
2298
|
await this.reloadMcp({
|
|
2259
2299
|
config: nextConfig,
|
|
@@ -2268,7 +2308,7 @@ var ConfigManager = class {
|
|
|
2268
2308
|
});
|
|
2269
2309
|
console.log("Config reload: companion setting applied.");
|
|
2270
2310
|
}
|
|
2271
|
-
if (plan.restartChannels
|
|
2311
|
+
if (plan.restartChannels) {
|
|
2272
2312
|
await this.rebuildChannels(nextConfig, { start: true });
|
|
2273
2313
|
console.log("Config reload: channels restarted.");
|
|
2274
2314
|
}
|
|
@@ -2363,9 +2403,6 @@ var ConfigManager = class {
|
|
|
2363
2403
|
this.providerReloadTask = null;
|
|
2364
2404
|
}
|
|
2365
2405
|
};
|
|
2366
|
-
reloadPlugins = async (params) => {
|
|
2367
|
-
return await this.hooks.reloadPlugins?.(params);
|
|
2368
|
-
};
|
|
2369
2406
|
reloadMcp = async (params) => {
|
|
2370
2407
|
await this.hooks.reloadMcp?.(params);
|
|
2371
2408
|
};
|
|
@@ -2572,8 +2609,15 @@ var ExtensionLifecycleService = class {
|
|
|
2572
2609
|
//#region src/features/extension-runtime/services/extension-manifest-discovery.service.ts
|
|
2573
2610
|
const EXTENSION_MANIFEST_FILE = "nextclaw.extension.json";
|
|
2574
2611
|
const BUILTIN_EXTENSION_PACKAGES = [
|
|
2612
|
+
"@nextclaw/channel-extension-dingtalk",
|
|
2613
|
+
"@nextclaw/channel-extension-discord",
|
|
2614
|
+
"@nextclaw/channel-extension-email",
|
|
2575
2615
|
"@nextclaw/channel-extension-feishu",
|
|
2576
2616
|
"@nextclaw/channel-extension-qq",
|
|
2617
|
+
"@nextclaw/channel-extension-slack",
|
|
2618
|
+
"@nextclaw/channel-extension-telegram",
|
|
2619
|
+
"@nextclaw/channel-extension-wecom",
|
|
2620
|
+
"@nextclaw/channel-extension-whatsapp",
|
|
2577
2621
|
"@nextclaw/channel-extension-weixin"
|
|
2578
2622
|
];
|
|
2579
2623
|
const runtimeRequire = createRequire(import.meta.url);
|
|
@@ -2612,7 +2656,7 @@ function findExtensionManifestRoot(startPath) {
|
|
|
2612
2656
|
current = parent;
|
|
2613
2657
|
}
|
|
2614
2658
|
}
|
|
2615
|
-
function resolveDevFirstPartyExtensionDir(explicitDir = process.env.
|
|
2659
|
+
function resolveDevFirstPartyExtensionDir(explicitDir = process.env.NEXTCLAW_DEV_FIRST_PARTY_EXTENSION_DIR, moduleDir = dirname(fileURLToPath(import.meta.url))) {
|
|
2616
2660
|
const configured = explicitDir?.trim();
|
|
2617
2661
|
if (configured) return configured;
|
|
2618
2662
|
return [
|
|
@@ -2660,8 +2704,7 @@ function resolveExtensionManifestRoots(params) {
|
|
|
2660
2704
|
join(getDataPath(), "extensions"),
|
|
2661
2705
|
join(params.workspace, ".nextclaw", "extensions"),
|
|
2662
2706
|
...devExtensionsDir ? [devExtensionsDir] : [],
|
|
2663
|
-
...resolveBuiltinExtensionManifestRoots()
|
|
2664
|
-
...params.config.plugins.load?.paths ?? []
|
|
2707
|
+
...resolveBuiltinExtensionManifestRoots()
|
|
2665
2708
|
]);
|
|
2666
2709
|
}
|
|
2667
2710
|
var ExtensionManifestDiscoveryService = class {
|
|
@@ -2781,11 +2824,35 @@ function toInboundMessage(value) {
|
|
|
2781
2824
|
metadata: readRecord$1(payload.metadata)
|
|
2782
2825
|
};
|
|
2783
2826
|
}
|
|
2827
|
+
function normalizeChannelConfigResult(value) {
|
|
2828
|
+
return readRecord$1(readRecord$1(value).channelConfig);
|
|
2829
|
+
}
|
|
2830
|
+
function normalizeAuthLoginResult(value) {
|
|
2831
|
+
const record = readRecord$1(value);
|
|
2832
|
+
return {
|
|
2833
|
+
channelConfig: normalizeChannelConfigResult(record),
|
|
2834
|
+
accountId: typeof record.accountId === "string" ? record.accountId : null,
|
|
2835
|
+
notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : []
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
function normalizeAuthPollResult(value) {
|
|
2839
|
+
if (!value) return null;
|
|
2840
|
+
const record = readRecord$1(value);
|
|
2841
|
+
return {
|
|
2842
|
+
channel: readRequiredString$2(record.channel, "channel"),
|
|
2843
|
+
status: record.status,
|
|
2844
|
+
message: readString$5(record.message),
|
|
2845
|
+
nextPollMs: readOptionalNumber(record.nextPollMs),
|
|
2846
|
+
accountId: typeof record.accountId === "string" ? record.accountId : null,
|
|
2847
|
+
notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
|
|
2848
|
+
channelConfig: normalizeChannelConfigResult(record)
|
|
2849
|
+
};
|
|
2850
|
+
}
|
|
2784
2851
|
var ExtensionChannelClient = class {
|
|
2785
2852
|
constructor(params) {
|
|
2786
2853
|
this.params = params;
|
|
2787
2854
|
}
|
|
2788
|
-
login = async ({ accountId, baseUrl, verbose }) => await this.params.request({
|
|
2855
|
+
login = async ({ accountId, baseUrl, verbose }) => normalizeAuthLoginResult(await this.params.request({
|
|
2789
2856
|
extensionId: this.params.extensionId,
|
|
2790
2857
|
kind: "channel.auth.login",
|
|
2791
2858
|
payload: {
|
|
@@ -2794,7 +2861,7 @@ var ExtensionChannelClient = class {
|
|
|
2794
2861
|
baseUrl,
|
|
2795
2862
|
verbose
|
|
2796
2863
|
}
|
|
2797
|
-
});
|
|
2864
|
+
}));
|
|
2798
2865
|
start = async (params) => await this.params.request({
|
|
2799
2866
|
extensionId: this.params.extensionId,
|
|
2800
2867
|
kind: "channel.auth.start",
|
|
@@ -2805,14 +2872,24 @@ var ExtensionChannelClient = class {
|
|
|
2805
2872
|
domain: params.domain
|
|
2806
2873
|
}
|
|
2807
2874
|
});
|
|
2808
|
-
|
|
2875
|
+
connect = async (params) => normalizeAuthPollResult(await this.params.request({
|
|
2876
|
+
extensionId: this.params.extensionId,
|
|
2877
|
+
kind: "channel.auth.connect",
|
|
2878
|
+
payload: {
|
|
2879
|
+
channelId: this.params.channelId,
|
|
2880
|
+
accountId: params.accountId,
|
|
2881
|
+
domain: params.domain,
|
|
2882
|
+
fields: params.fields
|
|
2883
|
+
}
|
|
2884
|
+
}));
|
|
2885
|
+
poll = async ({ sessionId }) => normalizeAuthPollResult(await this.params.request({
|
|
2809
2886
|
extensionId: this.params.extensionId,
|
|
2810
2887
|
kind: "channel.auth.poll",
|
|
2811
2888
|
payload: {
|
|
2812
2889
|
channelId: this.params.channelId,
|
|
2813
2890
|
sessionId
|
|
2814
2891
|
}
|
|
2815
|
-
});
|
|
2892
|
+
}));
|
|
2816
2893
|
sendText = async ({ to, text, accountId, replyTo, media, metadata }) => await this.params.request({
|
|
2817
2894
|
extensionId: this.params.extensionId,
|
|
2818
2895
|
kind: "channel.outbound.sendText",
|
|
@@ -2838,6 +2915,8 @@ var ExtensionRuntimeService = class {
|
|
|
2838
2915
|
registerIngressHandlers = () => {
|
|
2839
2916
|
this.options.ingress.addHandler(ingressKeys.extension.channelConfigGet, this.handleChannelConfigGet);
|
|
2840
2917
|
this.options.ingress.addHandler(ingressKeys.extension.channelMessageSubmit, this.handleChannelMessageSubmit);
|
|
2918
|
+
this.options.ingress.addHandler(ingressKeys.extension.channelCommandList, this.handleChannelCommandList);
|
|
2919
|
+
this.options.ingress.addHandler(ingressKeys.extension.channelCommandExecute, this.handleChannelCommandExecute);
|
|
2841
2920
|
this.options.ingress.addHandler(ingressKeys.extension.response, this.handleExtensionResponse);
|
|
2842
2921
|
};
|
|
2843
2922
|
loadChannelContributions = async (params) => {
|
|
@@ -2876,7 +2955,7 @@ var ExtensionRuntimeService = class {
|
|
|
2876
2955
|
if (!channelId) continue;
|
|
2877
2956
|
const configUiHints = this.readConfigUiHints(channel.configUiHints);
|
|
2878
2957
|
channelBindings.push({
|
|
2879
|
-
|
|
2958
|
+
extensionId: manifest.id,
|
|
2880
2959
|
channelId,
|
|
2881
2960
|
channel: {
|
|
2882
2961
|
id: channelId,
|
|
@@ -2915,6 +2994,49 @@ var ExtensionRuntimeService = class {
|
|
|
2915
2994
|
await this.options.messageBus.publishInbound(toInboundMessage(envelope.payload));
|
|
2916
2995
|
return { accepted: true };
|
|
2917
2996
|
};
|
|
2997
|
+
handleChannelCommandList = (_envelope, context) => {
|
|
2998
|
+
this.assertAuthorized(context);
|
|
2999
|
+
return { commands: new CommandRegistry(this.options.getConfig(), this.options.sessionManager).listSlashCommands() };
|
|
3000
|
+
};
|
|
3001
|
+
handleChannelCommandExecute = async (envelope, context) => {
|
|
3002
|
+
this.assertAuthorized(context);
|
|
3003
|
+
const payload = readRecord$1(envelope.payload);
|
|
3004
|
+
const channel = readRequiredString$2(payload.channelId, "channelId");
|
|
3005
|
+
const chatId = readRequiredString$2(payload.conversationId, "conversationId");
|
|
3006
|
+
const senderId = readRequiredString$2(payload.senderId, "senderId");
|
|
3007
|
+
const metadata = readRecord$1(payload.metadata);
|
|
3008
|
+
const config = this.options.getConfig();
|
|
3009
|
+
const registry = new CommandRegistry(config, this.options.sessionManager);
|
|
3010
|
+
const route = new AgentRouteResolver(config).resolveInbound({
|
|
3011
|
+
message: {
|
|
3012
|
+
channel,
|
|
3013
|
+
chatId,
|
|
3014
|
+
senderId,
|
|
3015
|
+
content: readString$5(payload.rawText) ?? readString$5(payload.commandName) ?? "",
|
|
3016
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
3017
|
+
attachments: [],
|
|
3018
|
+
metadata
|
|
3019
|
+
},
|
|
3020
|
+
forcedAgentId: readString$5(metadata.target_agent_id),
|
|
3021
|
+
sessionKeyOverride: readString$5(metadata.session_key_override)
|
|
3022
|
+
});
|
|
3023
|
+
const rawText = readString$5(payload.rawText);
|
|
3024
|
+
if (rawText) return await registry.executeText(rawText, {
|
|
3025
|
+
channel,
|
|
3026
|
+
chatId,
|
|
3027
|
+
senderId,
|
|
3028
|
+
sessionKey: route.sessionKey
|
|
3029
|
+
}) ?? {
|
|
3030
|
+
content: "",
|
|
3031
|
+
ephemeral: true
|
|
3032
|
+
};
|
|
3033
|
+
return await registry.execute(readRequiredString$2(payload.commandName, "commandName"), readRecord$1(payload.args), {
|
|
3034
|
+
channel,
|
|
3035
|
+
chatId,
|
|
3036
|
+
senderId,
|
|
3037
|
+
sessionKey: route.sessionKey
|
|
3038
|
+
});
|
|
3039
|
+
};
|
|
2918
3040
|
handleExtensionResponse = (envelope, context) => {
|
|
2919
3041
|
this.assertAuthorized(context);
|
|
2920
3042
|
const payload = readRecord$1(envelope.payload);
|
|
@@ -2975,451 +3097,64 @@ var ExtensionRuntimeService = class {
|
|
|
2975
3097
|
};
|
|
2976
3098
|
};
|
|
2977
3099
|
//#endregion
|
|
2978
|
-
//#region src/
|
|
2979
|
-
|
|
2980
|
-
try {
|
|
2981
|
-
const raw = fs.readFileSync(filePath, "utf-8");
|
|
2982
|
-
const parsed = JSON.parse(raw);
|
|
2983
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
2984
|
-
} catch {
|
|
2985
|
-
return null;
|
|
2986
|
-
}
|
|
2987
|
-
};
|
|
2988
|
-
const readString$4 = (value) => {
|
|
2989
|
-
if (typeof value !== "string") return;
|
|
2990
|
-
return value.trim() || void 0;
|
|
2991
|
-
};
|
|
2992
|
-
const toPluginIdFromPackageName = (packageName) => {
|
|
2993
|
-
const trimmed = packageName.trim();
|
|
2994
|
-
if (!trimmed) return "";
|
|
2995
|
-
return trimmed.includes("/") ? trimmed.split("/").pop() ?? trimmed : trimmed;
|
|
2996
|
-
};
|
|
2997
|
-
const normalizeInstallRecordPath = (value) => {
|
|
2998
|
-
const filePath = readString$4(value);
|
|
2999
|
-
return filePath ? path.resolve(filePath) : void 0;
|
|
3000
|
-
};
|
|
3001
|
-
const resolveDevFirstPartyPluginDir = (explicitDir, moduleDir = path.dirname(fileURLToPath(import.meta.url))) => {
|
|
3002
|
-
const configured = explicitDir?.trim();
|
|
3003
|
-
if (configured) return configured;
|
|
3004
|
-
return [
|
|
3005
|
-
path.resolve(moduleDir, "../../../extensions"),
|
|
3006
|
-
path.resolve(moduleDir, "../../../../extensions"),
|
|
3007
|
-
path.resolve(moduleDir, "../../../../../extensions")
|
|
3008
|
-
].find((candidate) => fs.existsSync(candidate));
|
|
3009
|
-
};
|
|
3010
|
-
const hasOpenClawExtensions = (pkg) => {
|
|
3011
|
-
const openclaw = pkg.openclaw;
|
|
3012
|
-
if (!openclaw || typeof openclaw !== "object" || Array.isArray(openclaw)) return false;
|
|
3013
|
-
const extensions = openclaw.extensions;
|
|
3014
|
-
return Array.isArray(extensions) && extensions.some((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
3015
|
-
};
|
|
3016
|
-
const hasOpenClawDevelopmentExtensions = (pkg) => {
|
|
3017
|
-
const openclaw = pkg.openclaw;
|
|
3018
|
-
if (!openclaw || typeof openclaw !== "object" || Array.isArray(openclaw)) return false;
|
|
3019
|
-
const development = openclaw.development;
|
|
3020
|
-
if (!development || typeof development !== "object" || Array.isArray(development)) return false;
|
|
3021
|
-
const extensions = development.extensions;
|
|
3022
|
-
return Array.isArray(extensions) && extensions.some((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
3023
|
-
};
|
|
3024
|
-
const normalizePackageSpec = (spec) => {
|
|
3025
|
-
const trimmed = spec.trim();
|
|
3026
|
-
if (!trimmed) return;
|
|
3027
|
-
if (trimmed.startsWith("@")) {
|
|
3028
|
-
const slashIndex = trimmed.indexOf("/");
|
|
3029
|
-
if (slashIndex < 0) return;
|
|
3030
|
-
const secondAtIndex = trimmed.indexOf("@", slashIndex + 1);
|
|
3031
|
-
return secondAtIndex < 0 ? trimmed : trimmed.slice(0, secondAtIndex);
|
|
3032
|
-
}
|
|
3033
|
-
const versionIndex = trimmed.indexOf("@");
|
|
3034
|
-
return versionIndex < 0 ? trimmed : trimmed.slice(0, versionIndex);
|
|
3035
|
-
};
|
|
3036
|
-
const readWorkspacePluginPackages = (workspaceExtensionsDir) => {
|
|
3037
|
-
if (!workspaceExtensionsDir.trim() || !fs.existsSync(workspaceExtensionsDir)) return [];
|
|
3038
|
-
const entries = fs.readdirSync(workspaceExtensionsDir, { withFileTypes: true });
|
|
3039
|
-
const packages = [];
|
|
3040
|
-
for (const entry of entries) {
|
|
3041
|
-
if (!entry.isDirectory()) continue;
|
|
3042
|
-
const packageDir = path.join(workspaceExtensionsDir, entry.name);
|
|
3043
|
-
const pkg = readJsonFile(path.join(packageDir, "package.json"));
|
|
3044
|
-
if (!pkg || !hasOpenClawExtensions(pkg)) continue;
|
|
3045
|
-
const packageName = readString$4(pkg.name);
|
|
3046
|
-
if (!packageName?.startsWith("@nextclaw/")) continue;
|
|
3047
|
-
packages.push({
|
|
3048
|
-
pluginId: toPluginIdFromPackageName(packageName),
|
|
3049
|
-
packageName,
|
|
3050
|
-
dir: packageDir,
|
|
3051
|
-
supportsDevelopmentSource: hasOpenClawDevelopmentExtensions(pkg)
|
|
3052
|
-
});
|
|
3053
|
-
}
|
|
3054
|
-
return packages;
|
|
3055
|
-
};
|
|
3056
|
-
const readInstalledFirstPartyPluginMatches = (workspaceExtensionsDir) => {
|
|
3057
|
-
const workspacePackages = readWorkspacePluginPackages(workspaceExtensionsDir);
|
|
3058
|
-
if (workspacePackages.length === 0) return [];
|
|
3059
|
-
const globalExtensionsDir = path.join(getDataPath(), "extensions");
|
|
3060
|
-
if (!fs.existsSync(globalExtensionsDir)) return [];
|
|
3061
|
-
const workspacePackageByName = new Map(workspacePackages.map((entry) => [entry.packageName, entry]));
|
|
3062
|
-
const entries = fs.readdirSync(globalExtensionsDir, { withFileTypes: true });
|
|
3063
|
-
const matches = [];
|
|
3064
|
-
for (const entry of entries) {
|
|
3065
|
-
if (!entry.isDirectory()) continue;
|
|
3066
|
-
const packageDir = path.join(globalExtensionsDir, entry.name);
|
|
3067
|
-
const packageName = readString$4(readJsonFile(path.join(packageDir, "package.json"))?.name);
|
|
3068
|
-
if (!packageName) continue;
|
|
3069
|
-
const workspacePackage = workspacePackageByName.get(packageName);
|
|
3070
|
-
if (!workspacePackage) continue;
|
|
3071
|
-
matches.push({
|
|
3072
|
-
packageName,
|
|
3073
|
-
workspaceDir: workspacePackage.dir,
|
|
3074
|
-
installPath: packageDir
|
|
3075
|
-
});
|
|
3076
|
-
}
|
|
3077
|
-
return matches;
|
|
3078
|
-
};
|
|
3079
|
-
const mergeLoadPaths$1 = (existingLoadPaths, devLoadPaths) => {
|
|
3080
|
-
const mergedLoadPaths = [...devLoadPaths];
|
|
3081
|
-
for (const entry of existingLoadPaths) if (!mergedLoadPaths.includes(entry)) mergedLoadPaths.push(entry);
|
|
3082
|
-
return mergedLoadPaths;
|
|
3083
|
-
};
|
|
3084
|
-
const findWorkspacePackageForInstallRecord = (installRecord, workspacePackages, packageByName) => {
|
|
3085
|
-
const packageName = normalizePackageSpec(readString$4(installRecord.spec) ?? "");
|
|
3086
|
-
if (packageName) {
|
|
3087
|
-
const matchedByPackageName = packageByName.get(packageName);
|
|
3088
|
-
if (matchedByPackageName) return matchedByPackageName;
|
|
3089
|
-
}
|
|
3090
|
-
const installPathCandidates = new Set([installRecord.sourcePath, installRecord.installPath].map(normalizeInstallRecordPath).filter((entry) => Boolean(entry)));
|
|
3091
|
-
if (installPathCandidates.size === 0) return;
|
|
3092
|
-
return workspacePackages.find((workspacePackage) => installPathCandidates.has(path.resolve(workspacePackage.dir)));
|
|
3093
|
-
};
|
|
3094
|
-
const resolveDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
|
|
3095
|
-
const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
|
|
3096
|
-
if (!rootDir) return [];
|
|
3097
|
-
const workspacePackages = readWorkspacePluginPackages(rootDir);
|
|
3098
|
-
if (workspacePackages.length === 0) return [];
|
|
3099
|
-
const installedPluginMatches = readInstalledFirstPartyPluginMatches(rootDir);
|
|
3100
|
-
const packageDirByName = new Map(workspacePackages.map((entry) => [entry.packageName, entry.dir]));
|
|
3101
|
-
const packageByName = new Map(workspacePackages.map((entry) => [entry.packageName, entry]));
|
|
3102
|
-
const loadPaths = [];
|
|
3103
|
-
const installs = config.plugins.installs ?? {};
|
|
3104
|
-
for (const installRecord of Object.values(installs)) {
|
|
3105
|
-
const matchedWorkspacePackage = findWorkspacePackageForInstallRecord(installRecord, workspacePackages, packageByName);
|
|
3106
|
-
const packageDir = matchedWorkspacePackage ? matchedWorkspacePackage.dir : packageDirByName.get(normalizePackageSpec(readString$4(installRecord.spec) ?? "") ?? "");
|
|
3107
|
-
if (!packageDir || loadPaths.includes(packageDir)) continue;
|
|
3108
|
-
loadPaths.push(packageDir);
|
|
3109
|
-
}
|
|
3110
|
-
for (const installedPlugin of installedPluginMatches) {
|
|
3111
|
-
if (loadPaths.includes(installedPlugin.workspaceDir)) continue;
|
|
3112
|
-
loadPaths.push(installedPlugin.workspaceDir);
|
|
3113
|
-
}
|
|
3114
|
-
return loadPaths;
|
|
3115
|
-
};
|
|
3116
|
-
const resolveDevFirstPartyPluginInstallRoots = (config, workspaceExtensionsDir) => {
|
|
3117
|
-
const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
|
|
3118
|
-
if (!rootDir) return [];
|
|
3119
|
-
const workspacePackages = readWorkspacePluginPackages(rootDir);
|
|
3120
|
-
if (workspacePackages.length === 0) return [];
|
|
3121
|
-
const packageNames = new Set(workspacePackages.map((entry) => entry.packageName));
|
|
3122
|
-
const packageByName = new Map(workspacePackages.map((entry) => [entry.packageName, entry]));
|
|
3123
|
-
const installRoots = [];
|
|
3124
|
-
const installedPluginMatches = readInstalledFirstPartyPluginMatches(rootDir);
|
|
3125
|
-
for (const installedPlugin of installedPluginMatches) {
|
|
3126
|
-
if (installRoots.includes(installedPlugin.installPath)) continue;
|
|
3127
|
-
installRoots.push(installedPlugin.installPath);
|
|
3128
|
-
}
|
|
3129
|
-
for (const installRecord of Object.values(config.plugins.installs ?? {})) {
|
|
3130
|
-
const workspacePackage = findWorkspacePackageForInstallRecord(installRecord, workspacePackages, packageByName);
|
|
3131
|
-
const packageName = normalizePackageSpec(readString$4(installRecord.spec) ?? "");
|
|
3132
|
-
if (!workspacePackage && (!packageName || !packageNames.has(packageName))) continue;
|
|
3133
|
-
const installPath = readString$4(installRecord.installPath);
|
|
3134
|
-
if (!installPath || installRoots.includes(installPath)) continue;
|
|
3135
|
-
if (workspacePackage && path.resolve(installPath) === path.resolve(workspacePackage.dir)) continue;
|
|
3136
|
-
installRoots.push(installPath);
|
|
3137
|
-
}
|
|
3138
|
-
return installRoots;
|
|
3139
|
-
};
|
|
3140
|
-
const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
|
|
3141
|
-
const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
|
|
3142
|
-
if (!rootDir) return config;
|
|
3143
|
-
if (readWorkspacePluginPackages(rootDir).length === 0) return config;
|
|
3144
|
-
const devLoadPaths = resolveDevFirstPartyPluginLoadPaths(config, rootDir);
|
|
3145
|
-
if (devLoadPaths.length === 0) return config;
|
|
3146
|
-
const mergedLoadPaths = mergeLoadPaths$1(Array.isArray(config.plugins.load?.paths) ? config.plugins.load.paths.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [], devLoadPaths);
|
|
3100
|
+
//#region src/managers/extension.manager.ts
|
|
3101
|
+
function createEmptyExtensionRegistry() {
|
|
3147
3102
|
return {
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
load: {
|
|
3152
|
-
...config.plugins.load,
|
|
3153
|
-
paths: mergedLoadPaths
|
|
3154
|
-
}
|
|
3155
|
-
}
|
|
3103
|
+
tools: [],
|
|
3104
|
+
channels: [],
|
|
3105
|
+
diagnostics: []
|
|
3156
3106
|
};
|
|
3157
|
-
};
|
|
3158
|
-
//#endregion
|
|
3159
|
-
//#region src/features/extension-development-source/utils/dev-plugin-overrides.utils.ts
|
|
3160
|
-
const DEV_PLUGIN_OVERRIDES_ENV = "NEXTCLAW_DEV_PLUGIN_OVERRIDES";
|
|
3161
|
-
function isRecord$4(value) {
|
|
3162
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3163
|
-
}
|
|
3164
|
-
function readOptionalString$5(value) {
|
|
3165
|
-
if (typeof value !== "string") return;
|
|
3166
|
-
return value.trim() || void 0;
|
|
3167
3107
|
}
|
|
3168
|
-
function
|
|
3169
|
-
|
|
3170
|
-
if (!fs.existsSync(packageJsonPath)) return null;
|
|
3171
|
-
try {
|
|
3172
|
-
return JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
3173
|
-
} catch {
|
|
3174
|
-
return null;
|
|
3175
|
-
}
|
|
3108
|
+
function buildSortedBindingSignatures(bindings) {
|
|
3109
|
+
return bindings.map((binding) => `${binding.extensionId}:${binding.channelId}`).sort();
|
|
3176
3110
|
}
|
|
3177
|
-
function
|
|
3178
|
-
|
|
3179
|
-
const packageManifest = readPackageManifest(override.pluginPath);
|
|
3180
|
-
if (!packageManifest) throw new Error(`[dev-plugin-override] package.json is missing or invalid for "${override.pluginId}": ${override.pluginPath}`);
|
|
3181
|
-
const pluginManifest = loadPluginManifest(override.pluginPath);
|
|
3182
|
-
if (!pluginManifest.ok) throw new Error(`[dev-plugin-override] ${pluginManifest.error} for "${override.pluginId}": ${override.pluginPath}`);
|
|
3183
|
-
if (pluginManifest.manifest.id !== override.pluginId) throw new Error(`[dev-plugin-override] plugin id mismatch: expected "${override.pluginId}" but found "${pluginManifest.manifest.id}" at ${override.pluginPath}`);
|
|
3184
|
-
if (getPackageManifestExtensions(packageManifest, override.source).length === 0) {
|
|
3185
|
-
const missingEntry = override.source === "development" ? "openclaw.development.extensions" : "openclaw.extensions";
|
|
3186
|
-
throw new Error(`[dev-plugin-override] ${missingEntry} is missing for "${override.pluginId}" at ${override.pluginPath}`);
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
function readOverrideRecord(value, index) {
|
|
3190
|
-
if (!isRecord$4(value)) throw new Error(`[dev-plugin-override] override[${index}] must be an object`);
|
|
3191
|
-
const pluginId = readOptionalString$5(value.pluginId);
|
|
3192
|
-
const pluginPath = readOptionalString$5(value.pluginPath);
|
|
3193
|
-
const source = value.source === "development" ? "development" : "production";
|
|
3194
|
-
if (!pluginId || !pluginPath) throw new Error(`[dev-plugin-override] override[${index}] requires pluginId and pluginPath`);
|
|
3195
|
-
const normalized = {
|
|
3196
|
-
pluginId,
|
|
3197
|
-
pluginPath: path.resolve(pluginPath),
|
|
3198
|
-
source
|
|
3199
|
-
};
|
|
3200
|
-
assertOverridePluginReadable(normalized);
|
|
3201
|
-
return normalized;
|
|
3202
|
-
}
|
|
3203
|
-
function resolveDevPluginOverrides(rawEnv = process.env[DEV_PLUGIN_OVERRIDES_ENV]) {
|
|
3204
|
-
if (typeof rawEnv !== "string" || rawEnv.trim().length === 0) return [];
|
|
3205
|
-
let parsed;
|
|
3206
|
-
try {
|
|
3207
|
-
parsed = JSON.parse(rawEnv);
|
|
3208
|
-
} catch (error) {
|
|
3209
|
-
throw new Error(`[dev-plugin-override] failed to parse ${DEV_PLUGIN_OVERRIDES_ENV}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3210
|
-
}
|
|
3211
|
-
if (!Array.isArray(parsed)) throw new Error(`[dev-plugin-override] ${DEV_PLUGIN_OVERRIDES_ENV} must be a JSON array`);
|
|
3212
|
-
const seenPluginIds = /* @__PURE__ */ new Set();
|
|
3213
|
-
const overrides = parsed.map((entry, index) => readOverrideRecord(entry, index));
|
|
3214
|
-
for (const entry of overrides) {
|
|
3215
|
-
if (seenPluginIds.has(entry.pluginId)) throw new Error(`[dev-plugin-override] duplicate plugin override for "${entry.pluginId}"`);
|
|
3216
|
-
seenPluginIds.add(entry.pluginId);
|
|
3217
|
-
}
|
|
3218
|
-
return overrides;
|
|
3219
|
-
}
|
|
3220
|
-
function mergeLoadPaths(existingLoadPaths, overrideLoadPaths) {
|
|
3221
|
-
const merged = [...overrideLoadPaths];
|
|
3222
|
-
for (const entry of existingLoadPaths) if (!merged.includes(entry)) merged.push(entry);
|
|
3223
|
-
return merged;
|
|
3224
|
-
}
|
|
3225
|
-
function applyExplicitDevPluginOverrides(config, overrides) {
|
|
3226
|
-
if (overrides.length === 0) return config;
|
|
3227
|
-
const nextEntries = { ...config.plugins.entries ?? {} };
|
|
3228
|
-
for (const override of overrides) nextEntries[override.pluginId] = {
|
|
3229
|
-
...nextEntries[override.pluginId] ?? {},
|
|
3230
|
-
source: override.source
|
|
3231
|
-
};
|
|
3232
|
-
const existingLoadPaths = Array.isArray(config.plugins.load?.paths) ? config.plugins.load.paths.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
|
|
3233
|
-
return {
|
|
3234
|
-
...config,
|
|
3235
|
-
plugins: {
|
|
3236
|
-
...config.plugins,
|
|
3237
|
-
entries: nextEntries,
|
|
3238
|
-
load: {
|
|
3239
|
-
...config.plugins.load,
|
|
3240
|
-
paths: mergeLoadPaths(existingLoadPaths, overrides.map((entry) => entry.pluginPath))
|
|
3241
|
-
}
|
|
3242
|
-
}
|
|
3243
|
-
};
|
|
3111
|
+
function buildSortedExtensionChannelIds(channels) {
|
|
3112
|
+
return channels.map((registration) => registration.channel.id).filter((id) => typeof id === "string" && id.trim().length > 0).sort();
|
|
3244
3113
|
}
|
|
3245
|
-
function
|
|
3246
|
-
|
|
3247
|
-
for (const override of overrides) {
|
|
3248
|
-
const installRecord = config.plugins.installs?.[override.pluginId];
|
|
3249
|
-
const installPath = readOptionalString$5(installRecord?.installPath);
|
|
3250
|
-
if (!installPath || installRoots.includes(installPath)) continue;
|
|
3251
|
-
installRoots.push(installPath);
|
|
3252
|
-
}
|
|
3253
|
-
return installRoots;
|
|
3254
|
-
}
|
|
3255
|
-
function resolveDevPluginLoadingContext(config, workspaceExtensionsDir, rawOverridesEnv = process.env[DEV_PLUGIN_OVERRIDES_ENV]) {
|
|
3256
|
-
const configWithFirstPartyOverrides = applyDevFirstPartyPluginLoadPaths(config, workspaceExtensionsDir);
|
|
3257
|
-
const overrides = resolveDevPluginOverrides(rawOverridesEnv);
|
|
3258
|
-
return {
|
|
3259
|
-
configWithDevPluginOverrides: applyExplicitDevPluginOverrides(configWithFirstPartyOverrides, overrides),
|
|
3260
|
-
excludedRoots: [...resolveDevFirstPartyPluginInstallRoots(config, workspaceExtensionsDir), ...resolveDevPluginOverrideInstallRoots(config, overrides)].filter((entry, index, list) => list.indexOf(entry) === index),
|
|
3261
|
-
overrides
|
|
3262
|
-
};
|
|
3263
|
-
}
|
|
3264
|
-
//#endregion
|
|
3265
|
-
//#region src/services/extension-plugin-registry.service.ts
|
|
3266
|
-
const RESERVED_TOOL_NAMES = [
|
|
3267
|
-
"read_file",
|
|
3268
|
-
"write_file",
|
|
3269
|
-
"edit_file",
|
|
3270
|
-
"list_dir",
|
|
3271
|
-
"exec",
|
|
3272
|
-
"web_search",
|
|
3273
|
-
"web_fetch",
|
|
3274
|
-
"message",
|
|
3275
|
-
"spawn",
|
|
3276
|
-
"sessions_list",
|
|
3277
|
-
"sessions_history",
|
|
3278
|
-
"memory_search",
|
|
3279
|
-
"memory_get",
|
|
3280
|
-
"subagents",
|
|
3281
|
-
"gateway",
|
|
3282
|
-
"cron"
|
|
3283
|
-
];
|
|
3284
|
-
function buildReservedPluginLoadOptions() {
|
|
3285
|
-
return {
|
|
3286
|
-
reservedToolNames: [...RESERVED_TOOL_NAMES],
|
|
3287
|
-
reservedChannelIds: [],
|
|
3288
|
-
reservedProviderIds: builtinProviderIds()
|
|
3289
|
-
};
|
|
3290
|
-
}
|
|
3291
|
-
function createPluginLogger() {
|
|
3292
|
-
return getAppLogger("extension.manager.plugin_registry");
|
|
3293
|
-
}
|
|
3294
|
-
var ExtensionPluginRegistryService = class {
|
|
3295
|
-
discoverEnabledPluginCount = (params) => {
|
|
3296
|
-
const { configWithDevPluginOverrides } = this.resolveLoadingContext(params.config);
|
|
3297
|
-
return discoverPluginStatusReport({
|
|
3298
|
-
config: configWithDevPluginOverrides,
|
|
3299
|
-
workspaceDir: params.workspace
|
|
3300
|
-
}).plugins.filter((plugin) => plugin.enabled).length;
|
|
3301
|
-
};
|
|
3302
|
-
load = (params) => {
|
|
3303
|
-
const { configWithDevPluginOverrides, excludedRoots } = this.resolveLoadingContext(params.config);
|
|
3304
|
-
return loadOpenClawPlugins({
|
|
3305
|
-
config: configWithDevPluginOverrides,
|
|
3306
|
-
workspaceDir: params.workspace,
|
|
3307
|
-
excludeRoots: excludedRoots,
|
|
3308
|
-
...buildReservedPluginLoadOptions(),
|
|
3309
|
-
logger: createPluginLogger()
|
|
3310
|
-
});
|
|
3311
|
-
};
|
|
3312
|
-
loadProgressively = async (params) => {
|
|
3313
|
-
const { configWithDevPluginOverrides, excludedRoots } = this.resolveLoadingContext(params.config);
|
|
3314
|
-
return await loadOpenClawPluginsProgressively({
|
|
3315
|
-
config: configWithDevPluginOverrides,
|
|
3316
|
-
workspaceDir: params.workspace,
|
|
3317
|
-
excludeRoots: excludedRoots,
|
|
3318
|
-
...buildReservedPluginLoadOptions(),
|
|
3319
|
-
onPluginProcessed: params.onPluginProcessed,
|
|
3320
|
-
logger: createPluginLogger()
|
|
3321
|
-
});
|
|
3322
|
-
};
|
|
3323
|
-
resolveLoadingContext = (config) => {
|
|
3324
|
-
return resolveDevPluginLoadingContext(config, resolveDevFirstPartyPluginDir(process.env.NEXTCLAW_DEV_FIRST_PARTY_PLUGIN_DIR));
|
|
3325
|
-
};
|
|
3326
|
-
};
|
|
3327
|
-
//#endregion
|
|
3328
|
-
//#region src/managers/extension.manager.ts
|
|
3329
|
-
function createEmptyPluginRegistry() {
|
|
3330
|
-
return {
|
|
3331
|
-
plugins: [],
|
|
3332
|
-
tools: [],
|
|
3333
|
-
channels: [],
|
|
3334
|
-
providers: [],
|
|
3335
|
-
diagnostics: [],
|
|
3336
|
-
resolvedTools: []
|
|
3337
|
-
};
|
|
3338
|
-
}
|
|
3339
|
-
function buildSortedBindingSignatures(bindings) {
|
|
3340
|
-
return bindings.map((binding) => `${binding.pluginId}:${binding.channelId}`).sort();
|
|
3341
|
-
}
|
|
3342
|
-
function buildSortedExtensionChannelIds(channels) {
|
|
3343
|
-
return channels.map((registration) => registration.channel.id).filter((id) => typeof id === "string" && id.trim().length > 0).sort();
|
|
3344
|
-
}
|
|
3345
|
-
function areSortedStringListsEqual(left, right) {
|
|
3346
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
3114
|
+
function areSortedStringListsEqual(left, right) {
|
|
3115
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
3347
3116
|
}
|
|
3348
3117
|
function readConfigPathSegment(path, prefix) {
|
|
3349
3118
|
if (!path.startsWith(prefix)) return null;
|
|
3350
3119
|
const [segment] = path.slice(prefix.length).split(".");
|
|
3351
3120
|
return segment?.trim() ? segment.trim() : null;
|
|
3352
3121
|
}
|
|
3122
|
+
function buildSnapshot(params) {
|
|
3123
|
+
return {
|
|
3124
|
+
extensionRegistry: {
|
|
3125
|
+
...createEmptyExtensionRegistry(),
|
|
3126
|
+
channels: params.channelBindings.map((binding) => ({
|
|
3127
|
+
extensionId: binding.extensionId,
|
|
3128
|
+
channel: binding.channel,
|
|
3129
|
+
source: "extension-manifest"
|
|
3130
|
+
}))
|
|
3131
|
+
},
|
|
3132
|
+
channelBindings: params.channelBindings,
|
|
3133
|
+
uiMetadata: params.uiMetadata
|
|
3134
|
+
};
|
|
3135
|
+
}
|
|
3353
3136
|
function shouldRestartChannelsForExtensionReload(params) {
|
|
3354
3137
|
const { changedPaths, currentSnapshot, nextSnapshot } = params;
|
|
3355
3138
|
if (!areSortedStringListsEqual(buildSortedBindingSignatures(currentSnapshot.channelBindings), buildSortedBindingSignatures(nextSnapshot.channelBindings))) return true;
|
|
3356
3139
|
if (!areSortedStringListsEqual(buildSortedExtensionChannelIds(currentSnapshot.extensionRegistry.channels), buildSortedExtensionChannelIds(nextSnapshot.extensionRegistry.channels))) return true;
|
|
3357
|
-
const channelPluginIds = /* @__PURE__ */ new Set();
|
|
3358
3140
|
const channelIds = /* @__PURE__ */ new Set();
|
|
3359
|
-
for (const binding of [...currentSnapshot.channelBindings, ...nextSnapshot.channelBindings])
|
|
3360
|
-
channelPluginIds.add(binding.pluginId);
|
|
3361
|
-
channelIds.add(binding.channelId);
|
|
3362
|
-
}
|
|
3141
|
+
for (const binding of [...currentSnapshot.channelBindings, ...nextSnapshot.channelBindings]) channelIds.add(binding.channelId);
|
|
3363
3142
|
for (const path of changedPaths) {
|
|
3364
|
-
const pluginId = readConfigPathSegment(path, "plugins.entries.");
|
|
3365
|
-
if (pluginId && channelPluginIds.has(pluginId)) return true;
|
|
3366
3143
|
const channelId = readConfigPathSegment(path, "channels.");
|
|
3367
3144
|
if (channelId && channelIds.has(channelId)) return true;
|
|
3145
|
+
if (path.startsWith("extensions.")) return true;
|
|
3368
3146
|
}
|
|
3369
3147
|
return false;
|
|
3370
3148
|
}
|
|
3371
|
-
function
|
|
3372
|
-
return
|
|
3373
|
-
tools: pluginRegistry.tools.map((tool) => ({
|
|
3374
|
-
extensionId: tool.pluginId,
|
|
3375
|
-
factory: tool.factory,
|
|
3376
|
-
names: tool.names,
|
|
3377
|
-
optional: tool.optional,
|
|
3378
|
-
source: tool.source
|
|
3379
|
-
})),
|
|
3380
|
-
channels: pluginRegistry.channels.map((channel) => ({
|
|
3381
|
-
extensionId: channel.pluginId,
|
|
3382
|
-
channel: channel.channel,
|
|
3383
|
-
source: channel.source
|
|
3384
|
-
})),
|
|
3385
|
-
diagnostics: pluginRegistry.diagnostics.map((diag) => ({
|
|
3386
|
-
level: diag.level,
|
|
3387
|
-
message: diag.message,
|
|
3388
|
-
extensionId: diag.pluginId,
|
|
3389
|
-
source: diag.source
|
|
3390
|
-
}))
|
|
3391
|
-
};
|
|
3392
|
-
}
|
|
3393
|
-
function toManifestChannelRegistrations(channelBindings) {
|
|
3394
|
-
return channelBindings.map((binding) => ({
|
|
3395
|
-
extensionId: binding.pluginId,
|
|
3396
|
-
channel: binding.channel,
|
|
3397
|
-
source: "extension-manifest"
|
|
3398
|
-
}));
|
|
3399
|
-
}
|
|
3400
|
-
function buildExtensionSnapshot(registry, contributions) {
|
|
3401
|
-
const extensionChannelIds = new Set(contributions.channelBindings.map((binding) => binding.channelId));
|
|
3402
|
-
const extensionPluginIds = new Set(contributions.uiMetadata.map((metadata) => metadata.id));
|
|
3403
|
-
const registryExtensionRegistry = toExtensionRegistry(registry);
|
|
3404
|
-
return {
|
|
3405
|
-
extensionRegistry: {
|
|
3406
|
-
...registryExtensionRegistry,
|
|
3407
|
-
channels: [...registryExtensionRegistry.channels.filter((registration) => {
|
|
3408
|
-
const channelId = registration.channel.id?.trim();
|
|
3409
|
-
return !channelId || !extensionChannelIds.has(channelId);
|
|
3410
|
-
}), ...toManifestChannelRegistrations(contributions.channelBindings)]
|
|
3411
|
-
},
|
|
3412
|
-
channelBindings: [...getPluginChannelBindings(registry).filter((binding) => !extensionChannelIds.has(binding.channelId)), ...contributions.channelBindings],
|
|
3413
|
-
uiMetadata: [...getPluginUiMetadataFromRegistry(registry).filter((metadata) => !extensionPluginIds.has(metadata.id)), ...contributions.uiMetadata]
|
|
3414
|
-
};
|
|
3149
|
+
function countExtensionIds(bindings, metadata) {
|
|
3150
|
+
return new Set([...bindings.map((binding) => binding.extensionId), ...metadata.map((item) => item.id)]).size;
|
|
3415
3151
|
}
|
|
3416
3152
|
var ExtensionManager = class {
|
|
3417
|
-
snapshot =
|
|
3153
|
+
snapshot = buildSnapshot({
|
|
3418
3154
|
channelBindings: [],
|
|
3419
3155
|
uiMetadata: []
|
|
3420
3156
|
});
|
|
3421
3157
|
runtime;
|
|
3422
|
-
pluginRegistry = new ExtensionPluginRegistryService();
|
|
3423
3158
|
constructor(options) {
|
|
3424
3159
|
this.options = options;
|
|
3425
3160
|
this.runtime = new ExtensionRuntimeService({
|
|
@@ -3427,38 +3162,32 @@ var ExtensionManager = class {
|
|
|
3427
3162
|
getConfig: options.configManager.loadConfig,
|
|
3428
3163
|
getWorkspace: this.getWorkspace,
|
|
3429
3164
|
ingress: options.ingress,
|
|
3430
|
-
messageBus: options.messageBus
|
|
3165
|
+
messageBus: options.messageBus,
|
|
3166
|
+
sessionManager: options.sessionManager
|
|
3431
3167
|
});
|
|
3432
3168
|
}
|
|
3433
|
-
load = async (params) => {
|
|
3434
|
-
const { changedPaths = [], onLoadStart,
|
|
3169
|
+
load = async (params = {}) => {
|
|
3170
|
+
const { changedPaths = [], onLoadStart, onExtensionProcessed } = params;
|
|
3435
3171
|
const config = params.config ?? this.options.configManager.loadConfig();
|
|
3436
3172
|
const workspace = getWorkspacePath(config.agents.defaults.workspace);
|
|
3437
|
-
const totalPluginCount = this.pluginRegistry.discoverEnabledPluginCount({
|
|
3438
|
-
config,
|
|
3439
|
-
workspace
|
|
3440
|
-
});
|
|
3441
|
-
onLoadStart?.({ totalPluginCount });
|
|
3442
|
-
let loadedPluginCount = 0;
|
|
3443
|
-
const registry = await this.pluginRegistry.loadProgressively({
|
|
3444
|
-
config,
|
|
3445
|
-
workspace,
|
|
3446
|
-
onPluginProcessed: (progress) => {
|
|
3447
|
-
loadedPluginCount = progress.loadedPluginCount;
|
|
3448
|
-
onPluginProcessed?.(progress);
|
|
3449
|
-
}
|
|
3450
|
-
});
|
|
3451
3173
|
const contributions = await this.runtime.loadChannelContributions({
|
|
3452
3174
|
config,
|
|
3453
3175
|
workspace
|
|
3454
3176
|
});
|
|
3177
|
+
const totalExtensionCount = countExtensionIds(contributions.channelBindings, contributions.uiMetadata);
|
|
3178
|
+
onLoadStart?.({ totalExtensionCount });
|
|
3179
|
+
for (const [index, binding] of contributions.channelBindings.entries()) onExtensionProcessed?.({
|
|
3180
|
+
extensionId: binding.extensionId,
|
|
3181
|
+
loadedExtensionCount: index + 1,
|
|
3182
|
+
totalExtensionCount
|
|
3183
|
+
});
|
|
3455
3184
|
const currentSnapshot = this.snapshot;
|
|
3456
|
-
const nextSnapshot =
|
|
3185
|
+
const nextSnapshot = buildSnapshot(contributions);
|
|
3457
3186
|
this.snapshot = nextSnapshot;
|
|
3458
3187
|
return {
|
|
3459
|
-
diagnostics:
|
|
3460
|
-
|
|
3461
|
-
|
|
3188
|
+
diagnostics: [],
|
|
3189
|
+
totalExtensionCount,
|
|
3190
|
+
loadedExtensionCount: totalExtensionCount,
|
|
3462
3191
|
shouldRestartChannels: shouldRestartChannelsForExtensionReload({
|
|
3463
3192
|
changedPaths,
|
|
3464
3193
|
currentSnapshot,
|
|
@@ -3479,11 +3208,49 @@ var ExtensionManager = class {
|
|
|
3479
3208
|
getExtensionRegistry = () => this.snapshot.extensionRegistry;
|
|
3480
3209
|
getChannelBindings = () => this.snapshot.channelBindings;
|
|
3481
3210
|
getUiMetadata = () => this.snapshot.uiMetadata;
|
|
3482
|
-
toConfigView = (config) =>
|
|
3483
|
-
mergeConfigView = (current, nextConfigView) =>
|
|
3211
|
+
toConfigView = (config) => toExtensionConfigView(config);
|
|
3212
|
+
mergeConfigView = (current, nextConfigView) => mergeExtensionConfigView(current, nextConfigView);
|
|
3484
3213
|
getWorkspace = () => getWorkspacePath(this.options.configManager.loadConfig().agents.defaults.workspace);
|
|
3485
3214
|
};
|
|
3486
3215
|
//#endregion
|
|
3216
|
+
//#region src/utils/model-message-vision.utils.ts
|
|
3217
|
+
const IMAGE_OMITTED_TEXT = "[Image omitted: the selected model is not configured for vision input.]";
|
|
3218
|
+
function isRecord$4(value) {
|
|
3219
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3220
|
+
}
|
|
3221
|
+
function isImageContentPart(value) {
|
|
3222
|
+
if (!isRecord$4(value)) return false;
|
|
3223
|
+
const type = value.type;
|
|
3224
|
+
return type === "image_url" || type === "input_image";
|
|
3225
|
+
}
|
|
3226
|
+
function normalizeContentWithoutVision(content) {
|
|
3227
|
+
if (!Array.isArray(content)) return content;
|
|
3228
|
+
let sawImage = false;
|
|
3229
|
+
const parts = content.map((part) => {
|
|
3230
|
+
if (!isImageContentPart(part)) return part;
|
|
3231
|
+
sawImage = true;
|
|
3232
|
+
return {
|
|
3233
|
+
type: "text",
|
|
3234
|
+
text: IMAGE_OMITTED_TEXT
|
|
3235
|
+
};
|
|
3236
|
+
});
|
|
3237
|
+
if (!sawImage) return content;
|
|
3238
|
+
const textParts = parts.filter((part) => isRecord$4(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
|
|
3239
|
+
if (textParts.length === parts.length) return textParts.join("\n\n");
|
|
3240
|
+
return parts;
|
|
3241
|
+
}
|
|
3242
|
+
function normalizeModelMessagesForVisionSupport(params) {
|
|
3243
|
+
if (params.supportsVision) return params.messages;
|
|
3244
|
+
return params.messages.map((message) => {
|
|
3245
|
+
if (!Object.prototype.hasOwnProperty.call(message, "content")) return message;
|
|
3246
|
+
const content = normalizeContentWithoutVision(message.content);
|
|
3247
|
+
return content === message.content ? message : {
|
|
3248
|
+
...message,
|
|
3249
|
+
content
|
|
3250
|
+
};
|
|
3251
|
+
});
|
|
3252
|
+
}
|
|
3253
|
+
//#endregion
|
|
3487
3254
|
//#region src/managers/llm-provider.manager.ts
|
|
3488
3255
|
const normalizedModel = (value) => {
|
|
3489
3256
|
if (typeof value !== "string") return null;
|
|
@@ -3529,10 +3296,19 @@ var LlmProviderManager = class {
|
|
|
3529
3296
|
return this.getOrCreateProvider(route);
|
|
3530
3297
|
};
|
|
3531
3298
|
chat = async (params) => {
|
|
3532
|
-
|
|
3299
|
+
const route = this.resolveRoute(params.model ?? null);
|
|
3300
|
+
return (route ? this.getOrCreateProvider(route) : this.missingProvider).chat({
|
|
3301
|
+
...params,
|
|
3302
|
+
messages: this.prepareMessagesForProvider(route, params.messages)
|
|
3303
|
+
});
|
|
3533
3304
|
};
|
|
3534
3305
|
chatStream = async function* (params) {
|
|
3535
|
-
|
|
3306
|
+
const route = this.resolveRoute(params.model ?? null);
|
|
3307
|
+
const provider = route ? this.getOrCreateProvider(route) : this.missingProvider;
|
|
3308
|
+
for await (const event of provider.chatStream({
|
|
3309
|
+
...params,
|
|
3310
|
+
messages: this.prepareMessagesForProvider(route, params.messages)
|
|
3311
|
+
})) yield event;
|
|
3536
3312
|
};
|
|
3537
3313
|
testConnection = async (input) => {
|
|
3538
3314
|
await this.createProvider({
|
|
@@ -3545,7 +3321,7 @@ var LlmProviderManager = class {
|
|
|
3545
3321
|
extraHeaders: input.extraHeaders ?? null,
|
|
3546
3322
|
wireApi: input.wireApi ?? "auto",
|
|
3547
3323
|
models: [],
|
|
3548
|
-
|
|
3324
|
+
modelConfig: {}
|
|
3549
3325
|
},
|
|
3550
3326
|
apiBase: input.apiBase ?? null,
|
|
3551
3327
|
model: input.defaultModel
|
|
@@ -3663,6 +3439,16 @@ var LlmProviderManager = class {
|
|
|
3663
3439
|
wireApi: route.provider?.wireApi ?? null
|
|
3664
3440
|
});
|
|
3665
3441
|
};
|
|
3442
|
+
prepareMessagesForProvider = (route, messages) => {
|
|
3443
|
+
return normalizeModelMessagesForVisionSupport({
|
|
3444
|
+
messages,
|
|
3445
|
+
supportsVision: modelSupportsVision({
|
|
3446
|
+
model: route?.model,
|
|
3447
|
+
providerName: route?.providerName,
|
|
3448
|
+
modelConfig: route?.provider?.modelConfig
|
|
3449
|
+
})
|
|
3450
|
+
});
|
|
3451
|
+
};
|
|
3666
3452
|
buildCacheKey = (route) => {
|
|
3667
3453
|
const routeProvider = route.provider;
|
|
3668
3454
|
return [
|
|
@@ -3923,7 +3709,7 @@ var NcpSessionManager = class {
|
|
|
3923
3709
|
this.runningSessionIds.clear();
|
|
3924
3710
|
};
|
|
3925
3711
|
createSession = async (params) => {
|
|
3926
|
-
const { agentId: requestedAgentId, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
|
|
3712
|
+
const { agentId: requestedAgentId, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
|
|
3927
3713
|
const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
|
|
3928
3714
|
const metadata = cloneInheritedMetadata(sourceSessionMetadata);
|
|
3929
3715
|
const title = readOptionalString$4(requestedTitle) ?? summarizeTask(task);
|
|
@@ -3948,7 +3734,7 @@ var NcpSessionManager = class {
|
|
|
3948
3734
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3949
3735
|
const nextMetadata = mergeMetadataOverrides(metadata, metadataOverrides);
|
|
3950
3736
|
const agentId = readOptionalString$4(requestedAgentId) ?? readOptionalString$4(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
|
|
3951
|
-
const sessionId = buildSessionId();
|
|
3737
|
+
const sessionId = readOptionalString$4(requestedSessionId) ?? buildSessionId();
|
|
3952
3738
|
const record = {
|
|
3953
3739
|
sessionId,
|
|
3954
3740
|
...agentId ? { agentId } : {},
|
|
@@ -4094,12 +3880,12 @@ function parseSkillFrontmatter(raw) {
|
|
|
4094
3880
|
const summaryI18n = readLocalizedTextMap(parsed, "summaryi18n", "summary_i18n");
|
|
4095
3881
|
const descriptionI18n = readLocalizedTextMap(parsed, "descriptioni18n", "description_i18n");
|
|
4096
3882
|
return {
|
|
4097
|
-
name: readString$
|
|
4098
|
-
summary: readString$
|
|
4099
|
-
summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$
|
|
4100
|
-
description: readString$
|
|
4101
|
-
descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$
|
|
4102
|
-
author: readString$
|
|
3883
|
+
name: readString$4(parsed, "name"),
|
|
3884
|
+
summary: readString$4(parsed, "summary"),
|
|
3885
|
+
summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$4(parsed, "summaryzh", "summary_zh") }),
|
|
3886
|
+
description: readString$4(parsed, "description"),
|
|
3887
|
+
descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$4(parsed, "descriptionzh", "description_zh") }),
|
|
3888
|
+
author: readString$4(parsed, "author"),
|
|
4103
3889
|
tags: readTags(parsed)
|
|
4104
3890
|
};
|
|
4105
3891
|
}
|
|
@@ -4126,7 +3912,7 @@ function parseYamlFrontmatter(raw) {
|
|
|
4126
3912
|
throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
|
|
4127
3913
|
}
|
|
4128
3914
|
}
|
|
4129
|
-
function readString$
|
|
3915
|
+
function readString$4(record, ...names) {
|
|
4130
3916
|
const value = readValue(record, names);
|
|
4131
3917
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
4132
3918
|
}
|
|
@@ -4279,14 +4065,9 @@ const RUNTIME_METADATA_KEYS = [
|
|
|
4279
4065
|
"session_type",
|
|
4280
4066
|
"runtime_type"
|
|
4281
4067
|
];
|
|
4282
|
-
function isDurableSessionEvent(event) {
|
|
4068
|
+
function isDurableSessionEvent$1(event) {
|
|
4283
4069
|
return event.type !== NcpEventType.ContextWindowUpdated;
|
|
4284
4070
|
}
|
|
4285
|
-
function readEventSessionId$1(event) {
|
|
4286
|
-
const payload = "payload" in event ? event.payload : null;
|
|
4287
|
-
if (!payload || typeof payload !== "object") return null;
|
|
4288
|
-
return "sessionId" in payload && typeof payload.sessionId === "string" ? payload.sessionId : null;
|
|
4289
|
-
}
|
|
4290
4071
|
function pickRuntimeMetadataPatch(current, next) {
|
|
4291
4072
|
const patch = {};
|
|
4292
4073
|
for (const key of RUNTIME_METADATA_KEYS) {
|
|
@@ -4341,29 +4122,6 @@ var SessionRunManager = class {
|
|
|
4341
4122
|
status: "idle"
|
|
4342
4123
|
});
|
|
4343
4124
|
};
|
|
4344
|
-
streamSessionEvents = (payload, options) => {
|
|
4345
|
-
this.assertNotDisposed();
|
|
4346
|
-
const signal = options?.signal ?? new AbortController().signal;
|
|
4347
|
-
const queue = new AsyncEventQueue();
|
|
4348
|
-
const stop = () => queue.close();
|
|
4349
|
-
const unsubscribe = this.eventBus.on(eventKeys.ncpEvent, (event) => {
|
|
4350
|
-
if (readEventSessionId$1(event) === payload.sessionId) queue.push(event);
|
|
4351
|
-
});
|
|
4352
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
4353
|
-
if (signal.aborted) stop();
|
|
4354
|
-
return (async function* () {
|
|
4355
|
-
try {
|
|
4356
|
-
for await (const event of queue.iterate()) {
|
|
4357
|
-
if (signal.aborted) break;
|
|
4358
|
-
yield event;
|
|
4359
|
-
}
|
|
4360
|
-
} finally {
|
|
4361
|
-
unsubscribe();
|
|
4362
|
-
signal.removeEventListener("abort", stop);
|
|
4363
|
-
queue.close();
|
|
4364
|
-
}
|
|
4365
|
-
})();
|
|
4366
|
-
};
|
|
4367
4125
|
updateToolCallResult = async ({ result, sessionId, toolCallId }) => {
|
|
4368
4126
|
this.assertNotDisposed();
|
|
4369
4127
|
const normalizedSessionId = sessionId.trim();
|
|
@@ -4442,7 +4200,7 @@ var SessionRunManager = class {
|
|
|
4442
4200
|
});
|
|
4443
4201
|
};
|
|
4444
4202
|
persistLiveSessionEvent = async (session, event) => {
|
|
4445
|
-
if (!isDurableSessionEvent(event)) return;
|
|
4203
|
+
if (!isDurableSessionEvent$1(event)) return;
|
|
4446
4204
|
await this.ncpSessionManager.appendSessionEvent({
|
|
4447
4205
|
sessionId: session.sessionId,
|
|
4448
4206
|
event
|
|
@@ -5018,14 +4776,15 @@ function waitForAgentRuntimeSessionReply(input) {
|
|
|
5018
4776
|
let acceptedMessageId = null;
|
|
5019
4777
|
const completedMessagesById = /* @__PURE__ */ new Map();
|
|
5020
4778
|
let unsubscribe = () => void 0;
|
|
4779
|
+
const acceptMessageId = (messageId) => {
|
|
4780
|
+
acceptedMessageId = messageId;
|
|
4781
|
+
input.onAccepted(messageId);
|
|
4782
|
+
};
|
|
5021
4783
|
const promise = new Promise((resolve, reject) => {
|
|
5022
4784
|
unsubscribe = input.eventBus.on(eventKeys.ncpEvent, (event) => {
|
|
5023
4785
|
switch (event.type) {
|
|
5024
4786
|
case NcpEventType.MessageAccepted:
|
|
5025
|
-
if (event.payload.correlationId === input.requestId)
|
|
5026
|
-
acceptedMessageId = event.payload.messageId;
|
|
5027
|
-
input.onAccepted(event.payload.messageId);
|
|
5028
|
-
}
|
|
4787
|
+
if (event.payload.correlationId === input.requestId) acceptMessageId(event.payload.messageId);
|
|
5029
4788
|
return;
|
|
5030
4789
|
case NcpEventType.MessageCompleted:
|
|
5031
4790
|
if (event.payload.correlationId === input.requestId || event.payload.message.id === acceptedMessageId) {
|
|
@@ -5037,8 +4796,7 @@ function waitForAgentRuntimeSessionReply(input) {
|
|
|
5037
4796
|
return;
|
|
5038
4797
|
case NcpEventType.RunFinished:
|
|
5039
4798
|
if ((event.payload.correlationId === input.requestId || event.payload.messageId === acceptedMessageId) && event.payload.messageId) {
|
|
5040
|
-
|
|
5041
|
-
input.onAccepted(event.payload.messageId);
|
|
4799
|
+
acceptMessageId(event.payload.messageId);
|
|
5042
4800
|
const completedMessage = completedMessagesById.get(event.payload.messageId);
|
|
5043
4801
|
if (completedMessage) {
|
|
5044
4802
|
unsubscribe();
|
|
@@ -5112,132 +4870,854 @@ function createAgentRuntimeSessionRequestDispatcher(options) {
|
|
|
5112
4870
|
} };
|
|
5113
4871
|
}
|
|
5114
4872
|
//#endregion
|
|
5115
|
-
//#region src/features/
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
}
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
4873
|
+
//#region src/features/agent-run/managers/agent-run-context-compaction.manager.ts
|
|
4874
|
+
var AgentRunContextCompactionManager = class {
|
|
4875
|
+
preflightService;
|
|
4876
|
+
constructor(configManager, providerManager, sessionRepository) {
|
|
4877
|
+
this.sessionRepository = sessionRepository;
|
|
4878
|
+
this.preflightService = new ContextCompactionPreflightService({
|
|
4879
|
+
configManager,
|
|
4880
|
+
providerManager
|
|
4881
|
+
});
|
|
4882
|
+
}
|
|
4883
|
+
runPreflight = async (input) => {
|
|
4884
|
+
const beginResult = this.preflightService.begin({
|
|
4885
|
+
inputMessages: [],
|
|
4886
|
+
requestMetadata: input.metadata,
|
|
4887
|
+
sessionId: input.sessionId,
|
|
4888
|
+
sessionMessages: input.messages,
|
|
4889
|
+
storedAgentId: input.agentId,
|
|
4890
|
+
storedMetadata: input.metadata
|
|
4891
|
+
});
|
|
4892
|
+
const events = await this.toEvents(input.sessionId, beginResult);
|
|
4893
|
+
if (!beginResult.pendingCompaction) return events;
|
|
4894
|
+
const finishResult = await this.preflightService.finish(beginResult.pendingCompaction);
|
|
4895
|
+
return [...events, ...await this.toEvents(input.sessionId, finishResult)];
|
|
4896
|
+
};
|
|
4897
|
+
toEvents = async (sessionId, result) => {
|
|
4898
|
+
if (Object.keys(result.metadataPatch).length > 0) await this.sessionRepository.patchSessionMetadata(sessionId, result.metadataPatch);
|
|
4899
|
+
if (!result.timelineMessage) return [];
|
|
4900
|
+
return [{
|
|
4901
|
+
type: NcpEventType.MessageSent,
|
|
4902
|
+
payload: {
|
|
4903
|
+
sessionId,
|
|
4904
|
+
message: result.timelineMessage
|
|
4905
|
+
}
|
|
4906
|
+
}];
|
|
4907
|
+
};
|
|
4908
|
+
};
|
|
4909
|
+
//#endregion
|
|
4910
|
+
//#region src/features/agent-run/managers/agent-run-request.manager.ts
|
|
4911
|
+
function toAgentRunRequest(envelope) {
|
|
4912
|
+
const metadata = envelope.metadata ?? {};
|
|
4913
|
+
const requestMetadata = {
|
|
4914
|
+
agentRuntimeId: metadata.agentRuntimeId,
|
|
4915
|
+
agentId: metadata.agentId,
|
|
4916
|
+
projectRoot: metadata.projectRoot,
|
|
4917
|
+
channel: metadata.channel,
|
|
4918
|
+
correlationId: envelope.correlationId,
|
|
4919
|
+
metadata: structuredClone(metadata),
|
|
4920
|
+
model: metadata.model,
|
|
4921
|
+
maxTokens: metadata.maxTokens,
|
|
4922
|
+
thinkingEffort: metadata.thinkingEffort
|
|
4923
|
+
};
|
|
4924
|
+
if (Array.isArray(envelope.content)) return {
|
|
4925
|
+
...requestMetadata,
|
|
4926
|
+
sessionId: envelope.sessionId,
|
|
4927
|
+
message: {
|
|
4928
|
+
sessionId: envelope.sessionId ?? "",
|
|
4929
|
+
id: `user-message-${randomUUID()}`,
|
|
4930
|
+
role: "user",
|
|
4931
|
+
status: "final",
|
|
4932
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4933
|
+
parts: structuredClone(envelope.content)
|
|
4934
|
+
}
|
|
4935
|
+
};
|
|
4936
|
+
const sourceMessage = envelope.message;
|
|
4937
|
+
if (!sourceMessage) throw new Error("Invalid agent run send request.");
|
|
4938
|
+
const messageSessionId = sourceMessage.sessionId;
|
|
4939
|
+
const message = {
|
|
4940
|
+
...sourceMessage,
|
|
4941
|
+
sessionId: messageSessionId ?? envelope.sessionId ?? "",
|
|
4942
|
+
id: sourceMessage.id ?? `user-message-${randomUUID()}`,
|
|
4943
|
+
role: sourceMessage.role ?? "user",
|
|
4944
|
+
status: sourceMessage.status ?? "final",
|
|
4945
|
+
timestamp: sourceMessage.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
4946
|
+
parts: structuredClone(sourceMessage.parts)
|
|
4947
|
+
};
|
|
4948
|
+
return {
|
|
4949
|
+
...requestMetadata,
|
|
4950
|
+
sessionId: envelope.sessionId ?? messageSessionId,
|
|
4951
|
+
message
|
|
4952
|
+
};
|
|
5135
4953
|
}
|
|
5136
|
-
function
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
4954
|
+
function toSessionMessageRequest(payload) {
|
|
4955
|
+
return {
|
|
4956
|
+
sessionId: payload.sessionId,
|
|
4957
|
+
message: {
|
|
4958
|
+
...payload.message,
|
|
4959
|
+
sessionId: payload.sessionId
|
|
4960
|
+
},
|
|
4961
|
+
correlationId: payload.requestId
|
|
4962
|
+
};
|
|
5144
4963
|
}
|
|
5145
|
-
function
|
|
5146
|
-
const model = resolveRequestedModel(params);
|
|
5147
|
-
if (!model) return;
|
|
5148
|
-
const resolution = resolveProviderRuntime(params.config, model);
|
|
5149
|
-
if (!resolution.provider) return;
|
|
5150
|
-
const apiBase = resolution.apiBase ?? (resolution.providerName ? BUILTIN_PROVIDER_REGISTRY.findProviderByName(resolution.providerName)?.defaultApiBase ?? null : null);
|
|
4964
|
+
function toRunHandle(accepted) {
|
|
5151
4965
|
return {
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
[NARP_API_MODE_HEADER]: resolveProviderApiMode(resolution)
|
|
5158
|
-
}
|
|
4966
|
+
sessionId: accepted.sessionId,
|
|
4967
|
+
userMessageId: accepted.userMessageId,
|
|
4968
|
+
assistantMessageId: null,
|
|
4969
|
+
runId: accepted.runId,
|
|
4970
|
+
correlationId: accepted.correlationId
|
|
5159
4971
|
};
|
|
5160
4972
|
}
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
4973
|
+
function findCompletedAssistantMessage(messages, messageId) {
|
|
4974
|
+
return [...messages].reverse().find((message) => message.role === "assistant" && message.status === "final" && (!messageId || message.id === messageId)) ?? null;
|
|
4975
|
+
}
|
|
4976
|
+
var AgentRunRequestManager$1 = class {
|
|
4977
|
+
cleanups = [];
|
|
4978
|
+
started = false;
|
|
4979
|
+
constructor(agentRuntimeManager, configManager, contextProviderManager, eventBus, ingress, sessionRepository, sessionRunManager, toolProviderManager) {
|
|
4980
|
+
this.agentRuntimeManager = agentRuntimeManager;
|
|
4981
|
+
this.configManager = configManager;
|
|
4982
|
+
this.contextProviderManager = contextProviderManager;
|
|
4983
|
+
this.eventBus = eventBus;
|
|
4984
|
+
this.ingress = ingress;
|
|
4985
|
+
this.sessionRepository = sessionRepository;
|
|
4986
|
+
this.sessionRunManager = sessionRunManager;
|
|
4987
|
+
this.toolProviderManager = toolProviderManager;
|
|
5166
4988
|
}
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
const nextDescribe = this.describeInternal();
|
|
5172
|
-
this.pendingDescribeByMode.set(describeMode, nextDescribe);
|
|
5173
|
-
try {
|
|
5174
|
-
return await nextDescribe;
|
|
5175
|
-
} finally {
|
|
5176
|
-
this.pendingDescribeByMode.delete(describeMode);
|
|
5177
|
-
}
|
|
4989
|
+
start = () => {
|
|
4990
|
+
if (this.started) return;
|
|
4991
|
+
this.started = true;
|
|
4992
|
+
this.cleanups.push(this.ingress.addHandler(ingressKeys.agentRun.send, this.handleSendRequest), this.ingress.addHandler(ingressKeys.agentRun.abort, this.handleAbortRequest), this.ingress.addHandler(ingressKeys.agentRun.sessionMessageRequest, this.handleSessionMessageRequest));
|
|
5178
4993
|
};
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
4994
|
+
dispose = () => {
|
|
4995
|
+
while (this.cleanups.length > 0) this.cleanups.pop()?.();
|
|
4996
|
+
this.started = false;
|
|
4997
|
+
};
|
|
4998
|
+
handleSendRequest = async (envelope) => {
|
|
4999
|
+
if (!envelope.payload) throw new Error("Invalid agent run send request.");
|
|
5000
|
+
return toRunHandle(await this.send(toAgentRunRequest(envelope.payload)));
|
|
5001
|
+
};
|
|
5002
|
+
handleAbortRequest = async (envelope) => {
|
|
5003
|
+
if (!envelope.payload?.sessionId) throw new Error("Invalid agent run abort request.");
|
|
5004
|
+
await this.abort({ sessionId: envelope.payload.sessionId });
|
|
5005
|
+
};
|
|
5006
|
+
handleSessionMessageRequest = async (envelope) => {
|
|
5007
|
+
if (!envelope.payload) throw new Error("Invalid agent run session message request.");
|
|
5008
|
+
return toRunHandle(await this.send(toSessionMessageRequest(envelope.payload)));
|
|
5009
|
+
};
|
|
5010
|
+
send = async (request) => {
|
|
5011
|
+
const session = await this.sessionRepository.getOrCreateSession({
|
|
5012
|
+
sessionId: request.sessionId,
|
|
5013
|
+
agentId: request.agentId,
|
|
5014
|
+
agentRuntimeId: request.agentRuntimeId,
|
|
5015
|
+
channel: request.channel,
|
|
5016
|
+
metadata: request.metadata,
|
|
5017
|
+
model: request.model,
|
|
5018
|
+
projectRoot: request.projectRoot,
|
|
5019
|
+
task: readMessageTask(request.message),
|
|
5020
|
+
thinkingEffort: request.thinkingEffort
|
|
5021
|
+
});
|
|
5022
|
+
const sessionRun = this.sessionRunManager.getSessionRun(session.sessionId) ?? await this.sessionRunManager.createSessionRun(session.sessionId);
|
|
5023
|
+
const message = {
|
|
5024
|
+
...request.message,
|
|
5025
|
+
sessionId: session.sessionId
|
|
5191
5026
|
};
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
reasonMessage: null,
|
|
5197
|
-
recommendedModel: config.recommendedModel ?? null,
|
|
5198
|
-
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5199
|
-
cta: null
|
|
5027
|
+
const providerRequest = {
|
|
5028
|
+
...request,
|
|
5029
|
+
sessionId: session.sessionId,
|
|
5030
|
+
message
|
|
5200
5031
|
};
|
|
5201
|
-
|
|
5202
|
-
const
|
|
5203
|
-
const
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5032
|
+
sessionRun.inbox.enqueue(message);
|
|
5033
|
+
const activeRun = sessionRun.beginRun();
|
|
5034
|
+
const model = request.model ?? session.model ?? this.configManager.getDefaultModel();
|
|
5035
|
+
const agentId = request.agentId ?? session.agentId ?? resolveDefaultAgentProfileId(this.configManager.loadConfig());
|
|
5036
|
+
const spec = {
|
|
5037
|
+
runId: activeRun.runId,
|
|
5038
|
+
agentId,
|
|
5039
|
+
model,
|
|
5040
|
+
maxTokens: request.maxTokens ?? this.configManager.getModelMaxTokens(model),
|
|
5041
|
+
thinkingEffort: request.thinkingEffort ?? session.thinkingEffort ?? null,
|
|
5042
|
+
correlationId: request.correlationId
|
|
5043
|
+
};
|
|
5044
|
+
const runtime = this.agentRuntimeManager.getOrCreate({
|
|
5045
|
+
agentRuntimeId: session.agentRuntimeId,
|
|
5046
|
+
session,
|
|
5047
|
+
sessionRun
|
|
5048
|
+
});
|
|
5049
|
+
const contextBlocks = await this.contextProviderManager.buildContext(providerRequest);
|
|
5050
|
+
const tools = await this.toolProviderManager.buildTools(providerRequest);
|
|
5051
|
+
let messageCompletedSeen = false;
|
|
5052
|
+
lastValueFrom(from(runtime.run(spec, {
|
|
5053
|
+
contextBlocks,
|
|
5054
|
+
sessionRun,
|
|
5055
|
+
signal: activeRun.signal,
|
|
5056
|
+
tools
|
|
5057
|
+
})).pipe(tap((event) => {
|
|
5058
|
+
const eventsToPublish = [];
|
|
5059
|
+
if (event.type === NcpEventType.MessageCompleted) messageCompletedSeen = true;
|
|
5060
|
+
if (event.type === NcpEventType.RunFinished && !messageCompletedSeen) {
|
|
5061
|
+
const message = findCompletedAssistantMessage(sessionRun.getSnapshot().messages, event.payload.messageId);
|
|
5062
|
+
if (!message) throw new Error(`Run finished without a final assistant message for session "${session.sessionId}".`);
|
|
5063
|
+
eventsToPublish.push({
|
|
5064
|
+
type: NcpEventType.MessageCompleted,
|
|
5065
|
+
payload: {
|
|
5066
|
+
sessionId: event.payload.sessionId ?? session.sessionId,
|
|
5067
|
+
message,
|
|
5068
|
+
correlationId: event.payload.correlationId
|
|
5069
|
+
}
|
|
5070
|
+
});
|
|
5071
|
+
messageCompletedSeen = true;
|
|
5072
|
+
}
|
|
5073
|
+
eventsToPublish.push(event);
|
|
5074
|
+
for (const eventToPublish of eventsToPublish) this.eventBus.emit(eventKeys.ncpEvent, eventToPublish, {
|
|
5075
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5076
|
+
source: "agent-run-request"
|
|
5209
5077
|
});
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
return {
|
|
5220
|
-
icon: resolveEntryIcon(this.entry),
|
|
5221
|
-
ready: true,
|
|
5222
|
-
reason: null,
|
|
5223
|
-
reasonMessage: null,
|
|
5224
|
-
recommendedModel: config.recommendedModel ?? null,
|
|
5225
|
-
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5226
|
-
cta: null
|
|
5227
|
-
};
|
|
5228
|
-
} catch (error) {
|
|
5229
|
-
return {
|
|
5230
|
-
icon: resolveEntryIcon(this.entry),
|
|
5231
|
-
ready: false,
|
|
5232
|
-
reason: "healthcheck_unreachable",
|
|
5233
|
-
reasonMessage: error instanceof Error ? error.message : "Failed to reach the configured HTTP runtime healthcheck.",
|
|
5234
|
-
recommendedModel: config.recommendedModel ?? null,
|
|
5235
|
-
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5236
|
-
cta: null
|
|
5078
|
+
}), catchError(async (error) => {
|
|
5079
|
+
const event = {
|
|
5080
|
+
type: NcpEventType.RunError,
|
|
5081
|
+
payload: {
|
|
5082
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5083
|
+
runId: spec.runId,
|
|
5084
|
+
sessionId: session.sessionId,
|
|
5085
|
+
correlationId: spec.correlationId
|
|
5086
|
+
}
|
|
5237
5087
|
};
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5088
|
+
await sessionRun.applyEvents([event]);
|
|
5089
|
+
this.eventBus.emit(eventKeys.ncpEvent, event, {
|
|
5090
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5091
|
+
source: "agent-run-request"
|
|
5092
|
+
});
|
|
5093
|
+
})), { defaultValue: void 0 });
|
|
5094
|
+
return {
|
|
5095
|
+
sessionId: session.sessionId,
|
|
5096
|
+
userMessageId: message.id,
|
|
5097
|
+
runId: spec.runId,
|
|
5098
|
+
correlationId: request.correlationId
|
|
5099
|
+
};
|
|
5100
|
+
};
|
|
5101
|
+
abort = async (request) => {
|
|
5102
|
+
this.sessionRunManager.getSessionRun(request.sessionId)?.abortRun(request.runId);
|
|
5103
|
+
};
|
|
5104
|
+
};
|
|
5105
|
+
//#endregion
|
|
5106
|
+
//#region src/features/agent-run/managers/agent-runtime.manager.ts
|
|
5107
|
+
var AgentRuntimeManager$1 = class {
|
|
5108
|
+
providers = /* @__PURE__ */ new Map();
|
|
5109
|
+
entries = /* @__PURE__ */ new Map();
|
|
5110
|
+
globalRuntimes = /* @__PURE__ */ new Map();
|
|
5111
|
+
sessionRuntimes = /* @__PURE__ */ new Map();
|
|
5112
|
+
register = (registration) => {
|
|
5113
|
+
const kind = this.normalizeId(registration.kind);
|
|
5114
|
+
if (this.providers.has(kind)) throw new Error(`Agent runtime provider is already registered: ${kind}`);
|
|
5115
|
+
const normalizedRegistration = {
|
|
5116
|
+
...registration,
|
|
5117
|
+
kind
|
|
5118
|
+
};
|
|
5119
|
+
this.providers.set(kind, normalizedRegistration);
|
|
5120
|
+
return async () => {
|
|
5121
|
+
if (this.providers.get(kind) !== normalizedRegistration) return;
|
|
5122
|
+
this.providers.delete(kind);
|
|
5123
|
+
await this.disposeAllRuntimes();
|
|
5124
|
+
};
|
|
5125
|
+
};
|
|
5126
|
+
applyEntries = (entries) => {
|
|
5127
|
+
this.entries.clear();
|
|
5128
|
+
for (const entry of entries) this.entries.set(this.normalizeId(entry.id), {
|
|
5129
|
+
...entry,
|
|
5130
|
+
id: this.normalizeId(entry.id),
|
|
5131
|
+
type: this.normalizeId(entry.type)
|
|
5132
|
+
});
|
|
5133
|
+
};
|
|
5134
|
+
getOrCreate = (params) => {
|
|
5135
|
+
const { agentRuntimeId, session, sessionRun } = params;
|
|
5136
|
+
const entry = this.getEntry(agentRuntimeId);
|
|
5137
|
+
const provider = this.getProvider(entry.type);
|
|
5138
|
+
const reuseScope = this.resolveReuseScope(entry, provider);
|
|
5139
|
+
const cacheKey = reuseScope === "global" ? entry.id : `${entry.id}:${session.sessionId}`;
|
|
5140
|
+
const cache = reuseScope === "global" ? this.globalRuntimes : this.sessionRuntimes;
|
|
5141
|
+
const existing = cache.get(cacheKey);
|
|
5142
|
+
if (existing) return existing;
|
|
5143
|
+
const agentRuntime = provider.createRuntime({
|
|
5144
|
+
entry,
|
|
5145
|
+
session,
|
|
5146
|
+
sessionRun
|
|
5147
|
+
});
|
|
5148
|
+
cache.set(cacheKey, agentRuntime);
|
|
5149
|
+
return agentRuntime;
|
|
5150
|
+
};
|
|
5151
|
+
listSessionTypes = async (_params) => {
|
|
5152
|
+
const entries = [...this.entries.values()].filter((entry) => entry.enabled !== false);
|
|
5153
|
+
const options = await Promise.all(entries.map(async (entry) => {
|
|
5154
|
+
const provider = this.providers.get(entry.type);
|
|
5155
|
+
const descriptor = provider?.describeSessionTypeForEntry ? await provider.describeSessionTypeForEntry({
|
|
5156
|
+
entry,
|
|
5157
|
+
describeParams: _params
|
|
5158
|
+
}) : null;
|
|
5159
|
+
return {
|
|
5160
|
+
value: entry.id,
|
|
5161
|
+
label: entry.label,
|
|
5162
|
+
icon: descriptor?.icon ?? entry.icon ?? null,
|
|
5163
|
+
ready: provider ? descriptor?.ready ?? true : false,
|
|
5164
|
+
reason: provider ? descriptor?.reason ?? null : "runtime_provider_unavailable",
|
|
5165
|
+
reasonMessage: provider ? descriptor?.reasonMessage ?? null : `Runtime provider unavailable for type "${entry.type}".`,
|
|
5166
|
+
recommendedModel: descriptor?.recommendedModel ?? null,
|
|
5167
|
+
cta: descriptor?.cta ?? null,
|
|
5168
|
+
...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
|
|
5169
|
+
};
|
|
5170
|
+
}));
|
|
5171
|
+
return {
|
|
5172
|
+
defaultType: this.entries.has("native") ? DEFAULT_AGENT_RUNTIME_ENTRY_ID : entries[0]?.id ?? "native",
|
|
5173
|
+
options
|
|
5174
|
+
};
|
|
5175
|
+
};
|
|
5176
|
+
dispose = async () => {
|
|
5177
|
+
await this.disposeAllRuntimes();
|
|
5178
|
+
this.providers.clear();
|
|
5179
|
+
this.entries.clear();
|
|
5180
|
+
};
|
|
5181
|
+
normalizeId = (agentRuntimeId) => {
|
|
5182
|
+
const normalizedId = agentRuntimeId.trim();
|
|
5183
|
+
if (!normalizedId) throw new Error("Agent runtime id is required.");
|
|
5184
|
+
return normalizedId;
|
|
5185
|
+
};
|
|
5186
|
+
getEntry = (agentRuntimeId) => {
|
|
5187
|
+
const normalizedId = this.normalizeId(agentRuntimeId);
|
|
5188
|
+
const entry = this.entries.get(normalizedId);
|
|
5189
|
+
if (!entry || entry.enabled === false) throw new Error(`Agent runtime entry is not registered: ${normalizedId}`);
|
|
5190
|
+
return entry;
|
|
5191
|
+
};
|
|
5192
|
+
getProvider = (kind) => {
|
|
5193
|
+
const provider = this.providers.get(this.normalizeId(kind));
|
|
5194
|
+
if (!provider) throw new Error(`Agent runtime provider is not registered: ${kind}`);
|
|
5195
|
+
return provider;
|
|
5196
|
+
};
|
|
5197
|
+
resolveReuseScope = (entry, provider) => {
|
|
5198
|
+
return entry.config?.reuseScope === "session" || entry.config?.reuseScope === "global" ? entry.config.reuseScope : provider.defaultReuseScope;
|
|
5199
|
+
};
|
|
5200
|
+
disposeAllRuntimes = async () => {
|
|
5201
|
+
for (const runtime of [...this.globalRuntimes.values(), ...this.sessionRuntimes.values()]) await runtime.dispose?.();
|
|
5202
|
+
this.globalRuntimes.clear();
|
|
5203
|
+
this.sessionRuntimes.clear();
|
|
5204
|
+
};
|
|
5205
|
+
};
|
|
5206
|
+
//#endregion
|
|
5207
|
+
//#region src/features/agent-run/managers/context-provider.manager.ts
|
|
5208
|
+
var ContextProviderManager = class {
|
|
5209
|
+
providers = /* @__PURE__ */ new Set();
|
|
5210
|
+
register = (provider) => {
|
|
5211
|
+
this.providers.add(provider);
|
|
5212
|
+
return () => {
|
|
5213
|
+
this.providers.delete(provider);
|
|
5214
|
+
};
|
|
5215
|
+
};
|
|
5216
|
+
buildContext = async (request) => {
|
|
5217
|
+
const blocks = [];
|
|
5218
|
+
for (const provider of [...this.providers]) blocks.push(...await provider.provide(request));
|
|
5219
|
+
return blocks;
|
|
5220
|
+
};
|
|
5221
|
+
dispose = () => {
|
|
5222
|
+
this.providers.clear();
|
|
5223
|
+
};
|
|
5224
|
+
};
|
|
5225
|
+
//#endregion
|
|
5226
|
+
//#region src/features/agent-run/managers/session-run.manager.ts
|
|
5227
|
+
var MessageInbox = class {
|
|
5228
|
+
messages = [];
|
|
5229
|
+
enqueue = (message) => {
|
|
5230
|
+
this.messages.push(message);
|
|
5231
|
+
};
|
|
5232
|
+
drain = () => {
|
|
5233
|
+
return this.messages.splice(0, this.messages.length);
|
|
5234
|
+
};
|
|
5235
|
+
isEmpty = () => this.messages.length === 0;
|
|
5236
|
+
};
|
|
5237
|
+
function isConversationStateEvent(event) {
|
|
5238
|
+
return event.type !== NcpEventType.ContextWindowUpdated;
|
|
5239
|
+
}
|
|
5240
|
+
var SessionRun = class {
|
|
5241
|
+
inbox = new MessageInbox();
|
|
5242
|
+
sessionId;
|
|
5243
|
+
activeRunId = null;
|
|
5244
|
+
activeRunController = null;
|
|
5245
|
+
constructor(seed, stateManager = new DefaultNcpAgentConversationStateManager()) {
|
|
5246
|
+
this.stateManager = stateManager;
|
|
5247
|
+
this.sessionId = seed.sessionId;
|
|
5248
|
+
this.stateManager.hydrate({
|
|
5249
|
+
sessionId: seed.sessionId,
|
|
5250
|
+
messages: seed.messages
|
|
5251
|
+
});
|
|
5252
|
+
}
|
|
5253
|
+
getSnapshot = () => {
|
|
5254
|
+
const snapshot = this.stateManager.getSnapshot();
|
|
5255
|
+
return { messages: snapshot.streamingMessage ? [...snapshot.messages, snapshot.streamingMessage] : snapshot.messages };
|
|
5256
|
+
};
|
|
5257
|
+
applyEvents = async (events) => {
|
|
5258
|
+
this.applyRunEvents(events);
|
|
5259
|
+
const conversationEvents = events.filter(isConversationStateEvent);
|
|
5260
|
+
if (conversationEvents.length > 0) await this.stateManager.dispatchBatch(conversationEvents);
|
|
5261
|
+
};
|
|
5262
|
+
beginRun = () => {
|
|
5263
|
+
if (this.activeRunId) throw new Error(`Session ${this.sessionId} already has an active run.`);
|
|
5264
|
+
const runId = `agent-run-${randomUUID()}`;
|
|
5265
|
+
const controller = new AbortController();
|
|
5266
|
+
this.activeRunId = runId;
|
|
5267
|
+
this.activeRunController = controller;
|
|
5268
|
+
return {
|
|
5269
|
+
runId,
|
|
5270
|
+
signal: controller.signal
|
|
5271
|
+
};
|
|
5272
|
+
};
|
|
5273
|
+
abortRun = (runId) => {
|
|
5274
|
+
if (!this.activeRunId || !this.activeRunController) return false;
|
|
5275
|
+
if (runId && this.activeRunId !== runId) return false;
|
|
5276
|
+
this.activeRunController.abort();
|
|
5277
|
+
return true;
|
|
5278
|
+
};
|
|
5279
|
+
dispose = () => {
|
|
5280
|
+
this.activeRunController?.abort();
|
|
5281
|
+
this.activeRunController = null;
|
|
5282
|
+
this.activeRunId = null;
|
|
5283
|
+
};
|
|
5284
|
+
applyRunEvents = (events) => {
|
|
5285
|
+
for (const event of events) {
|
|
5286
|
+
if (event.type === NcpEventType.RunStarted && event.payload.runId) this.activeRunId = event.payload.runId;
|
|
5287
|
+
if (event.type === NcpEventType.MessageAbort || (event.type === NcpEventType.RunFinished || event.type === NcpEventType.RunError) && (!event.payload.runId || event.payload.runId === this.activeRunId)) {
|
|
5288
|
+
this.activeRunId = null;
|
|
5289
|
+
this.activeRunController = null;
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
};
|
|
5293
|
+
};
|
|
5294
|
+
var SessionRunManager$1 = class {
|
|
5295
|
+
runs = /* @__PURE__ */ new Map();
|
|
5296
|
+
constructor(sessionRepository) {
|
|
5297
|
+
this.sessionRepository = sessionRepository;
|
|
5298
|
+
}
|
|
5299
|
+
getSessionRun = (sessionId) => this.runs.get(sessionId) ?? null;
|
|
5300
|
+
createSessionRun = async (sessionId) => {
|
|
5301
|
+
if (this.runs.has(sessionId)) throw new Error(`Session run already exists: ${sessionId}`);
|
|
5302
|
+
const run = new SessionRun({
|
|
5303
|
+
messages: await this.sessionRepository.listSessionMessages(sessionId),
|
|
5304
|
+
sessionId
|
|
5305
|
+
});
|
|
5306
|
+
this.runs.set(sessionId, run);
|
|
5307
|
+
return run;
|
|
5308
|
+
};
|
|
5309
|
+
deleteSessionRun = (sessionId) => {
|
|
5310
|
+
const run = this.runs.get(sessionId);
|
|
5311
|
+
if (!run) return false;
|
|
5312
|
+
run.dispose();
|
|
5313
|
+
return this.runs.delete(sessionId);
|
|
5314
|
+
};
|
|
5315
|
+
dispose = () => {
|
|
5316
|
+
for (const run of this.runs.values()) run.dispose();
|
|
5317
|
+
this.runs.clear();
|
|
5318
|
+
};
|
|
5319
|
+
};
|
|
5320
|
+
//#endregion
|
|
5321
|
+
//#region src/features/agent-run/managers/tool-provider.manager.ts
|
|
5322
|
+
var ToolProviderManager = class {
|
|
5323
|
+
providers = /* @__PURE__ */ new Set();
|
|
5324
|
+
register = (provider) => {
|
|
5325
|
+
this.providers.add(provider);
|
|
5326
|
+
return () => {
|
|
5327
|
+
this.providers.delete(provider);
|
|
5328
|
+
};
|
|
5329
|
+
};
|
|
5330
|
+
buildTools = async (request) => {
|
|
5331
|
+
const tools = [];
|
|
5332
|
+
for (const provider of [...this.providers]) tools.push(...await provider.provide(request));
|
|
5333
|
+
return tools;
|
|
5334
|
+
};
|
|
5335
|
+
dispose = () => {
|
|
5336
|
+
this.providers.clear();
|
|
5337
|
+
};
|
|
5338
|
+
};
|
|
5339
|
+
//#endregion
|
|
5340
|
+
//#region src/features/agent-run/repositories/session.repository.ts
|
|
5341
|
+
function readString$3(value) {
|
|
5342
|
+
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
5343
|
+
}
|
|
5344
|
+
function readEventSessionId$1(event) {
|
|
5345
|
+
return "payload" in event && "sessionId" in event.payload ? readString$3(event.payload.sessionId) : void 0;
|
|
5346
|
+
}
|
|
5347
|
+
function isDurableSessionEvent(event) {
|
|
5348
|
+
return event.type !== NcpEventType.ContextWindowUpdated;
|
|
5349
|
+
}
|
|
5350
|
+
function readThinkingEffort(metadata) {
|
|
5351
|
+
return readString$3(metadata?.thinkingEffort) ?? null;
|
|
5352
|
+
}
|
|
5353
|
+
function readProjectRoot(metadata) {
|
|
5354
|
+
return readString$3(metadata?.project_root) ?? readString$3(metadata?.projectRoot);
|
|
5355
|
+
}
|
|
5356
|
+
var SessionRepository = class {
|
|
5357
|
+
cleanups = [];
|
|
5358
|
+
started = false;
|
|
5359
|
+
constructor(eventBus, ncpSessionManager) {
|
|
5360
|
+
this.eventBus = eventBus;
|
|
5361
|
+
this.ncpSessionManager = ncpSessionManager;
|
|
5362
|
+
}
|
|
5363
|
+
start = () => {
|
|
5364
|
+
if (this.started) return;
|
|
5365
|
+
this.started = true;
|
|
5366
|
+
this.cleanups.push(this.eventBus.on(eventKeys.ncpEvent, async (event) => {
|
|
5367
|
+
const sessionId = readEventSessionId$1(event);
|
|
5368
|
+
if (!sessionId || !isDurableSessionEvent(event)) return;
|
|
5369
|
+
await this.appendSessionEvent(sessionId, event);
|
|
5370
|
+
}));
|
|
5371
|
+
};
|
|
5372
|
+
dispose = () => {
|
|
5373
|
+
while (this.cleanups.length > 0) this.cleanups.pop()?.();
|
|
5374
|
+
this.started = false;
|
|
5375
|
+
};
|
|
5376
|
+
getSession = async (sessionId) => {
|
|
5377
|
+
const record = await this.ncpSessionManager.getSessionRecord(sessionId);
|
|
5378
|
+
if (!record) throw new Error(`Session not found: ${sessionId}`);
|
|
5379
|
+
const agentRuntimeId = readString$3(record.metadata?.agentRuntimeId) ?? "native";
|
|
5380
|
+
const model = readString$3(record.metadata?.model);
|
|
5381
|
+
return {
|
|
5382
|
+
sessionId: record.sessionId,
|
|
5383
|
+
agentId: record.agentId,
|
|
5384
|
+
agentRuntimeId,
|
|
5385
|
+
metadata: structuredClone(record.metadata ?? {}),
|
|
5386
|
+
model,
|
|
5387
|
+
projectRoot: readProjectRoot(record.metadata),
|
|
5388
|
+
thinkingEffort: readThinkingEffort(record.metadata)
|
|
5389
|
+
};
|
|
5390
|
+
};
|
|
5391
|
+
createSession = async (params) => {
|
|
5392
|
+
const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, metadata, model, projectRoot, sessionId, task, thinkingEffort } = params;
|
|
5393
|
+
const agentRuntimeId = requestedAgentRuntimeId ?? "native";
|
|
5394
|
+
const created = await this.ncpSessionManager.createSession({
|
|
5395
|
+
sourceSessionMetadata: {},
|
|
5396
|
+
sessionId,
|
|
5397
|
+
task: task ?? "Session",
|
|
5398
|
+
agentId,
|
|
5399
|
+
metadataOverrides: {
|
|
5400
|
+
...structuredClone(metadata ?? {}),
|
|
5401
|
+
agentRuntimeId,
|
|
5402
|
+
channel
|
|
5403
|
+
},
|
|
5404
|
+
model,
|
|
5405
|
+
projectRoot,
|
|
5406
|
+
runtime: agentRuntimeId,
|
|
5407
|
+
sessionType: agentRuntimeId,
|
|
5408
|
+
thinkingLevel: thinkingEffort ?? void 0
|
|
5409
|
+
});
|
|
5410
|
+
return {
|
|
5411
|
+
sessionId: created.sessionId,
|
|
5412
|
+
agentId,
|
|
5413
|
+
agentRuntimeId,
|
|
5414
|
+
metadata: structuredClone(created.metadata ?? {}),
|
|
5415
|
+
model,
|
|
5416
|
+
projectRoot,
|
|
5417
|
+
thinkingEffort: thinkingEffort ?? null
|
|
5418
|
+
};
|
|
5419
|
+
};
|
|
5420
|
+
getOrCreateSession = async (params) => {
|
|
5421
|
+
if (!params.sessionId) return await this.createSession(params);
|
|
5422
|
+
if (await this.ncpSessionManager.getSessionRecord(params.sessionId)) return await this.getSession(params.sessionId);
|
|
5423
|
+
return await this.createSession(params);
|
|
5424
|
+
};
|
|
5425
|
+
listSessionMessages = async (sessionId) => {
|
|
5426
|
+
return await this.ncpSessionManager.listSessionMessages(sessionId);
|
|
5427
|
+
};
|
|
5428
|
+
patchSessionMetadata = async (sessionId, patch) => {
|
|
5429
|
+
if (!await this.ncpSessionManager.updateSessionMetadata(sessionId, patch)) throw new Error(`Session metadata was not updated: ${sessionId}`);
|
|
5430
|
+
};
|
|
5431
|
+
appendSessionEvent = async (sessionId, event) => {
|
|
5432
|
+
await this.ncpSessionManager.appendSessionEvent({
|
|
5433
|
+
event,
|
|
5434
|
+
sessionId
|
|
5435
|
+
});
|
|
5436
|
+
};
|
|
5437
|
+
};
|
|
5438
|
+
//#endregion
|
|
5439
|
+
//#region src/features/agent-run/services/agent-run-message-projector.service.ts
|
|
5440
|
+
var AgentRunMessageProjector = class {
|
|
5441
|
+
project = (params) => projectNcpMessagesWithContextCompaction({
|
|
5442
|
+
sessionId: params.sessionId,
|
|
5443
|
+
sessionMessages: params.messages
|
|
5444
|
+
});
|
|
5445
|
+
};
|
|
5446
|
+
//#endregion
|
|
5447
|
+
//#region src/features/agent-run/services/agent-run-model-input-budgeter.service.ts
|
|
5448
|
+
var AgentRunModelInputBudgeter = class {
|
|
5449
|
+
inputBudgetPruner = new InputBudgetPruner();
|
|
5450
|
+
constructor(configManager) {
|
|
5451
|
+
this.configManager = configManager;
|
|
5452
|
+
}
|
|
5453
|
+
prune = async (params) => {
|
|
5454
|
+
const config = this.configManager.loadConfig();
|
|
5455
|
+
const defaultAgentId = resolveDefaultAgentProfileId(config);
|
|
5456
|
+
const profile = findEffectiveAgentProfile(config, params.spec.agentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
|
|
5457
|
+
const contextTokens = profile?.contextTokens ?? config.agents.defaults.contextTokens;
|
|
5458
|
+
const reservedContextTokens = ContextWindowBudgetService.resolveReservedContextTokens({
|
|
5459
|
+
contextTokens,
|
|
5460
|
+
configuredReservedContextTokens: profile?.reservedContextTokens ?? config.agents.defaults.reservedContextTokens
|
|
5461
|
+
});
|
|
5462
|
+
const pruned = this.inputBudgetPruner.prune({
|
|
5463
|
+
messages: params.messages.map((message) => ({ ...message })),
|
|
5464
|
+
contextTokens,
|
|
5465
|
+
reserveTokensFloor: reservedContextTokens,
|
|
5466
|
+
softThresholdTokens: 0
|
|
5467
|
+
});
|
|
5468
|
+
return {
|
|
5469
|
+
...pruned,
|
|
5470
|
+
messages: pruned.messages
|
|
5471
|
+
};
|
|
5472
|
+
};
|
|
5473
|
+
};
|
|
5474
|
+
//#endregion
|
|
5475
|
+
//#region src/features/agent-run/services/agent-run-model-input-builder.service.ts
|
|
5476
|
+
var AgentRunModelInputBuilder = class {
|
|
5477
|
+
constructor(messageProjector, modelInputBudgeter, assetStore = null) {
|
|
5478
|
+
this.messageProjector = messageProjector;
|
|
5479
|
+
this.modelInputBudgeter = modelInputBudgeter;
|
|
5480
|
+
this.assetStore = assetStore;
|
|
5481
|
+
}
|
|
5482
|
+
build = async (request) => {
|
|
5483
|
+
const contextContent = request.contextBlocks.map((block) => block.trim()).filter(Boolean).join("\n\n");
|
|
5484
|
+
const contextMessages = contextContent ? [{
|
|
5485
|
+
role: "system",
|
|
5486
|
+
content: contextContent
|
|
5487
|
+
}] : [];
|
|
5488
|
+
const conversationMessages = this.messageProjector.project({
|
|
5489
|
+
sessionId: request.sessionId,
|
|
5490
|
+
messages: request.messages
|
|
5491
|
+
}).flatMap((message) => ncpMessageToOpenAiMessages(message, { assetStore: this.assetStore }));
|
|
5492
|
+
const pruned = await this.modelInputBudgeter.prune({
|
|
5493
|
+
spec: request.spec,
|
|
5494
|
+
messages: [...contextMessages, ...conversationMessages]
|
|
5495
|
+
});
|
|
5496
|
+
const tools = request.tools.map((tool) => buildOpenAiFunctionTool({
|
|
5497
|
+
name: tool.name,
|
|
5498
|
+
description: tool.description,
|
|
5499
|
+
parameters: tool.parameters
|
|
5500
|
+
}));
|
|
5501
|
+
return {
|
|
5502
|
+
messages: pruned.messages,
|
|
5503
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
5504
|
+
model: request.spec.model,
|
|
5505
|
+
thinkingLevel: request.spec.thinkingEffort ?? null,
|
|
5506
|
+
max_tokens: request.spec.maxTokens
|
|
5507
|
+
};
|
|
5508
|
+
};
|
|
5509
|
+
};
|
|
5510
|
+
//#endregion
|
|
5511
|
+
//#region src/features/agent-run/services/ncp-agent-runtime-wrapper.service.ts
|
|
5512
|
+
var NcpAgentRuntimeWrapper = class {
|
|
5513
|
+
stateManager = new DefaultNcpAgentConversationStateManager();
|
|
5514
|
+
runtime = null;
|
|
5515
|
+
currentTools = [];
|
|
5516
|
+
constructor(params) {
|
|
5517
|
+
this.params = params;
|
|
5518
|
+
}
|
|
5519
|
+
run = async function* (spec, options) {
|
|
5520
|
+
const { sessionRun, tools } = options;
|
|
5521
|
+
this.currentTools = tools.map(this.toOpenAiTool);
|
|
5522
|
+
const messages = sessionRun.inbox.drain();
|
|
5523
|
+
for (const event of this.toMessageSentEvents(messages, spec, sessionRun.sessionId)) yield await this.applyEvent(sessionRun, event);
|
|
5524
|
+
const input = {
|
|
5525
|
+
sessionId: sessionRun.sessionId,
|
|
5526
|
+
runId: spec.runId,
|
|
5527
|
+
messages,
|
|
5528
|
+
correlationId: spec.correlationId,
|
|
5529
|
+
metadata: this.buildMetadata(spec)
|
|
5530
|
+
};
|
|
5531
|
+
for await (const event of this.getRuntime().run(input, { signal: options.signal })) yield await this.applyEvent(sessionRun, event);
|
|
5532
|
+
this.currentTools = [];
|
|
5533
|
+
};
|
|
5534
|
+
dispose = async () => {
|
|
5535
|
+
if (this.runtime && "dispose" in this.runtime && typeof this.runtime.dispose === "function") await this.runtime.dispose();
|
|
5536
|
+
this.runtime = null;
|
|
5537
|
+
this.currentTools = [];
|
|
5538
|
+
};
|
|
5539
|
+
getRuntime = () => {
|
|
5540
|
+
if (!this.runtime) this.runtime = this.params.createRuntime({
|
|
5541
|
+
resolveTools: () => this.currentTools,
|
|
5542
|
+
stateManager: this.stateManager
|
|
5543
|
+
});
|
|
5544
|
+
return this.runtime;
|
|
5545
|
+
};
|
|
5546
|
+
toMessageSentEvents = (messages, spec, sessionId) => messages.map((message) => ({
|
|
5547
|
+
type: NcpEventType.MessageSent,
|
|
5548
|
+
payload: {
|
|
5549
|
+
sessionId,
|
|
5550
|
+
message,
|
|
5551
|
+
correlationId: spec.correlationId
|
|
5552
|
+
}
|
|
5553
|
+
}));
|
|
5554
|
+
buildMetadata = (spec) => ({
|
|
5555
|
+
...this.params.session.metadata,
|
|
5556
|
+
agentId: spec.agentId,
|
|
5557
|
+
agentRuntimeId: this.params.session.agentRuntimeId,
|
|
5558
|
+
maxTokens: spec.maxTokens,
|
|
5559
|
+
model: spec.model,
|
|
5560
|
+
preferred_model: spec.model,
|
|
5561
|
+
thinkingEffort: spec.thinkingEffort
|
|
5562
|
+
});
|
|
5563
|
+
toOpenAiTool = (tool) => buildOpenAiFunctionTool({
|
|
5564
|
+
name: tool.name,
|
|
5565
|
+
description: tool.description,
|
|
5566
|
+
parameters: tool.parameters
|
|
5567
|
+
});
|
|
5568
|
+
applyEvent = async (sessionRun, event) => {
|
|
5569
|
+
await sessionRun.applyEvents([event]);
|
|
5570
|
+
return event;
|
|
5571
|
+
};
|
|
5572
|
+
};
|
|
5573
|
+
//#endregion
|
|
5574
|
+
//#region src/features/agent-run/utils/agent-run-request-metadata.utils.ts
|
|
5575
|
+
function normalizeString(value) {
|
|
5576
|
+
return value?.trim() || void 0;
|
|
5577
|
+
}
|
|
5578
|
+
function buildAgentRunRequestMetadata(params) {
|
|
5579
|
+
const { request, session } = params;
|
|
5580
|
+
const agentId = normalizeString(request.agentId ?? session?.agentId);
|
|
5581
|
+
const projectRoot = normalizeString(request.projectRoot ?? session?.projectRoot);
|
|
5582
|
+
const channel = normalizeString(request.channel);
|
|
5583
|
+
const model = normalizeString(request.model ?? session?.model);
|
|
5584
|
+
return {
|
|
5585
|
+
...structuredClone(session?.metadata ?? {}),
|
|
5586
|
+
agentId,
|
|
5587
|
+
projectRoot,
|
|
5588
|
+
project_root: projectRoot,
|
|
5589
|
+
channel,
|
|
5590
|
+
model,
|
|
5591
|
+
thinkingEffort: request.thinkingEffort ?? session?.thinkingEffort
|
|
5592
|
+
};
|
|
5593
|
+
}
|
|
5594
|
+
//#endregion
|
|
5595
|
+
//#region src/features/narp-runtime/services/builtin-narp-runtime-provider.service.ts
|
|
5596
|
+
const NARP_API_MODE_HEADER = "x-nextclaw-narp-api-mode";
|
|
5597
|
+
const NARP_HTTP_RUNTIME_KIND = "narp-http";
|
|
5598
|
+
const NARP_STDIO_RUNTIME_KIND = "narp-stdio";
|
|
5599
|
+
const BUILTIN_PROVIDER_REGISTRY = new ProviderRegistry(BUILTIN_PROVIDER_PLUGINS);
|
|
5600
|
+
function readRecord(value) {
|
|
5601
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
5602
|
+
return value;
|
|
5603
|
+
}
|
|
5604
|
+
function readString$2(value) {
|
|
5605
|
+
if (typeof value !== "string") return;
|
|
5606
|
+
return value.trim() || void 0;
|
|
5607
|
+
}
|
|
5608
|
+
function resolveEntryIcon(entry) {
|
|
5609
|
+
return entry.icon ?? null;
|
|
5610
|
+
}
|
|
5611
|
+
function resolveRequestedModel(params) {
|
|
5612
|
+
const { configuredModel, defaultModel, input, sessionMetadata } = params;
|
|
5613
|
+
const runMetadata = readRecord(input.metadata);
|
|
5614
|
+
return readString$2(runMetadata?.preferred_model) ?? readString$2(runMetadata?.preferredModel) ?? readString$2(runMetadata?.model) ?? readString$2(sessionMetadata.preferred_model) ?? readString$2(sessionMetadata.preferredModel) ?? readString$2(sessionMetadata.model) ?? configuredModel ?? defaultModel;
|
|
5615
|
+
}
|
|
5616
|
+
function resolveProviderApiMode(resolution) {
|
|
5617
|
+
const wireApi = resolution.provider?.wireApi?.trim().toLowerCase();
|
|
5618
|
+
if (wireApi === "responses") return "codex_responses";
|
|
5619
|
+
if (wireApi === "chat") return "chat_completions";
|
|
5620
|
+
const providerName = resolution.providerName?.trim().toLowerCase();
|
|
5621
|
+
const apiBase = resolution.apiBase?.trim().toLowerCase() ?? "";
|
|
5622
|
+
if (providerName === "anthropic" || apiBase.includes("anthropic.com")) return "anthropic_messages";
|
|
5623
|
+
return "chat_completions";
|
|
5624
|
+
}
|
|
5625
|
+
function buildProviderRoute(params) {
|
|
5626
|
+
const model = resolveRequestedModel(params);
|
|
5627
|
+
if (!model) return;
|
|
5628
|
+
const resolution = resolveProviderRuntime(params.config, model);
|
|
5629
|
+
if (!resolution.provider) return;
|
|
5630
|
+
const apiBase = resolution.apiBase ?? (resolution.providerName ? BUILTIN_PROVIDER_REGISTRY.findProviderByName(resolution.providerName)?.defaultApiBase ?? null : null);
|
|
5631
|
+
return {
|
|
5632
|
+
model: resolution.providerLocalModel,
|
|
5633
|
+
apiKey: resolution.apiKey,
|
|
5634
|
+
apiBase,
|
|
5635
|
+
headers: {
|
|
5636
|
+
...resolution.provider.extraHeaders ?? {},
|
|
5637
|
+
[NARP_API_MODE_HEADER]: resolveProviderApiMode(resolution)
|
|
5638
|
+
}
|
|
5639
|
+
};
|
|
5640
|
+
}
|
|
5641
|
+
var BuiltinHttpRuntimeSessionTypeService = class {
|
|
5642
|
+
pendingDescribeByMode = /* @__PURE__ */ new Map();
|
|
5643
|
+
constructor(entry, defaultModel) {
|
|
5644
|
+
this.entry = entry;
|
|
5645
|
+
this.defaultModel = defaultModel;
|
|
5646
|
+
}
|
|
5647
|
+
describe = async (describeParams) => {
|
|
5648
|
+
const describeMode = describeParams?.describeMode === "probe" ? "probe" : "observation";
|
|
5649
|
+
const pending = this.pendingDescribeByMode.get(describeMode);
|
|
5650
|
+
if (pending) return await pending;
|
|
5651
|
+
const nextDescribe = this.describeInternal();
|
|
5652
|
+
this.pendingDescribeByMode.set(describeMode, nextDescribe);
|
|
5653
|
+
try {
|
|
5654
|
+
return await nextDescribe;
|
|
5655
|
+
} finally {
|
|
5656
|
+
this.pendingDescribeByMode.delete(describeMode);
|
|
5657
|
+
}
|
|
5658
|
+
};
|
|
5659
|
+
describeInternal = async () => {
|
|
5660
|
+
const config = new HttpRuntimeConfigResolver(this.entry.config ?? {}).resolve({ defaultModel: this.defaultModel });
|
|
5661
|
+
if (!config.baseUrl) return {
|
|
5662
|
+
icon: resolveEntryIcon(this.entry),
|
|
5663
|
+
ready: false,
|
|
5664
|
+
reason: "base_url_missing",
|
|
5665
|
+
reasonMessage: "Configure the runtime entry baseUrl before starting an HTTP runtime session.",
|
|
5666
|
+
recommendedModel: config.recommendedModel ?? null,
|
|
5667
|
+
cta: {
|
|
5668
|
+
kind: "settings",
|
|
5669
|
+
label: "Configure HTTP Runtime"
|
|
5670
|
+
}
|
|
5671
|
+
};
|
|
5672
|
+
if (!((config.capabilityProbe ?? true) && Boolean(config.healthcheckUrl))) return {
|
|
5673
|
+
icon: resolveEntryIcon(this.entry),
|
|
5674
|
+
ready: true,
|
|
5675
|
+
reason: null,
|
|
5676
|
+
reasonMessage: null,
|
|
5677
|
+
recommendedModel: config.recommendedModel ?? null,
|
|
5678
|
+
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5679
|
+
cta: null
|
|
5680
|
+
};
|
|
5681
|
+
const controller = new AbortController();
|
|
5682
|
+
const timeoutMs = config.healthcheckTimeoutMs ?? 3e3;
|
|
5683
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
5684
|
+
try {
|
|
5685
|
+
const response = await fetch(config.healthcheckUrl ?? "", {
|
|
5686
|
+
method: "GET",
|
|
5687
|
+
headers: config.headers,
|
|
5688
|
+
signal: controller.signal
|
|
5689
|
+
});
|
|
5690
|
+
if (!response.ok) return {
|
|
5691
|
+
icon: resolveEntryIcon(this.entry),
|
|
5692
|
+
ready: false,
|
|
5693
|
+
reason: "healthcheck_failed",
|
|
5694
|
+
reasonMessage: `HTTP runtime healthcheck returned HTTP ${response.status}.`,
|
|
5695
|
+
recommendedModel: config.recommendedModel ?? null,
|
|
5696
|
+
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5697
|
+
cta: null
|
|
5698
|
+
};
|
|
5699
|
+
return {
|
|
5700
|
+
icon: resolveEntryIcon(this.entry),
|
|
5701
|
+
ready: true,
|
|
5702
|
+
reason: null,
|
|
5703
|
+
reasonMessage: null,
|
|
5704
|
+
recommendedModel: config.recommendedModel ?? null,
|
|
5705
|
+
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5706
|
+
cta: null
|
|
5707
|
+
};
|
|
5708
|
+
} catch (error) {
|
|
5709
|
+
return {
|
|
5710
|
+
icon: resolveEntryIcon(this.entry),
|
|
5711
|
+
ready: false,
|
|
5712
|
+
reason: "healthcheck_unreachable",
|
|
5713
|
+
reasonMessage: error instanceof Error ? error.message : "Failed to reach the configured HTTP runtime healthcheck.",
|
|
5714
|
+
recommendedModel: config.recommendedModel ?? null,
|
|
5715
|
+
...config.supportedModels ? { supportedModels: config.supportedModels } : {},
|
|
5716
|
+
cta: null
|
|
5717
|
+
};
|
|
5718
|
+
} finally {
|
|
5719
|
+
clearTimeout(timeout);
|
|
5720
|
+
}
|
|
5241
5721
|
};
|
|
5242
5722
|
};
|
|
5243
5723
|
var BuiltinStdioRuntimeSessionTypeService = class {
|
|
@@ -5356,6 +5836,7 @@ var BuiltinNarpRuntimeProviderService = class {
|
|
|
5356
5836
|
...resolvedConfig.basePath ? { basePath: resolvedConfig.basePath } : {},
|
|
5357
5837
|
...resolvedConfig.endpointId ? { endpointId: resolvedConfig.endpointId } : {},
|
|
5358
5838
|
...resolvedConfig.headers ? { headers: resolvedConfig.headers } : {},
|
|
5839
|
+
resolveTools: runtimeParams.resolveTools,
|
|
5359
5840
|
stateManager: runtimeParams.stateManager,
|
|
5360
5841
|
resolveProviderRoute: (input) => buildProviderRoute({
|
|
5361
5842
|
config: this.configManager.loadConfig(),
|
|
@@ -5371,6 +5852,7 @@ var BuiltinNarpRuntimeProviderService = class {
|
|
|
5371
5852
|
return new StdioRuntimeNcpAgentRuntime({
|
|
5372
5853
|
...new StdioRuntimeConfigResolver(config).resolve(),
|
|
5373
5854
|
sessionId: runtimeParams.sessionId,
|
|
5855
|
+
resolveTools: runtimeParams.resolveTools,
|
|
5374
5856
|
stateManager: runtimeParams.stateManager,
|
|
5375
5857
|
resolveProviderRoute: (input) => buildProviderRoute({
|
|
5376
5858
|
config: this.configManager.loadConfig(),
|
|
@@ -5383,36 +5865,457 @@ var BuiltinNarpRuntimeProviderService = class {
|
|
|
5383
5865
|
};
|
|
5384
5866
|
};
|
|
5385
5867
|
//#endregion
|
|
5386
|
-
//#region src/contributions/agent-runtime/index.ts
|
|
5387
|
-
var
|
|
5388
|
-
cleanups = [];
|
|
5868
|
+
//#region src/contributions/kernel-branch/contributions/agent-run-runtime/index.ts
|
|
5869
|
+
var AgentRunRuntimeContribution = class {
|
|
5870
|
+
cleanups = [];
|
|
5871
|
+
modelInputBuilder;
|
|
5872
|
+
constructor(kernel, branch) {
|
|
5873
|
+
this.kernel = kernel;
|
|
5874
|
+
this.branch = branch;
|
|
5875
|
+
this.modelInputBuilder = new AgentRunModelInputBuilder(new AgentRunMessageProjector(), new AgentRunModelInputBudgeter(kernel.configManager), kernel.assetStore);
|
|
5876
|
+
}
|
|
5877
|
+
start = () => {
|
|
5878
|
+
if (this.cleanups.length > 0) return;
|
|
5879
|
+
const { entries } = resolveAgentRuntimeEntries({ config: this.kernel.configManager.loadConfig() });
|
|
5880
|
+
this.branch.agentRuntimeManager.applyEntries(entries);
|
|
5881
|
+
this.cleanups.push(this.registerNativeRuntime());
|
|
5882
|
+
for (const provider of new BuiltinNarpRuntimeProviderService(this.kernel.configManager).createProviders()) this.cleanups.push(this.registerNarpRuntime(provider));
|
|
5883
|
+
};
|
|
5884
|
+
dispose = async () => {
|
|
5885
|
+
while (this.cleanups.length > 0) await this.cleanups.pop()?.();
|
|
5886
|
+
};
|
|
5887
|
+
registerNativeRuntime = () => this.branch.agentRuntimeManager.register({
|
|
5888
|
+
kind: DEFAULT_AGENT_RUNTIME_ENTRY_ID,
|
|
5889
|
+
label: "Native",
|
|
5890
|
+
defaultReuseScope: "global",
|
|
5891
|
+
createRuntime: () => new DefaultNcpAgentRuntime$1({
|
|
5892
|
+
llmApi: new ProviderManagerNcpLLMApi(this.kernel.llmProviders),
|
|
5893
|
+
modelInputBuilder: this.modelInputBuilder,
|
|
5894
|
+
runPreflight: async ({ spec, sessionRun }) => {
|
|
5895
|
+
const session = await this.branch.sessionRepository.getSession(sessionRun.sessionId);
|
|
5896
|
+
return await this.branch.contextCompactionManager.runPreflight({
|
|
5897
|
+
agentId: spec.agentId,
|
|
5898
|
+
messages: sessionRun.getSnapshot().messages,
|
|
5899
|
+
metadata: session.metadata,
|
|
5900
|
+
sessionId: sessionRun.sessionId
|
|
5901
|
+
});
|
|
5902
|
+
}
|
|
5903
|
+
})
|
|
5904
|
+
});
|
|
5905
|
+
registerNarpRuntime = (provider) => this.branch.agentRuntimeManager.register({
|
|
5906
|
+
kind: provider.kind,
|
|
5907
|
+
label: provider.label,
|
|
5908
|
+
defaultReuseScope: provider.kind === "narp-stdio" ? "session" : "session",
|
|
5909
|
+
describeSessionTypeForEntry: provider.describeSessionTypeForEntry,
|
|
5910
|
+
createRuntime: ({ entry, session }) => {
|
|
5911
|
+
if (!provider.createRuntimeForEntry) throw new Error(`Agent runtime provider does not support entries: ${provider.kind}`);
|
|
5912
|
+
return new NcpAgentRuntimeWrapper({
|
|
5913
|
+
session,
|
|
5914
|
+
createRuntime: ({ resolveTools, stateManager }) => provider.createRuntimeForEntry({
|
|
5915
|
+
entry,
|
|
5916
|
+
runtimeParams: {
|
|
5917
|
+
sessionId: session.sessionId,
|
|
5918
|
+
...session.agentId ? { agentId: session.agentId } : {},
|
|
5919
|
+
resolveAssetContentPath: (assetUri) => this.kernel.assetStore.resolveContentPath(assetUri),
|
|
5920
|
+
resolveTools,
|
|
5921
|
+
sessionMetadata: session.metadata,
|
|
5922
|
+
stateManager
|
|
5923
|
+
}
|
|
5924
|
+
})
|
|
5925
|
+
});
|
|
5926
|
+
}
|
|
5927
|
+
});
|
|
5928
|
+
};
|
|
5929
|
+
//#endregion
|
|
5930
|
+
//#region src/contributions/kernel-branch/contributions/context-window/index.ts
|
|
5931
|
+
const STREAM_REFRESH_DELAY_MS$1 = 1500;
|
|
5932
|
+
function formatBackgroundError$1(error) {
|
|
5933
|
+
if (error instanceof Error) return error.stack ?? error.message;
|
|
5934
|
+
return String(error);
|
|
5935
|
+
}
|
|
5936
|
+
var ContextWindowContribution = class {
|
|
5937
|
+
contextWindowPreview;
|
|
5938
|
+
lastPublishedSignatureBySession = /* @__PURE__ */ new Map();
|
|
5939
|
+
pendingTimers = /* @__PURE__ */ new Map();
|
|
5940
|
+
stopped = true;
|
|
5941
|
+
unsubscribeNcpEvent = null;
|
|
5942
|
+
constructor(kernel, branch) {
|
|
5943
|
+
this.kernel = kernel;
|
|
5944
|
+
this.branch = branch;
|
|
5945
|
+
this.contextWindowPreview = new ContextCompactionPreflightService({ configManager: kernel.configManager });
|
|
5946
|
+
}
|
|
5947
|
+
start = () => {
|
|
5948
|
+
if (this.unsubscribeNcpEvent) return;
|
|
5949
|
+
this.stopped = false;
|
|
5950
|
+
this.unsubscribeNcpEvent = this.kernel.eventBus.on(eventKeys.ncpEvent, this.handleNcpEvent);
|
|
5951
|
+
};
|
|
5952
|
+
dispose = () => {
|
|
5953
|
+
this.unsubscribeNcpEvent?.();
|
|
5954
|
+
this.unsubscribeNcpEvent = null;
|
|
5955
|
+
this.stopped = true;
|
|
5956
|
+
for (const timer of this.pendingTimers.values()) clearTimeout(timer);
|
|
5957
|
+
this.pendingTimers.clear();
|
|
5958
|
+
this.lastPublishedSignatureBySession.clear();
|
|
5959
|
+
};
|
|
5960
|
+
handleNcpEvent = (event) => {
|
|
5961
|
+
const sessionId = readContextWindowEventSessionId(event);
|
|
5962
|
+
if (!sessionId || !this.branch.sessionRunManager.getSessionRun(sessionId)) return;
|
|
5963
|
+
if (event.type === NcpEventType.ContextWindowUpdated) {
|
|
5964
|
+
this.rememberPublishedContextWindow(sessionId, event.payload.contextWindow);
|
|
5965
|
+
return;
|
|
5966
|
+
}
|
|
5967
|
+
if (shouldRefreshContextWindowImmediately(event)) {
|
|
5968
|
+
this.refreshNow(sessionId);
|
|
5969
|
+
return;
|
|
5970
|
+
}
|
|
5971
|
+
if (shouldRefreshContextWindowDuringStream(event)) this.refreshSoon(sessionId);
|
|
5972
|
+
};
|
|
5973
|
+
refreshSoon = (sessionId) => {
|
|
5974
|
+
if (this.pendingTimers.has(sessionId)) return;
|
|
5975
|
+
const timer = setTimeout(() => {
|
|
5976
|
+
this.pendingTimers.delete(sessionId);
|
|
5977
|
+
this.refreshNow(sessionId);
|
|
5978
|
+
}, STREAM_REFRESH_DELAY_MS$1);
|
|
5979
|
+
this.pendingTimers.set(sessionId, timer);
|
|
5980
|
+
};
|
|
5981
|
+
refreshNow = (sessionId) => {
|
|
5982
|
+
const timer = this.pendingTimers.get(sessionId);
|
|
5983
|
+
if (timer) {
|
|
5984
|
+
clearTimeout(timer);
|
|
5985
|
+
this.pendingTimers.delete(sessionId);
|
|
5986
|
+
}
|
|
5987
|
+
this.publishContextWindow(sessionId).catch((error) => {
|
|
5988
|
+
console.error(`[kernel-branch-context-window] failed to refresh ${sessionId}: ${formatBackgroundError$1(error)}`);
|
|
5989
|
+
});
|
|
5990
|
+
};
|
|
5991
|
+
publishContextWindow = async (sessionId) => {
|
|
5992
|
+
if (this.stopped) return;
|
|
5993
|
+
const sessionRun = this.branch.sessionRunManager.getSessionRun(sessionId);
|
|
5994
|
+
if (!sessionRun) return;
|
|
5995
|
+
const session = await this.branch.sessionRepository.getSession(sessionId);
|
|
5996
|
+
const contextWindow = this.contextWindowPreview.preview({
|
|
5997
|
+
requestMetadata: session.metadata,
|
|
5998
|
+
sessionId,
|
|
5999
|
+
sessionMessages: sessionRun.getSnapshot().messages,
|
|
6000
|
+
storedAgentId: session.agentId,
|
|
6001
|
+
storedMetadata: session.metadata
|
|
6002
|
+
});
|
|
6003
|
+
if (!isContextWindowSnapshot(contextWindow) || this.stopped) return;
|
|
6004
|
+
const signature = createContextWindowSignature(contextWindow);
|
|
6005
|
+
if (this.lastPublishedSignatureBySession.get(sessionId) === signature) return;
|
|
6006
|
+
this.lastPublishedSignatureBySession.set(sessionId, signature);
|
|
6007
|
+
this.kernel.eventBus.emit(eventKeys.ncpEvent, {
|
|
6008
|
+
type: NcpEventType.ContextWindowUpdated,
|
|
6009
|
+
payload: {
|
|
6010
|
+
contextWindow,
|
|
6011
|
+
sessionId
|
|
6012
|
+
}
|
|
6013
|
+
}, {
|
|
6014
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6015
|
+
source: "kernel-branch-context-window"
|
|
6016
|
+
});
|
|
6017
|
+
};
|
|
6018
|
+
rememberPublishedContextWindow = (sessionId, contextWindow) => {
|
|
6019
|
+
this.lastPublishedSignatureBySession.set(sessionId, createContextWindowSignature(contextWindow));
|
|
6020
|
+
};
|
|
6021
|
+
};
|
|
6022
|
+
//#endregion
|
|
6023
|
+
//#region src/contributions/kernel-branch/contributions/context-provider/providers/kernel-context.provider.ts
|
|
6024
|
+
var KernelContextProvider = class {
|
|
6025
|
+
constructor(kernel, branch) {
|
|
6026
|
+
this.kernel = kernel;
|
|
6027
|
+
this.branch = branch;
|
|
6028
|
+
}
|
|
6029
|
+
provide = async (request) => {
|
|
6030
|
+
const session = request.sessionId ? await this.branch.sessionRepository.getSession(request.sessionId) : null;
|
|
6031
|
+
const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
|
|
6032
|
+
const requestMetadata = buildAgentRunRequestMetadata({
|
|
6033
|
+
request,
|
|
6034
|
+
session
|
|
6035
|
+
});
|
|
6036
|
+
const runContext = resolveNextclawNcpRunContext({
|
|
6037
|
+
configManager: this.kernel.configManager,
|
|
6038
|
+
sessionId,
|
|
6039
|
+
requestMetadata,
|
|
6040
|
+
sessionMetadata: session?.metadata ?? requestMetadata,
|
|
6041
|
+
storedAgentId: request.agentId ?? session?.agentId
|
|
6042
|
+
});
|
|
6043
|
+
const toolRegistry = this.kernel.toolManager.createRuntimeRegistry({ updateToolCallResult: async () => void 0 });
|
|
6044
|
+
toolRegistry.prepareForRun(runContext.toolRunContext);
|
|
6045
|
+
return [this.buildSystemContextBlock({
|
|
6046
|
+
availableTools: buildToolCatalogEntries(toolRegistry.getToolDefinitions()),
|
|
6047
|
+
runContext
|
|
6048
|
+
})];
|
|
6049
|
+
};
|
|
6050
|
+
buildSystemContextBlock = (params) => {
|
|
6051
|
+
const { availableTools, runContext } = params;
|
|
6052
|
+
const lines = [
|
|
6053
|
+
new ContextBuilder(runContext.effectiveWorkspace, runContext.config.agents.context, {
|
|
6054
|
+
hostWorkspace: runContext.profile.workspace,
|
|
6055
|
+
sessionProjectRoot: readSessionProjectRoot(runContext.sessionMetadata)
|
|
6056
|
+
}).buildSystemPrompt(void 0, runContext.sessionKey, availableTools, [buildSessionOrchestrationSection(), buildMinimalSystemExecutionPrompt(runContext.effectiveModel)]),
|
|
6057
|
+
"## Current Session",
|
|
6058
|
+
`Channel: ${runContext.channel}`,
|
|
6059
|
+
`Chat ID: ${runContext.chatId}`,
|
|
6060
|
+
`Session: ${runContext.sessionKey}`
|
|
6061
|
+
];
|
|
6062
|
+
if (runContext.runtimeThinking) lines.push(`Thinking policy: ${runContext.runtimeThinking}`);
|
|
6063
|
+
return lines.join("\n");
|
|
6064
|
+
};
|
|
6065
|
+
};
|
|
6066
|
+
//#endregion
|
|
6067
|
+
//#region src/contributions/kernel-branch/contributions/context-provider/index.ts
|
|
6068
|
+
var ContextProviderContribution = class {
|
|
6069
|
+
unregister = null;
|
|
6070
|
+
constructor(kernel, branch) {
|
|
6071
|
+
this.kernel = kernel;
|
|
6072
|
+
this.branch = branch;
|
|
6073
|
+
}
|
|
6074
|
+
start = () => {
|
|
6075
|
+
if (this.unregister) return;
|
|
6076
|
+
this.unregister = this.branch.contextProviderManager.register(new KernelContextProvider(this.kernel, this.branch));
|
|
6077
|
+
};
|
|
6078
|
+
dispose = () => {
|
|
6079
|
+
this.unregister?.();
|
|
6080
|
+
this.unregister = null;
|
|
6081
|
+
};
|
|
6082
|
+
};
|
|
6083
|
+
//#endregion
|
|
6084
|
+
//#region src/contributions/kernel-branch/contributions/tool-provider/providers/kernel-tool.provider.ts
|
|
6085
|
+
var KernelToolProvider = class {
|
|
6086
|
+
constructor(kernel, branch) {
|
|
6087
|
+
this.kernel = kernel;
|
|
6088
|
+
this.branch = branch;
|
|
6089
|
+
}
|
|
6090
|
+
provide = async (request) => {
|
|
6091
|
+
const session = request.sessionId ? await this.branch.sessionRepository.getSession(request.sessionId) : null;
|
|
6092
|
+
const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
|
|
6093
|
+
const requestMetadata = buildAgentRunRequestMetadata({
|
|
6094
|
+
request,
|
|
6095
|
+
session
|
|
6096
|
+
});
|
|
6097
|
+
const runContext = resolveNextclawNcpRunContext({
|
|
6098
|
+
configManager: this.kernel.configManager,
|
|
6099
|
+
sessionId,
|
|
6100
|
+
requestMetadata,
|
|
6101
|
+
sessionMetadata: session?.metadata ?? requestMetadata,
|
|
6102
|
+
storedAgentId: request.agentId ?? session?.agentId
|
|
6103
|
+
});
|
|
6104
|
+
const toolRegistry = this.kernel.toolManager.createRuntimeRegistry({ updateToolCallResult: async ({ result, sessionId: targetSessionId, toolCallId }) => {
|
|
6105
|
+
this.kernel.eventBus.emit(eventKeys.ncpEvent, {
|
|
6106
|
+
type: NcpEventType.MessageToolCallResult,
|
|
6107
|
+
payload: {
|
|
6108
|
+
sessionId: targetSessionId,
|
|
6109
|
+
toolCallId,
|
|
6110
|
+
content: result
|
|
6111
|
+
}
|
|
6112
|
+
}, {
|
|
6113
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6114
|
+
source: "agent-run-tool-provider"
|
|
6115
|
+
});
|
|
6116
|
+
} });
|
|
6117
|
+
toolRegistry.prepareForRun(runContext.toolRunContext);
|
|
6118
|
+
return toolRegistry.listTools();
|
|
6119
|
+
};
|
|
6120
|
+
};
|
|
6121
|
+
//#endregion
|
|
6122
|
+
//#region src/contributions/kernel-branch/contributions/tool-provider/index.ts
|
|
6123
|
+
var ToolProviderContribution = class {
|
|
6124
|
+
unregister = null;
|
|
6125
|
+
constructor(kernel, branch) {
|
|
6126
|
+
this.kernel = kernel;
|
|
6127
|
+
this.branch = branch;
|
|
6128
|
+
}
|
|
6129
|
+
start = () => {
|
|
6130
|
+
if (this.unregister) return;
|
|
6131
|
+
this.unregister = this.branch.toolProviderManager.register(new KernelToolProvider(this.kernel, this.branch));
|
|
6132
|
+
};
|
|
6133
|
+
dispose = () => {
|
|
6134
|
+
this.unregister?.();
|
|
6135
|
+
this.unregister = null;
|
|
6136
|
+
};
|
|
6137
|
+
};
|
|
6138
|
+
//#endregion
|
|
6139
|
+
//#region src/contributions/kernel-branch/index.ts
|
|
6140
|
+
var KernelBranch = class {
|
|
6141
|
+
agentRuntimeManager = new AgentRuntimeManager$1();
|
|
6142
|
+
contextCompactionManager;
|
|
6143
|
+
contextProviderManager = new ContextProviderManager();
|
|
6144
|
+
sessionRepository;
|
|
6145
|
+
sessionRunManager;
|
|
6146
|
+
toolProviderManager = new ToolProviderManager();
|
|
6147
|
+
agentRunRequestManager;
|
|
6148
|
+
contributions;
|
|
6149
|
+
started = false;
|
|
6150
|
+
constructor(kernel) {
|
|
6151
|
+
this.kernel = kernel;
|
|
6152
|
+
this.sessionRepository = new SessionRepository(kernel.eventBus, kernel.ncpSessionManager);
|
|
6153
|
+
this.contextCompactionManager = new AgentRunContextCompactionManager(kernel.configManager, kernel.llmProviders, this.sessionRepository);
|
|
6154
|
+
this.sessionRunManager = new SessionRunManager$1(this.sessionRepository);
|
|
6155
|
+
this.agentRunRequestManager = new AgentRunRequestManager$1(this.agentRuntimeManager, kernel.configManager, this.contextProviderManager, kernel.eventBus, kernel.ingress, this.sessionRepository, this.sessionRunManager, this.toolProviderManager);
|
|
6156
|
+
this.contributions = [
|
|
6157
|
+
new ToolProviderContribution(kernel, this),
|
|
6158
|
+
new ContextProviderContribution(kernel, this),
|
|
6159
|
+
new ContextWindowContribution(kernel, this),
|
|
6160
|
+
new AgentRunRuntimeContribution(kernel, this)
|
|
6161
|
+
];
|
|
6162
|
+
}
|
|
6163
|
+
start = () => {
|
|
6164
|
+
if (this.started) return;
|
|
6165
|
+
this.started = true;
|
|
6166
|
+
this.sessionRepository.start();
|
|
6167
|
+
for (const contribution of this.contributions) contribution.start();
|
|
6168
|
+
this.agentRunRequestManager.start();
|
|
6169
|
+
};
|
|
6170
|
+
listSessionTypes = (params) => this.agentRuntimeManager.listSessionTypes(params);
|
|
6171
|
+
dispose = async () => {
|
|
6172
|
+
if (!this.started) return;
|
|
6173
|
+
for (const contribution of [...this.contributions].reverse()) await contribution.dispose?.();
|
|
6174
|
+
this.agentRunRequestManager.dispose();
|
|
6175
|
+
this.toolProviderManager.dispose();
|
|
6176
|
+
this.contextProviderManager.dispose();
|
|
6177
|
+
await this.agentRuntimeManager.dispose();
|
|
6178
|
+
this.sessionRunManager.dispose();
|
|
6179
|
+
this.sessionRepository.dispose();
|
|
6180
|
+
this.started = false;
|
|
6181
|
+
};
|
|
6182
|
+
};
|
|
6183
|
+
//#endregion
|
|
6184
|
+
//#region src/contributions/agent-runtime/index.ts
|
|
6185
|
+
var AgentRuntimeContribution = class {
|
|
6186
|
+
cleanups = [];
|
|
6187
|
+
constructor(kernel) {
|
|
6188
|
+
this.kernel = kernel;
|
|
6189
|
+
}
|
|
6190
|
+
start = () => {
|
|
6191
|
+
if (this.cleanups.length > 0) return;
|
|
6192
|
+
const nativeRuntimeFactory = new NativeAgentRuntimeFactory({
|
|
6193
|
+
providerManager: this.kernel.llmProviders,
|
|
6194
|
+
configManager: this.kernel.configManager,
|
|
6195
|
+
llmUsage: this.kernel.llmUsage,
|
|
6196
|
+
assetStore: this.kernel.assetStore,
|
|
6197
|
+
updateToolCallResult: this.kernel.sessionRunManager.updateToolCallResult,
|
|
6198
|
+
toolManager: this.kernel.toolManager
|
|
6199
|
+
});
|
|
6200
|
+
const builtinNarpRuntimeProviders = new BuiltinNarpRuntimeProviderService(this.kernel.configManager).createProviders();
|
|
6201
|
+
const nativeRegistration = this.kernel.agentRuntimeManager.registerRuntimeProvider({
|
|
6202
|
+
kind: "native",
|
|
6203
|
+
label: "Native",
|
|
6204
|
+
createRuntime: nativeRuntimeFactory.create
|
|
6205
|
+
});
|
|
6206
|
+
this.cleanups = [() => nativeRegistration.dispose(), ...builtinNarpRuntimeProviders.map((provider) => {
|
|
6207
|
+
const registration = this.kernel.agentRuntimeManager.registerRuntimeProvider(provider);
|
|
6208
|
+
return () => registration.dispose();
|
|
6209
|
+
})];
|
|
6210
|
+
};
|
|
6211
|
+
dispose = () => {
|
|
6212
|
+
for (const cleanup of this.cleanups) cleanup();
|
|
6213
|
+
this.cleanups = [];
|
|
6214
|
+
};
|
|
6215
|
+
};
|
|
6216
|
+
//#endregion
|
|
6217
|
+
//#region src/contributions/session-context-window/index.ts
|
|
6218
|
+
const STREAM_REFRESH_DELAY_MS = 1500;
|
|
6219
|
+
function formatBackgroundError(error) {
|
|
6220
|
+
if (error instanceof Error) return error.stack ?? error.message;
|
|
6221
|
+
return String(error);
|
|
6222
|
+
}
|
|
6223
|
+
var SessionContextWindowContribution = class {
|
|
6224
|
+
unsubscribeNcpEvent = null;
|
|
6225
|
+
stopped = true;
|
|
6226
|
+
pendingTimers = /* @__PURE__ */ new Map();
|
|
6227
|
+
lastPublishedSignatureBySession = /* @__PURE__ */ new Map();
|
|
6228
|
+
constructor(kernel) {
|
|
6229
|
+
this.kernel = kernel;
|
|
6230
|
+
}
|
|
6231
|
+
start = () => {
|
|
6232
|
+
if (this.unsubscribeNcpEvent) return;
|
|
6233
|
+
this.stopped = false;
|
|
6234
|
+
this.unsubscribeNcpEvent = this.kernel.eventBus.on(eventKeys.ncpEvent, this.handleNcpEvent);
|
|
6235
|
+
};
|
|
6236
|
+
dispose = () => {
|
|
6237
|
+
this.unsubscribeNcpEvent?.();
|
|
6238
|
+
this.unsubscribeNcpEvent = null;
|
|
6239
|
+
this.stopped = true;
|
|
6240
|
+
for (const timer of this.pendingTimers.values()) clearTimeout(timer);
|
|
6241
|
+
this.pendingTimers.clear();
|
|
6242
|
+
this.lastPublishedSignatureBySession.clear();
|
|
6243
|
+
};
|
|
6244
|
+
handleNcpEvent = (event) => {
|
|
6245
|
+
const sessionId = readContextWindowEventSessionId(event);
|
|
6246
|
+
if (!sessionId) return;
|
|
6247
|
+
if (event.type === NcpEventType.ContextWindowUpdated) {
|
|
6248
|
+
this.rememberPublishedContextWindow(sessionId, event.payload.contextWindow);
|
|
6249
|
+
return;
|
|
6250
|
+
}
|
|
6251
|
+
if (shouldRefreshContextWindowImmediately(event)) {
|
|
6252
|
+
this.refreshNow(sessionId);
|
|
6253
|
+
return;
|
|
6254
|
+
}
|
|
6255
|
+
if (shouldRefreshContextWindowDuringStream(event)) this.refreshSoon(sessionId);
|
|
6256
|
+
};
|
|
6257
|
+
refreshSoon = (sessionId) => {
|
|
6258
|
+
if (this.pendingTimers.has(sessionId)) return;
|
|
6259
|
+
const timer = setTimeout(() => {
|
|
6260
|
+
this.pendingTimers.delete(sessionId);
|
|
6261
|
+
this.refreshNow(sessionId);
|
|
6262
|
+
}, STREAM_REFRESH_DELAY_MS);
|
|
6263
|
+
this.pendingTimers.set(sessionId, timer);
|
|
6264
|
+
};
|
|
6265
|
+
refreshNow = (sessionId) => {
|
|
6266
|
+
const timer = this.pendingTimers.get(sessionId);
|
|
6267
|
+
if (timer) {
|
|
6268
|
+
clearTimeout(timer);
|
|
6269
|
+
this.pendingTimers.delete(sessionId);
|
|
6270
|
+
}
|
|
6271
|
+
this.publishContextWindow(sessionId).catch((error) => {
|
|
6272
|
+
console.error(`[session-context-window] failed to refresh ${sessionId}: ${formatBackgroundError(error)}`);
|
|
6273
|
+
});
|
|
6274
|
+
};
|
|
6275
|
+
publishContextWindow = async (sessionId) => {
|
|
6276
|
+
if (this.stopped) return;
|
|
6277
|
+
const contextWindow = await this.kernel.ncpSessionManager.getContextWindow(sessionId, this.kernel.sessionRunManager.getLiveSessionRecord(sessionId));
|
|
6278
|
+
if (!isContextWindowSnapshot(contextWindow) || this.stopped) return;
|
|
6279
|
+
const signature = createContextWindowSignature(contextWindow);
|
|
6280
|
+
if (this.lastPublishedSignatureBySession.get(sessionId) === signature) return;
|
|
6281
|
+
this.lastPublishedSignatureBySession.set(sessionId, signature);
|
|
6282
|
+
this.kernel.eventBus.emit(eventKeys.ncpEvent, {
|
|
6283
|
+
type: NcpEventType.ContextWindowUpdated,
|
|
6284
|
+
payload: {
|
|
6285
|
+
sessionId,
|
|
6286
|
+
contextWindow
|
|
6287
|
+
}
|
|
6288
|
+
}, {
|
|
6289
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6290
|
+
source: "session-context-window"
|
|
6291
|
+
});
|
|
6292
|
+
};
|
|
6293
|
+
rememberPublishedContextWindow = (sessionId, contextWindow) => {
|
|
6294
|
+
this.lastPublishedSignatureBySession.set(sessionId, createContextWindowSignature(contextWindow));
|
|
6295
|
+
};
|
|
6296
|
+
};
|
|
6297
|
+
//#endregion
|
|
6298
|
+
//#region src/contributions/legacy-agent-run/index.ts
|
|
6299
|
+
var LegacyAgentRunContribution = class {
|
|
6300
|
+
contributions;
|
|
6301
|
+
started = false;
|
|
5389
6302
|
constructor(kernel) {
|
|
5390
6303
|
this.kernel = kernel;
|
|
6304
|
+
this.contributions = [new AgentRuntimeContribution(kernel), new SessionContextWindowContribution(kernel)];
|
|
5391
6305
|
}
|
|
5392
6306
|
start = () => {
|
|
5393
|
-
if (this.
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
llmUsage: this.kernel.llmUsage,
|
|
5398
|
-
assetStore: this.kernel.assetStore,
|
|
5399
|
-
updateToolCallResult: this.kernel.sessionRunManager.updateToolCallResult,
|
|
5400
|
-
toolManager: this.kernel.toolManager
|
|
5401
|
-
});
|
|
5402
|
-
const builtinNarpRuntimeProviders = new BuiltinNarpRuntimeProviderService(this.kernel.configManager).createProviders();
|
|
5403
|
-
const nativeRegistration = this.kernel.agentRuntimeManager.registerRuntimeProvider({
|
|
5404
|
-
kind: "native",
|
|
5405
|
-
label: "Native",
|
|
5406
|
-
createRuntime: nativeRuntimeFactory.create
|
|
5407
|
-
});
|
|
5408
|
-
this.cleanups = [() => nativeRegistration.dispose(), ...builtinNarpRuntimeProviders.map((provider) => {
|
|
5409
|
-
const registration = this.kernel.agentRuntimeManager.registerRuntimeProvider(provider);
|
|
5410
|
-
return () => registration.dispose();
|
|
5411
|
-
})];
|
|
6307
|
+
if (this.started) return;
|
|
6308
|
+
this.started = true;
|
|
6309
|
+
for (const contribution of this.contributions) contribution.start();
|
|
6310
|
+
this.kernel.agentRunRequestManager.start();
|
|
5412
6311
|
};
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
this.
|
|
6312
|
+
listSessionTypes = (params) => this.kernel.agentRuntimeManager.listSessionTypes(params);
|
|
6313
|
+
dispose = async () => {
|
|
6314
|
+
if (!this.started) return;
|
|
6315
|
+
await this.kernel.agentRunRequestManager.dispose();
|
|
6316
|
+
await this.kernel.sessionRunManager.dispose();
|
|
6317
|
+
for (const contribution of [...this.contributions].reverse()) await contribution.dispose();
|
|
6318
|
+
this.started = false;
|
|
5416
6319
|
};
|
|
5417
6320
|
};
|
|
5418
6321
|
//#endregion
|
|
@@ -5566,125 +6469,6 @@ var LearningLoopContribution = class {
|
|
|
5566
6469
|
};
|
|
5567
6470
|
};
|
|
5568
6471
|
//#endregion
|
|
5569
|
-
//#region src/contributions/session-context-window/index.ts
|
|
5570
|
-
const STREAM_REFRESH_DELAY_MS = 1500;
|
|
5571
|
-
function formatBackgroundError(error) {
|
|
5572
|
-
if (error instanceof Error) return error.stack ?? error.message;
|
|
5573
|
-
return String(error);
|
|
5574
|
-
}
|
|
5575
|
-
function readEventSessionId(event) {
|
|
5576
|
-
const payload = "payload" in event ? event.payload : null;
|
|
5577
|
-
if (!payload || typeof payload !== "object") return null;
|
|
5578
|
-
return "sessionId" in payload && typeof payload.sessionId === "string" ? payload.sessionId.trim() || null : null;
|
|
5579
|
-
}
|
|
5580
|
-
function isContextWindow(value) {
|
|
5581
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5582
|
-
}
|
|
5583
|
-
function createSignature(value) {
|
|
5584
|
-
return JSON.stringify(value);
|
|
5585
|
-
}
|
|
5586
|
-
function shouldRefreshDuringStream(event) {
|
|
5587
|
-
switch (event.type) {
|
|
5588
|
-
case NcpEventType.MessageTextStart:
|
|
5589
|
-
case NcpEventType.MessageTextDelta:
|
|
5590
|
-
case NcpEventType.MessageTextEnd:
|
|
5591
|
-
case NcpEventType.MessageReasoningStart:
|
|
5592
|
-
case NcpEventType.MessageReasoningDelta:
|
|
5593
|
-
case NcpEventType.MessageReasoningEnd:
|
|
5594
|
-
case NcpEventType.MessageToolCallStart:
|
|
5595
|
-
case NcpEventType.MessageToolCallArgs:
|
|
5596
|
-
case NcpEventType.MessageToolCallArgsDelta:
|
|
5597
|
-
case NcpEventType.MessageToolCallEnd:
|
|
5598
|
-
case NcpEventType.MessageToolCallResult: return true;
|
|
5599
|
-
default: return false;
|
|
5600
|
-
}
|
|
5601
|
-
}
|
|
5602
|
-
function shouldRefreshImmediately(event) {
|
|
5603
|
-
switch (event.type) {
|
|
5604
|
-
case NcpEventType.MessageSent:
|
|
5605
|
-
case NcpEventType.MessageCompleted:
|
|
5606
|
-
case NcpEventType.MessageFailed:
|
|
5607
|
-
case NcpEventType.MessageAbort:
|
|
5608
|
-
case NcpEventType.RunFinished:
|
|
5609
|
-
case NcpEventType.RunError: return true;
|
|
5610
|
-
default: return false;
|
|
5611
|
-
}
|
|
5612
|
-
}
|
|
5613
|
-
var SessionContextWindowContribution = class {
|
|
5614
|
-
unsubscribeNcpEvent = null;
|
|
5615
|
-
stopped = true;
|
|
5616
|
-
pendingTimers = /* @__PURE__ */ new Map();
|
|
5617
|
-
lastPublishedSignatureBySession = /* @__PURE__ */ new Map();
|
|
5618
|
-
constructor(kernel) {
|
|
5619
|
-
this.kernel = kernel;
|
|
5620
|
-
}
|
|
5621
|
-
start = () => {
|
|
5622
|
-
if (this.unsubscribeNcpEvent) return;
|
|
5623
|
-
this.stopped = false;
|
|
5624
|
-
this.unsubscribeNcpEvent = this.kernel.eventBus.on(eventKeys.ncpEvent, this.handleNcpEvent);
|
|
5625
|
-
};
|
|
5626
|
-
dispose = () => {
|
|
5627
|
-
this.unsubscribeNcpEvent?.();
|
|
5628
|
-
this.unsubscribeNcpEvent = null;
|
|
5629
|
-
this.stopped = true;
|
|
5630
|
-
for (const timer of this.pendingTimers.values()) clearTimeout(timer);
|
|
5631
|
-
this.pendingTimers.clear();
|
|
5632
|
-
this.lastPublishedSignatureBySession.clear();
|
|
5633
|
-
};
|
|
5634
|
-
handleNcpEvent = (event) => {
|
|
5635
|
-
const sessionId = readEventSessionId(event);
|
|
5636
|
-
if (!sessionId) return;
|
|
5637
|
-
if (event.type === NcpEventType.ContextWindowUpdated) {
|
|
5638
|
-
this.rememberPublishedContextWindow(sessionId, event.payload.contextWindow);
|
|
5639
|
-
return;
|
|
5640
|
-
}
|
|
5641
|
-
if (shouldRefreshImmediately(event)) {
|
|
5642
|
-
this.refreshNow(sessionId);
|
|
5643
|
-
return;
|
|
5644
|
-
}
|
|
5645
|
-
if (shouldRefreshDuringStream(event)) this.refreshSoon(sessionId);
|
|
5646
|
-
};
|
|
5647
|
-
refreshSoon = (sessionId) => {
|
|
5648
|
-
if (this.pendingTimers.has(sessionId)) return;
|
|
5649
|
-
const timer = setTimeout(() => {
|
|
5650
|
-
this.pendingTimers.delete(sessionId);
|
|
5651
|
-
this.refreshNow(sessionId);
|
|
5652
|
-
}, STREAM_REFRESH_DELAY_MS);
|
|
5653
|
-
this.pendingTimers.set(sessionId, timer);
|
|
5654
|
-
};
|
|
5655
|
-
refreshNow = (sessionId) => {
|
|
5656
|
-
const timer = this.pendingTimers.get(sessionId);
|
|
5657
|
-
if (timer) {
|
|
5658
|
-
clearTimeout(timer);
|
|
5659
|
-
this.pendingTimers.delete(sessionId);
|
|
5660
|
-
}
|
|
5661
|
-
this.publishContextWindow(sessionId).catch((error) => {
|
|
5662
|
-
console.error(`[session-context-window] failed to refresh ${sessionId}: ${formatBackgroundError(error)}`);
|
|
5663
|
-
});
|
|
5664
|
-
};
|
|
5665
|
-
publishContextWindow = async (sessionId) => {
|
|
5666
|
-
if (this.stopped) return;
|
|
5667
|
-
const contextWindow = await this.kernel.ncpSessionManager.getContextWindow(sessionId, this.kernel.sessionRunManager.getLiveSessionRecord(sessionId));
|
|
5668
|
-
if (!isContextWindow(contextWindow) || this.stopped) return;
|
|
5669
|
-
const signature = createSignature(contextWindow);
|
|
5670
|
-
if (this.lastPublishedSignatureBySession.get(sessionId) === signature) return;
|
|
5671
|
-
this.lastPublishedSignatureBySession.set(sessionId, signature);
|
|
5672
|
-
this.kernel.eventBus.emit(eventKeys.ncpEvent, {
|
|
5673
|
-
type: NcpEventType.ContextWindowUpdated,
|
|
5674
|
-
payload: {
|
|
5675
|
-
sessionId,
|
|
5676
|
-
contextWindow
|
|
5677
|
-
}
|
|
5678
|
-
}, {
|
|
5679
|
-
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5680
|
-
source: "session-context-window"
|
|
5681
|
-
});
|
|
5682
|
-
};
|
|
5683
|
-
rememberPublishedContextWindow = (sessionId, contextWindow) => {
|
|
5684
|
-
this.lastPublishedSignatureBySession.set(sessionId, createSignature(contextWindow));
|
|
5685
|
-
};
|
|
5686
|
-
};
|
|
5687
|
-
//#endregion
|
|
5688
6472
|
//#region src/contributions/session-activity-preview/utils/session-activity-preview-ncp-event.utils.ts
|
|
5689
6473
|
const PREVIEW_TEXT_MAX_LENGTH = 160;
|
|
5690
6474
|
function readSessionId(value) {
|
|
@@ -6140,7 +6924,7 @@ var SessionSearchTool = class {
|
|
|
6140
6924
|
}
|
|
6141
6925
|
validateArgs = (args) => {
|
|
6142
6926
|
const issues = [];
|
|
6143
|
-
const query = normalizeString(args.query);
|
|
6927
|
+
const query = normalizeString$1(args.query);
|
|
6144
6928
|
const limit = readOptionalInteger(args.limit);
|
|
6145
6929
|
const includeCurrentSession = readOptionalBoolean(args.includeCurrentSession);
|
|
6146
6930
|
if (!query) issues.push("query must be a non-empty string.");
|
|
@@ -6154,7 +6938,7 @@ var SessionSearchTool = class {
|
|
|
6154
6938
|
const issues = this.validateArgs(args);
|
|
6155
6939
|
if (issues.length > 0) throw new Error(issues.join(" "));
|
|
6156
6940
|
return this.queryService.search({
|
|
6157
|
-
query: normalizeString(args.query) ?? "",
|
|
6941
|
+
query: normalizeString$1(args.query) ?? "",
|
|
6158
6942
|
limit: readOptionalInteger(args.limit),
|
|
6159
6943
|
includeCurrentSession: readOptionalBoolean(args.includeCurrentSession),
|
|
6160
6944
|
currentSessionId: this.context.currentSessionId
|
|
@@ -6297,7 +7081,7 @@ var SessionSpawnTool = class extends Tool {
|
|
|
6297
7081
|
function readMetadataAccountId(metadata) {
|
|
6298
7082
|
const candidates = [metadata.accountId, metadata.account_id];
|
|
6299
7083
|
for (const candidate of candidates) {
|
|
6300
|
-
const normalized = normalizeString(candidate);
|
|
7084
|
+
const normalized = normalizeString$1(candidate);
|
|
6301
7085
|
if (normalized) return normalized;
|
|
6302
7086
|
}
|
|
6303
7087
|
}
|
|
@@ -6408,6 +7192,7 @@ var ToolContribution = class {
|
|
|
6408
7192
|
};
|
|
6409
7193
|
//#endregion
|
|
6410
7194
|
//#region src/app/nextclaw-kernel.ts
|
|
7195
|
+
const AGENT_RUN_CHAIN = "branch";
|
|
6411
7196
|
function resolveKernelSessionsDir(options) {
|
|
6412
7197
|
const homeDir = options.homeDir?.trim();
|
|
6413
7198
|
if (homeDir) return ensureDir(resolve(expandHome(homeDir), "sessions"));
|
|
@@ -6452,6 +7237,7 @@ var NextclawKernel = class {
|
|
|
6452
7237
|
sessionRunManager;
|
|
6453
7238
|
agentRuntimeManager;
|
|
6454
7239
|
ncpAgentSessionJournalStore;
|
|
7240
|
+
agentRunContribution;
|
|
6455
7241
|
contributions;
|
|
6456
7242
|
gatewayController;
|
|
6457
7243
|
constructor(options = {}) {
|
|
@@ -6480,7 +7266,8 @@ var NextclawKernel = class {
|
|
|
6480
7266
|
configManager: this.configManager,
|
|
6481
7267
|
eventBus: this.eventBus,
|
|
6482
7268
|
ingress: this.ingress,
|
|
6483
|
-
messageBus: this.messageBus
|
|
7269
|
+
messageBus: this.messageBus,
|
|
7270
|
+
sessionManager: this.sessions
|
|
6484
7271
|
});
|
|
6485
7272
|
this.skills = new SkillManager({ workspace: getWorkspacePath(this.configManager.config.agents.defaults.workspace) });
|
|
6486
7273
|
this.mcpManager = new McpManager(this.configManager.loadConfig);
|
|
@@ -6521,14 +7308,15 @@ var NextclawKernel = class {
|
|
|
6521
7308
|
ncpSessionManager: this.ncpSessionManager,
|
|
6522
7309
|
sessionRunManager: this.sessionRunManager
|
|
6523
7310
|
});
|
|
7311
|
+
this.agentRunContribution = AGENT_RUN_CHAIN === "branch" ? new KernelBranch(this) : new LegacyAgentRunContribution(this);
|
|
6524
7312
|
this.contributions = [
|
|
6525
|
-
new AgentRuntimeContribution(this),
|
|
6526
7313
|
new ToolContribution(this),
|
|
6527
7314
|
new SessionActivityPreviewContribution(this),
|
|
6528
|
-
new
|
|
6529
|
-
|
|
7315
|
+
new LearningLoopContribution(this),
|
|
7316
|
+
this.agentRunContribution
|
|
6530
7317
|
];
|
|
6531
7318
|
}
|
|
7319
|
+
listSessionTypes = (params) => this.agentRunContribution.listSessionTypes(params);
|
|
6532
7320
|
provideGatewayController = (gatewayController) => {
|
|
6533
7321
|
this.gatewayController = gatewayController;
|
|
6534
7322
|
};
|
|
@@ -6537,13 +7325,10 @@ var NextclawKernel = class {
|
|
|
6537
7325
|
this.sessionSearch.start();
|
|
6538
7326
|
this.mcpManager.start();
|
|
6539
7327
|
for (const contribution of this.contributions) contribution.start();
|
|
6540
|
-
this.agentRunRequestManager.start();
|
|
6541
7328
|
};
|
|
6542
7329
|
dispose = async () => {
|
|
6543
|
-
|
|
6544
|
-
await this.sessionRunManager.dispose();
|
|
7330
|
+
for (const contribution of [...this.contributions].reverse()) await contribution.dispose();
|
|
6545
7331
|
this.ncpSessionManager.dispose();
|
|
6546
|
-
for (const contribution of this.contributions) contribution.dispose();
|
|
6547
7332
|
await this.agentRuntimeManager.dispose();
|
|
6548
7333
|
await this.mcpManager.dispose();
|
|
6549
7334
|
await this.sessionSearch.dispose();
|
|
@@ -6597,7 +7382,7 @@ async function createFilePartFromLocalPath(attachment, localPath, assetApi) {
|
|
|
6597
7382
|
const bytes = await readFile(localPath);
|
|
6598
7383
|
return {
|
|
6599
7384
|
type: "file",
|
|
6600
|
-
assetUri: (await assetApi.
|
|
7385
|
+
assetUri: (await assetApi.putBytes({
|
|
6601
7386
|
fileName,
|
|
6602
7387
|
mimeType: attachment.mimeType ?? null,
|
|
6603
7388
|
bytes
|
|
@@ -6626,16 +7411,11 @@ async function buildUserMessageParts(params) {
|
|
|
6626
7411
|
for (const attachment of attachments ?? []) parts.push(await attachmentToPart(attachment, assetApi));
|
|
6627
7412
|
return parts;
|
|
6628
7413
|
}
|
|
6629
|
-
async function
|
|
7414
|
+
async function buildAgentRunSendPayload(params) {
|
|
6630
7415
|
const { assetApi, attachments, content, metadata, sessionId } = params;
|
|
6631
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
6632
7416
|
return {
|
|
6633
|
-
id: `${sessionId}:user:${timestamp}`,
|
|
6634
7417
|
sessionId,
|
|
6635
|
-
|
|
6636
|
-
status: "final",
|
|
6637
|
-
timestamp,
|
|
6638
|
-
parts: await buildUserMessageParts({
|
|
7418
|
+
content: await buildUserMessageParts({
|
|
6639
7419
|
content,
|
|
6640
7420
|
attachments,
|
|
6641
7421
|
assetApi
|
|
@@ -6643,41 +7423,208 @@ async function buildNcpUserMessage(params) {
|
|
|
6643
7423
|
metadata: structuredClone(metadata ?? {})
|
|
6644
7424
|
};
|
|
6645
7425
|
}
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
const
|
|
6649
|
-
|
|
6650
|
-
content,
|
|
6651
|
-
attachments,
|
|
6652
|
-
metadata,
|
|
6653
|
-
assetApi: agent.assetApi
|
|
6654
|
-
});
|
|
6655
|
-
for await (const event of agent.run({
|
|
6656
|
-
sessionId,
|
|
6657
|
-
message,
|
|
6658
|
-
metadata
|
|
6659
|
-
}, { ...abortSignal ? { signal: abortSignal } : {} })) {
|
|
6660
|
-
onEvent?.(event);
|
|
6661
|
-
yield event;
|
|
6662
|
-
}
|
|
7426
|
+
function readEventCorrelationId(event) {
|
|
7427
|
+
if (!("payload" in event)) return;
|
|
7428
|
+
const correlationId = "correlationId" in event.payload ? event.payload.correlationId : void 0;
|
|
7429
|
+
return typeof correlationId === "string" && correlationId.length > 0 ? correlationId : void 0;
|
|
6663
7430
|
}
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
7431
|
+
function readEventSessionId(event) {
|
|
7432
|
+
if (!("payload" in event)) return;
|
|
7433
|
+
const sessionId = "sessionId" in event.payload ? event.payload.sessionId : void 0;
|
|
7434
|
+
return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
|
|
7435
|
+
}
|
|
7436
|
+
function readEventRunId(event) {
|
|
7437
|
+
if (!("payload" in event)) return;
|
|
7438
|
+
const runId = "runId" in event.payload ? event.payload.runId : void 0;
|
|
7439
|
+
return typeof runId === "string" && runId.length > 0 ? runId : void 0;
|
|
7440
|
+
}
|
|
7441
|
+
function isTerminalEvent(event) {
|
|
7442
|
+
return event.type === NcpEventType.MessageFailed || event.type === NcpEventType.RunError || event.type === NcpEventType.RunFinished;
|
|
7443
|
+
}
|
|
7444
|
+
function isRunEventMatch(params) {
|
|
7445
|
+
const eventCorrelationId = readEventCorrelationId(params.event);
|
|
7446
|
+
if (eventCorrelationId) return eventCorrelationId === params.correlationId;
|
|
7447
|
+
if (!params.sessionId || !params.runId) return false;
|
|
7448
|
+
return readEventSessionId(params.event) === params.sessionId && readEventRunId(params.event) === params.runId;
|
|
7449
|
+
}
|
|
7450
|
+
var AsyncEventQueue = class {
|
|
7451
|
+
values = [];
|
|
7452
|
+
waiters = [];
|
|
7453
|
+
closed = false;
|
|
7454
|
+
failure;
|
|
7455
|
+
hasFailure = false;
|
|
7456
|
+
push = (value) => {
|
|
7457
|
+
if (this.closed || this.hasFailure) return;
|
|
7458
|
+
const waiter = this.waiters.shift();
|
|
7459
|
+
if (waiter) {
|
|
7460
|
+
waiter({
|
|
7461
|
+
done: false,
|
|
7462
|
+
value
|
|
7463
|
+
});
|
|
7464
|
+
return;
|
|
7465
|
+
}
|
|
7466
|
+
this.values.push(value);
|
|
7467
|
+
};
|
|
7468
|
+
close = () => {
|
|
7469
|
+
if (this.closed) return;
|
|
7470
|
+
this.closed = true;
|
|
7471
|
+
while (this.waiters.length > 0) this.waiters.shift()?.({
|
|
7472
|
+
done: true,
|
|
7473
|
+
value: void 0
|
|
7474
|
+
});
|
|
7475
|
+
};
|
|
7476
|
+
fail = (error) => {
|
|
7477
|
+
if (this.closed || this.hasFailure) return;
|
|
7478
|
+
this.hasFailure = true;
|
|
7479
|
+
this.failure = error;
|
|
7480
|
+
while (this.waiters.length > 0) this.waiters.shift()?.({
|
|
7481
|
+
done: true,
|
|
7482
|
+
value: void 0
|
|
7483
|
+
});
|
|
7484
|
+
};
|
|
7485
|
+
next = async () => {
|
|
7486
|
+
if (this.values.length > 0) return {
|
|
7487
|
+
done: false,
|
|
7488
|
+
value: this.values.shift()
|
|
7489
|
+
};
|
|
7490
|
+
if (this.hasFailure) throw this.failure;
|
|
7491
|
+
if (this.closed) return {
|
|
7492
|
+
done: true,
|
|
7493
|
+
value: void 0
|
|
7494
|
+
};
|
|
7495
|
+
return await new Promise((resolve) => {
|
|
7496
|
+
this.waiters.push(resolve);
|
|
7497
|
+
});
|
|
7498
|
+
};
|
|
7499
|
+
[Symbol.asyncIterator] = () => ({ next: this.next });
|
|
7500
|
+
};
|
|
7501
|
+
var AgentRunObserver = class {
|
|
7502
|
+
queue = new AsyncEventQueue();
|
|
7503
|
+
unsubscribe;
|
|
7504
|
+
abortCleanup;
|
|
7505
|
+
completedMessage;
|
|
7506
|
+
disposed = false;
|
|
7507
|
+
runId;
|
|
7508
|
+
sessionId;
|
|
7509
|
+
constructor(options) {
|
|
7510
|
+
this.options = options;
|
|
7511
|
+
this.unsubscribe = options.eventBus.on(eventKeys.ncpEvent, this.handleEvent);
|
|
7512
|
+
}
|
|
7513
|
+
attachHandle = (handle) => {
|
|
7514
|
+
this.sessionId = handle.sessionId;
|
|
7515
|
+
this.runId = handle.runId ?? void 0;
|
|
7516
|
+
const { abortSignal } = this.options;
|
|
7517
|
+
if (!abortSignal) return;
|
|
7518
|
+
const abort = () => {
|
|
7519
|
+
this.options.ingress.handle({
|
|
7520
|
+
type: ingressKeys.agentRun.abort,
|
|
7521
|
+
payload: {
|
|
7522
|
+
sessionId: handle.sessionId,
|
|
7523
|
+
correlationId: this.options.correlationId
|
|
7524
|
+
}
|
|
7525
|
+
}, { source: "agent-run-client" });
|
|
7526
|
+
};
|
|
7527
|
+
if (abortSignal.aborted) {
|
|
7528
|
+
abort();
|
|
7529
|
+
return;
|
|
7530
|
+
}
|
|
7531
|
+
abortSignal.addEventListener("abort", abort, { once: true });
|
|
7532
|
+
this.abortCleanup = () => abortSignal.removeEventListener("abort", abort);
|
|
7533
|
+
};
|
|
7534
|
+
stream = async function* () {
|
|
7535
|
+
for await (const event of this.queue) yield event;
|
|
7536
|
+
};
|
|
7537
|
+
waitForReply = async (options = {}) => {
|
|
7538
|
+
for await (const event of this.queue) {
|
|
7539
|
+
if (event.type === NcpEventType.MessageTextDelta) {
|
|
7540
|
+
options.onAssistantDelta?.(event.payload.delta);
|
|
7541
|
+
continue;
|
|
7542
|
+
}
|
|
7543
|
+
if (event.type === NcpEventType.MessageCompleted) {
|
|
7544
|
+
this.completedMessage = event.payload.message;
|
|
7545
|
+
continue;
|
|
7546
|
+
}
|
|
7547
|
+
if (event.type === NcpEventType.MessageFailed) throw new Error(event.payload.error.message);
|
|
7548
|
+
if (event.type === NcpEventType.RunError) throw new Error(event.payload.error ?? options.runErrorMessage ?? "NCP run failed.");
|
|
7549
|
+
if (event.type === NcpEventType.RunFinished) {
|
|
7550
|
+
if (!this.completedMessage) throw new Error(options.missingCompletedMessageError ?? "NCP run completed without a final assistant message.");
|
|
7551
|
+
return this.completedMessage;
|
|
7552
|
+
}
|
|
6670
7553
|
}
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
7554
|
+
throw new Error(options.missingCompletedMessageError ?? "NCP run completed without a final assistant message.");
|
|
7555
|
+
};
|
|
7556
|
+
dispose = () => {
|
|
7557
|
+
if (this.disposed) return;
|
|
7558
|
+
this.disposed = true;
|
|
7559
|
+
this.abortCleanup?.();
|
|
7560
|
+
this.unsubscribe();
|
|
7561
|
+
this.queue.close();
|
|
7562
|
+
};
|
|
7563
|
+
handleEvent = (event) => {
|
|
7564
|
+
if (this.disposed || !isRunEventMatch({
|
|
7565
|
+
correlationId: this.options.correlationId,
|
|
7566
|
+
event,
|
|
7567
|
+
runId: this.runId,
|
|
7568
|
+
sessionId: this.sessionId
|
|
7569
|
+
})) return;
|
|
7570
|
+
this.options.onEvent?.(event);
|
|
7571
|
+
this.queue.push(event);
|
|
7572
|
+
if (isTerminalEvent(event)) this.queue.close();
|
|
7573
|
+
};
|
|
7574
|
+
};
|
|
7575
|
+
var AgentRunClient = class {
|
|
7576
|
+
constructor(options) {
|
|
7577
|
+
this.options = options;
|
|
6674
7578
|
}
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
text: extractTextFromNcpMessage(completedMessage),
|
|
6678
|
-
completedMessage
|
|
7579
|
+
send = async (input) => {
|
|
7580
|
+
return await this.sendWithCorrelation(input, randomUUID());
|
|
6679
7581
|
};
|
|
6680
|
-
}
|
|
7582
|
+
sendAndWaitForReply = async (input, options = {}) => {
|
|
7583
|
+
const correlationId = randomUUID();
|
|
7584
|
+
const observer = this.prepareObserver(correlationId, options);
|
|
7585
|
+
try {
|
|
7586
|
+
const handle = await this.sendWithCorrelation(input, correlationId);
|
|
7587
|
+
observer.attachHandle(handle);
|
|
7588
|
+
const completedMessage = await observer.waitForReply(options);
|
|
7589
|
+
return {
|
|
7590
|
+
handle,
|
|
7591
|
+
completedMessage,
|
|
7592
|
+
text: extractTextFromNcpMessage(completedMessage)
|
|
7593
|
+
};
|
|
7594
|
+
} finally {
|
|
7595
|
+
observer.dispose();
|
|
7596
|
+
}
|
|
7597
|
+
};
|
|
7598
|
+
sendAndStreamEvents = async function* (input, options = {}) {
|
|
7599
|
+
const correlationId = randomUUID();
|
|
7600
|
+
const observer = this.prepareObserver(correlationId, options);
|
|
7601
|
+
try {
|
|
7602
|
+
const handle = await this.sendWithCorrelation(input, correlationId);
|
|
7603
|
+
observer.attachHandle(handle);
|
|
7604
|
+
for await (const event of observer.stream()) yield event;
|
|
7605
|
+
} finally {
|
|
7606
|
+
observer.dispose();
|
|
7607
|
+
}
|
|
7608
|
+
};
|
|
7609
|
+
prepareObserver = (correlationId, options) => {
|
|
7610
|
+
return new AgentRunObserver({
|
|
7611
|
+
abortSignal: options.abortSignal,
|
|
7612
|
+
correlationId,
|
|
7613
|
+
eventBus: this.options.eventBus,
|
|
7614
|
+
ingress: this.options.ingress,
|
|
7615
|
+
onEvent: options.onEvent
|
|
7616
|
+
});
|
|
7617
|
+
};
|
|
7618
|
+
sendWithCorrelation = async (input, correlationId) => {
|
|
7619
|
+
return await this.options.ingress.handle({
|
|
7620
|
+
type: ingressKeys.agentRun.send,
|
|
7621
|
+
payload: {
|
|
7622
|
+
...input,
|
|
7623
|
+
correlationId
|
|
7624
|
+
}
|
|
7625
|
+
}, { source: "agent-run-client" });
|
|
7626
|
+
};
|
|
7627
|
+
};
|
|
6681
7628
|
//#endregion
|
|
6682
7629
|
//#region src/features/ncp-dispatch/utils/channel-reply.utils.ts
|
|
6683
7630
|
function readString(value) {
|
|
@@ -6702,18 +7649,19 @@ function resolveChannelReplyRoute(params) {
|
|
|
6702
7649
|
};
|
|
6703
7650
|
}
|
|
6704
7651
|
async function dispatchChannelReplyRoute(params) {
|
|
6705
|
-
const { abortSignal,
|
|
7652
|
+
const { abortSignal, agentRunClient, assetApi, attachments, content, metadata, onEvent, route, sessionId } = params;
|
|
6706
7653
|
const input = {
|
|
6707
7654
|
target: {
|
|
6708
7655
|
...route.target,
|
|
6709
|
-
...
|
|
7656
|
+
...assetApi?.resolveContentPath ? { resolveAssetContentPath: assetApi.resolveContentPath } : {}
|
|
6710
7657
|
},
|
|
6711
|
-
eventStream:
|
|
6712
|
-
agent,
|
|
7658
|
+
eventStream: agentRunClient.sendAndStreamEvents(await buildAgentRunSendPayload({
|
|
6713
7659
|
sessionId,
|
|
6714
7660
|
content,
|
|
6715
7661
|
attachments,
|
|
6716
7662
|
metadata,
|
|
7663
|
+
assetApi
|
|
7664
|
+
}), {
|
|
6717
7665
|
abortSignal,
|
|
6718
7666
|
onEvent
|
|
6719
7667
|
})
|
|
@@ -6722,22 +7670,35 @@ async function dispatchChannelReplyRoute(params) {
|
|
|
6722
7670
|
}
|
|
6723
7671
|
//#endregion
|
|
6724
7672
|
//#region src/features/ncp-dispatch/utils/ncp-run-metadata.utils.ts
|
|
7673
|
+
const LEGACY_RUN_METADATA_KEYS = [
|
|
7674
|
+
"account_id",
|
|
7675
|
+
"agent_id",
|
|
7676
|
+
"chat_id",
|
|
7677
|
+
"preferred_model",
|
|
7678
|
+
"project_root",
|
|
7679
|
+
"runtime",
|
|
7680
|
+
"sender_id",
|
|
7681
|
+
"session_key",
|
|
7682
|
+
"session_type"
|
|
7683
|
+
];
|
|
7684
|
+
function stripLegacyRunMetadata(metadata) {
|
|
7685
|
+
const nextMetadata = structuredClone(metadata);
|
|
7686
|
+
for (const key of LEGACY_RUN_METADATA_KEYS) delete nextMetadata[key];
|
|
7687
|
+
return nextMetadata;
|
|
7688
|
+
}
|
|
6725
7689
|
function buildRunMetadata(params) {
|
|
6726
7690
|
const { message, metadata, route } = params;
|
|
6727
7691
|
return {
|
|
6728
|
-
...
|
|
6729
|
-
|
|
7692
|
+
...stripLegacyRunMetadata({
|
|
7693
|
+
...message.metadata ?? {},
|
|
7694
|
+
...metadata ?? {}
|
|
7695
|
+
}),
|
|
6730
7696
|
channel: message.channel,
|
|
6731
7697
|
chatId: message.chatId,
|
|
6732
|
-
chat_id: message.chatId,
|
|
6733
7698
|
accountId: route.accountId,
|
|
6734
|
-
account_id: route.accountId,
|
|
6735
7699
|
agentId: route.agentId,
|
|
6736
|
-
agent_id: route.agentId,
|
|
6737
7700
|
sessionKey: route.sessionKey,
|
|
6738
|
-
|
|
6739
|
-
senderId: message.senderId,
|
|
6740
|
-
sender_id: message.senderId
|
|
7701
|
+
senderId: message.senderId
|
|
6741
7702
|
};
|
|
6742
7703
|
}
|
|
6743
7704
|
//#endregion
|
|
@@ -6758,14 +7719,16 @@ var GatewayInboundProcessor = class {
|
|
|
6758
7719
|
message,
|
|
6759
7720
|
route
|
|
6760
7721
|
});
|
|
7722
|
+
if (await this.dispatchSlashCommandMaybe(message, route, runMetadata)) return;
|
|
6761
7723
|
if (await this.dispatchChannelReplyRouteMaybe(message, route, runMetadata)) return;
|
|
6762
7724
|
if (message.channel !== "system") await this.runtime.messageBus.publishOutbound(createAssistantStreamResetControlMessage(message));
|
|
6763
|
-
const result = await
|
|
6764
|
-
agent: this.runtime.kernel.agentRunRequestManager,
|
|
7725
|
+
const result = await this.runtime.agentRunClient.sendAndWaitForReply(await buildAgentRunSendPayload({
|
|
6765
7726
|
sessionId: route.sessionKey,
|
|
6766
7727
|
content: message.content,
|
|
6767
7728
|
attachments: message.attachments,
|
|
6768
7729
|
metadata: runMetadata,
|
|
7730
|
+
assetApi: this.runtime.kernel.assetStore
|
|
7731
|
+
}), {
|
|
6769
7732
|
onAssistantDelta: message.channel !== "system" ? (delta) => {
|
|
6770
7733
|
if (!delta) return;
|
|
6771
7734
|
this.runtime.messageBus.publishOutbound(createAssistantStreamDeltaControlMessage(message, delta));
|
|
@@ -6792,6 +7755,26 @@ var GatewayInboundProcessor = class {
|
|
|
6792
7755
|
sessionKeyOverride: normalize(message.metadata.session_key_override)
|
|
6793
7756
|
});
|
|
6794
7757
|
};
|
|
7758
|
+
dispatchSlashCommandMaybe = async (message, route, runMetadata) => {
|
|
7759
|
+
if (message.channel === "system") return false;
|
|
7760
|
+
const trimmed = message.content.trim();
|
|
7761
|
+
if (!trimmed.startsWith("/")) return false;
|
|
7762
|
+
const result = await new CommandRegistry(this.runtime.configManager.loadConfig(), this.runtime.sessionManager).executeText(trimmed, {
|
|
7763
|
+
channel: message.channel,
|
|
7764
|
+
chatId: message.chatId,
|
|
7765
|
+
senderId: message.senderId,
|
|
7766
|
+
sessionKey: route.sessionKey
|
|
7767
|
+
});
|
|
7768
|
+
if (!result) return false;
|
|
7769
|
+
await this.runtime.messageBus.publishOutbound({
|
|
7770
|
+
channel: message.channel,
|
|
7771
|
+
chatId: message.chatId,
|
|
7772
|
+
content: result.content,
|
|
7773
|
+
media: [],
|
|
7774
|
+
metadata: runMetadata
|
|
7775
|
+
});
|
|
7776
|
+
return true;
|
|
7777
|
+
};
|
|
6795
7778
|
dispatchChannelReplyRouteMaybe = async (message, route, runMetadata) => {
|
|
6796
7779
|
if (message.channel === "system") return false;
|
|
6797
7780
|
const replyRoute = resolveChannelReplyRoute({
|
|
@@ -6801,7 +7784,8 @@ var GatewayInboundProcessor = class {
|
|
|
6801
7784
|
});
|
|
6802
7785
|
if (!replyRoute) return false;
|
|
6803
7786
|
await dispatchChannelReplyRoute({
|
|
6804
|
-
|
|
7787
|
+
agentRunClient: this.runtime.agentRunClient,
|
|
7788
|
+
assetApi: this.runtime.kernel.assetStore,
|
|
6805
7789
|
route: replyRoute,
|
|
6806
7790
|
sessionId: route.sessionKey,
|
|
6807
7791
|
content: message.content,
|
|
@@ -6881,7 +7865,7 @@ function resolveDirectRoute(params) {
|
|
|
6881
7865
|
};
|
|
6882
7866
|
}
|
|
6883
7867
|
async function dispatchPromptOverNcp(params) {
|
|
6884
|
-
const { abortSignal, agentId, attachments, channel, chatId, config, content, metadata, onAssistantDelta,
|
|
7868
|
+
const { abortSignal, agentId, attachments, channel, chatId, config, content, metadata, onAssistantDelta, agentRunClient, sessionKey } = params;
|
|
6885
7869
|
const { message, route } = resolveDirectRoute({
|
|
6886
7870
|
config,
|
|
6887
7871
|
content,
|
|
@@ -6900,15 +7884,15 @@ async function dispatchPromptOverNcp(params) {
|
|
|
6900
7884
|
sessionKey: route.sessionKey
|
|
6901
7885
|
});
|
|
6902
7886
|
if (commandResult) return commandResult;
|
|
6903
|
-
return (await
|
|
6904
|
-
agent: agentRunRequests,
|
|
7887
|
+
return (await agentRunClient.sendAndWaitForReply(await buildAgentRunSendPayload({
|
|
6905
7888
|
sessionId: route.sessionKey,
|
|
6906
7889
|
content,
|
|
6907
7890
|
attachments,
|
|
6908
7891
|
metadata: buildRunMetadata({
|
|
6909
7892
|
message,
|
|
6910
7893
|
route
|
|
6911
|
-
})
|
|
7894
|
+
})
|
|
7895
|
+
}), {
|
|
6912
7896
|
abortSignal,
|
|
6913
7897
|
onAssistantDelta,
|
|
6914
7898
|
missingCompletedMessageError: `session "${route.sessionKey}" completed without a final assistant message`,
|
|
@@ -6959,11 +7943,11 @@ function parseLegacyToolCalls(value) {
|
|
|
6959
7943
|
return value.map((entry) => {
|
|
6960
7944
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
6961
7945
|
const toolCall = entry;
|
|
6962
|
-
const id = normalizeString(toolCall.id);
|
|
7946
|
+
const id = normalizeString$1(toolCall.id);
|
|
6963
7947
|
const rawFunction = toolCall.function;
|
|
6964
7948
|
if (!id || !rawFunction || typeof rawFunction !== "object" || Array.isArray(rawFunction)) return null;
|
|
6965
7949
|
const fn = rawFunction;
|
|
6966
|
-
const name = normalizeString(fn.name);
|
|
7950
|
+
const name = normalizeString$1(fn.name);
|
|
6967
7951
|
const args = typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments ?? {});
|
|
6968
7952
|
if (!name) return null;
|
|
6969
7953
|
return {
|
|
@@ -6981,7 +7965,7 @@ function createMessageId(sessionId, index, role, timestamp) {
|
|
|
6981
7965
|
}
|
|
6982
7966
|
function resolveMessageId(params) {
|
|
6983
7967
|
const { index, message, role, sessionId, timestamp } = params;
|
|
6984
|
-
return normalizeString(message.ncp_message_id) ?? createMessageId(sessionId, index, role, timestamp);
|
|
7968
|
+
return normalizeString$1(message.ncp_message_id) ?? createMessageId(sessionId, index, role, timestamp);
|
|
6985
7969
|
}
|
|
6986
7970
|
function isNcpMessagePart(value) {
|
|
6987
7971
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && typeof value.type === "string";
|
|
@@ -7108,13 +8092,13 @@ function toNcpMessages(sessionId, messages) {
|
|
|
7108
8092
|
const ncpMessages = [];
|
|
7109
8093
|
const assistantIndexByToolCallId = /* @__PURE__ */ new Map();
|
|
7110
8094
|
messages.forEach((message, index) => {
|
|
7111
|
-
const role = normalizeString(message.role)?.toLowerCase() ?? "assistant";
|
|
8095
|
+
const role = normalizeString$1(message.role)?.toLowerCase() ?? "assistant";
|
|
7112
8096
|
if (role === "tool") {
|
|
7113
|
-
const toolCallId = normalizeString(message.tool_call_id);
|
|
8097
|
+
const toolCallId = normalizeString$1(message.tool_call_id);
|
|
7114
8098
|
if (toolCallId) {
|
|
7115
8099
|
const assistantIndex = assistantIndexByToolCallId.get(toolCallId);
|
|
7116
8100
|
if (assistantIndex !== void 0) {
|
|
7117
|
-
ncpMessages[assistantIndex] = attachToolResult(ncpMessages[assistantIndex], toolCallId, structuredClone(message.content), normalizeString(message.name) ?? void 0, message.ncp_tool_result_content_items);
|
|
8101
|
+
ncpMessages[assistantIndex] = attachToolResult(ncpMessages[assistantIndex], toolCallId, structuredClone(message.content), normalizeString$1(message.name) ?? void 0, message.ncp_tool_result_content_items);
|
|
7118
8102
|
return;
|
|
7119
8103
|
}
|
|
7120
8104
|
}
|
|
@@ -7147,7 +8131,7 @@ function toNcpMessages(sessionId, messages) {
|
|
|
7147
8131
|
return ncpMessages;
|
|
7148
8132
|
}
|
|
7149
8133
|
function resolveLegacyEventType(message) {
|
|
7150
|
-
const role = normalizeString(message.role)?.toLowerCase() ?? "";
|
|
8134
|
+
const role = normalizeString$1(message.role)?.toLowerCase() ?? "";
|
|
7151
8135
|
if (role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0) return "assistant.tool_call";
|
|
7152
8136
|
if (role === "tool") return "tool.result";
|
|
7153
8137
|
if (role === "assistant") return "message.assistant";
|
|
@@ -7156,6 +8140,6 @@ function resolveLegacyEventType(message) {
|
|
|
7156
8140
|
return `message.${role || "other"}`;
|
|
7157
8141
|
}
|
|
7158
8142
|
//#endregion
|
|
7159
|
-
export { AgentManager, AgentRunRequestManager, AgentRuntimeManager, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, ConfigManager, ContextCompactionManager, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, ExtensionManager,
|
|
8143
|
+
export { AgentManager, AgentRunClient, AgentRunRequestManager, AgentRuntimeManager, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, ConfigManager, ContextCompactionManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NativeAgentRuntimeFactory, NcpAgentSessionJournalStore, NcpSessionManager, NextclawKernel, NextclawNcpContextBuilder, ProviderManagerNcpLLMApi, SessionRequestManager, SessionRunManager, SkillManager, ToolManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildSessionOrchestrationSection, buildUserMessageParts, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isReplyCapableChannel, listExtensionChannelIds, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, resolveAgentHandoffDepth, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
|
|
7160
8144
|
|
|
7161
8145
|
//# sourceMappingURL=index.js.map
|