Switch chat agents to GPT-5.6 Luna (max reasoning) (#499)
This commit is contained in:
parent
61b32ec647
commit
4d7fb661f0
@ -171,11 +171,12 @@ export class OnboardingChatAgent extends AIChatAgent {
|
|||||||
// Cancel the (billable) LLM call if the user aborts/navigates away.
|
// Cancel the (billable) LLM call if the user aborts/navigates away.
|
||||||
abortSignal: options?.abortSignal,
|
abortSignal: options?.abortSignal,
|
||||||
// Budget shared by reasoning + visible output. Reasoning tokens (enabled
|
// Budget shared by reasoning + visible output. Reasoning tokens (enabled
|
||||||
// on the model) eat into this, so it's well above what the ~350-word
|
// on the model) eat into this, and at max effort they dwarf the ~350-word
|
||||||
// strategy needs — otherwise the answer truncates mid-table once the
|
// strategy — the old 4000 cap left almost no answer headroom and
|
||||||
// model has spent the budget thinking. It's a ceiling, not a target: the
|
// truncated mid-table once the model had spent the budget thinking.
|
||||||
// model only generates (and we only bill) what it actually uses.
|
// Deliberately roomy: it's a per-step ceiling, not a target — the model
|
||||||
maxOutputTokens: 4000,
|
// only generates (and we only bill) what it actually uses.
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
stopWhen: stepCountIs(5),
|
stopWhen: stepCountIs(5),
|
||||||
// Meter LLM spend against the same credit pool as DataForSEO: sum the real
|
// Meter LLM spend against the same credit pool as DataForSEO: sum the real
|
||||||
// per-step cost OpenRouter reports and deduct it. Best-effort, hosted-only.
|
// per-step cost OpenRouter reports and deduct it. Best-effort, hosted-only.
|
||||||
|
|||||||
@ -302,9 +302,13 @@ export class SamChatAgent extends Think {
|
|||||||
// SAM is meant to run complex multi-step work in one turn (site-read
|
// SAM is meant to run complex multi-step work in one turn (site-read
|
||||||
// intake plus a full research chain, multi-competitor sweeps), so give
|
// intake plus a full research chain, multi-competitor sweeps), so give
|
||||||
// it generous headroom — cost is bounded by per-step metering and the
|
// it generous headroom — cost is bounded by per-step metering and the
|
||||||
// model stopping on its own, not by this cap.
|
// model stopping on its own, not by this cap. The per-step budget is
|
||||||
|
// shared by max-effort reasoning + visible output; a tight cap risks
|
||||||
|
// reasoning eating the reply (the issue #161 failure mode), so it's
|
||||||
|
// deliberately roomy — ~10x measured reasoning use — while keeping the
|
||||||
|
// worst-case turn (48 steps at the full cap) under ~$2.
|
||||||
maxSteps: 48,
|
maxSteps: 48,
|
||||||
maxOutputTokens: 6000,
|
maxOutputTokens: 32_000,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,30 +9,12 @@ import {
|
|||||||
|
|
||||||
// OpenRouter model slug used for the in-app chat agents (onboarding + SAM).
|
// OpenRouter model slug used for the in-app chat agents (onboarding + SAM).
|
||||||
// Override with OPENROUTER_MODEL to swap models without a code change.
|
// Override with OPENROUTER_MODEL to swap models without a code change.
|
||||||
const DEFAULT_CHAT_AGENT_MODEL = "minimax/minimax-m3";
|
const DEFAULT_CHAT_AGENT_MODEL = "openai/gpt-5.6-luna";
|
||||||
|
|
||||||
|
// Previous default; kept reachable via OPENROUTER_MODEL for rollback. Its
|
||||||
|
// routing needs the ZDR/provider tuning below.
|
||||||
|
const MINIMAX_M3 = "minimax/minimax-m3";
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the AI SDK LanguageModel for the chat agents. `usage: { include: true }`
|
|
||||||
* turns on OpenRouter usage accounting so each response carries its real USD
|
|
||||||
* cost (providerMetadata.openrouter.usage.cost) — which we meter against the
|
|
||||||
* shared usage-credit pool. `provider.order` prefers Together, then Atlas
|
|
||||||
* Cloud (fp8); `zdr: true` restricts routing to Zero-Data-Retention endpoints
|
|
||||||
* (prompts are never retained), which is the actual constraint — it excludes
|
|
||||||
* MiniMax first-party without a hand-maintained allowlist. The account also
|
|
||||||
* enforces this ("Non-frontier requires ZDR" data policy); the request-level
|
|
||||||
* flag is belt-and-braces so the constraint survives a dashboard change.
|
|
||||||
* Fallbacks stay on within the ZDR set because pinning providers caused a
|
|
||||||
* prod outage (Jul 2026: Together upstream-rate-limited m3 and every chat
|
|
||||||
* turn 429'd); as of Jul 2026 the ZDR set for m3 is Together/AtlasCloud/
|
|
||||||
* Novita/Parasail at the same price plus Morph at 2x output as a last resort.
|
|
||||||
*
|
|
||||||
* `reasoning` turns on OpenRouter's reasoning-token channel so the model's
|
|
||||||
* chain-of-thought comes back as a separate reasoning stream instead of
|
|
||||||
* leaking into the visible answer text (MiniMax M3 otherwise dumps its
|
|
||||||
* `<think>` trace inline). `effort: "medium"` is OpenRouter's default —
|
|
||||||
* stated explicitly only because the SDK type requires one once the channel
|
|
||||||
* is configured.
|
|
||||||
*/
|
|
||||||
export async function getChatAgentModel(): Promise<LanguageModelV3> {
|
export async function getChatAgentModel(): Promise<LanguageModelV3> {
|
||||||
const apiKey = await getRequiredEnvValue("OPENROUTER_API_KEY");
|
const apiKey = await getRequiredEnvValue("OPENROUTER_API_KEY");
|
||||||
const modelId = await getOptionalEnvValue("OPENROUTER_MODEL");
|
const modelId = await getOptionalEnvValue("OPENROUTER_MODEL");
|
||||||
@ -40,21 +22,49 @@ export async function getChatAgentModel(): Promise<LanguageModelV3> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronous variant for callers that already hold the env values. Think's
|
* Returns the AI SDK LanguageModel for the chat agents. `usage: { include: true }`
|
||||||
* `getModel()` hook is sync and runs on every turn, so the SAM agent reads the
|
* turns on OpenRouter usage accounting so each response carries its real USD
|
||||||
* key/model from its DO env and builds the model here.
|
* cost (providerMetadata.openrouter.usage.cost) — which we meter against the
|
||||||
|
* shared usage-credit pool.
|
||||||
|
*
|
||||||
|
* Default model: GPT-5.6 Luna at `reasoning.effort: "max"` — "max" is valid at
|
||||||
|
* the OpenRouter API for GPT-5.x but missing from the SDK's effort union, so
|
||||||
|
* the reasoning config rides in `extraBody`. Reasoning tokens stream on the
|
||||||
|
* separate reasoning channel and are billed as output tokens, which the usage
|
||||||
|
* accounting above captures.
|
||||||
|
*
|
||||||
|
* Sync on purpose: Think's `getModel()` hook is sync and runs on every turn,
|
||||||
|
* so the SAM agent reads the key/model from its DO env and builds here.
|
||||||
*/
|
*/
|
||||||
export function buildChatAgentModel(
|
export function buildChatAgentModel(
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
modelId?: string,
|
modelId?: string,
|
||||||
): LanguageModelV3 {
|
): LanguageModelV3 {
|
||||||
return createOpenRouter({ apiKey })(modelId ?? DEFAULT_CHAT_AGENT_MODEL, {
|
const model = modelId ?? DEFAULT_CHAT_AGENT_MODEL;
|
||||||
|
const openrouter = createOpenRouter({ apiKey });
|
||||||
|
|
||||||
|
// MiniMax M3 (env-override path only): `provider.order` prefers Together,
|
||||||
|
// then Atlas Cloud (fp8); `zdr: true` restricts routing to Zero-Data-
|
||||||
|
// Retention endpoints, which excludes MiniMax first-party — the account's
|
||||||
|
// "Non-frontier requires ZDR" data policy enforces the same, this flag is
|
||||||
|
// belt-and-braces. Fallbacks stay on within the ZDR set because pinning
|
||||||
|
// providers caused a prod outage (Jul 2026: Together upstream-rate-limited
|
||||||
|
// m3 and every chat turn 429'd). The explicit reasoning channel keeps m3's
|
||||||
|
// `<think>` trace out of the visible answer text.
|
||||||
|
if (model === MINIMAX_M3) {
|
||||||
|
return openrouter(model, {
|
||||||
|
usage: { include: true },
|
||||||
|
reasoning: { effort: "medium" },
|
||||||
|
provider: {
|
||||||
|
order: ["together", "atlas-cloud/fp8"],
|
||||||
|
zdr: true,
|
||||||
|
allow_fallbacks: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return openrouter(model, {
|
||||||
usage: { include: true },
|
usage: { include: true },
|
||||||
reasoning: { effort: "medium" },
|
extraBody: { reasoning: { effort: "max" } },
|
||||||
provider: {
|
|
||||||
order: ["together", "atlas-cloud/fp8"],
|
|
||||||
zdr: true,
|
|
||||||
allow_fallbacks: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user