Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/landing/InteractiveHeroAiPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { WorkspaceItem } from "#/features/workspaces/contracts";
import { getWorkspaceItemDisplay } from "#/features/workspaces/model/item-display";
import { cn } from "#/lib/utils";

const MODELS = ["Auto", "GPT-5", "Claude Sonnet", "Gemini Pro"] as const;
const MODELS = ["Auto", "GPT-6.1 Sol", "Claude Sonnet", "Gemini Pro"] as const;

/** Lightweight AI chat simulation for the public workspace preview. */
export function InteractiveHeroAiPanel({
Expand Down
2 changes: 1 addition & 1 deletion src/components/landing/visuals/ModelsVisual.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const MODEL_GROUPS = WORKSPACE_AI_CHAT_PROVIDERS.map((provider) => ({
})).filter((group) => group.models.length > 0);

export function ModelsVisual() {
const [selectedModelId, setSelectedModelId] = useState<WorkspaceAiChatModelId>("gpt-terra");
const [selectedModelId, setSelectedModelId] = useState<WorkspaceAiChatModelId>("gpt-sol");
// Derived from the registry rather than restated, so a new provider or model
// shows up here without an edit. Hoisted out of render: it is constant.
const detailModel = getWorkspaceAiChatModelById(selectedModelId);
Expand Down
32 changes: 15 additions & 17 deletions src/features/workspaces/ai/ai-gateway-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ type GatewayRoutingOptions = {

const GOOGLE_GATEWAY_PROVIDER_ORDER = ["google", "vertex"];
// The native Anthropic route is the only one we want. Vertex has no Anthropic
// quota in our GCP project (429 in ~200ms) and Bedrock has no Sonnet 5 access
// (403), so both only ever landed on Vercel's own credits. Cross-model fallback
// below covers a genuine Anthropic outage; add a provider back here if its
// account-side access is ever granted.
// quota in our GCP project (429 in ~200ms) and Bedrock has no current Sonnet
// access (403), so both only ever landed on Vercel's own credits. Cross-model
// fallback below covers a genuine Anthropic outage; add a provider back here if
// its account-side access is ever granted.
const CLAUDE_GATEWAY_PROVIDER_ORDER = ["anthropic"];
// `only` is the gateway's sole exclusion primitive, and it is a hard filter over
// the whole request — the fallback models below are unreachable unless their
Expand All @@ -29,33 +29,33 @@ const CLAUDE_GATEWAY_PROVIDER_ALLOWLIST = ["anthropic", "openai", "google"];
const workspaceAiGatewayRouting: Record<WorkspaceAiChatModelId, GatewayRoutingOptions> = {
auto: {
order: ["openai", "azure"],
models: ["google/gemini-3-flash", "anthropic/claude-haiku-4.5"],
models: ["google/gemini-3.8-flash", "anthropic/claude-haiku-4.5"],
},
"claude-sonnet": {
only: CLAUDE_GATEWAY_PROVIDER_ALLOWLIST,
order: CLAUDE_GATEWAY_PROVIDER_ORDER,
models: ["openai/gpt-5.6-terra", "google/gemini-3.1-pro-preview"],
models: ["openai/gpt-6.1-sol", "google/gemini-3.1-pro-preview"],
},
"claude-haiku": {
only: CLAUDE_GATEWAY_PROVIDER_ALLOWLIST,
order: CLAUDE_GATEWAY_PROVIDER_ORDER,
models: ["openai/gpt-5.6-luna", "google/gemini-3-flash"],
models: ["openai/gpt-6-luna", "google/gemini-3.8-flash"],
},
"gpt-terra": {
"gpt-sol": {
order: ["openai", "azure"],
models: ["anthropic/claude-sonnet-5", "google/gemini-3.1-pro-preview"],
models: ["anthropic/claude-sonnet-5.5", "google/gemini-3.1-pro-preview"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

This routing change is not covered by a test: the updated observability fixture uses hand-built metadata and never calls getWorkspaceAiGatewayRoutingOptions. Add a regression assertion for the gpt-terra and gemini-pro fallback model lists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/features/workspaces/ai/ai-gateway-routing.ts, line 46:

<comment>This routing change is not covered by a test: the updated observability fixture uses hand-built metadata and never calls `getWorkspaceAiGatewayRoutingOptions`. Add a regression assertion for the `gpt-terra` and `gemini-pro` fallback model lists.</comment>

<file context>
@@ -43,15 +43,15 @@ const workspaceAiGatewayRouting: Record<WorkspaceAiChatModelId, GatewayRoutingOp
 	"gpt-terra": {
 		order: ["openai", "azure"],
-		models: ["anthropic/claude-sonnet-5", "google/gemini-3.1-pro-preview"],
+		models: ["anthropic/claude-sonnet-5.5", "google/gemini-3.1-pro-preview"],
 	},
 	"gpt-luna": {
</file context>

},
"gpt-luna": {
order: ["openai", "azure"],
models: ["google/gemini-3-flash", "anthropic/claude-haiku-4.5"],
models: ["google/gemini-3.8-flash", "anthropic/claude-haiku-4.5"],
},
"gemini-pro": {
order: GOOGLE_GATEWAY_PROVIDER_ORDER,
models: ["openai/gpt-5.6-terra", "anthropic/claude-sonnet-5"],
models: ["openai/gpt-6.1-sol", "anthropic/claude-sonnet-5.5"],
},
gemini: {
order: GOOGLE_GATEWAY_PROVIDER_ORDER,
models: ["openai/gpt-5.6-luna", "anthropic/claude-haiku-4.5"],
models: ["openai/gpt-6-luna", "anthropic/claude-haiku-4.5"],
},
};

Expand All @@ -66,10 +66,8 @@ export function getWorkspaceAiGatewayRoutingOptions(modelId: WorkspaceAiChatMode
export function getAIThreadTitleGatewayRoutingOptions() {
return {
order: GOOGLE_GATEWAY_PROVIDER_ORDER,
// Cross-provider backstop for the Google primary. gpt-4.1-nano was retired
// from ChatGPT and has an Azure end-of-life with no named successor, so
// track a current nano instead.
models: ["openai/gpt-5.4-nano"],
// Lightweight cross-provider backstop for title generation.
models: ["openai/gpt-6-luna"],
};
}

Expand All @@ -78,6 +76,6 @@ export function getWorkspaceImageExtractionGatewayRoutingOptions() {
order: GOOGLE_GATEWAY_PROVIDER_ORDER,
// Cross-provider backstop so a Google outage still gets an image read.
// Both fallbacks accept image input; a text-only model would 400 the leg.
models: ["openai/gpt-5.6-luna", "anthropic/claude-haiku-4.5"],
models: ["openai/gpt-6-luna", "anthropic/claude-haiku-4.5"],
};
}
2 changes: 1 addition & 1 deletion src/features/workspaces/ai/chat/chat-telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface AiChatGenerationTelemetry {
threadId: string;
/** The turn's stream id — one trace groups the turn and its utility calls. */
traceId: string;
/** The gateway model string, e.g. "anthropic/claude-sonnet-5". */
/** The gateway model string, e.g. "anthropic/claude-sonnet-5.5". */
gatewayModel: string;
/** The app-level model id the user picked, for the requested_model property. */
requestedModel?: string;
Expand Down
15 changes: 8 additions & 7 deletions src/features/workspaces/ai/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
// has no framework dependencies; the comments carry over because the tuning
// rationale is unchanged.

export const AI_THREAD_TITLE_GATEWAY_MODEL = "google/gemini-2.5-flash-lite";
export const AI_THREAD_TITLE_GATEWAY_MODEL = "google/gemini-3.5-flash-lite";

type WorkspaceAiProviderOptions = NonNullable<
Parameters<typeof generateText>[0]["providerOptions"]
Expand Down Expand Up @@ -52,7 +52,7 @@ export function getWorkspaceAiGatewayTransportOptions() {
// Buy the fast lane where it exists. The gateway only forwards a tier to
// OpenAI, Google AI Studio, and Vertex, so this is a no-op on the Claude
// primaries and moves the models we actually default to (`auto`/luna, the
// Gemini pair, the nano/flash-lite title legs). It is a hint, never a
// Gemini pair, the luna/flash-lite title legs). It is a hint, never a
// promise: an unsupported model ignores it, and a provider that is out of
// priority capacity silently downgrades to standard and bills standard.
serviceTier: "priority" as const,
Expand Down Expand Up @@ -109,9 +109,9 @@ export function getAIThreadTitleGatewayProviderOptions(): WorkspaceAiProviderOpt
`model:${AI_THREAD_TITLE_GATEWAY_MODEL}`,
],
},
// The 2.5-series title model rejects `thinkingLevel`; budget is its knob.
google: { thinkingConfig: { thinkingBudget: 0 } },
vertex: { thinkingConfig: { thinkingBudget: 0 } },
// Keep title generation at the lowest supported thinking level.
google: { thinkingConfig: { thinkingLevel: "minimal" } },
vertex: { thinkingConfig: { thinkingLevel: "minimal" } },
openai: { reasoningEffort: "none" },
};
}
Expand All @@ -129,10 +129,11 @@ function getWorkspaceAiReasoningOptions(
thinkingConfig: { thinkingLevel: "low" },
},
};
case "gpt-terra":
case "gpt-sol":
return {
openai: {
reasoningEffort: "none",
// Sol 6.1 requires reasoning; low is its minimum supported effort.
reasoningEffort: "low",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

This model/provider behavior change has no regression assertions. Add tests that verify the gpt-sol reasoning option and title model's minimal thinking configuration.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/features/workspaces/ai/gateway.ts, line 136:

<comment>This model/provider behavior change has no regression assertions. Add tests that verify the `gpt-sol` reasoning option and title model's `minimal` thinking configuration.</comment>

<file context>
@@ -129,10 +129,11 @@ function getWorkspaceAiReasoningOptions(
 				openai: {
-					reasoningEffort: "none",
+					// Sol 6.1 requires reasoning; low is its minimum supported effort.
+					reasoningEffort: "low",
 				},
 			};
</file context>

},
};
default:
Expand Down
39 changes: 20 additions & 19 deletions src/features/workspaces/ai/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export type WorkspaceAiChatModelBillingTier = "standard" | "premium";
// across input, cached input, and output rather than output alone — output
// price by itself understates the models we send the most tokens to.
//
// Measured 1.0x / 2.5x / 4.7x / 9.5x / 10x, rounded to a clean ladder so these
// Standard-rate estimates: Luna 1x, Flash 7.5x, Haiku 10x, Sol 18.9x,
// Sonnet 20x, and Pro 21.2x, rounded to whole multipliers so these
// double as credit weights if usage is ever metered. Re-derive from the gateway
// catalog when the lineup changes; a stale multiplier misprices the plan.
//
Expand All @@ -38,7 +39,7 @@ export const WORKSPACE_AI_CHAT_MODELS = [
name: "Auto",
// Keep this a stable product choice while the server owns its availability
// policy and fallback chain.
gatewayModel: "openai/gpt-5.6-luna",
gatewayModel: "openai/gpt-6-luna",
provider: "auto",
tagline: "Fast and capable by default",
description:
Expand All @@ -48,20 +49,20 @@ export const WORKSPACE_AI_CHAT_MODELS = [
speed: 3,
cost: 1,
billingTier: "standard",
contextWindow: 1_000_000,
contextWindow: 1_050_000,
},
{
id: "claude-sonnet",
name: "Claude Sonnet 5",
gatewayModel: "anthropic/claude-sonnet-5",
name: "Claude Sonnet 5.5",
gatewayModel: "anthropic/claude-sonnet-5.5",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

Add a regression test for the changed claude-sonnet mapping. The observability fixture uses the new slug, but no test verifies that getWorkspaceAiChatModel("claude-sonnet") returns "anthropic/claude-sonnet-5.5".

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/features/workspaces/ai/models.ts, line 56:

<comment>Add a regression test for the changed `claude-sonnet` mapping. The observability fixture uses the new slug, but no test verifies that `getWorkspaceAiChatModel("claude-sonnet")` returns `"anthropic/claude-sonnet-5.5"`.</comment>

<file context>
@@ -52,8 +52,8 @@ export const WORKSPACE_AI_CHAT_MODELS = [
-		name: "Claude Sonnet 5",
-		gatewayModel: "anthropic/claude-sonnet-5",
+		name: "Claude Sonnet 5.5",
+		gatewayModel: "anthropic/claude-sonnet-5.5",
 		provider: "anthropic",
 		tagline: "Thoughtful and polished",
</file context>

provider: "anthropic",
tagline: "Thoughtful and polished",
description:
"A strong all-around model that is especially good at writing, careful thinking, and polished answers.",
bestFor: "Writing, analysis & coding",
intelligence: 4,
speed: 3,
cost: 10,
cost: 20,
billingTier: "premium",
contextWindow: 1_000_000,
},
Expand All @@ -75,29 +76,29 @@ export const WORKSPACE_AI_CHAT_MODELS = [
bestFor: "Quick help & short drafts",
intelligence: 2,
speed: 4,
cost: 5,
cost: 10,
billingTier: "standard",
contextWindow: 200_000,
},
{
id: "gpt-terra",
name: "GPT-5.6 Terra",
gatewayModel: "openai/gpt-5.6-terra",
id: "gpt-sol",
name: "GPT-6.1 Sol",
gatewayModel: "openai/gpt-6.1-sol",
provider: "openai",
tagline: "Strong on harder tasks",
description:
"A capable model for more involved tasks like planning, research, problem-solving, and detailed help.",
bestFor: "Planning, research & knowledge work",
intelligence: 4,
speed: 3,
cost: 10,
cost: 19,
billingTier: "premium",
contextWindow: 1_000_000,
contextWindow: 1_050_000,
},
{
id: "gpt-luna",
name: "GPT-5.6 Luna",
gatewayModel: "openai/gpt-5.6-luna",
name: "GPT-6 Luna",
gatewayModel: "openai/gpt-6-luna",
provider: "openai",
tagline: "Quick and capable",
description: "A faster GPT for quick help, everyday questions, and practical tasks.",
Expand All @@ -106,7 +107,7 @@ export const WORKSPACE_AI_CHAT_MODELS = [
speed: 4,
cost: 1,
billingTier: "standard",
contextWindow: 1_000_000,
contextWindow: 1_050_000,
},
{
id: "gemini-pro",
Expand All @@ -119,22 +120,22 @@ export const WORKSPACE_AI_CHAT_MODELS = [
bestFor: "Long docs, research & hard problems",
intelligence: 4,
speed: 2,
cost: 10,
cost: 21,
billingTier: "premium",
contextWindow: 1_000_000,
},
{
id: "gemini",
name: "Gemini 3 Flash",
gatewayModel: "google/gemini-3-flash",
name: "Gemini 3.8 Flash",
gatewayModel: "google/gemini-3.8-flash",
provider: "google",
tagline: "Fast and wide-ranging",
description:
"A fast Gemini that works well for quick answers, everyday use, and reading lots of context.",
bestFor: "Fast answers & big context",
intelligence: 3,
speed: 4,
cost: 3,
cost: 8,
billingTier: "standard",
contextWindow: 1_000_000,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {
MarkdownExtractionResult,
} from "#/features/workspaces/extraction/types";

const IMAGE_EXTRACTION_GATEWAY_MODEL = "google/gemini-2.5-flash";
const IMAGE_EXTRACTION_GATEWAY_MODEL = "google/gemini-3.8-flash";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

This model and thinking-config change alters the image-extraction request, but no test exercises createGeminiImageMarkdownProvider or asserts those fields. Add a focused regression test that mocks generateText and verifies the model and provider options.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/features/workspaces/extraction/providers/gemini-image-markdown.ts, line 16:

<comment>This model and thinking-config change alters the image-extraction request, but no test exercises `createGeminiImageMarkdownProvider` or asserts those fields. Add a focused regression test that mocks `generateText` and verifies the model and provider options.</comment>

<file context>
@@ -13,7 +13,7 @@ import type {
 } from "#/features/workspaces/extraction/types";
 
-const IMAGE_EXTRACTION_GATEWAY_MODEL = "google/gemini-2.5-flash";
+const IMAGE_EXTRACTION_GATEWAY_MODEL = "google/gemini-3.8-flash";
 const jpegMediaType = "image/jpeg";
 
</file context>

const jpegMediaType = "image/jpeg";

// Transcription, not interpretation: the markdown feeds search and chat context,
Expand Down Expand Up @@ -50,14 +50,12 @@ export function createGeminiImageMarkdownProvider(env: Env): MarkdownExtractionP
`model:${IMAGE_EXTRACTION_GATEWAY_MODEL}`,
],
},
// The 2.5-series rejects `thinkingLevel` outright, which 400s every
// Google leg; budget is its knob. Reading what is on the page needs
// no reasoning, and the fallbacks bill for it if it is left on.
// Minimize reasoning for transcription and its fallback models.
google: {
thinkingConfig: { thinkingBudget: 0 },
thinkingConfig: { thinkingLevel: "low" },
},
vertex: {
thinkingConfig: { thinkingBudget: 0 },
thinkingConfig: { thinkingLevel: "low" },
},
openai: {
reasoningEffort: "none",
Expand Down
4 changes: 2 additions & 2 deletions src/integrations/autumn/workspace-ai-access.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("resolveWorkspaceAiMessageAccess", () => {
});

it("falls back to auto when premium is spent but standard remains", () => {
for (const chosenModelId of ["claude-sonnet", "gpt-terra", "gemini-pro"] as const) {
for (const chosenModelId of ["claude-sonnet", "gpt-sol", "gemini-pro"] as const) {
expect(
resolveWorkspaceAiMessageAccess({
chosenModelId,
Expand Down Expand Up @@ -99,7 +99,7 @@ describe("resolveWorkspaceAiMessageAccess", () => {
// quietly becoming the priciest model in the tier it lands on.
describe("fallback pricing", () => {
it("lands on the cheapest model in the tier it falls back to", () => {
for (const chosenModelId of ["claude-sonnet", "gpt-terra", "gemini-pro"] as const) {
for (const chosenModelId of ["claude-sonnet", "gpt-sol", "gemini-pro"] as const) {
const access = resolveWorkspaceAiMessageAccess({
chosenModelId,
chosenTierAllowed: false,
Expand Down
2 changes: 1 addition & 1 deletion src/integrations/posthog/ai-observability.worker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ describe("getGatewayServedRoute", () => {
routing: {
finalProvider: "openai",
modelAttempts: [
{ canonicalSlug: "anthropic/claude-sonnet-5", success: false, providerAttempts: [] },
{ canonicalSlug: "anthropic/claude-sonnet-5.5", success: false, providerAttempts: [] },
{
canonicalSlug: "openai/gpt-5.6-terra",
success: true,
Expand Down
Loading