mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-21 09:32:24 +00:00
🧠 feat: Configurable Reasoning Replay for Custom Endpoints (#13921)
* 🧠 feat: Configurable Reasoning Replay for Custom Endpoints Adds customParams.includeReasoningContent so OpenAI-compatible custom endpoints (e.g. Xiaomi MiMo, Kimi) can replay reasoning_content on tool-call turns natively, without impersonating the moonshot provider. * 🔁 feat: Replay reasoning_content across turns for opted-in custom endpoints Extends the DeepSeek reasoning-content format spoof to honor customParams.includeReasoningContent, so custom OpenAI-compatible endpoints (Xiaomi MiMo, Kimi) reconstruct reasoning_content from persisted history on later turns, matching DeepSeek thinking-mode parity. Adds shouldReplayReasoningContent predicate (tested) and surfaces the flag on the initialized agent. * 🪢 refactor: Split within-run vs cross-turn reasoning replay flags moonshot only replays reasoning_content within a run's tool calls, not across turns. Decouples the two: includeReasoningContent = within-run replay (exact moonshot parity), new includeReasoningHistory = cross-turn reconstruction from persisted history (implies includeReasoningContent, since reconstruction is a no-op without the within-run replay flag). * 🩹 fix: Apply reasoning replay across all param-format branches Move the within-run includeReasoningContent application out of the OpenAI-only branch in getOpenAIConfig to after the branch dispatch, so custom endpoints using anthropic/google defaultParamsEndpoint gateway modes also honor includeReasoningContent/includeReasoningHistory. Addresses Codex finding. * chore: Update @librechat/agents to v3.2.46 * 🧽 refactor: De-spoof reasoning replay via explicit preserveReasoningContent Now that @librechat/agents 3.2.46 exposes an explicit preserveReasoningContent option on formatAgentMessages, pass it directly instead of impersonating provider: deepseek. Behavior is unchanged (shouldReplayReasoningContent still gates DeepSeek + the custom includeReasoningHistory flag); also corrects the comment to reference includeReasoningHistory. * 🌳 fix: Walk subagents in the reasoning-history replay gate The gate only checked the primary agent and top-level handoff/parallel configs, so an opted-in custom endpoint used solely as a nested subagent had its persisted reasoning dropped on later turns. New exported anyAgentReplaysReasoningContent walks subagentAgentConfigs (cycle-safe, mirrors anyAgentHasCodeEnv); client.js uses it. Addresses Codex finding.
This commit is contained in:
parent
f09a1ad7fc
commit
d9a76fca90
12 changed files with 276 additions and 23 deletions
|
|
@ -46,7 +46,7 @@
|
|||
"@azure/storage-blob": "^12.30.0",
|
||||
"@google/genai": "^2.8.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@librechat/agents": "^3.2.44",
|
||||
"@librechat/agents": "^3.2.46",
|
||||
"@librechat/api": "*",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const {
|
|||
computeSummaryUsedTokens,
|
||||
priorRunOutputTokens,
|
||||
createSubagentUsageSink,
|
||||
isDeepSeekReasoningProvider,
|
||||
anyAgentReplaysReasoningContent,
|
||||
GenerationJobManager,
|
||||
getTransactionsConfig,
|
||||
resolveRecursionLimit,
|
||||
|
|
@ -1160,14 +1160,17 @@ class AgentClient extends BaseClient {
|
|||
agents: [this.options.agent, ...(this.agentConfigs ? this.agentConfigs.values() : [])],
|
||||
});
|
||||
|
||||
/** Spoof `Providers.DEEPSEEK` so the SDK preserves `reasoning_content` on tool turns (#13366). */
|
||||
const hasDeepSeekAgent = (agent) =>
|
||||
agent != null &&
|
||||
isDeepSeekReasoningProvider(agent.provider, agent.model_parameters?.model ?? agent.model);
|
||||
const needsDeepSeekFormat =
|
||||
hasDeepSeekAgent(this.options.agent) ||
|
||||
(this.agentConfigs != null &&
|
||||
Array.from(this.agentConfigs.values()).some(hasDeepSeekAgent));
|
||||
/**
|
||||
* Reconstruct `reasoning_content` on prior tool-call turns: DeepSeek
|
||||
* thinking-mode (#13366) or custom endpoints opting in via
|
||||
* `customParams.includeReasoningHistory` (e.g. Xiaomi MiMo, Kimi).
|
||||
* Walks subagents too — the opted-in endpoint may appear only as a
|
||||
* nested subagent, not the primary or a top-level handoff agent.
|
||||
*/
|
||||
const needsReasoningContentFormat = anyAgentReplaysReasoningContent([
|
||||
this.options.agent,
|
||||
...(this.agentConfigs ? Array.from(this.agentConfigs.values()) : []),
|
||||
]);
|
||||
/**
|
||||
* Skills primed fresh this turn — manual ($ popover) and always-apply
|
||||
* (frontmatter). `injectSkillPrimes` (below) splices their SKILL.md
|
||||
|
|
@ -1184,9 +1187,9 @@ class AgentClient extends BaseClient {
|
|||
alwaysApplySkillPrimes,
|
||||
});
|
||||
const formatOptions =
|
||||
needsDeepSeekFormat || freshSkillPrimeNames.size > 0
|
||||
needsReasoningContentFormat || freshSkillPrimeNames.size > 0
|
||||
? {
|
||||
...(needsDeepSeekFormat ? { provider: Providers.DEEPSEEK } : {}),
|
||||
...(needsReasoningContentFormat ? { preserveReasoningContent: true } : {}),
|
||||
...(freshSkillPrimeNames.size > 0
|
||||
? { skipSkillBodyNames: freshSkillPrimeNames }
|
||||
: {}),
|
||||
|
|
|
|||
10
package-lock.json
generated
10
package-lock.json
generated
|
|
@ -61,7 +61,7 @@
|
|||
"@azure/storage-blob": "^12.30.0",
|
||||
"@google/genai": "^2.8.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@librechat/agents": "^3.2.44",
|
||||
"@librechat/agents": "^3.2.46",
|
||||
"@librechat/api": "*",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||
|
|
@ -9907,9 +9907,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@librechat/agents": {
|
||||
"version": "3.2.44",
|
||||
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.2.44.tgz",
|
||||
"integrity": "sha512-kBfF22rUye1D32FR55BaVqukphsYHfNpNxqvst2i/7iyFig81SVfCQaJQb715sEAkLTI8tYMOuoc1ui/l21ucA==",
|
||||
"version": "3.2.46",
|
||||
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.2.46.tgz",
|
||||
"integrity": "sha512-ppylwuFF3BOlhrnzDdD6J7h9mkUgAi9aF7LBt5pPpk6/Hab/h5BecxA6a7PyRo5x4xNfgPvAlnTn6MSDeAqJBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.92.0",
|
||||
|
|
@ -42463,7 +42463,7 @@
|
|||
"@azure/storage-blob": "^12.30.0",
|
||||
"@google/genai": "^2.8.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@librechat/agents": "^3.2.44",
|
||||
"@librechat/agents": "^3.2.46",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@
|
|||
"@azure/storage-blob": "^12.30.0",
|
||||
"@google/genai": "^2.8.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@librechat/agents": "^3.2.44",
|
||||
"@librechat/agents": "^3.2.46",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
|
|
|
|||
|
|
@ -261,6 +261,8 @@ export type InitializedAgent = Agent & {
|
|||
maxToolResultChars?: number;
|
||||
/** Response field to read model reasoning from for custom OpenAI-compatible endpoints. */
|
||||
reasoningKey?: ReasoningResponseKey;
|
||||
/** Whether to reconstruct `reasoning_content` from persisted history across turns (custom endpoint opt-in). */
|
||||
includeReasoningHistory?: boolean;
|
||||
/**
|
||||
* Whether the code-execution environment is available *for this agent*.
|
||||
* Narrower than the incoming `params.codeEnvAvailable` admin flag — this
|
||||
|
|
@ -1257,6 +1259,7 @@ export async function initializeAgent(
|
|||
baseContextTokens,
|
||||
codeEnvAvailable: effectiveCodeEnvAvailable,
|
||||
reasoningKey: customEndpointConfig?.customParams?.reasoningKey,
|
||||
includeReasoningHistory: customEndpointConfig?.customParams?.includeReasoningHistory,
|
||||
skillAuthoringAvailable,
|
||||
fileAuthoringToolNames: fileAuthoringToolNames.size > 0 ? fileAuthoringToolNames : undefined,
|
||||
skillCount,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Providers } from '@librechat/agents';
|
||||
import { ToolMessage, AIMessage, HumanMessage } from '@librechat/agents/langchain/messages';
|
||||
import { ReasoningResponseKey } from 'librechat-data-provider';
|
||||
|
||||
import { ToolMessage, AIMessage, HumanMessage } from '@librechat/agents/langchain/messages';
|
||||
import {
|
||||
extractDiscoveredToolsFromHistory,
|
||||
getReasoningKey,
|
||||
isDeepSeekReasoningProvider,
|
||||
shouldReplayReasoningContent,
|
||||
anyAgentReplaysReasoningContent,
|
||||
} from './run';
|
||||
|
||||
describe('extractDiscoveredToolsFromHistory', () => {
|
||||
|
|
@ -274,3 +275,96 @@ describe('isDeepSeekReasoningProvider', () => {
|
|||
expect(isDeepSeekReasoningProvider(undefined, 'community/deepseek-r1')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldReplayReasoningContent', () => {
|
||||
it('returns true when a custom endpoint opts in via includeReasoningHistory', () => {
|
||||
expect(
|
||||
shouldReplayReasoningContent({
|
||||
provider: Providers.OPENAI,
|
||||
model_parameters: { model: 'MiMo-V2.5' },
|
||||
includeReasoningHistory: true,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for DeepSeek reasoning agents without the flag', () => {
|
||||
expect(
|
||||
shouldReplayReasoningContent({
|
||||
provider: Providers.DEEPSEEK,
|
||||
model_parameters: { model: 'deepseek-chat' },
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shouldReplayReasoningContent({
|
||||
provider: Providers.OPENROUTER,
|
||||
model_parameters: { model: 'deepseek/deepseek-v4-pro' },
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for a non-DeepSeek agent that has not opted in', () => {
|
||||
expect(
|
||||
shouldReplayReasoningContent({
|
||||
provider: Providers.OPENAI,
|
||||
model_parameters: { model: 'MiMo-V2.5' },
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
shouldReplayReasoningContent({
|
||||
provider: Providers.OPENAI,
|
||||
model_parameters: { model: 'MiMo-V2.5' },
|
||||
includeReasoningHistory: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for nullish agents', () => {
|
||||
expect(shouldReplayReasoningContent(null)).toBe(false);
|
||||
expect(shouldReplayReasoningContent(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('anyAgentReplaysReasoningContent', () => {
|
||||
const plainAgent = (id: string, extra = {}) =>
|
||||
({
|
||||
id,
|
||||
provider: Providers.OPENAI,
|
||||
model_parameters: { model: 'MiMo-V2.5' },
|
||||
...extra,
|
||||
}) as unknown as Parameters<typeof anyAgentReplaysReasoningContent>[0][number];
|
||||
|
||||
it('returns true when the primary agent opts in', () => {
|
||||
expect(
|
||||
anyAgentReplaysReasoningContent([plainAgent('a', { includeReasoningHistory: true })]),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when only a nested subagent opts in', () => {
|
||||
const subagent = plainAgent('child', { includeReasoningHistory: true });
|
||||
const primary = plainAgent('root', {
|
||||
subagentAgentConfigs: [plainAgent('mid', { subagentAgentConfigs: [subagent] })],
|
||||
});
|
||||
expect(anyAgentReplaysReasoningContent([primary])).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when no reachable agent opts in', () => {
|
||||
const primary = plainAgent('root', {
|
||||
subagentAgentConfigs: [plainAgent('child')],
|
||||
});
|
||||
expect(anyAgentReplaysReasoningContent([primary, null, undefined])).toBe(false);
|
||||
});
|
||||
|
||||
it('is cycle-safe across subagent references', () => {
|
||||
const a = plainAgent('a');
|
||||
const b = plainAgent('b', { includeReasoningHistory: true });
|
||||
(a as { subagentAgentConfigs?: unknown[] }).subagentAgentConfigs = [b];
|
||||
(b as { subagentAgentConfigs?: unknown[] }).subagentAgentConfigs = [a];
|
||||
expect(anyAgentReplaysReasoningContent([a])).toBe(true);
|
||||
|
||||
const x = plainAgent('x');
|
||||
const y = plainAgent('y');
|
||||
(x as { subagentAgentConfigs?: unknown[] }).subagentAgentConfigs = [y];
|
||||
(y as { subagentAgentConfigs?: unknown[] }).subagentAgentConfigs = [x];
|
||||
expect(anyAgentReplaysReasoningContent([x])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -284,6 +284,29 @@ export function isDeepSeekReasoningProvider(
|
|||
return matchesDeepSeekModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether prior assistant tool-call messages should have `reasoning_content`
|
||||
* reconstructed when reformatting persisted history (cross-turn replay): either
|
||||
* DeepSeek thinking-mode (#13366) or a custom OpenAI-compatible endpoint that
|
||||
* opted in via `customParams.includeReasoningHistory` (e.g. Xiaomi MiMo, Kimi).
|
||||
*/
|
||||
export function shouldReplayReasoningContent(
|
||||
agent?: {
|
||||
provider?: string | Providers | null;
|
||||
model?: string | null;
|
||||
model_parameters?: { model?: string | null } | null;
|
||||
includeReasoningHistory?: boolean | null;
|
||||
} | null,
|
||||
): boolean {
|
||||
if (agent == null) {
|
||||
return false;
|
||||
}
|
||||
if (agent.includeReasoningHistory === true) {
|
||||
return true;
|
||||
}
|
||||
return isDeepSeekReasoningProvider(agent.provider, agent.model_parameters?.model ?? agent.model);
|
||||
}
|
||||
|
||||
type RunAgent = Omit<Agent, 'tools'> & {
|
||||
tools?: GenericTool[];
|
||||
maxContextTokens?: number;
|
||||
|
|
@ -309,6 +332,8 @@ type RunAgent = Omit<Agent, 'tools'> & {
|
|||
summarization?: SummarizationConfig;
|
||||
/** Response field to read model reasoning from for custom OpenAI-compatible endpoints. */
|
||||
reasoningKey?: ReasoningResponseKey;
|
||||
/** Whether to reconstruct `reasoning_content` from persisted history across turns. */
|
||||
includeReasoningHistory?: boolean;
|
||||
/**
|
||||
* Maximum characters allowed in a single tool result before truncation.
|
||||
* Overrides the default computed from maxContextTokens.
|
||||
|
|
@ -699,6 +724,36 @@ function anyAgentHasCodeEnv(agents: RunAgent[]): boolean {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether any agent reachable in the run — primary, handoff/parallel, or a
|
||||
* nested subagent — opts into cross-turn `reasoning_content` reconstruction.
|
||||
* Walks `subagentAgentConfigs` like {@link anyAgentHasCodeEnv}, since an
|
||||
* opted-in custom endpoint may appear only as a (possibly pruned) subagent.
|
||||
*/
|
||||
export function anyAgentReplaysReasoningContent(
|
||||
agents: Array<RunAgent | null | undefined>,
|
||||
): boolean {
|
||||
const visited = new Set<string>();
|
||||
const pending = [...agents];
|
||||
|
||||
for (let index = 0; index < pending.length; index++) {
|
||||
const agent = pending[index];
|
||||
if (agent == null || visited.has(agent.id)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(agent.id);
|
||||
if (shouldReplayReasoningContent(agent)) {
|
||||
return true;
|
||||
}
|
||||
for (const child of agent.subagentAgentConfigs ?? []) {
|
||||
if (!visited.has(child.id)) {
|
||||
pending.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds SubagentConfig entries for an agent: optional self-spawn plus any
|
||||
* explicit child agents loaded in `agent.subagentAgentConfigs`. Returns an empty
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
EModelEndpoint,
|
||||
ReasoningEffort,
|
||||
ReasoningSummary,
|
||||
ReasoningResponseKey,
|
||||
ReasoningParameterFormat,
|
||||
} from 'librechat-data-provider';
|
||||
import type { RequestInit } from 'undici';
|
||||
|
|
@ -216,6 +217,84 @@ describe('getOpenAIConfig', () => {
|
|||
expect((result.llmConfig as Record<string, unknown>).reasoning_effort).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should replay reasoning content when custom endpoint enables includeReasoningContent', () => {
|
||||
const result = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
customParams: {
|
||||
reasoningKey: ReasoningResponseKey.reasoningContent,
|
||||
includeReasoningContent: true,
|
||||
},
|
||||
modelOptions: {
|
||||
model: 'MiMo-VL-7B-RL',
|
||||
},
|
||||
},
|
||||
'custom-endpoint',
|
||||
);
|
||||
|
||||
expect(result.llmConfig).toHaveProperty('includeReasoningContent', true);
|
||||
});
|
||||
|
||||
it('should enable within-run replay when custom endpoint enables includeReasoningHistory', () => {
|
||||
const result = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
customParams: {
|
||||
reasoningKey: ReasoningResponseKey.reasoningContent,
|
||||
includeReasoningHistory: true,
|
||||
},
|
||||
modelOptions: {
|
||||
model: 'MiMo-VL-7B-RL',
|
||||
},
|
||||
},
|
||||
'custom-endpoint',
|
||||
);
|
||||
|
||||
expect(result.llmConfig).toHaveProperty('includeReasoningContent', true);
|
||||
});
|
||||
|
||||
it('should enable within-run replay for non-OpenAI param-format gateways (anthropic/google)', () => {
|
||||
const anthropic = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
customParams: {
|
||||
defaultParamsEndpoint: EModelEndpoint.anthropic,
|
||||
includeReasoningContent: true,
|
||||
},
|
||||
modelOptions: { model: 'claude-3-7-sonnet' },
|
||||
},
|
||||
'custom-endpoint',
|
||||
);
|
||||
expect(anthropic.llmConfig).toHaveProperty('includeReasoningContent', true);
|
||||
|
||||
const google = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
customParams: {
|
||||
defaultParamsEndpoint: EModelEndpoint.google,
|
||||
includeReasoningHistory: true,
|
||||
},
|
||||
modelOptions: { model: 'gemini-2.5-pro' },
|
||||
},
|
||||
'custom-endpoint',
|
||||
);
|
||||
expect(google.llmConfig).toHaveProperty('includeReasoningContent', true);
|
||||
});
|
||||
|
||||
it('should not replay reasoning content for custom endpoints by default', () => {
|
||||
const result = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
modelOptions: {
|
||||
model: 'MiMo-VL-7B-RL',
|
||||
},
|
||||
},
|
||||
'custom-endpoint',
|
||||
);
|
||||
|
||||
expect(result.llmConfig).not.toHaveProperty('includeReasoningContent');
|
||||
});
|
||||
|
||||
it('should default Vercel custom endpoints to reasoning object format', () => {
|
||||
const result = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
|
|
|
|||
|
|
@ -202,6 +202,19 @@ export function getOpenAIConfig(
|
|||
tools = openaiResult.tools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Within-run `reasoning_content` replay applies across every param-format
|
||||
* branch above (OpenAI / Anthropic / Google gateway modes all resolve to the
|
||||
* OpenAI client). `includeReasoningHistory` implies it, since reconstructed
|
||||
* history reasoning is only sent when the within-run flag is set.
|
||||
*/
|
||||
if (
|
||||
options.customParams?.includeReasoningContent === true ||
|
||||
options.customParams?.includeReasoningHistory === true
|
||||
) {
|
||||
llmConfig.includeReasoningContent = true;
|
||||
}
|
||||
|
||||
const configOptions: t.OpenAIConfiguration = {};
|
||||
if (baseURL) {
|
||||
configOptions.baseURL = baseURL;
|
||||
|
|
|
|||
|
|
@ -667,10 +667,10 @@ export function getOpenAILLMConfig({
|
|||
}
|
||||
|
||||
/** DeepSeek thinking-mode requires `reasoning_content` replay on tool turns (#13366). */
|
||||
if (
|
||||
const isDeepSeekModel =
|
||||
typeof modelOptions.model === 'string' &&
|
||||
/^deepseek(?:[-/]|$)/i.test(modelOptions.model.replace(/^~/, ''))
|
||||
) {
|
||||
/^deepseek(?:[-/]|$)/i.test(modelOptions.model.replace(/^~/, ''));
|
||||
if (isDeepSeekModel) {
|
||||
llmConfig.includeReasoningContent = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -857,6 +857,10 @@ export const endpointSchema = baseEndpointSchema.merge(
|
|||
defaultParamsEndpoint: z.string().default('custom'),
|
||||
reasoningFormat: eReasoningParameterFormatSchema.optional(),
|
||||
reasoningKey: eReasoningResponseKeySchema.optional(),
|
||||
/** Replays `reasoning_content` within a run's tool-call turns (e.g. Xiaomi MiMo, Kimi). */
|
||||
includeReasoningContent: z.boolean().optional(),
|
||||
/** Also reconstructs `reasoning_content` from persisted history across turns (implies `includeReasoningContent`). */
|
||||
includeReasoningHistory: z.boolean().optional(),
|
||||
paramDefinitions: z.array(paramDefinitionSchema).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
|
|
|||
|
|
@ -456,6 +456,8 @@ export type TConfig = {
|
|||
defaultParamsEndpoint?: string;
|
||||
reasoningFormat?: ReasoningParameterFormat;
|
||||
reasoningKey?: ReasoningResponseKey;
|
||||
includeReasoningContent?: boolean;
|
||||
includeReasoningHistory?: boolean;
|
||||
paramDefinitions?: Partial<SettingDefinition>[];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue