mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add Explore mode as subagent-only modality (#24448)
> This PR was authored by Mux on behalf of Mike. Introduce Explore mode, a read-only subagent modality for delegated discovery and code investigation. ## What Adds a `spawn_explore_agent` tool that creates child chats restricted to read-only operations. An admin can optionally configure a deployment-wide model override so Explore subagents use a model optimized for large context or reasoning without changing the root chat's model. ### Backend - New `ChatModeExplore` enum value (migration 000471). - `spawn_explore_agent` tool definition with read-only allowlist: `read_file`, `execute`, `process_output`, `read_skill`, `read_skill_file`. Write tools, file editors, and nested subagent spawning are blocked. - Deployment config storage for the Explore model override (`agents_chat_explore_model_override` in `site_configs`). - Model resolution hierarchy: configured override, then current turn model, then global default. Silent fallback with warning log when the override becomes unavailable. - RBAC: `AsChatd` for daemon reads, `ActionRead` and `ActionUpdate` on `ResourceDeploymentConfig` for admin API calls. - Plan mode root chats can use `spawn_explore_agent` for read-only research, matching the planning prompt guidance. - The Explore override config API now reports malformed saved overrides as "treated as unset" so admins can clear them explicitly. ### Frontend - `ExploreModelOverrideSettings` component in admin agent behavior settings. Uses `ModelSelector`, handles unavailable model warnings, and supports explicit Save and Clear actions. - Malformed saved overrides show a warning and require an explicit Save to clear, instead of Clear auto-submitting behind the scenes. ### Tests - Integration: `TestExploreSubagentIsReadOnly` (full spawn flow, tool verification, prompt overlay, DB state). - Unit: tool allowlist tests for explore, plan, and default modes. - Internal: model override resolution with valid, invalid UUID, disabled, and unconfigured override scenarios. - RBAC: `dbauthz_test.go` for `GetChatExploreModelOverride` and `UpsertChatExploreModelOverride`. - API: admin set and clear, malformed stored override reporting, disabled model rejection, non-admin denial.
This commit is contained in:
@@ -3276,6 +3276,24 @@ class ExperimentalApiMethods {
|
||||
);
|
||||
};
|
||||
|
||||
getChatExploreModelOverride =
|
||||
async (): Promise<TypesGen.ChatExploreModelOverrideResponse> => {
|
||||
const response =
|
||||
await this.axios.get<TypesGen.ChatExploreModelOverrideResponse>(
|
||||
"/api/experimental/chats/config/explore-model-override",
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
updateChatExploreModelOverride = async (
|
||||
req: TypesGen.UpdateChatExploreModelOverrideRequest,
|
||||
): Promise<void> => {
|
||||
await this.axios.put(
|
||||
"/api/experimental/chats/config/explore-model-override",
|
||||
req,
|
||||
);
|
||||
};
|
||||
|
||||
getChatDesktopEnabled =
|
||||
async (): Promise<TypesGen.ChatDesktopEnabledResponse> => {
|
||||
const response =
|
||||
|
||||
@@ -922,6 +922,23 @@ export const updateChatPlanModeInstructions = (queryClient: QueryClient) => ({
|
||||
},
|
||||
});
|
||||
|
||||
const chatExploreModelOverrideKey = ["chat-explore-model-override"] as const;
|
||||
|
||||
export const chatExploreModelOverride = () => ({
|
||||
queryKey: chatExploreModelOverrideKey,
|
||||
queryFn: () => API.experimental.getChatExploreModelOverride(),
|
||||
});
|
||||
|
||||
export const updateChatExploreModelOverride = (queryClient: QueryClient) => ({
|
||||
mutationFn: (req: TypesGen.UpdateChatExploreModelOverrideRequest) =>
|
||||
API.experimental.updateChatExploreModelOverride(req),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: chatExploreModelOverrideKey,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const chatDesktopEnabledKey = ["chat-desktop-enabled"] as const;
|
||||
|
||||
export const chatDesktopEnabled = () => ({
|
||||
|
||||
Generated
+23
@@ -1582,6 +1582,20 @@ export interface ChatDiffStatus {
|
||||
readonly stale_at?: string;
|
||||
}
|
||||
|
||||
// From codersdk/chats.go
|
||||
/**
|
||||
* ChatExploreModelOverrideResponse is the response body for the Explore
|
||||
* subagent model override configuration endpoint.
|
||||
*/
|
||||
export interface ChatExploreModelOverrideResponse {
|
||||
readonly model_config_id?: string;
|
||||
/**
|
||||
* HasMalformedOverride reports whether the saved override is malformed and
|
||||
* is currently being treated as unset.
|
||||
*/
|
||||
readonly has_malformed_override: boolean;
|
||||
}
|
||||
|
||||
// From codersdk/chats.go
|
||||
/**
|
||||
* ChatFileMetadata contains lightweight metadata about a file
|
||||
@@ -7581,6 +7595,15 @@ export interface UpdateChatDesktopEnabledRequest {
|
||||
readonly enable_desktop: boolean;
|
||||
}
|
||||
|
||||
// From codersdk/chats.go
|
||||
/**
|
||||
* UpdateChatExploreModelOverrideRequest is the request body for updating the
|
||||
* Explore subagent model override configuration endpoint.
|
||||
*/
|
||||
export interface UpdateChatExploreModelOverrideRequest {
|
||||
readonly model_config_id?: string;
|
||||
}
|
||||
|
||||
// From codersdk/chats.go
|
||||
/**
|
||||
* UpdateChatModelConfigRequest updates a chat model config.
|
||||
|
||||
Reference in New Issue
Block a user