fix: moonshot temperature=1, 20MB upload limit, file input FileList fix, rate limiter off

- workflow_integration: force temperature=1.0 for moonshot provider (Kimi K3 reasoning models reject other values), both agent node and orchestrator node
- config: LOCAL_FILE_WRITE_MAX_BYTES 2MB -> 20MB (image uploads)
- main: temporarily disable RateLimiterMiddleware
- useFileUpload: copy FileList before resetting input (Chromium clears reference)
- AgentChat/AgentChatPreview: attach button via ChatInputArea ref
This commit is contained in:
2026-07-27 00:43:17 +08:00
parent 8d9ddd3aa0
commit c3af128b81
6 changed files with 26 additions and 10 deletions

View File

@@ -64,10 +64,15 @@ async def run_agent_node(
formatted_prompt = raw_prompt
# 3. 构建 Agent 配置
_provider = node_data.get("provider", "openai")
temperature = float(node_data.get("temperature", 0.7))
# Kimi K3 等推理模型强制要求 temperature=1
if _provider == "moonshot":
temperature = 1.0
llm_config = AgentLLMConfig(
provider=node_data.get("provider", "openai"),
provider=_provider,
model=node_data.get("model", "gpt-4o-mini"),
temperature=float(node_data.get("temperature", 0.7)),
temperature=temperature,
max_iterations=int(node_data.get("max_iterations", 10)),
)
# 允许节点内联 api_key/base_url
@@ -244,6 +249,10 @@ async def run_orchestrator_node(
tools_whitelist = cfg.get("tools", tools_whitelist)
break
# Kimi K3 等推理模型强制要求 temperature=1
if provider == "moonshot":
temperature = 1.0
agent_configs.append(OrchestratorAgentConfig(
id=agent.id,
name=agent.name or "Agent",

View File

@@ -34,7 +34,7 @@ class Settings(BaseSettings):
# 本地文件工具(file_read / file_write):允许读写的根目录。空字符串表示使用「backend 的上一级目录」作为仓库根。
LOCAL_FILE_TOOLS_ROOT: str = ""
LOCAL_FILE_READ_MAX_BYTES: int = 2_097_152 # 单次读取上限(默认 2MB)
LOCAL_FILE_WRITE_MAX_BYTES: int = 2_097_152 # 单次写入内容上限(UTF-8 字节)
LOCAL_FILE_WRITE_MAX_BYTES: int = 20_971_520 # 单次写入内容上限 20MB(含图片上传)
# http_request 工具:写入 LLM 上下文的响应体最大字符数(HTML/JSON 过大时截断,避免超过模型 context)
HTTP_REQUEST_MAX_BODY_CHARS: int = 32_000

View File

@@ -191,7 +191,8 @@ app.add_middleware(
)
# API 限流中间件(在 CORS 之后、日志之前)
app.add_middleware(RateLimiterMiddleware)
# TODO: 暂时关闭限流,需要时恢复
# app.add_middleware(RateLimiterMiddleware)
# 安全响应头中间件(HSTS + X-Frame-Options + X-Content-Type-Options 等)
app.add_middleware(SecurityHeadersMiddleware)

View File

@@ -142,6 +142,7 @@
<!-- Shared ChatInputArea -->
<ChatInputArea
ref="inputAreaRef"
v-model="inputMessage"
:loading="loading"
:disabled="loading || !agentId"
@@ -182,7 +183,9 @@ import api, { WORKFLOW_EXECUTION_HTTP_TIMEOUT_MS } from '@/api'
import { useUserStore } from '@/stores/user'
// ---- Shared composables ----
const { pendingAttachments, fileInputRef, inputDragOver, uploadFiles, removeAttachment, clearAttachments, buildAttachmentContext, onFilesSelected, handleAttachFile } = useFileUpload()
const { pendingAttachments, inputDragOver, uploadFiles, removeAttachment, clearAttachments, buildAttachmentContext, onFilesSelected } = useFileUpload()
const inputAreaRef = ref<InstanceType<typeof ChatInputArea> | null>(null)
function handleAttachFile() { inputAreaRef.value?.fileInputEl?.click() }
const { stripMarkdownForTTS } = useMarkdown()
const { isSpeaking, speak: ttsSpeak, stop: ttsStop } = useTTS()

View File

@@ -155,10 +155,12 @@ export function useFileUpload() {
async function onFilesSelected(e: Event): Promise<PendingAttachment[]> {
const input = e.target as HTMLInputElement
const files = input.files
input.value = '' // Reset so the same file can be re-selected
if (files?.length) return uploadFiles(Array.from(files))
return []
const rawFiles = input.files
if (!rawFiles?.length) return []
// 必须先复制再重置 input,否则 Chromium 系清空 FileList 引用
const fileArr = Array.from(rawFiles)
input.value = ''
return uploadFiles(fileArr)
}
function handleAttachFile() {

View File

@@ -486,7 +486,8 @@ import { useTTS } from '@/composables/useTTS'
import { useSpeechRecognition } from '@/composables/useSpeechRecognition'
const { renderMarkdown, stripMarkdownForTTS } = useMarkdown()
const { pendingAttachments, inputDragOver, uploadFiles, removeAttachment, clearAttachments, buildAttachmentContext, onFilesSelected, handleAttachFile } = useFileUpload()
const { pendingAttachments, inputDragOver, uploadFiles, removeAttachment, clearAttachments, buildAttachmentContext, onFilesSelected } = useFileUpload()
function handleAttachFile() { inputAreaRef.value?.fileInputEl?.click() }
const { isSpeaking, speak: ttsSpeak, stop: ttsStop } = useTTS()
const { isListening, transcript, error: voiceError, supported: voiceSupported, start: voiceStart, stop: voiceStop } = useSpeechRecognition()
const modelConfigStore = useModelConfigStore()