|
|
@@ -1139,6 +1139,14 @@ export default function Chat() {
|
|
|
enabled: !!agentId,
|
|
|
})
|
|
|
|
|
|
+ // 工作区对话型助手(workspace.assistant)必须先绑定工作文件夹。无 ?dir / workDir
|
|
|
+ // 时不能对话——否则后端会拒绝(WORKSPACE_DIR_REQUIRED),且 agent 读不到用户文件
|
|
|
+ // 还'假装成功'。此处在前端先强制弹文件夹选择,禁用输入,关掉则退回工作台。
|
|
|
+ const needsWorkDir = agent?.agent_template === 'workspace.assistant' && !workDir
|
|
|
+ useEffect(() => {
|
|
|
+ if (needsWorkDir) setDirPickerOpen(true)
|
|
|
+ }, [needsWorkDir])
|
|
|
+
|
|
|
// Extract maxSteps from agent config for the Lambda Trace step counter
|
|
|
const agentMaxSteps = (() => {
|
|
|
const cfg = (agent?.config ?? {}) as Record<string, unknown>
|
|
|
@@ -1316,6 +1324,8 @@ export default function Chat() {
|
|
|
|
|
|
const sendMessage = useCallback(async () => {
|
|
|
if (!input.trim() || streaming || !agentId) return
|
|
|
+ // 工作区助手未绑定文件夹:不发,改为强制弹文件夹选择。
|
|
|
+ if (needsWorkDir) { setDirPickerOpen(true); return }
|
|
|
|
|
|
const userText = input.trim()
|
|
|
// Read from refs — always current, no stale-closure issue
|
|
|
@@ -1679,7 +1689,7 @@ export default function Chat() {
|
|
|
setStreaming(false)
|
|
|
abortRef.current = null
|
|
|
}
|
|
|
- }, [input, streaming, agentId, apiKey, qc])
|
|
|
+ }, [input, streaming, agentId, apiKey, qc, needsWorkDir])
|
|
|
|
|
|
// Belt-and-suspenders safety net: if the SSE stream silently drops (eg. the
|
|
|
// backend was restarted), the page would otherwise leave `streaming` stuck
|
|
|
@@ -1900,7 +1910,11 @@ export default function Chat() {
|
|
|
{dirPickerOpen && (
|
|
|
<DirPickerModal
|
|
|
initial={workDir}
|
|
|
- onClose={() => setDirPickerOpen(false)}
|
|
|
+ onClose={() => {
|
|
|
+ setDirPickerOpen(false)
|
|
|
+ // 工作区助手必须选目录:不选就关 → 退回工作台,不留无目录的死会话。
|
|
|
+ if (needsWorkDir) navigate('/dashboard')
|
|
|
+ }}
|
|
|
onSelect={(folder) => {
|
|
|
setDirPickerOpen(false)
|
|
|
if (!folder || folder === workDir) return
|
|
|
@@ -2054,14 +2068,16 @@ export default function Chat() {
|
|
|
onChange={e => setInput(e.target.value)}
|
|
|
onKeyDown={handleKeyDown}
|
|
|
placeholder={
|
|
|
- continueFromRunId
|
|
|
+ needsWorkDir
|
|
|
+ ? '请先选择工作文件夹再开始对话…'
|
|
|
+ : continueFromRunId
|
|
|
? '继续此 run — 输入下一步指令…(Enter 发送)'
|
|
|
: isDesktop
|
|
|
? '描述你的研究任务…(Enter 发送,Shift+Enter 换行)'
|
|
|
: '发消息… (Enter 发送,Shift+Enter 换行)'
|
|
|
}
|
|
|
rows={1}
|
|
|
- disabled={streaming}
|
|
|
+ disabled={streaming || needsWorkDir}
|
|
|
className={clsx(
|
|
|
'flex-1 resize-none rounded-xl border px-4 py-3 text-sm focus:outline-none focus:ring-2 disabled:bg-gray-50 max-h-40 leading-relaxed transition-colors',
|
|
|
continueFromRunId
|
|
|
@@ -2082,6 +2098,7 @@ export default function Chat() {
|
|
|
onClick={sendMessage}
|
|
|
disabled={
|
|
|
!input.trim() ||
|
|
|
+ needsWorkDir ||
|
|
|
// Edit mode requires a chosen sub-agent.
|
|
|
(!!continueFromRunId && mode === 'edit' && !targetSubagent)
|
|
|
}
|