修正GameAgent灵感区数据接入
保留灵感推荐空态展示 移除主站精选接口与素材类型接入 补充无数据状态回归测试与产品边界文档
This commit is contained in:
@@ -12,26 +12,6 @@ import { fetchClientHttp } from './clientHttp';
|
||||
|
||||
const ACCESS_TOKEN_STORAGE_KEY = 'genarrative.auth.access-token.v1';
|
||||
|
||||
export type EditorShowcaseResource = {
|
||||
resourceId: string;
|
||||
showcaseId?: string | null;
|
||||
label?: string | null;
|
||||
imageSrc: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
prompt?: string | null;
|
||||
actualPrompt?: string | null;
|
||||
assetKind?: string | null;
|
||||
authorDisplayName?: string | null;
|
||||
authorPublicUserCode?: string | null;
|
||||
likeCount?: number | null;
|
||||
};
|
||||
|
||||
type EditorShowcaseResourceListResponse = {
|
||||
resources: EditorShowcaseResource[];
|
||||
nextCursor?: string | null;
|
||||
};
|
||||
|
||||
export class ClientAuthRequestError extends Error {
|
||||
readonly status: number | null;
|
||||
readonly networkError: boolean;
|
||||
@@ -159,12 +139,3 @@ export function getClientProfileWalletLedger() {
|
||||
'读取泥点账单失败',
|
||||
);
|
||||
}
|
||||
|
||||
export function listClientShowcaseResources() {
|
||||
return requestClientApi<EditorShowcaseResourceListResponse>(
|
||||
'/api/editor/showcase/resources',
|
||||
{ method: 'GET' },
|
||||
'读取灵感推荐失败',
|
||||
{ skipAuth: true },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
type HomeDraft,
|
||||
useLauncherHomeDraftStore,
|
||||
} from './useHomeDraftStore';
|
||||
import { useHomeShowcase } from './useHomeShowcase';
|
||||
|
||||
export type {
|
||||
HomeAgentMode,
|
||||
@@ -73,8 +72,6 @@ export default function HomeView({
|
||||
(state) => state.setRichText,
|
||||
);
|
||||
const [homeCreationBusy, setHomeCreationBusy] = useState(false);
|
||||
const { resources: showcaseResources, status: showcaseStatus } =
|
||||
useHomeShowcase();
|
||||
const activeHomeMode =
|
||||
homeAgentModeItems.find((item) => item.mode === homeAgentMode) ??
|
||||
homeAgentModeItems[0];
|
||||
@@ -278,38 +275,13 @@ export default function HomeView({
|
||||
/>
|
||||
</span>
|
||||
<p className="mb-0 mt-1 text-[12px] text-(--platform-text-soft)">
|
||||
{showcaseStatus}
|
||||
暂无灵感
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
{showcaseResources.length > 0 ? (
|
||||
<div className="grid grid-cols-6 gap-3 max-[760px]:grid-cols-1">
|
||||
{showcaseResources.map((resource) => (
|
||||
<article
|
||||
className="grid gap-1.75 overflow-hidden rounded-lg border border-(--platform-surface-border) bg-(image:--platform-subpanel-fill) pb-2.5 shadow-(--platform-panel-shadow)"
|
||||
key={resource.showcaseId ?? resource.resourceId}
|
||||
>
|
||||
<img
|
||||
className="aspect-square w-full object-cover bg-(--platform-warm-bg)"
|
||||
src={resource.imageSrc}
|
||||
alt={resource.label || resource.prompt || '灵感素材'}
|
||||
/>
|
||||
<strong className="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap px-2.25 text-[12px] text-(--platform-text-strong)">
|
||||
{resource.label || '未命名素材'}
|
||||
</strong>
|
||||
<small className="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap px-2.25 text-[11px] text-(--platform-text-soft)">
|
||||
{resource.authorDisplayName ||
|
||||
resource.authorPublicUserCode ||
|
||||
'陶泥儿精选'}
|
||||
</small>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid min-h-24 place-items-center overflow-hidden rounded-lg border border-(--platform-surface-border) bg-(image:--platform-subpanel-fill) text-[11px] text-(--platform-text-soft)">
|
||||
{showcaseStatus}
|
||||
</div>
|
||||
)}
|
||||
<div className="grid min-h-24 place-items-center overflow-hidden rounded-lg border border-(--platform-surface-border) bg-(image:--platform-subpanel-fill) text-[11px] text-(--platform-text-soft)">
|
||||
暂无灵感
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
type EditorShowcaseResource,
|
||||
listClientShowcaseResources,
|
||||
} from '../../services/clientApi';
|
||||
|
||||
export function useHomeShowcase() {
|
||||
const [resources, setResources] = useState<EditorShowcaseResource[]>([]);
|
||||
const [status, setStatus] = useState('正在读取灵感');
|
||||
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
void listClientShowcaseResources()
|
||||
.then((response) => {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
setResources(response.resources.slice(0, 6));
|
||||
setStatus(response.resources.length > 0 ? '已读取灵感' : '暂无灵感');
|
||||
})
|
||||
.catch((error) => {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
setResources([]);
|
||||
setStatus(error instanceof Error ? error.message : '灵感读取失败');
|
||||
});
|
||||
return () => {
|
||||
disposed = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { resources, status };
|
||||
}
|
||||
@@ -25,6 +25,22 @@ import {
|
||||
} from './harness';
|
||||
|
||||
export function registerClientHomeTests() {
|
||||
it('keeps the empty inspiration section without reading the main-site showcase', async () => {
|
||||
const fetchSpy = vi.spyOn(globalThis, 'fetch');
|
||||
renderLauncherAt('/?launcher');
|
||||
|
||||
const inspirationSection = screen.getByLabelText('灵感推荐');
|
||||
expect(within(inspirationSection).getAllByText('暂无灵感')).toHaveLength(2);
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(
|
||||
fetchSpy.mock.calls.some(
|
||||
([input]) => String(input) === '/api/editor/showcase/resources',
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('projects Supervisor manifest updates into the open workbench without reopening the project', async () => {
|
||||
const projectPath = '/tmp/live-manifest-workbench';
|
||||
const initialManifest = createGameCreationAppManifest(
|
||||
|
||||
@@ -566,6 +566,7 @@ game-project/
|
||||
- Agent 状态列表从 `.agent/manifest.json` 的任务 / 角色清单、`.agent/run.latest.json` / `.agent/runs/<runId>.json` 的 step、taskGraph、passPlans、lifecycleStatus,以及 `read_game_creator_agent_runtimes` 批量读取的 `.agent/runtime/agents/<taskId>.json` 和最近任务派生;v1 不新增独立状态数据库,也不承诺完整后台 runner。
|
||||
- App 启动先检查平台登录态;登录后进入同一个客户端首页,不再有面向用户的启动器 / 主窗口切换概念。首页按 `做游戏` / `做素材` / `做方案` 保存 `game` / `art` / `doc` 初始意图,输入状态按文字与附件 token 的顺序保存,附件以文件名 token 内嵌在输入框中而非堆叠在下方;提交时才将 token 转为 LLM 可读的 `{1st attachment}` 引用。发送时弹出原生目录选择,目标目录存在且非空时必须二次确认;确认后调用 `init_local_game_project` 初始化本地项目、`upload_local_asset` 导入附件,再把首条需求直接投递给 active `project-supervisor` Session 的后台 Runtime,写入最近项目并切到项目开发页。缺少 active Session 时先创建并激活;成功后清空首页草稿,取消或创建失败时在首页回显状态,首页响应式断点与应用外壳统一为 `760px`。本流程不调用 `generate_local_game_draft`、`generate_platform_art_asset`、一次性 `chat_with_game_creator_agent` 或 legacy 项目对话 append。
|
||||
- 首页发送、项目组目录选择和本地文件选择必须使用 Tauri 非阻塞原生 picker,并把选择器绑定到当前 `client` 窗口;禁止在同步 command 中调用 `blocking_pick_folder` / `blocking_pick_file` 阻塞 WebView 事件循环。选择器打开期间保留首页草稿可编辑,取消后恢复“开启创作”按钮并回显“已取消”。
|
||||
- 当前尚未定义 GameAgent 独立的灵感数据源;首页保留“灵感推荐”区块并显示无数据状态,但不得展示或请求主站 `/creation` 的陶泥儿精选 `/api/editor/showcase/resources`。后续接入前必须先明确独立数据契约和交互验收。
|
||||
- debug 构建启动后在用户 `client` 窗口之外额外打开 `developer` 窗口;该窗口用于开发者单独选择 Agent、管理对应 active/archived Session 并读取历史,用户消息和真实 Agent 回复只持久化到 `.agent/conversations/agents/<agentId>/` 下的规范 Session。普通用户窗口不得出现 `Agent 聊天` 导航、picker 或工具台入口。
|
||||
- 首页最近项目只展示最近 3 个有效项目;项目组页在同一窗口管理最近项目、打开项目、新建项目和显示目录。打开项目只读取已初始化项目并切到项目开发页,不打开第二窗口;新建项目仍沿用非空目录确认,不自动重建无效历史路径。
|
||||
- 项目开发页保留左侧栏和顶部栏,顶部展示项目名、路径和最近 run 状态;中间只挂载 active `project-supervisor` Session 的正式对话面、Runtime 状态、确认/Needs input 和专业 Agent 协作只读状态,底部保留附件导入结果。真正的项目开发画布仍未落地;专业 Agent picker、完整计划和工具台继续留在开发入口。
|
||||
|
||||
Reference in New Issue
Block a user