feat: refine mobile master agent sync and chat rendering
This commit is contained in:
@@ -25,6 +25,7 @@ import type {
|
||||
ThreadConversationExecutionConflict,
|
||||
ThreadConversationExecutionConflictAction,
|
||||
} from "@/lib/thread-execution-conflict";
|
||||
import { parseChatMarkdown, type ChatMarkdownBlock } from "@/lib/chat-markdown";
|
||||
import {
|
||||
describeThreadConversationExecutionConflict,
|
||||
labelForProjectConflictAllowPolicy,
|
||||
@@ -907,13 +908,101 @@ export function ChatBubble({ message }: { message: Message }) {
|
||||
{tag ? (
|
||||
<div className="mb-2 text-[11px] font-semibold opacity-80">{tag}</div>
|
||||
) : null}
|
||||
{message.body}
|
||||
<ChatBubbleMarkdown body={message.body} mine={mine} green={green} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ChatBubbleMarkdown({
|
||||
body,
|
||||
mine,
|
||||
green,
|
||||
}: {
|
||||
body: string;
|
||||
mine: boolean;
|
||||
green: boolean;
|
||||
}) {
|
||||
const blocks = parseChatMarkdown(body);
|
||||
|
||||
return (
|
||||
<div className="space-y-2 break-words">
|
||||
{blocks.map((block, index) => (
|
||||
<ChatMarkdownBlockView key={`${block.kind}-${index}`} block={block} mine={mine} green={green} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ChatMarkdownBlockView({
|
||||
block,
|
||||
mine,
|
||||
green,
|
||||
}: {
|
||||
block: ChatMarkdownBlock;
|
||||
mine: boolean;
|
||||
green: boolean;
|
||||
}) {
|
||||
const mutedClass = mine ? "text-white/82" : green ? "text-[#4E7A60]" : "text-[#57606A]";
|
||||
const markerClass = mine ? "text-white/72" : green ? "text-[#44A064]" : "text-[#8C8C8C]";
|
||||
|
||||
switch (block.kind) {
|
||||
case "heading":
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"font-semibold leading-6",
|
||||
block.level === 1 ? "text-[16px]" : block.level === 2 ? "text-[15px]" : "text-[14px]",
|
||||
)}
|
||||
>
|
||||
{block.text}
|
||||
</div>
|
||||
);
|
||||
case "label":
|
||||
return (
|
||||
<div className="rounded-2xl bg-black/[0.035] px-3 py-2">
|
||||
<div className={clsx("text-[12px] font-semibold", markerClass)}>{block.label}</div>
|
||||
<div className="mt-1 whitespace-pre-wrap text-[14px] leading-6">{block.text}</div>
|
||||
</div>
|
||||
);
|
||||
case "bullet":
|
||||
return (
|
||||
<div className="flex gap-2 leading-6">
|
||||
<span className={markerClass}>•</span>
|
||||
<span className="min-w-0 flex-1">{block.text}</span>
|
||||
</div>
|
||||
);
|
||||
case "ordered":
|
||||
return (
|
||||
<div className="flex gap-2 leading-6">
|
||||
<span className={clsx("tabular-nums", markerClass)}>{block.order}</span>
|
||||
<span className="min-w-0 flex-1">{block.text}</span>
|
||||
</div>
|
||||
);
|
||||
case "quote":
|
||||
return (
|
||||
<div className={clsx("border-l-2 pl-3 text-[14px] leading-6", mine ? "border-white/50" : "border-[#D8DEE4]", mutedClass)}>
|
||||
{block.text}
|
||||
</div>
|
||||
);
|
||||
case "code":
|
||||
return (
|
||||
<pre
|
||||
className={clsx(
|
||||
"overflow-x-auto rounded-2xl px-3 py-2 text-[12px] leading-5",
|
||||
mine ? "bg-white/16 text-white" : "bg-[#F2F3F5] text-[#24292F]",
|
||||
)}
|
||||
>
|
||||
<code>{block.text}</code>
|
||||
</pre>
|
||||
);
|
||||
case "paragraph":
|
||||
default:
|
||||
return <div className="whitespace-pre-wrap leading-6">{block.text}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export function ProjectHeaderActions({ projectId }: { projectId: string }) {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
UserMasterPrompt,
|
||||
} from "@/lib/boss-data";
|
||||
import type { MasterAgentChatPageAnchors } from "@/lib/master-agent-chat-menu";
|
||||
import { getMasterAgentModelOptions } from "@/lib/master-agent-model-options";
|
||||
import { formatTimestampLabel } from "@/lib/boss-projections";
|
||||
|
||||
type MemoryDraft = {
|
||||
@@ -191,6 +192,7 @@ export function MasterAgentPromptMemoryClient({
|
||||
});
|
||||
|
||||
const allMemories = useMemo(() => [...projectMemories, ...globalMemories], [projectMemories, globalMemories]);
|
||||
const modelOptions = useMemo(() => getMasterAgentModelOptions(modelOverride), [modelOverride]);
|
||||
const promptPreview = useMemo(() => {
|
||||
const sections = [
|
||||
globalPrompt.trim() ? `【管理员全局主提示词】\n${globalPrompt.trim()}` : null,
|
||||
@@ -431,9 +433,11 @@ export function MasterAgentPromptMemoryClient({
|
||||
className="w-full rounded-xl border border-[#E5E5EA] bg-[#F7F8FA] px-3 py-2 text-[13px] text-[#111111] outline-none"
|
||||
>
|
||||
<option value="">默认</option>
|
||||
<option value="gpt-5.4">gpt-5.4</option>
|
||||
<option value="gpt-4.1">gpt-4.1</option>
|
||||
<option value="gpt-4.1-mini">gpt-4.1-mini</option>
|
||||
{modelOptions.map((option) => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label id={anchors.reasoningEffort.split("#")[1]} className="space-y-1 scroll-mt-4">
|
||||
|
||||
Reference in New Issue
Block a user