Sync thread names from Codex

This commit is contained in:
Codex
2026-05-21 09:47:05 +00:00
parent 660458af32
commit 1d433038ab
5 changed files with 162 additions and 21 deletions
+82 -21
View File
@@ -270,6 +270,7 @@ func (b *Bot) sendResumeChoices(ctx context.Context, userID, chatID int64, page
_, err := b.tg.SendMessage(ctx, chatID, text, SendMessageOptions{})
return err
}
threads = b.syncThreadTitles(ctx, threads)
hasNext := len(threads) > resumeThreadPageSize
if hasNext {
threads = threads[:resumeThreadPageSize]
@@ -302,11 +303,9 @@ func (b *Bot) resumeThreadByID(ctx context.Context, userID, chatID int64, id int
if err != nil {
return b.sendError(ctx, chatID, "Could not resume Codex thread", err)
}
if resumed.Name != "" && normalizeThreadTitle(resumed.Name) != thread.Title {
thread.Title = normalizeThreadTitle(resumed.Name)
if err := b.store.RenameThread(ctx, userID, thread.ID, thread.Title); err != nil {
return err
}
thread, err = b.applyCodexThreadTitle(ctx, thread, resumed)
if err != nil {
return err
}
if err := b.store.SetActiveThread(ctx, userID, thread.ID); err != nil {
return err
@@ -357,8 +356,17 @@ func (b *Bot) renameThread(ctx context.Context, userID, chatID int64, session st
if err := b.codex.SetThreadName(ctx, thread.CodexThreadID, title); err != nil {
return b.sendError(ctx, chatID, "Could not rename Codex thread", err)
}
if err := b.store.RenameThread(ctx, userID, thread.ID, title); err != nil {
return err
if codexThread, readErr := b.codex.ReadThread(ctx, thread.CodexThreadID); readErr == nil {
thread, err = b.applyCodexThreadTitle(ctx, thread, codexThread)
if err != nil {
return err
}
title = thread.Title
} else {
b.logger.Printf("read renamed thread %s: %v", thread.CodexThreadID, readErr)
if err := b.store.SyncThreadTitle(ctx, userID, thread.ID, title); err != nil {
return err
}
}
_, err = b.tg.SendMessage(ctx, chatID, fmt.Sprintf("Renamed thread ID %d: %s", thread.ID, title), SendMessageOptions{})
return err
@@ -373,10 +381,7 @@ func (b *Bot) forkThread(ctx context.Context, userID, chatID int64, session stor
if err != nil {
return b.sendError(ctx, chatID, "Could not fork Codex thread", err)
}
title := forked.Name
if title == "" {
title = "fork of ID " + strconv.FormatInt(thread.ID, 10)
}
title := codexThreadTitle(forked, "fork of ID "+strconv.FormatInt(thread.ID, 10))
local, err := b.store.CreateThread(ctx, userID, forked.ID, thread.WorkspaceID, title)
if err != nil {
return err
@@ -423,7 +428,15 @@ func (b *Bot) sendStatus(ctx context.Context, userID, chatID int64, session stor
}
thread := "(none)"
if session.ActiveThreadID != 0 {
thread = fmt.Sprintf("#%d", session.ActiveThreadID)
thread = fmt.Sprintf("ID %d", session.ActiveThreadID)
if active, err := b.store.GetThreadByID(ctx, userID, session.ActiveThreadID); err == nil {
if synced, syncErr := b.syncThreadTitle(ctx, active); syncErr == nil {
active = synced
} else {
b.logger.Printf("sync status thread title %s: %v", active.CodexThreadID, syncErr)
}
thread = fmt.Sprintf("ID %d: %s", active.ID, threadDisplayTitle(active))
}
}
model := session.Model
if model == "" {
@@ -703,6 +716,51 @@ func (b *Bot) continueThread(ctx context.Context, message *Message, session stor
return nil
}
func codexThreadTitle(thread codexapp.Thread, fallback string) string {
if title := normalizeThreadTitle(thread.Name); title != "" {
return title
}
if title := normalizeThreadTitle(thread.Preview); title != "" {
return title
}
return normalizeThreadTitle(fallback)
}
func (b *Bot) applyCodexThreadTitle(ctx context.Context, thread store.Thread, codexThread codexapp.Thread) (store.Thread, error) {
title := codexThreadTitle(codexThread, "")
if title == thread.Title {
return thread, nil
}
if err := b.store.SyncThreadTitle(ctx, thread.TelegramUserID, thread.ID, title); err != nil {
return thread, err
}
thread.Title = title
return thread, nil
}
func (b *Bot) syncThreadTitle(ctx context.Context, thread store.Thread) (store.Thread, error) {
if thread.CodexThreadID == "" {
return thread, nil
}
codexThread, err := b.codex.ReadThread(ctx, thread.CodexThreadID)
if err != nil {
return thread, err
}
return b.applyCodexThreadTitle(ctx, thread, codexThread)
}
func (b *Bot) syncThreadTitles(ctx context.Context, threads []store.Thread) []store.Thread {
for i := range threads {
synced, err := b.syncThreadTitle(ctx, threads[i])
if err != nil {
b.logger.Printf("sync thread title %s: %v", threads[i].CodexThreadID, err)
continue
}
threads[i] = synced
}
return threads
}
func (b *Bot) createNewThread(ctx context.Context, userID, chatID int64, session store.Session) (store.Thread, store.Workspace, error) {
workspace, err := b.resolveWorkspace(ctx, userID, session)
if err != nil {
@@ -712,13 +770,7 @@ func (b *Bot) createNewThread(ctx context.Context, userID, chatID int64, session
if err != nil {
return store.Thread{}, store.Workspace{}, b.sendError(ctx, chatID, "Could not start Codex thread", err)
}
title := codexThread.Name
if title == "" {
title = codexThread.Preview
}
if title == "" {
title = workspace.Label
}
title := codexThreadTitle(codexThread, workspace.Label)
thread, err := b.store.CreateThread(ctx, userID, codexThread.ID, workspace.ID, title)
if err != nil {
return store.Thread{}, store.Workspace{}, err
@@ -734,6 +786,11 @@ func (b *Bot) ensureThread(ctx context.Context, userID, chatID int64, session st
if session.ActiveThreadID != 0 {
thread, err := b.store.GetThreadByID(ctx, userID, session.ActiveThreadID)
if err == nil && !thread.Archived {
if synced, syncErr := b.syncThreadTitle(ctx, thread); syncErr == nil {
thread = synced
} else {
b.logger.Printf("sync active thread title %s: %v", thread.CodexThreadID, syncErr)
}
workspace, err := b.store.GetWorkspaceByID(ctx, thread.WorkspaceID)
return thread, workspace, err
}
@@ -1236,8 +1293,12 @@ func (b *Bot) handleCodexNotification(ctx context.Context, event codexapp.Event)
if err := json.Unmarshal(event.Params, &params); err != nil {
return err
}
if params.ThreadID != "" && params.ThreadName != nil {
return b.store.RenameThreadByCodexID(ctx, params.ThreadID, normalizeThreadTitle(*params.ThreadName))
if params.ThreadID != "" {
title := ""
if params.ThreadName != nil {
title = normalizeThreadTitle(*params.ThreadName)
}
return b.store.SyncThreadTitleByCodexID(ctx, params.ThreadID, title)
}
case "serverRequest/resolved":
var params struct {