diff --git a/src/auto-reply/reply/agent-runner-utils.ts b/src/auto-reply/reply/agent-runner-utils.ts index 96353311385..b4ec6754712 100644 --- a/src/auto-reply/reply/agent-runner-utils.ts +++ b/src/auto-reply/reply/agent-runner-utils.ts @@ -98,12 +98,13 @@ export const resolveEnforceFinalTag = ( model = run.model, ) => Boolean( - run.enforceFinalTag || - isReasoningTagProvider(provider, { - config: run.config, - workspaceDir: run.workspaceDir, - modelId: model, - }), + (run.skipProviderRuntimeHints ? false : undefined) ?? + (run.enforceFinalTag || + isReasoningTagProvider(provider, { + config: run.config, + workspaceDir: run.workspaceDir, + modelId: model, + })), ); export function resolveModelFallbackOptions(run: FollowupRun["run"]) { diff --git a/src/auto-reply/reply/get-reply-fast-path.ts b/src/auto-reply/reply/get-reply-fast-path.ts index d52c240fd3f..b3e79120eb1 100644 --- a/src/auto-reply/reply/get-reply-fast-path.ts +++ b/src/auto-reply/reply/get-reply-fast-path.ts @@ -1,10 +1,13 @@ import crypto from "node:crypto"; import path from "node:path"; import { normalizeChatType } from "../../channels/chat-type.js"; +import { normalizeAnyChannelId } from "../../channels/registry.js"; import type { OpenClawConfig } from "../../config/config.js"; import { applyMergePatch } from "../../config/merge-patch.js"; import type { SessionEntry } from "../../config/sessions/types.js"; +import { normalizeCommandBody } from "../commands-registry.js"; import type { MsgContext, TemplateContext } from "../templating.js"; +import type { CommandContext } from "./commands-types.js"; import { stripMentions, stripStructuralPrefixes } from "./mentions.js"; import type { SessionInitResult } from "./session.js"; @@ -103,6 +106,47 @@ export function shouldUseReplyFastDirectiveExecution(params: { return !params.triggerBodyNormalized.includes("/"); } +export function buildFastReplyCommandContext(params: { + ctx: MsgContext; + cfg: OpenClawConfig; + agentId?: string; + sessionKey?: string; + isGroup: boolean; + triggerBodyNormalized: string; + commandAuthorized: boolean; +}): CommandContext { + const { ctx, cfg, agentId, sessionKey, isGroup, triggerBodyNormalized, commandAuthorized } = + params; + const surface = (ctx.Surface ?? ctx.Provider ?? "").trim().toLowerCase(); + const channel = (ctx.Provider ?? surface).trim().toLowerCase(); + const from = ctx.From?.trim() || undefined; + const to = ctx.To?.trim() || undefined; + return { + surface, + channel, + channelId: normalizeAnyChannelId(channel) ?? normalizeAnyChannelId(surface) ?? undefined, + ownerList: [], + senderIsOwner: false, + isAuthorizedSender: commandAuthorized, + senderId: from, + abortKey: sessionKey ?? from ?? to, + rawBodyNormalized: triggerBodyNormalized, + commandBodyNormalized: normalizeCommandBody( + isGroup ? stripMentions(triggerBodyNormalized, ctx, cfg, agentId) : triggerBodyNormalized, + { botUsername: ctx.BotUsername }, + ), + from, + to, + }; +} + +export function shouldHandleFastReplyTextCommands(params: { + cfg: OpenClawConfig; + commandSource?: string; +}): boolean { + return params.commandSource === "native" || params.cfg.commands?.text !== false; +} + export function initFastReplySessionState(params: { ctx: MsgContext; cfg: OpenClawConfig; diff --git a/src/auto-reply/reply/get-reply-run.ts b/src/auto-reply/reply/get-reply-run.ts index 09fa9ae1357..2e51453a3f5 100644 --- a/src/auto-reply/reply/get-reply-run.ts +++ b/src/auto-reply/reply/get-reply-run.ts @@ -558,13 +558,15 @@ export async function runPreparedReply( authProfileId, authProfileIdSource, thinkLevel: resolvedThinkLevel, - fastMode: resolveFastModeState({ - cfg, - provider, - model, - agentId, - sessionEntry: preparedSessionState.sessionEntry, - }).enabled, + fastMode: useFastReplyRuntime + ? false + : resolveFastModeState({ + cfg, + provider, + model, + agentId, + sessionEntry: preparedSessionState.sessionEntry, + }).enabled, verboseLevel: resolvedVerboseLevel, reasoningLevel: resolvedReasoningLevel, elevatedLevel: resolvedElevatedLevel, @@ -579,7 +581,9 @@ export async function runPreparedReply( ownerNumbers: command.ownerList.length > 0 ? command.ownerList : undefined, inputProvenance: ctx.InputProvenance ?? sessionCtx.InputProvenance, extraSystemPrompt: extraSystemPromptParts.join("\n\n") || undefined, - ...(isReasoningTagProvider(provider, { + skipProviderRuntimeHints: useFastReplyRuntime, + ...(!useFastReplyRuntime && + isReasoningTagProvider(provider, { config: cfg, workspaceDir, modelId: model, diff --git a/src/auto-reply/reply/get-reply.ts b/src/auto-reply/reply/get-reply.ts index 8f49baa29e6..7f8bb5d7d37 100644 --- a/src/auto-reply/reply/get-reply.ts +++ b/src/auto-reply/reply/get-reply.ts @@ -12,18 +12,17 @@ import { resolveChannelModelOverride } from "../../channels/model-overrides.js"; import { type OpenClawConfig, loadConfig } from "../../config/config.js"; import { defaultRuntime } from "../../runtime.js"; import { normalizeStringEntries } from "../../shared/string-normalization.js"; -import { resolveCommandAuthorization } from "../command-auth.js"; -import { shouldHandleTextCommands } from "../commands-text-routing.js"; import type { MsgContext } from "../templating.js"; import { normalizeVerboseLevel } from "../thinking.js"; import { SILENT_REPLY_TOKEN } from "../tokens.js"; import type { GetReplyOptions, ReplyPayload } from "../types.js"; -import { buildCommandContext } from "./commands-context.js"; import { resolveDefaultModel } from "./directive-handling.defaults.js"; import { clearInlineDirectives } from "./get-reply-directives-utils.js"; import { resolveReplyDirectives } from "./get-reply-directives.js"; import { initFastReplySessionState, + buildFastReplyCommandContext, + shouldHandleFastReplyTextCommands, shouldUseReplyFastDirectiveExecution, resolveGetReplyConfig, shouldUseReplyFastTestBootstrap, @@ -240,11 +239,6 @@ export async function getReplyFromConfig( }); const commandAuthorized = finalized.CommandAuthorized; - resolveCommandAuthorization({ - ctx: finalized, - cfg, - commandAuthorized, - }); const sessionState = useFastTestBootstrap ? initFastReplySessionState({ ctx: finalized, @@ -336,6 +330,15 @@ export async function getReplyFromConfig( triggerBodyNormalized, }) ) { + const fastCommand = buildFastReplyCommandContext({ + ctx, + cfg, + agentId, + sessionKey, + isGroup, + triggerBodyNormalized, + commandAuthorized, + }); return runPreparedReply({ ctx, sessionCtx, @@ -345,19 +348,10 @@ export async function getReplyFromConfig( agentCfg, sessionCfg, commandAuthorized, - command: buildCommandContext({ - ctx, - cfg, - agentId, - sessionKey, - isGroup, - triggerBodyNormalized, - commandAuthorized, - }), + command: fastCommand, commandSource: finalized.BodyForCommands ?? finalized.CommandBody ?? finalized.RawBody ?? "", - allowTextCommands: shouldHandleTextCommands({ + allowTextCommands: shouldHandleFastReplyTextCommands({ cfg, - surface: finalized.Surface ?? finalized.Provider ?? "", commandSource: finalized.CommandSource, }), directives: clearInlineDirectives( diff --git a/src/auto-reply/reply/queue/types.ts b/src/auto-reply/reply/queue/types.ts index 7ab90d40b79..6eeb5a53af4 100644 --- a/src/auto-reply/reply/queue/types.ts +++ b/src/auto-reply/reply/queue/types.ts @@ -81,6 +81,7 @@ export type FollowupRun = { inputProvenance?: InputProvenance; extraSystemPrompt?: string; enforceFinalTag?: boolean; + skipProviderRuntimeHints?: boolean; silentExpected?: boolean; }; };