UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

139 lines 6.67 kB
import type { LanguageModelV2Prompt } from '@ai-sdk/provider-v5'; import type { MastraDBMessage } from '../agent/message-list/index.js'; import type { Processor, ProcessAPIErrorArgs, ProcessAPIErrorResult, ProcessLLMRequestArgs, ProcessLLMRequestResult } from './index.js'; /** * A single compatibility rule that resolves a known provider history * incompatibility. Rules can resolve issues either: * * - **Reactively** via {@link CompatRule.fix}: when an API call fails with an * error matching one of {@link CompatRule.errorPatterns}, the fix mutates * the persisted message list and the request is retried. Suitable for * incompatibilities that, once fixed, stay fixed across future turns * (e.g. tool-call ID format). * * - **Preemptively** via {@link CompatRule.applyToPrompt}: runs in * `processLLMRequest` after `MessageList → LanguageModelV2Prompt` conversion * and before the prompt is sent to the provider. Mutations affect only the * outbound prompt; nothing is persisted to the message list. Suitable for * incompatibilities that would otherwise re-trigger on every turn (e.g. * fields the model adds to its own response that the same provider rejects * on subsequent input). * * A rule may implement either hook, both, or — rarely — neither (e.g. a * placeholder for future error-pattern matching). */ export interface CompatRule { /** Human-readable identifier for logging/debugging. */ name: string; /** Regexes matched against the error message and response body. */ errorPatterns?: RegExp[]; /** Mutate persisted messages to resolve the incompatibility. Return `true` if changes were made. */ fix?: (messages: MastraDBMessage[]) => boolean; /** * Rewrite the outbound LLM request preemptively. Receives the resolved model * so rules can scope themselves to specific providers. Return a new prompt * to forward, or `undefined` to leave the prompt unchanged. */ applyToPrompt?: (args: { prompt: LanguageModelV2Prompt; model: unknown; }) => LanguageModelV2Prompt | undefined; } /** * Anthropic enforces `^[a-zA-Z0-9_-]+$` on tool_use.id values. * Tool-call IDs from other providers (e.g. containing `.`, `:`) will be * rejected. This rule rewrites offending characters to `_`. */ export declare const anthropicToolIdFormat: CompatRule; export declare function isMaybeCerebras(model: string | { provider?: string; modelId?: string; } | ((...args: any[]) => any) | { model: any; enabled?: boolean; }[] | unknown): boolean; export declare function isMaybeAnthropic(model: string | { provider?: string; modelId?: string; } | ((...args: any[]) => any) | { model: any; enabled?: boolean; }[] | unknown): boolean; /** * Cerebras's API rejects assistant messages carrying a `reasoning_content` * field with HTTP 400 (`property '...reasoning_content' is unsupported`). * * Starting in `@ai-sdk/openai-compatible@1.0.32` (https://github.com/vercel/ai/pull/12049), * which `@ai-sdk/cerebras` depends on, reasoning parts on assistant messages * are unconditionally serialized as `reasoning_content` on outbound requests. * That breaks multi-turn tool calls with reasoning enabled (e.g. * `cerebras/zai-glm-4.7`) on the second-or-later assistant turn. * * This rule preemptively strips `reasoning` parts from assistant messages * in the outbound prompt when the resolved model is Cerebras. The strip * runs in `processLLMRequest` so it affects only what is sent to Cerebras — * the persisted message list (memory, UI, observability) keeps the full * reasoning trace, and other providers (e.g. Z.ai's coding-plan endpoint, * which *requires* `reasoning_content` echoed back for its preserved-thinking * feature) are unaffected because the rule is provider-scoped. * * It can't be reactive (`processAPIError`) because the model emits a fresh * reasoning part on every turn — a reactive rule would cause one * failed-and-retried request per turn. * * Once https://github.com/vercel/ai/pull/11278 lands a per-provider * `sendReasoning` opt-out, this rule can be replaced with `sendReasoning: false` * on the cerebras provider config. */ export declare const cerebrasStripReasoningContent: CompatRule; /** * Anthropic accepts its own thinking/reasoning history, but rejects reasoning * parts emitted by other providers. Strip only foreign reasoning parts at the * Anthropic provider boundary so persisted history remains intact and native * Anthropic thinking can still round-trip. */ export declare const anthropicStripForeignReasoningContent: CompatRule; /** * All built-in compat rules. Extend by passing additional rules to the * `ProviderHistoryCompat` constructor. */ export declare const DEFAULT_COMPAT_RULES: CompatRule[]; /** * Handles provider-specific history incompatibilities by applying a registry * of {@link CompatRule}s. Rules can rewrite the outbound prompt preemptively * via `processLLMRequest`, or react to non-retryable API rejections via * `processAPIError`. * * Built-in rules: * - **anthropic-tool-id-format** — rewrites tool-call IDs that contain * characters outside `[a-zA-Z0-9_-]` (e.g. `.` or `:` from other * providers). Reactive (matches a 400 response body, retries with * sanitized IDs). * - **cerebras-strip-reasoning-content** — strips `reasoning` parts from * assistant messages in the outbound prompt when the resolved model is * Cerebras, to avoid the `@ai-sdk/openai-compatible@>=1.0.32` regression * that serializes them as `reasoning_content` (a field Cerebras's API * rejects). Preemptive; runs in `processLLMRequest` so the persisted * message list keeps the reasoning trace. * - **anthropic-strip-foreign-reasoning-content** — strips non-Anthropic * `reasoning` parts from assistant messages in the outbound prompt when the * resolved model is Anthropic. Anthropic-native reasoning parts are kept. * * To add custom rules, pass them to the constructor: * ```ts * new ProviderHistoryCompat({ * additionalRules: [myCustomRule], * }) * ``` */ export declare class ProviderHistoryCompat implements Processor<'provider-history-compat'> { readonly id: "provider-history-compat"; readonly name = "Provider History Compat"; private rules; constructor(opts?: { additionalRules?: CompatRule[]; }); processLLMRequest({ prompt, model }: ProcessLLMRequestArgs): ProcessLLMRequestResult; processAPIError({ error, messageList, retryCount, }: ProcessAPIErrorArgs): Promise<ProcessAPIErrorResult | void>; } //# sourceMappingURL=provider-history-compat.d.ts.map