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.
|
||||
abortSignal: options?.abortSignal,
|
||||
// Budget shared by reasoning + visible output. Reasoning tokens (enabled
|
||||
// on the model) eat into this, so it's well above what the ~350-word
|
||||
// strategy needs — otherwise the answer truncates mid-table once the
|
||||
// model has spent the budget thinking. It's a ceiling, not a target: the
|
||||
// model only generates (and we only bill) what it actually uses.
|
||||
maxOutputTokens: 4000,
|
||||
// on the model) eat into this, and at max effort they dwarf the ~350-word
|
||||
// strategy — the old 4000 cap left almost no answer headroom and
|
||||
// truncated mid-table once the model had spent the budget thinking.
|
||||
// Deliberately roomy: it's a per-step ceiling, not a target — the model
|
||||
// only generates (and we only bill) what it actually uses.
|
||||
maxOutputTokens: 32_000,
|
||||
stopWhen: stepCountIs(5),
|
||||
// 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.
|
||||
|
||||
@ -302,9 +302,13 @@ export class SamChatAgent extends Think {
|
||||
// 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
|
||||
// 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,
|
||||
maxOutputTokens: 6000,
|
||||
maxOutputTokens: 32_000,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -9,30 +9,12 @@ import {
|
||||
|
||||
// OpenRouter model slug used for the in-app chat agents (onboarding + SAM).
|
||||
// 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> {
|
||||
const apiKey = await getRequiredEnvValue("OPENROUTER_API_KEY");
|
||||
const modelId = await getOptionalEnvValue("OPENROUTER_MODEL");
|
||||
@ -40,15 +22,37 @@ export async function getChatAgentModel(): Promise<LanguageModelV3> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous variant for callers that already hold the env values. 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 the model here.
|
||||
* 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.
|
||||
*
|
||||
* 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(
|
||||
apiKey: string,
|
||||
modelId?: string,
|
||||
): 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: {
|
||||
@ -58,3 +62,9 @@ export function buildChatAgentModel(
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return openrouter(model, {
|
||||
usage: { include: true },
|
||||
extraBody: { reasoning: { effort: "max" } },
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user