@mastra/core
Version:
Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.
139 lines • 6.67 kB
TypeScript
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