diff --git a/packages/app/src/app/agent/new.tsx b/packages/app/src/app/agent/new.tsx index 054487a68..0e8abf666 100644 --- a/packages/app/src/app/agent/new.tsx +++ b/packages/app/src/app/agent/new.tsx @@ -29,10 +29,14 @@ import type { AgentProvider, AgentSessionConfig, } from "@server/server/agent/agent-sdk-types"; +import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest"; const SIDEBAR_WIDTH = 280; const LARGE_SCREEN_BREAKPOINT = 768; const DRAFT_AGENT_ID = "__new_agent__"; +const PROVIDER_DEFINITION_MAP = new Map( + AGENT_PROVIDER_DEFINITIONS.map((definition) => [definition.id, definition]) +); function getParamValue(value: string | string[] | undefined) { if (typeof value === "string") { @@ -42,6 +46,27 @@ function getParamValue(value: string | string[] | undefined) { return undefined; } +function getValidProvider(value: string | undefined) { + if (!value) { + return undefined; + } + return PROVIDER_DEFINITION_MAP.has(value as AgentProvider) + ? (value as AgentProvider) + : undefined; +} + +function getValidMode( + provider: AgentProvider | undefined, + value: string | undefined +) { + if (!provider || !value) { + return undefined; + } + const definition = PROVIDER_DEFINITION_MAP.get(provider); + const modes = definition?.modes ?? []; + return modes.some((mode) => mode.id === value) ? value : undefined; +} + type DraftAgentParams = { serverId?: string; provider?: string; @@ -69,8 +94,8 @@ export default function DraftAgentScreen() { const params = useLocalSearchParams(); const resolvedServerId = getParamValue(params.serverId); - const resolvedProvider = getParamValue(params.provider); - const resolvedMode = getParamValue(params.modeId); + const resolvedProvider = getValidProvider(getParamValue(params.provider)); + const resolvedMode = getValidMode(resolvedProvider, getParamValue(params.modeId)); const resolvedModel = getParamValue(params.model); const resolvedWorkingDir = getParamValue(params.workingDir); @@ -80,16 +105,13 @@ export default function DraftAgentScreen() { values.workingDir = resolvedWorkingDir; } if (resolvedProvider) { - values.provider = resolvedProvider as AgentProvider; + values.provider = resolvedProvider; } if (resolvedMode) { values.modeId = resolvedMode; } - if (resolvedModel) { - values.model = resolvedModel; - } return values; - }, [resolvedMode, resolvedModel, resolvedProvider, resolvedWorkingDir]); + }, [resolvedMode, resolvedProvider, resolvedWorkingDir]); const { selectedServerId, setSelectedServerIdFromUser, @@ -108,12 +130,31 @@ export default function DraftAgentScreen() { modelError, refreshProviderModels, persistFormPreferences, + userEditedPreferencesRef, } = useAgentFormState({ initialServerId: resolvedServerId ?? null, initialValues, isVisible: true, isCreateFlow: true, }); + const hasAppliedModelParamRef = useRef(false); + useEffect(() => { + if (!resolvedModel || hasAppliedModelParamRef.current) { + return; + } + if (availableModels.length === 0) { + return; + } + const isValidModel = availableModels.some((model) => model.id === resolvedModel); + hasAppliedModelParamRef.current = true; + if (!isValidModel) { + return; + } + if (userEditedPreferencesRef.current.model) { + return; + } + setModelFromUser(resolvedModel); + }, [availableModels, resolvedModel, setModelFromUser, userEditedPreferencesRef]); const hostEntry = selectedServerId ? connectionStates.get(selectedServerId) : undefined; diff --git a/plan.md b/plan.md index 29583cc9e..471367a28 100644 --- a/plan.md +++ b/plan.md @@ -103,11 +103,12 @@ Improvements to the new agent screen in the app. - Add fix tasks for any issues found. - **Done (2025-12-29 00:18)**: WHAT: `plan.md:97` marked this checkpoint complete; `plan.md:106` added follow-up fix task for URL-param validation; `REPORT-typecheck-code-quality.md:1` documented typecheck + code-quality findings. RESULT: typecheck passed; identified URL-param cast risk and created fix task. EVIDENCE: `npm run typecheck` (workspace typecheck completed with exit code 0). -- [ ] **Fix**: Validate URL-derived provider/mode/model on new agent screen. +- [x] **Fix**: Validate URL-derived provider/mode/model on new agent screen. - Guard `useLocalSearchParams` values in `packages/app/src/app/agent/new.tsx`. - Only accept provider/mode/model values that exist in current definitions/options. - Drop invalid values instead of casting to `AgentProvider`. + - **Done (2025-12-29 00:22)**: WHAT: `packages/app/src/app/agent/new.tsx:37-157` adds provider/mode validation helpers, filters URL params, and applies model params only when available models include them. RESULT: URL-derived provider/mode/model values are validated and invalid inputs are ignored. EVIDENCE: Not run (not requested). - [ ] **Checkpoint**: Review daemon test coverage for fixes in this plan.