From e0482751fd00833f6bc6da08e221b87542fec20d Mon Sep 17 00:00:00 2001 From: Michael Meding Date: Sun, 3 May 2026 23:35:25 -0300 Subject: [PATCH] [codex] Reset scheduled metadata for new chats Manual chats should always start from chat defaults, even when the reused window session previously displayed a scheduled run. Resetting the origin metadata with the session identity prevents sidebar filtering and badges from inheriting schedule state. Add regression coverage for resetting a scheduled session and saving the first manual turn afterward. --- .../Chat/SessionSourcePersistenceTests.swift | 44 +++++++++++++++++++ .../OsaurusCore/Views/Chat/ChatView.swift | 4 ++ 2 files changed, 48 insertions(+) diff --git a/Packages/OsaurusCore/Tests/Chat/SessionSourcePersistenceTests.swift b/Packages/OsaurusCore/Tests/Chat/SessionSourcePersistenceTests.swift index 1a592de1a..39a203018 100644 --- a/Packages/OsaurusCore/Tests/Chat/SessionSourcePersistenceTests.swift +++ b/Packages/OsaurusCore/Tests/Chat/SessionSourcePersistenceTests.swift @@ -86,6 +86,50 @@ struct SessionSourcePersistenceTests { #expect(data.externalSessionKey == nil) } + @Test + func chatSession_resetClearsScheduledOriginForNextManualChat() { + let scheduleId = UUID() + let dispatchId = UUID() + let session = ChatSession() + session.source = .schedule + session.externalSessionKey = scheduleId.uuidString + session.dispatchTaskId = dispatchId + session.sessionId = dispatchId + session.title = "Scheduled report" + + session.reset() + + #expect(session.source == .chat) + #expect(session.sourcePluginId == nil) + #expect(session.externalSessionKey == nil) + #expect(session.dispatchTaskId == nil) + #expect(session.sessionId == nil) + #expect(session.turns.isEmpty) + } + + @Test + func chatSession_firstSaveAfterResetPersistsManualChatOrigin() async throws { + try await ChatHistoryTestStorage.run { + let scheduleId = UUID() + let dispatchId = UUID() + let session = ChatSession() + session.source = .schedule + session.externalSessionKey = scheduleId.uuidString + session.dispatchTaskId = dispatchId + session.sessionId = dispatchId + + session.reset() + session.turns = [ChatTurn(role: .user, content: "manual follow-up")] + session.save() + + let data = session.toSessionData() + #expect(data.source == .chat) + #expect(data.sourcePluginId == nil) + #expect(data.externalSessionKey == nil) + #expect(data.dispatchTaskId == nil) + } + } + @Test func executionContext_reattach_restoresIdAndOriginAndTurns() async { let originalId = UUID() diff --git a/Packages/OsaurusCore/Views/Chat/ChatView.swift b/Packages/OsaurusCore/Views/Chat/ChatView.swift index 26a8dc071..dc91d6eaa 100644 --- a/Packages/OsaurusCore/Views/Chat/ChatView.swift +++ b/Packages/OsaurusCore/Views/Chat/ChatView.swift @@ -572,6 +572,10 @@ final class ChatSession: ObservableObject { title = "New Chat" createdAt = Date() updatedAt = Date() + source = .chat + sourcePluginId = nil + externalSessionKey = nil + dispatchTaskId = nil isDirty = false // Reset agent-loop UI state.