diff --git a/.project-docs/30-worklog/tasks/20261012-agent-chat-polish-9f43c8a2.md b/.project-docs/30-worklog/tasks/20261012-agent-chat-polish-9f43c8a2.md new file mode 100644 index 00000000..b1ccd616 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20261012-agent-chat-polish-9f43c8a2.md @@ -0,0 +1,78 @@ +# Task: Polish personal Agent conversations and update combined trial + +## Identity + +- Task ID: 20261012-agent-chat-polish-9f43c8a2 +- Mode: Feature +- Branch: codex/20261012-agent-chat-polish-9f43c8a2-agent-chat-polish +- Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore/20261012-agent-chat-polish-9f43c8a2 +- Base commit: 1aef423df0320cf946600af8ff44fa469f637c2b +- Owner: codex +- Status: Ready for Integration + +## Scope + +- Polish personal Agent conversation layout, welcome, message roles, toolbar, files and composer using the existing Makelore light/cream/pastel visual system. Combine chat-only adjustment action into the conversation-source row to reduce duplicate navigation; include completed entry-nav refinements from base. Latest user steering cancels the trial update; finish code and checks only. Current trial stays unchanged. + +## Intent And Constraints + +- User requests product-language communication and chat polish. Initially requested a combined trial update, then explicitly said “不用更新临时应用”; that newer constraint is authoritative. Preserve all message text, Markdown, attachment, history, approval, new-thread, stop, queue, replay/recovery and draft-leave guards. Main/WS/Yuxi identity, billing and execution remain authoritative. Styling is scoped to personal CloudChat and its workspace shell; Code/teacher and WeChat protocols unchanged. Opening or example selection does not submit. No real cloud mutation/model call during verification; manual login after restart remains with user. + +## Project Context Loaded + +Task context: +- Task ID: 20261012-agent-chat-polish-9f43c8a2; mode Feature; owner codex. +- Branch: codex/20261012-agent-chat-polish-9f43c8a2-agent-chat-polish. +- Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore/20261012-agent-chat-polish-9f43c8a2. +- Base: 1aef423df0320cf946600af8ff44fa469f637c2b, verified current trial source including completed entry navigation. +- Successful bundled start/status matched identity, absolute worktree, mode, branch and base. 36 other owners inspected through peer task records only; 35 concrete scopes, one undefined old child-language task with no dependency; no blocking semantic conflict. + +Read: +- AGENTS.md; 05-agent-entry/read-before-planning.md, memory-index.md, planning-gate.md and own task record. +- 00-brief/project-positioning.md, success-criteria.md; 20-architecture/community-collaboration.md; current-state integrated snapshot. +- 10-decisions/decision-index.md and full personal-cloud-agents ADR; task-relevant system-overview, business-rules and evidence/reflection/commitments indexes (unchanged canonical context retained from prior navigation task). +- Existing CloudChat/DraftEditor/files and scoped visual CSS. Design skill system search and Airbnb warm/soft consumer reference; adapt to existing project fonts/colors, no external fonts/assets or dark theme. + +Relevant understanding: +- Goal: approachable AI creation/use for students and creators; no course management or cloud-auth/billing authority in Renderer. +- Integrated current-state predates this conversation's simplified config and entry UI; current user-approved behavior in base is authoritative. +- New task is presentation polish only, plus reducing redundant chat action row. Pending operations/retries retain original identity and draft/attachment guards, server Run state remains authoritative, no decorative invented status. +- Evidence commitments distinguish fixture/local runtime from paid-provider, cloud deployment and signed installed acceptance. +- Likely modules: CloudChat, scoped agent-chat CSS, DraftEditor chat shell; focused workflow/unit/browser/Electron tests and README. +- Unknown: native trial currently awaits login; CUA clicks/screenshots have been intermittently unreliable. Real final page observation may need user navigation. Prior discard authorization does not cover new edits. + +Gate result: +- Passed. + +## Plan + +1. Apply existing cream/pastel language to personal chat welcome, message roles, readable transcript and prominent composer. +2. Combine chat-only adjustment/source controls and pass presentation identity without changing save/apply/navigation safeguards. +3. Verify focused workflows and responsive empty/history/running/approval states, build and review. +4. Record final verification and complete task ownership; do not bind, probe, launch or replace the temporary app after the latest cancellation. + +## Outcome + +- Personal chat now shares the existing cream, pastel blue/lilac/mint palette and rounded controls. Empty conversations show the current assistant portrait/name, a friendly greeting and existing example prompts; examples still only fill a draft. +- User and assistant messages have distinct presentation, assistant portraits and readable text. Long Markdown/code/tables remain complete and scroll inside their message bounds; files, history, new conversation, status, approvals, stop and send retain their behavior. +- Chat-only “调整智能体” moved into the source-control row. Saved persona data is passed as presentation props; save/apply, pending input, hidden mounts and source-switch guards are unchanged. Narrow containers wrap controls and stack examples; the composer stays visible separately from the transcript. Short chat windows hide only duplicate settled configuration status and already-disabled save/apply controls; dirty, busy, pending, conflict, error or unknown publication status restores them. Name/avatar/back/adjust/first-start remain available. +- README updated. Meaningful browser and Electron fixtures cover responsive bounds, full workspace shell, example no-submit, actual persona display, history/files/stop/approval actions and homepage re-entry. +- User cancelled trial updating before any build binding, probe, launch or replacement. A prepared, unbound app directory remains at /Users/chillishark/Makelore 麦洛/.trial-runtime/agent-chat-polish-20261012-9f43c8a2; it is not a deliverable runtime and must be rebound/rechecked if requested later. Current pointer remains Entry Trial source 1aef423df0320cf946600af8ff44fa469f637c2b, PID 63739. No real cloud draft, publish or model operation was used. + +## Verification + +- TypeScript typecheck passed. Scoped ESLint passed with zero errors and two existing CloudChat warnings (mixed component export and ref cleanup); no new warning introduced. Whitespace check passed. +- 31 Cloud Agents page unit cases passed; 26 workflow/guidance cases passed, including history, pending retries, previews, queue, approval and recovery behaviors. +- All 8 isolated real-CloudChat Chrome layout cases passed: empty at 375/768/1024/1440; long Markdown at 375×540/1440×900; narrow running Stop and short approval. Fixtures mock only Main IPC/event streams and block external browser requests. No account or model involved. +- Electron fixture passed the personal-agent create/config/save/apply/direct-chat flow, same-row source/adjust controls, persona rendering, example draft/no-submit, long transcript/composer bounds and whole-editor 980×680 at 1.5 zoom, plus homepage re-entry. The first complete native fixture screenshot exposed a zero-height transcript despite a visible composer; settled-header and compact spacing refinements restore at least 80 px of transcript in the final check. A subsequent 76 px result was corrected by reducing short-window composer/section spacing; the assertion was not weakened. Native fixture capture is used for the zoomed visual check because Chromium screenshots crop a zoomed Electron surface. +- build:vite passed for Renderer/Main/preload/utility; existing Browserslist, chunk-size and mixed-import notices only. Production-code layout reviewed in isolated fixtures, not represented as real signed installed/cloud acceptance. +- Independent read-only review found no functional regression. Its request for a complete-shell narrow/short check was addressed in Electron, in addition to CloudChat-only browser coverage. A second review confirmed the settled-header condition only hides actions that are already disabled and does not affect configuration pages or pending operations. +- Fixture screenshots retained in ignored .tmp/chat-layout-verified and .tmp/chat-electron-verified, inside this worktree. Runtime pointer observed read-only and unchanged; no live-login/navigation/visual acceptance claimed. + +## Follow-ups + +- No outstanding implementation work. Updating the temporary app requires a new user request; any future launch still needs fresh unsaved-input observation and user login. + +## Promotion Candidates + +- Integrate the scoped chat presentation and its checks alongside the completed entry-navigation base; canonical project documents were intentionally not edited in Feature mode. diff --git a/README.md b/README.md index f10d7c98..a10576b2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Makelore 是一个面向软件、视觉创作、智能机器人与个人云智 - `Makelore Code|AI 编程`:管理本地项目、项目智能体、对话、文件上下文、代码变更和运行时。 会话工作台采用浅蓝项目栏、彩色通用手柄图标与卡片选中态;中间对话/作品使用圆角标签,作品预览的后退、前进、刷新与网址输入统一放在标签右侧;只在作品页显示,窄窗口自动换行。右侧智能体咨询使用奶油色标题区。沿用真实项目和会话入口、侧栏伸缩与账户菜单,样式只作用于 Code 会话工作台。可编辑的空对话在输入区上方的可用区域中央显示童趣欢迎语;「去作品广场逛逛」入口紧贴输入框上方,两者一起位于底部。老师介绍以固定宽度浮在右上角,不占用中间布局;欢迎语和底部输入区始终相对项目栏右侧的整个内容区域居中;小窗口的欢迎内容独立滚动;发送首条消息后收起欢迎区。侧栏保留「作品广场」入口,只有点击后才在系统浏览器打开公共广场,不请求、摘取或内嵌展示广场作品。打开广场保留当前项目、对话、草稿和附件,不自动发送消息;老师求助按钮保留临时应用的最新文案「帮我整体看🧠」。 -- `Makelore Agents|AI 智能体`:从模块首页进入时先打开“我的智能体”卡片列表,保留此前对话与操作恢复记录;返回首页箭头与侧栏折叠按钮同排,折叠后仍可返回或展开,macOS 原生窗口按钮留出安全空间。首页围绕自己的智能体和创建入口,显示童趣问候“Hi,今天想创造还是想聊聊?”,不再显示更多、收到的分享、活动或归档筛选。卡片显示名称、可为空的一句话介绍及状态,支持聊天、调整、继续制作和确认删除;删除沿用云端归档机制,移出列表并停用新调用,历史和费用保留。创建先填写名称并选择平台像素头像或上传头像,下一步进入独立配置。顶部名称有编辑图标,头像可点击修改;未设置头像时使用同一张默认像素头像,从创建到配置、改名、保存和重新打开保持一致。基础页为“介绍与提示词”,一句话介绍可留空,完整提示词保留原始文本;模型作为高级设置第一项必选,未选择时不能开始使用,草稿可分步保存,不自动选模型。介绍与提示词采用浅蓝介绍卡和浅紫提示词卡;高级设置按模型、工具箱(Tool)、做事手册(Skill)、MCP 服务、子智能体和知识库纵向呈现,不再设内部分类切换;不展示 Tool/Skill 解释、云端能力管理、费用上限或运行限制卡片,保存其他配置时保留既有运行限制,费用规则不变。顶层页签切换保留搜索、资源选择、知识表单及未保存输入。配置页移除聊天、自动任务和使用与接入导航,独立聊天仍从卡片进入,微信账号仍在侧栏渠道管理。草稿明确保存(Ctrl/⌘+S);保存只更新草稿,“应用最新修改”使新配置生效,失败重试保持原操作身份;点击“开始使用”完成必要的私有启用后直接打开聊天,不再展示二次确认页;未保存修改、缺少模型、冲突或尚未确认的请求会留在配置页处理,打开聊天不自动发送消息。头像上传、Main-owned Host API、访问隔离、费用与不可变版本规则保持;介绍留空需要配套 Yuxi DraftCreate/DraftSave 的空字符串契约。 +- `Makelore Agents|AI 智能体`:从模块首页进入时先打开“我的智能体”卡片列表,保留此前对话与操作恢复记录;返回首页箭头与侧栏折叠按钮同排,折叠后仍可返回或展开,macOS 原生窗口按钮留出安全空间。首页围绕自己的智能体和创建入口,显示童趣问候“Hi,今天想创造还是想聊聊?”,不再显示更多、收到的分享、活动或归档筛选。卡片显示名称、可为空的一句话介绍及状态,支持聊天、调整、继续制作和确认删除;删除沿用云端归档机制,移出列表并停用新调用,历史和费用保留。创建先填写名称并选择平台像素头像或上传头像,下一步进入独立配置。顶部名称有编辑图标,头像可点击修改;未设置头像时使用同一张默认像素头像,从创建到配置、改名、保存和重新打开保持一致。基础页为“介绍与提示词”,一句话介绍可留空,完整提示词保留原始文本;模型作为高级设置第一项必选,未选择时不能开始使用,草稿可分步保存,不自动选模型。介绍与提示词采用浅蓝介绍卡和浅紫提示词卡;高级设置按模型、工具箱(Tool)、做事手册(Skill)、MCP 服务、子智能体和知识库纵向呈现,不再设内部分类切换;不展示 Tool/Skill 解释、云端能力管理、费用上限或运行限制卡片,保存其他配置时保留既有运行限制,费用规则不变。顶层页签切换保留搜索、资源选择、知识表单及未保存输入。配置页移除聊天、自动任务和使用与接入导航,独立聊天仍从卡片进入,微信账号仍在侧栏渠道管理。草稿明确保存(Ctrl/⌘+S);保存只更新草稿,“应用最新修改”使新配置生效,失败重试保持原操作身份;点击“开始使用”完成必要的私有启用后直接打开聊天,不再展示二次确认页;未保存修改、缺少模型、冲突或尚未确认的请求会留在配置页处理,打开聊天不自动发送消息。独立对话沿用奶油底色和浅蓝、浅紫、薄荷色:空对话展示当前智能体头像与名称,示例只填入草稿;用户消息和智能体回复区分呈现,长 Markdown、表格和代码在消息区内滚动,底部输入框、附件、停止和历史入口保留;短窗口中,配置完全生效且没有待处理问题时收起重复的已保存/已应用提示和禁用按钮,修改或待确认时恢复;“调整智能体”与客户端/微信来源同排,窄窗口会换行,未发送内容的离开保护不变。头像上传、Main-owned Host API、访问隔离、费用与不可变版本规则保持;介绍留空需要配套 Yuxi DraftCreate/DraftSave 的空字符串契约。 云知识库的 embedding 模型只由平台管理员在 Yuxi 后台维护:在「智能体管理 → 模型供应商」启用供应商,按供应商要求填写有效的服务地址和 API Key,添加并启用 embedding 模型并填写实际向量维度;embedding 向量化费用由平台承担,不计入用户用量、词元点数或智能体费用上限;one-api 不参与 embedding 配置,Works Square 只负责其他应计费模型调用的创建者词元点数账本。客户端区分目录加载中、加载失败与无可用模型,空状态提供管理员配置说明;「刷新知识库与模型」保留未提交名称,未确认的创建请求沿用原操作身份。 diff --git a/src/pages/CloudAgents/CloudChat.tsx b/src/pages/CloudAgents/CloudChat.tsx index d7732f99..2003ee3b 100644 --- a/src/pages/CloudAgents/CloudChat.tsx +++ b/src/pages/CloudAgents/CloudChat.tsx @@ -1,11 +1,13 @@ import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'; -import { History, MessageSquarePlus, Send, Square } from 'lucide-react'; +import { ArrowUpRight, History, MessageCircle, MessageSquarePlus, Send, Sparkles, Square } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { cloudAgentsApi } from '@/lib/cloud-agents-api'; import type { CloudHistory, CloudInterrupt, CloudPrompt, CloudRequest, CloudRun, CloudThread, CloudScheduleProposal } from '../../../shared/cloud-agents'; import { CloudFiles } from './CloudFiles'; +import { CloudAvatar } from './CloudAvatar'; import './desktop-workspace.css'; +import './agent-chat.css'; import ReactMarkdown, { defaultUrlTransform } from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { CloudPendingContext, useCloudPendingState, usePendingCloudInput } from './CloudPending'; @@ -21,8 +23,8 @@ const message = (e: unknown) => e instanceof Error ? e.message : '暂时无法 const object = (v: unknown): Record => v && typeof v === 'object' ? v as Record : {}; export function CloudChat({ slug, previewRevision: latestRevision, initialThread, initialThreadId, onSchedule, activeView = true, headerAction, previewReady = true, - examples = agentExamples(), hasUnsavedChanges = false, saveDisabled = false, onSaveForPreview }: { - slug: string; headerAction?: ReactNode; previewReady?: boolean; activeView?: boolean; previewRevision?: number; initialThread?: CloudThread; initialThreadId?: string; onSchedule?: (proposal: CloudScheduleProposal) => void; + assistantName = '助手', assistantAvatarUrl, examples = agentExamples(), hasUnsavedChanges = false, saveDisabled = false, onSaveForPreview }: { + slug: string; assistantName?: string; assistantAvatarUrl?: string | null; headerAction?: ReactNode; previewReady?: boolean; activeView?: boolean; previewRevision?: number; initialThread?: CloudThread; initialThreadId?: string; onSchedule?: (proposal: CloudScheduleProposal) => void; examples?: readonly string[]; hasUnsavedChanges?: boolean; saveDisabled?: boolean; onSaveForPreview?: () => Promise; }) { const [previewRevision, setPreviewRevision] = useState(latestRevision === undefined ? undefined : initialThread?.draft_revision ?? latestRevision); @@ -256,16 +258,16 @@ export function CloudChat({ slug, previewRevision: latestRevision, initialThread else if (runId) await cloudAgentsApi.call('cancelRun', { run_id: runId }); } catch (e) { setError(message(e)); } finally { setBusy(false); } }; - return
-
-
{previewRevision === undefined ? '和助手聊一聊' : '试一试'} + return
+
+

