@nextclaw/kernel 0.1.4 → 0.1.5
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 +10 -0
- package/dist/index.js +677 -94
- package/package.json +14 -14
package/dist/index.d.ts
CHANGED
|
@@ -279,6 +279,7 @@ type AgentRuntimeHandle = AgentRuntimeEndpoint & {
|
|
|
279
279
|
};
|
|
280
280
|
declare function createAgentRuntimeHandle(params: {
|
|
281
281
|
backend: DefaultNcpAgentBackend;
|
|
282
|
+
agentClientEndpoint?: NcpAgentClientEndpoint;
|
|
282
283
|
runtimeRegistry: AgentRuntimeRegistry;
|
|
283
284
|
refreshPluginRuntimeRegistrations: () => void;
|
|
284
285
|
refreshConfiguredRuntimeEntries: () => void;
|
|
@@ -495,6 +496,8 @@ declare class AgentRuntimeManager {
|
|
|
495
496
|
get currentHandle(): AgentRuntimeHandle | null;
|
|
496
497
|
connectGatewayController: (gatewayController: GatewayController) => void;
|
|
497
498
|
bootstrap: () => Promise<AgentRuntimeHandle>;
|
|
499
|
+
private readonly materializeAgentSendEnvelope;
|
|
500
|
+
private readonly createMaterializingAgentClientEndpoint;
|
|
498
501
|
warmDerivedCapabilities: () => Promise<void>;
|
|
499
502
|
dispose: () => Promise<void>;
|
|
500
503
|
private readonly registerCoreRuntimes;
|
|
@@ -653,9 +656,14 @@ declare class ToolManager {
|
|
|
653
656
|
}
|
|
654
657
|
//#endregion
|
|
655
658
|
//#region src/services/ncp-session-api.service.d.ts
|
|
659
|
+
type NcpAgentSessionReadableStore = AgentSessionStore & {
|
|
660
|
+
listSessionSummaries?: () => Promise<NcpSessionSummary[]>;
|
|
661
|
+
listSessionMessages?: (sessionId: string) => Promise<NcpMessage[]>;
|
|
662
|
+
};
|
|
656
663
|
type NcpSessionApiServiceOptions = {
|
|
657
664
|
eventBus: EventBus;
|
|
658
665
|
getConfig: () => Config;
|
|
666
|
+
ncpAgentSessionStore?: NcpAgentSessionReadableStore;
|
|
659
667
|
sessionManager: SessionManager;
|
|
660
668
|
};
|
|
661
669
|
declare class NcpSessionApiService implements NcpSessionApi {
|
|
@@ -713,6 +721,7 @@ declare class NextclawKernel {
|
|
|
713
721
|
readonly learningLoop: LearningLoopManager;
|
|
714
722
|
private readonly sessionLifecycleEvents;
|
|
715
723
|
private readonly ncpAgentSessionStore;
|
|
724
|
+
private readonly ncpAgentSessionJournalStore;
|
|
716
725
|
private startPromise;
|
|
717
726
|
constructor(options?: NextclawKernelOptions);
|
|
718
727
|
start: () => Promise<void>;
|
|
@@ -952,6 +961,7 @@ declare function createNcpSessionSummary(params: {
|
|
|
952
961
|
sessionId: string;
|
|
953
962
|
agentId?: string;
|
|
954
963
|
messages: readonly NcpMessage[];
|
|
964
|
+
createdAt: string;
|
|
955
965
|
updatedAt: string;
|
|
956
966
|
status: NcpSessionStatus;
|
|
957
967
|
metadata?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,9 @@ import { AgentRouteResolver, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, Ch
|
|
|
3
3
|
import { EventBus, Ingress, createAppEventKey, createTypedKey, eventKeys } from "@nextclaw/shared";
|
|
4
4
|
import { DefaultNcpAgentRuntime, LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool } from "@nextclaw/ncp-agent-runtime";
|
|
5
5
|
import { NcpEventType, readAssistantReasoningNormalizationMode, readAssistantReasoningNormalizationModeFromMetadata, sanitizeAssistantReplyTags, writeAssistantReasoningNormalizationModeToMetadata } from "@nextclaw/ncp";
|
|
6
|
-
import { DefaultNcpAgentBackend, createAgentClientFromServer } from "@nextclaw/ncp-toolkit";
|
|
6
|
+
import { DefaultNcpAgentBackend, DefaultNcpAgentConversationStateManager, createAgentClientFromServer } from "@nextclaw/ncp-toolkit";
|
|
7
7
|
import { basename, delimiter, dirname, join, resolve } from "node:path";
|
|
8
|
-
import { access, readFile } from "node:fs/promises";
|
|
8
|
+
import { access, appendFile, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
|
|
9
9
|
import { appendFileSync, constants, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { BUILTIN_PROVIDER_PLUGINS } from "@nextclaw/runtime";
|
|
11
11
|
import { HttpRuntimeConfigResolver, HttpRuntimeNcpAgentRuntime } from "@nextclaw/nextclaw-ncp-runtime-http-client";
|
|
@@ -592,10 +592,10 @@ var AgentRuntimeRegistry = class {
|
|
|
592
592
|
//#endregion
|
|
593
593
|
//#region src/features/ncp-dispatch/utils/agent-runtime-handle.utils.ts
|
|
594
594
|
function createAgentRuntimeHandle(params) {
|
|
595
|
-
const { backend, runtimeRegistry, refreshPluginRuntimeRegistrations, refreshConfiguredRuntimeEntries, applyMcpConfig, dispose, assetStore } = params;
|
|
595
|
+
const { agentClientEndpoint, backend, runtimeRegistry, refreshPluginRuntimeRegistrations, refreshConfiguredRuntimeEntries, applyMcpConfig, dispose, assetStore } = params;
|
|
596
596
|
return {
|
|
597
597
|
basePath: "/api/ncp/agent",
|
|
598
|
-
agentClientEndpoint: createAgentClientFromServer(backend),
|
|
598
|
+
agentClientEndpoint: agentClientEndpoint ?? createAgentClientFromServer(backend),
|
|
599
599
|
streamProvider: backend,
|
|
600
600
|
runApi: backend,
|
|
601
601
|
sessionApi: backend,
|
|
@@ -625,11 +625,11 @@ function normalizeString(value) {
|
|
|
625
625
|
const trimmed = value.trim();
|
|
626
626
|
return trimmed.length > 0 ? trimmed : null;
|
|
627
627
|
}
|
|
628
|
-
function isRecord$
|
|
628
|
+
function isRecord$4(value) {
|
|
629
629
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
630
630
|
}
|
|
631
631
|
function cloneMetadata(value) {
|
|
632
|
-
return isRecord$
|
|
632
|
+
return isRecord$4(value) ? structuredClone(value) : void 0;
|
|
633
633
|
}
|
|
634
634
|
function readStringArray(value) {
|
|
635
635
|
if (!Array.isArray(value)) return null;
|
|
@@ -1876,7 +1876,7 @@ var LlmUsageManager = class {
|
|
|
1876
1876
|
};
|
|
1877
1877
|
//#endregion
|
|
1878
1878
|
//#region src/tools/session-search.tools.ts
|
|
1879
|
-
function isRecord$
|
|
1879
|
+
function isRecord$3(value) {
|
|
1880
1880
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1881
1881
|
}
|
|
1882
1882
|
function readOptionalInteger(value) {
|
|
@@ -1926,7 +1926,7 @@ var SessionSearchTool = class {
|
|
|
1926
1926
|
return issues;
|
|
1927
1927
|
};
|
|
1928
1928
|
execute = async (args) => {
|
|
1929
|
-
if (!isRecord$
|
|
1929
|
+
if (!isRecord$3(args)) throw new Error("session_search requires an object argument.");
|
|
1930
1930
|
const issues = this.validateArgs(args);
|
|
1931
1931
|
if (issues.length > 0) throw new Error(issues.join(" "));
|
|
1932
1932
|
return this.queryService.search({
|
|
@@ -1939,13 +1939,13 @@ var SessionSearchTool = class {
|
|
|
1939
1939
|
};
|
|
1940
1940
|
//#endregion
|
|
1941
1941
|
//#region src/features/native-runtime/tools/ncp-asset.tools.ts
|
|
1942
|
-
function readOptionalString$
|
|
1942
|
+
function readOptionalString$3(value) {
|
|
1943
1943
|
if (typeof value !== "string") return null;
|
|
1944
1944
|
const trimmed = value.trim();
|
|
1945
1945
|
return trimmed.length > 0 ? trimmed : null;
|
|
1946
1946
|
}
|
|
1947
1947
|
function readOptionalBase64Bytes(value) {
|
|
1948
|
-
const base64 = readOptionalString$
|
|
1948
|
+
const base64 = readOptionalString$3(value);
|
|
1949
1949
|
if (!base64) return null;
|
|
1950
1950
|
try {
|
|
1951
1951
|
return Buffer.from(base64, "base64");
|
|
@@ -1996,18 +1996,18 @@ var AssetPutTool = class {
|
|
|
1996
1996
|
this.contentBasePath = contentBasePath;
|
|
1997
1997
|
}
|
|
1998
1998
|
validateArgs = (args) => {
|
|
1999
|
-
const path = readOptionalString$
|
|
2000
|
-
const bytesBase64 = readOptionalString$
|
|
2001
|
-
const fileName = readOptionalString$
|
|
1999
|
+
const path = readOptionalString$3(args.path);
|
|
2000
|
+
const bytesBase64 = readOptionalString$3(args.bytesBase64);
|
|
2001
|
+
const fileName = readOptionalString$3(args.fileName);
|
|
2002
2002
|
if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
|
|
2003
2003
|
if (path) return [];
|
|
2004
2004
|
if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
|
|
2005
2005
|
return ["Provide either path, or bytesBase64 + fileName."];
|
|
2006
2006
|
};
|
|
2007
2007
|
execute = async (args) => {
|
|
2008
|
-
const path = readOptionalString$
|
|
2009
|
-
const fileName = readOptionalString$
|
|
2010
|
-
const mimeType = readOptionalString$
|
|
2008
|
+
const path = readOptionalString$3(args?.path);
|
|
2009
|
+
const fileName = readOptionalString$3(args?.fileName);
|
|
2010
|
+
const mimeType = readOptionalString$3(args?.mimeType);
|
|
2011
2011
|
const bytes = readOptionalBase64Bytes(args?.bytesBase64);
|
|
2012
2012
|
if (path) return {
|
|
2013
2013
|
ok: true,
|
|
@@ -2050,8 +2050,8 @@ var AssetExportTool = class {
|
|
|
2050
2050
|
this.assetStore = assetStore;
|
|
2051
2051
|
}
|
|
2052
2052
|
execute = async (args) => {
|
|
2053
|
-
const assetUri = readOptionalString$
|
|
2054
|
-
const targetPath = readOptionalString$
|
|
2053
|
+
const assetUri = readOptionalString$3(args?.assetUri);
|
|
2054
|
+
const targetPath = readOptionalString$3(args?.targetPath);
|
|
2055
2055
|
if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
|
|
2056
2056
|
return {
|
|
2057
2057
|
ok: true,
|
|
@@ -2077,7 +2077,7 @@ var AssetStatTool = class {
|
|
|
2077
2077
|
this.contentBasePath = contentBasePath;
|
|
2078
2078
|
}
|
|
2079
2079
|
execute = async (args) => {
|
|
2080
|
-
const assetUri = readOptionalString$
|
|
2080
|
+
const assetUri = readOptionalString$3(args?.assetUri);
|
|
2081
2081
|
if (!assetUri) throw new Error("asset_stat requires assetUri.");
|
|
2082
2082
|
const record = await this.assetStore.statRecord(assetUri);
|
|
2083
2083
|
if (!record) return {
|
|
@@ -2252,7 +2252,7 @@ function readRequiredString$1(params, key) {
|
|
|
2252
2252
|
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
|
|
2253
2253
|
return value.trim();
|
|
2254
2254
|
}
|
|
2255
|
-
function readOptionalString$
|
|
2255
|
+
function readOptionalString$2(params, key) {
|
|
2256
2256
|
const value = params[key];
|
|
2257
2257
|
if (typeof value !== "string") return;
|
|
2258
2258
|
const trimmed = value.trim();
|
|
@@ -2313,7 +2313,7 @@ var SessionRequestTool = class extends Tool {
|
|
|
2313
2313
|
const target = params.target;
|
|
2314
2314
|
if (!target || typeof target !== "object" || Array.isArray(target)) throw new Error("target must be an object.");
|
|
2315
2315
|
const task = readRequiredString$1(params, "task");
|
|
2316
|
-
const notifyMode = readOptionalString$
|
|
2316
|
+
const notifyMode = readOptionalString$2(params, "notify")?.toLowerCase();
|
|
2317
2317
|
if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
|
|
2318
2318
|
const { toolCallId, updateToolCallResult } = context;
|
|
2319
2319
|
return this.manager.requestSession({
|
|
@@ -2322,7 +2322,7 @@ var SessionRequestTool = class extends Tool {
|
|
|
2322
2322
|
updateToolCallResult,
|
|
2323
2323
|
targetSessionId: readRequiredString$1(target, "session_id"),
|
|
2324
2324
|
task,
|
|
2325
|
-
title: readOptionalString$
|
|
2325
|
+
title: readOptionalString$2(params, "title"),
|
|
2326
2326
|
notify: notifyMode,
|
|
2327
2327
|
handoffDepth: this.handoffDepth
|
|
2328
2328
|
});
|
|
@@ -2334,13 +2334,13 @@ function readRequiredString(value, key) {
|
|
|
2334
2334
|
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
|
|
2335
2335
|
return value.trim();
|
|
2336
2336
|
}
|
|
2337
|
-
function readOptionalString(value) {
|
|
2337
|
+
function readOptionalString$1(value) {
|
|
2338
2338
|
if (typeof value !== "string") return;
|
|
2339
2339
|
const trimmed = value.trim();
|
|
2340
2340
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
2341
2341
|
}
|
|
2342
2342
|
function readSpawnScope(value) {
|
|
2343
|
-
const normalized = readOptionalString(value)?.toLowerCase();
|
|
2343
|
+
const normalized = readOptionalString$1(value)?.toLowerCase();
|
|
2344
2344
|
if (!normalized || normalized === "standalone") return "standalone";
|
|
2345
2345
|
if (normalized === "child") return "child";
|
|
2346
2346
|
throw new Error("scope must be \"standalone\" or \"child\".");
|
|
@@ -2348,7 +2348,7 @@ function readSpawnScope(value) {
|
|
|
2348
2348
|
function readSpawnRequestOptions(value) {
|
|
2349
2349
|
if (typeof value === "undefined") return;
|
|
2350
2350
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("request must be an object.");
|
|
2351
|
-
const notifyMode = readOptionalString(value.notify)?.toLowerCase();
|
|
2351
|
+
const notifyMode = readOptionalString$1(value.notify)?.toLowerCase();
|
|
2352
2352
|
if (notifyMode === "none" || notifyMode === "final_reply") return { notify: notifyMode };
|
|
2353
2353
|
throw new Error("request.notify must be \"none\" or \"final_reply\".");
|
|
2354
2354
|
}
|
|
@@ -2429,10 +2429,10 @@ var SessionSpawnTool = class extends Tool {
|
|
|
2429
2429
|
updateToolCallResult,
|
|
2430
2430
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
2431
2431
|
task,
|
|
2432
|
-
title: readOptionalString(rawTitle),
|
|
2433
|
-
agentId: readOptionalString(rawAgentId),
|
|
2434
|
-
model: readOptionalString(rawModel),
|
|
2435
|
-
runtime: readOptionalString(rawRuntime),
|
|
2432
|
+
title: readOptionalString$1(rawTitle),
|
|
2433
|
+
agentId: readOptionalString$1(rawAgentId),
|
|
2434
|
+
model: readOptionalString$1(rawModel),
|
|
2435
|
+
runtime: readOptionalString$1(rawRuntime),
|
|
2436
2436
|
handoffDepth: this.handoffDepth,
|
|
2437
2437
|
...parentSessionId ? { parentSessionId } : {},
|
|
2438
2438
|
notify: request.notify
|
|
@@ -2440,11 +2440,11 @@ var SessionSpawnTool = class extends Tool {
|
|
|
2440
2440
|
const session = this.sessionManager.createSession({
|
|
2441
2441
|
sourceSessionId: this.sourceSessionId,
|
|
2442
2442
|
task,
|
|
2443
|
-
title: readOptionalString(rawTitle),
|
|
2443
|
+
title: readOptionalString$1(rawTitle),
|
|
2444
2444
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
2445
|
-
agentId: readOptionalString(rawAgentId),
|
|
2446
|
-
model: readOptionalString(rawModel),
|
|
2447
|
-
runtime: readOptionalString(rawRuntime),
|
|
2445
|
+
agentId: readOptionalString$1(rawAgentId),
|
|
2446
|
+
model: readOptionalString$1(rawModel),
|
|
2447
|
+
runtime: readOptionalString$1(rawRuntime),
|
|
2448
2448
|
...parentSessionId ? { parentSessionId } : {}
|
|
2449
2449
|
});
|
|
2450
2450
|
this.onSessionUpdated?.(session.sessionId);
|
|
@@ -2469,10 +2469,10 @@ var SessionSpawnTool = class extends Tool {
|
|
|
2469
2469
|
//#endregion
|
|
2470
2470
|
//#region src/features/native-runtime/services/nextclaw-ncp-tool-registry.service.ts
|
|
2471
2471
|
function toToolParams(args) {
|
|
2472
|
-
if (isRecord$
|
|
2472
|
+
if (isRecord$4(args)) return args;
|
|
2473
2473
|
if (typeof args === "string") try {
|
|
2474
2474
|
const parsed = JSON.parse(args);
|
|
2475
|
-
return isRecord$
|
|
2475
|
+
return isRecord$4(parsed) ? parsed : {};
|
|
2476
2476
|
} catch {
|
|
2477
2477
|
return {};
|
|
2478
2478
|
}
|
|
@@ -2664,14 +2664,14 @@ function readAccountIdForHints(metadata, sessionMetadata) {
|
|
|
2664
2664
|
//#endregion
|
|
2665
2665
|
//#region src/features/native-runtime/services/nextclaw-ncp-context-builder.service.ts
|
|
2666
2666
|
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, /(现在|此刻|当前时间|现在几点|几点了|今天|今晚|今早|今晨|明天|昨天|日期)/];
|
|
2667
|
-
function isRecord$
|
|
2667
|
+
function isRecord$2(value) {
|
|
2668
2668
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2669
2669
|
}
|
|
2670
2670
|
function mergeInputMetadata(input) {
|
|
2671
|
-
const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$
|
|
2671
|
+
const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$2(message.metadata))?.metadata;
|
|
2672
2672
|
return {
|
|
2673
|
-
...isRecord$
|
|
2674
|
-
...isRecord$
|
|
2673
|
+
...isRecord$2(messageMetadata) ? structuredClone(messageMetadata) : {},
|
|
2674
|
+
...isRecord$2(input.metadata) ? structuredClone(input.metadata) : {}
|
|
2675
2675
|
};
|
|
2676
2676
|
}
|
|
2677
2677
|
const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
|
|
@@ -2978,12 +2978,12 @@ function createContextWindowUpdatedEvent(params) {
|
|
|
2978
2978
|
}
|
|
2979
2979
|
};
|
|
2980
2980
|
}
|
|
2981
|
-
function isRecord(value) {
|
|
2981
|
+
function isRecord$1(value) {
|
|
2982
2982
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2983
2983
|
}
|
|
2984
2984
|
function resolveNativeReasoningNormalizationMode(params) {
|
|
2985
2985
|
const runtimeEntry = params.config.agents.runtimes.entries.native?.config ?? params.config.ui.ncp.runtimes.native;
|
|
2986
|
-
const runtimeMetadata = isRecord(runtimeEntry) ? runtimeEntry : {};
|
|
2986
|
+
const runtimeMetadata = isRecord$1(runtimeEntry) ? runtimeEntry : {};
|
|
2987
2987
|
return readAssistantReasoningNormalizationModeFromMetadata(params.sessionMetadata) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalizationMode) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization_mode) ?? "think-tags";
|
|
2988
2988
|
}
|
|
2989
2989
|
function createSessionSearchTools(params) {
|
|
@@ -3240,6 +3240,24 @@ function createAgentRuntimeSessionRequestDispatcher(options) {
|
|
|
3240
3240
|
}
|
|
3241
3241
|
//#endregion
|
|
3242
3242
|
//#region src/managers/agent-runtime.manager.ts
|
|
3243
|
+
function readOptionalString(value) {
|
|
3244
|
+
if (typeof value !== "string") return null;
|
|
3245
|
+
const trimmed = value.trim();
|
|
3246
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
3247
|
+
}
|
|
3248
|
+
function readMessageTask(message) {
|
|
3249
|
+
for (const part of message.parts) if ((part.type === "text" || part.type === "rich-text" || part.type === "reasoning") && part.text.trim()) return part.text.trim();
|
|
3250
|
+
return "Session";
|
|
3251
|
+
}
|
|
3252
|
+
function readSessionMetadataString(metadata, ...keys) {
|
|
3253
|
+
for (const key of keys) {
|
|
3254
|
+
const value = readOptionalString(metadata?.[key]);
|
|
3255
|
+
if (value) return value;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
async function consumeAgentEvents(events) {
|
|
3259
|
+
for await (const event of events);
|
|
3260
|
+
}
|
|
3243
3261
|
var AgentRuntimeManager = class {
|
|
3244
3262
|
runtimeRegistry = new AgentRuntimeRegistry();
|
|
3245
3263
|
mcpRuntimeSupport;
|
|
@@ -3321,6 +3339,7 @@ var AgentRuntimeManager = class {
|
|
|
3321
3339
|
await this.backend.start();
|
|
3322
3340
|
this.handle = createAgentRuntimeHandle({
|
|
3323
3341
|
backend: this.backend,
|
|
3342
|
+
agentClientEndpoint: this.createMaterializingAgentClientEndpoint(this.backend),
|
|
3324
3343
|
runtimeRegistry: this.runtimeRegistry,
|
|
3325
3344
|
refreshPluginRuntimeRegistrations: this.pluginRuntimeRegistrationController.refreshPluginRuntimeRegistrations,
|
|
3326
3345
|
refreshConfiguredRuntimeEntries: this.refreshConfiguredRuntimeEntries,
|
|
@@ -3330,6 +3349,68 @@ var AgentRuntimeManager = class {
|
|
|
3330
3349
|
});
|
|
3331
3350
|
return this.handle;
|
|
3332
3351
|
};
|
|
3352
|
+
materializeAgentSendEnvelope = (envelope) => {
|
|
3353
|
+
const existingSessionId = readOptionalString(envelope.sessionId) ?? readOptionalString(envelope.message.sessionId);
|
|
3354
|
+
if (existingSessionId) return {
|
|
3355
|
+
...envelope,
|
|
3356
|
+
sessionId: existingSessionId,
|
|
3357
|
+
message: {
|
|
3358
|
+
...envelope.message,
|
|
3359
|
+
sessionId: existingSessionId
|
|
3360
|
+
}
|
|
3361
|
+
};
|
|
3362
|
+
const metadata = envelope.metadata ?? {};
|
|
3363
|
+
const createdSession = this.params.sessions.createSession({
|
|
3364
|
+
task: readMessageTask(envelope.message),
|
|
3365
|
+
title: readSessionMetadataString(metadata, "label", "title"),
|
|
3366
|
+
sourceSessionMetadata: {},
|
|
3367
|
+
metadataOverrides: metadata,
|
|
3368
|
+
agentId: readSessionMetadataString(metadata, "agent_id", "agentId"),
|
|
3369
|
+
model: readSessionMetadataString(metadata, "preferred_model", "model"),
|
|
3370
|
+
runtime: readSessionMetadataString(metadata, "runtime", "session_type"),
|
|
3371
|
+
sessionType: readSessionMetadataString(metadata, "session_type", "runtime"),
|
|
3372
|
+
thinkingLevel: readSessionMetadataString(metadata, "preferred_thinking", "thinking"),
|
|
3373
|
+
projectRoot: readSessionMetadataString(metadata, "project_root")
|
|
3374
|
+
});
|
|
3375
|
+
this.params.onSessionUpdated(createdSession.sessionId);
|
|
3376
|
+
return {
|
|
3377
|
+
...envelope,
|
|
3378
|
+
sessionId: createdSession.sessionId,
|
|
3379
|
+
message: {
|
|
3380
|
+
...envelope.message,
|
|
3381
|
+
sessionId: createdSession.sessionId
|
|
3382
|
+
}
|
|
3383
|
+
};
|
|
3384
|
+
};
|
|
3385
|
+
createMaterializingAgentClientEndpoint = (backend) => ({
|
|
3386
|
+
get manifest() {
|
|
3387
|
+
return backend.manifest;
|
|
3388
|
+
},
|
|
3389
|
+
start: backend.start,
|
|
3390
|
+
stop: backend.stop,
|
|
3391
|
+
subscribe: backend.subscribe,
|
|
3392
|
+
stream: async (payload) => {
|
|
3393
|
+
await consumeAgentEvents(backend.stream(payload));
|
|
3394
|
+
},
|
|
3395
|
+
abort: backend.abort,
|
|
3396
|
+
send: async (envelope) => {
|
|
3397
|
+
await consumeAgentEvents(backend.send(this.materializeAgentSendEnvelope(envelope)));
|
|
3398
|
+
},
|
|
3399
|
+
emit: async (event) => {
|
|
3400
|
+
switch (event.type) {
|
|
3401
|
+
case NcpEventType.MessageRequest:
|
|
3402
|
+
await consumeAgentEvents(backend.send(this.materializeAgentSendEnvelope(event.payload)));
|
|
3403
|
+
return;
|
|
3404
|
+
case NcpEventType.MessageStreamRequest:
|
|
3405
|
+
await consumeAgentEvents(backend.stream(event.payload));
|
|
3406
|
+
return;
|
|
3407
|
+
case NcpEventType.MessageAbort:
|
|
3408
|
+
await backend.abort(event.payload);
|
|
3409
|
+
return;
|
|
3410
|
+
default: await backend.emit(event);
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
});
|
|
3333
3414
|
warmDerivedCapabilities = async () => {
|
|
3334
3415
|
this.assertNotDisposed();
|
|
3335
3416
|
this.warmupPromise ??= this.runDerivedCapabilityWarmup();
|
|
@@ -4069,11 +4150,12 @@ var NcpLifecycleEventBridge = class {
|
|
|
4069
4150
|
//#endregion
|
|
4070
4151
|
//#region src/utils/ncp-session-summary.utils.ts
|
|
4071
4152
|
function createNcpSessionSummary(params) {
|
|
4072
|
-
const { sessionId, agentId, messages, updatedAt, status, metadata, contextWindow } = params;
|
|
4153
|
+
const { sessionId, agentId, messages, createdAt, updatedAt, status, metadata, contextWindow } = params;
|
|
4073
4154
|
return {
|
|
4074
4155
|
sessionId,
|
|
4075
4156
|
...agentId ? { agentId } : {},
|
|
4076
4157
|
messageCount: messages.length,
|
|
4158
|
+
createdAt,
|
|
4077
4159
|
updatedAt,
|
|
4078
4160
|
...messages.length > 0 ? { lastMessageAt: messages[messages.length - 1]?.timestamp ?? updatedAt } : {},
|
|
4079
4161
|
status,
|
|
@@ -4100,6 +4182,28 @@ function buildUpdatedMetadata(params) {
|
|
|
4100
4182
|
function normalizeSessionId(sessionId) {
|
|
4101
4183
|
return sessionId.trim();
|
|
4102
4184
|
}
|
|
4185
|
+
function toSessionCandidate(record) {
|
|
4186
|
+
const sessionId = normalizeSessionId(record.key);
|
|
4187
|
+
return sessionId ? {
|
|
4188
|
+
...record,
|
|
4189
|
+
sessionId
|
|
4190
|
+
} : null;
|
|
4191
|
+
}
|
|
4192
|
+
function createSessionListSummary(record) {
|
|
4193
|
+
return {
|
|
4194
|
+
sessionId: record.sessionId,
|
|
4195
|
+
...record.agentId ? { agentId: record.agentId } : {},
|
|
4196
|
+
messageCount: record.messageCount ?? 0,
|
|
4197
|
+
createdAt: record.created_at,
|
|
4198
|
+
updatedAt: record.updated_at,
|
|
4199
|
+
...record.lastMessageAt ? { lastMessageAt: record.lastMessageAt } : {},
|
|
4200
|
+
status: "idle",
|
|
4201
|
+
metadata: structuredClone(record.metadata)
|
|
4202
|
+
};
|
|
4203
|
+
}
|
|
4204
|
+
function readSessionActivityAt$1(record) {
|
|
4205
|
+
return record.lastMessageAt ?? record.created_at;
|
|
4206
|
+
}
|
|
4103
4207
|
var NcpSessionApiService = class {
|
|
4104
4208
|
unsubscribeSessionUpdated = null;
|
|
4105
4209
|
contextWindowPreview;
|
|
@@ -4133,32 +4237,36 @@ var NcpSessionApiService = class {
|
|
|
4133
4237
|
this.options.eventBus.emit(eventKeys.sessionSummaryDelete, { sessionKey: normalizedSessionKey });
|
|
4134
4238
|
};
|
|
4135
4239
|
listSessions = async (options) => {
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
const sessionId = normalizeSessionId(record.key);
|
|
4139
|
-
if (!sessionId) continue;
|
|
4140
|
-
const session = this.options.sessionManager.getIfExists(sessionId);
|
|
4141
|
-
if (!session) continue;
|
|
4142
|
-
summaries.push(createNcpSessionSummary({
|
|
4143
|
-
sessionId,
|
|
4144
|
-
agentId: session.agentId,
|
|
4145
|
-
messages: toNcpMessages(sessionId, session.messages),
|
|
4146
|
-
updatedAt: session.updatedAt.toISOString(),
|
|
4147
|
-
status: "idle",
|
|
4148
|
-
metadata: session.metadata
|
|
4149
|
-
}));
|
|
4150
|
-
}
|
|
4151
|
-
summaries.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
4152
|
-
return applyLimit(summaries, options?.limit);
|
|
4240
|
+
if (this.options.ncpAgentSessionStore?.listSessionSummaries) return applyLimit(await this.options.ncpAgentSessionStore.listSessionSummaries(), options?.limit);
|
|
4241
|
+
return applyLimit(this.options.sessionManager.listSessions().map(toSessionCandidate).filter((record) => Boolean(record)).sort((left, right) => readSessionActivityAt$1(right).localeCompare(readSessionActivityAt$1(left))), options?.limit).map(createSessionListSummary);
|
|
4153
4242
|
};
|
|
4154
4243
|
listSessionMessages = async (sessionId, options) => {
|
|
4155
4244
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
4245
|
+
if (normalizedSessionId && this.options.ncpAgentSessionStore?.listSessionMessages) return applyLimit(await this.options.ncpAgentSessionStore.listSessionMessages(normalizedSessionId), options?.limit);
|
|
4156
4246
|
const session = normalizedSessionId ? this.options.sessionManager.getIfExists(normalizedSessionId) : null;
|
|
4157
4247
|
if (!session) return [];
|
|
4158
4248
|
return applyLimit(toNcpMessages(normalizedSessionId, session.messages).map((message) => structuredClone(message)), options?.limit);
|
|
4159
4249
|
};
|
|
4160
4250
|
getSession = async (sessionId) => {
|
|
4161
4251
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
4252
|
+
if (normalizedSessionId && this.options.ncpAgentSessionStore?.getSession) {
|
|
4253
|
+
const record = await this.options.ncpAgentSessionStore.getSession(normalizedSessionId);
|
|
4254
|
+
if (record) return createNcpSessionSummary({
|
|
4255
|
+
sessionId: normalizedSessionId,
|
|
4256
|
+
agentId: record.agentId,
|
|
4257
|
+
messages: record.messages,
|
|
4258
|
+
createdAt: record.createdAt ?? record.updatedAt,
|
|
4259
|
+
updatedAt: record.updatedAt,
|
|
4260
|
+
status: "idle",
|
|
4261
|
+
metadata: record.metadata,
|
|
4262
|
+
contextWindow: this.contextWindowPreview.preview({
|
|
4263
|
+
contextWindowOwner: "nextclaw",
|
|
4264
|
+
requestMetadata: record.metadata ?? {},
|
|
4265
|
+
sessionId: normalizedSessionId,
|
|
4266
|
+
sessionMessages: record.messages
|
|
4267
|
+
})
|
|
4268
|
+
});
|
|
4269
|
+
}
|
|
4162
4270
|
const session = normalizedSessionId ? this.options.sessionManager.getIfExists(normalizedSessionId) : null;
|
|
4163
4271
|
if (!session) return null;
|
|
4164
4272
|
const messages = toNcpMessages(normalizedSessionId, session.messages);
|
|
@@ -4166,6 +4274,7 @@ var NcpSessionApiService = class {
|
|
|
4166
4274
|
sessionId: normalizedSessionId,
|
|
4167
4275
|
agentId: session.agentId,
|
|
4168
4276
|
messages,
|
|
4277
|
+
createdAt: session.createdAt.toISOString(),
|
|
4169
4278
|
updatedAt: session.updatedAt.toISOString(),
|
|
4170
4279
|
status: "idle",
|
|
4171
4280
|
metadata: session.metadata,
|
|
@@ -4179,6 +4288,21 @@ var NcpSessionApiService = class {
|
|
|
4179
4288
|
};
|
|
4180
4289
|
updateSession = async (sessionId, patch) => {
|
|
4181
4290
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
4291
|
+
if (normalizedSessionId && this.options.ncpAgentSessionStore) {
|
|
4292
|
+
const existing = await this.options.ncpAgentSessionStore.getSession(normalizedSessionId);
|
|
4293
|
+
if (existing) {
|
|
4294
|
+
await this.options.ncpAgentSessionStore.replaceSession({
|
|
4295
|
+
...existing,
|
|
4296
|
+
metadata: buildUpdatedMetadata({
|
|
4297
|
+
existingMetadata: existing.metadata,
|
|
4298
|
+
patch
|
|
4299
|
+
}),
|
|
4300
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4301
|
+
});
|
|
4302
|
+
await this.publishSessionChange(normalizedSessionId);
|
|
4303
|
+
return await this.getSession(normalizedSessionId);
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4182
4306
|
const session = normalizedSessionId ? this.options.sessionManager.getIfExists(normalizedSessionId) : null;
|
|
4183
4307
|
if (!session) return null;
|
|
4184
4308
|
session.metadata = buildUpdatedMetadata({
|
|
@@ -4193,6 +4317,7 @@ var NcpSessionApiService = class {
|
|
|
4193
4317
|
deleteSession = async (sessionId) => {
|
|
4194
4318
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
4195
4319
|
if (!normalizedSessionId) return;
|
|
4320
|
+
if (this.options.ncpAgentSessionStore) await this.options.ncpAgentSessionStore.deleteSession(normalizedSessionId);
|
|
4196
4321
|
this.options.sessionManager.delete(normalizedSessionId);
|
|
4197
4322
|
await this.publishSessionChange(normalizedSessionId);
|
|
4198
4323
|
};
|
|
@@ -4205,58 +4330,72 @@ function resolvePersistedSessionMetadata(params) {
|
|
|
4205
4330
|
return mergeSessionMetadata(preserveExistingMetadata ? mergeSessionMetadata(currentMetadata, messageMetadata) : mergeSessionMetadata({}, messageMetadata), cloneMetadata(sessionRecord.metadata));
|
|
4206
4331
|
}
|
|
4207
4332
|
//#endregion
|
|
4208
|
-
//#region src/
|
|
4209
|
-
function readAgentIdFromMetadata(metadata) {
|
|
4210
|
-
return normalizeString(metadata?.agent_id)?.toLowerCase() ?? normalizeString(metadata?.agentId)?.toLowerCase() ?? void 0;
|
|
4211
|
-
}
|
|
4333
|
+
//#region src/stores/ncp-agent-legacy-session.store.ts
|
|
4212
4334
|
function resolveSessionRecordAgentId(record) {
|
|
4213
|
-
return normalizeString(record.agentId)?.toLowerCase() ??
|
|
4335
|
+
return normalizeString(record.agentId)?.toLowerCase() ?? normalizeString(record.metadata?.agent_id)?.toLowerCase() ?? normalizeString(record.metadata?.agentId)?.toLowerCase();
|
|
4214
4336
|
}
|
|
4215
|
-
var
|
|
4337
|
+
var NcpAgentLegacySessionStore = class {
|
|
4216
4338
|
constructor(sessionManager, options = {}) {
|
|
4217
4339
|
this.sessionManager = sessionManager;
|
|
4218
4340
|
this.options = options;
|
|
4219
4341
|
}
|
|
4220
|
-
getSession =
|
|
4342
|
+
getSession = (sessionId) => {
|
|
4221
4343
|
const session = this.sessionManager.getIfExists(sessionId);
|
|
4222
4344
|
if (!session) return null;
|
|
4223
4345
|
return {
|
|
4224
4346
|
sessionId,
|
|
4225
4347
|
...session.agentId ? { agentId: session.agentId } : {},
|
|
4226
4348
|
messages: toNcpMessages(sessionId, session.messages),
|
|
4349
|
+
createdAt: session.createdAt.toISOString(),
|
|
4227
4350
|
updatedAt: session.updatedAt.toISOString(),
|
|
4228
4351
|
metadata: structuredClone(session.metadata)
|
|
4229
4352
|
};
|
|
4230
4353
|
};
|
|
4231
|
-
|
|
4232
|
-
const
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
});
|
|
4246
|
-
}
|
|
4247
|
-
sessions.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
4248
|
-
return sessions;
|
|
4354
|
+
getSessionSummary = (sessionId) => {
|
|
4355
|
+
const session = this.getSession(sessionId);
|
|
4356
|
+
if (!session) return null;
|
|
4357
|
+
const lastMessageAt = session.messages.at(-1)?.timestamp;
|
|
4358
|
+
return {
|
|
4359
|
+
sessionId: session.sessionId,
|
|
4360
|
+
...session.agentId ? { agentId: session.agentId } : {},
|
|
4361
|
+
messageCount: session.messages.length,
|
|
4362
|
+
createdAt: session.createdAt,
|
|
4363
|
+
updatedAt: session.updatedAt,
|
|
4364
|
+
...lastMessageAt ? { lastMessageAt } : {},
|
|
4365
|
+
status: "idle",
|
|
4366
|
+
metadata: session.metadata
|
|
4367
|
+
};
|
|
4249
4368
|
};
|
|
4250
|
-
|
|
4251
|
-
|
|
4369
|
+
listSessionMessages = (sessionId) => this.getSession(sessionId)?.messages ?? [];
|
|
4370
|
+
listSessionSummaries = () => this.sessionManager.listSessions().map((record) => ({
|
|
4371
|
+
sessionId: record.key,
|
|
4372
|
+
...record.agentId ? { agentId: record.agentId } : {},
|
|
4373
|
+
messageCount: record.messageCount ?? 0,
|
|
4374
|
+
createdAt: record.created_at,
|
|
4375
|
+
updatedAt: record.updated_at,
|
|
4376
|
+
...record.lastMessageAt ? { lastMessageAt: record.lastMessageAt } : {},
|
|
4377
|
+
status: "idle",
|
|
4378
|
+
metadata: structuredClone(record.metadata)
|
|
4379
|
+
}));
|
|
4380
|
+
saveSession = (sessionRecord) => this.persistSession(sessionRecord, true);
|
|
4381
|
+
replaceSession = (sessionRecord) => this.persistSession(sessionRecord, false);
|
|
4382
|
+
deleteSession = (sessionId) => {
|
|
4383
|
+
const existing = this.getSession(sessionId);
|
|
4384
|
+
if (!existing) return null;
|
|
4385
|
+
this.sessionManager.delete(sessionId);
|
|
4386
|
+
this.options.onSessionUpdated?.(sessionId);
|
|
4387
|
+
return existing;
|
|
4388
|
+
};
|
|
4389
|
+
persistSession = async (sessionRecord, preserveExistingMetadata) => {
|
|
4252
4390
|
const session = this.sessionManager.getIfExists(sessionRecord.sessionId) ?? this.sessionManager.getOrCreate(sessionRecord.sessionId);
|
|
4253
4391
|
const legacyMessages = toLegacyMessages(sessionRecord.messages);
|
|
4254
4392
|
const nextAgentId = resolveSessionRecordAgentId(sessionRecord);
|
|
4255
4393
|
if (nextAgentId) session.agentId = nextAgentId;
|
|
4394
|
+
if (sessionRecord.createdAt) session.createdAt = new Date(ensureIsoTimestamp(sessionRecord.createdAt, session.createdAt.toISOString()));
|
|
4256
4395
|
session.metadata = resolvePersistedSessionMetadata({
|
|
4257
4396
|
currentMetadata: session.metadata,
|
|
4258
4397
|
sessionRecord,
|
|
4259
|
-
preserveExistingMetadata
|
|
4398
|
+
preserveExistingMetadata
|
|
4260
4399
|
});
|
|
4261
4400
|
this.sessionManager.clear(session);
|
|
4262
4401
|
for (const message of legacyMessages) this.sessionManager.appendEvent(session, {
|
|
@@ -4268,19 +4407,457 @@ var NcpAgentSessionStoreAdapter = class {
|
|
|
4268
4407
|
this.sessionManager.save(session);
|
|
4269
4408
|
this.options.onSessionUpdated?.(sessionRecord.sessionId);
|
|
4270
4409
|
};
|
|
4410
|
+
};
|
|
4411
|
+
//#endregion
|
|
4412
|
+
//#region src/services/ncp-agent-session-store-adapter.service.ts
|
|
4413
|
+
function readSessionActivityAt(record) {
|
|
4414
|
+
return record.messages.at(-1)?.timestamp ?? record.createdAt ?? record.updatedAt;
|
|
4415
|
+
}
|
|
4416
|
+
var NcpAgentSessionStoreAdapter = class {
|
|
4417
|
+
appendSessionEvent;
|
|
4418
|
+
legacyStore;
|
|
4419
|
+
constructor(sessionManager, options = {}) {
|
|
4420
|
+
this.options = options;
|
|
4421
|
+
this.legacyStore = new NcpAgentLegacySessionStore(sessionManager, { onSessionUpdated: options.onSessionUpdated });
|
|
4422
|
+
const journalStore = options.journalStore;
|
|
4423
|
+
if (journalStore) this.appendSessionEvent = async (params) => {
|
|
4424
|
+
const { event, session } = params;
|
|
4425
|
+
if (!await journalStore.hasSession(session.sessionId)) {
|
|
4426
|
+
const legacySession = this.legacyStore.getSession(session.sessionId);
|
|
4427
|
+
if (legacySession) await journalStore.replaceSession(legacySession);
|
|
4428
|
+
}
|
|
4429
|
+
await journalStore.appendSessionEvent(params);
|
|
4430
|
+
if (isSessionSummaryRefreshEvent(event)) this.options.onSessionUpdated?.(session.sessionId);
|
|
4431
|
+
};
|
|
4432
|
+
}
|
|
4433
|
+
getSession = async (sessionId) => await this.options.journalStore?.getSession(sessionId) ?? this.legacyStore.getSession(sessionId);
|
|
4434
|
+
getSessionSummary = async (sessionId) => await this.options.journalStore?.getSessionSummary(sessionId) ?? this.legacyStore.getSessionSummary(sessionId);
|
|
4435
|
+
listSessionMessages = async (sessionId) => {
|
|
4436
|
+
const journalStore = this.options.journalStore;
|
|
4437
|
+
return journalStore && await journalStore.hasSession(sessionId) ? await journalStore.listSessionMessages(sessionId) : this.legacyStore.listSessionMessages(sessionId);
|
|
4438
|
+
};
|
|
4439
|
+
listSessionSummaries = async () => {
|
|
4440
|
+
const journalSummaries = await this.options.journalStore?.listSessionSummaries() ?? [];
|
|
4441
|
+
const journalIds = new Set(journalSummaries.map((summary) => summary.sessionId));
|
|
4442
|
+
const legacySummaries = this.legacyStore.listSessionSummaries().filter((summary) => !journalIds.has(summary.sessionId));
|
|
4443
|
+
return [...journalSummaries, ...legacySummaries].sort((left, right) => readSummaryActivityAt(right).localeCompare(readSummaryActivityAt(left)));
|
|
4444
|
+
};
|
|
4445
|
+
listSessions = async () => {
|
|
4446
|
+
const summaries = await this.listSessionSummaries();
|
|
4447
|
+
const sessions = [];
|
|
4448
|
+
for (const summary of summaries) {
|
|
4449
|
+
const sessionId = summary.sessionId.trim();
|
|
4450
|
+
if (!sessionId) continue;
|
|
4451
|
+
const session = await this.getSession(sessionId);
|
|
4452
|
+
if (!session) continue;
|
|
4453
|
+
sessions.push(session);
|
|
4454
|
+
}
|
|
4455
|
+
sessions.sort((left, right) => readSessionActivityAt(right).localeCompare(readSessionActivityAt(left)));
|
|
4456
|
+
return sessions;
|
|
4457
|
+
};
|
|
4271
4458
|
saveSession = async (sessionRecord) => {
|
|
4272
|
-
|
|
4459
|
+
const journalStore = this.options.journalStore;
|
|
4460
|
+
if (journalStore && await journalStore.hasSession(sessionRecord.sessionId)) {
|
|
4461
|
+
await journalStore.replaceSession(sessionRecord);
|
|
4462
|
+
this.options.onSessionUpdated?.(sessionRecord.sessionId);
|
|
4463
|
+
return;
|
|
4464
|
+
}
|
|
4465
|
+
await this.legacyStore.saveSession(sessionRecord);
|
|
4273
4466
|
};
|
|
4274
4467
|
replaceSession = async (sessionRecord) => {
|
|
4275
|
-
|
|
4468
|
+
const journalStore = this.options.journalStore;
|
|
4469
|
+
if (journalStore && await journalStore.hasSession(sessionRecord.sessionId)) {
|
|
4470
|
+
await journalStore.replaceSession(sessionRecord);
|
|
4471
|
+
this.options.onSessionUpdated?.(sessionRecord.sessionId);
|
|
4472
|
+
return;
|
|
4473
|
+
}
|
|
4474
|
+
await this.legacyStore.replaceSession(sessionRecord);
|
|
4276
4475
|
};
|
|
4277
4476
|
deleteSession = async (sessionId) => {
|
|
4278
|
-
const
|
|
4279
|
-
|
|
4280
|
-
this.
|
|
4281
|
-
|
|
4477
|
+
const journalSession = await this.options.journalStore?.deleteSession(sessionId);
|
|
4478
|
+
const legacySession = this.legacyStore.deleteSession(sessionId);
|
|
4479
|
+
if (journalSession && !legacySession) this.options.onSessionUpdated?.(sessionId);
|
|
4480
|
+
return journalSession ?? legacySession;
|
|
4481
|
+
};
|
|
4482
|
+
};
|
|
4483
|
+
function readSummaryActivityAt(summary) {
|
|
4484
|
+
return summary.lastMessageAt ?? summary.createdAt ?? summary.updatedAt;
|
|
4485
|
+
}
|
|
4486
|
+
function isSessionSummaryRefreshEvent(event) {
|
|
4487
|
+
switch (event.type) {
|
|
4488
|
+
case NcpEventType.MessageSent:
|
|
4489
|
+
case NcpEventType.MessageCompleted:
|
|
4490
|
+
case NcpEventType.MessageAbort:
|
|
4491
|
+
case NcpEventType.RunFinished:
|
|
4492
|
+
case NcpEventType.RunError: return true;
|
|
4493
|
+
default: return false;
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
const NCP_AGENT_SESSION_JOURNAL_INDEX_FILE = ".ncp-agent-session-index.json";
|
|
4497
|
+
const AUTO_SESSION_LABEL_MAX_LENGTH = 64;
|
|
4498
|
+
function normalizeNcpSessionId(sessionId) {
|
|
4499
|
+
return sessionId.trim();
|
|
4500
|
+
}
|
|
4501
|
+
function safeNcpSessionFilename(value) {
|
|
4502
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4503
|
+
}
|
|
4504
|
+
function normalizeNcpAgentId(agentId) {
|
|
4505
|
+
const normalized = agentId?.trim().toLowerCase();
|
|
4506
|
+
return normalized ? normalized : void 0;
|
|
4507
|
+
}
|
|
4508
|
+
function isRecord(value) {
|
|
4509
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4510
|
+
}
|
|
4511
|
+
function toIsoString(value, fallback) {
|
|
4512
|
+
if (typeof value !== "string") return fallback;
|
|
4513
|
+
const parsed = Date.parse(value);
|
|
4514
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : fallback;
|
|
4515
|
+
}
|
|
4516
|
+
function createNcpAgentSessionSummary(record) {
|
|
4517
|
+
const metadata = structuredClone(record.metadata ?? {});
|
|
4518
|
+
const label = readOptionalText(metadata.label) ?? resolveAutoSessionLabel(record.messages);
|
|
4519
|
+
if (label) metadata.label = label;
|
|
4520
|
+
const lastMessageAt = readMessageTimestamp(record.messages.at(-1));
|
|
4521
|
+
return {
|
|
4522
|
+
sessionId: record.sessionId,
|
|
4523
|
+
...normalizeNcpAgentId(record.agentId) ? { agentId: normalizeNcpAgentId(record.agentId) } : {},
|
|
4524
|
+
messageCount: record.messages.length,
|
|
4525
|
+
...record.createdAt ? { createdAt: record.createdAt } : {},
|
|
4526
|
+
updatedAt: record.updatedAt,
|
|
4527
|
+
...lastMessageAt ? { lastMessageAt } : {},
|
|
4528
|
+
status: "idle",
|
|
4529
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
function createNcpAgentSessionJournalMetadataEntry(record) {
|
|
4533
|
+
return {
|
|
4534
|
+
_type: "metadata",
|
|
4535
|
+
version: 1,
|
|
4536
|
+
created_at: record.createdAt ?? record.updatedAt,
|
|
4537
|
+
updated_at: record.updatedAt,
|
|
4538
|
+
...normalizeNcpAgentId(record.agentId) ? { agent_id: normalizeNcpAgentId(record.agentId) } : {},
|
|
4539
|
+
metadata: structuredClone(record.metadata ?? {})
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4542
|
+
function upsertNcpAgentSessionSummaryEvent(params) {
|
|
4543
|
+
const { current, event, session, updatedAt } = params;
|
|
4544
|
+
const metadata = {
|
|
4545
|
+
...current?.metadata ? structuredClone(current.metadata) : {},
|
|
4546
|
+
...session.metadata ? structuredClone(session.metadata) : {}
|
|
4547
|
+
};
|
|
4548
|
+
const label = readOptionalText(metadata.label) ?? readSummaryLabelFromEvent(event);
|
|
4549
|
+
if (label) metadata.label = truncateLabel(label);
|
|
4550
|
+
const eventMessage = readMessageFromSummaryEvent(event);
|
|
4551
|
+
const messageCount = current ? current.messageCount + (eventMessage ? 1 : 0) : eventMessage ? 1 : 0;
|
|
4552
|
+
const lastMessageAt = readMessageTimestamp(eventMessage) ?? current?.lastMessageAt;
|
|
4553
|
+
return {
|
|
4554
|
+
sessionId: session.sessionId,
|
|
4555
|
+
...normalizeNcpAgentId(session.agentId ?? current?.agentId) ? { agentId: normalizeNcpAgentId(session.agentId ?? current?.agentId) } : {},
|
|
4556
|
+
messageCount,
|
|
4557
|
+
createdAt: current?.createdAt ?? session.createdAt ?? updatedAt,
|
|
4558
|
+
updatedAt,
|
|
4559
|
+
...lastMessageAt ? { lastMessageAt } : {},
|
|
4560
|
+
status: "idle",
|
|
4561
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
4562
|
+
};
|
|
4563
|
+
}
|
|
4564
|
+
async function replayNcpAgentSessionEvents(events) {
|
|
4565
|
+
const stateManager = new DefaultNcpAgentConversationStateManager();
|
|
4566
|
+
for (const event of events) await stateManager.dispatch(event.type === NcpEventType.MessageCompleted ? createCompletedMessageEvent(event) : structuredClone(event));
|
|
4567
|
+
const snapshot = stateManager.getSnapshot();
|
|
4568
|
+
return [...snapshot.messages.map((message) => structuredClone(message)), ...snapshot.streamingMessage ? [structuredClone(snapshot.streamingMessage)] : []];
|
|
4569
|
+
}
|
|
4570
|
+
function readNcpSessionSummaryActivityAt(summary) {
|
|
4571
|
+
return summary.lastMessageAt ?? summary.createdAt ?? summary.updatedAt;
|
|
4572
|
+
}
|
|
4573
|
+
function readMessageTimestamp(message) {
|
|
4574
|
+
return typeof message?.timestamp === "string" && Number.isFinite(Date.parse(message.timestamp)) ? new Date(message.timestamp).toISOString() : void 0;
|
|
4575
|
+
}
|
|
4576
|
+
function truncateLabel(value) {
|
|
4577
|
+
const chars = Array.from(value);
|
|
4578
|
+
return chars.length <= AUTO_SESSION_LABEL_MAX_LENGTH ? value : `${chars.slice(0, AUTO_SESSION_LABEL_MAX_LENGTH).join("")}...`;
|
|
4579
|
+
}
|
|
4580
|
+
function readOptionalText(value) {
|
|
4581
|
+
if (typeof value !== "string") return null;
|
|
4582
|
+
const trimmed = value.trim();
|
|
4583
|
+
return trimmed ? trimmed : null;
|
|
4584
|
+
}
|
|
4585
|
+
function resolveAutoSessionLabel(messages) {
|
|
4586
|
+
for (const message of messages) {
|
|
4587
|
+
if (message.role !== "user") continue;
|
|
4588
|
+
for (const part of message.parts) if (part.type === "text" || part.type === "rich-text") {
|
|
4589
|
+
const text = readOptionalText(part.text);
|
|
4590
|
+
if (text) return truncateLabel(text);
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
return null;
|
|
4594
|
+
}
|
|
4595
|
+
function readMessageFromSummaryEvent(event) {
|
|
4596
|
+
switch (event.type) {
|
|
4597
|
+
case NcpEventType.MessageSent: return event.payload.message;
|
|
4598
|
+
case NcpEventType.MessageCompleted: return event.payload.message;
|
|
4599
|
+
default: return;
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
function readSummaryLabelFromEvent(event) {
|
|
4603
|
+
const message = readMessageFromSummaryEvent(event);
|
|
4604
|
+
if (message?.role !== "user") return null;
|
|
4605
|
+
return resolveAutoSessionLabel([message]);
|
|
4606
|
+
}
|
|
4607
|
+
function createCompletedMessageEvent(event) {
|
|
4608
|
+
return {
|
|
4609
|
+
type: NcpEventType.MessageSent,
|
|
4610
|
+
payload: {
|
|
4611
|
+
sessionId: event.payload.sessionId,
|
|
4612
|
+
message: structuredClone(event.payload.message),
|
|
4613
|
+
...event.payload.correlationId ? { correlationId: event.payload.correlationId } : {},
|
|
4614
|
+
metadata: event.payload.metadata
|
|
4615
|
+
}
|
|
4616
|
+
};
|
|
4617
|
+
}
|
|
4618
|
+
//#endregion
|
|
4619
|
+
//#region src/stores/ncp-agent-session-journal.store.ts
|
|
4620
|
+
var NcpAgentSessionJournalStore = class {
|
|
4621
|
+
sessions = /* @__PURE__ */ new Map();
|
|
4622
|
+
nextSeqBySession = /* @__PURE__ */ new Map();
|
|
4623
|
+
writeChains = /* @__PURE__ */ new Map();
|
|
4624
|
+
summaryIndex = null;
|
|
4625
|
+
constructor(journalDir) {
|
|
4626
|
+
this.journalDir = journalDir;
|
|
4627
|
+
}
|
|
4628
|
+
appendSessionEvent = async (params) => {
|
|
4629
|
+
const sessionId = normalizeNcpSessionId(params.session.sessionId);
|
|
4630
|
+
if (!sessionId) return;
|
|
4631
|
+
const next = (this.writeChains.get(sessionId) ?? Promise.resolve()).then(() => this.appendSessionEventNow({
|
|
4632
|
+
...params,
|
|
4633
|
+
session: {
|
|
4634
|
+
...params.session,
|
|
4635
|
+
sessionId
|
|
4636
|
+
}
|
|
4637
|
+
}));
|
|
4638
|
+
this.writeChains.set(sessionId, next.catch(() => void 0));
|
|
4639
|
+
await next;
|
|
4640
|
+
};
|
|
4641
|
+
getSession = async (sessionId) => {
|
|
4642
|
+
const normalizedSessionId = normalizeNcpSessionId(sessionId);
|
|
4643
|
+
if (!normalizedSessionId) return null;
|
|
4644
|
+
const cached = this.sessions.get(normalizedSessionId);
|
|
4645
|
+
if (cached) return structuredClone(cached.record);
|
|
4646
|
+
const loaded = await this.loadSession(normalizedSessionId);
|
|
4647
|
+
if (!loaded) return null;
|
|
4648
|
+
this.sessions.set(normalizedSessionId, loaded);
|
|
4649
|
+
return structuredClone(loaded.record);
|
|
4650
|
+
};
|
|
4651
|
+
getSessionSummary = async (sessionId) => {
|
|
4652
|
+
const normalizedSessionId = normalizeNcpSessionId(sessionId);
|
|
4653
|
+
if (!normalizedSessionId) return null;
|
|
4654
|
+
const indexed = (await this.loadSummaryIndex()).get(normalizedSessionId);
|
|
4655
|
+
if (indexed) return structuredClone(indexed);
|
|
4656
|
+
const record = await this.getSession(normalizedSessionId);
|
|
4657
|
+
return record ? createNcpAgentSessionSummary(record) : null;
|
|
4658
|
+
};
|
|
4659
|
+
listSessionSummaries = async () => {
|
|
4660
|
+
return [...(await this.loadSummaryIndex()).values()].map((summary) => structuredClone(summary)).sort((left, right) => readNcpSessionSummaryActivityAt(right).localeCompare(readNcpSessionSummaryActivityAt(left)));
|
|
4661
|
+
};
|
|
4662
|
+
listSessionMessages = async (sessionId) => {
|
|
4663
|
+
const session = await this.getSession(sessionId);
|
|
4664
|
+
return session ? session.messages.map((message) => structuredClone(message)) : [];
|
|
4665
|
+
};
|
|
4666
|
+
replaceSession = async (record) => {
|
|
4667
|
+
const sessionId = normalizeNcpSessionId(record.sessionId);
|
|
4668
|
+
if (!sessionId) return;
|
|
4669
|
+
await this.ensureJournalDir();
|
|
4670
|
+
const nextRecord = structuredClone({
|
|
4671
|
+
...record,
|
|
4672
|
+
sessionId
|
|
4673
|
+
});
|
|
4674
|
+
const entries = [createNcpAgentSessionJournalMetadataEntry(nextRecord), ...nextRecord.messages.map((message, index) => ({
|
|
4675
|
+
_type: "event",
|
|
4676
|
+
version: 1,
|
|
4677
|
+
seq: index + 1,
|
|
4678
|
+
timestamp: message.timestamp ?? nextRecord.updatedAt,
|
|
4679
|
+
event: {
|
|
4680
|
+
type: NcpEventType.MessageSent,
|
|
4681
|
+
payload: {
|
|
4682
|
+
sessionId,
|
|
4683
|
+
message: structuredClone(message)
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
}))];
|
|
4687
|
+
await writeFile(this.sessionPath(sessionId), `${entries.map((entry) => JSON.stringify(entry)).join("\n")}\n`, "utf-8");
|
|
4688
|
+
const nextSeq = nextRecord.messages.length + 1;
|
|
4689
|
+
this.sessions.set(sessionId, {
|
|
4690
|
+
record: nextRecord,
|
|
4691
|
+
nextSeq
|
|
4692
|
+
});
|
|
4693
|
+
this.nextSeqBySession.set(sessionId, nextSeq);
|
|
4694
|
+
await this.upsertSummaryIndex(createNcpAgentSessionSummary(nextRecord));
|
|
4695
|
+
};
|
|
4696
|
+
deleteSession = async (sessionId) => {
|
|
4697
|
+
const normalizedSessionId = normalizeNcpSessionId(sessionId);
|
|
4698
|
+
if (!normalizedSessionId) return null;
|
|
4699
|
+
const existing = await this.getSession(normalizedSessionId);
|
|
4700
|
+
this.sessions.delete(normalizedSessionId);
|
|
4701
|
+
this.nextSeqBySession.delete(normalizedSessionId);
|
|
4702
|
+
try {
|
|
4703
|
+
await unlink(this.sessionPath(normalizedSessionId));
|
|
4704
|
+
} catch {}
|
|
4705
|
+
await this.removeSummaryIndex(normalizedSessionId);
|
|
4282
4706
|
return existing;
|
|
4283
4707
|
};
|
|
4708
|
+
hasSession = async (sessionId) => {
|
|
4709
|
+
const normalizedSessionId = normalizeNcpSessionId(sessionId);
|
|
4710
|
+
if (!normalizedSessionId) return false;
|
|
4711
|
+
return (await this.loadSummaryIndex()).has(normalizedSessionId);
|
|
4712
|
+
};
|
|
4713
|
+
appendSessionEventNow = async (params) => {
|
|
4714
|
+
const { event, session, updatedAt } = params;
|
|
4715
|
+
const { sessionId } = session;
|
|
4716
|
+
await this.ensureJournalDir();
|
|
4717
|
+
const existing = this.sessions.get(sessionId) ?? (this.nextSeqBySession.has(sessionId) ? null : await this.loadSession(sessionId));
|
|
4718
|
+
const hasJournal = Boolean(existing) || this.nextSeqBySession.has(sessionId);
|
|
4719
|
+
const nextSeq = this.nextSeqBySession.get(sessionId) ?? existing?.nextSeq ?? 1;
|
|
4720
|
+
const path = this.sessionPath(sessionId);
|
|
4721
|
+
if (!hasJournal) await appendFile(path, `${JSON.stringify(createNcpAgentSessionJournalMetadataEntry(session))}\n`, "utf-8");
|
|
4722
|
+
const entry = {
|
|
4723
|
+
_type: "event",
|
|
4724
|
+
version: 1,
|
|
4725
|
+
seq: nextSeq,
|
|
4726
|
+
timestamp: updatedAt,
|
|
4727
|
+
event: structuredClone(event)
|
|
4728
|
+
};
|
|
4729
|
+
await appendFile(path, `${JSON.stringify(entry)}\n`, "utf-8");
|
|
4730
|
+
this.nextSeqBySession.set(sessionId, nextSeq + 1);
|
|
4731
|
+
this.sessions.delete(sessionId);
|
|
4732
|
+
await this.upsertSummaryIndexForEvent({
|
|
4733
|
+
session,
|
|
4734
|
+
event,
|
|
4735
|
+
updatedAt
|
|
4736
|
+
});
|
|
4737
|
+
};
|
|
4738
|
+
loadSession = async (sessionId) => {
|
|
4739
|
+
let raw;
|
|
4740
|
+
try {
|
|
4741
|
+
raw = await readFile(this.sessionPath(sessionId), "utf-8");
|
|
4742
|
+
} catch {
|
|
4743
|
+
return null;
|
|
4744
|
+
}
|
|
4745
|
+
const { agentId, createdAt, events, metadata, nextSeq, updatedAt } = this.parseSessionJournal(raw);
|
|
4746
|
+
const messages = await replayNcpAgentSessionEvents(events);
|
|
4747
|
+
const record = {
|
|
4748
|
+
sessionId,
|
|
4749
|
+
...agentId ? { agentId } : {},
|
|
4750
|
+
messages,
|
|
4751
|
+
createdAt,
|
|
4752
|
+
updatedAt,
|
|
4753
|
+
metadata
|
|
4754
|
+
};
|
|
4755
|
+
this.nextSeqBySession.set(sessionId, nextSeq);
|
|
4756
|
+
return {
|
|
4757
|
+
record,
|
|
4758
|
+
nextSeq
|
|
4759
|
+
};
|
|
4760
|
+
};
|
|
4761
|
+
parseSessionJournal = (raw) => {
|
|
4762
|
+
let metadata = {};
|
|
4763
|
+
let agentId;
|
|
4764
|
+
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4765
|
+
let updatedAt = createdAt;
|
|
4766
|
+
let nextSeq = 1;
|
|
4767
|
+
const events = [];
|
|
4768
|
+
for (const line of raw.split("\n")) {
|
|
4769
|
+
if (!line.trim()) continue;
|
|
4770
|
+
const parsed = JSON.parse(line);
|
|
4771
|
+
if (!isRecord(parsed)) continue;
|
|
4772
|
+
if (parsed._type === "metadata") {
|
|
4773
|
+
metadata = isRecord(parsed.metadata) ? structuredClone(parsed.metadata) : {};
|
|
4774
|
+
agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
|
|
4775
|
+
createdAt = toIsoString(parsed.created_at, createdAt);
|
|
4776
|
+
updatedAt = toIsoString(parsed.updated_at, updatedAt);
|
|
4777
|
+
continue;
|
|
4778
|
+
}
|
|
4779
|
+
if (parsed._type === "event" && isRecord(parsed.event)) {
|
|
4780
|
+
const seq = Number(parsed.seq);
|
|
4781
|
+
nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
|
|
4782
|
+
updatedAt = toIsoString(parsed.timestamp, updatedAt);
|
|
4783
|
+
events.push(structuredClone(parsed.event));
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4786
|
+
return {
|
|
4787
|
+
metadata,
|
|
4788
|
+
...agentId ? { agentId } : {},
|
|
4789
|
+
createdAt,
|
|
4790
|
+
updatedAt,
|
|
4791
|
+
nextSeq,
|
|
4792
|
+
events
|
|
4793
|
+
};
|
|
4794
|
+
};
|
|
4795
|
+
loadSummaryIndex = async () => {
|
|
4796
|
+
if (this.summaryIndex) return this.summaryIndex;
|
|
4797
|
+
try {
|
|
4798
|
+
const parsed = JSON.parse(await readFile(this.indexPath(), "utf-8"));
|
|
4799
|
+
if (parsed.version === 1 && Array.isArray(parsed.records)) {
|
|
4800
|
+
this.summaryIndex = new Map(parsed.records.map((record) => [record.sessionId, structuredClone(record)]));
|
|
4801
|
+
return this.summaryIndex;
|
|
4802
|
+
}
|
|
4803
|
+
} catch {}
|
|
4804
|
+
this.summaryIndex = await this.rebuildSummaryIndex();
|
|
4805
|
+
await this.persistSummaryIndex();
|
|
4806
|
+
return this.summaryIndex;
|
|
4807
|
+
};
|
|
4808
|
+
rebuildSummaryIndex = async () => {
|
|
4809
|
+
const records = /* @__PURE__ */ new Map();
|
|
4810
|
+
let entries = [];
|
|
4811
|
+
try {
|
|
4812
|
+
entries = await readdir(this.journalDir);
|
|
4813
|
+
} catch {
|
|
4814
|
+
return records;
|
|
4815
|
+
}
|
|
4816
|
+
for (const entry of entries) {
|
|
4817
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
4818
|
+
const sessionId = entry.replace(/\.jsonl$/, "").replace(/_/g, ":");
|
|
4819
|
+
const loaded = await this.loadSession(sessionId);
|
|
4820
|
+
if (!loaded) continue;
|
|
4821
|
+
this.sessions.set(sessionId, loaded);
|
|
4822
|
+
records.set(sessionId, createNcpAgentSessionSummary(loaded.record));
|
|
4823
|
+
}
|
|
4824
|
+
return records;
|
|
4825
|
+
};
|
|
4826
|
+
upsertSummaryIndex = async (summary) => {
|
|
4827
|
+
(await this.loadSummaryIndex()).set(summary.sessionId, structuredClone(summary));
|
|
4828
|
+
await this.persistSummaryIndex();
|
|
4829
|
+
};
|
|
4830
|
+
upsertSummaryIndexForEvent = async (params) => {
|
|
4831
|
+
const { event, session, updatedAt } = params;
|
|
4832
|
+
const index = await this.loadSummaryIndex();
|
|
4833
|
+
const summary = upsertNcpAgentSessionSummaryEvent({
|
|
4834
|
+
current: index.get(session.sessionId),
|
|
4835
|
+
session,
|
|
4836
|
+
event,
|
|
4837
|
+
updatedAt
|
|
4838
|
+
});
|
|
4839
|
+
index.set(summary.sessionId, summary);
|
|
4840
|
+
await this.persistSummaryIndex();
|
|
4841
|
+
};
|
|
4842
|
+
removeSummaryIndex = async (sessionId) => {
|
|
4843
|
+
(await this.loadSummaryIndex()).delete(sessionId);
|
|
4844
|
+
await this.persistSummaryIndex();
|
|
4845
|
+
};
|
|
4846
|
+
persistSummaryIndex = async () => {
|
|
4847
|
+
const records = [...this.summaryIndex?.values() ?? []].map((summary) => structuredClone(summary)).sort((left, right) => readNcpSessionSummaryActivityAt(right).localeCompare(readNcpSessionSummaryActivityAt(left)));
|
|
4848
|
+
await this.ensureJournalDir();
|
|
4849
|
+
await writeFile(this.indexPath(), `${JSON.stringify({
|
|
4850
|
+
version: 1,
|
|
4851
|
+
records
|
|
4852
|
+
})}\n`, "utf-8");
|
|
4853
|
+
};
|
|
4854
|
+
ensureJournalDir = async () => {
|
|
4855
|
+
await mkdir(this.journalDir, { recursive: true });
|
|
4856
|
+
};
|
|
4857
|
+
sessionPath = (sessionId) => {
|
|
4858
|
+
return join(this.journalDir, `${safeNcpSessionFilename(sessionId.replace(/:/g, "_"))}.jsonl`);
|
|
4859
|
+
};
|
|
4860
|
+
indexPath = () => resolve(this.journalDir, NCP_AGENT_SESSION_JOURNAL_INDEX_FILE);
|
|
4284
4861
|
};
|
|
4285
4862
|
//#endregion
|
|
4286
4863
|
//#region src/app/nextclaw-kernel.ts
|
|
@@ -4326,6 +4903,7 @@ var NextclawKernel = class {
|
|
|
4326
4903
|
learningLoop;
|
|
4327
4904
|
sessionLifecycleEvents;
|
|
4328
4905
|
ncpAgentSessionStore;
|
|
4906
|
+
ncpAgentSessionJournalStore;
|
|
4329
4907
|
startPromise = null;
|
|
4330
4908
|
constructor(options = {}) {
|
|
4331
4909
|
const sessionsDir = resolveKernelSessionsDir(options);
|
|
@@ -4336,7 +4914,11 @@ var NextclawKernel = class {
|
|
|
4336
4914
|
sessionsDir,
|
|
4337
4915
|
onSessionUpdated: this.publishSessionUpdated
|
|
4338
4916
|
});
|
|
4339
|
-
this.
|
|
4917
|
+
this.ncpAgentSessionJournalStore = new NcpAgentSessionJournalStore(resolve(sessionsDir, ".ncp-agent-journal"));
|
|
4918
|
+
this.ncpAgentSessionStore = new NcpAgentSessionStoreAdapter(this.sessions, {
|
|
4919
|
+
journalStore: this.ncpAgentSessionJournalStore,
|
|
4920
|
+
onSessionUpdated: this.sessionSearch.handleSessionUpdated
|
|
4921
|
+
});
|
|
4340
4922
|
this.sessionRequests = new SessionRequestManager({
|
|
4341
4923
|
sessions: this.sessions,
|
|
4342
4924
|
dispatcher: createAgentRuntimeSessionRequestDispatcher({
|
|
@@ -4363,6 +4945,7 @@ var NextclawKernel = class {
|
|
|
4363
4945
|
this.ncpSessionApi = new NcpSessionApiService({
|
|
4364
4946
|
eventBus: this.eventBus,
|
|
4365
4947
|
getConfig: this.configManager.loadConfig,
|
|
4948
|
+
ncpAgentSessionStore: this.ncpAgentSessionStore,
|
|
4366
4949
|
sessionManager: this.sessions
|
|
4367
4950
|
});
|
|
4368
4951
|
this.agentRuntimeManager = new AgentRuntimeManager({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/kernel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "NextClaw product kernel skeleton for agents, tasks, sessions, context, tools, skills, providers, automation, and channels.",
|
|
6
6
|
"type": "module",
|
|
@@ -20,19 +20,19 @@
|
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@nextclaw/
|
|
24
|
-
"@nextclaw/
|
|
25
|
-
"@nextclaw/
|
|
26
|
-
"@nextclaw/ncp-
|
|
27
|
-
"@nextclaw/ncp-mcp": "0.1.
|
|
28
|
-
"@nextclaw/ncp-toolkit": "0.5.
|
|
29
|
-
"@nextclaw/nextclaw-
|
|
30
|
-
"@nextclaw/nextclaw-ncp-runtime-
|
|
31
|
-
"@nextclaw/nextclaw-
|
|
32
|
-
"@nextclaw/openclaw-compat": "1.0.
|
|
33
|
-
"@nextclaw/
|
|
34
|
-
"@nextclaw/
|
|
35
|
-
"@nextclaw/ncp": "0.5.
|
|
23
|
+
"@nextclaw/core": "0.12.16",
|
|
24
|
+
"@nextclaw/ncp-http-agent-server": "0.3.21",
|
|
25
|
+
"@nextclaw/mcp": "0.1.81",
|
|
26
|
+
"@nextclaw/ncp-agent-runtime": "0.3.19",
|
|
27
|
+
"@nextclaw/ncp-mcp": "0.1.83",
|
|
28
|
+
"@nextclaw/ncp-toolkit": "0.5.14",
|
|
29
|
+
"@nextclaw/nextclaw-ncp-runtime-http-client": "0.1.8",
|
|
30
|
+
"@nextclaw/nextclaw-ncp-runtime-stdio-client": "0.1.9",
|
|
31
|
+
"@nextclaw/nextclaw-hermes-acp-bridge": "0.1.8",
|
|
32
|
+
"@nextclaw/openclaw-compat": "1.0.16",
|
|
33
|
+
"@nextclaw/shared": "0.1.3",
|
|
34
|
+
"@nextclaw/runtime": "0.2.48",
|
|
35
|
+
"@nextclaw/ncp": "0.5.9"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^20.17.6",
|