Merge pull request #14 from eigent-ai/feat/remote-sub-agent

move default value
This commit is contained in:
Tong Chen 2026-05-19 19:39:34 +08:00 committed by GitHub
commit 027d6f57df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 190 additions and 51 deletions

View file

@ -31,7 +31,7 @@ from app.remote_sub_agent.types import (
logger = logging.getLogger(__name__)
_DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta"
_DEFAULT_AGENT = "waverunner"
_DEFAULT_AGENT = ""
_TERMINAL_SUCCESS_STATUSES = {"completed"}
_TERMINAL_FAILURE_STATUSES = {"failed", "cancelled", "expired", "incomplete"}
_UNSUPPORTED_ACTION_STATUSES = {"requires_action"}

View file

@ -29,7 +29,7 @@ async def test_validate_remote_sub_agent_rejects_missing_fields():
provider="gemini_agents",
api_key="",
base_url="https://example.test/v1beta",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
)
)
@ -61,7 +61,7 @@ async def test_validate_remote_sub_agent_success(monkeypatch):
provider="gemini_agents",
api_key=" test-key ",
base_url=" https://example.test/v1beta ",
agent_name=" waverunner ",
agent_name=" antigravity-preview-05-2026 ",
timeout_seconds=12,
)
)
@ -76,7 +76,7 @@ async def test_validate_remote_sub_agent_success(monkeypatch):
"gemini_agents": {
"api_key": "test-key",
"base_url": "https://example.test/v1beta",
"agent_name": "waverunner",
"agent_name": "antigravity-preview-05-2026",
},
}
assert seen["timeout"] == 12
@ -98,7 +98,7 @@ async def test_validate_remote_sub_agent_failure(monkeypatch):
provider="gemini_agents",
api_key="bad-key",
base_url="https://example.test/v1beta",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
)
)

View file

@ -48,7 +48,7 @@ async def test_provider_posts_agent_interaction():
200,
json={
"id": "interaction-1",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"environment_id": "env-1",
"status": "completed",
"outputs": [{"type": "text", "text": "done"}],
@ -58,7 +58,7 @@ async def test_provider_posts_agent_interaction():
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
transport=httpx.MockTransport(handler),
)
@ -77,7 +77,7 @@ async def test_provider_posts_agent_interaction():
body = seen["body"]
assert isinstance(body, dict)
assert body["agent"] == "waverunner"
assert body["agent"] == "antigravity-preview-05-2026"
assert body["input"] == [{"type": "text", "text": "research this"}]
assert body["stream"] is False
assert body["environment"] == {"enabled": True}
@ -102,7 +102,7 @@ async def test_provider_validation_posts_background_probe():
200,
json={
"id": "interaction-validation",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"environment_id": "env-validation",
"status": "in_progress",
},
@ -110,7 +110,7 @@ async def test_provider_validation_posts_background_probe():
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
transport=httpx.MockTransport(handler),
)
@ -119,7 +119,7 @@ async def test_provider_validation_posts_background_probe():
body = seen["body"]
assert isinstance(body, dict)
assert body["agent"] == "waverunner"
assert body["agent"] == "antigravity-preview-05-2026"
assert body["stream"] is False
assert body["background"] is True
assert body["environment"] == {"enabled": True}
@ -148,14 +148,14 @@ async def test_provider_validation_falls_back_without_background():
200,
json={
"id": "interaction-validation",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"status": "completed",
},
)
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
transport=httpx.MockTransport(handler),
)
@ -178,7 +178,7 @@ async def test_provider_uses_configured_agent_over_display_name():
200,
json={
"id": "interaction-1",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"status": "completed",
"outputs": [{"type": "text", "text": "done"}],
},
@ -186,7 +186,7 @@ async def test_provider_uses_configured_agent_over_display_name():
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
transport=httpx.MockTransport(handler),
)
@ -205,7 +205,7 @@ async def test_provider_uses_configured_agent_over_display_name():
body = seen["body"]
assert isinstance(body, dict)
assert body["agent"] == "waverunner"
assert body["agent"] == "antigravity-preview-05-2026"
assert events[-1].content == "done"
@ -216,7 +216,7 @@ async def test_provider_concatenates_chunked_outputs_without_extra_newlines():
200,
json={
"id": "interaction-1",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"status": "completed",
"outputs": [
{"type": "text", "text": "sha256sum orders"},
@ -229,7 +229,7 @@ async def test_provider_concatenates_chunked_outputs_without_extra_newlines():
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
transport=httpx.MockTransport(handler),
)
@ -257,7 +257,7 @@ async def test_provider_merges_system_instruction_for_agent():
200,
json={
"id": "interaction-1",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"status": "completed",
"outputs": [{"type": "text", "text": "done"}],
},
@ -265,7 +265,7 @@ async def test_provider_merges_system_instruction_for_agent():
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
transport=httpx.MockTransport(handler),
)
@ -302,7 +302,7 @@ async def test_provider_polls_background_agent_until_completed():
200,
json={
"id": "interaction-1",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"status": "in_progress",
},
)
@ -310,7 +310,7 @@ async def test_provider_polls_background_agent_until_completed():
200,
json={
"id": "interaction-1",
"agent": "waverunner",
"agent": "antigravity-preview-05-2026",
"status": "completed",
"outputs": [{"type": "text", "text": "done"}],
"usage": {"total_tokens": 42},
@ -319,7 +319,7 @@ async def test_provider_polls_background_agent_until_completed():
provider = GeminiAgentsProvider(
api_key="test-key",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
base_url="https://example.test/v1beta",
poll_interval_seconds=0,
transport=httpx.MockTransport(handler),

View file

@ -32,7 +32,7 @@ def _config() -> dict:
"gemini_agents": {
"api_key": "test-key",
"base_url": "https://example.test/v1beta",
"agent_name": "waverunner",
"agent_name": "antigravity-preview-05-2026",
"max_wall_time_seconds": 900,
"poll_interval_seconds": 7,
},
@ -62,7 +62,7 @@ def test_registry_builds_gemini_provider_from_provider_config():
assert provider.name == "gemini_agents"
assert provider.api_key == "test-key"
assert provider.base_url == "https://example.test/v1beta"
assert provider.agent_name == "waverunner"
assert provider.agent_name == "antigravity-preview-05-2026"
assert provider.poll_interval_seconds == 7

View file

@ -31,7 +31,7 @@ def _valid_config() -> dict:
"gemini_agents": {
"api_key": "test-key",
"base_url": "https://generativelanguage.googleapis.com/v1beta",
"agent_name": "waverunner",
"agent_name": "antigravity-preview-05-2026",
"max_wall_time_seconds": 900,
"poll_interval_seconds": 5,
},
@ -58,7 +58,7 @@ async def test_toolkit_returns_message_when_config_is_incomplete():
"gemini_agents": {
"api_key": "",
"base_url": "https://generativelanguage.googleapis.com/v1beta",
"agent_name": "waverunner",
"agent_name": "antigravity-preview-05-2026",
},
},
)

