Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions .downstream/gpt6-routing-and-prompts.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GPT-6 模型、Codex 路由与提示词

本轮以官方 v0.2.7 和下游生产提交 `300bd6dc5c40191d935cc08db910942f996bb26f` 为基线。宿主目标版本为 `0.2.7-codexrip.2`,七个内置插件为 `0.2.8`;新版插件要求宿主至少为该下游版本。宿主每次发布都会重新签名内置包,已安装的同版本号不能换包,因此 `0.2.7-codexrip.4` 起七个插件为 `0.2.9`,合并官方 v0.2.8 后的 `0.2.8-codexrip.1` 起为 `0.2.10`,加入 Codex 质量诊断的 `0.2.8-codexrip.2` 起为 `0.2.11`(宿主范围放宽到 `<0.2.9`,下限不变,便于回退到 0.2.7 宿主)。官方 v0.2.8 自带 GPT-6 Sol/Luna 定价与识别,下游改用官方实现,只保留 Codex 专属的路由门控、指令模板、实时容量和日期快照不改名的约定。插件固定版本意图继续保留,旧提示词插件不能解释新规则时明确报告不可用。
官方基线见 [upstream-base](upstream-base)。内置提示词能力在宿主内原生运行,随宿主交付;第三方插件框架独立保留。GPT-6 Sol/Luna 的定价与识别沿用官方实现,Codex 专属路由、指令模板、实时容量和日期快照约定见下文。

## 模型同步与容量

Expand Down Expand Up @@ -39,25 +39,41 @@ API Key 使用完整 Responses。OAuth 目录保留实际 Lite 与上下文字

## 提示词规则与账号选择

系统提示词页面的“应用规则”复用原有模板及不可变版本。规则稳定排序,可按请求模型或最终上游模型精确匹配;空模型集合表示全部。
系统提示词页面使用一个编辑器管理正文、角色、位置、平台/模型范围和默认选择。“保存并生效”在一个事务中创建不可变内容版本、更新规则和开关,只递增一次 revision。历史版本、来源同步和远程 Skill 位于高级入口;不存在第二个“设为全局当前模板”的生效步骤。

管理员 `GET /api/v1/admin/system-prompts/config` 返回配置、按规则 ID 索引的正文和协议能力。`PUT` 提交 `expected_revision`、运行开关、v2 `policy` 及仅包含改动正文的 `contents`。新规则可以携带零模板/版本 ID 和正文,也可以明确引用已有不可变版本;事务内生成真实引用。固定版本的旧规则 ID、默认选择、账号引用和顺序保留,v1 写入及无目标规则的旧发布操作明确拒绝。

| 位置 | 含义 |
| --- | --- |
| control_prepend / control_append | 控制指令区前后 |
| conversation_head / conversation_tail | 本次最终发送的消息数组头尾 |
| before_last_user / after_last_user | 本次序列中最后一条真实用户消息的前后,纯工具结果不算用户输入 |

v2 使用独立 `role=auto/system/developer` 与 `position`。平台必须显式选择,模型默认按最终上游 ID 精确匹配;空模型集合表示全部,也可选择按请求模型匹配。同一落点按列表顺序排列。

| 最终协议 | 实际投递 |
| --- | --- |
| Responses | auto 控制区使用 instructions,auto 消息位置使用 developer;显式角色保留在 input。Codex OAuth 不接受 system。 |
| Chat Completions | auto 使用 system;明确要求 system 的目标不接受严格 developer,不做静默角色替换。 |
| Messages | 控制区使用顶层 system;会话内 system 仅对明确支持的模型及合法边界开放。developer 不支持。 |
| Gemini | 使用 systemInstruction,系统指令只支持控制区前后。Antigravity upstream 账号按其实际 Messages 协议处理。 |

发送方式与位置分开:`native_control` 使用目标原生控制字段,仅用于控制区;`system` 和 `developer` 要求最终发包保留对应显式角色。Codex OAuth 不接受严格 system 的组合会明确返回不支持,原生模式标明实际使用 `instructions`。续接数组位置不包含 `previous_response_id` 指向的隐藏历史。
找不到最后用户消息,或插入会拆开工具调用配对时,跳过该条规则并返回原因,请求继续。角色/位置与目标不兼容则明确返回错误。位置只指本次出站序列,不包含 previous_response_id 指向的隐藏历史。

账号详情和账号批量操作提供 `inherit / off / custom`:继承默认规则、关闭、或用指定规则替换默认集合。默认集合留空、指定账号选择 custom,即可只对指定账号开启。账号仅存规则引用,不复制正文;shadow 使用自身绑定。

预览选择账号、模型、协议、HTTP/WS和样例请求,显示网关基础模板、客户指令、站点规则及最终结构。它不访问上游。实际发送前执行同一载体校验,覆盖 Responses、Chat、转换链路和 WS passthrough;重试及换账号精确撤回本站插入,不按相同正文猜测客户内容。规则变化隔离缓存,保留续接标识和已有回显设置。
预览接受未保存正文和规则,使用实际协议转换与同一个编排器,展示基础指令、客户指令、最终角色/载体/索引及跳过原因,不访问模型上游。OAuth 身份参数等模拟部分会标明。实际转发先转换协议和准备基础指令,再应用规则、生成缓存标识/签名并发送;每次重试从干净输入构建,WS 历史累计器不保存本站注入。每轮冻结内容快照,换账号时重新解析绑定;规则变化隔离缓存,保留续接标识及精确载体回显保护。

