Skip to content

Commit df71472

Browse files
committed
feat: add request orchestration v1 workbench
1 parent 5303498 commit df71472

40 files changed

Lines changed: 5000 additions & 2039 deletions

.agents/skills/gettokens-domain-engineering/SKILL.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ This skill unifies the technical rules for building, styling, and debugging GetT
118118
- **Themes**: Support `system`, `light`, and `dark`. Ensure `--bg-main` and `--bg-surface` are distinct in dark mode.
119119
- **l10n**: Add new copy to both `zh.json` and `en.json`. Default is Chinese.
120120
- **Controls**: Use segmented controls for discrete settings.
121+
- **Complex Workflow Screens**: When a flow/configuration page starts feeling complex, reduce the information architecture before adding more components:
122+
- put the final route/result summary first
123+
- keep the expanded editor to the fewest decision zones users must act on
124+
- hide proxy/route choices until the selected account can actually use them
125+
- remove duplicate “current configuration” KV panels when the path summary already carries the same truth
126+
- keep locators/debug metadata available, but visually subordinate to the main decision path
121127
- **Action Selects**: For `select + right-side actions` patterns, use the project-level `frontend/src/components/ui/ActionSelect.tsx` instead of hand-rolling label/select/button grids. Keep `+` and optional delete actions inside the select frame so field widths align across sibling rows.
122128
- **Status Local CLI Config**: In `StatusApplyLocalSection`, Codex and Claude Code tabs must share field components for equivalent concepts such as Relay API key, endpoint/base URL, provider, and model. Do not maintain parallel JSX just because one tab has fewer fields.
123129
- **Codex Feature Config UI**: The local Codex `[features]` bool editor is a config list, not a data table. Each feature is one row with feature key as the title, stage as a compact tag before the subtitle, localized description as the subtitle, and the switch as the only bool value expression. Do not add duplicate `default/local/on/off` value labels when the switch already communicates the state. Do not force feature keys or descriptions to uppercase; preserve source and localization casing.

