diff --git a/internal/engine/engine.go b/internal/engine/engine.go index a0f0372..461a337 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -107,6 +107,13 @@ func (e *Engine) History() []message.Message { return e.history } +// InjectMessage appends a message to conversation history without triggering a turn. +// Used for system notifications (permission mode changes, incognito toggles) that +// the model should see as context in subsequent turns. +func (e *Engine) InjectMessage(msg message.Message) { + e.history = append(e.history, msg) +} + // Usage returns cumulative token usage. func (e *Engine) Usage() message.Usage { return e.usage diff --git a/internal/tui/app.go b/internal/tui/app.go index 4420b47..c44ff69 100644 --- a/internal/tui/app.go +++ b/internal/tui/app.go @@ -11,6 +11,7 @@ import ( "charm.land/bubbles/v2/textinput" "charm.land/lipgloss/v2" "somegit.dev/Owlibou/gnoma/internal/engine" + "somegit.dev/Owlibou/gnoma/internal/message" "somegit.dev/Owlibou/gnoma/internal/permission" "somegit.dev/Owlibou/gnoma/internal/security" "somegit.dev/Owlibou/gnoma/internal/session" @@ -126,13 +127,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Toggle incognito if m.config.Firewall != nil { m.incognito = m.config.Firewall.Incognito().Toggle() + var msg string if m.incognito { - m.messages = append(m.messages, chatMessage{role: "system", - content: "πŸ”’ incognito ON β€” no persistence, no learning, no logging"}) + msg = "πŸ”’ incognito ON β€” no persistence, no learning, no logging" } else { - m.messages = append(m.messages, chatMessage{role: "system", - content: "πŸ”“ incognito OFF"}) + msg = "πŸ”“ incognito OFF" } + m.messages = append(m.messages, chatMessage{role: "system", content: msg}) + m.injectSystemContext(msg) m.scrollOffset = 0 } return m, nil @@ -156,8 +158,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { next = permission.ModeBypass } m.config.Permissions.SetMode(next) - m.messages = append(m.messages, chatMessage{role: "system", - content: fmt.Sprintf("permission mode changed to: %s β€” previous tool denials no longer apply, retry if asked", next)}) + msg := fmt.Sprintf("permission mode changed to: %s β€” previous tool denials no longer apply, retry if asked", next) + m.messages = append(m.messages, chatMessage{role: "system", content: msg}) + m.injectSystemContext(msg) m.scrollOffset = 0 } return m, nil @@ -309,8 +312,9 @@ func (m Model) handleCommand(cmd string) (tea.Model, tea.Cmd) { return m, nil } m.config.Permissions.SetMode(mode) - m.messages = append(m.messages, chatMessage{role: "system", - content: fmt.Sprintf("permission mode changed to: %s β€” previous tool denials no longer apply, retry if asked", mode)}) + msg := fmt.Sprintf("permission mode changed to: %s β€” previous tool denials no longer apply, retry if asked", mode) + m.messages = append(m.messages, chatMessage{role: "system", content: msg}) + m.injectSystemContext(msg) return m, nil case "/provider": @@ -679,6 +683,17 @@ func wrapText(text string, width int) string { return result.String() } +// injectSystemContext adds a message to the engine's conversation history +// so the model sees it as context in subsequent turns. +func (m Model) injectSystemContext(text string) { + if m.config.Engine != nil { + m.config.Engine.InjectMessage(message.NewUserText("[system] " + text)) + // Immediately follow with a synthetic assistant acknowledgment + // so the conversation stays in userβ†’assistant alternation + m.config.Engine.InjectMessage(message.NewAssistantText("Understood.")) + } +} + func detectGitBranch() string { cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") out, err := cmd.Output()