迁移 `255_prompt_rule_policy_v2.sql` 固定旧 follow_active 当时的真实版本,并将旧各域开关折入相应规则,保留 OpenAI/Cindy 范围,避免自动扩散到新平台。Claude 旧自定义块保留布局、缓存属性、模型条件及单次占位符展开,统一投递;Settings 页的旧正文字段仅保留核对,修改请求返回迁移提示。单文档保留 64 KiB 上限;配置最多 64 条规则以容纳旧两个域的并集,每个实际请求命中的编译正文仍限制为 256 KiB,互斥平台的配置不相加计算请求预算。

远程 Skill 仍以共享 `/current` 树和提示词成对发布。订阅该来源的所有规则都是明确影响集合;发布/回滚携带完整 `target_rule_ids` 和 `expected_config_revision`,与 registry revision 一起在事务内比较。普通来源同步只创建候选,应用历史正文只更新指定规则。来源不可用不会阻止无关内联规则,也不妨碍关闭总开关;命中不可用来源的请求明确失败。

迁移 `253_prompt_rule_policies.sql` 为旧活动版本建立默认规则,保留原总开关、账号范围与 256 KiB 合法编译上限。配置和账号绑定均使用版本比较,冲突需要重新读取后处理;被账号引用的规则不能直接删除。
配置冲突保留编辑器草稿,重新读取后可合并未编辑的远端字段。账号仍用自身版本比较;被账号引用的规则不能直接删除。

## 界面与验证边界

公共插件 context 的同值刷新不再重建 iframe。主题按 URL/变量差异更新,新 CSS 及字体准备完成再替换旧外观;加载失败保留最后成功版本。内容测量按帧合并,使用自然尺寸而非随滚动变化的 viewport 坐标。

离线真实 Chromium 验证了左侧导航、分类栏和右侧账号详情:两次正常 15 秒刷新、未保存输入与滚动保留、主题失败恢复、真实字体加载、菜单伸缩及跨 lg 布局。跨 lg 后表格切换为文档流时,其原容器滚动值会归零,这是原有响应式行为,不属于本轮刷新验收结果。

本地测试只覆盖实际修改风险,正常 PR 必需检查继续执行。真实验证须另用本次固定账本:一个账号,Astra/Sol/Luna 各最多采集与复验一次,另最多一次 WS;每次 25 秒、128 KiB 读取上限,失败不追加请求。真实结果、生产镜像及部署指针由工作区接手手册和本次交付证据维护;本文件不把离线成功写成线上模型质量证明。
本地测试只覆盖实际修改风险,正常 PR 必需检查继续执行;同代码的成功结果复用。提示词重构使用离线编排、模拟上游与隔离 PostgreSQL 验证,不发真实模型请求。生产镜像及部署指针由工作区接手手册和交付证据维护,离线或部署健康结果不代表模型质量。
2 changes: 2 additions & 0 deletions .github/workflows/downstream-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ jobs:
src/components/account/__tests__/BulkEditAccountModal.spec.ts \
src/views/admin/__tests__/SystemPromptsView.spec.ts \
src/views/admin/__tests__/SystemPromptsView.locale.spec.ts \
src/views/admin/__tests__/systemPromptsIntegrationSurface.spec.ts \
src/api/admin/__tests__/systemPrompts.spec.ts \
src/components/admin/systemPrompt/__tests__/PromptRules.spec.ts \
src/views/admin/__tests__/AccountsView.console.spec.ts \
src/views/admin/__tests__/AccountsView.priorityColumn.spec.ts \
Expand Down
22 changes: 11 additions & 11 deletions backend/cmd/server/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions backend/internal/handler/admin/setting_handler_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
response.ErrorFrom(c, err)
return
}
if (req.ClaudeOAuthSystemPrompt != nil && *req.ClaudeOAuthSystemPrompt != previousSettings.ClaudeOAuthSystemPrompt) ||
(req.ClaudeOAuthSystemPromptBlocks != nil && *req.ClaudeOAuthSystemPromptBlocks != previousSettings.ClaudeOAuthSystemPromptBlocks) {
response.ErrorWithDetails(c, http.StatusConflict, "Custom prompts are managed in System Prompts; use /api/v1/admin/system-prompts/config", "prompt_configuration_moved", nil)
return
}
previousAuthSourceDefaults, err := h.settingService.GetAuthSourceDefaultSettings(c.Request.Context())
if err != nil {
response.ErrorFrom(c, err)
Expand Down
37 changes: 37 additions & 0 deletions backend/internal/handler/admin/system_prompt_config_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package admin

import (
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
)

func (h *SystemPromptHandler) Config(c *gin.Context) {
state, err := h.service.PromptConfig(c.Request.Context())
if err != nil {
writeBusinessSystemPromptError(c, err)
return
}
c.Header("Cache-Control", "no-store")
response.Success(c, state)
}

func (h *SystemPromptHandler) SaveConfig(c *gin.Context) {
var request service.PromptConfigUpdate
if err := c.ShouldBindJSON(&request); err != nil {
response.BadRequest(c, "Invalid prompt configuration")
return
}
actor, ok := h.actorID(c)
if !ok {
return
}
state, err := h.service.SavePromptConfig(c.Request.Context(), request, actor)
if err != nil {
writeBusinessSystemPromptError(c, err)
return
}
middleware.SetAuditExtra(c, map[string]any{"revision": state.Revision, "rule_count": len(state.Policy.Rules), "result": "prompt_config_saved"})
response.Success(c, state)
}
Loading
Loading