Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion apps/server/src/git/Layers/ClaudeTextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Effect, Layer, Option, Schema, Stream } from "effect";
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";

import { ClaudeModelSelection } from "@t3tools/contracts";
import { resolveApiModelId } from "@t3tools/shared/model";
import { sanitizeBranchFragment, sanitizeFeatureBranchName } from "@t3tools/shared/git";

import { TextGenerationError } from "../Errors.ts";
Expand Down Expand Up @@ -103,7 +104,7 @@ const makeClaudeTextGeneration = Effect.gen(function* () {
"--json-schema",
jsonSchemaStr,
"--model",
modelSelection.model,
resolveApiModelId(modelSelection),
Comment thread
cursor[bot] marked this conversation as resolved.
...(normalizedOptions?.effort ? ["--effort", normalizedOptions.effort] : []),
...(Object.keys(settings).length > 0 ? ["--settings", JSON.stringify(settings)] : []),
"--dangerously-skip-permissions",
Expand Down
15 changes: 11 additions & 4 deletions apps/server/src/provider/Layers/ClaudeAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ import {
type UserInputQuestion,
ClaudeCodeEffort,
} from "@t3tools/contracts";
import { hasEffortLevel, applyClaudePromptEffortPrefix, trimOrNull } from "@t3tools/shared/model";
import {
hasEffortLevel,
applyClaudePromptEffortPrefix,
resolveApiModelId,
trimOrNull,
} from "@t3tools/shared/model";
import {
Cause,
DateTime,
Expand Down Expand Up @@ -2727,6 +2732,7 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) {
const claudeBinaryPath = claudeSettings.binaryPath;
const modelSelection =
input.modelSelection?.provider === "claudeAgent" ? input.modelSelection : undefined;
const apiModelId = modelSelection ? resolveApiModelId(modelSelection) : undefined;
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
const requestedEffort = trimOrNull(modelSelection?.options?.effort ?? null);
const caps = getClaudeModelCapabilities(modelSelection?.model);
const effort =
Expand All @@ -2746,7 +2752,7 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) {

const queryOptions: ClaudeQueryOptions = {
...(input.cwd ? { cwd: input.cwd } : {}),
...(modelSelection?.model ? { model: modelSelection.model } : {}),
...(apiModelId ? { model: apiModelId } : {}),
pathToClaudeCodeExecutable: claudeBinaryPath,
settingSources: [...CLAUDE_SETTING_SOURCES],
...(effectiveEffort ? { effort: effectiveEffort } : {}),
Expand Down Expand Up @@ -2840,7 +2846,7 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) {
threadId,
payload: {
config: {
...(modelSelection?.model ? { model: modelSelection.model } : {}),
...(apiModelId ? { model: apiModelId } : {}),
...(input.cwd ? { cwd: input.cwd } : {}),
...(effectiveEffort ? { effort: effectiveEffort } : {}),
...(permissionMode ? { permissionMode } : {}),
Expand Down Expand Up @@ -2893,8 +2899,9 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) {
}

if (modelSelection?.model) {
const apiModelId = resolveApiModelId(modelSelection);
yield* Effect.tryPromise({
try: () => context.query.setModel(modelSelection.model),
try: () => context.query.setModel(apiModelId),
catch: (cause) => toRequestError(input.threadId, "turn/setModel", cause),
});
}
Expand Down
10 changes: 10 additions & 0 deletions apps/server/src/provider/Layers/ClaudeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [
{ value: "200k", label: "200k", isDefault: true },
{ value: "1m", label: "1M" },
],
Comment thread
cursor[bot] marked this conversation as resolved.
promptInjectedEffortLevels: ["ultrathink"],
} satisfies ModelCapabilities,
},
Expand All @@ -58,6 +62,10 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [
{ value: "200k", label: "200k", isDefault: true },
{ value: "1m", label: "1M" },
],
promptInjectedEffortLevels: ["ultrathink"],
} satisfies ModelCapabilities,
},
Expand All @@ -69,6 +77,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
reasoningEffortLevels: [],
supportsFastMode: false,
supportsThinkingToggle: true,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
} satisfies ModelCapabilities,
},
Expand All @@ -81,6 +90,7 @@ export function getClaudeModelCapabilities(model: string | null | undefined): Mo
reasoningEffortLevels: [],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
}
);
Expand Down
7 changes: 7 additions & 0 deletions apps/server/src/provider/Layers/CodexProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -64,6 +65,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -80,6 +82,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -96,6 +99,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -112,6 +116,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -128,6 +133,7 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -140,6 +146,7 @@ export function getCodexModelCapabilities(model: string | null | undefined): Mod
reasoningEffortLevels: [],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ async function mountMenu(props?: { modelSelection?: ModelSelection; prompt?: str
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: ["ultrathink"],
},
},
Expand All @@ -71,6 +72,7 @@ async function mountMenu(props?: { modelSelection?: ModelSelection; prompt?: str
reasoningEffortLevels: [],
supportsFastMode: false,
supportsThinkingToggle: true,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -87,6 +89,7 @@ async function mountMenu(props?: { modelSelection?: ModelSelection; prompt?: str
],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: ["ultrathink"],
},
},
Expand All @@ -103,6 +106,7 @@ async function mountMenu(props?: { modelSelection?: ModelSelection; prompt?: str
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/components/chat/ProviderModelPicker.browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
reasoningEffortLevels: [effort("low"), effort("medium", true), effort("high")],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -44,6 +45,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
reasoningEffortLevels: [effort("low"), effort("medium", true), effort("high")],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand Down Expand Up @@ -71,6 +73,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
],
supportsFastMode: false,
supportsThinkingToggle: true,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -87,6 +90,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
],
supportsFastMode: false,
supportsThinkingToggle: true,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand All @@ -98,6 +102,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
reasoningEffortLevels: [effort("low"), effort("medium", true), effort("high")],
supportsFastMode: false,
supportsThinkingToggle: true,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/components/chat/TraitsPicker.browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand Down Expand Up @@ -77,6 +78,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
Comment thread
juliusmarminge marked this conversation as resolved.
promptInjectedEffortLevels: ["ultrathink"],
},
},
Expand All @@ -93,6 +95,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: ["ultrathink"],
},
},
Expand All @@ -104,6 +107,7 @@ const TEST_PROVIDERS: ReadonlyArray<ServerProvider> = [
reasoningEffortLevels: [],
supportsFastMode: false,
supportsThinkingToggle: true,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
},
},
Expand Down
62 changes: 62 additions & 0 deletions apps/web/src/components/chat/TraitsPicker.tsx
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
isClaudeUltrathinkPrompt,
trimOrNull,
getDefaultEffort,
getDefaultContextWindow,
hasEffortLevel,
hasContextWindowOption,
} from "@t3tools/shared/model";
import { memo, useCallback, useState } from "react";
import type { VariantProps } from "class-variance-authority";
Expand Down Expand Up @@ -53,6 +55,16 @@ function getRawEffort(
return trimOrNull((modelOptions as ClaudeModelOptions | undefined)?.effort);
}

