Files
pikasTech-HWLAB/docs/reference/spec-v03-workbench-vue-migration.md
T
2026-06-12 02:28:36 +08:00

14 KiB
Raw Blame History

v0.3 Workbench Vue 迁移语义合同

本文定义 Cloud Workbench 从 React useWorkbenchStore 迁移到 Vue/Pinia 时必须保留的 API、store 和 trace 语义。Vue 实现可以复用 Sub2API frontend 的 api/store/composable 分层形态,但不能照搬 Sub2API 的 bearer token 鉴权和通用刷新模型。

基线来源

来源 基线文件 可迁移结论
HWLAB React Workbench web/hwlab-cloud-web/src/state/workbench.tsrunner-trace.tstrace-reattach.tsservices/api/client.tstypes/domain.ts 当前语义权威。Vue 迁移必须保持显式 session、inactivity-timeout、trace reattach、result/trace 同源 API 和 HWPOD evidence label。
HWLAB Web 规格 docs/reference/spec-v02-hwlab-cloud-web.md Code Agent 没有浏览器侧 total-timeout / attempt cap;唯一 abort 信号是 activityRef 驱动的 inactivity-timeout。
Sub2API frontend v0.1.136 src/api/client.tssrc/stores/auth.tssrc/stores/app.tssrc/composables/useAutoRefresh.tssrc/composables/useClipboard.ts 可复用 Composition API Pinia store、独立 api module、toast/clipboard/auto-refresh composable 的组织方式;不可复用 localStorage bearer token 鉴权。

React Workbench 语义提取

React 模块 当前语义 Vue 迁移归属
services/api/client.ts::fetchJson / fetchText 同源 fetchcredentials=same-origin、统一 ApiResult<T>recordApiTimingactivityRef 每秒重算 idle window,超时错误必须说明 waitingForlastEventLabel src/api/client.ts 保持 fetch client,不换成 Sub2API axios bearer client。
services/api/client.ts::api 同源代理覆盖 auth bootstrap、live probe、workspace、conversation、Code Agent send/steer/result/cancel、HWPOD node-ops、skills 等端点。 拆成 src/api/workbench.tssrc/api/auth.ts;只拆模块,不改 endpoint path 和 timeout contract。
state/workbench.ts::initialState providerProfilecodeAgentTimeoutMsgatewayShellTimeoutMs 从 localStorage 读取并 clamp;默认 Code Agent inactivity budget 为 1_800_000ms stores/workbench state 初始化;持久化 key 保持 hwlab.workbench.*.v1
state/workbench.ts::hydrate 并发读取 /v1/workbench/workspace/v1/agent/conversations,用 workspace selected conversation 生成 message 列表并记住 projectId。 stores/workbench.hydrate();首屏可由 useWorkspaceBootstrap 提供 workspace 快照,后续再补 conversation list。
state/workbench.ts::refreshLive 每 30s 读取 health/live、health、REST index、adapter、HWPOD specs、HWPOD node-ops、live-builds,并推导 Code Agent availability。 stores/workbench.refreshLive() + useAutoRefresh;只能在 workspace 入口启用,性能页不得初始化。
state/workbench.ts::createSession / selectConversation / deleteCurrentSession session 由用户显式创建、选择、删除;普通 send 不隐式创建 sessionselect payload 带 updatedByClient stores/workbench actionsVue UI 必须先暴露 session 创建/选择入口,再允许普通 turn。
state/workbench-reducer.ts::composerFromState 通过当前 request、running agent message、workspace active trace 推导 composerrunning turn 时 submit mode 为 steer 且 route 为 /v1/agent/chat/steer stores/workbench getter composer;不要在组件中重复推导。
state/workbench.ts::submitMessage 生成 user/pending message,先 persistConversation,再 POST send/steersubmit kickoff 调 recordActivity()POST 使用同一个 activityRefterminal 后 merge trace/result 并再次持久化。 stores/workbench.submitMessage()useTraceSubscriptionmessage mutation 和 persistence 保持 store 内聚。
state/runner-trace.ts::subscribeToTrace result 和 trace 两路同源 poll;每次成功 poll 调 onActivity5xx 不刷新 activity 且继续 poll;非 5xx 失败走 infrastructure error;外层 for(;;) 没有 total timeout。 composables/useTraceSubscription.ts 的唯一 active polling 入口。
state/runner-trace.ts::mergeTraceResults terminal result 与 trace snapshot 合并;优先使用 finalResponse、terminal assistant event、result text,保留 agentRun、events、traceSummary、terminalEvidence。 api/workbenchcomposables/useTraceSubscription 附近的纯函数;必须有单元测试。
state/trace-reattach.ts hydrate 后发现 activeTraceId 且当前没有 pending,就创建 placeholder 并主动订阅到 terminal;完成/失败都写回 conversation。 composables/useTraceReattach.ts watch store.activeTraceIdstore.chatPending
components/hwpod/HwpodNodeOpsSidebar.tsx evidence label 为 ContractSpecsSpecNodeOps、per-op label 和 probestatus/freshness/blocker 来源必须是同源 /v1/hwpod-node-ops/v1/hwpod/specs?probe=1 Vue HWPOD panel 保留同名 label、data-hwpod-detail 语义和 blocker/status 规则。