{previewRevision === undefined ? '和助手聊一聊' : '试一试'}

{previewRevision !== undefined &&

当前试用 · 修订 {previewRevision}

} -

由创建者支付词元点数{run?.version && ` · 版本 ${run.version}`}

-
- {headerAction}
+

由创建者支付词元点数{run?.version && ` · 版本 ${run.version}`}

+
+ {headerAction}
{showHistory && threads.length === 0 &&

还没有历史对话

} - {showHistory && threads.length > 0 && 0 || childrenPending.hasPending} onChange={e => void choose(threads.find(t => t.thread_id === e.target.value) ?? null)}> {threads.map(t => )} } @@ -278,23 +280,28 @@ export function CloudChat({ slug, previewRevision: latestRevision, initialThread
}
{ const el = e.currentTarget; following.current = el.scrollHeight - el.scrollTop - el.clientHeight < 64; }}>
- {loading ?

正在读取对话…

- : !history?.messages.length && !liveText &&
-

{mode === 'preview' ? '问它一个小问题' : '今天想让它帮你做什么?'}

-

{mode === 'preview' ? '看看它的回答是否符合你的要求。不满意就改一改,再试一次。' : '从下面选一句,或写下你自己的想法。'}

-
{examples.map(example => )}
-

点选只会填入输入框,由你决定何时发送。

+ onScroll={e => { const el = e.currentTarget; following.current = el.scrollHeight - el.scrollTop - el.clientHeight < 64; }}>
+ {loading ?
+ : !history?.messages.length && !liveText &&
+
+

{assistantName}

+

{mode === 'preview' ? '问它一个小问题' : 'Hi,今天想聊些什么?'}

+

{mode === 'preview' ? '看看它的回答是否符合你的要求。不满意就改一改,再试一次。' : '从下面选一句,或写下你自己的想法。'}

+
{examples.map((example, index) => )}
+

点选只会填入输入框,由你决定何时发送。

} {previousTrial &&
对比上一次试用 · 修订 {previousTrial.revision}

这是修改前的回答。用同一个问题再问一次,更容易看出变化。

- +
} - {history && } - {liveText &&
{liveText}
} + {history && } + {liveText &&
+ +

{assistantName}

{liveText}
+
} {onSchedule && history?.schedule_proposals?.map(proposal =>

自动任务建议 · {proposal.name}

{proposal.prompt}

{proposal.cron_expression} · {proposal.timezone} · 尚未启用

@@ -336,27 +343,30 @@ export function CloudChat({ slug, previewRevision: latestRevision, initialThread }} />
{leaving &&
放弃未发送的内容并新建对话?
} -
{ e.preventDefault(); void send(); }}> -