Allow ACP providers without model lists

This commit is contained in:
Mohamed Boudra
2026-05-19 20:01:56 +07:00
parent f238cbc20c
commit bc7798af28
8 changed files with 353 additions and 80 deletions
@@ -0,0 +1,51 @@
export interface WorkspaceDraftAutoSubmitConfig {
provider: string;
model: string | null;
}
export function validateDraftSubmission(input: {
text: string;
allowsEmptyAutoSubmit: boolean;
composerState: {
providerDefinitions: unknown[];
selectedProvider: string | null;
isModelLoading: boolean;
effectiveModelId: string | null;
availableModels: unknown[];
};
autoSubmitConfig: WorkspaceDraftAutoSubmitConfig | null;
workspaceDirectory: string | null;
hasClient: boolean;
}): string | null {
const {
text,
allowsEmptyAutoSubmit,
composerState,
autoSubmitConfig,
workspaceDirectory,
hasClient,
} = input;
if (!allowsEmptyAutoSubmit && !text.trim()) {
return "Initial prompt is required";
}
if (composerState.providerDefinitions.length === 0) {
return "No available providers on the selected host";
}
if (!(autoSubmitConfig?.provider ?? composerState.selectedProvider)) {
return "Select a model";
}
if (composerState.isModelLoading) {
return "Model defaults are still loading";
}
const hasSelectedModel = Boolean(autoSubmitConfig?.model ?? composerState.effectiveModelId);
if (!hasSelectedModel && composerState.availableModels.length > 0) {
return "No model is available for the selected provider";
}
if (!workspaceDirectory) {
return "Workspace directory not found";
}
if (!hasClient) {
return "Host is not connected";
}
return null;
}
@@ -0,0 +1,51 @@
import { describe, expect, test } from "vitest";
import { validateDraftSubmission } from "./workspace-draft-agent-tab-core";
const baseComposerState = {
providerDefinitions: [{ id: "deepseek-tui" }],
selectedProvider: "deepseek-tui",
isModelLoading: false,
effectiveModelId: "",
availableModels: [],
};
function validate(overrides = {}) {
return validateDraftSubmission({
text: "hello",
allowsEmptyAutoSubmit: false,
composerState: baseComposerState,
autoSubmitConfig: null,
workspaceDirectory: "/tmp/project",
hasClient: true,
...overrides,
});
}
describe("workspace draft agent model validation", () => {
test("allows a ready provider with no models to submit without a selected model", () => {
expect(validate({})).toBeNull();
});
test("keeps waiting while model defaults are loading", () => {
expect(
validate({
composerState: {
...baseComposerState,
isModelLoading: true,
},
}),
).toBe("Model defaults are still loading");
});
test("still requires a selected model when the provider exposes models", () => {
expect(
validate({
composerState: {
...baseComposerState,
availableModels: [{ id: "deepseek/deepseek-v4-pro" }],
},
}),
).toBe("No model is available for the selected provider");
});
});
@@ -22,6 +22,7 @@ import { useWorkspaceDraftSubmissionStore } from "@/stores/workspace-draft-submi
import { encodeImages } from "@/utils/encode-images";
import type { WorkspaceFileOpenRequest } from "@/workspace/file-open";
import { shouldAutoFocusWorkspaceDraftComposer } from "@/screens/workspace/workspace-draft-pane-focus";
import { validateDraftSubmission } from "@/screens/workspace/workspace-draft-agent-tab-core";
import type { AgentCapabilityFlags } from "@server/server/agent/agent-sdk-types";
import type { AgentSnapshotPayload } from "@server/shared/messages";
import type { DaemonClient } from "@server/client/daemon-client";
@@ -73,51 +74,6 @@ function resolveAutoSubmitConfig(
};
}
function validateDraftSubmission(input: {
text: string;
allowsEmptyAutoSubmit: boolean;
composerState: {
providerDefinitions: unknown[];
selectedProvider: string | null;
isModelLoading: boolean;
effectiveModelId: string | null;
};
autoSubmitConfig: AutoSubmitConfig | null;
workspaceDirectory: string | null;
hasClient: boolean;
}): string | null {
const {
text,
allowsEmptyAutoSubmit,
composerState,
autoSubmitConfig,
workspaceDirectory,
hasClient,
} = input;
if (!allowsEmptyAutoSubmit && !text.trim()) {
return "Initial prompt is required";
}
if (composerState.providerDefinitions.length === 0) {
return "No available providers on the selected host";
}
if (!(autoSubmitConfig?.provider ?? composerState.selectedProvider)) {
return "Select a model";
}
if (composerState.isModelLoading) {
return "Model defaults are still loading";
}
if (!(autoSubmitConfig?.model ?? composerState.effectiveModelId)) {
return "No model is available for the selected provider";
}
if (!workspaceDirectory) {
return "Workspace directory not found";
}
if (!hasClient) {
return "Host is not connected";
}
return null;
}
function resolveDraftModeIdOverride(input: {
autoSubmitConfig: AutoSubmitConfig | null;
modeOptionsCount: number;