@nextclaw/kernel 0.10.0-beta.0 → 0.10.1
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 +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +311 -72
- package/dist/index.js.map +1 -1
- package/package.json +15 -15
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, getAutomaticUpdateCheckDelay, resol
|
|
|
2
2
|
import { n as getUnsignedUpdateManifest, r as serializeUnsignedUpdateManifest, t as UpdateManifestReader } from "./update-manifest.types-C0qPrjGQ.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, DIAGNOSTIC_CORRELATION_METADATA_KEY, DiagnosticRuntime, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderModelDiscoveryService, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, ViewImageTool, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, estimateInputTokens, evaluateSilentReply, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, isNextclawControlMessage, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeAgentProfileId, normalizeInlineSecretRefs, normalizeModelThinkingCapability, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveRuntimeCommandLaunch, resolveSessionProjectContext, resolveSessionWorkspacePath, resolveThinkingLevel, safeFilename, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
|
|
5
|
-
import { NCP_AI_EXECUTION_METADATA_KEY, NCP_INTERNAL_VISIBILITY_METADATA_KEY, NcpEventType, OBSERVATION_EVENT_EXTENSION_TYPE, createUnavailableNcpAiExecutionMetadata, isHiddenNcpMessage, normalizeAssistantText, readNcpAiExecutionMetadata, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
|
|
5
|
+
import { NCP_AI_EXECUTION_METADATA_KEY, NCP_INTERNAL_VISIBILITY_METADATA_KEY, NCP_RUN_TRIGGER_METADATA_KEY, NcpEventType, OBSERVATION_EVENT_EXTENSION_TYPE, createUnavailableNcpAiExecutionMetadata, isHiddenNcpMessage, normalizeAssistantText, parseNcpRunTriggerInput, readNcpAiExecutionMetadata, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
|
|
6
6
|
import { CHAT_CONTINUATION_TARGET_MESSAGE_METADATA_KEY, CHAT_CONVERSATION_EXCERPT_TOKEN_KIND, CHAT_INLINE_TOKENS_METADATA_KEY, CHAT_INLINE_TOKENS_SCHEMA_VERSION, CHAT_PROJECT_TOKEN_KIND, CHAT_SESSION_MATERIALIZATION_METADATA_KEY, CHAT_SYSTEM_OBJECT_TOKEN_KIND, CHAT_UI_RESOURCE_TOKEN_KIND, CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND, CHAT_WORKSPACE_EXCERPT_TOKEN_KIND, CHAT_WORKSPACE_FILE_TOKEN_KIND, Contribution as Contribution$1, EventBus, EventBus as EventBus$1, Ingress, Ingress as Ingress$1, PANEL_APP_INLINE_HOST_CONTRACT, PANEL_APP_SCROLL_RESTORATION_CONTRACT, SYSTEM_OBJECT_REFERENCE_DEFAULT_LIMIT, SYSTEM_OBJECT_REFERENCE_MAX_LIMIT, SYSTEM_OBJECT_TYPE_CRON_JOB, SYSTEM_OBJECT_TYPE_INBOX_DELIVERY, UI_CONTENT_PARAMS_HOST_CONTRACT, classifyDiagnosticError, createSystemObjectReferenceUri, createTypedKey, eventKeys, eventKeys as eventKeys$1, ingressKeys, ingressKeys as ingressKeys$1, isRuntimeDefaultModelValue, isSilentReplyNcpMessage, normalizeRuntimeModelSelectionMode, parseSystemObjectReferenceUri, readChatUiResourceReference, readInlineContentHeight, readSystemObjectResolvedReference, readUiContentParams } from "@nextclaw/shared";
|
|
7
7
|
import { LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, isTextLikeAsset, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
|
|
8
8
|
import { createHash, createHmac, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
|
|
@@ -1514,26 +1514,26 @@ const SESSION_ACTIVITY_PREVIEW_STATUS_KINDS = new Set([
|
|
|
1514
1514
|
"run-failed",
|
|
1515
1515
|
"run-interrupted"
|
|
1516
1516
|
]);
|
|
1517
|
-
function isRecord$
|
|
1517
|
+
function isRecord$19(value) {
|
|
1518
1518
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1519
1519
|
}
|
|
1520
|
-
function readOptionalString$
|
|
1520
|
+
function readOptionalString$13(value) {
|
|
1521
1521
|
if (typeof value !== "string") return;
|
|
1522
1522
|
const trimmed = value.trim();
|
|
1523
1523
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
1524
1524
|
}
|
|
1525
1525
|
function readSessionActivityPreviewMetadata(value) {
|
|
1526
|
-
if (!isRecord$
|
|
1526
|
+
if (!isRecord$19(value)) return null;
|
|
1527
1527
|
const state = value.state;
|
|
1528
|
-
const timestamp = readOptionalString$
|
|
1528
|
+
const timestamp = readOptionalString$13(value.timestamp);
|
|
1529
1529
|
if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
|
|
1530
|
-
const statusKind = readOptionalString$
|
|
1530
|
+
const statusKind = readOptionalString$13(value.statusKind);
|
|
1531
1531
|
return {
|
|
1532
1532
|
state,
|
|
1533
1533
|
timestamp,
|
|
1534
1534
|
statusKind: SESSION_ACTIVITY_PREVIEW_STATUS_KINDS.has(statusKind) ? statusKind : void 0,
|
|
1535
|
-
statusText: readOptionalString$
|
|
1536
|
-
replyText: readOptionalString$
|
|
1535
|
+
statusText: readOptionalString$13(value.statusText),
|
|
1536
|
+
replyText: readOptionalString$13(value.replyText)
|
|
1537
1537
|
};
|
|
1538
1538
|
}
|
|
1539
1539
|
function compareIsoTimestamp(left, right) {
|
|
@@ -1617,7 +1617,7 @@ var SessionActivityPreviewEventService = class {
|
|
|
1617
1617
|
//#endregion
|
|
1618
1618
|
//#region src/managers/agent-run-session-command.manager.ts
|
|
1619
1619
|
const CONTINUATION_PROMPT = "Continue from where you stopped. Preserve completed work and avoid repeating it.";
|
|
1620
|
-
function isRecord$
|
|
1620
|
+
function isRecord$18(value) {
|
|
1621
1621
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1622
1622
|
}
|
|
1623
1623
|
function hasSendableMessageContent(message) {
|
|
@@ -1625,7 +1625,7 @@ function hasSendableMessageContent(message) {
|
|
|
1625
1625
|
}
|
|
1626
1626
|
function readSessionActivityState(metadata) {
|
|
1627
1627
|
const preview = metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY];
|
|
1628
|
-
return isRecord$
|
|
1628
|
+
return isRecord$18(preview) && typeof preview.state === "string" ? preview.state : null;
|
|
1629
1629
|
}
|
|
1630
1630
|
var AgentRunSessionCommandManager = class {
|
|
1631
1631
|
pendingCommands = /* @__PURE__ */ new Map();
|
|
@@ -1676,6 +1676,13 @@ var AgentRunSessionCommandManager = class {
|
|
|
1676
1676
|
role: "user",
|
|
1677
1677
|
status: "final",
|
|
1678
1678
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1679
|
+
},
|
|
1680
|
+
trigger: {
|
|
1681
|
+
actor: "human",
|
|
1682
|
+
source: "message-edit",
|
|
1683
|
+
triggeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1684
|
+
sourceSessionId: request.sessionId,
|
|
1685
|
+
sourceMessageId: request.messageId
|
|
1679
1686
|
}
|
|
1680
1687
|
});
|
|
1681
1688
|
};
|
|
@@ -1685,6 +1692,7 @@ var AgentRunSessionCommandManager = class {
|
|
|
1685
1692
|
const activityState = readSessionActivityState(sourceRecord.metadata);
|
|
1686
1693
|
if (activityState !== "cancelled" && activityState !== "failed") throw new Error("Only a cancelled or failed session can continue running.");
|
|
1687
1694
|
const latestVisibleConversationMessage = [...sourceRecord.messages].reverse().find((message) => (message.role === "user" || message.role === "assistant") && !isHiddenNcpMessage(message) && !isSilentReplyNcpMessage(message));
|
|
1695
|
+
const triggeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1688
1696
|
return await this.send({
|
|
1689
1697
|
correlationId: request.correlationId,
|
|
1690
1698
|
sessionId: request.sessionId,
|
|
@@ -1693,7 +1701,7 @@ var AgentRunSessionCommandManager = class {
|
|
|
1693
1701
|
sessionId: request.sessionId,
|
|
1694
1702
|
role: "user",
|
|
1695
1703
|
status: "final",
|
|
1696
|
-
timestamp:
|
|
1704
|
+
timestamp: triggeredAt,
|
|
1697
1705
|
parts: [{
|
|
1698
1706
|
type: "text",
|
|
1699
1707
|
text: CONTINUATION_PROMPT
|
|
@@ -1702,6 +1710,13 @@ var AgentRunSessionCommandManager = class {
|
|
|
1702
1710
|
[NCP_INTERNAL_VISIBILITY_METADATA_KEY]: "hidden",
|
|
1703
1711
|
[CHAT_CONTINUATION_TARGET_MESSAGE_METADATA_KEY]: latestVisibleConversationMessage?.role === "assistant" ? latestVisibleConversationMessage.id : void 0
|
|
1704
1712
|
}
|
|
1713
|
+
},
|
|
1714
|
+
trigger: {
|
|
1715
|
+
actor: "human",
|
|
1716
|
+
source: "continue-run",
|
|
1717
|
+
triggeredAt,
|
|
1718
|
+
sourceSessionId: request.sessionId,
|
|
1719
|
+
...latestVisibleConversationMessage ? { sourceMessageId: latestVisibleConversationMessage.id } : {}
|
|
1705
1720
|
}
|
|
1706
1721
|
});
|
|
1707
1722
|
};
|
|
@@ -1950,13 +1965,13 @@ function createUnavailableAiExecutionMetadataEvent(params) {
|
|
|
1950
1965
|
}
|
|
1951
1966
|
//#endregion
|
|
1952
1967
|
//#region src/utils/agent-run-request.utils.ts
|
|
1953
|
-
function readOptionalString$
|
|
1968
|
+
function readOptionalString$12(value) {
|
|
1954
1969
|
if (typeof value !== "string") return;
|
|
1955
1970
|
return value.trim() || void 0;
|
|
1956
1971
|
}
|
|
1957
1972
|
function toAgentRunRequest(envelope) {
|
|
1958
1973
|
const metadata = envelope.metadata ?? {};
|
|
1959
|
-
const peerId = readOptionalString$
|
|
1974
|
+
const peerId = readOptionalString$12(envelope.peerId);
|
|
1960
1975
|
const requestMetadata = {
|
|
1961
1976
|
agentRuntimeId: metadata.agentRuntimeId,
|
|
1962
1977
|
agentId: metadata.agentId,
|
|
@@ -1968,10 +1983,10 @@ function toAgentRunRequest(envelope) {
|
|
|
1968
1983
|
maxTokens: metadata.maxTokens,
|
|
1969
1984
|
thinkingEffort: metadata.thinkingEffort,
|
|
1970
1985
|
delivery: envelope.delivery,
|
|
1971
|
-
idempotencyKey: readOptionalString$
|
|
1986
|
+
idempotencyKey: readOptionalString$12(envelope.idempotencyKey)
|
|
1972
1987
|
};
|
|
1973
1988
|
if (Array.isArray(envelope.content)) {
|
|
1974
|
-
const sessionId = readOptionalString$
|
|
1989
|
+
const sessionId = readOptionalString$12(envelope.sessionId);
|
|
1975
1990
|
if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
|
|
1976
1991
|
return {
|
|
1977
1992
|
...requestMetadata,
|
|
@@ -1989,8 +2004,8 @@ function toAgentRunRequest(envelope) {
|
|
|
1989
2004
|
}
|
|
1990
2005
|
const sourceMessage = envelope.message;
|
|
1991
2006
|
if (!sourceMessage) throw new Error("Invalid agent run send request.");
|
|
1992
|
-
const envelopeSessionId = readOptionalString$
|
|
1993
|
-
const messageSessionId = readOptionalString$
|
|
2007
|
+
const envelopeSessionId = readOptionalString$12(envelope.sessionId);
|
|
2008
|
+
const messageSessionId = readOptionalString$12(sourceMessage.sessionId);
|
|
1994
2009
|
const sessionId = envelopeSessionId ?? messageSessionId;
|
|
1995
2010
|
if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
|
|
1996
2011
|
return {
|
|
@@ -2051,7 +2066,7 @@ function readSessionMaterialization(metadata) {
|
|
|
2051
2066
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2052
2067
|
const materialization = value;
|
|
2053
2068
|
if (materialization.kind !== "child") throw new Error("session_materialization.kind must be \"child\".");
|
|
2054
|
-
const parentSessionId = readOptionalString$
|
|
2069
|
+
const parentSessionId = readOptionalString$12(materialization.parentSessionId);
|
|
2055
2070
|
if (!parentSessionId) throw new Error("session_materialization.parentSessionId is required.");
|
|
2056
2071
|
if (materialization.inheritContext !== true) throw new Error("session_materialization.inheritContext must be true.");
|
|
2057
2072
|
return {
|
|
@@ -2093,7 +2108,7 @@ function resolveRunSpec(params) {
|
|
|
2093
2108
|
};
|
|
2094
2109
|
}
|
|
2095
2110
|
function attachRunSpecMetadata(params) {
|
|
2096
|
-
const { message, modelSource, request, session, spec, startedAt } = params;
|
|
2111
|
+
const { message, modelSource, request, session, spec, startedAt, trigger } = params;
|
|
2097
2112
|
const metadata = structuredClone(message.metadata ?? {});
|
|
2098
2113
|
metadata[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY] = {
|
|
2099
2114
|
version: 1,
|
|
@@ -2112,6 +2127,7 @@ function attachRunSpecMetadata(params) {
|
|
|
2112
2127
|
correlationId: spec.correlationId ?? null,
|
|
2113
2128
|
execution: structuredClone(AGENT_RUN_EXECUTION_METADATA)
|
|
2114
2129
|
};
|
|
2130
|
+
metadata[NCP_RUN_TRIGGER_METADATA_KEY] = structuredClone(trigger);
|
|
2115
2131
|
return {
|
|
2116
2132
|
...message,
|
|
2117
2133
|
metadata
|
|
@@ -2164,7 +2180,7 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2164
2180
|
}));
|
|
2165
2181
|
messageCompletedSeen = true;
|
|
2166
2182
|
}
|
|
2167
|
-
eventsToPublish.push(event);
|
|
2183
|
+
eventsToPublish.push(this.projectCompletedMessage(event, sessionRun));
|
|
2168
2184
|
eventsToPublish.forEach(this.publishNcpEvent);
|
|
2169
2185
|
if (consumedSteeringInput) this.publishRunQueueUpdated(session.sessionId);
|
|
2170
2186
|
}), catchError(async (error) => {
|
|
@@ -2235,6 +2251,17 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2235
2251
|
source: "agent-run-request"
|
|
2236
2252
|
});
|
|
2237
2253
|
};
|
|
2254
|
+
projectCompletedMessage = (event, sessionRun) => {
|
|
2255
|
+
if (event.type !== NcpEventType.MessageCompleted) return event;
|
|
2256
|
+
const message = sessionRun.getSnapshot().messages.find((item) => item.id === event.payload.message.id);
|
|
2257
|
+
return message ? {
|
|
2258
|
+
...event,
|
|
2259
|
+
payload: {
|
|
2260
|
+
...event.payload,
|
|
2261
|
+
message: structuredClone(message)
|
|
2262
|
+
}
|
|
2263
|
+
} : event;
|
|
2264
|
+
};
|
|
2238
2265
|
publishNcpEvent = (event) => {
|
|
2239
2266
|
this.options.eventBus.emit(eventKeys$1.ncpEvent, event, {
|
|
2240
2267
|
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2243,6 +2270,110 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2243
2270
|
};
|
|
2244
2271
|
};
|
|
2245
2272
|
//#endregion
|
|
2273
|
+
//#region src/utils/agent-run-trigger.utils.ts
|
|
2274
|
+
function isRecord$17(value) {
|
|
2275
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2276
|
+
}
|
|
2277
|
+
function readOptionalString$11(value) {
|
|
2278
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2279
|
+
}
|
|
2280
|
+
function readSourceRunSpec(message) {
|
|
2281
|
+
const value = message.metadata?.[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY];
|
|
2282
|
+
return isRecord$17(value) ? value : {};
|
|
2283
|
+
}
|
|
2284
|
+
const SOURCE_CONTEXT_KEYS = [
|
|
2285
|
+
"channel",
|
|
2286
|
+
"chatId",
|
|
2287
|
+
"accountId",
|
|
2288
|
+
"senderId",
|
|
2289
|
+
"sessionKey",
|
|
2290
|
+
"cron_job_id",
|
|
2291
|
+
"cron_job_name",
|
|
2292
|
+
"session_origin",
|
|
2293
|
+
"observation_delivery_id",
|
|
2294
|
+
"observation_subscription_id"
|
|
2295
|
+
];
|
|
2296
|
+
function readSourceContext(request) {
|
|
2297
|
+
const candidates = {
|
|
2298
|
+
...request.metadata ?? {},
|
|
2299
|
+
...request.message.metadata ?? {},
|
|
2300
|
+
...request.peerId ? { peerId: request.peerId } : {}
|
|
2301
|
+
};
|
|
2302
|
+
const entries = [...SOURCE_CONTEXT_KEYS, "peerId"].flatMap((key) => {
|
|
2303
|
+
const value = candidates[key];
|
|
2304
|
+
return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value) || typeof value === "boolean" ? [[key, value]] : [];
|
|
2305
|
+
});
|
|
2306
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
2307
|
+
}
|
|
2308
|
+
function createAgentToolRunTriggerInput(params) {
|
|
2309
|
+
const { request, source } = params;
|
|
2310
|
+
const runSpec = readSourceRunSpec(request.message);
|
|
2311
|
+
const sourceSessionId = readOptionalString$11(request.sessionId);
|
|
2312
|
+
const sourceRunId = readOptionalString$11(runSpec.runId);
|
|
2313
|
+
const sourceModel = readOptionalString$11(runSpec.model);
|
|
2314
|
+
const sourceContext = readSourceContext(request);
|
|
2315
|
+
return {
|
|
2316
|
+
actor: "agent",
|
|
2317
|
+
source,
|
|
2318
|
+
triggeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2319
|
+
...sourceSessionId ? { sourceSessionId } : {},
|
|
2320
|
+
sourceMessageId: request.message.id,
|
|
2321
|
+
...sourceRunId ? { sourceRunId } : {},
|
|
2322
|
+
...sourceModel ? { sourceModel } : {},
|
|
2323
|
+
...sourceContext ? { sourceContext } : {}
|
|
2324
|
+
};
|
|
2325
|
+
}
|
|
2326
|
+
function createIngressRunTriggerInput(params) {
|
|
2327
|
+
const { request } = params;
|
|
2328
|
+
const source = request.channel ? `channel:${request.channel}` : params.source.trim() || "internal";
|
|
2329
|
+
const sourceSessionId = readOptionalString$11(request.sessionId);
|
|
2330
|
+
const sourceContext = readSourceContext(request);
|
|
2331
|
+
const cronJobId = readOptionalString$11(request.metadata?.cron_job_id);
|
|
2332
|
+
const isCron = request.metadata?.session_origin === "cron" || Boolean(cronJobId);
|
|
2333
|
+
return {
|
|
2334
|
+
actor: isCron ? "automation" : request.message.role === "user" ? "human" : request.message.role === "service" ? "automation" : "system",
|
|
2335
|
+
source: isCron ? cronJobId ? `cron:${cronJobId}` : "cron" : source,
|
|
2336
|
+
triggeredAt: request.message.timestamp,
|
|
2337
|
+
...sourceSessionId ? { sourceSessionId } : {},
|
|
2338
|
+
sourceMessageId: request.message.id,
|
|
2339
|
+
...sourceContext ? { sourceContext } : {}
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
function resolveRunTriggerMetadata(params) {
|
|
2343
|
+
const { request, spec, startedAt } = params;
|
|
2344
|
+
const input = request.trigger ?? createIngressRunTriggerInput({
|
|
2345
|
+
request,
|
|
2346
|
+
source: "internal"
|
|
2347
|
+
});
|
|
2348
|
+
const triggeredAt = Number.isFinite(Date.parse(input.triggeredAt)) ? new Date(input.triggeredAt).toISOString() : startedAt;
|
|
2349
|
+
return {
|
|
2350
|
+
version: 1,
|
|
2351
|
+
...structuredClone(input),
|
|
2352
|
+
triggeredAt,
|
|
2353
|
+
targetRunId: spec.runId
|
|
2354
|
+
};
|
|
2355
|
+
}
|
|
2356
|
+
function createRunTriggerMetadataEvent(params) {
|
|
2357
|
+
const { sessionId, spec, trigger } = params;
|
|
2358
|
+
return {
|
|
2359
|
+
occurredAt: trigger.triggeredAt,
|
|
2360
|
+
type: NcpEventType.RunMetadata,
|
|
2361
|
+
payload: {
|
|
2362
|
+
sessionId,
|
|
2363
|
+
runId: spec.runId,
|
|
2364
|
+
correlationId: spec.correlationId,
|
|
2365
|
+
metadata: { [NCP_RUN_TRIGGER_METADATA_KEY]: structuredClone(trigger) }
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
function attachSourceToolCall(trigger, sourceToolCallId) {
|
|
2370
|
+
const normalizedToolCallId = readOptionalString$11(sourceToolCallId);
|
|
2371
|
+
return {
|
|
2372
|
+
...structuredClone(trigger),
|
|
2373
|
+
...normalizedToolCallId ? { sourceToolCallId: normalizedToolCallId } : {}
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
//#endregion
|
|
2246
2377
|
//#region src/managers/agent-run-request.manager.ts
|
|
2247
2378
|
var AgentRunRequestManager = class {
|
|
2248
2379
|
cleanups = [];
|
|
@@ -2283,9 +2414,14 @@ var AgentRunRequestManager = class {
|
|
|
2283
2414
|
this.sessionCommandManager.dispose();
|
|
2284
2415
|
this.started = false;
|
|
2285
2416
|
};
|
|
2286
|
-
handleSendRequest = async (envelope) => {
|
|
2417
|
+
handleSendRequest = async (envelope, context) => {
|
|
2287
2418
|
if (!envelope.payload) throw new Error("Invalid agent run send request.");
|
|
2288
|
-
|
|
2419
|
+
const request = toAgentRunRequest(envelope.payload);
|
|
2420
|
+
request.trigger = createIngressRunTriggerInput({
|
|
2421
|
+
request,
|
|
2422
|
+
source: context.source
|
|
2423
|
+
});
|
|
2424
|
+
return toRunHandle(await this.send(request));
|
|
2289
2425
|
};
|
|
2290
2426
|
handleAbortRequest = async (envelope) => {
|
|
2291
2427
|
if (!envelope.payload?.sessionId) throw new Error("Invalid agent run abort request.");
|
|
@@ -2312,7 +2448,8 @@ var AgentRunRequestManager = class {
|
|
|
2312
2448
|
...envelope.payload.message,
|
|
2313
2449
|
sessionId: envelope.payload.sessionId
|
|
2314
2450
|
},
|
|
2315
|
-
correlationId: envelope.payload.requestId
|
|
2451
|
+
correlationId: envelope.payload.requestId,
|
|
2452
|
+
trigger: structuredClone(envelope.payload.trigger)
|
|
2316
2453
|
}));
|
|
2317
2454
|
};
|
|
2318
2455
|
send = async (request) => await this.idempotency.accept(request, this.sendOnce);
|
|
@@ -2365,6 +2502,11 @@ var AgentRunRequestManager = class {
|
|
|
2365
2502
|
runId: activeRequest.runId,
|
|
2366
2503
|
session
|
|
2367
2504
|
});
|
|
2505
|
+
const trigger = resolveRunTriggerMetadata({
|
|
2506
|
+
request,
|
|
2507
|
+
spec,
|
|
2508
|
+
startedAt: requestRunStartedAt
|
|
2509
|
+
});
|
|
2368
2510
|
const message = attachRunSpecMetadata({
|
|
2369
2511
|
message: {
|
|
2370
2512
|
...request.message,
|
|
@@ -2375,7 +2517,8 @@ var AgentRunRequestManager = class {
|
|
|
2375
2517
|
request,
|
|
2376
2518
|
session,
|
|
2377
2519
|
spec,
|
|
2378
|
-
startedAt: requestRunStartedAt
|
|
2520
|
+
startedAt: requestRunStartedAt,
|
|
2521
|
+
trigger
|
|
2379
2522
|
});
|
|
2380
2523
|
const providerRequest = {
|
|
2381
2524
|
...request,
|
|
@@ -2402,8 +2545,14 @@ var AgentRunRequestManager = class {
|
|
|
2402
2545
|
message,
|
|
2403
2546
|
correlationId: request.correlationId
|
|
2404
2547
|
});
|
|
2405
|
-
|
|
2548
|
+
const triggerEvent = createRunTriggerMetadataEvent({
|
|
2549
|
+
sessionId: session.sessionId,
|
|
2550
|
+
spec,
|
|
2551
|
+
trigger
|
|
2552
|
+
});
|
|
2553
|
+
await sessionRun.applyEvents([messageSentEvent, triggerEvent]);
|
|
2406
2554
|
this.publishNcpEvent(messageSentEvent);
|
|
2555
|
+
this.publishNcpEvent(triggerEvent);
|
|
2407
2556
|
try {
|
|
2408
2557
|
const runtime = this.agentRuntimeManager.getOrCreate({
|
|
2409
2558
|
agentRuntimeId: session.agentRuntimeId,
|
|
@@ -10237,20 +10386,39 @@ function readMessageFromSummaryEvent(event) {
|
|
|
10237
10386
|
function readRecordLabel(record) {
|
|
10238
10387
|
return readOptionalString(record.metadata?.label) ?? void 0;
|
|
10239
10388
|
}
|
|
10389
|
+
function resolveRequestTrigger(params) {
|
|
10390
|
+
return {
|
|
10391
|
+
...params.trigger ?? {
|
|
10392
|
+
actor: "system",
|
|
10393
|
+
source: "session-request",
|
|
10394
|
+
triggeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10395
|
+
sourceSessionId: params.sourceSessionId
|
|
10396
|
+
},
|
|
10397
|
+
sourceRequestId: params.requestId
|
|
10398
|
+
};
|
|
10399
|
+
}
|
|
10240
10400
|
var SessionRequestManager = class {
|
|
10241
10401
|
constructor(options) {
|
|
10242
10402
|
this.options = options;
|
|
10243
10403
|
}
|
|
10244
10404
|
spawnSessionAndRequest = async (params) => {
|
|
10245
|
-
const { sourceSessionId, sourceToolCallId, updateToolCallResult, sourceSessionMetadata, metadataOverrides, contextInheritance, task, title, model, runtime, handoffDepth, sessionType, thinkingLevel, projectRoot, agentId, parentSessionId, notify } = params;
|
|
10405
|
+
const { sourceSessionId, sourceToolCallId, updateToolCallResult, sourceSessionMetadata, metadataOverrides, contextInheritance, task, title, model, runtime, handoffDepth, sessionType, thinkingLevel, projectRoot, agentId, parentSessionId, notify, trigger: requestedTrigger } = params;
|
|
10246
10406
|
const requestId = randomUUID();
|
|
10407
|
+
const trigger = resolveRequestTrigger({
|
|
10408
|
+
trigger: requestedTrigger,
|
|
10409
|
+
sourceSessionId,
|
|
10410
|
+
requestId
|
|
10411
|
+
});
|
|
10247
10412
|
const createdSession = await this.options.sessionManager.createSession({
|
|
10248
10413
|
sourceSessionId,
|
|
10249
10414
|
...parentSessionId ? { parentSessionId } : {},
|
|
10250
10415
|
task,
|
|
10251
10416
|
title,
|
|
10252
10417
|
sourceSessionMetadata,
|
|
10253
|
-
|
|
10418
|
+
metadataOverrides: {
|
|
10419
|
+
...metadataOverrides ?? {},
|
|
10420
|
+
session_creation_trigger: structuredClone(trigger)
|
|
10421
|
+
},
|
|
10254
10422
|
contextInheritance,
|
|
10255
10423
|
agentId,
|
|
10256
10424
|
model,
|
|
@@ -10273,18 +10441,25 @@ var SessionRequestManager = class {
|
|
|
10273
10441
|
agentId: createdSession.agentId,
|
|
10274
10442
|
isChildSession: Boolean(parentSessionId),
|
|
10275
10443
|
...parentSessionId ? { parentSessionId } : {},
|
|
10276
|
-
spawnedByRequestId: requestId
|
|
10444
|
+
spawnedByRequestId: requestId,
|
|
10445
|
+
trigger
|
|
10277
10446
|
});
|
|
10278
10447
|
};
|
|
10279
10448
|
requestSession = async (params) => {
|
|
10280
|
-
const { sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, notify, handoffDepth } = params;
|
|
10449
|
+
const { sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, notify, handoffDepth, trigger: requestedTrigger } = params;
|
|
10281
10450
|
const normalizedTargetSessionId = targetSessionId.trim();
|
|
10282
10451
|
if (normalizedTargetSessionId === sourceSessionId.trim()) throw new Error("sessions_request cannot target the current session.");
|
|
10283
10452
|
const targetSession = await this.options.sessionManager.getSessionRecord(normalizedTargetSessionId);
|
|
10284
10453
|
if (!targetSession) throw new Error(`Target session not found: ${targetSessionId}`);
|
|
10285
10454
|
const parentSessionId = readParentSessionId(targetSession.metadata);
|
|
10455
|
+
const requestId = randomUUID();
|
|
10456
|
+
const trigger = resolveRequestTrigger({
|
|
10457
|
+
trigger: requestedTrigger,
|
|
10458
|
+
sourceSessionId,
|
|
10459
|
+
requestId
|
|
10460
|
+
});
|
|
10286
10461
|
return this.dispatchRequest({
|
|
10287
|
-
requestId
|
|
10462
|
+
requestId,
|
|
10288
10463
|
sourceSessionId,
|
|
10289
10464
|
sourceToolCallId,
|
|
10290
10465
|
updateToolCallResult,
|
|
@@ -10296,11 +10471,12 @@ var SessionRequestManager = class {
|
|
|
10296
10471
|
agentId: targetSession.agentId,
|
|
10297
10472
|
isChildSession: Boolean(parentSessionId),
|
|
10298
10473
|
parentSessionId: parentSessionId ?? void 0,
|
|
10299
|
-
spawnedByRequestId: void 0
|
|
10474
|
+
spawnedByRequestId: void 0,
|
|
10475
|
+
trigger
|
|
10300
10476
|
});
|
|
10301
10477
|
};
|
|
10302
10478
|
dispatchRequest = async (params) => {
|
|
10303
|
-
const { requestId, sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, handoffDepth, notify, agentId, isChildSession, parentSessionId, spawnedByRequestId } = params;
|
|
10479
|
+
const { requestId, sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, handoffDepth, notify, agentId, isChildSession, parentSessionId, spawnedByRequestId, trigger } = params;
|
|
10304
10480
|
const request = createRunningSessionRequest({
|
|
10305
10481
|
requestId,
|
|
10306
10482
|
sourceSessionId,
|
|
@@ -10311,7 +10487,8 @@ var SessionRequestManager = class {
|
|
|
10311
10487
|
title,
|
|
10312
10488
|
task,
|
|
10313
10489
|
isChildSession,
|
|
10314
|
-
parentSessionId
|
|
10490
|
+
parentSessionId,
|
|
10491
|
+
trigger
|
|
10315
10492
|
});
|
|
10316
10493
|
const resultContext = {
|
|
10317
10494
|
task,
|
|
@@ -10469,6 +10646,13 @@ function waitForAgentRuntimeSessionReply(input) {
|
|
|
10469
10646
|
};
|
|
10470
10647
|
}
|
|
10471
10648
|
async function dispatchAgentRuntimeSessionRequest(input) {
|
|
10649
|
+
const trigger = parseNcpRunTriggerInput(input.request.metadata?.run_trigger) ?? {
|
|
10650
|
+
actor: "system",
|
|
10651
|
+
source: "session-request-recovery",
|
|
10652
|
+
triggeredAt: input.request.createdAt,
|
|
10653
|
+
sourceSessionId: input.request.sourceSessionId,
|
|
10654
|
+
sourceRequestId: input.request.requestId
|
|
10655
|
+
};
|
|
10472
10656
|
await input.ingress.handle({
|
|
10473
10657
|
type: ingressKeys$1.agentRun.sessionMessageRequest,
|
|
10474
10658
|
payload: {
|
|
@@ -10485,7 +10669,8 @@ async function dispatchAgentRuntimeSessionRequest(input) {
|
|
|
10485
10669
|
metadata: { session_request_id: input.request.requestId }
|
|
10486
10670
|
},
|
|
10487
10671
|
requestId: input.request.requestId,
|
|
10488
|
-
sessionId: input.request.targetSessionId
|
|
10672
|
+
sessionId: input.request.targetSessionId,
|
|
10673
|
+
trigger: structuredClone(trigger)
|
|
10489
10674
|
}
|
|
10490
10675
|
}, { source: "session-request" });
|
|
10491
10676
|
}
|
|
@@ -12826,6 +13011,7 @@ const createSelfManagementContextProvider = () => ({ provide: () => {
|
|
|
12826
13011
|
} });
|
|
12827
13012
|
const createSessionOrchestrationContextProvider = () => staticBlock([
|
|
12828
13013
|
"## Session Orchestration",
|
|
13014
|
+
"- Only top-level sessions can create new sessions. Child sessions must complete their delegated task directly and return further delegation needs to the parent session.",
|
|
12829
13015
|
"- Before passing a non-default `runtime` to `sessions_spawn` or agent creation/update flows, inspect the installed runtime kinds with `nextclaw agents runtimes --json`.",
|
|
12830
13016
|
"- `sessions_spawn` is the unified session-creation tool. Omit `scope` or use `scope=\"standalone\"` for a regular session, and use `scope=\"child\"` when the new session should be a child session of the current flow.",
|
|
12831
13017
|
"- `sessions_spawn` only creates the session by default. Add top-level `notify: \"none\" | \"final_reply\"` when the new session should start working immediately.",
|
|
@@ -12977,6 +13163,9 @@ function renderWebSearchReadiness(params) {
|
|
|
12977
13163
|
if (!readSearchApiKey(searchConfig, provider)) return `web_search is not ready: provider ${provider} has no API key configured.`;
|
|
12978
13164
|
return `web_search is ready with provider ${provider}.`;
|
|
12979
13165
|
}
|
|
13166
|
+
function renderDelegationGuidance(toolNames) {
|
|
13167
|
+
return toolNames.includes("sessions_spawn") ? "If a task is more complex or takes longer, spawn a sub-agent. Completion is push-based: it will auto-announce when done." : "Sub-agent spawning is unavailable in this delegated session. Complete the assigned task directly and return any further delegation needs to the parent session.";
|
|
13168
|
+
}
|
|
12980
13169
|
var ToolingContextProvider = class {
|
|
12981
13170
|
constructor(context) {
|
|
12982
13171
|
this.context = context;
|
|
@@ -12998,7 +13187,7 @@ var ToolingContextProvider = class {
|
|
|
12998
13187
|
"TOOLS.md does not control tool availability; it is user guidance for how to use external tools.",
|
|
12999
13188
|
"For long waits, avoid rapid poll loops: use exec with enough yieldMs.",
|
|
13000
13189
|
"For relative time/date scheduling requests (for example 'in 5 minutes' / '1分钟后'), first check the current local time with an available tool such as exec/date, then convert it to an absolute ISO time with timezone. Do not guess.",
|
|
13001
|
-
|
|
13190
|
+
renderDelegationGuidance(toolCatalog.map((tool) => tool.name)),
|
|
13002
13191
|
"Do not poll `subagents list` / `sessions_list` in a loop; only check status on-demand (for intervention, debugging, or when explicitly asked)."
|
|
13003
13192
|
].join("\n")];
|
|
13004
13193
|
};
|
|
@@ -13692,6 +13881,7 @@ var LearningLoopContribution = class extends Contribution$1 {
|
|
|
13692
13881
|
if (toolCallsSinceReview < runtimeConfig.toolCallThreshold) return;
|
|
13693
13882
|
this.inFlightSessionIds.add(sessionId);
|
|
13694
13883
|
try {
|
|
13884
|
+
const triggeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13695
13885
|
const reviewSession = await this.sessionRequester.spawnSessionAndRequest({
|
|
13696
13886
|
sourceSessionId: sessionId,
|
|
13697
13887
|
sourceSessionMetadata: metadata,
|
|
@@ -13707,11 +13897,18 @@ var LearningLoopContribution = class extends Contribution$1 {
|
|
|
13707
13897
|
sessionId,
|
|
13708
13898
|
toolCallsSinceReview,
|
|
13709
13899
|
currentToolCallCount: totalToolCalls
|
|
13710
|
-
})
|
|
13900
|
+
}),
|
|
13901
|
+
trigger: {
|
|
13902
|
+
actor: "automation",
|
|
13903
|
+
source: "learning-loop",
|
|
13904
|
+
triggeredAt,
|
|
13905
|
+
sourceSessionId: sessionId,
|
|
13906
|
+
...typeof metadata.preferred_model === "string" && metadata.preferred_model.trim() ? { sourceModel: metadata.preferred_model.trim() } : {}
|
|
13907
|
+
}
|
|
13711
13908
|
});
|
|
13712
13909
|
await this.sessionStore.updateSessionMetadata(sessionId, {
|
|
13713
13910
|
[LEARNING_LOOP_LAST_TOOL_CALL_COUNT_METADATA_KEY]: totalToolCalls,
|
|
13714
|
-
[LEARNING_LOOP_LAST_REQUESTED_AT_METADATA_KEY]:
|
|
13911
|
+
[LEARNING_LOOP_LAST_REQUESTED_AT_METADATA_KEY]: triggeredAt,
|
|
13715
13912
|
[LEARNING_LOOP_LAST_REVIEW_SESSION_ID_METADATA_KEY]: reviewSession.sessionId
|
|
13716
13913
|
});
|
|
13717
13914
|
} finally {
|
|
@@ -14076,12 +14273,14 @@ var SessionRequestTool = class {
|
|
|
14076
14273
|
};
|
|
14077
14274
|
sourceSessionId = "";
|
|
14078
14275
|
handoffDepth = 0;
|
|
14276
|
+
trigger = null;
|
|
14079
14277
|
constructor(manager) {
|
|
14080
14278
|
this.manager = manager;
|
|
14081
14279
|
}
|
|
14082
14280
|
setContext = (params) => {
|
|
14083
14281
|
this.sourceSessionId = params.sourceSessionId;
|
|
14084
14282
|
this.handoffDepth = params.handoffDepth ?? 0;
|
|
14283
|
+
this.trigger = structuredClone(params.trigger);
|
|
14085
14284
|
};
|
|
14086
14285
|
execute = async (args, context) => {
|
|
14087
14286
|
const params = normalizeToolParams(args);
|
|
@@ -14098,9 +14297,14 @@ var SessionRequestTool = class {
|
|
|
14098
14297
|
task,
|
|
14099
14298
|
title: readOptionalString$6(params, "title"),
|
|
14100
14299
|
notify: notifyMode,
|
|
14101
|
-
handoffDepth: this.handoffDepth
|
|
14300
|
+
handoffDepth: this.handoffDepth,
|
|
14301
|
+
trigger: attachSourceToolCall(this.readTriggerOrThrow(), context?.toolCallId)
|
|
14102
14302
|
});
|
|
14103
14303
|
};
|
|
14304
|
+
readTriggerOrThrow = () => {
|
|
14305
|
+
if (!this.trigger) throw new Error("sessions_request requires an active run trigger context.");
|
|
14306
|
+
return structuredClone(this.trigger);
|
|
14307
|
+
};
|
|
14104
14308
|
};
|
|
14105
14309
|
//#endregion
|
|
14106
14310
|
//#region src/tools/session-search.tools.ts
|
|
@@ -14240,16 +14444,20 @@ var SessionSpawnTool = class {
|
|
|
14240
14444
|
sourceSessionId = "";
|
|
14241
14445
|
sourceSessionMetadata = {};
|
|
14242
14446
|
handoffDepth = 0;
|
|
14447
|
+
trigger = null;
|
|
14243
14448
|
constructor(sessionManager, sessionRequestManager) {
|
|
14244
14449
|
this.sessionManager = sessionManager;
|
|
14245
14450
|
this.sessionRequestManager = sessionRequestManager;
|
|
14246
14451
|
}
|
|
14247
14452
|
setContext = (params) => {
|
|
14248
|
-
|
|
14249
|
-
this.
|
|
14250
|
-
this.
|
|
14453
|
+
const { handoffDepth, sourceSessionId, sourceSessionMetadata, trigger } = params;
|
|
14454
|
+
this.sourceSessionId = sourceSessionId;
|
|
14455
|
+
this.sourceSessionMetadata = structuredClone(sourceSessionMetadata);
|
|
14456
|
+
this.handoffDepth = handoffDepth ?? 0;
|
|
14457
|
+
this.trigger = structuredClone(trigger);
|
|
14251
14458
|
};
|
|
14252
14459
|
execute = async (args, context) => {
|
|
14460
|
+
const { toolCallId, updateToolCallResult } = context ?? {};
|
|
14253
14461
|
const { agentId: rawAgentId, model: rawModel, notify: rawNotify, runtime: rawRuntime, scope: rawScope, task: rawTask, title: rawTitle, inheritContext: rawInheritContext } = normalizeToolParams(args);
|
|
14254
14462
|
const task = readRequiredString$4(rawTask, "task");
|
|
14255
14463
|
const scope = readSpawnScope(rawScope);
|
|
@@ -14257,11 +14465,12 @@ var SessionSpawnTool = class {
|
|
|
14257
14465
|
const inheritContext = readInheritContext(rawInheritContext);
|
|
14258
14466
|
if (inheritContext && scope !== "child") throw new Error("inheritContext=true requires scope=\"child\".");
|
|
14259
14467
|
const parentSessionId = scope === "child" ? this.readParentSessionIdOrThrow() : void 0;
|
|
14260
|
-
const contextInheritance = inheritContext ? { anchorToolCallId:
|
|
14468
|
+
const contextInheritance = inheritContext ? { anchorToolCallId: toolCallId } : void 0;
|
|
14469
|
+
const trigger = attachSourceToolCall(this.readTriggerOrThrow(), toolCallId);
|
|
14261
14470
|
if (notify) return this.sessionRequestManager.spawnSessionAndRequest({
|
|
14262
14471
|
sourceSessionId: this.sourceSessionId,
|
|
14263
|
-
sourceToolCallId:
|
|
14264
|
-
updateToolCallResult
|
|
14472
|
+
sourceToolCallId: toolCallId,
|
|
14473
|
+
updateToolCallResult,
|
|
14265
14474
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
14266
14475
|
task,
|
|
14267
14476
|
title: readOptionalString$5(rawTitle),
|
|
@@ -14271,7 +14480,8 @@ var SessionSpawnTool = class {
|
|
|
14271
14480
|
contextInheritance,
|
|
14272
14481
|
handoffDepth: this.handoffDepth,
|
|
14273
14482
|
parentSessionId,
|
|
14274
|
-
notify
|
|
14483
|
+
notify,
|
|
14484
|
+
trigger
|
|
14275
14485
|
});
|
|
14276
14486
|
const session = await this.sessionManager.createSession({
|
|
14277
14487
|
sourceSessionId: this.sourceSessionId,
|
|
@@ -14282,7 +14492,8 @@ var SessionSpawnTool = class {
|
|
|
14282
14492
|
model: readOptionalString$5(rawModel),
|
|
14283
14493
|
runtime: readOptionalString$5(rawRuntime),
|
|
14284
14494
|
contextInheritance,
|
|
14285
|
-
parentSessionId
|
|
14495
|
+
parentSessionId,
|
|
14496
|
+
metadataOverrides: { session_creation_trigger: structuredClone(trigger) }
|
|
14286
14497
|
});
|
|
14287
14498
|
return {
|
|
14288
14499
|
kind: "nextclaw.session",
|
|
@@ -14301,6 +14512,10 @@ var SessionSpawnTool = class {
|
|
|
14301
14512
|
if (!sourceSessionId) throw new Error("scope=\"child\" requires an active source session.");
|
|
14302
14513
|
return sourceSessionId;
|
|
14303
14514
|
};
|
|
14515
|
+
readTriggerOrThrow = () => {
|
|
14516
|
+
if (!this.trigger) throw new Error("sessions_spawn requires an active run trigger context.");
|
|
14517
|
+
return structuredClone(this.trigger);
|
|
14518
|
+
};
|
|
14304
14519
|
};
|
|
14305
14520
|
//#endregion
|
|
14306
14521
|
//#region src/tools/session-update.tools.ts
|
|
@@ -14355,26 +14570,38 @@ var SessionToolProvider = class {
|
|
|
14355
14570
|
this.sessionSearch = sessionSearch;
|
|
14356
14571
|
}
|
|
14357
14572
|
provide = async (request) => {
|
|
14358
|
-
const { toolRunContext } = await this.runContextService.resolve(request);
|
|
14573
|
+
const { session, toolRunContext } = await this.runContextService.resolve(request);
|
|
14359
14574
|
const { handoffDepth, metadata, sessionId } = toolRunContext;
|
|
14360
|
-
const
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
handoffDepth
|
|
14575
|
+
const isChildSession = Boolean(readParentSessionId(session?.metadata ?? metadata));
|
|
14576
|
+
const requestTrigger = createAgentToolRunTriggerInput({
|
|
14577
|
+
request,
|
|
14578
|
+
source: "sessions_request"
|
|
14365
14579
|
});
|
|
14366
14580
|
const sessionsRequestTool = new SessionRequestTool(this.sessionRequests);
|
|
14367
14581
|
sessionsRequestTool.setContext({
|
|
14368
14582
|
sourceSessionId: sessionId,
|
|
14369
|
-
handoffDepth
|
|
14583
|
+
handoffDepth,
|
|
14584
|
+
trigger: requestTrigger
|
|
14370
14585
|
});
|
|
14371
14586
|
const tools = [
|
|
14372
|
-
sessionsSpawnTool,
|
|
14373
14587
|
sessionsRequestTool,
|
|
14374
14588
|
new SessionsListTool(this.sessionManager),
|
|
14375
14589
|
new SessionsHistoryTool(this.sessionManager),
|
|
14376
14590
|
new SessionsUpdateTool(this.sessionManager)
|
|
14377
14591
|
];
|
|
14592
|
+
if (!isChildSession) {
|
|
14593
|
+
const sessionsSpawnTool = new SessionSpawnTool(this.sessionManager, this.sessionRequests);
|
|
14594
|
+
sessionsSpawnTool.setContext({
|
|
14595
|
+
sourceSessionId: sessionId,
|
|
14596
|
+
sourceSessionMetadata: metadata,
|
|
14597
|
+
handoffDepth,
|
|
14598
|
+
trigger: createAgentToolRunTriggerInput({
|
|
14599
|
+
request,
|
|
14600
|
+
source: "sessions_spawn"
|
|
14601
|
+
})
|
|
14602
|
+
});
|
|
14603
|
+
tools.unshift(sessionsSpawnTool);
|
|
14604
|
+
}
|
|
14378
14605
|
if (!this.sessionSearch.isReady()) return tools;
|
|
14379
14606
|
tools.push(new SessionSearchTool({ search: this.sessionSearch.search }, { currentSessionId: sessionId }));
|
|
14380
14607
|
return tools;
|
|
@@ -15242,6 +15469,14 @@ const SESSION_METADATA_LABEL_KEY = "label";
|
|
|
15242
15469
|
const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
|
|
15243
15470
|
const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
|
|
15244
15471
|
const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
|
|
15472
|
+
async function assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, getSessionRecord) {
|
|
15473
|
+
if (Object.prototype.hasOwnProperty.call(metadataOverrides ?? {}, CHILD_SESSION_PARENT_METADATA_KEY)) throw new Error("Session parent must be set through parentSessionId.");
|
|
15474
|
+
if (readOptionalMetadataString(sourceRecord?.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Source session: ${sourceRecord?.sessionId}.`);
|
|
15475
|
+
if (!parentSessionId) return;
|
|
15476
|
+
const parentRecord = sourceRecord?.sessionId === parentSessionId ? sourceRecord : await getSessionRecord(parentSessionId);
|
|
15477
|
+
if (!parentRecord) throw new Error(`Parent session not found: ${parentSessionId}`);
|
|
15478
|
+
if (readOptionalMetadataString(parentRecord.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Parent session: ${parentSessionId}.`);
|
|
15479
|
+
}
|
|
15245
15480
|
function readThinkingEffort(metadata) {
|
|
15246
15481
|
return readOptionalMetadataString(metadata?.thinkingEffort) ?? readOptionalMetadataString(metadata?.preferred_thinking) ?? readOptionalMetadataString(metadata?.thinking) ?? null;
|
|
15247
15482
|
}
|
|
@@ -17294,6 +17529,7 @@ var SessionManager = class {
|
|
|
17294
17529
|
const metadata = cloneInheritedMetadata(sourceSessionMetadata);
|
|
17295
17530
|
const title = readOptionalString$2(requestedTitle) ?? summarizeTask(task);
|
|
17296
17531
|
const parentSessionId = readOptionalString$2(rawParentSessionId);
|
|
17532
|
+
await assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, this.getSessionRecord);
|
|
17297
17533
|
const requestId = readOptionalString$2(rawRequestId);
|
|
17298
17534
|
const sessionType = resolveSessionType({
|
|
17299
17535
|
runtime,
|
|
@@ -17453,23 +17689,9 @@ var SessionManager = class {
|
|
|
17453
17689
|
return (liveRecord ? await this.summaryProjection.createWithContextWindow(liveRecord) : await this.getSession(sessionId))?.contextWindow ?? null;
|
|
17454
17690
|
};
|
|
17455
17691
|
getAgentRunSession = async (sessionId) => {
|
|
17456
|
-
const
|
|
17457
|
-
if (!
|
|
17458
|
-
|
|
17459
|
-
const model = readOptionalMetadataString(record.metadata?.model);
|
|
17460
|
-
return {
|
|
17461
|
-
sessionId: record.sessionId,
|
|
17462
|
-
agentId: record.agentId,
|
|
17463
|
-
agentRuntimeId,
|
|
17464
|
-
metadata: structuredClone(record.metadata ?? {}),
|
|
17465
|
-
model,
|
|
17466
|
-
projectRoot: readProjectRoot(record.metadata),
|
|
17467
|
-
workingDir: this.workingDirResolver.resolve({
|
|
17468
|
-
agentId: record.agentId,
|
|
17469
|
-
metadata: record.metadata
|
|
17470
|
-
}),
|
|
17471
|
-
thinkingEffort: readThinkingEffort(record.metadata)
|
|
17472
|
-
};
|
|
17692
|
+
const summary = await this.options.journalStore.getSessionSummary(sessionId);
|
|
17693
|
+
if (!summary) throw new Error(`Session not found: ${sessionId}`);
|
|
17694
|
+
return this.toAgentRunSession(summary);
|
|
17473
17695
|
};
|
|
17474
17696
|
createAgentRunSession = async (params) => {
|
|
17475
17697
|
const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, contextInheritance, metadata, model, parentSessionId: rawParentSessionId, peerId: rawPeerId, projectRoot, sessionId, sourceSessionId: rawSourceSessionId, sourceSessionMetadata: requestedSourceSessionMetadata, task, thinkingEffort } = params;
|
|
@@ -17520,7 +17742,24 @@ var SessionManager = class {
|
|
|
17520
17742
|
};
|
|
17521
17743
|
getOrCreateAgentRunSession = async (params) => {
|
|
17522
17744
|
if (!params.sessionId) return await this.createAgentRunSession(params);
|
|
17523
|
-
|
|
17745
|
+
const summary = await this.options.journalStore.getSessionSummary(params.sessionId);
|
|
17746
|
+
return summary ? this.toAgentRunSession(summary) : await this.createAgentRunSession(params);
|
|
17747
|
+
};
|
|
17748
|
+
toAgentRunSession = (summary) => {
|
|
17749
|
+
const metadata = summary.metadata ?? {};
|
|
17750
|
+
return {
|
|
17751
|
+
sessionId: summary.sessionId,
|
|
17752
|
+
agentId: summary.agentId,
|
|
17753
|
+
agentRuntimeId: readOptionalMetadataString(metadata.agentRuntimeId) ?? "native",
|
|
17754
|
+
metadata: structuredClone(metadata),
|
|
17755
|
+
model: readOptionalMetadataString(metadata.model) ?? readOptionalMetadataString(metadata.preferred_model),
|
|
17756
|
+
projectRoot: readProjectRoot(metadata),
|
|
17757
|
+
workingDir: this.workingDirResolver.resolve({
|
|
17758
|
+
agentId: summary.agentId,
|
|
17759
|
+
metadata
|
|
17760
|
+
}),
|
|
17761
|
+
thinkingEffort: readThinkingEffort(metadata)
|
|
17762
|
+
};
|
|
17524
17763
|
};
|
|
17525
17764
|
patchSessionMetadata = async (sessionId, patch) => {
|
|
17526
17765
|
if (!await this.updateSessionMetadata(sessionId, patch)) throw new Error(`Session metadata was not updated: ${sessionId}`);
|