feat(ai): 添加 Codex CLI 命令解析和环境变量处理功能
- 实现了对 Codex CLI 命令的解析,支持路径解析和环境变量设置 - 增加了对命令环境的处理,确保正确的执行路径 - 添加了相关的单元测试,确保功能的正确性
This commit is contained in:
6 files changed
+360
-12
No files matched your search
@@ -18,6 +18,7 @@ import DatabaseIcon from "@/components/icons/DatabaseIcon.vue";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { buildAiContext, runAgentStream, type AiAction } from "@/lib/ai";
|
||||
import { formatAiModelOption } from "@/lib/aiModelPresentation";
|
||||
import type { AgentEvent } from "@/lib/tauri";
|
||||
import { buildAiAgentPlan } from "@/lib/aiAgentPlan";
|
||||
import { buildAiAgentStepItems, type AiAgentStepItem, type AiAgentStepTone } from "@/lib/aiAgentStepPresentation";
|
||||
@@ -136,6 +137,14 @@ function displayModelName(modelId: string) {
|
||||
return modelOptions.value.find((model) => model.id === modelId)?.displayName || modelId;
|
||||
}
|
||||
|
||||
function modelOptionPresentation(modelId: string, label = displayModelName(modelId)) {
|
||||
return formatAiModelOption(label, modelId);
|
||||
}
|
||||
|
||||
function modelOptionSecondary(modelId: string, label = displayModelName(modelId)) {
|
||||
return modelOptionPresentation(modelId, label).secondary;
|
||||
}
|
||||
|
||||
/** Deferred context compaction info; applied after stream ends to avoid shifting assistantIdx. */
|
||||
const pendingCompaction = ref<{ summary: string; compactedMessages: number } | null>(null);
|
||||
|
||||
@@ -1300,7 +1309,7 @@ const messageRenderer = computed(() => {
|
||||
:display-name="displayModelName"
|
||||
trigger-class="min-w-0 w-auto max-w-[220px] shrink justify-end rounded-full border px-2 py-0.5 text-[11px] text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
content-class="w-72"
|
||||
item-class="text-xs px-2"
|
||||
item-class="h-auto min-h-8 px-2 py-1.5 text-xs"
|
||||
@update:model-value="handleModelSelect"
|
||||
@update:open="(open: boolean) => open && fetchModelOptions()"
|
||||
>
|
||||
@@ -1308,9 +1317,9 @@ const messageRenderer = computed(() => {
|
||||
<span class="min-w-0 truncate">{{ loading ? t("ai.loadingModels") : label }}</span>
|
||||
</template>
|
||||
<template #option-label="{ option, label }">
|
||||
<span class="flex min-w-0 flex-col">
|
||||
<span class="truncate">{{ label }}</span>
|
||||
<span v-if="label !== option" class="truncate text-[11px] text-muted-foreground">{{ option }}</span>
|
||||
<span class="flex min-w-0 flex-col leading-tight">
|
||||
<span class="truncate">{{ modelOptionPresentation(option, label).primary }}</span>
|
||||
<span v-if="modelOptionSecondary(option, label)" class="mt-0.5 truncate text-[11px] text-muted-foreground">{{ modelOptionSecondary(option, label) }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
type CustomTheme,
|
||||
} from "@/stores/settingsStore";
|
||||
import { loadEditorTheme, editorFontTheme } from "@/lib/editorThemes";
|
||||
import { formatAiModelOption } from "@/lib/aiModelPresentation";
|
||||
import ThemeCustomizerDialog from "./ThemeCustomizerDialog.vue";
|
||||
import { isTauriRuntime } from "@/lib/tauriRuntime";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
@@ -1594,6 +1595,14 @@ function displayAiModelName(modelId: string): string {
|
||||
return aiModelOptions.value.find((model) => model.id === modelId)?.displayName || modelId;
|
||||
}
|
||||
|
||||
function aiModelOptionPresentation(modelId: string, label = displayAiModelName(modelId)) {
|
||||
return formatAiModelOption(label, modelId);
|
||||
}
|
||||
|
||||
function aiModelOptionSecondary(modelId: string, label = displayAiModelName(modelId)) {
|
||||
return aiModelOptionPresentation(modelId, label).secondary;
|
||||
}
|
||||
|
||||
async function aiRefreshModels() {
|
||||
if (aiModelLoading.value) return;
|
||||
if (!aiModelListSupported.value) {
|
||||
@@ -2985,6 +2994,7 @@ watch(
|
||||
:display-name="displayAiModelName"
|
||||
trigger-class="h-8 min-w-[104px] max-w-[150px] shrink-0 border border-border bg-background px-2 text-xs shadow-none hover:bg-muted/50"
|
||||
content-class="w-72"
|
||||
item-class="h-auto min-h-8 py-1.5"
|
||||
@update:model-value="aiSelectModel"
|
||||
@update:open="onAiModelListOpen"
|
||||
>
|
||||
@@ -2992,9 +3002,9 @@ watch(
|
||||
<span class="truncate">{{ loading ? t("ai.loadingModels") : t("ai.browseModels") }}</span>
|
||||
</template>
|
||||
<template #option-label="{ option, label }">
|
||||
<span class="flex min-w-0 flex-col">
|
||||
<span class="truncate">{{ label }}</span>
|
||||
<span v-if="label !== option" class="truncate text-[11px] text-muted-foreground">{{ option }}</span>
|
||||
<span class="flex min-w-0 flex-col leading-tight">
|
||||
<span class="truncate">{{ aiModelOptionPresentation(option, label).primary }}</span>
|
||||
<span v-if="aiModelOptionSecondary(option, label)" class="mt-0.5 truncate text-[11px] text-muted-foreground">{{ aiModelOptionSecondary(option, label) }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
||||
Reference in new issue
Block a user