View file

@ -44,15 +44,18 @@ class RemoteSubAgentProviderIn(BaseModel):
config: dict | None = None
@model_validator(mode="after")
def validate_enabled_config(self):
if self.enabled and (
def validate_provider_config(self):
if not self.provider_name.strip():
raise ValueError("Remote sub agent provider requires provider_name.")
if (
not self.api_key.strip()
or not self.endpoint_url.strip()
or not self.agent_name.strip()
):
raise ValueError(
"Enabled remote sub agent provider requires api_key, "
"endpoint_url, and agent_name."
"Remote sub agent provider requires api_key, endpoint_url, "
"and agent_name."
)
return self

View file

@ -21,10 +21,24 @@ from app.model.remote_sub_agent.provider import RemoteSubAgentProviderIn
class TestRemoteSubAgentProviderSchema:
def test_disabled_provider_allows_incomplete_credentials(self):
def test_disabled_provider_requires_credentials(self):
with pytest.raises(ValidationError):
RemoteSubAgentProviderIn(
provider_name="gemini_agents",
enabled=False,
)
def test_disabled_provider_accepts_agent_configuration(self):
config = RemoteSubAgentProviderIn(
provider_name="gemini_agents",
enabled=False,
api_key="test-key",
endpoint_url="https://generativelanguage.googleapis.com/v1beta",
agent_name="antigravity-preview-05-2026",
config={
"max_wall_time_seconds": 900,
"poll_interval_seconds": 5,
},
)
assert config.provider_name == "gemini_agents"
@ -47,7 +61,7 @@ class TestRemoteSubAgentProviderSchema:
enabled=True,
api_key="test-key",
endpoint_url="https://generativelanguage.googleapis.com/v1beta",
agent_name="waverunner",
agent_name="antigravity-preview-05-2026",
config={
"max_wall_time_seconds": 900,
"poll_interval_seconds": 5,

View file

@ -178,6 +178,15 @@
"models-default-setting-title": "الإعداد الافتراضي",
"models-default-setting-description": "اختر أحد النماذج المكوّنة ليكون النموذج الافتراضي لـ Eigent، وسيتم تطبيقه عالميًا عبر مساحة العمل الخاصة بك.",
"models-configuration": "التكوين",
"sub-agents": "الوكلاء الفرعيون",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "فوّض المهام المناسبة إلى صندوق عزل مُدار لوكيل بعيد.",
"agent-provider": "موفّر الوكيل",
"agent-id": "معرّف الوكيل",
"max-wall-time-seconds": "الحد الأقصى لوقت التشغيل (بالثواني)",
"poll-interval-seconds": "فاصل الاستعلام (بالثواني)",
"remote-sub-agent-required-fields": "API Key و API Host و Agent ID مطلوبة عند تفعيل Sub Agent.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -238,6 +238,15 @@
"models-default-setting-title": "Standard-Einstellung",
"models-default-setting-description": "Wähle eines deiner konfigurierten Modelle als Standardmodell für Eigent. Es wird global in deinem Arbeitsbereich angewendet.",
"models-configuration": "Konfiguration",
"sub-agents": "Sub-Agents",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "Delegiere geeignete Aufgaben an eine verwaltete Remote-Agent-Sandbox.",
"agent-provider": "Agent-Anbieter",
"agent-id": "Agent-ID",
"max-wall-time-seconds": "Max. Laufzeit (Sekunden)",
"poll-interval-seconds": "Abfrageintervall (Sekunden)",
"remote-sub-agent-required-fields": "API-Schlüssel, API-Host und Agent-ID sind erforderlich, wenn Sub Agent aktiviert ist.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -209,7 +209,7 @@
"sub-agents": "Sub Agents",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "Delegate suitable tasks to a managed Waverunner-compatible remote agent sandbox.",
"remote-sub-agent-description": "Delegate suitable tasks to a managed remote agent sandbox.",
"agent-provider": "Agent Provider",
"agent-id": "Agent ID",
"max-wall-time-seconds": "Max Wall Time (Seconds)",

View file

@ -238,6 +238,15 @@
"models-default-setting-title": "Configuración predeterminada",
"models-default-setting-description": "Elige uno de tus modelos configurados como modelo predeterminado para Eigent. Se aplicará globalmente en tu espacio de trabajo.",
"models-configuration": "Configuración",
"sub-agents": "Subagentes",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "Delega tareas adecuadas a un sandbox de agente remoto administrado.",
"agent-provider": "Proveedor de agente",
"agent-id": "ID de agente",
"max-wall-time-seconds": "Tiempo máximo de ejecución (segundos)",
"poll-interval-seconds": "Intervalo de sondeo (segundos)",
"remote-sub-agent-required-fields": "API Key, API Host y Agent ID son obligatorios cuando Sub Agent está habilitado.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -221,6 +221,15 @@
"models-default-setting-title": "Paramètre par défaut",
"models-default-setting-description": "Choisissez l'un de vos modèles configurés comme modèle par défaut pour Eigent. Il sera appliqué globalement dans votre espace de travail.",
"models-configuration": "Configuration",
"sub-agents": "Sous-agents",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "Déléguez les tâches adaptées à un bac à sable d'agent distant géré.",
"agent-provider": "Fournisseur d'agent",
"agent-id": "ID de l'agent",
"max-wall-time-seconds": "Temps d'exécution maximal (secondes)",
"poll-interval-seconds": "Intervalle d'interrogation (secondes)",
"remote-sub-agent-required-fields": "La clé API, l'hôte API et l'ID de l'agent sont requis lorsque Sub Agent est activé.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -238,6 +238,15 @@
"models-default-setting-title": "Impostazione predefinita",
"models-default-setting-description": "Seleziona uno dei modelli configurati come modello predefinito per Eigent. Verrà applicato globalmente nel tuo spazio di lavoro.",
"models-configuration": "Configurazione",
"sub-agents": "Sub-agent",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "Delega le attività adatte a una sandbox di agent remoto gestita.",
"agent-provider": "Provider agent",
"agent-id": "ID agent",
"max-wall-time-seconds": "Tempo massimo di esecuzione (secondi)",
"poll-interval-seconds": "Intervallo di polling (secondi)",
"remote-sub-agent-required-fields": "API Key, API Host e Agent ID sono obbligatori quando Sub Agent è abilitato.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -239,6 +239,15 @@
"models-default-setting-title": "デフォルト設定",
"models-default-setting-description": "設定済みモデルの中から、Eigent のデフォルトモデルを1つ選択します。ワークスペース全体にグローバルに適用されます。",
"models-configuration": "構成",
"sub-agents": "サブエージェント",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "適したタスクを管理されたリモートエージェントのサンドボックスに委任します。",
"agent-provider": "エージェントプロバイダー",
"agent-id": "エージェント ID",
"max-wall-time-seconds": "最大実行時間(秒)",
"poll-interval-seconds": "ポーリング間隔(秒)",
"remote-sub-agent-required-fields": "Sub Agent を有効にするには、API Key、API Host、Agent ID が必要です。",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -239,6 +239,15 @@
"models-default-setting-title": "기본 설정",
"models-default-setting-description": "구성된 모델 중 하나를 Eigent의 기본 모델로 선택하세요. 워크스페이스 전체에 전역으로 적용됩니다.",
"models-configuration": "구성",
"sub-agents": "서브 에이전트",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "적합한 작업을 관리형 원격 에이전트 샌드박스에 위임합니다.",
"agent-provider": "에이전트 제공자",
"agent-id": "에이전트 ID",
"max-wall-time-seconds": "최대 실행 시간(초)",
"poll-interval-seconds": "폴링 간격(초)",
"remote-sub-agent-required-fields": "Sub Agent를 활성화하려면 API Key, API Host, Agent ID가 필요합니다.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -238,6 +238,15 @@
"models-default-setting-title": "Настройка по умолчанию",
"models-default-setting-description": "Выберите одну из настроенных моделей как модель по умолчанию для Eigent. Она будет применяться глобально во всём рабочем пространстве.",
"models-configuration": "Конфигурация",
"sub-agents": "Суб-агенты",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "Делегируйте подходящие задачи управляемой песочнице удалённого агента.",
"agent-provider": "Поставщик агента",
"agent-id": "ID агента",
"max-wall-time-seconds": "Макс. время выполнения (секунды)",
"poll-interval-seconds": "Интервал опроса (секунды)",
"remote-sub-agent-required-fields": "API Key, API Host и Agent ID обязательны, когда Sub Agent включён.",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -199,7 +199,7 @@
"sub-agents": "Sub Agents",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "把适合远程执行的任务委托给 Waverunner 兼容的托管智能体沙盒。",
"remote-sub-agent-description": "把适合远程执行的任务委托给托管远程智能体沙盒。",
"agent-provider": "Agent Provider",
"agent-id": "Agent ID",
"max-wall-time-seconds": "最长运行时间(秒)",

View file

@ -167,6 +167,15 @@
"models-default-setting-title": "預設設定",
"models-default-setting-description": "從已配置的模型中選擇一個作為 Eigent 的預設模型,它將全域套用於您的工作區。",
"models-configuration": "配置",
"sub-agents": "Sub Agents",
"gemini-agent": "Gemini Agents API",
"gemini-remote-sub-agent": "Gemini Agents API",
"remote-sub-agent-description": "把適合遠端執行的任務委託給託管遠端智能體沙盒。",
"agent-provider": "Agent Provider",
"agent-id": "Agent ID",
"max-wall-time-seconds": "最長執行時間(秒)",
"poll-interval-seconds": "輪詢間隔(秒)",
"remote-sub-agent-required-fields": "啟用 Sub Agent 時,需要填寫 API Key、API Host 和 Agent ID。",
"gemini-3-pro-preview-name": "Gemini 3 Pro Preview",
"gemini-3.1-pro-preview-name": "Gemini 3.1 Pro Preview",

View file

@ -16,7 +16,7 @@ export const REMOTE_SUB_AGENT_PROVIDER = 'gemini_agents';
export const REMOTE_SUB_AGENT_PROVIDER_ID = REMOTE_SUB_AGENT_PROVIDER;
export const REMOTE_SUB_AGENT_DEFAULT_BASE_URL =
'https://generativelanguage.googleapis.com/v1beta';
export const REMOTE_SUB_AGENT_DEFAULT_AGENT = 'waverunner';
export const REMOTE_SUB_AGENT_DEFAULT_AGENT = '';
export const REMOTE_SUB_AGENT_DEFAULT_MAX_WALL_TIME_SECONDS = '900';
export const REMOTE_SUB_AGENT_DEFAULT_POLL_INTERVAL_SECONDS = '5';
@ -101,6 +101,12 @@ export function toRemoteSubAgentProviderPayload(form: RemoteSubAgentFormState) {
const agentName = form.agentName.trim();
const maxWallTimeSeconds = Number(form.maxWallTimeSeconds);
const pollIntervalSeconds = Number(form.pollIntervalSeconds);
const fallbackMaxWallTimeSeconds = Number(
REMOTE_SUB_AGENT_DEFAULT_MAX_WALL_TIME_SECONDS
);
const fallbackPollIntervalSeconds = Number(
REMOTE_SUB_AGENT_DEFAULT_POLL_INTERVAL_SECONDS
);
return {
provider_name: REMOTE_SUB_AGENT_PROVIDER_ID,
@ -110,12 +116,14 @@ export function toRemoteSubAgentProviderPayload(form: RemoteSubAgentFormState) {
agent_name: agentName,
model_name: '',
config: {
max_wall_time_seconds: Number.isFinite(maxWallTimeSeconds)
? maxWallTimeSeconds
: Number(REMOTE_SUB_AGENT_DEFAULT_MAX_WALL_TIME_SECONDS),
poll_interval_seconds: Number.isFinite(pollIntervalSeconds)
? pollIntervalSeconds
: Number(REMOTE_SUB_AGENT_DEFAULT_POLL_INTERVAL_SECONDS),
max_wall_time_seconds:
Number.isFinite(maxWallTimeSeconds) && maxWallTimeSeconds > 0
? maxWallTimeSeconds
: fallbackMaxWallTimeSeconds,
poll_interval_seconds:
Number.isFinite(pollIntervalSeconds) && pollIntervalSeconds > 0
? pollIntervalSeconds
: fallbackPollIntervalSeconds,
},
};
}

View file

@ -75,10 +75,22 @@ export default function SubAgents() {
return t('setting.validate-failed');
};
const getRemoteSubAgentRequiredError = (form: RemoteSubAgentFormState) => {
const getRemoteSubAgentRequiredError = (
form: RemoteSubAgentFormState,
requireFields = form.enabled
) => {
const maxWallTimeSeconds = Number(form.maxWallTimeSeconds.trim());
const pollIntervalSeconds = Number(form.pollIntervalSeconds.trim());
if (
form.enabled &&
(!form.apiKey.trim() || !form.baseUrl.trim() || !form.agentName.trim())
requireFields &&
(!form.apiKey.trim() ||
!form.baseUrl.trim() ||
!form.agentName.trim() ||
!Number.isFinite(maxWallTimeSeconds) ||
maxWallTimeSeconds <= 0 ||
!Number.isFinite(pollIntervalSeconds) ||
pollIntervalSeconds <= 0)
) {
return t('setting.remote-sub-agent-required-fields');
}
@ -105,8 +117,17 @@ export default function SubAgents() {
});
};
const persistRemoteSubAgentForm = async (form: RemoteSubAgentFormState) => {
const requiredError = getRemoteSubAgentRequiredError(form);
const persistRemoteSubAgentForm = async (
form: RemoteSubAgentFormState,
{
requireFields = form.enabled,
validateConnection = form.enabled,
}: {
requireFields?: boolean;
validateConnection?: boolean;
} = {}
) => {
const requiredError = getRemoteSubAgentRequiredError(form, requireFields);
if (requiredError) {
setRemoteSubAgentError(requiredError);
toast.error(requiredError);
@ -116,7 +137,7 @@ export default function SubAgents() {
setRemoteSubAgentSaving(true);
setRemoteSubAgentError(null);
try {
if (form.enabled) {
if (validateConnection) {
await validateRemoteSubAgentConfig(form);
}
@ -145,7 +166,10 @@ export default function SubAgents() {
};
const handleRemoteSubAgentSave = async () => {
await persistRemoteSubAgentForm(remoteSubAgentForm);
await persistRemoteSubAgentForm(remoteSubAgentForm, {
requireFields: true,
validateConnection: true,
});
};
const handleRemoteSubAgentToggle = async (checked: boolean) => {
@ -155,7 +179,13 @@ export default function SubAgents() {
enabled: checked,
};
const requiredError = getRemoteSubAgentRequiredError(nextForm);
if (!checked && !remoteSubAgentForm.provider_id) {
setRemoteSubAgentForm(nextForm);
setRemoteSubAgentError(null);
return;
}
const requiredError = getRemoteSubAgentRequiredError(nextForm, checked);
if (requiredError) {
setRemoteSubAgentError(requiredError);
toast.error(requiredError);
@ -163,7 +193,10 @@ export default function SubAgents() {
}
setRemoteSubAgentForm(nextForm);
const saved = await persistRemoteSubAgentForm(nextForm);
const saved = await persistRemoteSubAgentForm(nextForm, {
requireFields: checked,
validateConnection: checked,
});
if (!saved) {
setRemoteSubAgentForm(previousForm);
}