feat(ai): make agent turn limit configurable
This commit is contained in:
1 parent
21e9578f78
commit
9253203d99
21 files changed
+307
-5
No files matched your search
@@ -48,6 +48,7 @@ import {
|
||||
} from "@/stores/settingsStore";
|
||||
import { createRunStatementButtonDom, loadEditorTheme, editorFontTheme } from "@/lib/editor/editorThemes";
|
||||
import { orderAiConfigsForDisplay } from "@/lib/ai/aiConfigOrdering";
|
||||
import { MAX_AGENT_TURNS_DEFAULT, MAX_AGENT_TURNS_MAX, MAX_AGENT_TURNS_MIN, maxAgentTurnsOutOfRange, normalizeMaxAgentTurns } from "@/lib/ai/maxAgentTurns";
|
||||
import { normalizeAiModelEffortLevels, normalizeClaudeCodeReasoningLevel } from "@/lib/ai/aiModelEffort";
|
||||
import ThemeCustomizerDialog from "./ThemeCustomizerDialog.vue";
|
||||
import TunnelProfileManager from "@/components/connection/TunnelProfileManager.vue";
|
||||
@@ -65,6 +66,8 @@ import {
|
||||
forgetWebdavSyncSecretsPassphrase,
|
||||
forgetWebdavSavedPassword,
|
||||
getAppSupportInfo,
|
||||
loadMaxAgentTurns,
|
||||
saveMaxAgentTurns,
|
||||
saveWebdavSyncSecretsPreference,
|
||||
saveWebdavSavedPassword,
|
||||
saveSnippetSavedToken,
|
||||
@@ -1954,6 +1957,7 @@ watch(activeSettingsTab, async (tab) => {
|
||||
if (tab === "mcp" && !mcpStatus.value && !mcpStatusLoading.value) void refreshMcpStatus();
|
||||
if (tab === "ai" && aiIsCliProvider.value) void ensureCliMcpStatus();
|
||||
if (tab === "ai") {
|
||||
void loadMaxAgentTurnsSetting();
|
||||
// Await completion so we don't snapshot an empty default when the store
|
||||
// is still loading its first payload (init via App.vue is fire-and-forget).
|
||||
await promptTemplateStore.ensureLoaded();
|
||||
@@ -2137,6 +2141,45 @@ function globalInstructionsTooLong(): boolean {
|
||||
return promptTemplateCharacterCount(editGlobalInstructions.value) > GLOBAL_INSTRUCTIONS_MAX;
|
||||
}
|
||||
|
||||
// Agent turn limit for DBX's API-backed agent loop. CLI providers enforce their own limits.
|
||||
// Mirrors DEFAULT/MIN/MAX_MAX_AGENT_TURNS in crates/dbx-core/src/agent_loop.rs —
|
||||
// keep in sync; the backend clamp on save/load is the actual source of truth.
|
||||
const editMaxAgentTurns = ref<number | undefined>(undefined);
|
||||
const maxAgentTurnsSaving = ref(false);
|
||||
const maxAgentTurnsLoaded = ref(false);
|
||||
const maxAgentTurnsLoading = ref(false);
|
||||
const maxAgentTurnsLoadError = ref("");
|
||||
|
||||
async function loadMaxAgentTurnsSetting() {
|
||||
if (maxAgentTurnsLoaded.value || maxAgentTurnsLoading.value) return;
|
||||
maxAgentTurnsLoading.value = true;
|
||||
maxAgentTurnsLoadError.value = "";
|
||||
try {
|
||||
editMaxAgentTurns.value = await loadMaxAgentTurns();
|
||||
maxAgentTurnsLoaded.value = true;
|
||||
} catch (e: any) {
|
||||
maxAgentTurnsLoadError.value = e?.message || String(e);
|
||||
toast(maxAgentTurnsLoadError.value, 5000);
|
||||
} finally {
|
||||
maxAgentTurnsLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveMaxAgentTurnsSetting() {
|
||||
if (!maxAgentTurnsLoaded.value) return;
|
||||
const clamped = normalizeMaxAgentTurns(editMaxAgentTurns.value);
|
||||
maxAgentTurnsSaving.value = true;
|
||||
try {
|
||||
await saveMaxAgentTurns(clamped);
|
||||
editMaxAgentTurns.value = clamped;
|
||||
toast(t("ai.maxAgentTurnsSaved"));
|
||||
} catch (e: any) {
|
||||
toast(e?.message || String(e), 5000);
|
||||
} finally {
|
||||
maxAgentTurnsSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// AI Config Delete Confirmation
|
||||
const aiDeleteConfirmOpen = ref(false);
|
||||
const aiDeleteConfigId = ref<string | null>(null);
|
||||
@@ -4768,6 +4811,28 @@ onUnmounted(cleanupPreviewEditor);
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Agent Turn Limit (list mode, global) -->
|
||||
<div v-if="aiConfigListMode === 'list'" class="space-y-3">
|
||||
<Separator />
|
||||
<div>
|
||||
<h3 class="text-sm font-medium">{{ t("ai.maxAgentTurns") }}</h3>
|
||||
<p class="text-xs text-muted-foreground">{{ t("ai.maxAgentTurnsDescription") }}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input v-model.number="editMaxAgentTurns" type="number" :min="MAX_AGENT_TURNS_MIN" :max="MAX_AGENT_TURNS_MAX" step="1" class="h-8 w-32 text-xs" :placeholder="String(MAX_AGENT_TURNS_DEFAULT)" :disabled="!maxAgentTurnsLoaded || maxAgentTurnsSaving" />
|
||||
<span class="text-xs" :class="maxAgentTurnsOutOfRange(editMaxAgentTurns) ? 'text-destructive' : 'text-muted-foreground'">
|
||||
{{ t("ai.maxAgentTurnsRange", { min: MAX_AGENT_TURNS_MIN, max: MAX_AGENT_TURNS_MAX, default: MAX_AGENT_TURNS_DEFAULT }) }}
|
||||
</span>
|
||||
<div class="flex-1"></div>
|
||||
<Button v-if="maxAgentTurnsLoadError" type="button" size="sm" variant="outline" :disabled="maxAgentTurnsLoading" @click="loadMaxAgentTurnsSetting">
|
||||
{{ t("common.retry") }}
|
||||
</Button>
|
||||
<Button type="button" size="sm" :disabled="!maxAgentTurnsLoaded || maxAgentTurnsSaving || maxAgentTurnsOutOfRange(editMaxAgentTurns)" @click="saveMaxAgentTurnsSetting">
|
||||
{{ maxAgentTurnsSaving ? t("common.processing") : t("common.save") }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Prompt Templates Management (list mode) -->
|
||||
<div v-if="aiConfigListMode === 'list'" class="space-y-3">
|
||||
<Separator />
|
||||
|
||||
Reference in new issue
Block a user