app_request_orchestration.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import wailsapp "github.com/linhay/gettokens/internal/wailsapp"
4+
5+
type RequestOrchestrationFlowTest = wailsapp.RequestOrchestrationFlowTest
6+
type RequestOrchestrationFlowConfig = wailsapp.RequestOrchestrationFlowConfig
7+
type RequestOrchestrationAccountOverride = wailsapp.RequestOrchestrationAccountOverride
8+
type RequestOrchestrationConfig = wailsapp.RequestOrchestrationConfig
9+
type RequestOrchestrationAccountState = wailsapp.RequestOrchestrationAccountState
10+
type RequestOrchestrationSnapshot = wailsapp.RequestOrchestrationSnapshot
11+
type ApplyRequestOrchestrationResult = wailsapp.ApplyRequestOrchestrationResult
12+
13+
func (a *App) GetRequestOrchestrationConfig() (*RequestOrchestrationConfig, error) {
14+
return a.core.GetRequestOrchestrationConfig()
15+
}
16+
17+
func (a *App) SaveRequestOrchestrationConfig(input RequestOrchestrationConfig) (*RequestOrchestrationConfig, error) {
18+
return a.core.SaveRequestOrchestrationConfig(input)
19+
}
20+
21+
func (a *App) GetRequestOrchestrationSnapshot() (*RequestOrchestrationSnapshot, error) {
22+
return a.core.GetRequestOrchestrationSnapshot()
23+
}
24+
25+
func (a *App) ApplyRequestOrchestration() (*ApplyRequestOrchestrationResult, error) {
26+
return a.core.ApplyRequestOrchestration()
27+
}
28+
29+
func (a *App) RestoreRequestOrchestration() (*ApplyRequestOrchestrationResult, error) {
30+
return a.core.RestoreRequestOrchestration()
31+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# 2026-05-05 Request Orchestration Implementation Start
2+
3+
## 背景
4+
5+
请求编排设计稿经历了画布、节点、泳道、四卡横向流程和路径优先单面板几轮收敛。用户最终反馈“四卡版仍然复杂”,因此本轮在开始真实前端施工前,先把稳定 UI 模式沉淀下来。
6+
7+
## 沉淀模式
8+
9+
复杂编排页不要优先增加卡片数量,而要先把信息架构降到两个层级:
10+
11+
1. 第一层只回答“当前请求会怎么走”。
12+
- 用一条路径摘要表达 `入口 -> 账号组 -> 账号 / 出口 -> 测试`
13+
- 折叠态也只展示这条链路的压缩摘要和状态。
14+
2. 第二层只保留用户必须操作的决策区。
15+
- `请求入口` 只选 CLI。
16+
- `账号` 先选组再选账号,代理池开关跟随账号。
17+
- `出口与测试` 只处理当前账号出口和连通性。
18+
19+
## 实现边界
20+
21+
本轮开始施工的第一步只落 APP 层工作台:
22+
23+
- 新增一级菜单 `请求编排`
24+
- 新增 `features/request-orchestration/`,把兼容性、账号选择、出口可见性和测试判定放到纯模型层。
25+
- 页面先支持浏览器 preview 静态数据,同时在 Wails 环境下接入真实账号池数据。
26+
- 真实账号来源:sidecar `ready` 后调用 `ListAuthFiles``ListAccounts`,复用账号池现有 `mapAuthFileToRecord` / `mapBackendAccountRecord` 映射。
27+
- OpenAI-Compatible 账号与模型来源:同步调用 `ListOpenAICompatibleProviders`,先把 provider 本体转换成请求编排账号,再把 provider 内已配置的模型列表映射为该账号在 `codex` 入口下的目标模型,优先精确匹配入口模型,否则回退到 provider 第一个模型。
28+
- 真实代理来源:读取代理池 localStorage 中的代理节点,只把 `available` 节点映射为请求出口;账号未启用代理池时只显示 `direct`,启用代理池后只显示可用代理出口。
29+
- 编排流程组来源:APP 层 localStorage 持久化,恢复时会过滤已经不存在的账号和代理出口。
30+
- 账号级覆盖来源:APP 层 localStorage 持久化请求编排页内的 `disabled / proxyPoolEnabled` 覆盖,不回写账号池资产本体。
31+
- 账号参与来源:每个流程组维护自己的 `enabledAccountIDs` 白名单;兼容性只决定账号是否“可用”,是否参与该流程由用户在账号列表中勾选,不回写账号池资产本体。
32+
- 暂不写入 CLIProxyAPI,也不改 sidecar 原生策略枚举。
33+
34+
## 当前真实数据边界
35+
36+
- `codex` / `claude-code` 支持关系先按账号 provider 保守推断:`codex`、Codex API key 和 OpenAI-Compatible provider 参与 `codex``anthropic / claude` 参与 `claude-code``bridge` 账号可参与两者。
37+
- 模型映射对 OpenAI-Compatible provider 已接入真实 provider 模型列表;OpenAI-Compatible provider 本体必须进入 `openai-compatible` 账号组,不能只作为模型映射源存在。其他账号仍先使用入口默认模型到同名目标模型的 APP 层默认值,后续再补账号级可编辑映射。
38+
- 账号禁用与代理池启用目前是请求编排页内的 APP 层临时覆盖,不回写账号池或 CLIProxyAPI。
39+
- 启用账号代理池时,若当前账号仍是 `direct/null` 出口,会自动选择第一个可用代理;若没有可用代理,则该账号不可出站,测试结果会阻断并提示未选择可用代理。
40+
- 账号列表中的 checkbox 是流程级参与开关;取消勾选当前账号时,当前流程会自动切到同组内仍勾选且可用的下一个账号。
41+
42+
## 2026-05-07 后端闭环
43+
44+
- `应用当前组` 已从纯 APP 层标记升级为 Wails 后端动作:前端先保存当前 flows 到 `~/.config/gettokens-data/request-orchestration/config.json`,再调用 `ApplyRequestOrchestration`
45+
- apply 会读取当前 relay routing config、账号 disabled 状态和 OpenAI-Compatible provider disabled 状态,写入 `runtime-snapshot.json` 后,只保留当前流程组 `enabledAccountIDs` 参与,其余账号 / provider 临时禁用。
46+
- restore 会读取 `runtime-snapshot.json`,恢复 relay routing YAML 和各账号 / provider 原始 disabled 状态,随后删除快照。
47+
- 浏览器 preview 或 sidecar 未 ready 时,前端仍只显示预览标记,不宣称真实 sidecar 状态已改变。
48+
- V1 仍不新增 CLIProxyAPI 原生策略;账号级代理选择仍先服务于 APP 层出口预览和测试判定,不承诺写回所有账号类型。
49+
50+
## 可复用规则
51+
52+
已补充项目级 skill `gettokens-domain-engineering``Complex Workflow Screens` 规则:
53+
54+
- 最终路径/结果摘要优先。
55+
- 决策区数量压到最少。
56+
- 未满足条件时不展示不可操作的大量候选项。
57+
- 不重复展示“当前配置”KV。
58+
- 定位器和调试元数据保留,但视觉上降级。

docs-linhay/memory/2026-05-03.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@
4141
- 视觉方向:`Swiss-industrial workbench`,保持 GetTokens 现有黑白灰硬边工作台语义,用左侧产品导航、顶部链路态总览、四段泳道和右侧影响面板表达“调度台而不是表单页”。
4242
- 交互重点:入口 CLI / 模型切换、唯一组模式切换、账号代理模式切换都会即时影响出口预览和右侧焦点说明。
4343

44+
## 请求编排节点连线画布
45+
46+
- 关键决策:请求编排设计稿从“泳道模式”收敛为“节点连线制画布”,四类主节点为 `请求入口 -> 账号组 -> 代理池 -> 结束/测试`,交互心智以节点、端口、连线和底部 active path 为主。
47+
- 入口限制:请求入口固定为 `codex``claude code` 两个 CLI socket;入口节点单独展示 `model key`,用于后续账号 CLI 支持与模型映射裁剪。
48+
- 体验收敛:顶部说明面板移除,只保留右上角恢复/应用操作;active path 移到底部状态坞,代理目标压缩为小端口 tile,并保留点击复制 locator。
49+
- 验证:浏览器预览已跑通 `claude code -> Claude 灰度组 -> bridge-01 -> 直连 -> 测试`,截图已归档到对应 space;`docs-linhay/scripts/check-docs.sh` 通过。
50+
- 管理语义补充:账号组节点负责从账号池加入、从当前编排移出、禁用/启用账号;代理池节点负责搜索、新增、禁用/启用、删除代理目标;单账号通过点击代理 tile 或拖拽账号端口关联代理。删除账号/代理在本页均按“移出当前编排/代理目标”处理,不等同删除底层账号资产。
51+
- 交互升级:画布新增空白区域平移、主节点头部拖动、相邻层通用拖线。入口 socket 只在成功拖到账号组后切换 CLI;账号与代理、代理与结束节点也按合法落点生效,避免拖拽取消时污染当前状态。
52+
4453
## Claude / Codex 本地配置 UI 复用
4554

4655
- 偏好更新:状态页本地 CLI 配置区中,Codex 与 Claude Code 的 Relay API key 选择器、Endpoint / Base URL 区域必须复用同一组局部组件,不再在两个 tab 内平行维护同款 JSX。

0 commit comments

Comments
 (0)