@nextclaw/kernel 0.4.0-beta.1 → 0.4.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as getUnsignedUpdateManifest, r as serializeUnsignedUpdateManifest, t as UpdateManifestReader } from "./update-manifest.types-C0qPrjGQ.js";
2
2
  import { createRequire } from "node:module";
3
3
  import { NcpEventType, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
4
- import { AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, ConfigSchema, ContextBuilder, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, EditFileTool, ExecTool, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SessionSearchManager, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, summarizeSessionRequestTask, toDisposable, toExtensionConfigView } from "@nextclaw/core";
4
+ import { AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, ConfigSchema, ContextBuilder, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, EditFileTool, ExecTool, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SessionSearchManager, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, summarizeSessionRequestTask, toDisposable, toExtensionConfigView } from "@nextclaw/core";
5
5
  import { LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
6
6
  import { createHash, createHmac, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
7
7
  import { EventBus, Ingress, eventKeys, ingressKeys } from "@nextclaw/shared";
@@ -15,7 +15,6 @@ import { BUILTIN_PROVIDER_PLUGINS } from "@nextclaw/runtime";
15
15
  import { McpRegistryService, McpServerLifecycleManager } from "@nextclaw/mcp";
16
16
  import { McpNcpToolRegistryAdapter } from "@nextclaw/ncp-mcp";
17
17
  import { DefaultNcpAgentConversationStateManager } from "@nextclaw/ncp-toolkit";
18
- import { createRuntimeChildEnv } from "@nextclaw/core/child-process-env";
19
18
  import { parse } from "yaml";
20
19
  import { HttpRuntimeConfigResolver, HttpRuntimeNcpAgentRuntime } from "@nextclaw/nextclaw-ncp-runtime-http-client";
21
20
  import { StdioRuntimeConfigResolver, StdioRuntimeNcpAgentRuntime, probeStdioRuntime } from "@nextclaw/nextclaw-ncp-runtime-stdio-client";
@@ -149,6 +148,12 @@ function toLegacyMessages(messages, options = {}) {
149
148
  //#region src/features/context-compaction/utils/context-compaction-timeline-message.utils.ts
150
149
  const NEXTCLAW_TIMELINE_KIND_METADATA_KEY = "nextclaw_timeline_kind";
151
150
  const CONTEXT_COMPACTION_TIMELINE_KIND = "context_compaction";
151
+ function readCheckpointTimelineText(checkpoint) {
152
+ return checkpoint.status === "compressing" ? "正在压缩较早上下文" : "较早上下文已自动压缩";
153
+ }
154
+ function createContextCompactionMessageId() {
155
+ return `context-compaction-message-${randomUUID()}`;
156
+ }
152
157
  function readTimelineMetadata(message) {
153
158
  const rawMetadata = message?.ncp_metadata;
154
159
  if (!rawMetadata || typeof rawMetadata !== "object" || Array.isArray(rawMetadata)) return null;
@@ -162,13 +167,14 @@ function readTimelineMetadata(message) {
162
167
  };
163
168
  }
164
169
  function buildTimelineMessage(checkpoint) {
170
+ const text = readCheckpointTimelineText(checkpoint);
165
171
  return {
166
172
  role: "service",
167
- content: checkpoint.status === "compressing" ? "正在压缩较早上下文" : "较早上下文已自动压缩",
173
+ content: text,
168
174
  timestamp: checkpoint.updatedAt,
169
175
  ncp_parts: [{
170
176
  type: "text",
171
- text: checkpoint.status === "compressing" ? "正在压缩较早上下文" : "较早上下文已自动压缩"
177
+ text
172
178
  }],
173
179
  ncp_metadata: {
174
180
  [NEXTCLAW_TIMELINE_KIND_METADATA_KEY]: CONTEXT_COMPACTION_TIMELINE_KIND,
@@ -177,10 +183,10 @@ function buildTimelineMessage(checkpoint) {
177
183
  };
178
184
  }
179
185
  function buildContextCompactionTimelineNcpMessage(params) {
180
- const { checkpoint, sessionId } = params;
181
- const text = checkpoint.status === "compressing" ? "正在压缩较早上下文" : "较早上下文已自动压缩";
186
+ const { checkpoint, messageId, sessionId } = params;
187
+ const text = readCheckpointTimelineText(checkpoint);
182
188
  return {
183
- id: `${sessionId}:service:context-compaction:${checkpoint.id}`,
189
+ id: messageId,
184
190
  sessionId,
185
191
  role: "service",
186
192
  status: "final",
@@ -234,34 +240,31 @@ function isContextCompactionTimelineMessage(message) {
234
240
  }
235
241
  //#endregion
236
242
  //#region src/features/context-compaction/utils/context-compaction-projection.utils.ts
237
- function readCompactionSummary(message) {
243
+ function readCompactionCheckpoint(message) {
238
244
  const metadata = message.metadata;
239
- if (metadata?.["nextclaw_timeline_kind"] !== "context_compaction") return null;
240
- return readCompressedContextCompactionCheckpoint(metadata.checkpoint)?.summary ?? null;
245
+ return metadata?.["nextclaw_timeline_kind"] === "context_compaction" ? readCompressedContextCompactionCheckpoint(metadata.checkpoint) : null;
246
+ }
247
+ function readLatestContextCompactionCheckpoint(sessionMessages) {
248
+ return sessionMessages.reduce((checkpoint, message) => {
249
+ const candidateCheckpoint = readCompactionCheckpoint(message);
250
+ return candidateCheckpoint && (!checkpoint || Date.parse(candidateCheckpoint.updatedAt) >= Date.parse(checkpoint.updatedAt)) ? candidateCheckpoint : checkpoint;
251
+ }, null);
241
252
  }
242
253
  function projectNcpMessagesWithContextCompaction(params) {
243
254
  const { sessionId, sessionMessages } = params;
244
- let checkpointIndex = -1;
245
- let summary = "";
246
- for (let index = sessionMessages.length - 1; index >= 0; index -= 1) {
247
- const candidateSummary = readCompactionSummary(sessionMessages[index]);
248
- if (!candidateSummary) continue;
249
- checkpointIndex = index;
250
- summary = candidateSummary;
251
- break;
252
- }
253
- if (checkpointIndex < 0) return sessionMessages.filter((message) => !readCompactionSummary(message)).map((message) => structuredClone(message));
255
+ const checkpoint = readLatestContextCompactionCheckpoint(sessionMessages);
256
+ if (!checkpoint) return sessionMessages.filter((message) => !readCompactionCheckpoint(message)).map((message) => structuredClone(message));
254
257
  return [{
255
- id: `${sessionId}:context-compaction-summary:${sessionMessages[checkpointIndex]?.id ?? "latest"}`,
258
+ id: `${sessionId}:context-compaction-summary:${checkpoint.id}:${checkpoint.updatedAt}`,
256
259
  sessionId,
257
260
  role: "user",
258
261
  status: "final",
259
- timestamp: sessionMessages[checkpointIndex]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
262
+ timestamp: checkpoint.updatedAt,
260
263
  parts: [{
261
264
  type: "text",
262
- text: summary
265
+ text: checkpoint.summary
263
266
  }]
264
- }, ...sessionMessages.slice(checkpointIndex + 1).filter((message) => !readCompactionSummary(message)).map((message) => structuredClone(message))];
267
+ }, ...sessionMessages.filter((message) => !readCompactionCheckpoint(message) && Date.parse(message.timestamp) > Date.parse(checkpoint.updatedAt)).sort((left, right) => Date.parse(left.timestamp) - Date.parse(right.timestamp)).map((message) => structuredClone(message))];
265
268
  }
266
269
  //#endregion
267
270
  //#region src/features/context-compaction/services/context-compaction-preflight.service.ts
@@ -312,23 +315,6 @@ function buildContextWindowSnapshotFromBudget(params) {
312
315
  compactedUsedContextTokens: checkpoint ? budget.estimatedTokens : void 0
313
316
  });
314
317
  }
315
- function buildContextWindowSnapshotForMessages(contextWindowBudgetService, params) {
316
- const { checkpoint, contextTokens, reservedContextTokens, sessionId, sessionMessages } = params;
317
- const modelCandidateMessages = sessionMessages.filter((message) => !isContextCompactionTimelineMessage(message));
318
- const messages = toLegacyMessages(checkpoint ? projectNcpMessagesWithContextCompaction({
319
- sessionId,
320
- sessionMessages
321
- }) : modelCandidateMessages);
322
- return buildContextWindowSnapshotFromBudget({
323
- budget: contextWindowBudgetService.evaluate({
324
- messages,
325
- contextTokens,
326
- reservedContextTokens
327
- }),
328
- checkpoint,
329
- totalContextTokens: contextTokens
330
- });
331
- }
332
318
  var ContextCompactionPreflightService = class {
333
319
  compactionService = new ContextCompactionService();
334
320
  contextWindowBudgetService = new ContextWindowBudgetService();
@@ -342,13 +328,19 @@ var ContextCompactionPreflightService = class {
342
328
  requestMetadata,
343
329
  storedAgentId
344
330
  });
345
- const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]);
346
- return buildContextWindowSnapshotForMessages(this.contextWindowBudgetService, {
347
- checkpoint: existingCheckpoint,
348
- contextTokens: profile.contextTokens,
349
- reservedContextTokens: profile.reservedContextTokens,
331
+ const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]) ?? readLatestContextCompactionCheckpoint(sessionMessages);
332
+ const projectedMessages = existingCheckpoint ? projectNcpMessagesWithContextCompaction({
350
333
  sessionId,
351
334
  sessionMessages
335
+ }) : sessionMessages.filter((message) => !isContextCompactionTimelineMessage(message));
336
+ return buildContextWindowSnapshotFromBudget({
337
+ budget: this.contextWindowBudgetService.evaluate({
338
+ messages: toLegacyMessages(projectedMessages),
339
+ contextTokens: profile.contextTokens,
340
+ reservedContextTokens: profile.reservedContextTokens
341
+ }),
342
+ checkpoint: existingCheckpoint,
343
+ totalContextTokens: profile.contextTokens
352
344
  });
353
345
  };
354
346
  begin = (params) => {
@@ -363,26 +355,27 @@ var ContextCompactionPreflightService = class {
363
355
  inputMessages,
364
356
  sessionMessages
365
357
  });
366
- const modelCandidateMessages = ncpMessages.filter((message) => !isContextCompactionTimelineMessage(message));
367
- const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]);
358
+ const existingCheckpoint = readCompressedContextCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]) ?? readLatestContextCompactionCheckpoint(ncpMessages);
368
359
  const messages = toLegacyMessages(existingCheckpoint ? projectNcpMessagesWithContextCompaction({
369
360
  sessionId,
370
361
  sessionMessages: ncpMessages
371
- }) : modelCandidateMessages);
362
+ }) : ncpMessages.filter((message) => !isContextCompactionTimelineMessage(message)));
372
363
  const budget = this.contextWindowBudgetService.evaluate({
373
364
  messages,
374
365
  contextTokens,
375
366
  reservedContextTokens
376
367
  });