function getRawContextWindow(
provider: ProviderKind,
modelOptions: ProviderOptions | null | undefined,
): string | null {
if (provider === "claudeAgent") {
return trimOrNull((modelOptions as ClaudeModelOptions | undefined)?.contextWindow);
}
return null;
}

function buildNextOptions(
provider: ProviderKind,
modelOptions: ProviderOptions | null | undefined,
Expand Down Expand Up @@ -104,6 +116,15 @@ function getSelectedTraits(
caps.supportsFastMode &&
(modelOptions as { fastMode?: boolean } | undefined)?.fastMode === true;

// Context window
const contextWindowOptions = caps.contextWindowOptions;
const rawContextWindow = getRawContextWindow(provider, modelOptions);
const defaultContextWindow = getDefaultContextWindow(caps);
const contextWindow =
rawContextWindow && hasContextWindowOption(caps, rawContextWindow)
? rawContextWindow
: defaultContextWindow;

// Prompt-controlled effort (e.g. ultrathink in prompt text)
const ultrathinkPromptControlled =
allowPromptInjectedEffort &&
Expand All @@ -116,6 +137,9 @@ function getSelectedTraits(
effortLevels,
thinkingEnabled,
fastModeEnabled,
contextWindowOptions,
contextWindow,
defaultContextWindow,
ultrathinkPromptControlled,
};
}
Expand Down Expand Up @@ -159,6 +183,9 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({
effortLevels,
thinkingEnabled,
fastModeEnabled,
contextWindowOptions,
contextWindow,
defaultContextWindow,
Comment thread
cursor[bot] marked this conversation as resolved.
ultrathinkPromptControlled,
} = getSelectedTraits(provider, models, model, prompt, modelOptions, allowPromptInjectedEffort);
const defaultEffort = getDefaultEffort(caps);
Expand Down Expand Up @@ -258,6 +285,33 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({
</MenuGroup>
</>
) : null}
{contextWindowOptions.length > 1 ? (
<>
<MenuDivider />
<MenuGroup>
<div className="px-2 py-1.5 font-medium text-muted-foreground text-xs">
Context Window
</div>
<MenuRadioGroup
value={contextWindow ?? defaultContextWindow ?? ""}
onValueChange={(value) => {
updateModelOptions(
buildNextOptions(provider, modelOptions, {
contextWindow: value === defaultContextWindow ? undefined : value,
}),
);
}}
>
{contextWindowOptions.map((option) => (
<MenuRadioItem key={option.value} value={option.value}>
{option.label}
{option.value === defaultContextWindow ? " (default)" : ""}
</MenuRadioItem>
))}
</MenuRadioGroup>
</MenuGroup>
</>
) : null}
</>
);
});
Expand All @@ -281,12 +335,19 @@ export const TraitsPicker = memo(function TraitsPicker({
effortLevels,
thinkingEnabled,
fastModeEnabled,
contextWindowOptions,
contextWindow,
defaultContextWindow,
ultrathinkPromptControlled,
} = getSelectedTraits(provider, models, model, prompt, modelOptions, allowPromptInjectedEffort);

const effortLabel = effort
? (effortLevels.find((l) => l.value === effort)?.label ?? effort)
: null;
const contextWindowLabel =
contextWindowOptions.length > 1 && contextWindow !== defaultContextWindow
? (contextWindowOptions.find((o) => o.value === contextWindow)?.label ?? null)
: null;
const triggerLabel = [
ultrathinkPromptControlled
? "Ultrathink"
Expand All @@ -296,6 +357,7 @@ export const TraitsPicker = memo(function TraitsPicker({
? null
: `Thinking ${thinkingEnabled ? "On" : "Off"}`,
...(caps.supportsFastMode && fastModeEnabled ? ["Fast"] : []),
...(contextWindowLabel ? [contextWindowLabel] : []),
]
.filter(Boolean)
.join(" · ");
Expand Down
Loading
Loading