Skip to content

Codex 对接 #13

Description

@SATA260

Codex 对接 模块

功能职责

把本机已安装的 Codex 接到现有对话里,让用户用和 Codex CLI、官方 Codex 扩展相同的操作把代码写完。

  • 发现本机是否装了 Codex、是否已取得 Codex 授权、Codex 有哪些模型与模式
  • 一个对话只走 Codex,并记住 Codex 的 thread 编号
  • 切换 Codex 的模型、推理强度、Plan、权限预设;只把用户改过的项交给 Codex
  • Codex 的 / 命令与官方扩展按钮是同一套动作
  • 给本条消息挂上 Codex 认的文件提及或图片
  • 向 Codex 发送、排队、手动打断
  • 按 Codex 的方式分叉对话、归档、改标题、新开对话
  • 回放 Codex 的可见进展:正文、推理、命令、改文件、方案
  • 回答 Codex 已知的反问:跑命令、改文件、补一句字、MCP 弹出的表单
  • Codex 问了本模块认不出的新提问,提示不兼容并回包,避免转圈
  • Codex 的 /mcp/skills 等只提示去终端改 Codex 配置,不在本模块里改

边界

  • 这是对接 Codex,不是给本地模型再加一个供应商;不走本地对话的工具、记忆装载和压缩。
  • 绑了 Codex 的对话不能中途改成本地模型;要换就开新对话。
  • 一个 Codex 对话同时只有一个进行中的回合;多个 Codex 对话可以同时各跑一个。进行中再发下一条只排队,不打断;要停掉当前一轮只能手动打断。当前一轮结束或被打断后,再开排队里的下一条。
  • 共用本机已有的 Codex 配置与授权,不另存密钥。未取得 Codex 授权时可以看选项,不能开回合。
  • 本模块落下的历史只给人看,不写回 Codex 当上下文;Codex 的 thread 失效就失败,不静默再开一条 thread。
  • 归档、分叉不删本机 Codex 记录。分叉是新对话加新的 Codex thread,原对话不动。
  • /mcp/skills 只提示去终端,不改 Codex 配置文件。这不等于不回答运行中弹出来的 MCP 表单:表单要做完整作答界面。
  • 跑命令、改文件、补一句字、MCP 表单都走完整界面。只有官方新加、本模块认不出的提问才提示不兼容;提示不兼容并回包,不等于用户拒绝了那条命令或改文件。
  • 工作目录跟当前仓库根走,不是每个对话自选。进程重启后,做到一半的 Codex 回合失败,不替用户重发。

内部拆分

引擎目录(Catalog)

管本机有没有 Codex、是否已取得 Codex 授权、Codex 允许选哪些模型与模式。不管对话,不管开回合。

type EngineStatus struct {
	Available  bool
	Authorized bool
	Version    string
	Hint       string // 不可用时给人看的原因,如未安装或未授权
}

type ModelInfo struct {
	ID            string
	Efforts       []string // 该 Codex 模型支持的推理强度
	DefaultEffort string
	Hidden        bool
	IsDefault     bool
}

type ModeInfo struct {
	ID       string // Codex 的 Plan 或权限预设名,如 auto、read-only、full-access
	Kind     string // collaboration | permission
	Approval string // Codex 的 approval 值;Plan 可空
	Sandbox  string // Codex 的 sandbox 值;Plan 可空
}

func Probe() (EngineStatus, error)     // 查看本机 Codex 是否可用、是否已取得授权。
func ListModels() ([]ModelInfo, error) // 列出 Codex 模型及各自支持的推理强度。
func ListModes() ([]ModeInfo, error)   // 列出 Codex 的 Plan 与权限预设。

会话(Session)

管走 Codex 的对话容器、Codex thread 编号、新建、归档、改标题、分叉。不管 Codex 配置项的值,不管回合怎么跑。

type Session struct {
	ID           string
	ThreadID     string // Codex thread 编号,首次开回合后才有
	Title        string
	ActiveTurnID string // 同时只能有一个进行中的回合
	Archived     bool
}