Sub2API 分层对照

Sub2API v0.1.136 对照必须来自真实 frontend 源码,不允许凭记忆复写。当前迁移基线读取过以下文件:

Sub2API 文件 HWLAB 吸收结论
frontend/package.jsonfrontend/vite.config.ts Vue 3、Pinia、Vue Router、Vue I18n、Tailwind/PostCSS 作为单一前端栈;HWLAB 删除 React 入口和 React 依赖,不做长期双栈。
frontend/src/main.tsfrontend/src/App.vue main.ts 只负责安装 Pinia/router/i18n 并挂载 appApp.vue 保持全局 shell、route outlet、toast/弹窗类横切组件,不承载业务状态机。
frontend/src/router/index.tsfrontend/src/router/title.ts 路由按 public/user/admin 分段懒加载,metadata 表达 auth/admin/titleHWLAB 保留默认首屏 workbench,并保持 Cloud Web 同源入口。
frontend/src/components/layout/AppLayout.vueAppSidebar.vueAppHeader.vue 平台壳拆成 layout 组件和导航数据;HWLAB 采用同类分层,但导航语义改为 Workbench、Code Agent、HWPOD、Access、Provider。
frontend/src/components/common/NavigationProgress.vueStatusBadge.vueSkeleton.vueEmptyState.vue common 组件只承载视觉/反馈原语,可复用为 HWLAB 的状态标记、加载态、空态、导航进度。
frontend/src/views/user/DashboardView.vuefrontend/src/views/admin/DashboardView.vue user/admin view 只组合 layout、common 和业务 store,不把 API fetch 散落到 app shellHWLAB 的 workbench/dashboard/admin 页面遵循同样边界。
frontend/src/i18n/index.tsfrontend/src/style.cssfrontend/tailwind.config.js i18n 初始化、Tailwind base/components/utilities、颜色和字体 token 集中管理;HWLAB 保留自己的文案和 Web session 约束,不照搬 Sub2API token/Secret/刷新策略。
Sub2API 形态 可吸收部分 HWLAB 必须改写部分
api/client.ts axios instance、request/response interceptor、统一 unwrap { code, data } api client 是独立模块,业务 endpoint 放在 src/api/*.ts;请求取消保持原错误,便于调用方忽略。 HWLAB 不使用 localStorage auth_tokenrefresh_token 或 401 token refresh queue;保留 same-origin cookie session、ApiResult<T>activityRef inactivity-timeout。
stores/auth.ts Composition API Piniaref state、computed getter、actions、定时器 cleanup auth store 的组织方式、启动时 checkAuth/bootstrap、loading/error state 可复用。 HWLAB stores/auth 只消费 /auth/bootstrap/auth/session/auth/login/auth/logout;不得持久化 bearer token 或引入 Sub2API refresh token。
stores/app.ts toast、global loading、cached settings toast/loading 与 useClipboard 依赖 app store 的方式可复用。 Workbench live refresh、workspace hydrate 不放进 app storeapp store 只保留 UI 横切状态。
composables/useAutoRefresh.ts localStorage 保存 enabled/interval/countdown/fetching,组件卸载清 timer 可作为 Workbench live refresh 和 HWPOD panel refresh 控件基础。 不得用 auto-refresh 替代 Code Agent trace subscriptiontrace 仍由 useTraceSubscription 无限 poll 并使用 activityRef
composables/useClipboard.ts Clipboard API + textarea fallback + toast 可直接迁移为工作台复制 trace/result/session id 的通用 composable。 成功/失败文案走 HWLAB app store/i18n;不要把复制行为和业务状态 mutation 耦合。

Vue Pinia / Composable 目标映射

目标文件 责任边界 必须暴露的接口
src/api/client.ts fetch 基础设施、ApiResult<T>ActivityRef、inactivity-timeout、RUM timing。 fetchJson<T>(path, options)fetchText(path, options)type ActivityReftype ActivityRefSource
src/api/workbench.ts Workbench 业务 endpoint wrapper;只表达 HTTP path 和 timeout,不持有 UI state。 workspaceupdateWorkspaceselectConversationconversationssaveConversationdeleteConversationsendAgentMessagesteerAgentMessagegetAgentChatResultcancelAgentMessageliveSurfacehwpodSpecshwpodNodeOpsHealth
src/api/auth.ts Web session bootstrap/login/logout wrapper。 bootstrap()session()login(username,password)logout();返回同源 session 状态。
src/stores/auth.ts Web session 状态。 state: authenticateduseractorexpiresAtloadingerror; actions: bootstraploginlogout; getter: isAuthenticated
src/stores/workbench.ts Workbench durable state、derived composer、session lifecycle、message mutation、conversation persistence。 state: workspaceconversationsmessagesproviderProfile、timeouts、livecodeAgentAvailabilitychatPendingcurrentRequestlastActivityAt; getters: activeProjectIdactiveConversationIdsessionTabscomposeractiveTraceId; actions: hydraterefreshLivecreateSessionselectConversationdeleteCurrentSessionsubmitMessagecancelAgentMessageretryAgentMessagereplayAgentTracerecordActivity、timeout/profile setters。
src/composables/useTraceSubscription.ts active trace polling lifecycle;替代 React subscribeToTrace start(config)stop()running; config 包含 traceIdprojectIdinitialinactivityTimeoutMsonActivityonSnapshotonCompleteonInfrastructureError
src/composables/useTraceReattach.ts watch store active trace and reattach after hydrate/refresh。 自动 watch enabledstore.activeTraceIdstore.chatPending; 创建 placeholder、订阅、完成/失败后 persist。
src/composables/useWorkspaceBootstrap.ts 首屏 bootstrap 合并 auth/workspace,避免重复请求。 bootstrapWorkspace(projectId) 返回 auth state + workspace snapshot;必须消费 /auth/workspace-bootstrap?projectId=...
src/composables/useAutoRefresh.ts UI refresh control for live surface only。 复用 Sub2API enabledintervalSecondscountdownfetchingsetEnabledsetIntervalshouldPause 默认在 hidden/performance route 时暂停。
src/composables/useClipboard.ts 文本复制和 toast。 copyToClipboard(text, successMessage?)copied

Trace / Result 不变量

  • submitMessageuseTraceReattach 必须共享 useTraceSubscription,不得拆成 submit-only 和 hydrate-only 两套 polling。
  • getAgentChatResult(resultUrl, inactivityTimeoutMs, activityRef) 的 timeout 入参不随 wall-clock 缩小;外层循环没有累计耗时上限、attempt cap 或 timeoutMs * N 兜底。
  • 每一次成功 result poll 或 trace poll 都调用 store.recordActivity()5xx retry 不调用,非 5xx 业务失败进入 infrastructure error。
  • terminal 完成前至少尝试合并 trace snapshotfinal assistant text 优先级保持 finalResponse、terminal assistant event、result text、普通 assistant event。
  • steer POST 如果 timeout/ECONNRESET 但目标 trace 仍 runningVue store 必须释放本次 submit lock、保留原 agent message running/steerable,不得把原 turn 标 failed。
  • session_failedthread-resume-failed、provider continuation 失效、运行面中断或用户取消后,不得自动滚动新 session;下一步必须由用户显式创建或选择 session。

迁移顺序

  1. 先迁 types/domain.ts、trace merge 纯函数和 api/client.ts,用无浏览器单测锁住 activityRef inactivity 行为。
  2. 再迁 api/workbench.tsstores/auth.ts,确认同源 session contract 未引入 bearer token。
  3. useTraceSubscriptionuseTraceReattach,用 fake API 断言无 total-timeout、成功 poll 刷新 activity、5xx 不刷新 activity、terminal result 合并 trace。
  4. stores/workbench.ts,把 React reducer 的 action 语义变成 Pinia action/getter;组件只读 getter 和调 action。
  5. 最后迁 UI 组件,HWPOD、trace panel、session sidebar 和 composer 只消费 store/composable,不内联业务推导。

验证要求

  • 源码层:Vue 迁移 PR 至少覆盖 api/client inactivity、useTraceSubscription polling、stores/workbench.composeruseTraceReattach placeholder/terminal persistence、HWPOD label mapping。
  • 静态检查:保留 bun run --cwd web/hwlab-cloud-web check 或 Vue 等价入口;不得恢复旧 quick prompt、旧 layout smoke 或与当前契约无关的门禁。
  • 同路径验收:显式创建或选择 Code Agent session 后,通过 Web 同源 path 提交 turnresult/trace --render web 使用同一 trace row;未选择 session 的普通 send 必须返回 session_required
  • HWPOD 验收:Vue 面板必须从 /v1/hwpod-node-ops/v1/hwpod/specs?probe=1 显示 status/freshness/blocker,不得用 fixture 或 blocked fallback 声称真实硬件 DEV-LIVE。