From 9632c1b4a62833a3ae4938389fd1622f86ab4005 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?cls=5F=E5=AE=81=E6=B3=A2=E6=9C=AC=E6=9C=BA?=
<908705107@qq.com>
Date: Sat, 13 Jun 2026 11:45:03 +0800
Subject: [PATCH] fix: wire ai platform run and codex chat
---
backend-fastapi/ai_platform/api/agent_api.py | 71 +++++
.../ai_platform/api/provider_api.py | 2 +
web/apps/web-ele/src/router/access.ts | 11 +
web/apps/web-ele/src/router/light-menu.ts | 2 +
.../ai-platform/model/model-config-form.vue | 65 ++++-
.../workflow-runs/modules/detail-dialog.vue | 141 +++++++++-
.../src/views/ai-platform/workflow/index.vue | 258 +++++++++++++++++-
7 files changed, 526 insertions(+), 24 deletions(-)
diff --git a/backend-fastapi/ai_platform/api/agent_api.py b/backend-fastapi/ai_platform/api/agent_api.py
index 939d7bc..9365617 100644
--- a/backend-fastapi/ai_platform/api/agent_api.py
+++ b/backend-fastapi/ai_platform/api/agent_api.py
@@ -44,6 +44,75 @@ from ai_platform.services.agent_import_export import (
logger = logging.getLogger(__name__)
+
+CODEX_AGENT_PROMPT = """
+你是 ai-agent-admin 内置的 Codex 协作助手。你的目标是帮助用户拆解工程任务、解释代码、规划实现、生成可执行步骤,并在需要时提示用户进入智能体、流程编排、模型配置和执行历史等模块完成操作。
+
+回答要求:
+- 直接、具体、可执行。
+- 优先给出最小可落地方案,再说明关键风险。
+- 涉及代码或配置时,明确文件、接口、命令或字段。
+- 对不确定事实要说明需要验证,不要编造。
+""".strip()
+
+
+async def _resolve_default_chat_model_id(db: AsyncSession) -> Optional[str]:
+ result = await db.execute(
+ select(LLMModel)
+ .where(
+ LLMModel.is_deleted == False,
+ LLMModel.is_active == True,
+ LLMModel.model_type == "chat",
+ )
+ .order_by(LLMModel.sort.desc(), LLMModel.sys_create_datetime.desc())
+ )
+ model = result.scalars().first()
+ return str(model.id) if model else None
+
+
+async def _ensure_codex_agent(db: AsyncSession) -> Agent:
+ model_id = await _resolve_default_chat_model_id(db)
+ if not model_id:
+ raise HTTPException(
+ status_code=400,
+ detail="Codex 智能体需要先配置一个启用的 chat 模型",
+ )
+
+ agent = Agent(
+ name="Codex",
+ code="codex",
+ description="内置通用 AI 编程协作助手",
+ mode="autonomous",
+ status="published",
+ is_global=True,
+ is_public=True,
+ model_id=model_id,
+ temperature=0.3,
+ top_p=1.0,
+ max_tokens=4096,
+ max_iterations=6,
+ enable_memory=True,
+ memory_window=10,
+ enable_streaming=True,
+ persona={
+ "role": "AI 编程协作助手",
+ "skills": ["代码理解", "任务拆解", "方案设计", "问题排查"],
+ "constraints": ["不编造事实", "优先输出可执行步骤"],
+ },
+ system_prompt=CODEX_AGENT_PROMPT,
+ welcome_message="我是 Codex 协作助手,可以帮你拆解任务、解释代码、规划实现和排查问题。",
+ suggested_questions=[
+ "帮我分析当前 AI Agent Admin 的下一步实现重点",
+ "解释一下智能体和流程编排如何协作",
+ "帮我设计一个 OC-69 多智能体协作流程",
+ ],
+ sort=100,
+ )
+ db.add(agent)
+ await db.commit()
+ await db.refresh(agent)
+ return agent
+
router = APIRouter(prefix="/agent", tags=["AI-智能体"])
@@ -171,6 +240,8 @@ async def get_agent_by_code(code: str, db: AsyncSession = Depends(get_db)):
select(Agent).where(Agent.code == code, Agent.is_deleted == False)
)
agent = result.scalar_one_or_none()
+ if not agent and code == "codex":
+ agent = await _ensure_codex_agent(db)
if not agent:
raise HTTPException(status_code=404, detail="智能体不存在")
diff --git a/backend-fastapi/ai_platform/api/provider_api.py b/backend-fastapi/ai_platform/api/provider_api.py
index 58669b2..059fd92 100644
--- a/backend-fastapi/ai_platform/api/provider_api.py
+++ b/backend-fastapi/ai_platform/api/provider_api.py
@@ -110,6 +110,8 @@ async def update_provider(
raise HTTPException(status_code=404, detail="提供商不存在")
update_data = data.model_dump(exclude_unset=True)
+ if update_data.get("api_key") == "":
+ update_data.pop("api_key")
for key, value in update_data.items():
setattr(provider, key, value)
diff --git a/web/apps/web-ele/src/router/access.ts b/web/apps/web-ele/src/router/access.ts
index b361a8c..2e662ce 100644
--- a/web/apps/web-ele/src/router/access.ts
+++ b/web/apps/web-ele/src/router/access.ts
@@ -62,6 +62,17 @@ function createLightAiMenuRoute(
}
const LIGHT_AI_PLATFORM_MENU_ROUTES = [
+ createLightAiMenuRoute({
+ component: '/_core/agent-chat/index',
+ meta: {
+ fullPathKey: true,
+ icon: 'lucide:code',
+ order: 25,
+ title: 'menu-title.codex',
+ },
+ name: 'CodexAgentChat',
+ path: '/agent-chat/codex',
+ }),
createLightAiMenuRoute({
component: '/ai-platform/model/index',
meta: {
diff --git a/web/apps/web-ele/src/router/light-menu.ts b/web/apps/web-ele/src/router/light-menu.ts
index b29bda4..6832a8c 100644
--- a/web/apps/web-ele/src/router/light-menu.ts
+++ b/web/apps/web-ele/src/router/light-menu.ts
@@ -7,6 +7,7 @@ export const LIGHT_MENU_NAMES = new Set([
'AIWorkflowRuns',
'AnnouncementList',
'AnnouncementManage',
+ 'CodexAgentChat',
'KnowledgeBase',
'PageRenderMainHome',
'SystemManagement',
@@ -23,6 +24,7 @@ const LIGHT_ROUTE_PATH_PREFIXES = [
'/ai-platform/model',
'/ai-platform/workflow',
'/ai-platform/workflow-runs',
+ '/agent-chat',
'/message/announcement',
'/page-render/main_home',
'/system/menu',
diff --git a/web/apps/web-ele/src/views/ai-platform/model/model-config-form.vue b/web/apps/web-ele/src/views/ai-platform/model/model-config-form.vue
index 71af536..e526d26 100644
--- a/web/apps/web-ele/src/views/ai-platform/model/model-config-form.vue
+++ b/web/apps/web-ele/src/views/ai-platform/model/model-config-form.vue
@@ -2,6 +2,7 @@
import type {
DefaultModel,
ModelListItem,
+ ProviderCreateInput,
ProviderListItem,
ProviderType,
} from '#/api/ai-platform/ai-platform';
@@ -57,6 +58,7 @@ import {
deleteProviderApi,
fetchProviderModelsApi,
getModelListApi,
+ getProviderDetailApi,
getProviderDefaultModelsApi,
getProviderListApi,
getProviderTypesApi,
@@ -95,6 +97,7 @@ const providerForm = ref({
name: '',
provider_type: '',
api_key: '',
+ api_key_masked: '',
api_base: '',
ollama_host: 'http://localhost:11434',
description: '',
@@ -247,6 +250,7 @@ function handleAddProvider() {
name: '',
provider_type: '',
api_key: '',
+ api_key_masked: '',
api_base: '',
ollama_host: 'http://localhost:11434',
description: '',
@@ -255,28 +259,51 @@ function handleAddProvider() {
showProviderDialog.value = true;
}
-function handleEditProvider(row: ProviderListItem) {
+async function handleEditProvider(row: ProviderListItem) {
providerDialogMode.value = 'edit';
- providerForm.value = {
- id: row.id,
- name: row.name,
- provider_type: row.provider_type,
- api_key: '',
- api_base: '',
- ollama_host: 'http://localhost:11434',
- description: row.description,
- is_active: row.is_active,
+ try {
+ const detail = await getProviderDetailApi(row.id);
+ providerForm.value = {
+ id: detail.id,
+ name: detail.name,
+ provider_type: detail.provider_type,
+ api_key: '',
+ api_key_masked: detail.api_key_masked || '',
+ api_base: detail.api_base || '',
+ ollama_host: detail.ollama_host || 'http://localhost:11434',
+ description: detail.description || '',
+ is_active: detail.is_active,
+ };
+ showProviderDialog.value = true;
+ } catch (error: any) {
+ ElMessage.error(error.message || $t('ui.actionMessage.operationFailed'));
+ }
+}
+
+function buildProviderPayload() {
+ const payload: ProviderCreateInput = {
+ name: providerForm.value.name,
+ provider_type: providerForm.value.provider_type,
+ api_base: providerForm.value.api_base,
+ ollama_host: providerForm.value.ollama_host,
+ description: providerForm.value.description,
+ is_active: providerForm.value.is_active,
};
- showProviderDialog.value = true;
+ const apiKey = providerForm.value.api_key.trim();
+ if (apiKey) {
+ payload.api_key = apiKey;
+ }
+ return payload;
}
async function handleSaveProvider() {
try {
+ const payload = buildProviderPayload();
if (providerDialogMode.value === 'add') {
- await createProviderApi(providerForm.value);
+ await createProviderApi(payload);
ElMessage.success($t('ui.actionMessage.operationSuccess'));
} else {
- await updateProviderApi(providerForm.value.id, providerForm.value);
+ await updateProviderApi(providerForm.value.id, payload);
ElMessage.success($t('ui.actionMessage.operationSuccess'));
}
showProviderDialog.value = false;
@@ -889,9 +916,19 @@ defineExpose({ reset });
{{ previewValue(log.inputs) }}
+ {{ previewValue(log.output) }}
+