func Create(userID string) (Session, error)              // 创建一条只走 Codex 的对话。
func Get(sessionID string) (Session, error)              // 读取对话。
func BindThread(sessionID, threadID string) error        // 记下 Codex thread 编号,只能写一次。
func Archive(sessionID string) error                     // 归档,之后不能再向 Codex 开回合。
func Rename(sessionID, title string) error               // 改对话标题。
func Fork(sessionID string) (Session, error)             // 按已落盘历史分叉出新对话和新的 Codex thread,原对话不动。
func ClaimActiveTurn(sessionID, turnID string) error     // 标成当前执行;同时只能有一个。
func ClearActiveTurn(sessionID, turnID string) error     // 清掉当前执行标记。

官方配置(Settings)

管这个对话里生效的 Codex 模型、推理强度、Plan、权限,以及只有改过的项才交给 Codex。不管发消息,不管命令怎么拆词。

type Settings struct {
	Model             string
	Effort            string
	CollaborationMode string   // Codex 的 Plan;空表示非 Plan
	ApprovalPolicy    string   // Codex 的值,如 on-request
	Sandbox           string   // Codex 的值,如 workspace-write
	Cwd               string   // 仓库根
	Overridden        []string // 用户改过、需要交给 Codex 的字段名
}

func Effective(sessionID string) (Settings, error)             // 返回 Codex 默认与用户覆盖合并后的生效配置。
func Apply(sessionID string, patch Settings) (Settings, error) // 只记下用户改过的 Codex 项。

命令(Command)

管把 Codex 斜杠名和官方扩展按钮收成同一套动作:能做的交给会话、配置、回合或附件,不能做的只提示去终端。不管怎么对 Codex 说话。

type CommandAction string // apply_settings | turn | session | attach | hint

type CommandSpec struct {
	Name   string        // 与 Codex 斜杠同名,如 model、plan、fork、mcp
	Action CommandAction
	Hint   string        // hint 时给人看的话
}

type CommandResult struct {
	Hint string // 不能在本模块落地时给人看的说明
}

func List() []CommandSpec                                    // 列出与 Codex 斜杠、官方扩展按钮共用的命令。
func Invoke(sessionID, name, args string) (CommandResult, error) // 执行同名动作,或返回去终端改 Codex 配置的提示。

附件(Attachment)

管本条将要带给 Codex 的文件提及和图片。不管发送,不管工作目录从哪来。

type Input struct {
	Text     string
	Mentions []string // 仓库内路径,对 Codex 的 mention
	Images   []string // 本地图片路径,对 Codex 的 localImage
}

func Mention(sessionID, path string) error      // 把仓库内文件挂到待发给 Codex 的内容上。
func AttachImage(sessionID, path string) error  // 把本地图片挂到待发给 Codex 的内容上。
func TakeDraft(sessionID string) (Input, error) // 取出本条附件草稿并清空。

回合(Turn)

管一次用户请求对应的那一轮 Codex 工作:开始、排队、手动打断。不管实录怎么记,不管人怎么点批准。

type InputMode string // start | queue

type TurnStatus string // queued | running | waiting_approval | completed | failed | cancelled

type Turn struct {
	ID        string
	SessionID string
	Status    TurnStatus
}

func Start(sessionID, content string, input Input, mode InputMode) (turnID string, err error) // 空闲则向 Codex 开新一轮;进行中则排队,不打断。
func Queue(sessionID, content string, input Input) (turnID string, err error)                 // 等当前 Codex 一轮结束或被打断后再开。
func Cancel(turnID string) error                                                              // 用户手动打断当前一轮,并向 Codex 传播取消。
func Continue(turnID string) error                                                            // 审批有了结果后让 Codex 继续。

实录(Transcript)

管把 Codex 的进展落成给人看、可回放的记录。不管驱动 Codex,不管改磁盘。

type ProgressKind string // user | text | reasoning | command | file_change | plan | notice

type Progress struct {
	Kind    ProgressKind
	Text    string
	Command string
	Paths   []string
	Diff    string
}

func AppendUser(sessionID, turnID, text string, input Input) error // 记下用户这一条。
func AppendProgress(sessionID, turnID string, item Progress) error // 记下 Codex 的推理、正文、命令、改文件、方案或提示。
func Hydrate(sessionID string) ([]Progress, error)                // 按已落下的记录回放。

