@nextclaw/kernel 0.1.5 → 0.1.6
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 +4 -1
- package/dist/index.js +263 -77
- package/package.json +14 -14
package/dist/index.d.ts
CHANGED
|
@@ -494,6 +494,7 @@ declare class AgentRuntimeManager {
|
|
|
494
494
|
private disposed;
|
|
495
495
|
constructor(params: AgentRuntimeManagerOptions);
|
|
496
496
|
get currentHandle(): AgentRuntimeHandle | null;
|
|
497
|
+
isLiveSessionRunning: (sessionId: string) => boolean;
|
|
497
498
|
connectGatewayController: (gatewayController: GatewayController) => void;
|
|
498
499
|
bootstrap: () => Promise<AgentRuntimeHandle>;
|
|
499
500
|
private readonly materializeAgentSendEnvelope;
|
|
@@ -663,6 +664,7 @@ type NcpAgentSessionReadableStore = AgentSessionStore & {
|
|
|
663
664
|
type NcpSessionApiServiceOptions = {
|
|
664
665
|
eventBus: EventBus;
|
|
665
666
|
getConfig: () => Config;
|
|
667
|
+
isLiveSessionRunning?: (sessionId: string) => boolean;
|
|
666
668
|
ncpAgentSessionStore?: NcpAgentSessionReadableStore;
|
|
667
669
|
sessionManager: SessionManager;
|
|
668
670
|
};
|
|
@@ -679,6 +681,7 @@ declare class NcpSessionApiService implements NcpSessionApi {
|
|
|
679
681
|
getSession: (sessionId: string) => Promise<NcpSessionSummary | null>;
|
|
680
682
|
updateSession: (sessionId: string, patch: NcpSessionPatch) => Promise<NcpSessionSummary | null>;
|
|
681
683
|
deleteSession: (sessionId: string) => Promise<void>;
|
|
684
|
+
private withLiveSessionStatus;
|
|
682
685
|
}
|
|
683
686
|
//#endregion
|
|
684
687
|
//#region src/app/nextclaw-kernel.d.ts
|
|
@@ -722,7 +725,7 @@ declare class NextclawKernel {
|
|
|
722
725
|
private readonly sessionLifecycleEvents;
|
|
723
726
|
private readonly ncpAgentSessionStore;
|
|
724
727
|
private readonly ncpAgentSessionJournalStore;
|
|
725
|
-
private
|
|
728
|
+
private readonly contributions;
|
|
726
729
|
constructor(options?: NextclawKernelOptions);
|
|
727
730
|
start: () => Promise<void>;
|
|
728
731
|
dispose: () => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -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$5(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$5(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$4(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$4(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$4(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$4(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$4(args.path);
|
|
2000
|
+
const bytesBase64 = readOptionalString$4(args.bytesBase64);
|
|
2001
|
+
const fileName = readOptionalString$4(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$4(args?.path);
|
|
2009
|
+
const fileName = readOptionalString$4(args?.fileName);
|
|
2010
|
+
const mimeType = readOptionalString$4(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$4(args?.assetUri);
|
|
2054
|
+
const targetPath = readOptionalString$4(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$4(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$3(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$3(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$3(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$
|
|
2337
|
+
function readOptionalString$2(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$
|
|
2343
|
+
const normalized = readOptionalString$2(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$
|
|
2351
|
+
const notifyMode = readOptionalString$2(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$
|
|
2433
|
-
agentId: readOptionalString$
|
|
2434
|
-
model: readOptionalString$
|
|
2435
|
-
runtime: readOptionalString$
|
|
2432
|
+
title: readOptionalString$2(rawTitle),
|
|
2433
|
+
agentId: readOptionalString$2(rawAgentId),
|
|
2434
|
+
model: readOptionalString$2(rawModel),
|
|
2435
|
+
runtime: readOptionalString$2(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$
|
|
2443
|
+
title: readOptionalString$2(rawTitle),
|
|
2444
2444
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
2445
|
-
agentId: readOptionalString$
|
|
2446
|
-
model: readOptionalString$
|
|
2447
|
-
runtime: readOptionalString$
|
|
2445
|
+
agentId: readOptionalString$2(rawAgentId),
|
|
2446
|
+
model: readOptionalString$2(rawModel),
|
|
2447
|
+
runtime: readOptionalString$2(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$5(args)) return args;
|
|
2473
2473
|
if (typeof args === "string") try {
|
|
2474
2474
|
const parsed = JSON.parse(args);
|
|
2475
|
-
return isRecord$
|
|
2475
|
+
return isRecord$5(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$3(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$3(message.metadata))?.metadata;
|
|
2672
2672
|
return {
|
|
2673
|
-
...isRecord$
|
|
2674
|
-
...isRecord$
|
|
2673
|
+
...isRecord$3(messageMetadata) ? structuredClone(messageMetadata) : {},
|
|
2674
|
+
...isRecord$3(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$
|
|
2981
|
+
function isRecord$2(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$
|
|
2986
|
+
const runtimeMetadata = isRecord$2(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,7 +3240,7 @@ function createAgentRuntimeSessionRequestDispatcher(options) {
|
|
|
3240
3240
|
}
|
|
3241
3241
|
//#endregion
|
|
3242
3242
|
//#region src/managers/agent-runtime.manager.ts
|
|
3243
|
-
function readOptionalString(value) {
|
|
3243
|
+
function readOptionalString$1(value) {
|
|
3244
3244
|
if (typeof value !== "string") return null;
|
|
3245
3245
|
const trimmed = value.trim();
|
|
3246
3246
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -3251,7 +3251,7 @@ function readMessageTask(message) {
|
|
|
3251
3251
|
}
|
|
3252
3252
|
function readSessionMetadataString(metadata, ...keys) {
|
|
3253
3253
|
for (const key of keys) {
|
|
3254
|
-
const value = readOptionalString(metadata?.[key]);
|
|
3254
|
+
const value = readOptionalString$1(metadata?.[key]);
|
|
3255
3255
|
if (value) return value;
|
|
3256
3256
|
}
|
|
3257
3257
|
}
|
|
@@ -3286,6 +3286,7 @@ var AgentRuntimeManager = class {
|
|
|
3286
3286
|
get currentHandle() {
|
|
3287
3287
|
return this.handle;
|
|
3288
3288
|
}
|
|
3289
|
+
isLiveSessionRunning = (sessionId) => this.backend?.isLiveSessionRunning(sessionId) ?? false;
|
|
3289
3290
|
connectGatewayController = (gatewayController) => {
|
|
3290
3291
|
this.assertNotDisposed();
|
|
3291
3292
|
this.gatewayController = gatewayController;
|
|
@@ -3350,7 +3351,7 @@ var AgentRuntimeManager = class {
|
|
|
3350
3351
|
return this.handle;
|
|
3351
3352
|
};
|
|
3352
3353
|
materializeAgentSendEnvelope = (envelope) => {
|
|
3353
|
-
const existingSessionId = readOptionalString(envelope.sessionId) ?? readOptionalString(envelope.message.sessionId);
|
|
3354
|
+
const existingSessionId = readOptionalString$1(envelope.sessionId) ?? readOptionalString$1(envelope.message.sessionId);
|
|
3354
3355
|
if (existingSessionId) return {
|
|
3355
3356
|
...envelope,
|
|
3356
3357
|
sessionId: existingSessionId,
|
|
@@ -4182,13 +4183,6 @@ function buildUpdatedMetadata(params) {
|
|
|
4182
4183
|
function normalizeSessionId(sessionId) {
|
|
4183
4184
|
return sessionId.trim();
|
|
4184
4185
|
}
|
|
4185
|
-
function toSessionCandidate(record) {
|
|
4186
|
-
const sessionId = normalizeSessionId(record.key);
|
|
4187
|
-
return sessionId ? {
|
|
4188
|
-
...record,
|
|
4189
|
-
sessionId
|
|
4190
|
-
} : null;
|
|
4191
|
-
}
|
|
4192
4186
|
function createSessionListSummary(record) {
|
|
4193
4187
|
return {
|
|
4194
4188
|
sessionId: record.sessionId,
|
|
@@ -4201,9 +4195,6 @@ function createSessionListSummary(record) {
|
|
|
4201
4195
|
metadata: structuredClone(record.metadata)
|
|
4202
4196
|
};
|
|
4203
4197
|
}
|
|
4204
|
-
function readSessionActivityAt$1(record) {
|
|
4205
|
-
return record.lastMessageAt ?? record.created_at;
|
|
4206
|
-
}
|
|
4207
4198
|
var NcpSessionApiService = class {
|
|
4208
4199
|
unsubscribeSessionUpdated = null;
|
|
4209
4200
|
contextWindowPreview;
|
|
@@ -4237,8 +4228,11 @@ var NcpSessionApiService = class {
|
|
|
4237
4228
|
this.options.eventBus.emit(eventKeys.sessionSummaryDelete, { sessionKey: normalizedSessionKey });
|
|
4238
4229
|
};
|
|
4239
4230
|
listSessions = async (options) => {
|
|
4240
|
-
if (this.options.ncpAgentSessionStore?.listSessionSummaries) return applyLimit(await this.options.ncpAgentSessionStore.listSessionSummaries(), options?.limit);
|
|
4241
|
-
return applyLimit(this.options.sessionManager.listSessions().map(
|
|
4231
|
+
if (this.options.ncpAgentSessionStore?.listSessionSummaries) return applyLimit(await this.options.ncpAgentSessionStore.listSessionSummaries(), options?.limit).map(this.withLiveSessionStatus);
|
|
4232
|
+
return applyLimit(this.options.sessionManager.listSessions().map((record) => ({
|
|
4233
|
+
...record,
|
|
4234
|
+
sessionId: normalizeSessionId(record.key)
|
|
4235
|
+
})).filter((record) => Boolean(record)).sort((left, right) => (right.lastMessageAt ?? right.created_at).localeCompare(left.lastMessageAt ?? left.created_at)), options?.limit).map(createSessionListSummary).map(this.withLiveSessionStatus);
|
|
4242
4236
|
};
|
|
4243
4237
|
listSessionMessages = async (sessionId, options) => {
|
|
4244
4238
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
@@ -4251,7 +4245,7 @@ var NcpSessionApiService = class {
|
|
|
4251
4245
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
4252
4246
|
if (normalizedSessionId && this.options.ncpAgentSessionStore?.getSession) {
|
|
4253
4247
|
const record = await this.options.ncpAgentSessionStore.getSession(normalizedSessionId);
|
|
4254
|
-
if (record) return createNcpSessionSummary({
|
|
4248
|
+
if (record) return this.withLiveSessionStatus(createNcpSessionSummary({
|
|
4255
4249
|
sessionId: normalizedSessionId,
|
|
4256
4250
|
agentId: record.agentId,
|
|
4257
4251
|
messages: record.messages,
|
|
@@ -4265,12 +4259,12 @@ var NcpSessionApiService = class {
|
|
|
4265
4259
|
sessionId: normalizedSessionId,
|
|
4266
4260
|
sessionMessages: record.messages
|
|
4267
4261
|
})
|
|
4268
|
-
});
|
|
4262
|
+
}));
|
|
4269
4263
|
}
|
|
4270
4264
|
const session = normalizedSessionId ? this.options.sessionManager.getIfExists(normalizedSessionId) : null;
|
|
4271
4265
|
if (!session) return null;
|
|
4272
4266
|
const messages = toNcpMessages(normalizedSessionId, session.messages);
|
|
4273
|
-
return createNcpSessionSummary({
|
|
4267
|
+
return this.withLiveSessionStatus(createNcpSessionSummary({
|
|
4274
4268
|
sessionId: normalizedSessionId,
|
|
4275
4269
|
agentId: session.agentId,
|
|
4276
4270
|
messages,
|
|
@@ -4284,7 +4278,7 @@ var NcpSessionApiService = class {
|
|
|
4284
4278
|
sessionId: normalizedSessionId,
|
|
4285
4279
|
sessionMessages: messages
|
|
4286
4280
|
})
|
|
4287
|
-
});
|
|
4281
|
+
}));
|
|
4288
4282
|
};
|
|
4289
4283
|
updateSession = async (sessionId, patch) => {
|
|
4290
4284
|
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
@@ -4321,6 +4315,10 @@ var NcpSessionApiService = class {
|
|
|
4321
4315
|
this.options.sessionManager.delete(normalizedSessionId);
|
|
4322
4316
|
await this.publishSessionChange(normalizedSessionId);
|
|
4323
4317
|
};
|
|
4318
|
+
withLiveSessionStatus = (summary) => this.options.isLiveSessionRunning?.(summary.sessionId) ? {
|
|
4319
|
+
...summary,
|
|
4320
|
+
status: "running"
|
|
4321
|
+
} : summary;
|
|
4324
4322
|
};
|
|
4325
4323
|
//#endregion
|
|
4326
4324
|
//#region src/utils/ncp-session-metadata.utils.ts
|
|
@@ -4505,7 +4503,7 @@ function normalizeNcpAgentId(agentId) {
|
|
|
4505
4503
|
const normalized = agentId?.trim().toLowerCase();
|
|
4506
4504
|
return normalized ? normalized : void 0;
|
|
4507
4505
|
}
|
|
4508
|
-
function isRecord(value) {
|
|
4506
|
+
function isRecord$1(value) {
|
|
4509
4507
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4510
4508
|
}
|
|
4511
4509
|
function toIsoString(value, fallback) {
|
|
@@ -4768,15 +4766,15 @@ var NcpAgentSessionJournalStore = class {
|
|
|
4768
4766
|
for (const line of raw.split("\n")) {
|
|
4769
4767
|
if (!line.trim()) continue;
|
|
4770
4768
|
const parsed = JSON.parse(line);
|
|
4771
|
-
if (!isRecord(parsed)) continue;
|
|
4769
|
+
if (!isRecord$1(parsed)) continue;
|
|
4772
4770
|
if (parsed._type === "metadata") {
|
|
4773
|
-
metadata = isRecord(parsed.metadata) ? structuredClone(parsed.metadata) : {};
|
|
4771
|
+
metadata = isRecord$1(parsed.metadata) ? structuredClone(parsed.metadata) : {};
|
|
4774
4772
|
agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
|
|
4775
4773
|
createdAt = toIsoString(parsed.created_at, createdAt);
|
|
4776
4774
|
updatedAt = toIsoString(parsed.updated_at, updatedAt);
|
|
4777
4775
|
continue;
|
|
4778
4776
|
}
|
|
4779
|
-
if (parsed._type === "event" && isRecord(parsed.event)) {
|
|
4777
|
+
if (parsed._type === "event" && isRecord$1(parsed.event)) {
|
|
4780
4778
|
const seq = Number(parsed.seq);
|
|
4781
4779
|
nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
|
|
4782
4780
|
updatedAt = toIsoString(parsed.timestamp, updatedAt);
|
|
@@ -4860,6 +4858,196 @@ var NcpAgentSessionJournalStore = class {
|
|
|
4860
4858
|
indexPath = () => resolve(this.journalDir, NCP_AGENT_SESSION_JOURNAL_INDEX_FILE);
|
|
4861
4859
|
};
|
|
4862
4860
|
//#endregion
|
|
4861
|
+
//#region src/contributions/session-activity-preview/utils/session-activity-preview-ncp-event.utils.ts
|
|
4862
|
+
const PREVIEW_TEXT_MAX_LENGTH = 160;
|
|
4863
|
+
function readSessionId(value) {
|
|
4864
|
+
if (typeof value !== "string") return null;
|
|
4865
|
+
const trimmed = value.trim();
|
|
4866
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
4867
|
+
}
|
|
4868
|
+
function compactPreviewText(value) {
|
|
4869
|
+
return value.replace(/\s+/g, " ").trim();
|
|
4870
|
+
}
|
|
4871
|
+
function truncatePreviewText(value) {
|
|
4872
|
+
const compacted = compactPreviewText(value);
|
|
4873
|
+
if (compacted.length <= PREVIEW_TEXT_MAX_LENGTH) return compacted;
|
|
4874
|
+
return compacted.slice(0, PREVIEW_TEXT_MAX_LENGTH - 1).trimEnd();
|
|
4875
|
+
}
|
|
4876
|
+
function readMessagePreviewText(message) {
|
|
4877
|
+
const chunks = [];
|
|
4878
|
+
for (const part of message.parts) if ((part.type === "text" || part.type === "rich-text") && part.text.trim()) chunks.push(part.text);
|
|
4879
|
+
const previewText = truncatePreviewText(chunks.join(" "));
|
|
4880
|
+
return previewText.length > 0 ? previewText : null;
|
|
4881
|
+
}
|
|
4882
|
+
function createProjection(sessionId, preview) {
|
|
4883
|
+
if (!sessionId) return null;
|
|
4884
|
+
return {
|
|
4885
|
+
sessionId,
|
|
4886
|
+
preview
|
|
4887
|
+
};
|
|
4888
|
+
}
|
|
4889
|
+
function formatErrorStatus(error) {
|
|
4890
|
+
if (typeof error === "string" && error.trim()) return `运行出错:${truncatePreviewText(error)}`;
|
|
4891
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
4892
|
+
const message = error.message;
|
|
4893
|
+
if (typeof message === "string" && message.trim()) return `运行出错:${truncatePreviewText(message)}`;
|
|
4894
|
+
}
|
|
4895
|
+
return "运行出错";
|
|
4896
|
+
}
|
|
4897
|
+
function createSessionActivityPreviewFromNcpEvent(event, timestamp) {
|
|
4898
|
+
switch (event.type) {
|
|
4899
|
+
case NcpEventType.RunStarted: return createProjection(readSessionId(event.payload.sessionId), {
|
|
4900
|
+
state: "running",
|
|
4901
|
+
statusText: "正在处理...",
|
|
4902
|
+
timestamp
|
|
4903
|
+
});
|
|
4904
|
+
case NcpEventType.RunFinished: return createProjection(readSessionId(event.payload.sessionId), {
|
|
4905
|
+
state: "completed",
|
|
4906
|
+
timestamp
|
|
4907
|
+
});
|
|
4908
|
+
case NcpEventType.RunError: return createProjection(readSessionId(event.payload.sessionId), {
|
|
4909
|
+
state: "failed",
|
|
4910
|
+
statusText: formatErrorStatus(event.payload.error),
|
|
4911
|
+
timestamp
|
|
4912
|
+
});
|
|
4913
|
+
case NcpEventType.MessageSent: {
|
|
4914
|
+
const text = readMessagePreviewText(event.payload.message);
|
|
4915
|
+
if (!text || event.payload.message.role !== "user") return null;
|
|
4916
|
+
return createProjection(readSessionId(event.payload.sessionId), {
|
|
4917
|
+
state: "running",
|
|
4918
|
+
statusText: text,
|
|
4919
|
+
timestamp: event.payload.message.timestamp || timestamp
|
|
4920
|
+
});
|
|
4921
|
+
}
|
|
4922
|
+
case NcpEventType.MessageCompleted: {
|
|
4923
|
+
const text = readMessagePreviewText(event.payload.message);
|
|
4924
|
+
if (!text || event.payload.message.role !== "assistant") return null;
|
|
4925
|
+
return createProjection(readSessionId(event.payload.sessionId), {
|
|
4926
|
+
state: "completed",
|
|
4927
|
+
replyText: text,
|
|
4928
|
+
timestamp: event.payload.message.timestamp || timestamp
|
|
4929
|
+
});
|
|
4930
|
+
}
|
|
4931
|
+
case NcpEventType.MessageFailed: return createProjection(readSessionId(event.payload.sessionId), {
|
|
4932
|
+
state: "failed",
|
|
4933
|
+
statusText: formatErrorStatus(event.payload.error),
|
|
4934
|
+
timestamp
|
|
4935
|
+
});
|
|
4936
|
+
case NcpEventType.MessageToolCallStart: return createProjection(readSessionId(event.payload.sessionId), {
|
|
4937
|
+
state: "running",
|
|
4938
|
+
statusText: `正在调用工具:${event.payload.toolName}`,
|
|
4939
|
+
timestamp
|
|
4940
|
+
});
|
|
4941
|
+
case NcpEventType.MessageToolCallEnd:
|
|
4942
|
+
case NcpEventType.MessageToolCallResult: return createProjection(readSessionId(event.payload.sessionId), {
|
|
4943
|
+
state: "running",
|
|
4944
|
+
statusText: "工具调用完成",
|
|
4945
|
+
timestamp
|
|
4946
|
+
});
|
|
4947
|
+
default: return null;
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
//#endregion
|
|
4951
|
+
//#region src/contributions/session-activity-preview/utils/session-activity-preview-metadata.utils.ts
|
|
4952
|
+
const SESSION_ACTIVITY_PREVIEW_METADATA_KEY = "last_activity_preview";
|
|
4953
|
+
const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
|
|
4954
|
+
"running",
|
|
4955
|
+
"completed",
|
|
4956
|
+
"failed",
|
|
4957
|
+
"idle"
|
|
4958
|
+
]);
|
|
4959
|
+
function isRecord(value) {
|
|
4960
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4961
|
+
}
|
|
4962
|
+
function readOptionalString(value) {
|
|
4963
|
+
if (typeof value !== "string") return;
|
|
4964
|
+
const trimmed = value.trim();
|
|
4965
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
4966
|
+
}
|
|
4967
|
+
function readSessionActivityPreviewMetadata(value) {
|
|
4968
|
+
if (!isRecord(value)) return null;
|
|
4969
|
+
const state = value.state;
|
|
4970
|
+
const timestamp = readOptionalString(value.timestamp);
|
|
4971
|
+
if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
|
|
4972
|
+
return {
|
|
4973
|
+
state,
|
|
4974
|
+
timestamp,
|
|
4975
|
+
...readOptionalString(value.statusText) ? { statusText: readOptionalString(value.statusText) } : {},
|
|
4976
|
+
...readOptionalString(value.replyText) ? { replyText: readOptionalString(value.replyText) } : {}
|
|
4977
|
+
};
|
|
4978
|
+
}
|
|
4979
|
+
function compareIsoTimestamp(left, right) {
|
|
4980
|
+
const leftTime = Date.parse(left);
|
|
4981
|
+
const rightTime = Date.parse(right);
|
|
4982
|
+
if (!Number.isFinite(leftTime) || !Number.isFinite(rightTime)) return left.localeCompare(right);
|
|
4983
|
+
return leftTime - rightTime;
|
|
4984
|
+
}
|
|
4985
|
+
function mergeSessionActivityPreview(current, incoming) {
|
|
4986
|
+
if (current && compareIsoTimestamp(incoming.timestamp, current.timestamp) < 0) return current;
|
|
4987
|
+
return {
|
|
4988
|
+
state: incoming.state,
|
|
4989
|
+
timestamp: incoming.timestamp,
|
|
4990
|
+
...incoming.statusText ?? (incoming.state === "completed" ? current?.statusText : void 0) ? { statusText: incoming.statusText ?? current?.statusText } : {},
|
|
4991
|
+
...incoming.replyText ?? current?.replyText ? { replyText: incoming.replyText ?? current?.replyText } : {}
|
|
4992
|
+
};
|
|
4993
|
+
}
|
|
4994
|
+
function areSessionActivityPreviewsEqual(left, right) {
|
|
4995
|
+
return Boolean(left) && left?.state === right.state && left.timestamp === right.timestamp && left.statusText === right.statusText && left.replyText === right.replyText;
|
|
4996
|
+
}
|
|
4997
|
+
function writeSessionActivityPreviewMetadata(metadata, projection) {
|
|
4998
|
+
const current = readSessionActivityPreviewMetadata(metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY]);
|
|
4999
|
+
const next = mergeSessionActivityPreview(current, projection.preview);
|
|
5000
|
+
if (areSessionActivityPreviewsEqual(current, next)) return null;
|
|
5001
|
+
return {
|
|
5002
|
+
...metadata ?? {},
|
|
5003
|
+
[SESSION_ACTIVITY_PREVIEW_METADATA_KEY]: next
|
|
5004
|
+
};
|
|
5005
|
+
}
|
|
5006
|
+
//#endregion
|
|
5007
|
+
//#region src/contributions/session-activity-preview/index.ts
|
|
5008
|
+
function formatBackgroundError(error) {
|
|
5009
|
+
if (error instanceof Error) return error.stack ?? error.message;
|
|
5010
|
+
return String(error);
|
|
5011
|
+
}
|
|
5012
|
+
function readMetadata(value) {
|
|
5013
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
5014
|
+
return value;
|
|
5015
|
+
}
|
|
5016
|
+
var SessionActivityPreviewContribution = class {
|
|
5017
|
+
unsubscribeNcpEvent = null;
|
|
5018
|
+
stopped = true;
|
|
5019
|
+
constructor(kernel) {
|
|
5020
|
+
this.kernel = kernel;
|
|
5021
|
+
}
|
|
5022
|
+
start = () => {
|
|
5023
|
+
if (this.unsubscribeNcpEvent) return;
|
|
5024
|
+
this.stopped = false;
|
|
5025
|
+
this.unsubscribeNcpEvent = this.kernel.eventBus.on(eventKeys.ncpEvent, (event) => {
|
|
5026
|
+
const projection = createSessionActivityPreviewFromNcpEvent(event, (/* @__PURE__ */ new Date()).toISOString());
|
|
5027
|
+
if (!projection) return;
|
|
5028
|
+
this.updatePreview(projection);
|
|
5029
|
+
});
|
|
5030
|
+
};
|
|
5031
|
+
dispose = () => {
|
|
5032
|
+
this.unsubscribeNcpEvent?.();
|
|
5033
|
+
this.unsubscribeNcpEvent = null;
|
|
5034
|
+
this.stopped = true;
|
|
5035
|
+
};
|
|
5036
|
+
updatePreview = (projection) => {
|
|
5037
|
+
this.persistPreview(projection).catch((error) => {
|
|
5038
|
+
console.error(`[session-activity-preview] failed to update ${projection.sessionId}: ${formatBackgroundError(error)}`);
|
|
5039
|
+
});
|
|
5040
|
+
};
|
|
5041
|
+
persistPreview = async (projection) => {
|
|
5042
|
+
if (this.stopped) return;
|
|
5043
|
+
const summary = await this.kernel.ncpSessionApi.getSession(projection.sessionId);
|
|
5044
|
+
if (!summary || this.stopped) return;
|
|
5045
|
+
const nextMetadata = writeSessionActivityPreviewMetadata(readMetadata(summary.metadata), projection);
|
|
5046
|
+
if (!nextMetadata) return;
|
|
5047
|
+
await this.kernel.ncpSessionApi.updateSession(projection.sessionId, { metadata: nextMetadata });
|
|
5048
|
+
};
|
|
5049
|
+
};
|
|
5050
|
+
//#endregion
|
|
4863
5051
|
//#region src/app/nextclaw-kernel.ts
|
|
4864
5052
|
function resolveKernelSessionsDir(options) {
|
|
4865
5053
|
const homeDir = options.homeDir?.trim();
|
|
@@ -4904,7 +5092,7 @@ var NextclawKernel = class {
|
|
|
4904
5092
|
sessionLifecycleEvents;
|
|
4905
5093
|
ncpAgentSessionStore;
|
|
4906
5094
|
ncpAgentSessionJournalStore;
|
|
4907
|
-
|
|
5095
|
+
contributions;
|
|
4908
5096
|
constructor(options = {}) {
|
|
4909
5097
|
const sessionsDir = resolveKernelSessionsDir(options);
|
|
4910
5098
|
this.sessions = new SessionManager({ sessionsDir });
|
|
@@ -4942,12 +5130,6 @@ var NextclawKernel = class {
|
|
|
4942
5130
|
channels: this.channels,
|
|
4943
5131
|
providerManager: this.llmProviders
|
|
4944
5132
|
});
|
|
4945
|
-
this.ncpSessionApi = new NcpSessionApiService({
|
|
4946
|
-
eventBus: this.eventBus,
|
|
4947
|
-
getConfig: this.configManager.loadConfig,
|
|
4948
|
-
ncpAgentSessionStore: this.ncpAgentSessionStore,
|
|
4949
|
-
sessionManager: this.sessions
|
|
4950
|
-
});
|
|
4951
5133
|
this.agentRuntimeManager = new AgentRuntimeManager({
|
|
4952
5134
|
bus: this.messageBus,
|
|
4953
5135
|
providerManager: this.llmProviders,
|
|
@@ -4964,30 +5146,34 @@ var NextclawKernel = class {
|
|
|
4964
5146
|
llmUsage: this.llmUsage,
|
|
4965
5147
|
onSessionUpdated: this.publishSessionUpdated
|
|
4966
5148
|
});
|
|
5149
|
+
this.ncpSessionApi = new NcpSessionApiService({
|
|
5150
|
+
eventBus: this.eventBus,
|
|
5151
|
+
getConfig: this.configManager.loadConfig,
|
|
5152
|
+
isLiveSessionRunning: this.agentRuntimeManager.isLiveSessionRunning,
|
|
5153
|
+
ncpAgentSessionStore: this.ncpAgentSessionStore,
|
|
5154
|
+
sessionManager: this.sessions
|
|
5155
|
+
});
|
|
4967
5156
|
this.learningLoop = new LearningLoopManager({
|
|
4968
5157
|
eventBus: this.eventBus,
|
|
4969
5158
|
sessionManager: this.sessions,
|
|
4970
5159
|
sessionRequester: this.sessionRequests,
|
|
4971
5160
|
resolveLearningLoopConfig: () => readLearningLoopRuntimeConfig(this.configManager.loadConfig())
|
|
4972
5161
|
});
|
|
5162
|
+
this.contributions = [new SessionActivityPreviewContribution(this)];
|
|
4973
5163
|
}
|
|
4974
5164
|
start = async () => {
|
|
4975
|
-
this.
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
this.startPromise = null;
|
|
4981
|
-
throw error;
|
|
4982
|
-
});
|
|
4983
|
-
return this.startPromise;
|
|
5165
|
+
this.ncpSessionApi.start();
|
|
5166
|
+
this.sessionSearch.start();
|
|
5167
|
+
for (const contribution of this.contributions) contribution.start();
|
|
5168
|
+
this.agentRuntimeManager.bootstrap();
|
|
5169
|
+
this.learningLoop.start();
|
|
4984
5170
|
};
|
|
4985
5171
|
dispose = async () => {
|
|
4986
5172
|
this.learningLoop.dispose();
|
|
5173
|
+
for (const contribution of this.contributions) contribution.dispose();
|
|
4987
5174
|
this.ncpSessionApi.dispose();
|
|
4988
5175
|
await this.agentRuntimeManager.dispose();
|
|
4989
5176
|
await this.sessionSearch.dispose();
|
|
4990
|
-
this.startPromise = null;
|
|
4991
5177
|
};
|
|
4992
5178
|
publishSessionUpdated = (sessionKey) => {
|
|
4993
5179
|
this.sessionLifecycleEvents.publishSessionUpdated(sessionKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/kernel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
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/core": "0.12.
|
|
24
|
-
"@nextclaw/
|
|
25
|
-
"@nextclaw/
|
|
26
|
-
"@nextclaw/ncp-agent-
|
|
27
|
-
"@nextclaw/
|
|
28
|
-
"@nextclaw/ncp-toolkit": "0.5.
|
|
29
|
-
"@nextclaw/nextclaw-ncp-runtime-http-client": "0.1.
|
|
30
|
-
"@nextclaw/
|
|
31
|
-
"@nextclaw/
|
|
32
|
-
"@nextclaw/
|
|
33
|
-
"@nextclaw/shared": "0.1.
|
|
34
|
-
"@nextclaw/
|
|
35
|
-
"@nextclaw/ncp": "0.
|
|
23
|
+
"@nextclaw/core": "0.12.17",
|
|
24
|
+
"@nextclaw/mcp": "0.1.82",
|
|
25
|
+
"@nextclaw/ncp-agent-runtime": "0.3.20",
|
|
26
|
+
"@nextclaw/ncp-http-agent-server": "0.3.22",
|
|
27
|
+
"@nextclaw/nextclaw-hermes-acp-bridge": "0.1.9",
|
|
28
|
+
"@nextclaw/ncp-toolkit": "0.5.15",
|
|
29
|
+
"@nextclaw/nextclaw-ncp-runtime-http-client": "0.1.9",
|
|
30
|
+
"@nextclaw/openclaw-compat": "1.0.17",
|
|
31
|
+
"@nextclaw/runtime": "0.2.49",
|
|
32
|
+
"@nextclaw/nextclaw-ncp-runtime-stdio-client": "0.1.10",
|
|
33
|
+
"@nextclaw/shared": "0.1.4",
|
|
34
|
+
"@nextclaw/ncp": "0.5.10",
|
|
35
|
+
"@nextclaw/ncp-mcp": "0.1.84"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^20.17.6",
|