完善策划调试入口与顾问态切换
统一策划 Debug 日志、快速推进按钮和快速推进命令的开关。 将做成游戏入口放到顾问阶段条末尾并接入正常运行时切换。 登记策划产物资产并补充工作区调试入口测试与技术文档。
This commit is contained in:
@@ -21,6 +21,9 @@ const appRoot = fileURLToPath(new URL('..', import.meta.url));
|
||||
const repoRoot = resolve(appRoot, '../..');
|
||||
const tauriCliPath = resolve(repoRoot, 'node_modules/@tauri-apps/cli/tauri.js');
|
||||
const AGC_DESIGN_DEBUG_ENV = 'GENARRATIVE_AGC_DESIGN_DEBUG';
|
||||
const AGC_DESIGN_DEBUG_VITE_ENV = 'VITE_GENARRATIVE_AGC_DESIGN_DEBUG';
|
||||
const designDebugEnabled =
|
||||
process.env[AGC_DESIGN_DEBUG_ENV]?.trim() === '0' ? '0' : '1';
|
||||
|
||||
function buildTauriArguments(argv, devUrl = readAgcDevEndpoint().url) {
|
||||
const args = [...argv];
|
||||
@@ -111,7 +114,8 @@ async function runTauriDev(
|
||||
child = spawnCli(tauriArguments, {
|
||||
env: {
|
||||
...withAgcDevEndpointEnv(endpoint),
|
||||
[AGC_DESIGN_DEBUG_ENV]: '1',
|
||||
[AGC_DESIGN_DEBUG_ENV]: designDebugEnabled,
|
||||
[AGC_DESIGN_DEBUG_VITE_ENV]: designDebugEnabled,
|
||||
},
|
||||
});
|
||||
const childResult = waitForCli(child);
|
||||
@@ -161,7 +165,13 @@ async function prepareFrontendDev(endpoint, { onChild, signal }) {
|
||||
const frontend = spawnChild(
|
||||
process.platform === 'win32' ? 'npm.cmd' : 'npm',
|
||||
['run', 'agc:serve'],
|
||||
{ cwd: repoRoot, env: withAgcDevEndpointEnv(endpoint) },
|
||||
{
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...withAgcDevEndpointEnv(endpoint),
|
||||
[AGC_DESIGN_DEBUG_VITE_ENV]: designDebugEnabled,
|
||||
},
|
||||
},
|
||||
);
|
||||
onChild(frontend);
|
||||
console.log(
|
||||
|
||||
@@ -857,9 +857,86 @@ pub(crate) fn set_design_agent_runtime_mode(
|
||||
root,
|
||||
"design.runtime-mode",
|
||||
)?;
|
||||
if active_runtime.trim() == "game" {
|
||||
crate::assets::register_design_artifacts_at(root)?;
|
||||
}
|
||||
write_design_runtime_mode(root, active_runtime.trim())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn debug_fast_forward_design_session(
|
||||
app: tauri::AppHandle,
|
||||
project_path: String,
|
||||
target_phase: String,
|
||||
) -> Result<DesignRuntimeMode, String> {
|
||||
if !cfg!(debug_assertions)
|
||||
|| std::env::var("GENARRATIVE_AGC_DESIGN_DEBUG").ok().as_deref() != Some("1")
|
||||
{
|
||||
return Err("策划 Agent 快速推进仅可用于 Debug 构建".to_string());
|
||||
}
|
||||
let root = Path::new(project_path.trim());
|
||||
let project_id = design_project_id(root)?;
|
||||
let target_index = design_phase_index(target_phase.trim())?;
|
||||
let _lock = acquire_game_creator_agent_runtime_project_write_lock_with_wait(
|
||||
root,
|
||||
"design.debug-fast-forward",
|
||||
)?;
|
||||
let artifact_paths = [
|
||||
"project/00_concept/design.md",
|
||||
"project/速览卡.md",
|
||||
"project/01_top_design/design.md",
|
||||
"project/02_architecture/design.md",
|
||||
"project/03_systems/debug-system.md",
|
||||
"project/04_tdd/01_技术实现.md",
|
||||
"project/04_tdd/02_美术圣经.md",
|
||||
"project/04_tdd/03_数据与配表.md",
|
||||
"project/04_tdd/总册.md",
|
||||
];
|
||||
for relative in artifact_paths {
|
||||
let path = root.join("design_artifacts").join(relative);
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent).map_err(|error| {
|
||||
format!("创建调试策划产物目录失败:{}: {error}", parent.display())
|
||||
})?;
|
||||
}
|
||||
if !path.exists() {
|
||||
std::fs::write(
|
||||
&path,
|
||||
"# Debug Design Artifact\n\n这是生产 Runtime 快速推进测试生成的占位产物,不代表真实策划内容。\n",
|
||||
)
|
||||
.map_err(|error| format!("写入调试策划产物失败:{}: {error}", path.display()))?;
|
||||
}
|
||||
}
|
||||
let mut session =
|
||||
read_design_session(root)?.unwrap_or_else(|| new_design_session(&project_id, ""));
|
||||
session.current_phase = target_phase.trim().to_string();
|
||||
session.approved_phases = DESIGN_PHASES[..target_index]
|
||||
.iter()
|
||||
.map(|phase| phase.to_string())
|
||||
.collect();
|
||||
session.pending_approval = None;
|
||||
session.pending_clarification = None;
|
||||
session.turn = None;
|
||||
session.pending_batch = None;
|
||||
session.last_error = None;
|
||||
session.updated_at = unix_timestamp();
|
||||
write_design_session(root, &session)?;
|
||||
let mode = write_design_runtime_mode(root, "design")?;
|
||||
app.emit(
|
||||
"design-agent-update",
|
||||
design_event(
|
||||
root,
|
||||
"debug-fast-forward",
|
||||
"state",
|
||||
None,
|
||||
None,
|
||||
Some(design_view(&session, false)),
|
||||
),
|
||||
)
|
||||
.map_err(|error| format!("刷新策划调试状态失败:{error}"))?;
|
||||
Ok(mode)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn continue_design_agent_session(
|
||||
app: tauri::AppHandle,
|
||||
|
||||
@@ -533,6 +533,70 @@ pub(crate) fn register_local_asset_at(
|
||||
register_local_asset_entry(root, local_path, kind, media_type, id_prefix, source)
|
||||
}
|
||||
|
||||
pub(crate) fn register_design_artifacts_at(root: &Path) -> Result<usize, String> {
|
||||
let design_root = root.join("design_artifacts");
|
||||
if !design_root.exists() {
|
||||
return Ok(0);
|
||||
}
|
||||
let mut files = Vec::new();
|
||||
let mut directories = vec![design_root];
|
||||
while let Some(directory) = directories.pop() {
|
||||
for entry in fs::read_dir(&directory)
|
||||
.map_err(|error| format!("读取策划产物目录失败:{}: {error}", directory.display()))?
|
||||
{
|
||||
let entry = entry.map_err(|error| format!("读取策划产物失败:{error}"))?;
|
||||
let path = entry.path();
|
||||
let metadata = fs::symlink_metadata(&path)
|
||||
.map_err(|error| format!("读取策划产物元数据失败:{}: {error}", path.display()))?;
|
||||
if metadata.file_type().is_symlink() {
|
||||
continue;
|
||||
}
|
||||
if metadata.is_dir() {
|
||||
directories.push(path);
|
||||
} else if metadata.is_file() {
|
||||
files.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
files.sort();
|
||||
let mut registered = 0;
|
||||
for path in files {
|
||||
let relative = path
|
||||
.strip_prefix(root)
|
||||
.map_err(|_| "策划产物路径不在项目根目录内".to_string())?
|
||||
.to_string_lossy()
|
||||
.replace('\\', "/");
|
||||
let media_type = match path.extension().and_then(|value| value.to_str()) {
|
||||
Some("md") => "text/markdown",
|
||||
Some("txt") => "text/plain",
|
||||
Some("json") => "application/json",
|
||||
Some("yaml" | "yml") => "text/yaml",
|
||||
_ => "application/octet-stream",
|
||||
};
|
||||
register_local_asset_at(
|
||||
root,
|
||||
&relative,
|
||||
"design-document",
|
||||
media_type,
|
||||
"design-document",
|
||||
GameCreationAppAssetSource {
|
||||
kind: GameCreationAppAssetSourceKind::Uploaded,
|
||||
canvas_project_id: None,
|
||||
resource_id: None,
|
||||
asset_object_id: None,
|
||||
task_id: None,
|
||||
prompt: None,
|
||||
model: None,
|
||||
generation_route: None,
|
||||
generation_kind: None,
|
||||
reference_resource_ids: Vec::new(),
|
||||
},
|
||||
)?;
|
||||
registered += 1;
|
||||
}
|
||||
Ok(registered)
|
||||
}
|
||||
|
||||
pub(crate) fn import_canvas_asset_at(
|
||||
root: &Path,
|
||||
local_path: &str,
|
||||
|
||||
@@ -2584,6 +2584,7 @@ fn main() {
|
||||
hydrate_planning_session_v2,
|
||||
hydrate_design_agent_session,
|
||||
set_design_agent_runtime_mode,
|
||||
debug_fast_forward_design_session,
|
||||
continue_design_agent_session,
|
||||
decide_design_phase,
|
||||
list_design_workspace,
|
||||
|
||||
@@ -525,7 +525,6 @@ type AppProps = {
|
||||
) => void;
|
||||
onAgentResultsChange?: (results: ProjectAgentResultSummary[]) => void;
|
||||
onMakeGameFromApprovedGdd?: (projectPath: string) => Promise<void>;
|
||||
onSwitchToGameRuntime?: (projectPath: string) => Promise<void>;
|
||||
};
|
||||
|
||||
type ExecuteChatAgentReplyInput = {
|
||||
@@ -554,7 +553,6 @@ export function App({
|
||||
onAgentRuntimeSummariesChange,
|
||||
onAgentResultsChange,
|
||||
onMakeGameFromApprovedGdd,
|
||||
onSwitchToGameRuntime,
|
||||
}: AppProps = {}) {
|
||||
const { setTitle: setWindowTitle } = useWindowChrome();
|
||||
const [planningV2Active, setPlanningV2Active] = useState(planningStartMode);
|
||||
@@ -11690,15 +11688,6 @@ export function App({
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onDesignMakeGame={
|
||||
useDesignAgentSurface && onSwitchToGameRuntime
|
||||
? () => {
|
||||
const nextProjectPath = resolveChatProjectPath(localProject);
|
||||
if (nextProjectPath)
|
||||
void onSwitchToGameRuntime(nextProjectPath);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onMakeGameFromApprovedGdd={
|
||||
onMakeGameFromApprovedGdd
|
||||
? () =>
|
||||
|
||||
@@ -363,6 +363,9 @@ export function WorkspaceLauncherShell({
|
||||
onPlay={() =>
|
||||
requestCurrentProjectPlay(currentProjectContext.projectPath)
|
||||
}
|
||||
onMakeGame={() =>
|
||||
void switchToGameRuntime(currentProjectContext.projectPath)
|
||||
}
|
||||
onManifestChange={syncActiveProjectManifest}
|
||||
onHomeOpen={() => setLauncherView('home')}
|
||||
onProjectsOpen={() => setLauncherView('projects')}
|
||||
|
||||
@@ -23,7 +23,6 @@ type DesignAgentSurfaceProps = {
|
||||
text: string,
|
||||
) => void;
|
||||
onRetry: () => void;
|
||||
onMakeGame: () => void;
|
||||
};
|
||||
|
||||
export function DesignAgentSurface({
|
||||
@@ -33,7 +32,6 @@ export function DesignAgentSurface({
|
||||
onApprove,
|
||||
onClarify,
|
||||
onRetry,
|
||||
onMakeGame,
|
||||
}: DesignAgentSurfaceProps) {
|
||||
const [clarifyText, setClarifyText] = useState('');
|
||||
const phase = view?.session.currentPhase ?? 'concept';
|
||||
@@ -49,16 +47,6 @@ export function DesignAgentSurface({
|
||||
<span>当前阶段</span>
|
||||
<div className="design-agent-controls__phase-title">
|
||||
<strong>{PHASE_LABELS[phase] ?? phase}</strong>
|
||||
{phase === 'consultant' ? (
|
||||
<button
|
||||
type="button"
|
||||
className="design-agent-make-game"
|
||||
disabled={busy || Boolean(view?.running)}
|
||||
onClick={onMakeGame}
|
||||
>
|
||||
做成游戏
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{view?.running ? (
|
||||
|
||||
+63
-12
@@ -24,6 +24,7 @@ const PHASES = [
|
||||
|
||||
type DesignWorkspacePanelProps = {
|
||||
projectPath: string;
|
||||
onMakeGame?: () => void;
|
||||
};
|
||||
|
||||
function phaseLabel(phase: string) {
|
||||
@@ -171,6 +172,7 @@ function DesignTreeBranch({
|
||||
|
||||
export function DesignWorkspacePanel({
|
||||
projectPath,
|
||||
onMakeGame,
|
||||
}: DesignWorkspacePanelProps) {
|
||||
const [view, setView] = useState<DesignView | null>(null);
|
||||
const [files, setFiles] = useState<DesignWorkspaceEntry[]>([]);
|
||||
@@ -178,6 +180,7 @@ export function DesignWorkspacePanel({
|
||||
const [previewText, setPreviewText] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [previewLoading, setPreviewLoading] = useState(false);
|
||||
const [debugPreparing, setDebugPreparing] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [expandedPaths, setExpandedPaths] = useState<Set<string>>(
|
||||
() => new Set(),
|
||||
@@ -344,18 +347,56 @@ export function DesignWorkspacePanel({
|
||||
<h1>{phaseLabel(currentPhase)}</h1>
|
||||
<p>Agent 产生的策划文档会显示在这里。</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="design-workspace-panel__refresh"
|
||||
onClick={() =>
|
||||
void loadWorkspace({ showLoading: true, hydrateSession: true })
|
||||
}
|
||||
disabled={loading}
|
||||
aria-label="刷新策划工作区"
|
||||
>
|
||||
<RefreshCw size={15} aria-hidden="true" />
|
||||
刷新
|
||||
</button>
|
||||
<div className="design-workspace-panel__actions">
|
||||
{import.meta.env.VITE_GENARRATIVE_AGC_DESIGN_DEBUG === '1' ? (
|
||||
<button
|
||||
type="button"
|
||||
className="design-workspace-panel__refresh"
|
||||
disabled={loading || debugPreparing}
|
||||
onClick={async () => {
|
||||
const invoke = resolveTauriInvoke();
|
||||
if (!invoke) {
|
||||
setError('需要在陶泥儿客户端内运行');
|
||||
return;
|
||||
}
|
||||
setDebugPreparing(true);
|
||||
setError('');
|
||||
try {
|
||||
await invoke('debug_fast_forward_design_session', {
|
||||
projectPath,
|
||||
targetPhase: 'consultant',
|
||||
});
|
||||
await loadWorkspace({
|
||||
showLoading: false,
|
||||
hydrateSession: true,
|
||||
});
|
||||
} catch (nextError) {
|
||||
setError(
|
||||
nextError instanceof Error
|
||||
? nextError.message
|
||||
: String(nextError),
|
||||
);
|
||||
} finally {
|
||||
setDebugPreparing(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{debugPreparing ? '正在准备…' : '快速准备做成游戏测试'}
|
||||
</button>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
className="design-workspace-panel__refresh"
|
||||
onClick={() =>
|
||||
void loadWorkspace({ showLoading: true, hydrateSession: true })
|
||||
}
|
||||
disabled={loading}
|
||||
aria-label="刷新策划工作区"
|
||||
>
|
||||
<RefreshCw size={15} aria-hidden="true" />
|
||||
刷新
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav className="design-phase-rail" aria-label="策划阶段">
|
||||
@@ -376,6 +417,16 @@ export function DesignWorkspacePanel({
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
))}
|
||||
{currentPhase === 'consultant' && onMakeGame ? (
|
||||
<button
|
||||
type="button"
|
||||
className="design-phase-rail__make-game"
|
||||
onClick={onMakeGame}
|
||||
aria-label="做成游戏"
|
||||
>
|
||||
做成游戏
|
||||
</button>
|
||||
) : null}
|
||||
</nav>
|
||||
|
||||
{error ? (
|
||||
|
||||
@@ -109,7 +109,6 @@ type ProjectSupervisorViewProps = RuntimePanelProps & {
|
||||
text: string,
|
||||
) => void;
|
||||
onDesignRetry?: () => void;
|
||||
onDesignMakeGame?: () => void;
|
||||
};
|
||||
|
||||
export function ProjectSupervisorView({
|
||||
@@ -150,7 +149,6 @@ export function ProjectSupervisorView({
|
||||
onDesignApprove,
|
||||
onDesignClarify,
|
||||
onDesignRetry,
|
||||
onDesignMakeGame,
|
||||
...runtimePanelProps
|
||||
}: ProjectSupervisorViewProps) {
|
||||
const planningSurfaceActive =
|
||||
@@ -187,7 +185,6 @@ export function ProjectSupervisorView({
|
||||
onApprove={onDesignApprove ?? (() => undefined)}
|
||||
onClarify={onDesignClarify ?? (() => undefined)}
|
||||
onRetry={onDesignRetry ?? (() => undefined)}
|
||||
onMakeGame={onDesignMakeGame ?? (() => undefined)}
|
||||
/>
|
||||
) : (
|
||||
<PlanGddSurface
|
||||
|
||||
@@ -8211,6 +8211,13 @@ iframe.preview-frame {
|
||||
padding-bottom: 18px;
|
||||
}
|
||||
|
||||
.design-workspace-panel__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.design-workspace-panel__eyebrow {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
@@ -8283,6 +8290,25 @@ iframe.preview-frame {
|
||||
color: var(--platform-text-base);
|
||||
}
|
||||
|
||||
.design-phase-rail__make-game {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
min-height: 30px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--platform-button-primary-border);
|
||||
border-radius: 999px;
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.design-phase-rail__make-game:hover {
|
||||
filter: brightness(0.97);
|
||||
}
|
||||
|
||||
.design-phase-rail__marker {
|
||||
display: inline-grid;
|
||||
width: 18px;
|
||||
|
||||
@@ -388,6 +388,7 @@ export type ProjectDevelopmentViewProps = {
|
||||
onHomeOpen: () => void;
|
||||
onProjectsOpen: () => void;
|
||||
onPlay?: () => void;
|
||||
onMakeGame?: () => void;
|
||||
onManifestChange?: (
|
||||
projectPath: string,
|
||||
manifest: GameCreationAppManifest,
|
||||
@@ -857,6 +858,7 @@ export default function ProjectDevelopmentView({
|
||||
walletEntry,
|
||||
onManifestChange,
|
||||
onPlay,
|
||||
onMakeGame,
|
||||
}: ProjectDevelopmentViewProps) {
|
||||
const professionalDagVisible = orchestrationMode === 'professional-dag';
|
||||
const [mode, setMode] = useState<WorkbenchMode>('resources');
|
||||
@@ -4218,7 +4220,10 @@ export default function ProjectDevelopmentView({
|
||||
>
|
||||
<div className="game-workbench-layout game-workbench-layout--design">
|
||||
<section className="game-workbench-stage" aria-label="策划工作区">
|
||||
<DesignWorkspacePanel projectPath={projectPath} />
|
||||
<DesignWorkspacePanel
|
||||
projectPath={projectPath}
|
||||
onMakeGame={onMakeGame}
|
||||
/>
|
||||
</section>
|
||||
<aside className="game-workbench-chat" aria-label="策划 Agent 对话">
|
||||
<header>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// @vitest-environment jsdom
|
||||
import {
|
||||
cleanup,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { afterEach, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DesignWorkspacePanel } from '../src/features/project-workspace/DesignWorkspacePanel';
|
||||
|
||||
vi.mock('../src/components/ChatMarkdownMessage', () => ({
|
||||
ChatMarkdownMessage: () => null,
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
delete window.__TAURI__;
|
||||
});
|
||||
|
||||
it('prepares debug fixtures from the header and refreshes the phase and files without a manual refresh', async () => {
|
||||
let prepared = false;
|
||||
const invoke = vi.fn(async (command: string) => {
|
||||
if (command === 'debug_fast_forward_design_session') {
|
||||
prepared = true;
|
||||
return { activeRuntime: 'design' };
|
||||
}
|
||||
if (command === 'hydrate_design_agent_session') {
|
||||
return { session: { currentPhase: prepared ? 'consultant' : 'concept' } };
|
||||
}
|
||||
if (command === 'list_design_workspace') {
|
||||
return prepared ? [{ path: 'debug.md', kind: 'file', size: 10 }] : [];
|
||||
}
|
||||
throw new Error(`Unexpected command: ${command}`);
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
|
||||
render(<DesignWorkspacePanel projectPath="test-project" />);
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen
|
||||
.getByRole('button', { name: '刷新策划工作区' })
|
||||
.hasAttribute('disabled'),
|
||||
).toBe(false),
|
||||
);
|
||||
const header = screen
|
||||
.getByRole('heading', { name: '概念设计' })
|
||||
.closest('header')!;
|
||||
fireEvent.click(
|
||||
within(header).getByRole('button', { name: '快速准备做成游戏测试' }),
|
||||
);
|
||||
await screen.findByRole('heading', { name: '顾问' });
|
||||
await screen.findByRole('button', { name: 'debug.md' });
|
||||
expect(invoke).toHaveBeenCalledWith('debug_fast_forward_design_session', {
|
||||
projectPath: 'test-project',
|
||||
targetPhase: 'consultant',
|
||||
});
|
||||
});
|
||||
@@ -340,7 +340,11 @@ UI 使用“批准”和“继续修改”两个文字按钮,分别配 Lucide
|
||||
- 多 Agent 协作;
|
||||
- 旧 Fast GDD 展示和 GDD schema 兼容。
|
||||
|
||||
## 14. 策划 Agent reasoning 展示现状
|
||||
## 14. 开发调试入口
|
||||
|
||||
开发构建的策划工作区页头在“刷新”旁提供“快速准备做成游戏测试”按钮。该入口与策划 Debug 日志共用 `GENARRATIVE_AGC_DESIGN_DEBUG=1` 开关:开关未启用时按钮不显示,命令也不可执行。入口仅进行本地 fixture 和会话状态写入,不调用 Provider;完成后自动刷新文件树与阶段,通过 `design-agent-update` 状态事件同步右侧审批/阶段操作区。随后仍需点击正常的“做成游戏”按钮执行资产登记与运行时切换。
|
||||
|
||||
## 15. 策划 Agent reasoning 展示现状
|
||||
|
||||
右侧栏已预留策划 Agent 的 `reasoningText` 事件字段和默认折叠的展示样式,但当前 Provider 解析链仍会过滤 reasoning 内容,尚未向策划 Runtime 产出该字段。因此现阶段只展示用户可见正文和工具状态;reasoning 折叠区在没有数据时不会出现。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user