审批(Approval)

管 Codex 已知的反问:跑命令、改文件、补一句字、MCP 弹出的表单。不管官方新加、本模块认不出的提问,不管本地模型那套工具审批。

type DecisionScope string // once | session

type AskKind string // command | file_change | question | form

type ApprovalAsk struct {
	Kind              AskKind
	Command           string
	Paths             []string
	Diff              string
	Prompt            string   // 选择题或表单给人看的题面
	Options           []string // 补一句字时的选项
	Fields            []string // MCP 表单字段名
	ExternalRequestID string   // 用来回给 Codex 的那张问票
}

type AskAnswer struct {
	Approved bool
	Scope    DecisionScope
	Choice   string   // 选择题选中的项
	Values   []string // 表单填写结果
}

func Require(turnID string, ask ApprovalAsk) (approvalID string, err error) // 登记一条 Codex 已知的反问。
func Decide(approvalID string, answer AskAnswer) error                      // 按人对已知反问的作答记下结果。
func Expire(approvalID string) error                                        // 过期按拒绝回给 Codex,避免死等。

Codex(Codex)

管对本机 Codex 说话:开 thread、开一轮、打断、分叉、压缩、评审,以及把反问递进递出。不管本模块有多少对话,不管本地模型。

func StartThread(cwd string, settings Settings) (threadID string, err error)               // 让 Codex 新建一条 thread。
func ResumeThread(threadID string) error                                                   // 接上已有的 Codex thread。
func ForkThread(threadID string) (newThreadID string, err error)                           // 按 Codex 已落盘历史分叉出新 thread。
func StartTurn(threadID string, input Input, settings Settings) (turnID string, err error) // 让 Codex 开始一轮。
func Interrupt(threadID, turnID string) error                                              // 按用户请求打断 Codex 当前一轮。
func Compact(threadID string) error                                                        // 让 Codex 自己压缩上下文。
func Review(threadID string) error                                                         // 让 Codex 评审当前工作区改动。
func ReplyAsk(requestID string, answer AskAnswer) error                                    // 把人对已知反问的回答回给 Codex。
func RejectUnknown(requestID string) error                                                 // 官方新加、认不出的提问:提示不兼容并回包,避免卡死。

流程

用户选 Codex、改 Codex 配置、带文件发送、排队、回答已知反问、分叉、手动打断或重连;Codex 的配置类斜杠只给提示。

// 用户打开新对话并选 Codex
Catalog.Probe(...)
Catalog.ListModels(...)
Catalog.ListModes(...)
Session.Create(...)
Settings.Effective(...)

// 用户切换 Codex 模型或权限
Settings.Apply(...)
Command.Invoke(...)

// 用户挂上文件并发送给 Codex
Attachment.Mention(...)
Turn.Start(...)
Session.ClaimActiveTurn(...)
Codex.StartThread(...)
Session.BindThread(...)
Codex.StartTurn(...)
Transcript.AppendUser(...)

// Codex 流出进展
Transcript.AppendProgress(...)

// 用户回答 Codex 的命令、改文件、选择题或 MCP 表单
Approval.Require(...)
Approval.Decide(...)
Codex.ReplyAsk(...)
Turn.Continue(...)

// Codex 问了认不出的新提问
Transcript.AppendProgress(...)
Codex.RejectUnknown(...)
Turn.Continue(...)

// 用户在 Codex 进行中再发一条,先排队
Turn.Queue(...)
Transcript.AppendUser(...)

// 用户手动打断当前一轮;排着的下一条再开
Turn.Cancel(...)
Codex.Interrupt(...)
Session.ClearActiveTurn(...)
Turn.Start(...)
Session.ClaimActiveTurn(...)
Codex.StartTurn(...)

// 用户按 Codex 方式分叉对话
Command.Invoke(...)
Codex.ForkThread(...)
Session.Fork(...)

// 用户重连
Transcript.Hydrate(...)

// 用户点 Codex 的配置类斜杠
Command.Invoke(...)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    moduleSingle-module objects, interfaces, and design

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions