
























@@ -0,0 +1,231 @@
1+import type { ModelAliasIndex } from "../../agents/model-selection.js";
2+import type { OpenClawConfig } from "../../config/config.js";
3+import { createLazyImportLoader } from "../../shared/lazy-promise.js";
4+import { normalizeOptionalString } from "../../shared/string-coerce.js";
5+import type { GetReplyOptions } from "../get-reply-options.types.js";
6+import type { ReplyPayload } from "../reply-payload.js";
7+import type { MsgContext } from "../templating.js";
8+import { buildCommandContext } from "./commands-context.js";
9+import { clearInlineDirectives } from "./get-reply-directives-utils.js";
10+import { resolveReplyDirectives } from "./get-reply-directives.js";
11+import { initFastReplySessionState } from "./get-reply-fast-path.js";
12+import { handleInlineActions } from "./get-reply-inline-actions.js";
13+import { stripStructuralPrefixes } from "./mentions.js";
14+import type { createTypingController } from "./typing.js";
15+16+type AgentDefaults = NonNullable<NonNullable<OpenClawConfig["agents"]>["defaults"]> | undefined;
17+18+const commandsRuntimeLoader = createLazyImportLoader(() => import("./commands.runtime.js"));
19+const statusCommandRuntimeLoader = createLazyImportLoader(() => import("./commands-status.js"));
20+21+function loadCommandsRuntime() {
22+return commandsRuntimeLoader.load();
23+}
24+25+function loadStatusCommandRuntime() {
26+return statusCommandRuntimeLoader.load();
27+}
28+29+function resolveNativeSlashCommandName(ctx: MsgContext): string | undefined {
30+if (ctx.CommandSource !== "native") {
31+return undefined;
32+}
33+const commandText = stripStructuralPrefixes(
34+ctx.BodyForCommands ?? ctx.CommandBody ?? ctx.RawBody ?? ctx.Body ?? "",
35+).trim();
36+const match = commandText.match(/^\/([^\s:]+)(?::|\s|$)/);
37+return normalizeOptionalString(match?.[1])?.toLowerCase();
38+}
39+40+function shouldRunNativeSlashCommandFastPath(ctx: MsgContext): boolean {
41+const commandName = resolveNativeSlashCommandName(ctx);
42+return Boolean(commandName && commandName !== "new" && commandName !== "reset");
43+}
44+45+export async function maybeResolveNativeSlashCommandFastReply(params: {
46+ctx: MsgContext;
47+cfg: OpenClawConfig;
48+agentId: string;
49+agentDir: string;
50+agentCfg: AgentDefaults;
51+commandAuthorized: boolean;
52+defaultProvider: string;
53+defaultModel: string;
54+aliasIndex: ModelAliasIndex;
55+provider: string;
56+model: string;
57+workspaceDir: string;
58+typing: ReturnType<typeof createTypingController>;
59+opts?: GetReplyOptions;
60+skillFilter?: string[];
61+}): Promise<
62+{ handled: true; reply: ReplyPayload | ReplyPayload[] | undefined } | { handled: false }
63+> {
64+if (!shouldRunNativeSlashCommandFastPath(params.ctx)) {
65+return { handled: false };
66+}
67+68+const sessionState = initFastReplySessionState({
69+ctx: params.ctx,
70+cfg: params.cfg,
71+agentId: params.agentId,
72+commandAuthorized: params.commandAuthorized,
73+workspaceDir: params.workspaceDir,
74+});
75+const command = buildCommandContext({
76+ctx: params.ctx,
77+cfg: params.cfg,
78+agentId: params.agentId,
79+sessionKey: sessionState.sessionKey,
80+isGroup: sessionState.isGroup,
81+triggerBodyNormalized: sessionState.triggerBodyNormalized,
82+commandAuthorized: params.commandAuthorized,
83+});
84+if (command.commandBodyNormalized === "/status") {
85+const targetSessionEntry =
86+sessionState.sessionStore[sessionState.sessionKey] ?? sessionState.sessionEntry;
87+const { buildStatusReply } = await loadStatusCommandRuntime();
88+return {
89+handled: true,
90+reply: await buildStatusReply({
91+cfg: params.cfg,
92+ command,
93+sessionEntry: targetSessionEntry,
94+sessionKey: sessionState.sessionKey,
95+parentSessionKey: targetSessionEntry?.parentSessionKey ?? params.ctx.ParentSessionKey,
96+sessionScope: sessionState.sessionScope,
97+storePath: sessionState.storePath,
98+provider: params.provider,
99+model: params.model,
100+workspaceDir: params.workspaceDir,
101+resolvedThinkLevel: undefined,
102+resolvedVerboseLevel: "off",
103+resolvedReasoningLevel: "off",
104+resolvedElevatedLevel: "off",
105+resolveDefaultThinkingLevel: async () => undefined,
106+isGroup: sessionState.isGroup,
107+defaultGroupActivation: () => "always",
108+mediaDecisions: params.ctx.MediaUnderstandingDecisions,
109+}),
110+};
111+}
112+113+const commandResult = await (
114+await loadCommandsRuntime()
115+).handleCommands({
116+ctx: sessionState.sessionCtx,
117+rootCtx: params.ctx,
118+cfg: params.cfg,
119+ command,
120+agentId: params.agentId,
121+agentDir: params.agentDir,
122+directives: clearInlineDirectives(sessionState.triggerBodyNormalized),
123+elevated: {
124+enabled: false,
125+allowed: false,
126+failures: [],
127+},
128+sessionEntry: sessionState.sessionEntry,
129+previousSessionEntry: sessionState.previousSessionEntry,
130+sessionStore: sessionState.sessionStore,
131+sessionKey: sessionState.sessionKey,
132+storePath: sessionState.storePath,
133+sessionScope: sessionState.sessionScope,
134+workspaceDir: params.workspaceDir,
135+opts: params.opts,
136+defaultGroupActivation: () => "always",
137+resolvedThinkLevel: undefined,
138+resolvedVerboseLevel: "off",
139+resolvedReasoningLevel: "off",
140+resolvedElevatedLevel: "off",
141+blockReplyChunking: undefined,
142+resolvedBlockStreamingBreak: "text_end",
143+resolveDefaultThinkingLevel: async () => undefined,
144+provider: params.provider,
145+model: params.model,
146+contextTokens: params.agentCfg?.contextTokens ?? 0,
147+isGroup: sessionState.isGroup,
148+skillCommands: [],
149+typing: params.typing,
150+});
151+if (!commandResult.shouldContinue) {
152+return { handled: true, reply: commandResult.reply };
153+}
154+155+const directiveResult = await resolveReplyDirectives({
156+ctx: params.ctx,
157+cfg: params.cfg,
158+agentId: params.agentId,
159+agentDir: params.agentDir,
160+workspaceDir: params.workspaceDir,
161+agentCfg: params.agentCfg,
162+sessionCtx: sessionState.sessionCtx,
163+sessionEntry: sessionState.sessionEntry,
164+sessionStore: sessionState.sessionStore,
165+sessionKey: sessionState.sessionKey,
166+storePath: sessionState.storePath,
167+sessionScope: sessionState.sessionScope,
168+groupResolution: sessionState.groupResolution,
169+isGroup: sessionState.isGroup,
170+triggerBodyNormalized: sessionState.triggerBodyNormalized,
171+resetTriggered: false,
172+commandAuthorized: params.commandAuthorized,
173+defaultProvider: params.defaultProvider,
174+defaultModel: params.defaultModel,
175+aliasIndex: params.aliasIndex,
176+provider: params.provider,
177+model: params.model,
178+hasResolvedHeartbeatModelOverride: false,
179+typing: params.typing,
180+opts: params.opts,
181+skillFilter: params.skillFilter,
182+});
183+if (directiveResult.kind === "reply") {
184+return { handled: true, reply: directiveResult.reply };
185+}
186+187+const inlineActionResult = await handleInlineActions({
188+ctx: params.ctx,
189+sessionCtx: sessionState.sessionCtx,
190+cfg: params.cfg,
191+agentId: params.agentId,
192+agentDir: params.agentDir,
193+sessionEntry: sessionState.sessionEntry,
194+previousSessionEntry: sessionState.previousSessionEntry,
195+sessionStore: sessionState.sessionStore,
196+sessionKey: sessionState.sessionKey,
197+storePath: sessionState.storePath,
198+sessionScope: sessionState.sessionScope,
199+workspaceDir: params.workspaceDir,
200+isGroup: sessionState.isGroup,
201+opts: params.opts,
202+typing: params.typing,
203+allowTextCommands: directiveResult.result.allowTextCommands,
204+inlineStatusRequested: directiveResult.result.inlineStatusRequested,
205+command: directiveResult.result.command,
206+skillCommands: directiveResult.result.skillCommands,
207+directives: directiveResult.result.directives,
208+cleanedBody: directiveResult.result.cleanedBody,
209+elevatedEnabled: directiveResult.result.elevatedEnabled,
210+elevatedAllowed: directiveResult.result.elevatedAllowed,
211+elevatedFailures: directiveResult.result.elevatedFailures,
212+defaultActivation: () => directiveResult.result.defaultActivation,
213+resolvedThinkLevel: directiveResult.result.resolvedThinkLevel,
214+resolvedVerboseLevel: directiveResult.result.resolvedVerboseLevel,
215+resolvedReasoningLevel: directiveResult.result.resolvedReasoningLevel,
216+resolvedElevatedLevel: directiveResult.result.resolvedElevatedLevel,
217+blockReplyChunking: directiveResult.result.blockReplyChunking,
218+resolvedBlockStreamingBreak: directiveResult.result.resolvedBlockStreamingBreak,
219+resolveDefaultThinkingLevel: directiveResult.result.modelState.resolveDefaultThinkingLevel,
220+provider: directiveResult.result.provider,
221+model: directiveResult.result.model,
222+contextTokens: directiveResult.result.contextTokens,
223+directiveAck: directiveResult.result.directiveAck,
224+abortedLastRun: sessionState.abortedLastRun,
225+skillFilter: params.skillFilter,
226+});
227+if (inlineActionResult.kind === "reply") {
228+return { handled: true, reply: inlineActionResult.reply };
229+}
230+return { handled: false };
231+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。