ai写作默认模型
This commit is contained in:
1 parent
8bdbf6ab15
commit
dab6ecbf9a
8 files changed
+111
-158
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { PenLine } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { getBackendBaseURL } from '@/core/config';
|
||||
import { apiFetch } from '@/core/api';
|
||||
import { useModels } from '@/core/models/hooks';
|
||||
|
||||
import type { AIWritingRequest } from '../../types/ai-writing';
|
||||
import { useArticleTypes } from '../../hooks/useArticleTypes';
|
||||
@@ -23,11 +22,6 @@ interface AIWritingFormProps {
|
||||
hideAdvancedFields?: boolean;
|
||||
}
|
||||
|
||||
interface ModelOption {
|
||||
name: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
const INPUT_CLASS =
|
||||
'flex h-12 w-full rounded-xl border border-[#e8dedd] bg-white px-4 py-2 text-sm shadow-sm ' +
|
||||
'placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 ' +
|
||||
@@ -52,10 +46,24 @@ export function AIWritingForm({
|
||||
const [wordCountInput, setWordCountInput] = useState('800');
|
||||
const [strictMode, setStrictMode] = useState(false);
|
||||
const [modelName, setModelName] = useState('');
|
||||
const [models, setModels] = useState<ModelOption[]>([]);
|
||||
const { models, isLoading: modelsLoading } = useModels();
|
||||
|
||||
const { articleTypes, loading: typesLoading, refresh: refreshTypes } = useArticleTypes();
|
||||
|
||||
// 首次 /api/models 返回后默认选第一项;配置变更导致当前值不在列表时也回退到首项。
|
||||
useEffect(() => {
|
||||
if (models.length === 0) return;
|
||||
const stillExists = models.some((m) => m.name === modelName);
|
||||
if (!modelName || !stillExists) {
|
||||
setModelName(models[0].name);
|
||||
}
|
||||
}, [models, modelName]);
|
||||
|
||||
const selectedModel = useMemo(
|
||||
() => models.find((m) => m.name === modelName) ?? models[0],
|
||||
[models, modelName],
|
||||
);
|
||||
|
||||
// 初始化时加载文章类型
|
||||
useEffect(() => {
|
||||
refreshTypes();
|
||||
@@ -81,25 +89,6 @@ export function AIWritingForm({
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
apiFetch(`${getBackendBaseURL()}/api/models`)
|
||||
.then((r) => r.json())
|
||||
.then((data) => {
|
||||
const list: ModelOption[] = (data.models ?? []).map(
|
||||
(m: { name: string; display_name?: string }) => ({
|
||||
name: m.name,
|
||||
displayName: m.display_name || m.name,
|
||||
}),
|
||||
);
|
||||
setModels(list);
|
||||
if (list.length > 0 && !modelName) {
|
||||
setModelName(list[0].name);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
function handleWordCountBlur() {
|
||||
const num = parseInt(wordCountInput, 10);
|
||||
if (isNaN(num) || num < 100) {
|
||||
@@ -122,7 +111,7 @@ export function AIWritingForm({
|
||||
wordCountTarget: wordCount,
|
||||
keywordCount: DEFAULT_KEYWORD_COUNT,
|
||||
writingMode: hideAdvancedFields ? 'loose' : strictMode ? 'strict' : 'loose',
|
||||
modelName: modelName || undefined,
|
||||
modelName: selectedModel?.name || modelName || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,17 +181,25 @@ export function AIWritingForm({
|
||||
<div className="mt-4 space-y-2">
|
||||
<label className={FIELD_LABEL_CLASS}>写作模型</label>
|
||||
<Select
|
||||
value={modelName}
|
||||
value={selectedModel?.name ?? ''}
|
||||
onValueChange={setModelName}
|
||||
disabled={disabled || models.length === 0}
|
||||
disabled={disabled || modelsLoading || models.length === 0}
|
||||
>
|
||||
<SelectTrigger className={FIELD_TRIGGER_CLASS}>
|
||||
<SelectValue placeholder={models.length > 0 ? '选择模型…' : '模型加载中…'} />
|
||||
<SelectValue
|
||||
placeholder={
|
||||
modelsLoading
|
||||
? '模型加载中…'
|
||||
: models.length > 0
|
||||
? '选择模型…'
|
||||
: '暂无可用模型'
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{models.map((m) => (
|
||||
<SelectItem key={m.name} value={m.name} className="text-sm">
|
||||
{m.displayName}
|
||||
{m.display_name || m.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface StreamRecommendResult {
|
||||
* `done` → picks parsed and validated, ready to populate the dialog as
|
||||
* default-checked selections.
|
||||
* `asking` → recommender failed to emit a usable [RECOMMEND_READY] block,
|
||||
* caller should apply its fallback list (typically the 6 roundtable-* seats).
|
||||
* caller should pick from the live candidate pool as fallback.
|
||||
* `error` → upstream / network failure.
|
||||
*/
|
||||
status: "done" | "asking" | "error";
|
||||
|
||||
@@ -62,20 +62,6 @@ export interface RecommendAgentsDialogProps {
|
||||
const MIN_SELECTED = 2;
|
||||
const MAX_SELECTED = 8;
|
||||
|
||||
/**
|
||||
* Default selection when the recommender fails or returns < 2 valid picks.
|
||||
* Intersected with the live candidate pool at runtime so missing built-ins
|
||||
* don't break the dialog.
|
||||
*/
|
||||
const FALLBACK_AGENT_IDS = [
|
||||
"roundtable-intelligence",
|
||||
"roundtable-environment",
|
||||
"roundtable-solution-design",
|
||||
"roundtable-risk-review",
|
||||
"roundtable-execution-plan",
|
||||
"roundtable-summary",
|
||||
];
|
||||
|
||||
type DialogPhase =
|
||||
| "idle"
|
||||
| "loading_agents"
|
||||
@@ -319,12 +305,17 @@ export function RecommendAgentsDialog({
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: status === "asking" or picks too few. Use the 6 built-in
|
||||
// roundtable seats, intersected against the live pool.
|
||||
const fallback = intersectInOrder(FALLBACK_AGENT_IDS, candidates);
|
||||
const seed = fallback.length >= MIN_SELECTED
|
||||
? fallback
|
||||
: candidates.slice(0, MIN_SELECTED).map((c) => c.agent_id);
|
||||
// Fallback: status === "asking" or picks too few — pick from live pool.
|
||||
const seed = candidates.slice(0, MIN_SELECTED).map((c) => c.agent_id);
|
||||
if (seed.length < MIN_SELECTED) {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
phase: "error",
|
||||
streamPhase: null,
|
||||
errorMessage: `候选智能体不足 ${MIN_SELECTED} 个,无法进入圆桌研讨。请先发布更多智能体。`,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
setSelectedIds(new Set(seed));
|
||||
const { rationale } = parseRecommendStreamContent(result.content || "");
|
||||
setState((prev) => ({
|
||||
@@ -334,7 +325,7 @@ export function RecommendAgentsDialog({
|
||||
recommendedIds: seed,
|
||||
reasons,
|
||||
streamPhase: null,
|
||||
warning: "智能推荐未生成有效结果,已为你勾选默认的圆桌席位,可手动调整。",
|
||||
warning: "智能推荐未生成有效结果,已为你勾选候选池中的前几位智能体,可手动调整。",
|
||||
}));
|
||||
} catch (err) {
|
||||
if (myGen !== generationRef.current) return;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 状态全部来自 `useStep2Orchestration` —— 本组件不调任何后端、不持久化。
|
||||
*/
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Cpu,
|
||||
FileIcon,
|
||||
@@ -89,8 +89,8 @@ export interface Step2PanelProps {
|
||||
// ─── Handlers ─────────────────────────────────────────────────
|
||||
onPauseRoundtable: () => void;
|
||||
onResumeRoundtable: () => void;
|
||||
onRecordInjectMessage: () => void;
|
||||
onSubmitClarification: (answer: string) => void;
|
||||
onInjectToRoundtable: () => void;
|
||||
onSavePersona: (id: number) => void;
|
||||
onProceedToStep3: () => void;
|
||||
onTriggerToast: (msg: string) => void;
|
||||
@@ -123,8 +123,8 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
setSelectedAgentId,
|
||||
onPauseRoundtable,
|
||||
onResumeRoundtable,
|
||||
onRecordInjectMessage,
|
||||
onSubmitClarification,
|
||||
onInjectToRoundtable,
|
||||
onSavePersona,
|
||||
onProceedToStep3,
|
||||
onTriggerToast,
|
||||
@@ -134,14 +134,24 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
const { atBottom: step2AtBottom, scrollToBottom: scrollStep2ToBottom } =
|
||||
useAutoScroll(step2ScrollRef, [step2RoundtableDialogues]);
|
||||
|
||||
// 干预研审 → 暂停会商联动反馈:点击「干预研审」瞬间让右上角按钮高亮闪烁,
|
||||
// 让用户清楚看到状态已切换到「恢复会商」。
|
||||
// 干预研审 → 暂停会商:与右上角按钮共用 onPauseRoundtable;乐观 UI 避免等父 state 刷新。
|
||||
const [pauseFlash, setPauseFlash] = useState(false);
|
||||
const [optimisticPaused, setOptimisticPaused] = useState(false);
|
||||
const showPausedUi = !isRoundTableRunning || optimisticPaused;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRoundTableRunning) {
|
||||
setOptimisticPaused(false);
|
||||
}
|
||||
}, [isRoundTableRunning]);
|
||||
|
||||
const handleInject = useCallback(() => {
|
||||
onInjectToRoundtable();
|
||||
setOptimisticPaused(true);
|
||||
onPauseRoundtable();
|
||||
onRecordInjectMessage();
|
||||
setPauseFlash(true);
|
||||
window.setTimeout(() => setPauseFlash(false), 1600);
|
||||
}, [onInjectToRoundtable]);
|
||||
}, [onPauseRoundtable, onRecordInjectMessage]);
|
||||
|
||||
const isSandboxStreaming =
|
||||
isOrchestrating ||
|
||||
@@ -186,16 +196,7 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{isRoundTableRunning ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onPauseRoundtable}
|
||||
className="bg-amber-100 hover:bg-amber-200 text-amber-800 text-[10px] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-amber-200/40 shadow-sm"
|
||||
>
|
||||
<Pause className="w-3.5 h-3.5" />
|
||||
暂停会商
|
||||
</button>
|
||||
) : (
|
||||
{showPausedUi ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onResumeRoundtable}
|
||||
@@ -208,6 +209,15 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
<Play className="w-3.5 h-3.5 fill-emerald-800" />
|
||||
恢复会商
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onPauseRoundtable}
|
||||
className="bg-amber-100 hover:bg-amber-200 text-amber-800 text-[10px] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-amber-200/40 shadow-sm"
|
||||
>
|
||||
<Pause className="w-3.5 h-3.5" />
|
||||
暂停会商
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -342,8 +352,9 @@ export function Step2Panel(props: Step2PanelProps) {
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleInject}
|
||||
title="发送干预指令并暂停会商;点击右上角「恢复会商」继续执行"
|
||||
title="暂停会商并记录干预指令;点击右上角「恢复会商」继续执行"
|
||||
className="bg-primary hover:bg-[var(--brand-900)] text-white text-xs font-bold px-4 py-2.5 rounded-xl transition shrink-0 cursor-pointer active:scale-95 shadow-md shadow-primary/10"
|
||||
>
|
||||
干预研审
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
type ThreadIdMap,
|
||||
} from "@/roundtable-planning/api/multi-agent";
|
||||
import {
|
||||
DEFAULT_SELECTED_AGENTS,
|
||||
MAX_CYCLES,
|
||||
buildAgentNameToRole,
|
||||
buildRoleTemplates,
|
||||
@@ -99,18 +98,8 @@ export type Step2Snapshot = {
|
||||
seatStubMessages: Record<string, StubAiMessage[]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* 6 个默认席位的初始 Persona 配置。model 留空 → 运行时 `agentConfigs[seat]?.model
|
||||
* || selectedModel || undefined`,即「席位覆盖优先,否则跟随全局模型」。
|
||||
*/
|
||||
const DEFAULT_AGENT_CONFIGS: Record<number, AgentConfig> = {
|
||||
2: { model: "", weight: 90, temp: 0.2, prompt: "你负责解析核心任务、资源极限和用户目标偏好,监督全局研商收敛。" },
|
||||
3: { model: "", weight: 85, temp: 0.3, prompt: "你负责搜集电力、通信系统、历史极端部署条件情报,支持备灾架构体系。" },
|
||||
4: { model: "", weight: 88, temp: 0.1, prompt: "你评估服务器机房热载荷、算力并发承载极限,预报运行瓶颈与风险时钟。" },
|
||||
5: { model: "", weight: 92, temp: 0.4, prompt: "你负责双全栈主备建模设计,高内聚低耦合,规避不可预知停机崩溃。" },
|
||||
6: { model: "", weight: 95, temp: 0.1, prompt: "你作为安全主管,严厉把控预算开销与合规通过率防线,识别计划漏洞。" },
|
||||
7: { model: "", weight: 80, temp: 0.4, prompt: "你负责对72小时里程碑执行路径规划、重排和资源调配演练序列。" },
|
||||
};
|
||||
/** 席位 Persona 配置;初始为空,用户在 Persona 抽屉保存后写入。 */
|
||||
const DEFAULT_AGENT_CONFIGS: Record<number, AgentConfig> = {};
|
||||
|
||||
export interface UseStep2OrchestrationOptions {
|
||||
/** 当前页面 currentStep,===2 触发自动 init。 */
|
||||
@@ -175,9 +164,11 @@ export interface UseStep2OrchestrationReturn {
|
||||
pauseRoundtable: () => void;
|
||||
/** 与 Step2Panel「恢复会商」按钮相同 —— 恢复自动研讨(含待处理的干预指令)。 */
|
||||
resumeRoundtable: () => void;
|
||||
/** 记录干预指令(不暂停);通常由 Step2Panel 在 pauseRoundtable 之后调用。 */
|
||||
recordInjectMessage: () => void;
|
||||
/** 中断所有 in-flight SSE(给新建任务 / 加载草稿用)。 */
|
||||
abortAllInFlight: () => void;
|
||||
/** 用户「干预研审」—— 先暂停会商,干预指令在恢复后执行。 */
|
||||
/** @deprecated 请用 pauseRoundtable + recordInjectMessage;保留兼容组合调用。 */
|
||||
handleInjectToRoundtable: () => void;
|
||||
/** 总控澄清回复 —— 把回答拼到 prompt 里再起一轮编排。 */
|
||||
submitClarification: (rawAnswer: string) => void;
|
||||
@@ -251,9 +242,7 @@ export function useStep2Orchestration(
|
||||
Record<string, StubAiMessage[]>
|
||||
>({});
|
||||
const seatStubMessagesRef = useRef<Record<string, StubAiMessage[]>>({});
|
||||
const [selectedAgents, setSelectedAgents] = useState<SelectedAgent[]>(
|
||||
DEFAULT_SELECTED_AGENTS,
|
||||
);
|
||||
const [selectedAgents, setSelectedAgents] = useState<SelectedAgent[]>([]);
|
||||
const [threadIds, setThreadIds] = useState<ThreadIdMap | null>(null);
|
||||
const [coordinatorName, setCoordinatorName] = useState<string | null>(null);
|
||||
const [isInitializing, setIsInitializing] = useState<boolean>(false);
|
||||
@@ -1151,6 +1140,7 @@ export function useStep2Orchestration(
|
||||
|
||||
const pauseRoundtable = useCallback(() => {
|
||||
setIsRoundTableRunning(false);
|
||||
orchestrationCancelRef.current = true;
|
||||
stopOrchestration();
|
||||
triggerToast("⏸️ 会商已暂停");
|
||||
}, [stopOrchestration, triggerToast]);
|
||||
@@ -1160,29 +1150,29 @@ export function useStep2Orchestration(
|
||||
triggerToast("▶️ 恢复大模型并行博弈与推理决策");
|
||||
}, [triggerToast]);
|
||||
|
||||
// ─── Public handlers ─────────────────────────────────────────────
|
||||
const handleInjectToRoundtable = useCallback(() => {
|
||||
if (!customAgentInput.trim()) return;
|
||||
const recordInjectMessage = useCallback(() => {
|
||||
const userText = customAgentInput.trim();
|
||||
if (!userText) return;
|
||||
if (!threadIdsRef.current || !coordinatorNameRef.current) {
|
||||
triggerToast("⚠️ 圆桌尚未就绪,请稍候");
|
||||
triggerToast("⚠️ 圆桌尚未就绪,无法记录干预指令");
|
||||
return;
|
||||
}
|
||||
|
||||
const userText = customAgentInput.trim();
|
||||
setCustomAgentInput("");
|
||||
|
||||
// 与右上角「暂停会商」完全相同的挂起逻辑。
|
||||
pauseRoundtable();
|
||||
|
||||
appendDialogue({
|
||||
sender: "用户 (插话干预)",
|
||||
avatarType: "human",
|
||||
content: `💡 (人工指令介入) ${userText}`,
|
||||
confidence: "最高指令",
|
||||
});
|
||||
|
||||
pendingInjectPromptRef.current = `用户人工干预新指令:${userText}\n\n请结合当前讨论状态,决定是否继续派活或直接给出更新后的结论。`;
|
||||
}, [appendDialogue, customAgentInput, pauseRoundtable, triggerToast]);
|
||||
triggerToast("干预指令已记录,点击「恢复会商」后执行");
|
||||
}, [appendDialogue, customAgentInput, triggerToast]);
|
||||
|
||||
const handleInjectToRoundtable = useCallback(() => {
|
||||
pauseRoundtable();
|
||||
recordInjectMessage();
|
||||
}, [pauseRoundtable, recordInjectMessage]);
|
||||
|
||||
const submitClarification = useCallback(
|
||||
(rawAnswer: string) => {
|
||||
@@ -1376,6 +1366,7 @@ export function useStep2Orchestration(
|
||||
stopOrchestration,
|
||||
pauseRoundtable,
|
||||
resumeRoundtable,
|
||||
recordInjectMessage,
|
||||
abortAllInFlight,
|
||||
handleInjectToRoundtable,
|
||||
submitClarification,
|
||||
|
||||
@@ -24,23 +24,7 @@ export type RoleEntry = {
|
||||
/** 用户在推荐弹窗选定的一个研讨席位。 */
|
||||
export type SelectedAgent = { agent_id: string; name: string };
|
||||
|
||||
/**
|
||||
* 6 个内置 roundtable 席位的展示元数据。用户保留默认席位时,
|
||||
* 头像 / 配色 / 中文显示名都按这里走;非内置(用户自建)走 FALLBACK_AVATAR_TYPES。
|
||||
*/
|
||||
export const BUILTIN_AGENT_META: Record<
|
||||
string,
|
||||
{ avatarType: string; displayName: string }
|
||||
> = {
|
||||
"roundtable-intelligence": { avatarType: "purple", displayName: "情报收集" },
|
||||
"roundtable-environment": { avatarType: "emerald", displayName: "环境评估" },
|
||||
"roundtable-solution-design": { avatarType: "human", displayName: "方案设计" },
|
||||
"roundtable-risk-review": { avatarType: "amber", displayName: "风险审查" },
|
||||
"roundtable-execution-plan": { avatarType: "pink", displayName: "执行规划" },
|
||||
"roundtable-summary": { avatarType: "blue", displayName: "总结陈述" },
|
||||
};
|
||||
|
||||
/** 非内置 agent 的头像配色轮换池。 */
|
||||
/** 研讨席位的头像配色轮换池。 */
|
||||
export const FALLBACK_AVATAR_TYPES = [
|
||||
"blue",
|
||||
"purple",
|
||||
@@ -49,28 +33,12 @@ export const FALLBACK_AVATAR_TYPES = [
|
||||
"pink",
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* 用户未确认推荐弹窗时,Step 2 默认使用的 6 个内置席位。
|
||||
* 保留默认时页面与原硬编码行为完全一致。
|
||||
*/
|
||||
export const DEFAULT_SELECTED_AGENTS: SelectedAgent[] = [
|
||||
{ agent_id: "roundtable-summary", name: "总结陈述" },
|
||||
{ agent_id: "roundtable-intelligence", name: "情报收集" },
|
||||
{ agent_id: "roundtable-environment", name: "环境评估" },
|
||||
{ agent_id: "roundtable-solution-design", name: "方案设计" },
|
||||
{ agent_id: "roundtable-risk-review", name: "风险审查" },
|
||||
{ agent_id: "roundtable-execution-plan", name: "执行规划" },
|
||||
];
|
||||
|
||||
export function getAvatarTypeFor(agentId: string, index: number): string {
|
||||
return (
|
||||
BUILTIN_AGENT_META[agentId]?.avatarType ??
|
||||
FALLBACK_AVATAR_TYPES[index % FALLBACK_AVATAR_TYPES.length]
|
||||
);
|
||||
export function getAvatarTypeFor(_agentId: string, index: number): string {
|
||||
return FALLBACK_AVATAR_TYPES[index % FALLBACK_AVATAR_TYPES.length];
|
||||
}
|
||||
|
||||
export function getDisplayNameFor(agent: SelectedAgent): string {
|
||||
return BUILTIN_AGENT_META[agent.agent_id]?.displayName ?? agent.name;
|
||||
return agent.name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,7 +62,6 @@ import {
|
||||
import { useStep2Orchestration } from "@/roundtable-planning/hooks/useStep2Orchestration";
|
||||
import { useDraftPersistence } from "@/roundtable-planning/hooks/useDraftPersistence";
|
||||
import {
|
||||
BUILTIN_AGENT_META,
|
||||
getAvatarTypeFor,
|
||||
getDisplayNameFor,
|
||||
makeRolesFromTemplates,
|
||||
@@ -260,8 +259,7 @@ export default function RoundtablePlanningPage() {
|
||||
(agents: Array<{ agent_id: string; name: string }>) => {
|
||||
const normalized: SelectedAgent[] = agents.map(({ agent_id, name }) => ({
|
||||
agent_id,
|
||||
// 内置 agent 走 BUILTIN_AGENT_META;非内置用候选池传过来的 name。
|
||||
name: BUILTIN_AGENT_META[agent_id]?.displayName ?? name ?? agent_id,
|
||||
name: name ?? agent_id,
|
||||
}));
|
||||
step2.setSelectedAgents(normalized);
|
||||
step2.resetInitGate();
|
||||
@@ -498,12 +496,12 @@ export default function RoundtablePlanningPage() {
|
||||
openArtifactPreview={step2.openArtifactPreview}
|
||||
onPauseRoundtable={step2.pauseRoundtable}
|
||||
onResumeRoundtable={step2.resumeRoundtable}
|
||||
onRecordInjectMessage={step2.recordInjectMessage}
|
||||
setClarificationDraft={step2.setClarificationDraft}
|
||||
setCustomAgentInput={step2.setCustomAgentInput}
|
||||
setAgentConfigs={step2.setAgentConfigs}
|
||||
setSelectedAgentId={step2.setSelectedAgentId}
|
||||
onSubmitClarification={step2.submitClarification}
|
||||
onInjectToRoundtable={step2.handleInjectToRoundtable}
|
||||
onSavePersona={step2.handleSaveAgentAndRecalculate}
|
||||
onProceedToStep3={() => {
|
||||
if (!step2.hasConsensus) {
|
||||
@@ -895,9 +893,7 @@ function LeftSidebar({
|
||||
...selectedAgents.map((agent, i) => ({
|
||||
id: agent.agent_id,
|
||||
name: getDisplayNameFor(agent),
|
||||
role: BUILTIN_AGENT_META[agent.agent_id]
|
||||
? `${BUILTIN_AGENT_META[agent.agent_id].displayName} 席位`
|
||||
: "圆桌席位",
|
||||
role: "圆桌席位",
|
||||
icon: getAvatar(getAvatarTypeFor(agent.agent_id, i), "h-7 w-7"),
|
||||
})),
|
||||
].map((contrib, idx) => (
|
||||
|
||||
@@ -406,7 +406,7 @@ RECOMMENDER_AGENT_SOUL = """# 智能体推荐专员
|
||||
|
||||
> 以下两个示例覆盖**不同任务类型**,目的是教你「思路要呼应任务本身」,**不要**把任何一个示例的具体职能链当模板。
|
||||
|
||||
### 示例 A:合规改造任务(职能型候选池)
|
||||
### 示例 A:合规改造任务(领域候选池)
|
||||
|
||||
**用户输入**:
|
||||
```
|
||||
@@ -415,12 +415,11 @@ RECOMMENDER_AGENT_SOUL = """# 智能体推荐专员
|
||||
关键假设:现有系统具备基础数字化能力;允许预定窗口停机
|
||||
|
||||
候选智能体池:
|
||||
- roundtable-intelligence (情报收集):检索同类历史案例、行业最佳实践与外部情报
|
||||
- roundtable-environment (环境评估):评估硬件容量与系统量化承载力
|
||||
- roundtable-solution-design (方案设计):产出主备方案与关键路径
|
||||
- roundtable-risk-review (风险审查):合规红线检查与收敛建议
|
||||
- roundtable-execution-plan (执行规划):里程碑与资源排布
|
||||
- roundtable-summary (总结陈述):归纳冲突标记与盖印
|
||||
- compliance-research (合规调研):检索同类历史案例、行业最佳实践与监管口径
|
||||
- infra-capacity (基础设施评估):评估硬件容量与系统量化承载力
|
||||
- solution-architect (方案架构):产出主备方案与关键路径
|
||||
- risk-auditor (风险审查):合规红线检查与收敛建议
|
||||
- execution-planner (执行规划):里程碑与资源排布
|
||||
- my-cost-calc (成本测算):基于预算和资源单价计算总成本
|
||||
```
|
||||
|
||||
@@ -431,10 +430,10 @@ RECOMMENDER_AGENT_SOUL = """# 智能体推荐专员
|
||||
```json
|
||||
{
|
||||
"picks": [
|
||||
{"agent_id": "roundtable-intelligence", "reason": "检索同类等保 2.0 改造案例与监管口径,直接支撑本次合规对标"},
|
||||
{"agent_id": "roundtable-solution-design", "reason": "在 6 个月工期约束下产出主备改造方案与关键路径"},
|
||||
{"agent_id": "roundtable-risk-review", "reason": "对照等保 2.0 合规红线审查方案,避免后期返工"},
|
||||
{"agent_id": "roundtable-execution-plan", "reason": "把改造拆成可在 6 个月内交付的里程碑与资源排布"},
|
||||
{"agent_id": "compliance-research", "reason": "检索同类等保 2.0 改造案例与监管口径,直接支撑本次合规对标"},
|
||||
{"agent_id": "solution-architect", "reason": "在 6 个月工期约束下产出主备改造方案与关键路径"},
|
||||
{"agent_id": "risk-auditor", "reason": "对照等保 2.0 合规红线审查方案,避免后期返工"},
|
||||
{"agent_id": "execution-planner", "reason": "把改造拆成可在 6 个月内交付的里程碑与资源排布"},
|
||||
{"agent_id": "my-cost-calc", "reason": "校验整体方案落在 500 万元预算硬约束内"}
|
||||
]
|
||||
}
|
||||
@@ -453,7 +452,7 @@ RECOMMENDER_AGENT_SOUL = """# 智能体推荐专员
|
||||
- channel-planner (渠道规划师):按预算和受众设计跨平台投放组合
|
||||
- audience-insight (受众洞察):画像、关键词、情绪点研究
|
||||
- creative-copy (创意文案):产出落地页与社媒文案变体
|
||||
- roundtable-risk-review (风险审查):合规红线检查与收敛建议
|
||||
- ad-compliance (广告合规):审查文案与素材合规风险
|
||||
```
|
||||
|
||||
**你的输出**:
|
||||
@@ -471,8 +470,8 @@ RECOMMENDER_AGENT_SOUL = """# 智能体推荐专员
|
||||
}
|
||||
```
|
||||
|
||||
> **关键观察**:示例 A 选了 `roundtable-intelligence / solution-design / execution-plan` 等"职能型"智能体,示例 B **完全没用任何 `roundtable-*` 内置**,而是从用户自建的领域智能体里挑。
|
||||
> 这是因为:**候选池里的智能体能不能匹配任务,只看 description 和任务的实际语义,不看 id 是不是 `roundtable-` 开头**。如果候选池里有"广告设计智能体"且任务是广告设计,**你必须挑它**,而不是套用示例 A 的职能链。
|
||||
> **关键观察**:两个示例都从候选池里按任务语义挑选,**不要**套用固定职能链(如"调研→设计→风险→执行")。
|
||||
> 候选池里的智能体能不能匹配任务,只看 description 和任务的实际语义。如果候选池里有"广告设计智能体"且任务是广告设计,**你必须挑它**,而不是机械复制示例 A 的链路。
|
||||
"""
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user