@nextclaw/kernel 0.10.0 → 0.10.2
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 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +361 -97
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
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
|
};
|
|
@@ -1772,13 +1787,14 @@ var AgentRunInputDeliveryService = class {
|
|
|
1772
1787
|
input: this.toPendingInput(moved)
|
|
1773
1788
|
};
|
|
1774
1789
|
};
|
|
1775
|
-
|
|
1790
|
+
promotePreferredSteeringInput = (sessionRun, queuedInputId, session) => {
|
|
1776
1791
|
try {
|
|
1777
|
-
|
|
1792
|
+
if (this.agentRuntimeManager.getOrCreate({
|
|
1778
1793
|
agentRuntimeId: session.agentRuntimeId,
|
|
1779
1794
|
session,
|
|
1780
1795
|
sessionRun
|
|
1781
|
-
}).capabilities?.nextStepInput
|
|
1796
|
+
}).capabilities?.nextStepInput !== true) return null;
|
|
1797
|
+
return sessionRun.moveQueuedRequestToNextStep(queuedInputId);
|
|
1782
1798
|
} catch {
|
|
1783
1799
|
return null;
|
|
1784
1800
|
}
|
|
@@ -1950,13 +1966,13 @@ function createUnavailableAiExecutionMetadataEvent(params) {
|
|
|
1950
1966
|
}
|
|
1951
1967
|
//#endregion
|
|
1952
1968
|
//#region src/utils/agent-run-request.utils.ts
|
|
1953
|
-
function readOptionalString$
|
|
1969
|
+
function readOptionalString$12(value) {
|
|
1954
1970
|
if (typeof value !== "string") return;
|
|
1955
1971
|
return value.trim() || void 0;
|
|
1956
1972
|
}
|
|
1957
1973
|
function toAgentRunRequest(envelope) {
|
|
1958
1974
|
const metadata = envelope.metadata ?? {};
|
|
1959
|
-
const peerId = readOptionalString$
|
|
1975
|
+
const peerId = readOptionalString$12(envelope.peerId);
|
|
1960
1976
|
const requestMetadata = {
|
|
1961
1977
|
agentRuntimeId: metadata.agentRuntimeId,
|
|
1962
1978
|
agentId: metadata.agentId,
|
|
@@ -1968,10 +1984,10 @@ function toAgentRunRequest(envelope) {
|
|
|
1968
1984
|
maxTokens: metadata.maxTokens,
|
|
1969
1985
|
thinkingEffort: metadata.thinkingEffort,
|
|
1970
1986
|
delivery: envelope.delivery,
|
|
1971
|
-
idempotencyKey: readOptionalString$
|
|
1987
|
+
idempotencyKey: readOptionalString$12(envelope.idempotencyKey)
|
|
1972
1988
|
};
|
|
1973
1989
|
if (Array.isArray(envelope.content)) {
|
|
1974
|
-
const sessionId = readOptionalString$
|
|
1990
|
+
const sessionId = readOptionalString$12(envelope.sessionId);
|
|
1975
1991
|
if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
|
|
1976
1992
|
return {
|
|
1977
1993
|
...requestMetadata,
|
|
@@ -1989,8 +2005,8 @@ function toAgentRunRequest(envelope) {
|
|
|
1989
2005
|
}
|
|
1990
2006
|
const sourceMessage = envelope.message;
|
|
1991
2007
|
if (!sourceMessage) throw new Error("Invalid agent run send request.");
|
|
1992
|
-
const envelopeSessionId = readOptionalString$
|
|
1993
|
-
const messageSessionId = readOptionalString$
|
|
2008
|
+
const envelopeSessionId = readOptionalString$12(envelope.sessionId);
|
|
2009
|
+
const messageSessionId = readOptionalString$12(sourceMessage.sessionId);
|
|
1994
2010
|
const sessionId = envelopeSessionId ?? messageSessionId;
|
|
1995
2011
|
if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
|
|
1996
2012
|
return {
|
|
@@ -2051,7 +2067,7 @@ function readSessionMaterialization(metadata) {
|
|
|
2051
2067
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2052
2068
|
const materialization = value;
|
|
2053
2069
|
if (materialization.kind !== "child") throw new Error("session_materialization.kind must be \"child\".");
|
|
2054
|
-
const parentSessionId = readOptionalString$
|
|
2070
|
+
const parentSessionId = readOptionalString$12(materialization.parentSessionId);
|
|
2055
2071
|
if (!parentSessionId) throw new Error("session_materialization.parentSessionId is required.");
|
|
2056
2072
|
if (materialization.inheritContext !== true) throw new Error("session_materialization.inheritContext must be true.");
|
|
2057
2073
|
return {
|
|
@@ -2093,7 +2109,7 @@ function resolveRunSpec(params) {
|
|
|
2093
2109
|
};
|
|
2094
2110
|
}
|
|
2095
2111
|
function attachRunSpecMetadata(params) {
|
|
2096
|
-
const { message, modelSource, request, session, spec, startedAt } = params;
|
|
2112
|
+
const { message, modelSource, request, session, spec, startedAt, trigger } = params;
|
|
2097
2113
|
const metadata = structuredClone(message.metadata ?? {});
|
|
2098
2114
|
metadata[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY] = {
|
|
2099
2115
|
version: 1,
|
|
@@ -2112,6 +2128,7 @@ function attachRunSpecMetadata(params) {
|
|
|
2112
2128
|
correlationId: spec.correlationId ?? null,
|
|
2113
2129
|
execution: structuredClone(AGENT_RUN_EXECUTION_METADATA)
|
|
2114
2130
|
};
|
|
2131
|
+
metadata[NCP_RUN_TRIGGER_METADATA_KEY] = structuredClone(trigger);
|
|
2115
2132
|
return {
|
|
2116
2133
|
...message,
|
|
2117
2134
|
metadata
|
|
@@ -2164,7 +2181,7 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2164
2181
|
}));
|
|
2165
2182
|
messageCompletedSeen = true;
|
|
2166
2183
|
}
|
|
2167
|
-
eventsToPublish.push(event);
|
|
2184
|
+
eventsToPublish.push(this.projectCompletedMessage(event, sessionRun));
|
|
2168
2185
|
eventsToPublish.forEach(this.publishNcpEvent);
|
|
2169
2186
|
if (consumedSteeringInput) this.publishRunQueueUpdated(session.sessionId);
|
|
2170
2187
|
}), catchError(async (error) => {
|
|
@@ -2235,6 +2252,17 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2235
2252
|
source: "agent-run-request"
|
|
2236
2253
|
});
|
|
2237
2254
|
};
|
|
2255
|
+
projectCompletedMessage = (event, sessionRun) => {
|
|
2256
|
+
if (event.type !== NcpEventType.MessageCompleted) return event;
|
|
2257
|
+
const message = sessionRun.getSnapshot().messages.find((item) => item.id === event.payload.message.id);
|
|
2258
|
+
return message ? {
|
|
2259
|
+
...event,
|
|
2260
|
+
payload: {
|
|
2261
|
+
...event.payload,
|
|
2262
|
+
message: structuredClone(message)
|
|
2263
|
+
}
|
|
2264
|
+
} : event;
|
|
2265
|
+
};
|
|
2238
2266
|
publishNcpEvent = (event) => {
|
|
2239
2267
|
this.options.eventBus.emit(eventKeys$1.ncpEvent, event, {
|
|
2240
2268
|
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2243,6 +2271,125 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2243
2271
|
};
|
|
2244
2272
|
};
|
|
2245
2273
|
//#endregion
|
|
2274
|
+
//#region src/utils/agent-run-trigger.utils.ts
|
|
2275
|
+
function isRecord$17(value) {
|
|
2276
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2277
|
+
}
|
|
2278
|
+
function readOptionalString$11(value) {
|
|
2279
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2280
|
+
}
|
|
2281
|
+
function readSourceRunSpec(message) {
|
|
2282
|
+
const value = message.metadata?.[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY];
|
|
2283
|
+
return isRecord$17(value) ? value : {};
|
|
2284
|
+
}
|
|
2285
|
+
const SOURCE_CONTEXT_KEYS = [
|
|
2286
|
+
"channel",
|
|
2287
|
+
"chatId",
|
|
2288
|
+
"accountId",
|
|
2289
|
+
"senderId",
|
|
2290
|
+
"sessionKey",
|
|
2291
|
+
"cron_job_id",
|
|
2292
|
+
"cron_job_name",
|
|
2293
|
+
"session_origin",
|
|
2294
|
+
"observation_delivery_id",
|
|
2295
|
+
"observation_subscription_id"
|
|
2296
|
+
];
|
|
2297
|
+
function readSourceContext(request) {
|
|
2298
|
+
const candidates = {
|
|
2299
|
+
...request.metadata ?? {},
|
|
2300
|
+
...request.message.metadata ?? {},
|
|
2301
|
+
...request.peerId ? { peerId: request.peerId } : {}
|
|
2302
|
+
};
|
|
2303
|
+
const entries = [...SOURCE_CONTEXT_KEYS, "peerId"].flatMap((key) => {
|
|
2304
|
+
const value = candidates[key];
|
|
2305
|
+
return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value) || typeof value === "boolean" ? [[key, value]] : [];
|
|
2306
|
+
});
|
|
2307
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
2308
|
+
}
|
|
2309
|
+
function createAgentToolRunTriggerInput(params) {
|
|
2310
|
+
const { request, source } = params;
|
|
2311
|
+
const runSpec = readSourceRunSpec(request.message);
|
|
2312
|
+
const sourceSessionId = readOptionalString$11(request.sessionId);
|
|
2313
|
+
const sourceRunId = readOptionalString$11(runSpec.runId);
|
|
2314
|
+
const sourceModel = readOptionalString$11(runSpec.model);
|
|
2315
|
+
const sourceContext = readSourceContext(request);
|
|
2316
|
+
return {
|
|
2317
|
+
actor: "agent",
|
|
2318
|
+
source,
|
|
2319
|
+
triggeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2320
|
+
...sourceSessionId ? { sourceSessionId } : {},
|
|
2321
|
+
sourceMessageId: request.message.id,
|
|
2322
|
+
...sourceRunId ? { sourceRunId } : {},
|
|
2323
|
+
...sourceModel ? { sourceModel } : {},
|
|
2324
|
+
...sourceContext ? { sourceContext } : {}
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
function createIngressRunTriggerInput(params) {
|
|
2328
|
+
const { request } = params;
|
|
2329
|
+
const source = request.channel ? `channel:${request.channel}` : params.source.trim() || "internal";
|
|
2330
|
+
const sourceSessionId = readOptionalString$11(request.sessionId);
|
|
2331
|
+
const sourceContext = readSourceContext(request);
|
|
2332
|
+
const cronJobId = readOptionalString$11(request.metadata?.cron_job_id);
|
|
2333
|
+
const isCron = request.metadata?.session_origin === "cron" || Boolean(cronJobId);
|
|
2334
|
+
return {
|
|
2335
|
+
actor: isCron ? "automation" : request.message.role === "user" ? "human" : request.message.role === "service" ? "automation" : "system",
|
|
2336
|
+
source: isCron ? cronJobId ? `cron:${cronJobId}` : "cron" : source,
|
|
2337
|
+
triggeredAt: request.message.timestamp,
|
|
2338
|
+
...sourceSessionId ? { sourceSessionId } : {},
|
|
2339
|
+
sourceMessageId: request.message.id,
|
|
2340
|
+
...sourceContext ? { sourceContext } : {}
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
function resolveRunTriggerMetadata(params) {
|
|
2344
|
+
const { request, spec, startedAt } = params;
|
|
2345
|
+
return resolveTargetRunTriggerMetadata({
|
|
2346
|
+
request,
|
|
2347
|
+
targetRunId: spec.runId,
|
|
2348
|
+
fallbackTriggeredAt: startedAt
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
function resolveSteeringRunTriggerMetadata(params) {
|
|
2352
|
+
return resolveTargetRunTriggerMetadata({
|
|
2353
|
+
request: params.request,
|
|
2354
|
+
targetRunId: params.targetRunId,
|
|
2355
|
+
fallbackTriggeredAt: params.acceptedAt
|
|
2356
|
+
});
|
|
2357
|
+
}
|
|
2358
|
+
function resolveTargetRunTriggerMetadata(params) {
|
|
2359
|
+
const { request } = params;
|
|
2360
|
+
const input = request.trigger ?? createIngressRunTriggerInput({
|
|
2361
|
+
request,
|
|
2362
|
+
source: "internal"
|
|
2363
|
+
});
|
|
2364
|
+
const triggeredAt = Number.isFinite(Date.parse(input.triggeredAt)) ? new Date(input.triggeredAt).toISOString() : params.fallbackTriggeredAt;
|
|
2365
|
+
return {
|
|
2366
|
+
version: 1,
|
|
2367
|
+
...structuredClone(input),
|
|
2368
|
+
triggeredAt,
|
|
2369
|
+
targetRunId: params.targetRunId
|
|
2370
|
+
};
|
|
2371
|
+
}
|
|
2372
|
+
function createRunTriggerMetadataEvent(params) {
|
|
2373
|
+
const { sessionId, spec, trigger } = params;
|
|
2374
|
+
return {
|
|
2375
|
+
occurredAt: trigger.triggeredAt,
|
|
2376
|
+
type: NcpEventType.RunMetadata,
|
|
2377
|
+
payload: {
|
|
2378
|
+
sessionId,
|
|
2379
|
+
runId: spec.runId,
|
|
2380
|
+
correlationId: spec.correlationId,
|
|
2381
|
+
metadata: { [NCP_RUN_TRIGGER_METADATA_KEY]: structuredClone(trigger) }
|
|
2382
|
+
}
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
function attachSourceToolCall(trigger, sourceToolCallId) {
|
|
2386
|
+
const normalizedToolCallId = readOptionalString$11(sourceToolCallId);
|
|
2387
|
+
return {
|
|
2388
|
+
...structuredClone(trigger),
|
|
2389
|
+
...normalizedToolCallId ? { sourceToolCallId: normalizedToolCallId } : {}
|
|
2390
|
+
};
|
|
2391
|
+
}
|
|
2392
|
+
//#endregion
|
|
2246
2393
|
//#region src/managers/agent-run-request.manager.ts
|
|
2247
2394
|
var AgentRunRequestManager = class {
|
|
2248
2395
|
cleanups = [];
|
|
@@ -2283,9 +2430,14 @@ var AgentRunRequestManager = class {
|
|
|
2283
2430
|
this.sessionCommandManager.dispose();
|
|
2284
2431
|
this.started = false;
|
|
2285
2432
|
};
|
|
2286
|
-
handleSendRequest = async (envelope) => {
|
|
2433
|
+
handleSendRequest = async (envelope, context) => {
|
|
2287
2434
|
if (!envelope.payload) throw new Error("Invalid agent run send request.");
|
|
2288
|
-
|
|
2435
|
+
const request = toAgentRunRequest(envelope.payload);
|
|
2436
|
+
request.trigger = createIngressRunTriggerInput({
|
|
2437
|
+
request,
|
|
2438
|
+
source: context.source
|
|
2439
|
+
});
|
|
2440
|
+
return toRunHandle(await this.send(request));
|
|
2289
2441
|
};
|
|
2290
2442
|
handleAbortRequest = async (envelope) => {
|
|
2291
2443
|
if (!envelope.payload?.sessionId) throw new Error("Invalid agent run abort request.");
|
|
@@ -2312,7 +2464,8 @@ var AgentRunRequestManager = class {
|
|
|
2312
2464
|
...envelope.payload.message,
|
|
2313
2465
|
sessionId: envelope.payload.sessionId
|
|
2314
2466
|
},
|
|
2315
|
-
correlationId: envelope.payload.requestId
|
|
2467
|
+
correlationId: envelope.payload.requestId,
|
|
2468
|
+
trigger: structuredClone(envelope.payload.trigger)
|
|
2316
2469
|
}));
|
|
2317
2470
|
};
|
|
2318
2471
|
send = async (request) => await this.idempotency.accept(request, this.sendOnce);
|
|
@@ -2329,7 +2482,8 @@ var AgentRunRequestManager = class {
|
|
|
2329
2482
|
sessionId: session.sessionId,
|
|
2330
2483
|
message: baseMessage
|
|
2331
2484
|
};
|
|
2332
|
-
const
|
|
2485
|
+
const queuedRequest = sessionRun.enqueueRequest(normalizedRequest, session);
|
|
2486
|
+
const steeringRequest = request.delivery === "prefer-steer" && sessionRun.isRunning() ? this.pendingInputs.promotePreferredSteeringInput(sessionRun, queuedRequest.id, session) : null;
|
|
2333
2487
|
if (steeringRequest) {
|
|
2334
2488
|
this.publishRunQueueUpdated(session.sessionId);
|
|
2335
2489
|
return {
|
|
@@ -2340,7 +2494,6 @@ var AgentRunRequestManager = class {
|
|
|
2340
2494
|
delivery: "steered"
|
|
2341
2495
|
};
|
|
2342
2496
|
}
|
|
2343
|
-
const queuedRequest = sessionRun.enqueueRequest(normalizedRequest, session);
|
|
2344
2497
|
const activeRequest = sessionRun.beginNextRun();
|
|
2345
2498
|
this.publishRunQueueUpdated(session.sessionId);
|
|
2346
2499
|
if (activeRequest?.id === queuedRequest.id) await this.startQueuedRun(sessionRun, activeRequest);
|
|
@@ -2365,6 +2518,11 @@ var AgentRunRequestManager = class {
|
|
|
2365
2518
|
runId: activeRequest.runId,
|
|
2366
2519
|
session
|
|
2367
2520
|
});
|
|
2521
|
+
const trigger = resolveRunTriggerMetadata({
|
|
2522
|
+
request,
|
|
2523
|
+
spec,
|
|
2524
|
+
startedAt: requestRunStartedAt
|
|
2525
|
+
});
|
|
2368
2526
|
const message = attachRunSpecMetadata({
|
|
2369
2527
|
message: {
|
|
2370
2528
|
...request.message,
|
|
@@ -2375,7 +2533,8 @@ var AgentRunRequestManager = class {
|
|
|
2375
2533
|
request,
|
|
2376
2534
|
session,
|
|
2377
2535
|
spec,
|
|
2378
|
-
startedAt: requestRunStartedAt
|
|
2536
|
+
startedAt: requestRunStartedAt,
|
|
2537
|
+
trigger
|
|
2379
2538
|
});
|
|
2380
2539
|
const providerRequest = {
|
|
2381
2540
|
...request,
|
|
@@ -2402,8 +2561,14 @@ var AgentRunRequestManager = class {
|
|
|
2402
2561
|
message,
|
|
2403
2562
|
correlationId: request.correlationId
|
|
2404
2563
|
});
|
|
2405
|
-
|
|
2564
|
+
const triggerEvent = createRunTriggerMetadataEvent({
|
|
2565
|
+
sessionId: session.sessionId,
|
|
2566
|
+
spec,
|
|
2567
|
+
trigger
|
|
2568
|
+
});
|
|
2569
|
+
await sessionRun.applyEvents([messageSentEvent, triggerEvent]);
|
|
2406
2570
|
this.publishNcpEvent(messageSentEvent);
|
|
2571
|
+
this.publishNcpEvent(triggerEvent);
|
|
2407
2572
|
try {
|
|
2408
2573
|
const runtime = this.agentRuntimeManager.getOrCreate({
|
|
2409
2574
|
agentRuntimeId: session.agentRuntimeId,
|
|
@@ -9340,13 +9505,31 @@ var SessionPendingInputs = class {
|
|
|
9340
9505
|
intendedRunId
|
|
9341
9506
|
});
|
|
9342
9507
|
};
|
|
9343
|
-
moveNextRunToNextStep = (requestId, intendedRunId) => {
|
|
9508
|
+
moveNextRunToNextStep = (requestId, intendedRunId, activeRunSpec) => {
|
|
9344
9509
|
const index = this.nextRun.findIndex(({ id }) => id === requestId);
|
|
9345
9510
|
if (index < 0) return null;
|
|
9346
9511
|
const [request] = this.nextRun.splice(index, 1);
|
|
9347
9512
|
if (!request) return null;
|
|
9348
|
-
|
|
9349
|
-
|
|
9513
|
+
const steeringRequest = {
|
|
9514
|
+
...request,
|
|
9515
|
+
request: {
|
|
9516
|
+
...request.request,
|
|
9517
|
+
message: {
|
|
9518
|
+
...request.request.message,
|
|
9519
|
+
metadata: {
|
|
9520
|
+
...request.request.message.metadata ?? {},
|
|
9521
|
+
...activeRunSpec ? { [AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY]: structuredClone(activeRunSpec) } : {},
|
|
9522
|
+
[NCP_RUN_TRIGGER_METADATA_KEY]: resolveSteeringRunTriggerMetadata({
|
|
9523
|
+
request: request.request,
|
|
9524
|
+
targetRunId: intendedRunId,
|
|
9525
|
+
acceptedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9526
|
+
})
|
|
9527
|
+
}
|
|
9528
|
+
}
|
|
9529
|
+
}
|
|
9530
|
+
};
|
|
9531
|
+
this.enqueueNextStep(steeringRequest, intendedRunId);
|
|
9532
|
+
return this.toPendingRequest(steeringRequest, "steering", intendedRunId);
|
|
9350
9533
|
};
|
|
9351
9534
|
list = () => [...this.nextStep.map((request) => this.toPendingRequest(request, "steering", request.intendedRunId)), ...this.nextRun.map((request) => this.toPendingRequest(request, "queued", null))];
|
|
9352
9535
|
listNextRun = () => structuredClone(this.nextRun);
|
|
@@ -9398,6 +9581,13 @@ var SessionPendingInputs = class {
|
|
|
9398
9581
|
function isConversationStateEvent(event) {
|
|
9399
9582
|
return event.type !== NcpEventType.ContextWindowUpdated;
|
|
9400
9583
|
}
|
|
9584
|
+
function findRunSpec(messages, runId) {
|
|
9585
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
9586
|
+
const runSpec = messages[index]?.metadata?.[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY];
|
|
9587
|
+
if (runSpec && typeof runSpec === "object" && !Array.isArray(runSpec) && runSpec.runId === runId) return runSpec;
|
|
9588
|
+
}
|
|
9589
|
+
return null;
|
|
9590
|
+
}
|
|
9401
9591
|
var SessionRun = class {
|
|
9402
9592
|
sessionId;
|
|
9403
9593
|
statusListeners = /* @__PURE__ */ new Set();
|
|
@@ -9459,23 +9649,7 @@ var SessionRun = class {
|
|
|
9459
9649
|
};
|
|
9460
9650
|
moveQueuedRequestToNextStep = (queuedRequestId) => {
|
|
9461
9651
|
if (!this.activeRunId) return null;
|
|
9462
|
-
return this.pendingInputs.moveNextRunToNextStep(queuedRequestId, this.activeRunId);
|
|
9463
|
-
};
|
|
9464
|
-
enqueueNextStepRequest = (request, session) => {
|
|
9465
|
-
if (!this.activeRunId) return null;
|
|
9466
|
-
const pendingRequest = {
|
|
9467
|
-
id: `pending-input-${randomUUID()}`,
|
|
9468
|
-
runId: `agent-run-${randomUUID()}`,
|
|
9469
|
-
enqueuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9470
|
-
request: structuredClone(request),
|
|
9471
|
-
session: structuredClone(session)
|
|
9472
|
-
};
|
|
9473
|
-
this.pendingInputs.enqueueNextStep(pendingRequest, this.activeRunId);
|
|
9474
|
-
return structuredClone({
|
|
9475
|
-
...pendingRequest,
|
|
9476
|
-
placement: "steering",
|
|
9477
|
-
intendedRunId: this.activeRunId
|
|
9478
|
-
});
|
|
9652
|
+
return this.pendingInputs.moveNextRunToNextStep(queuedRequestId, this.activeRunId, findRunSpec(this.getSnapshot().messages, this.activeRunId));
|
|
9479
9653
|
};
|
|
9480
9654
|
claimNextStepRequests = (runId) => this.pendingInputs.claimNextStep(runId).map((request) => ({
|
|
9481
9655
|
...request,
|
|
@@ -10237,20 +10411,39 @@ function readMessageFromSummaryEvent(event) {
|
|
|
10237
10411
|
function readRecordLabel(record) {
|
|
10238
10412
|
return readOptionalString(record.metadata?.label) ?? void 0;
|
|
10239
10413
|
}
|
|
10414
|
+
function resolveRequestTrigger(params) {
|
|
10415
|
+
return {
|
|
10416
|
+
...params.trigger ?? {
|
|
10417
|
+
actor: "system",
|
|
10418
|
+
source: "session-request",
|
|
10419
|
+
triggeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10420
|
+
sourceSessionId: params.sourceSessionId
|
|
10421
|
+
},
|
|
10422
|
+
sourceRequestId: params.requestId
|
|
10423
|
+
};
|
|
10424
|
+
}
|
|
10240
10425
|
var SessionRequestManager = class {
|
|
10241
10426
|
constructor(options) {
|
|
10242
10427
|
this.options = options;
|
|
10243
10428
|
}
|
|
10244
10429
|
spawnSessionAndRequest = async (params) => {
|
|
10245
|
-
const { sourceSessionId, sourceToolCallId, updateToolCallResult, sourceSessionMetadata, metadataOverrides, contextInheritance, task, title, model, runtime, handoffDepth, sessionType, thinkingLevel, projectRoot, agentId, parentSessionId, notify } = params;
|
|
10430
|
+
const { sourceSessionId, sourceToolCallId, updateToolCallResult, sourceSessionMetadata, metadataOverrides, contextInheritance, task, title, model, runtime, handoffDepth, sessionType, thinkingLevel, projectRoot, agentId, parentSessionId, notify, trigger: requestedTrigger } = params;
|
|
10246
10431
|
const requestId = randomUUID();
|
|
10432
|
+
const trigger = resolveRequestTrigger({
|
|
10433
|
+
trigger: requestedTrigger,
|
|
10434
|
+
sourceSessionId,
|
|
10435
|
+
requestId
|
|
10436
|
+
});
|
|
10247
10437
|
const createdSession = await this.options.sessionManager.createSession({
|
|
10248
10438
|
sourceSessionId,
|
|
10249
10439
|
...parentSessionId ? { parentSessionId } : {},
|
|
10250
10440
|
task,
|
|
10251
10441
|
title,
|
|
10252
10442
|
sourceSessionMetadata,
|
|
10253
|
-
|
|
10443
|
+
metadataOverrides: {
|
|
10444
|
+
...metadataOverrides ?? {},
|
|
10445
|
+
session_creation_trigger: structuredClone(trigger)
|
|
10446
|
+
},
|
|
10254
10447
|
contextInheritance,
|
|
10255
10448
|
agentId,
|
|
10256
10449
|
model,
|
|
@@ -10273,18 +10466,25 @@ var SessionRequestManager = class {
|
|
|
10273
10466
|
agentId: createdSession.agentId,
|
|
10274
10467
|
isChildSession: Boolean(parentSessionId),
|
|
10275
10468
|
...parentSessionId ? { parentSessionId } : {},
|
|
10276
|
-
spawnedByRequestId: requestId
|
|
10469
|
+
spawnedByRequestId: requestId,
|
|
10470
|
+
trigger
|
|
10277
10471
|
});
|
|
10278
10472
|
};
|
|
10279
10473
|
requestSession = async (params) => {
|
|
10280
|
-
const { sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, notify, handoffDepth } = params;
|
|
10474
|
+
const { sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, notify, handoffDepth, trigger: requestedTrigger } = params;
|
|
10281
10475
|
const normalizedTargetSessionId = targetSessionId.trim();
|
|
10282
10476
|
if (normalizedTargetSessionId === sourceSessionId.trim()) throw new Error("sessions_request cannot target the current session.");
|
|
10283
10477
|
const targetSession = await this.options.sessionManager.getSessionRecord(normalizedTargetSessionId);
|
|
10284
10478
|
if (!targetSession) throw new Error(`Target session not found: ${targetSessionId}`);
|
|
10285
10479
|
const parentSessionId = readParentSessionId(targetSession.metadata);
|
|
10480
|
+
const requestId = randomUUID();
|
|
10481
|
+
const trigger = resolveRequestTrigger({
|
|
10482
|
+
trigger: requestedTrigger,
|
|
10483
|
+
sourceSessionId,
|
|
10484
|
+
requestId
|
|
10485
|
+
});
|
|
10286
10486
|
return this.dispatchRequest({
|
|
10287
|
-
requestId
|
|
10487
|
+
requestId,
|
|
10288
10488
|
sourceSessionId,
|
|
10289
10489
|
sourceToolCallId,
|
|
10290
10490
|
updateToolCallResult,
|
|
@@ -10296,11 +10496,12 @@ var SessionRequestManager = class {
|
|
|
10296
10496
|
agentId: targetSession.agentId,
|
|
10297
10497
|
isChildSession: Boolean(parentSessionId),
|
|
10298
10498
|
parentSessionId: parentSessionId ?? void 0,
|
|
10299
|
-
spawnedByRequestId: void 0
|
|
10499
|
+
spawnedByRequestId: void 0,
|
|
10500
|
+
trigger
|
|
10300
10501
|
});
|
|
10301
10502
|
};
|
|
10302
10503
|
dispatchRequest = async (params) => {
|
|
10303
|
-
const { requestId, sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, handoffDepth, notify, agentId, isChildSession, parentSessionId, spawnedByRequestId } = params;
|
|
10504
|
+
const { requestId, sourceSessionId, sourceToolCallId, updateToolCallResult, targetSessionId, task, title, handoffDepth, notify, agentId, isChildSession, parentSessionId, spawnedByRequestId, trigger } = params;
|
|
10304
10505
|
const request = createRunningSessionRequest({
|
|
10305
10506
|
requestId,
|
|
10306
10507
|
sourceSessionId,
|
|
@@ -10311,7 +10512,8 @@ var SessionRequestManager = class {
|
|
|
10311
10512
|
title,
|
|
10312
10513
|
task,
|
|
10313
10514
|
isChildSession,
|
|
10314
|
-
parentSessionId
|
|
10515
|
+
parentSessionId,
|
|
10516
|
+
trigger
|
|
10315
10517
|
});
|
|
10316
10518
|
const resultContext = {
|
|
10317
10519
|
task,
|
|
@@ -10469,6 +10671,13 @@ function waitForAgentRuntimeSessionReply(input) {
|
|
|
10469
10671
|
};
|
|
10470
10672
|
}
|
|
10471
10673
|
async function dispatchAgentRuntimeSessionRequest(input) {
|
|
10674
|
+
const trigger = parseNcpRunTriggerInput(input.request.metadata?.run_trigger) ?? {
|
|
10675
|
+
actor: "system",
|
|
10676
|
+
source: "session-request-recovery",
|
|
10677
|
+
triggeredAt: input.request.createdAt,
|
|
10678
|
+
sourceSessionId: input.request.sourceSessionId,
|
|
10679
|
+
sourceRequestId: input.request.requestId
|
|
10680
|
+
};
|
|
10472
10681
|
await input.ingress.handle({
|
|
10473
10682
|
type: ingressKeys$1.agentRun.sessionMessageRequest,
|
|
10474
10683
|
payload: {
|
|
@@ -10485,7 +10694,8 @@ async function dispatchAgentRuntimeSessionRequest(input) {
|
|
|
10485
10694
|
metadata: { session_request_id: input.request.requestId }
|
|
10486
10695
|
},
|
|
10487
10696
|
requestId: input.request.requestId,
|
|
10488
|
-
sessionId: input.request.targetSessionId
|
|
10697
|
+
sessionId: input.request.targetSessionId,
|
|
10698
|
+
trigger: structuredClone(trigger)
|
|
10489
10699
|
}
|
|
10490
10700
|
}, { source: "session-request" });
|
|
10491
10701
|
}
|
|
@@ -12826,6 +13036,7 @@ const createSelfManagementContextProvider = () => ({ provide: () => {
|
|
|
12826
13036
|
} });
|
|
12827
13037
|
const createSessionOrchestrationContextProvider = () => staticBlock([
|
|
12828
13038
|
"## Session Orchestration",
|
|
13039
|
+
"- 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
13040
|
"- 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
13041
|
"- `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
13042
|
"- `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 +13188,9 @@ function renderWebSearchReadiness(params) {
|
|
|
12977
13188
|
if (!readSearchApiKey(searchConfig, provider)) return `web_search is not ready: provider ${provider} has no API key configured.`;
|
|
12978
13189
|
return `web_search is ready with provider ${provider}.`;
|
|
12979
13190
|
}
|
|
13191
|
+
function renderDelegationGuidance(toolNames) {
|
|
13192
|
+
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.";
|
|
13193
|
+
}
|
|
12980
13194
|
var ToolingContextProvider = class {
|
|
12981
13195
|
constructor(context) {
|
|
12982
13196
|
this.context = context;
|
|
@@ -12998,7 +13212,7 @@ var ToolingContextProvider = class {
|
|
|
12998
13212
|
"TOOLS.md does not control tool availability; it is user guidance for how to use external tools.",
|
|
12999
13213
|
"For long waits, avoid rapid poll loops: use exec with enough yieldMs.",
|
|
13000
13214
|
"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
|
-
|
|
13215
|
+
renderDelegationGuidance(toolCatalog.map((tool) => tool.name)),
|
|
13002
13216
|
"Do not poll `subagents list` / `sessions_list` in a loop; only check status on-demand (for intervention, debugging, or when explicitly asked)."
|
|
13003
13217
|
].join("\n")];
|
|
13004
13218
|
};
|
|
@@ -13692,6 +13906,7 @@ var LearningLoopContribution = class extends Contribution$1 {
|
|
|
13692
13906
|
if (toolCallsSinceReview < runtimeConfig.toolCallThreshold) return;
|
|
13693
13907
|
this.inFlightSessionIds.add(sessionId);
|
|
13694
13908
|
try {
|
|
13909
|
+
const triggeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13695
13910
|
const reviewSession = await this.sessionRequester.spawnSessionAndRequest({
|
|
13696
13911
|
sourceSessionId: sessionId,
|
|
13697
13912
|
sourceSessionMetadata: metadata,
|
|
@@ -13707,11 +13922,18 @@ var LearningLoopContribution = class extends Contribution$1 {
|
|
|
13707
13922
|
sessionId,
|
|
13708
13923
|
toolCallsSinceReview,
|
|
13709
13924
|
currentToolCallCount: totalToolCalls
|
|
13710
|
-
})
|
|
13925
|
+
}),
|
|
13926
|
+
trigger: {
|
|
13927
|
+
actor: "automation",
|
|
13928
|
+
source: "learning-loop",
|
|
13929
|
+
triggeredAt,
|
|
13930
|
+
sourceSessionId: sessionId,
|
|
13931
|
+
...typeof metadata.preferred_model === "string" && metadata.preferred_model.trim() ? { sourceModel: metadata.preferred_model.trim() } : {}
|
|
13932
|
+
}
|
|
13711
13933
|
});
|
|
13712
13934
|
await this.sessionStore.updateSessionMetadata(sessionId, {
|
|
13713
13935
|
[LEARNING_LOOP_LAST_TOOL_CALL_COUNT_METADATA_KEY]: totalToolCalls,
|
|
13714
|
-
[LEARNING_LOOP_LAST_REQUESTED_AT_METADATA_KEY]:
|
|
13936
|
+
[LEARNING_LOOP_LAST_REQUESTED_AT_METADATA_KEY]: triggeredAt,
|
|
13715
13937
|
[LEARNING_LOOP_LAST_REVIEW_SESSION_ID_METADATA_KEY]: reviewSession.sessionId
|
|
13716
13938
|
});
|
|
13717
13939
|
} finally {
|
|
@@ -14076,12 +14298,14 @@ var SessionRequestTool = class {
|
|
|
14076
14298
|
};
|
|
14077
14299
|
sourceSessionId = "";
|
|
14078
14300
|
handoffDepth = 0;
|
|
14301
|
+
trigger = null;
|
|
14079
14302
|
constructor(manager) {
|
|
14080
14303
|
this.manager = manager;
|
|
14081
14304
|
}
|
|
14082
14305
|
setContext = (params) => {
|
|
14083
14306
|
this.sourceSessionId = params.sourceSessionId;
|
|
14084
14307
|
this.handoffDepth = params.handoffDepth ?? 0;
|
|
14308
|
+
this.trigger = structuredClone(params.trigger);
|
|
14085
14309
|
};
|
|
14086
14310
|
execute = async (args, context) => {
|
|
14087
14311
|
const params = normalizeToolParams(args);
|
|
@@ -14098,9 +14322,14 @@ var SessionRequestTool = class {
|
|
|
14098
14322
|
task,
|
|
14099
14323
|
title: readOptionalString$6(params, "title"),
|
|
14100
14324
|
notify: notifyMode,
|
|
14101
|
-
handoffDepth: this.handoffDepth
|
|
14325
|
+
handoffDepth: this.handoffDepth,
|
|
14326
|
+
trigger: attachSourceToolCall(this.readTriggerOrThrow(), context?.toolCallId)
|
|
14102
14327
|
});
|
|
14103
14328
|
};
|
|
14329
|
+
readTriggerOrThrow = () => {
|
|
14330
|
+
if (!this.trigger) throw new Error("sessions_request requires an active run trigger context.");
|
|
14331
|
+
return structuredClone(this.trigger);
|
|
14332
|
+
};
|
|
14104
14333
|
};
|
|
14105
14334
|
//#endregion
|
|
14106
14335
|
//#region src/tools/session-search.tools.ts
|
|
@@ -14240,16 +14469,20 @@ var SessionSpawnTool = class {
|
|
|
14240
14469
|
sourceSessionId = "";
|
|
14241
14470
|
sourceSessionMetadata = {};
|
|
14242
14471
|
handoffDepth = 0;
|
|
14472
|
+
trigger = null;
|
|
14243
14473
|
constructor(sessionManager, sessionRequestManager) {
|
|
14244
14474
|
this.sessionManager = sessionManager;
|
|
14245
14475
|
this.sessionRequestManager = sessionRequestManager;
|
|
14246
14476
|
}
|
|
14247
14477
|
setContext = (params) => {
|
|
14248
|
-
|
|
14249
|
-
this.
|
|
14250
|
-
this.
|
|
14478
|
+
const { handoffDepth, sourceSessionId, sourceSessionMetadata, trigger } = params;
|
|
14479
|
+
this.sourceSessionId = sourceSessionId;
|
|
14480
|
+
this.sourceSessionMetadata = structuredClone(sourceSessionMetadata);
|
|
14481
|
+
this.handoffDepth = handoffDepth ?? 0;
|
|
14482
|
+
this.trigger = structuredClone(trigger);
|
|
14251
14483
|
};
|
|
14252
14484
|
execute = async (args, context) => {
|
|
14485
|
+
const { toolCallId, updateToolCallResult } = context ?? {};
|
|
14253
14486
|
const { agentId: rawAgentId, model: rawModel, notify: rawNotify, runtime: rawRuntime, scope: rawScope, task: rawTask, title: rawTitle, inheritContext: rawInheritContext } = normalizeToolParams(args);
|
|
14254
14487
|
const task = readRequiredString$4(rawTask, "task");
|
|
14255
14488
|
const scope = readSpawnScope(rawScope);
|
|
@@ -14257,11 +14490,12 @@ var SessionSpawnTool = class {
|
|
|
14257
14490
|
const inheritContext = readInheritContext(rawInheritContext);
|
|
14258
14491
|
if (inheritContext && scope !== "child") throw new Error("inheritContext=true requires scope=\"child\".");
|
|
14259
14492
|
const parentSessionId = scope === "child" ? this.readParentSessionIdOrThrow() : void 0;
|
|
14260
|
-
const contextInheritance = inheritContext ? { anchorToolCallId:
|
|
14493
|
+
const contextInheritance = inheritContext ? { anchorToolCallId: toolCallId } : void 0;
|
|
14494
|
+
const trigger = attachSourceToolCall(this.readTriggerOrThrow(), toolCallId);
|
|
14261
14495
|
if (notify) return this.sessionRequestManager.spawnSessionAndRequest({
|
|
14262
14496
|
sourceSessionId: this.sourceSessionId,
|
|
14263
|
-
sourceToolCallId:
|
|
14264
|
-
updateToolCallResult
|
|
14497
|
+
sourceToolCallId: toolCallId,
|
|
14498
|
+
updateToolCallResult,
|
|
14265
14499
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
14266
14500
|
task,
|
|
14267
14501
|
title: readOptionalString$5(rawTitle),
|
|
@@ -14271,7 +14505,8 @@ var SessionSpawnTool = class {
|
|
|
14271
14505
|
contextInheritance,
|
|
14272
14506
|
handoffDepth: this.handoffDepth,
|
|
14273
14507
|
parentSessionId,
|
|
14274
|
-
notify
|
|
14508
|
+
notify,
|
|
14509
|
+
trigger
|
|
14275
14510
|
});
|
|
14276
14511
|
const session = await this.sessionManager.createSession({
|
|
14277
14512
|
sourceSessionId: this.sourceSessionId,
|
|
@@ -14282,7 +14517,8 @@ var SessionSpawnTool = class {
|
|
|
14282
14517
|
model: readOptionalString$5(rawModel),
|
|
14283
14518
|
runtime: readOptionalString$5(rawRuntime),
|
|
14284
14519
|
contextInheritance,
|
|
14285
|
-
parentSessionId
|
|
14520
|
+
parentSessionId,
|
|
14521
|
+
metadataOverrides: { session_creation_trigger: structuredClone(trigger) }
|
|
14286
14522
|
});
|
|
14287
14523
|
return {
|
|
14288
14524
|
kind: "nextclaw.session",
|
|
@@ -14301,6 +14537,10 @@ var SessionSpawnTool = class {
|
|
|
14301
14537
|
if (!sourceSessionId) throw new Error("scope=\"child\" requires an active source session.");
|
|
14302
14538
|
return sourceSessionId;
|
|
14303
14539
|
};
|
|
14540
|
+
readTriggerOrThrow = () => {
|
|
14541
|
+
if (!this.trigger) throw new Error("sessions_spawn requires an active run trigger context.");
|
|
14542
|
+
return structuredClone(this.trigger);
|
|
14543
|
+
};
|
|
14304
14544
|
};
|
|
14305
14545
|
//#endregion
|
|
14306
14546
|
//#region src/tools/session-update.tools.ts
|
|
@@ -14355,26 +14595,38 @@ var SessionToolProvider = class {
|
|
|
14355
14595
|
this.sessionSearch = sessionSearch;
|
|
14356
14596
|
}
|
|
14357
14597
|
provide = async (request) => {
|
|
14358
|
-
const { toolRunContext } = await this.runContextService.resolve(request);
|
|
14598
|
+
const { session, toolRunContext } = await this.runContextService.resolve(request);
|
|
14359
14599
|
const { handoffDepth, metadata, sessionId } = toolRunContext;
|
|
14360
|
-
const
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
handoffDepth
|
|
14600
|
+
const isChildSession = Boolean(readParentSessionId(session?.metadata ?? metadata));
|
|
14601
|
+
const requestTrigger = createAgentToolRunTriggerInput({
|
|
14602
|
+
request,
|
|
14603
|
+
source: "sessions_request"
|
|
14365
14604
|
});
|
|
14366
14605
|
const sessionsRequestTool = new SessionRequestTool(this.sessionRequests);
|
|
14367
14606
|
sessionsRequestTool.setContext({
|
|
14368
14607
|
sourceSessionId: sessionId,
|
|
14369
|
-
handoffDepth
|
|
14608
|
+
handoffDepth,
|
|
14609
|
+
trigger: requestTrigger
|
|
14370
14610
|
});
|
|
14371
14611
|
const tools = [
|
|
14372
|
-
sessionsSpawnTool,
|
|
14373
14612
|
sessionsRequestTool,
|
|
14374
14613
|
new SessionsListTool(this.sessionManager),
|
|
14375
14614
|
new SessionsHistoryTool(this.sessionManager),
|
|
14376
14615
|
new SessionsUpdateTool(this.sessionManager)
|
|
14377
14616
|
];
|
|
14617
|
+
if (!isChildSession) {
|
|
14618
|
+
const sessionsSpawnTool = new SessionSpawnTool(this.sessionManager, this.sessionRequests);
|
|
14619
|
+
sessionsSpawnTool.setContext({
|
|
14620
|
+
sourceSessionId: sessionId,
|
|
14621
|
+
sourceSessionMetadata: metadata,
|
|
14622
|
+
handoffDepth,
|
|
14623
|
+
trigger: createAgentToolRunTriggerInput({
|
|
14624
|
+
request,
|
|
14625
|
+
source: "sessions_spawn"
|
|
14626
|
+
})
|
|
14627
|
+
});
|
|
14628
|
+
tools.unshift(sessionsSpawnTool);
|
|
14629
|
+
}
|
|
14378
14630
|
if (!this.sessionSearch.isReady()) return tools;
|
|
14379
14631
|
tools.push(new SessionSearchTool({ search: this.sessionSearch.search }, { currentSessionId: sessionId }));
|
|
14380
14632
|
return tools;
|
|
@@ -15242,6 +15494,14 @@ const SESSION_METADATA_LABEL_KEY = "label";
|
|
|
15242
15494
|
const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
|
|
15243
15495
|
const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
|
|
15244
15496
|
const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
|
|
15497
|
+
async function assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, getSessionRecord) {
|
|
15498
|
+
if (Object.prototype.hasOwnProperty.call(metadataOverrides ?? {}, CHILD_SESSION_PARENT_METADATA_KEY)) throw new Error("Session parent must be set through parentSessionId.");
|
|
15499
|
+
if (readOptionalMetadataString(sourceRecord?.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Source session: ${sourceRecord?.sessionId}.`);
|
|
15500
|
+
if (!parentSessionId) return;
|
|
15501
|
+
const parentRecord = sourceRecord?.sessionId === parentSessionId ? sourceRecord : await getSessionRecord(parentSessionId);
|
|
15502
|
+
if (!parentRecord) throw new Error(`Parent session not found: ${parentSessionId}`);
|
|
15503
|
+
if (readOptionalMetadataString(parentRecord.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Parent session: ${parentSessionId}.`);
|
|
15504
|
+
}
|
|
15245
15505
|
function readThinkingEffort(metadata) {
|
|
15246
15506
|
return readOptionalMetadataString(metadata?.thinkingEffort) ?? readOptionalMetadataString(metadata?.preferred_thinking) ?? readOptionalMetadataString(metadata?.thinking) ?? null;
|
|
15247
15507
|
}
|
|
@@ -17294,6 +17554,7 @@ var SessionManager = class {
|
|
|
17294
17554
|
const metadata = cloneInheritedMetadata(sourceSessionMetadata);
|
|
17295
17555
|
const title = readOptionalString$2(requestedTitle) ?? summarizeTask(task);
|
|
17296
17556
|
const parentSessionId = readOptionalString$2(rawParentSessionId);
|
|
17557
|
+
await assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, this.getSessionRecord);
|
|
17297
17558
|
const requestId = readOptionalString$2(rawRequestId);
|
|
17298
17559
|
const sessionType = resolveSessionType({
|
|
17299
17560
|
runtime,
|
|
@@ -17453,23 +17714,9 @@ var SessionManager = class {
|
|
|
17453
17714
|
return (liveRecord ? await this.summaryProjection.createWithContextWindow(liveRecord) : await this.getSession(sessionId))?.contextWindow ?? null;
|
|
17454
17715
|
};
|
|
17455
17716
|
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
|
-
};
|
|
17717
|
+
const summary = await this.options.journalStore.getSessionSummary(sessionId);
|
|
17718
|
+
if (!summary) throw new Error(`Session not found: ${sessionId}`);
|
|
17719
|
+
return this.toAgentRunSession(summary);
|
|
17473
17720
|
};
|
|
17474
17721
|
createAgentRunSession = async (params) => {
|
|
17475
17722
|
const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, contextInheritance, metadata, model, parentSessionId: rawParentSessionId, peerId: rawPeerId, projectRoot, sessionId, sourceSessionId: rawSourceSessionId, sourceSessionMetadata: requestedSourceSessionMetadata, task, thinkingEffort } = params;
|
|
@@ -17520,7 +17767,24 @@ var SessionManager = class {
|
|
|
17520
17767
|
};
|
|
17521
17768
|
getOrCreateAgentRunSession = async (params) => {
|
|
17522
17769
|
if (!params.sessionId) return await this.createAgentRunSession(params);
|
|
17523
|
-
|
|
17770
|
+
const summary = await this.options.journalStore.getSessionSummary(params.sessionId);
|
|
17771
|
+
return summary ? this.toAgentRunSession(summary) : await this.createAgentRunSession(params);
|
|
17772
|
+
};
|
|
17773
|
+
toAgentRunSession = (summary) => {
|
|
17774
|
+
const metadata = summary.metadata ?? {};
|
|
17775
|
+
return {
|
|
17776
|
+
sessionId: summary.sessionId,
|
|
17777
|
+
agentId: summary.agentId,
|
|
17778
|
+
agentRuntimeId: readOptionalMetadataString(metadata.agentRuntimeId) ?? "native",
|
|
17779
|
+
metadata: structuredClone(metadata),
|
|
17780
|
+
model: readOptionalMetadataString(metadata.model) ?? readOptionalMetadataString(metadata.preferred_model),
|
|
17781
|
+
projectRoot: readProjectRoot(metadata),
|
|
17782
|
+
workingDir: this.workingDirResolver.resolve({
|
|
17783
|
+
agentId: summary.agentId,
|
|
17784
|
+
metadata
|
|
17785
|
+
}),
|
|
17786
|
+
thinkingEffort: readThinkingEffort(metadata)
|
|
17787
|
+
};
|
|
17524
17788
|
};
|
|
17525
17789
|
patchSessionMetadata = async (sessionId, patch) => {
|
|
17526
17790
|
if (!await this.updateSessionMetadata(sessionId, patch)) throw new Error(`Session metadata was not updated: ${sessionId}`);
|