377
- const plan = existingCheckpoint || !budget.shouldCompact ? null : this.compactionService.prepareForModelInput({
368
+ const plan = !budget.shouldCompact ? null : this.compactionService.prepareForModelInput({
378
369
  messages: budget.messages,
379
370
  contextTokens,
380
371
  compactionThresholdTokens: budget.triggerTokens
381
372
  });
373
+ const coveredSessionMessageCount = plan ? (existingCheckpoint?.coveredSessionMessageCount ?? 0) + plan.coveredMessages.length - (existingCheckpoint ? 1 : 0) : 0;
374
+ const serviceMessageId = createContextCompactionMessageId();
382
375
  const checkpoint = plan ? {
383
376
  ...buildCompressingCompactionCheckpoint(storedMetadata[CONTEXT_COMPACTION_METADATA_KEY]),
384
- coveredMessageCount: plan.coveredMessages.length,
385
- coveredSessionMessageCount: plan.coveredMessages.length,
377
+ coveredMessageCount: coveredSessionMessageCount,
378
+ coveredSessionMessageCount,
386
379
  originalEstimatedTokens: plan.originalEstimatedTokens,
387
380
  projectedEstimatedTokens: budget.estimatedTokens
388
381
  } : existingCheckpoint;
@@ -395,12 +388,14 @@ var ContextCompactionPreflightService = class {
395
388
  metadataPatch: plan && checkpoint ? { [CONTEXT_COMPACTION_METADATA_KEY]: checkpoint } : {},
396
389
  sessionMessages: ncpMessages,
397
390
  timelineMessage: plan && checkpoint ? buildContextCompactionTimelineNcpMessage({
391
+ messageId: serviceMessageId,
398
392
  sessionId,
399
393
  checkpoint
400
394
  }) : null,
401
395
  pendingCompaction: plan && checkpoint ? {
402
396
  checkpoint,
403
397
  contextTokens,
398
+ serviceMessageId,
404
399
  model: profile.model,
405
400
  plan,
406
401
  reservedContextTokens,
@@ -424,6 +419,8 @@ var ContextCompactionPreflightService = class {
424
419
  ...generatedCheckpoint,
425
420
  id: pending.checkpoint.id,
426
421
  createdAt: pending.checkpoint.createdAt,
422
+ coveredMessageCount: pending.checkpoint.coveredMessageCount,
423
+ coveredSessionMessageCount: pending.checkpoint.coveredSessionMessageCount,
427
424
  status: "compressed"
428
425
  };
429
426
  return {
@@ -439,6 +436,7 @@ var ContextCompactionPreflightService = class {
439
436
  metadataPatch: { [CONTEXT_COMPACTION_METADATA_KEY]: checkpoint },
440
437
  sessionMessages: pending.sessionMessages,
441
438
  timelineMessage: buildContextCompactionTimelineNcpMessage({
439
+ messageId: pending.serviceMessageId,
442
440
  sessionId: pending.sessionId,
443
441
  checkpoint
444
442
  })
@@ -3072,6 +3070,30 @@ var McpManager = class {
3072
3070
  for (const result of results) if (!result.ok) console.warn(`[mcp] Failed to warm ${result.name}: ${result.error}`);
3073
3071
  };
3074
3072
  };
3073
+ //#endregion
3074
+ //#region src/utils/agent-peer-session.utils.ts
3075
+ const AGENT_RUN_PEER_ID_METADATA_KEY = "agent_peer_id";
3076
+ const AGENT_RUN_PEER_SCOPE_METADATA_KEY = "agent_peer_scope";
3077
+ function createAgentPeerSessionIdentity(params) {
3078
+ const scope = resolveAgentPeerScope(params);
3079
+ return {
3080
+ metadata: {
3081
+ [AGENT_RUN_PEER_ID_METADATA_KEY]: params.peerId,
3082
+ [AGENT_RUN_PEER_SCOPE_METADATA_KEY]: scope
3083
+ },
3084
+ sessionId: `agent-peer-${createHash("sha256").update(`${scope}\0${params.peerId}`).digest("hex").slice(0, 32)}`
3085
+ };
3086
+ }
3087
+ function resolveAgentPeerScope(params) {
3088
+ const metadata = params.metadata ?? {};
3089
+ const explicitScope = readOptionalString$8(metadata["agent_peer_scope"]) ?? readOptionalString$8(metadata.agentPeerScope);
3090
+ if (explicitScope) return explicitScope;
3091
+ return `agent:${readOptionalString$8(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$8(params.channel) ?? readOptionalString$8(metadata.channel) ?? "agent-run"}:${readOptionalString$8(metadata.accountId) ?? readOptionalString$8(metadata.account_id) ?? "default"}`;
3092
+ }
3093
+ function readOptionalString$8(value) {
3094
+ if (typeof value !== "string") return;
3095
+ return value.trim() || void 0;
3096
+ }
3075
3097
  const NCP_AGENT_SESSION_JOURNAL_INDEX_FILE = ".ncp-agent-session-index.json";
3076
3098
  const AUTO_SESSION_LABEL_MAX_LENGTH = 64;
3077
3099
  const NCP_AGENT_SESSION_SNAPSHOT_MESSAGE_EVENT_TYPE = "session.snapshot.message";
@@ -3097,10 +3119,12 @@ function toIsoString(value, fallback) {
3097
3119
  function createNcpAgentSessionSummary(record) {
3098
3120
  const metadata = structuredClone(record.metadata ?? {});
3099
3121
  const label = readOptionalText(metadata.label) ?? resolveAutoSessionLabel(record.messages);
3122
+ const peerId = readNcpAgentSessionPeerId(metadata);
3100
3123
  if (label) metadata.label = label;
3101
3124
  const lastMessageAt = record.messages.reduceRight((timestamp, message) => timestamp ?? readMessageTimestamp(message), void 0);
3102
3125
  return {
3103
3126
  sessionId: record.sessionId,
3127
+ peerId: peerId ?? void 0,
3104
3128
  ...normalizeNcpAgentId(record.agentId) ? { agentId: normalizeNcpAgentId(record.agentId) } : {},
3105
3129
  messageCount: record.messages.length,
3106
3130
  ...record.createdAt ? { createdAt: record.createdAt } : {},
@@ -3110,6 +3134,9 @@ function createNcpAgentSessionSummary(record) {
3110
3134
  ...Object.keys(metadata).length > 0 ? { metadata } : {}
3111
3135
  };
3112
3136
  }
3137
+ function readNcpAgentSessionPeerId(metadata) {
3138
+ return readOptionalText(metadata[AGENT_RUN_PEER_ID_METADATA_KEY]);
3139
+ }
3113
3140
  function createNcpAgentSessionJournalMetadataEntry(record) {
3114
3141
  return {
3115
3142
  _type: "metadata",
@@ -3126,6 +3153,7 @@ function upsertNcpAgentSessionSummaryEvent(params) {
3126
3153
  const lastMessageAt = readMessageTimestamp(eventMessage) ?? current?.lastMessageAt;
3127
3154
  return {
3128
3155
  sessionId,
3156
+ peerId: current?.peerId,
3129
3157
  ...normalizeNcpAgentId(current?.agentId) ? { agentId: normalizeNcpAgentId(current?.agentId) } : {},
3130
3158
  messageCount,
3131
3159
  createdAt: current?.createdAt ?? updatedAt,
@@ -3136,9 +3164,14 @@ function upsertNcpAgentSessionSummaryEvent(params) {
3136
3164
  }
3137
3165
  async function replayNcpAgentSessionEvents(events) {
3138
3166
  const stateManager = new DefaultNcpAgentConversationStateManager();
3167
+ const knownMessageIds = /* @__PURE__ */ new Set();
3139
3168
  for (const event of events) {
3140
3169
  if (isJournalOnlyEvent(event)) continue;
3141
- await stateManager.dispatch(createReplayEvent(event));
3170
+ const replayEvent = createReplayEvent(event);
3171
+ const bootstrapEvent = createReplayStreamingBootstrapEvent(replayEvent, knownMessageIds);
3172
+ if (bootstrapEvent) await stateManager.dispatch(bootstrapEvent);
3173
+ rememberReplayMessageId(replayEvent, knownMessageIds);
3174
+ await stateManager.dispatch(replayEvent);
3142
3175
  }
3143
3176
  const snapshot = stateManager.getSnapshot();
3144
3177
  return [...snapshot.messages.map((message) => structuredClone(message)), ...snapshot.streamingMessage ? [structuredClone(snapshot.streamingMessage)] : []];
@@ -3146,6 +3179,8 @@ async function replayNcpAgentSessionEvents(events) {
3146
3179
  function createReplayEvent(event) {
3147
3180
  const replayEvent = structuredClone(event);
3148
3181
  const replayMessage = readMessageFromSummaryEvent(replayEvent);
3182
+ const legacyCompactionMessageId = readLegacyContextCompactionMessageId(replayMessage);
3183
+ if (replayMessage && legacyCompactionMessageId) replayMessage.id = legacyCompactionMessageId;
3149
3184
  if (replayMessage?.role === "assistant" && (replayMessage.status === "pending" || replayMessage.status === "streaming")) replayMessage.status = "final";
3150
3185
  if (replayEvent.type === "session.snapshot.message" || replayEvent.type === NcpEventType.MessageCompleted) return {
3151
3186
  type: NcpEventType.MessageSent,
@@ -3153,6 +3188,58 @@ function createReplayEvent(event) {
3153
3188
  };
3154
3189
  return replayEvent;
3155
3190
  }
3191
+ function readLegacyContextCompactionMessageId(message) {
3192
+ const checkpoint = isRecord$10(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
3193
+ const checkpointId = typeof checkpoint?.id === "string" ? checkpoint.id : "";
3194
+ const coveredCount = checkpoint?.coveredSessionMessageCount;
3195
+ const legacyId = `${message?.sessionId}:service:context-compaction:${checkpointId}`;
3196
+ return typeof coveredCount === "number" && message?.id === legacyId ? `${legacyId}:${coveredCount}` : null;
3197
+ }
3198
+ function createReplayStreamingBootstrapEvent(event, knownMessageIds) {
3199
+ const messageId = readStreamingMessageId(event);
3200
+ if (!messageId || knownMessageIds.has(messageId)) return null;
3201
+ knownMessageIds.add(messageId);
3202
+ return {
3203
+ type: NcpEventType.MessageSent,
3204
+ payload: {
3205
+ sessionId: readEventSessionId$2(event),
3206
+ message: {
3207
+ id: messageId,
3208
+ sessionId: readEventSessionId$2(event),
3209
+ role: "assistant",
3210
+ status: "streaming",
3211
+ parts: [],
3212
+ timestamp: readReplayPayloadTimestamp(event) ?? (/* @__PURE__ */ new Date()).toISOString()
3213
+ }
3214
+ }
3215
+ };
3216
+ }
3217
+ function rememberReplayMessageId(event, knownMessageIds) {
3218
+ const message = readMessageFromSummaryEvent(event);
3219
+ if (message?.id) knownMessageIds.add(message.id);
3220
+ }
3221
+ function readEventSessionId$2(event) {
3222
+ const sessionId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.sessionId;
3223
+ return typeof sessionId === "string" ? sessionId : "";
3224
+ }
3225
+ function readReplayPayloadTimestamp(event) {
3226
+ const payload = "payload" in event && isRecord$10(event.payload) ? event.payload : null;
3227
+ const timestamp = typeof payload?.timestamp === "string" ? payload.timestamp : "";
3228
+ return Number.isFinite(Date.parse(timestamp)) ? new Date(timestamp).toISOString() : null;
3229
+ }
3230
+ function readStreamingMessageId(event) {
3231
+ switch (event.type) {
3232
+ case NcpEventType.MessageTextStart:
3233
+ case NcpEventType.MessageTextDelta:
3234
+ case NcpEventType.MessageTextEnd:
3235
+ case NcpEventType.MessageReasoningStart:
3236
+ case NcpEventType.MessageReasoningDelta:
3237
+ case NcpEventType.MessageReasoningEnd:
3238
+ case NcpEventType.MessageToolCallStart:
3239
+ case NcpEventType.MessageToolCallArgsDelta: return event.payload.messageId?.trim() || null;
3240
+ default: return null;
3241
+ }
3242
+ }
3156
3243
  function isJournalOnlyEvent(event) {
3157
3244
  return event.type === "session.request.accepted" || event.type === "session.request.completed" || event.type === "session.request.failed";
3158
3245
  }
@@ -3183,30 +3270,6 @@ function readMessageFromSummaryEvent(event) {
3183
3270
  if (event.type === NcpEventType.MessageSent || event.type === NcpEventType.MessageCompleted || event.type === "session.snapshot.message") return event.payload.message;
3184
3271
  }
3185
3272
  //#endregion
3186
- //#region src/utils/agent-peer-session.utils.ts
3187
- const AGENT_RUN_PEER_ID_METADATA_KEY = "agent_peer_id";
3188
- const AGENT_RUN_PEER_SCOPE_METADATA_KEY = "agent_peer_scope";
3189
- function createAgentPeerSessionIdentity(params) {
3190
- const scope = resolveAgentPeerScope(params);
3191
- return {
3192
- metadata: {
3193
- [AGENT_RUN_PEER_ID_METADATA_KEY]: params.peerId,
3194
- [AGENT_RUN_PEER_SCOPE_METADATA_KEY]: scope
3195
- },
3196
- sessionId: `agent-peer-${createHash("sha256").update(`${scope}\0${params.peerId}`).digest("hex").slice(0, 32)}`
3197
- };
3198
- }
3199
- function resolveAgentPeerScope(params) {
3200
- const metadata = params.metadata ?? {};
3201
- const explicitScope = readOptionalString$8(metadata["agent_peer_scope"]) ?? readOptionalString$8(metadata.agentPeerScope);
3202
- if (explicitScope) return explicitScope;
3203
- return `agent:${readOptionalString$8(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$8(params.channel) ?? readOptionalString$8(metadata.channel) ?? "agent-run"}:${readOptionalString$8(metadata.accountId) ?? readOptionalString$8(metadata.account_id) ?? "default"}`;
3204
- }
3205
- function readOptionalString$8(value) {
3206
- if (typeof value !== "string") return;
3207
- return value.trim() || void 0;
3208
- }
3209
- //#endregion
3210
3273
  //#region src/managers/session.manager.ts
3211
3274
  const DEFAULT_SESSION_TYPE = "native";
3212
3275
  const DEFAULT_LIFECYCLE = "persistent";
@@ -3425,7 +3488,8 @@ var SessionManager = class {
3425
3488
  return await this.options.journalStore.getSession(normalizedSessionId);
3426
3489
  };
3427
3490
  listSessions = async (options) => {
3428
- return applyLimit(await this.options.journalStore.listSessionSummaries(), options?.limit);
3491
+ const peerId = readOptionalString$7(options?.peerId);
3492
+ return applyLimit((await this.options.journalStore.listSessionSummaries()).filter((summary) => !peerId || summary.peerId === peerId), options?.limit);
3429
3493
  };
3430
3494
  listSessionMessages = async (sessionId, options) => {
3431
3495
  const normalizedSessionId = normalizeSessionId(sessionId);
@@ -4309,6 +4373,35 @@ function getPanelAppBridgeScript(params = {
4309
4373
  });
4310
4374
  }
4311
4375
 
4376
+ function resolveApiFetchUrl(input) {
4377
+ const raw = typeof input === "string" || input instanceof URL ? input.toString() : input?.url;
4378
+ if (typeof raw !== "string") {
4379
+ return null;
4380
+ }
4381
+ try {
4382
+ const url = new URL(raw, window.location.href);
4383
+ return url.origin === window.location.origin && url.pathname.startsWith("/api/") ? url : null;
4384
+ } catch {
4385
+ return null;
4386
+ }
4387
+ }
4388
+
4389
+ function createFetchInitWithRuntimeToken(input, init) {
4390
+ if (!resolveApiFetchUrl(input)) {
4391
+ return init;
4392
+ }
4393
+ const headers = new Headers(init?.headers || (typeof input === "object" && input ? input.headers : undefined));
4394
+ if (!headers.has("x-nextclaw-panel-bridge-session")) {
4395
+ headers.set("x-nextclaw-panel-bridge-session", runtimeToken);
4396
+ }
4397
+ return { ...init, headers };
4398
+ }
4399
+
4400
+ const nativeFetch = window.fetch?.bind(window);
4401
+ if (nativeFetch) {
4402
+ window.fetch = (input, init) => nativeFetch(input, createFetchInitWithRuntimeToken(input, init));
4403
+ }
4404
+
4312
4405
  function unwrapServiceActionResult(result) {
4313
4406
  if (!result || typeof result !== "object") {
4314
4407
  return result;
@@ -4386,7 +4479,7 @@ const PANEL_APP_CLIENT_MARKER = "nextclaw:panel-app-client:init";
4386
4479
  const PANEL_APP_CLIENT_SDK_PATH = "/api/panel-app-client-sdk.js";
4387
4480
  function injectPanelAppClientScript(html, params) {
4388
4481
  if (html.includes(PANEL_APP_CLIENT_MARKER)) return html;
4389
- const script = [`<script src="${PANEL_APP_CLIENT_SDK_PATH}"><\/script>`, `<script>${getPanelAppClientInitScript(params)}<\/script>`].join("");
4482
+ const script = [`<script src="${PANEL_APP_CLIENT_SDK_PATH}" crossorigin="anonymous"><\/script>`, `<script>${getPanelAppClientInitScript(params)}<\/script>`].join("");
4390
4483
  const headMatch = /<head(?:\s[^>]*)?>/i.exec(html);
4391
4484
  if (headMatch?.index !== void 0) {
4392
4485
  const insertAt = headMatch.index + headMatch[0].length;
@@ -4618,9 +4711,27 @@ function resolvePanelAppIconUrl(id, icon) {
4618
4711
  }
4619
4712
  function injectPanelAppAssetBase(html, baseHref) {
4620
4713
  const base = `<base href="${baseHref}">`;
4621
- if (/<base\b/i.test(html)) return html;
4622
- if (/<head[^>]*>/i.test(html)) return html.replace(/<head[^>]*>/i, (head) => `${head}${base}`);
4623
- return `${base}${html}`;
4714
+ return injectLocalScriptCrossOrigin((() => {
4715
+ if (/<base\b/i.test(html)) return html;
4716
+ if (/<head[^>]*>/i.test(html)) return html.replace(/<head[^>]*>/i, (head) => `${head}${base}`);
4717
+ return `${base}${html}`;
4718
+ })());
4719
+ }
4720
+ function injectLocalScriptCrossOrigin(html) {
4721
+ return html.replace(/<script\b(?=[^>]*\bsrc\s*=)(?![^>]*\bcrossorigin\b)[^>]*>/gi, (tag) => {
4722
+ const src = extractScriptSrc(tag);
4723
+ if (!src || !isLocalScriptSrc(src)) return tag;
4724
+ return `${tag.slice(0, -1)} crossorigin="anonymous">`;
4725
+ });
4726
+ }
4727
+ function extractScriptSrc(tag) {
4728
+ const match = /\bsrc\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tag);
4729
+ return match?.[1] ?? match?.[2] ?? match?.[3];
4730
+ }
4731
+ function isLocalScriptSrc(src) {
4732
+ const value = src.trim();
4733
+ if (!value || value.startsWith("//")) return false;
4734
+ return !/^(?:https?|data|blob|javascript):/i.test(value);
4624
4735
  }
4625
4736
  function encodePanelAppAssetPath(path) {
4626
4737
  return path.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
@@ -6068,6 +6179,16 @@ function serializeJournalEntry(entry) {
6068
6179
  if (!isRecord$10(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
6069
6180
  return serialized;
6070
6181
  }
6182
+ function attachJournalTimestamp(event, timestamp) {
6183
+ if (!("payload" in event) || !isRecord$10(event.payload)) return event;
6184
+ return {
6185
+ ...event,
6186
+ payload: {
6187
+ ...event.payload,
6188
+ timestamp
6189
+ }
6190
+ };
6191
+ }
6071
6192
  var NcpAgentSessionJournalStore = class {
6072
6193
  sessions = /* @__PURE__ */ new Map();
6073
6194
  nextSeqBySession = /* @__PURE__ */ new Map();
@@ -6234,8 +6355,10 @@ var NcpAgentSessionJournalStore = class {
6234
6355
  updatedAt: summary.updatedAt,
6235
6356
  metadata: {}
6236
6357
  });
6358
+ const peerId = summary.peerId ?? readNcpAgentSessionPeerId(snapshot.metadata);
6237
6359
  return {
6238
6360
  ...summary,
6361
+ peerId: peerId ?? void 0,
6239
6362
  ...!summary.agentId && snapshot.agentId ? { agentId: snapshot.agentId } : {},
6240
6363
  ...Object.keys(snapshot.metadata).length > 0 ? { metadata: snapshot.metadata } : {}
6241
6364
  };
@@ -6292,9 +6415,10 @@ var NcpAgentSessionJournalStore = class {
6292
6415
  if (parsed._type === "event" && isRecord$10(parsed.event)) {
6293
6416
  const seq = Number(parsed.seq);
6294
6417
  nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
6295
- updatedAt = toIsoString(parsed.timestamp, updatedAt);
6418
+ const eventTimestamp = toIsoString(parsed.timestamp, updatedAt);
6419
+ updatedAt = eventTimestamp;
6296
6420
  const event = structuredClone(parsed.event);
6297
- events.push(event);
6421
+ events.push(attachJournalTimestamp(event, eventTimestamp));
6298
6422
  }
6299
6423
  }
6300
6424
  return {
@@ -9588,6 +9712,6 @@ function resolveLegacyEventType(message) {
9588
9712
  return `message.${role || "other"}`;
9589
9713
  }
9590
9714
  //#endregion
9591
- export { AccessManager, AgentManager, AgentRunClient, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppAssetTokenService, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildServiceActionId, buildSessionOrchestrationSection, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
9715
+ export { AccessManager, AgentManager, AgentRunClient, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppAssetTokenService, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildServiceActionId, buildSessionOrchestrationSection, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
9592
9716
 
9593
9717
  //# sourceMappingURL=index.js.map