From ac20ac212ed81fe3c32b74b196797e1c8219864a Mon Sep 17 00:00:00 2001 From: John Date: Thu, 2 Jul 2026 07:19:26 +0800 Subject: [PATCH] feat: add gated h5 code run entry --- .env.example | 5 ++++ src/api/client.ts | 4 +++ src/hooks/usePageEditSubChat.ts | 11 ++++++++- src/hooks/useTKMindChat.ts | 8 +++++- src/utils/agentRunMode.ts | 44 +++++++++++++++++++++++++++++++++ src/vite-env.d.ts | 2 ++ 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 src/utils/agentRunMode.ts diff --git a/.env.example b/.env.example index 95a637d..ed6d838 100644 --- a/.env.example +++ b/.env.example @@ -19,6 +19,11 @@ H5_PUBLIC_BASE_URL=http://127.0.0.1:5173 # MEMIND_RUNTIME_REDIS_URL=redis://127.0.0.1:6379/0 # MEMIND_RUNTIME_REDIS_NAMESPACE=memind:runtime +# Code-tool agent run 灰度开关(默认关闭)。 +# 开启后,页面编辑子聊天会传 tool_mode=code;普通聊天仍需同时开启 AUTODETECT 才会按文本自动识别代码任务。 +# VITE_AGENT_CODE_RUNS_ENABLED=0 +# VITE_AGENT_CODE_RUNS_AUTODETECT=0 + # ===== memind_adm(独立后台服务)===== # 平台超管 /admin-api/* 与广场运营 /api/ops/v1/* 已从公网服务拆出,独立进程运行。 # 登录仍在主域完成;后台凭 H5_COOKIE_DOMAIN=.tkmind.cn 共享的会话 Cookie 鉴权(生产务必设置)。 diff --git a/src/api/client.ts b/src/api/client.ts index 2ed98cc..ce93f58 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -58,6 +58,7 @@ import type { } from '../types'; import { CHAT_IMAGE_UPLOAD_MAX_INPUT_BYTES } from '../utils/imageUpload'; import { normalizeConversationMessages, normalizeUserMessageForApi } from '../utils/message'; +import type { AgentRunCreateOptions } from '../utils/agentRunMode'; const API = '/api'; const DEFAULT_API_TIMEOUT_MS = 20_000; @@ -2247,6 +2248,7 @@ export async function createAgentRun( sessionId: string | null, requestId: string, userMessage: Message, + options: AgentRunCreateOptions = {}, ): Promise { const result = await apiFetch<{ run: AgentRun }>( AGENT_RUNS_PATH, @@ -2256,6 +2258,8 @@ export async function createAgentRun( session_id: sessionId, request_id: requestId, user_message: normalizeUserMessageForApi(userMessage), + ...(options.toolMode ? { tool_mode: options.toolMode } : {}), + ...(options.taskType ? { task_type: options.taskType } : {}), }), }, { timeoutMs: AGENT_CONNECT_TIMEOUT_MS }, diff --git a/src/hooks/usePageEditSubChat.ts b/src/hooks/usePageEditSubChat.ts index b7978b8..9f25975 100644 --- a/src/hooks/usePageEditSubChat.ts +++ b/src/hooks/usePageEditSubChat.ts @@ -20,6 +20,7 @@ import { CHAT_IMAGE_UPLOAD_MAX_INPUT_BYTES, } from '../utils/imageUpload'; import { buildAbsoluteAssetImageUrl } from '../utils/mindspaceCards'; +import { resolveAgentRunOptions } from '../utils/agentRunMode'; import { buildUserMessage, normalizeConversationMessages, @@ -339,7 +340,15 @@ export function usePageEditSubChat({ setPendingTool(null); try { - const createdRun = await createAgentRun(currentSession.id, requestId, userMessage); + const createdRun = await createAgentRun( + currentSession.id, + requestId, + userMessage, + resolveAgentRunOptions(trimmed, { + taskType: 'page_edit_code_task', + forceCode: true, + }), + ); const finishedRun = createdRun.status === 'succeeded' ? createdRun : await waitForAgentRun(createdRun.id); if (!finishedRun.sessionId) { diff --git a/src/hooks/useTKMindChat.ts b/src/hooks/useTKMindChat.ts index a536c42..8acf5ce 100644 --- a/src/hooks/useTKMindChat.ts +++ b/src/hooks/useTKMindChat.ts @@ -50,6 +50,7 @@ import { CHAT_IMAGE_UPLOAD_MAX_INPUT_BYTES, } from '../utils/imageUpload'; import { buildAbsoluteAssetImageUrl } from '../utils/mindspaceCards'; +import { resolveAgentRunOptions } from '../utils/agentRunMode'; import { buildUserMessage, normalizeConversationMessages, @@ -1168,7 +1169,12 @@ export function useTKMindChat( } try { - const createdRun = await createAgentRun(activeSessionId, requestId, userMessage); + const createdRun = await createAgentRun( + activeSessionId, + requestId, + userMessage, + resolveAgentRunOptions(trimmed, { taskType: 'h5_chat_code_task' }), + ); const finishedRun = createdRun.status === 'succeeded' ? createdRun : await waitForAgentRun(createdRun.id); activeSessionId = finishedRun.sessionId; diff --git a/src/utils/agentRunMode.ts b/src/utils/agentRunMode.ts new file mode 100644 index 0000000..ad16718 --- /dev/null +++ b/src/utils/agentRunMode.ts @@ -0,0 +1,44 @@ +export type AgentRunCreateOptions = { + toolMode?: 'chat' | 'code'; + taskType?: string | null; +}; + +function envFlag(value: unknown): boolean { + const normalized = String(value ?? '').trim().toLowerCase(); + return ['1', 'true', 'yes', 'on'].includes(normalized); +} + +export const agentCodeRunsEnabled = envFlag(import.meta.env.VITE_AGENT_CODE_RUNS_ENABLED); +export const agentCodeRunsAutodetectEnabled = envFlag( + import.meta.env.VITE_AGENT_CODE_RUNS_AUTODETECT, +); + +const CODE_TASK_PATTERNS = [ + /\b(repo|repository|branch|commit|pull request|pr|diff|patch)\b/i, + /\b(aider|openhands|codex|codebase|workspace)\b/i, + /\b(refactor|debug|fix bug|implement|add test|unit test)\b/i, + /(修改|修复|重构|调试|实现|新增|编写|更新).{0,12}(代码|仓库|分支|文件|测试|组件|接口)/, + /(代码|仓库|项目|文件|组件|接口).{0,12}(修改|修复|重构|调试|实现|新增|编写|更新)/, +]; + +export function resolveAgentRunOptions( + text: string, + { + taskType = 'code_task', + forceCode = false, + allowAutodetect = agentCodeRunsAutodetectEnabled, + }: { + taskType?: string; + forceCode?: boolean; + allowAutodetect?: boolean; + } = {}, +): AgentRunCreateOptions { + if (!agentCodeRunsEnabled) return {}; + const normalizedText = String(text ?? '').trim(); + const shouldUseCode = forceCode || (allowAutodetect && CODE_TASK_PATTERNS.some((pattern) => pattern.test(normalizedText))); + if (!shouldUseCode) return {}; + return { + toolMode: 'code', + taskType, + }; +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index cfba7f1..1eeca6e 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -7,6 +7,8 @@ interface ImportMetaEnv { readonly VITE_TKMIND_MEMORY_QUERY: string; readonly VITE_PLAZA_BASE?: string; readonly VITE_MINDSPACE_BASE?: string; + readonly VITE_AGENT_CODE_RUNS_ENABLED?: string; + readonly VITE_AGENT_CODE_RUNS_AUTODETECT?: string; } interface ImportMeta {