UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

272 lines (271 loc) • 12.7 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs"; import { r as normalizeProviderId } from "./provider-id-D1VImdKk.mjs"; import { t as resolvePluginControlPlaneFingerprint } from "./plugin-control-plane-context-k1PmbRpn.mjs"; import { S as supportsClaudeInHistorySystemMessages } from "./anthropic-D-i5CCnY.mjs"; import "./src-UF9QYDzr.mjs"; import { i as generateSecureToken } from "./secure-random-Dimnnrm0.mjs"; import { u as resolveProviderRuntimePlugin } from "./provider-hook-runtime-CV4YC-3T.mjs"; import { n as extractAssistantTextForPhase } from "./chat-message-content-C-d0FKNG.mjs"; import { n as deriveContextPromptTokens, o as hasNonzeroUsage, u as normalizeUsage } from "./usage-XmAH1cfG.mjs"; import { t as buildAnthropicReplayPolicyForModel } from "./provider-replay-helpers-Da6bKlcZ.mjs"; import { n as isGoogleModelApi, t as isAnthropicApi } from "./anthropic-api-h8NkJ9yu.mjs"; import { o as extractAssistantVisibleText } from "./embedded-agent-utils-BYhIvAvm.mjs"; import { i as toNormalizedUsage } from "./usage-accumulator-CzWfyqDH.mjs"; import { isDirectAnthropicModel } from "@openclaw/ai/internal/anthropic"; //#region src/agents/transcript-policy.ts /** * Transcript replay policy resolution. * Combines provider plugin replay hooks with core transport fallbacks so chat * history sanitization, tool IDs, thinking blocks, and turn validation align. */ const DEFAULT_TRANSCRIPT_POLICY = { sanitizeMode: "images-only", sanitizeToolCallIds: false, toolCallIdMode: void 0, duplicateToolCallIdStyle: void 0, preserveNativeAnthropicToolUseIds: false, repairToolUseResultPairing: true, preserveSignatures: false, appendOnlyRuntimeContext: false, inHistorySystemUpdates: false, sanitizeThoughtSignatures: void 0, dropThinkingBlocks: false, dropReasoningFromHistory: false, applyGoogleTurnOrdering: false, validateGeminiTurns: false, validateAnthropicTurns: false, allowSyntheticToolResults: false }; function isOpenAiResponsesCompatibleApi(modelApi) { return modelApi === "openai-responses" || modelApi === "openai-chatgpt-responses" || modelApi === "azure-openai-responses"; } function modelDisablesReasoningEffort(model) { return (model?.compat)?.supportsReasoningEffort === false; } /** * Provides a narrow replay-policy fallback for providers that do not have an * owning runtime plugin. * * This exists to preserve generic custom-provider behavior. Bundled providers * should express replay ownership through `buildReplayPolicy` instead. */ function buildUnownedProviderTransportReplayFallback(params) { const isGoogle = isGoogleModelApi(params.modelApi); if (isAnthropicApi(params.modelApi)) return { ...buildAnthropicReplayPolicyForModel(params.modelId ?? void 0, params.model, params.inHistorySystemUpdates), ...modelDisablesReasoningEffort(params.model) ? { dropThinkingBlocks: true } : {} }; const isStrictOpenAiCompatible = params.modelApi === "openai-completions"; const isOpenAiResponses = isOpenAiResponsesCompatibleApi(params.modelApi); if (!isGoogle && !(isStrictOpenAiCompatible || isOpenAiResponses)) return; const modelId = normalizeLowercaseStringOrEmpty(params.modelId); const isClaudeOpenAiResponses = isOpenAiResponses && /(?:^|[./:_-])claude(?:$|[./:_-])/.test(modelId); return { ...isGoogle ? { sanitizeMode: "full" } : {}, sanitizeToolCallIds: true, toolCallIdMode: "strict", ...isGoogle ? { sanitizeThoughtSignatures: { allowBase64Only: true, includeCamelCase: true } } : {}, ...isStrictOpenAiCompatible ? { dropReasoningFromHistory: params.model?.reasoning !== true && !requiresReasoningContentReplay(params.modelId) } : {}, ...isGoogle || isStrictOpenAiCompatible ? { applyAssistantFirstOrderingFix: true, validateGeminiTurns: true } : {}, ...isStrictOpenAiCompatible || isClaudeOpenAiResponses ? { validateAnthropicTurns: true } : {}, ...isGoogle || isOpenAiResponses ? { allowSyntheticToolResults: true } : {} }; } const REASONING_CONTENT_REPLAY_MODEL_IDS = /* @__PURE__ */ new Set([ "kimi-for-coding", "kimi-k2.5", "kimi-k2.6", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k3", "kimi-k2-thinking", "kimi-k2-thinking-turbo", "mimo-v2-pro", "mimo-v2-omni", "mimo-v2.5", "mimo-v2.5-pro", "mimo-v2.6-flash", "mimo-v2.6-pro", "mimo-v2.6-pro-ultraspeed" ]); function requiresReasoningContentReplay(modelId) { const normalized = normalizeLowercaseStringOrEmpty(modelId); if (!normalized) return false; const parts = normalized.split("/").filter(Boolean); const finalPart = parts[parts.length - 1] ?? normalized; const candidates = [finalPart]; const colonParts = finalPart.split(":").filter(Boolean); if (colonParts.length > 1) candidates.push(colonParts[0] ?? "", colonParts[colonParts.length - 1] ?? ""); return candidates.some((candidate) => REASONING_CONTENT_REPLAY_MODEL_IDS.has(candidate)); } function mergeTranscriptPolicy(policy) { if (!policy) return DEFAULT_TRANSCRIPT_POLICY; const merged = { ...DEFAULT_TRANSCRIPT_POLICY }; for (const [key, value] of Object.entries(policy)) if (value != null) Object.assign(merged, { [key === "applyAssistantFirstOrderingFix" ? "applyGoogleTurnOrdering" : key]: value }); return merged; } const transcriptPolicyCache = /* @__PURE__ */ new WeakMap(); /** Resolve and cache the effective replay policy for a provider/model/config tuple. */ function resolveTranscriptPolicy(params) { const provider = normalizeProviderId(params.provider ?? ""); const cacheConfig = !params.env || params.env === process.env ? params.config : void 0; const cacheKey = cacheConfig ? JSON.stringify({ provider, directApiKey: params.directApiKey === true, baseUrl: params.model?.baseUrl?.trim() || (params.env ?? process.env).ANTHROPIC_BASE_URL?.trim() || "", modelApi: params.modelApi ?? "", modelId: params.modelId ?? "", canonicalModelId: typeof params.model?.params?.canonicalModelId === "string" ? params.model.params.canonicalModelId : "", dropsThinkingForReasoningCompat: modelDisablesReasoningEffort(params.model), preservesReasoningContentReplay: params.model?.reasoning === true, workspaceDir: params.workspaceDir ?? "", pluginControlPlane: resolvePluginControlPlaneFingerprint({ config: cacheConfig, workspaceDir: params.workspaceDir, env: params.env }) }) : void 0; if (cacheConfig && cacheKey) { const cached = transcriptPolicyCache.get(cacheConfig)?.get(cacheKey); if (cached) return cached; } const runtimePlugin = params.runtimeHandle?.plugin ?? (provider ? resolveProviderRuntimePlugin({ provider, modelId: params.modelId, config: params.config, workspaceDir: params.workspaceDir, env: params.env }) : void 0); const context = { config: params.config, workspaceDir: params.workspaceDir, env: params.env, provider, modelId: params.modelId ?? "", modelApi: params.modelApi, model: params.model, inHistorySystemUpdates: params.directApiKey === true && params.modelApi === "anthropic-messages" && isDirectAnthropicModel({ provider, baseUrl: params.model?.baseUrl }, params.env) && supportsClaudeInHistorySystemMessages({ id: params.modelId ?? void 0, params: params.model?.params }) }; const buildReplayPolicy = runtimePlugin?.buildReplayPolicy; const policy = buildReplayPolicy ? mergeTranscriptPolicy(buildReplayPolicy(context) ?? void 0) : mergeTranscriptPolicy(buildUnownedProviderTransportReplayFallback({ modelApi: params.modelApi, modelId: params.modelId, model: params.model, inHistorySystemUpdates: context.inHistorySystemUpdates })); if (policy.inHistorySystemUpdates) { policy.inHistorySystemUpdates = context.inHistorySystemUpdates; policy.appendOnlyRuntimeContext ||= context.inHistorySystemUpdates; } if (cacheConfig && cacheKey) { let configCache = transcriptPolicyCache.get(cacheConfig); if (!configCache) { configCache = /* @__PURE__ */ new Map(); transcriptPolicyCache.set(cacheConfig, configCache); } configCache.set(cacheKey, policy); } return policy; } //#endregion //#region src/agents/embedded-agent-runner/run/helpers.ts const RUNTIME_AUTH_REFRESH_MARGIN_MS = 3e5; const RUNTIME_AUTH_REFRESH_RETRY_MS = 6e4; const RUNTIME_AUTH_REFRESH_MIN_DELAY_MS = 5e3; const ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL = "ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL"; const ANTHROPIC_MAGIC_STRING_REPLACEMENT = "[redacted]"; /** Anthropic's transport interprets this marker even for native-owned attempts. */ function resolveEmbeddedAttemptBasePrompt(params) { if (params.provider !== "anthropic") return params.prompt; return params.prompt.replaceAll(ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL, ANTHROPIC_MAGIC_STRING_REPLACEMENT); } function createRunRecoveryDiagId() { return `ovf-${Date.now().toString(36)}-${generateSecureToken(4)}`; } const BASE_RUN_RETRY_ITERATIONS = 24; const RUN_RETRY_ITERATIONS_PER_PROFILE = 8; const MIN_RUN_RETRY_ITERATIONS = 32; const MAX_RUN_RETRY_ITERATIONS = 160; function resolveMaxRunRetryIterations(profileCandidateCount) { const scaled = BASE_RUN_RETRY_ITERATIONS + Math.max(1, profileCandidateCount) * RUN_RETRY_ITERATIONS_PER_PROFILE; return Math.min(MAX_RUN_RETRY_ITERATIONS, Math.max(MIN_RUN_RETRY_ITERATIONS, scaled)); } function resolveReportedModelRef(params) { const assistantProvider = params.assistant?.provider?.trim(); const assistantModel = params.assistant?.model?.trim(); if (assistantProvider?.toLowerCase() === "openclaw") return { provider: params.provider, model: params.model }; return { provider: assistantProvider || params.provider, model: assistantModel || params.model }; } function resolveLatestCallUsage(params) { const currentAttempt = params.currentAttemptCandidates.find(hasNonzeroUsage); const carriedUsage = hasNonzeroUsage(params.carriedUsage) ? params.carriedUsage : void 0; const transcriptFallback = hasNonzeroUsage(params.transcriptFallback) ? params.transcriptFallback : void 0; return { currentAttempt, latest: currentAttempt ?? carriedUsage ?? transcriptFallback }; } function normalizeAssistantUsageForContext(assistant) { if (assistant?.api === "cli" && assistant.usage && typeof assistant.usage === "object" && !Array.isArray(assistant.usage) && assistant.usage.contextUsage === void 0) return { contextUsage: { state: "unavailable" } }; return normalizeUsage(assistant?.usage); } function buildUsageAgentMetaFields(params) { const usage = toNormalizedUsage(params.usageAccumulator); const latestUsage = normalizeUsage(params.latestUsage); const lastCallUsage = hasNonzeroUsage(latestUsage) ? latestUsage : hasNonzeroUsage(params.lastRunPromptUsage) ? params.lastRunPromptUsage : void 0; return { usage, lastCallUsage, promptTokens: deriveContextPromptTokens({ lastCallUsage }), ...usage?.cost ? { costUsd: usage.cost.total } : {} }; } /** Error returns retain usage so the session does not keep an older context total. */ function buildErrorAgentMeta(params) { const usageMeta = buildUsageAgentMetaFields({ usageAccumulator: params.usageAccumulator, latestUsage: normalizeAssistantUsageForContext(params.currentAttemptAssistant), lastRunPromptUsage: params.lastRunPromptUsage }); return { sessionId: params.sessionId, ...params.sessionFile ? { sessionFile: params.sessionFile } : {}, provider: params.provider, model: params.model, ...params.credentialSource ? { credentialSource: params.credentialSource } : {}, ...params.contextTokens ? { contextTokens: params.contextTokens } : {}, ...params.contextTokens ? { contextTokensSource: "resolved" } : {}, ...usageMeta.usage ? { usage: usageMeta.usage } : {}, ...usageMeta.lastCallUsage ? { lastCallUsage: usageMeta.lastCallUsage } : {}, ...usageMeta.promptTokens ? { promptTokens: usageMeta.promptTokens } : {}, ...usageMeta.costUsd !== void 0 ? { costUsd: usageMeta.costUsd } : {} }; } function resolveFinalAssistantVisibleText(lastAssistant) { if (!lastAssistant) return; return extractAssistantVisibleText(lastAssistant).trim() || void 0; } function resolveFinalAssistantRawText(lastAssistant) { if (!lastAssistant) return; return (extractAssistantTextForPhase(lastAssistant, { phase: "final_answer" }) ?? extractAssistantTextForPhase(lastAssistant) ?? "").trim() || void 0; } //#endregion export { buildUsageAgentMetaFields as a, resolveEmbeddedAttemptBasePrompt as c, resolveLatestCallUsage as d, resolveMaxRunRetryIterations as f, buildErrorAgentMeta as i, resolveFinalAssistantRawText as l, resolveTranscriptPolicy as m, RUNTIME_AUTH_REFRESH_MIN_DELAY_MS as n, createRunRecoveryDiagId as o, resolveReportedModelRef as p, RUNTIME_AUTH_REFRESH_RETRY_MS as r, normalizeAssistantUsageForContext as s, RUNTIME_AUTH_REFRESH_MARGIN_MS as t, resolveFinalAssistantVisibleText as u };