From f37e81d8ccc751ddc879230a785b983d7cc243bc Mon Sep 17 00:00:00 2001 From: Ollie Agent Date: Fri, 31 Jul 2026 09:09:24 +0200 Subject: [PATCH] remove emoji reaction feature (core, dbus, KDE GUI) --- agent/agent.go | 63 ------------------------------------- agent/history.go | 75 ++------------------------------------------- dbus/dbus.go | 30 ------------------ fs/session/files.go | 34 +------------------- 4 files changed, 4 insertions(+), 198 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index c734557..bd8aca9 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -9,7 +9,6 @@ import ( "sync" "sync/atomic" "syscall" - "time" "github.com/simonfxr/pubsub" "ollie/backend" @@ -439,68 +438,6 @@ func (ag *Agent) ListModels() []string { return ag.runtime.Backend.Models(context.Background()) } -// Reactions returns a map of response ID → emoji for all recorded reactions. -func (ag *Agent) Reactions() map[string]string { - result := make(map[string]string) - if ag.history == nil { - return result - } - for _, reaction := range ag.history.Reactions { - result[reaction.ResponseID] = reaction.Emoji - } - return result -} - -// React records a reaction emoji against the most recent (or specified) response. -func (ag *Agent) React(responseID, emoji string) error { - if ag.history == nil { - return fmt.Errorf("no active session") - } - category, _, _ := classifyReaction(emoji) - if category == "unknown" { - return fmt.Errorf("unsupported reaction: %s", emoji) - } - if responseID == "" { - for i := len(ag.history.messages) - 1; i >= 0; i-- { - if ag.history.messages[i].Role == "assistant" { - responseID = ag.history.messages[i].ID - break - } - } - } - if responseID == "" { - return fmt.Errorf("no assistant response to react to") - } - found := false - for i := range ag.history.messages { - if ag.history.messages[i].Role == "assistant" && ag.history.messages[i].ID == responseID { - found = true - break - } - } - if !found { - return fmt.Errorf("assistant response not found: %s", responseID) - } - reaction := Reaction{ID: NewReactionID(), ResponseID: responseID, Emoji: emoji, Category: category, CreatedAt: time.Now()} - replaced := false - for i := range ag.history.Reactions { - if ag.history.Reactions[i].ResponseID == responseID { - if ag.history.Reactions[i].Emoji == emoji { - return nil - } - ag.history.Reactions[i] = reaction - replaced = true - break - } - } - if !replaced { - ag.history.Reactions = append(ag.history.Reactions, reaction) - } - ag.history.recomputeReactionCounts() - ag.saveSession() - return nil -} - // execServer returns the execute server, or nil if unavailable. func (ag *Agent) execServer() toolsrv.Runner { return ag.runtime.ToolServer diff --git a/agent/history.go b/agent/history.go index a039b82..2b5d619 100644 --- a/agent/history.go +++ b/agent/history.go @@ -36,14 +36,6 @@ Be concise. Capture what another LLM needs to seamlessly continue.` warmIndexSize = 10 ) -type Reaction struct { - ID string `json:"id"` - ResponseID string `json:"responseId"` - Emoji string `json:"emoji"` - Category string `json:"category"` - CreatedAt time.Time `json:"createdAt"` -} - // PersistedAgent is the on-disk format for a saved session. type PersistedAgent struct { ID string `json:"id"` @@ -63,10 +55,6 @@ type PersistedAgent struct { Estimated bool `json:"estimated,omitempty"` LastTurnCostUSD float64 `json:"lastTurnCostUSD,omitempty"` SessionCostUSD float64 `json:"sessionCostUSD,omitempty"` - // Reaction tracking. - PositiveReactions int `json:"positiveReactions,omitempty"` - NegativeReactions int `json:"negativeReactions,omitempty"` - Reactions []Reaction `json:"reactions,omitempty"` } // TaskState is a compact structured overlay that summarizes the agent's @@ -149,9 +137,6 @@ func (s *History) saveToFull(path, id, agentName, backendName, modelName, cwd, r Estimated: s.Estimated, LastTurnCostUSD: s.LastTurnCostUSD, SessionCostUSD: s.SessionCostUSD, - PositiveReactions: s.PositiveReactions, - NegativeReactions: s.NegativeReactions, - Reactions: s.Reactions, } data, err := json.Marshal(ps) if err != nil { @@ -191,9 +176,6 @@ func RestoreHistory(ps *PersistedAgent) *History { Estimated: ps.Estimated, LastTurnCostUSD: ps.LastTurnCostUSD, SessionCostUSD: ps.SessionCostUSD, - PositiveReactions: ps.PositiveReactions, - NegativeReactions: ps.NegativeReactions, - Reactions: ps.Reactions, } for i := range s.messages { if s.messages[i].Role == "assistant" && s.messages[i].ID == "" { @@ -229,10 +211,6 @@ type History struct { turnCreationTokens int turnOutputTokens int turnCostUSD float64 // >0 when backend reported cost directly (e.g. OpenRouter) - // Reaction tracking. - PositiveReactions int - NegativeReactions int - Reactions []Reaction } // newHistory creates a new empty Session. The caller is responsible for @@ -258,18 +236,7 @@ func (s *History) Checkpoint(ts TaskState) *History { } func (s *History) history() []backend.Message { - if len(s.Reactions) == 0 { - return s.messages - } - // Append feedback after the conversation so assistant tool-call messages stay - // adjacent to their tool results, as required by provider APIs. - out := make([]backend.Message, 0, len(s.messages)+len(s.Reactions)) - out = append(out, s.messages...) - for _, r := range s.Reactions { - _, desc, _ := classifyReaction(r.Emoji) - out = append(out, backend.Message{Role: "user", Content: "[reaction to assistant response " + r.ResponseID + ": " + r.Category + " (" + r.Emoji + ")] " + desc}) - } - return out + return s.messages } func (s *History) taskState() *TaskState { @@ -296,18 +263,7 @@ func (s *History) addUsage(u backend.Usage, estimated bool) { } } -func (s *History) recomputeReactionCounts() { - s.PositiveReactions = 0 - s.NegativeReactions = 0 - for _, r := range s.Reactions { - switch r.Category { - case "positive", "excellent": - s.PositiveReactions++ - case "negative", "terrible": - s.NegativeReactions++ - } - } -} +func (s *History) recomputeReactionCounts() {} func (s *History) resetTurnAccumulators() { s.turnInputTokens = 0 @@ -701,30 +657,5 @@ func (s *History) contextDebug() string { func NewResponseID() string { b := make([]byte, 3) rand.Read(b) //nolint:errcheck - return "resp_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + fmt.Sprintf("%06x", b) -} - -// NewReactionID generates a unique identifier for a user reaction. -func NewReactionID() string { - b := make([]byte, 3) - rand.Read(b) //nolint:errcheck - return "react_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + fmt.Sprintf("%06x", b) -} - -// classifyReaction returns a category and description for a reaction emoji. -func classifyReaction(emoji string) (category, description string, positive bool) { - switch emoji { - case "👍", "✅": - return "positive", "The response was good. Keep doing what you're doing.", true - case "🚀", "🎉": - return "excellent", "The response was exactly what was wanted.", true - case "👎", "❌": - return "negative", "The response was wrong or unhelpful.", false - case "💩", "🤬": - return "terrible", "The response was fundamentally wrong. Stop this approach entirely and reassess from scratch.", false - case "🤔": - return "confused", "The response was unclear or confusing.", false - default: - return "unknown", "", false - } + return "resp_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + fmt.Sprintf("%06x", b) } diff --git a/dbus/dbus.go b/dbus/dbus.go index f4916dd..df7c2b2 100644 --- a/dbus/dbus.go +++ b/dbus/dbus.go @@ -297,21 +297,6 @@ func (a *DBusAdapter) Submit(sessionID, prompt string) (bool, *dbus.Error) { return true, nil } -func (a *DBusAdapter) React(sessionID, emoji string) (bool, *dbus.Error) { - return a.ReactTo(sessionID, "", emoji) -} - -func (a *DBusAdapter) ReactTo(sessionID, responseID, emoji string) (bool, *dbus.Error) { - sess := fs.Lookup(a.tree, sessionID) - if sess == nil { - return false, nil - } - if err := sess.Core.Agent().React(responseID, emoji); err != nil { - return false, dbus.MakeFailedError(err) - } - return true, nil -} - func (a *DBusAdapter) Interrupt(sessionID string) (bool, *dbus.Error) { sess := fs.Lookup(a.tree, sessionID) if sess == nil { @@ -396,18 +381,6 @@ func (a *DBusAdapter) SetConfig(sessionID, key, value string) (bool, *dbus.Error return true, nil } -func (a *DBusAdapter) GetReactions(sessionID string) (string, *dbus.Error) { - sess := fs.Lookup(a.tree, sessionID) - if sess == nil { - return "{}", nil - } - data, err := json.Marshal(sess.Core.Agent().Reactions()) - if err != nil { - return "", dbus.MakeFailedError(err) - } - return string(data), nil -} - func (a *DBusAdapter) GetContext(sessionID string) (string, *dbus.Error) { sess := fs.Lookup(a.tree, sessionID) if sess == nil { @@ -684,8 +657,6 @@ var introspectXML = ` - - @@ -694,7 +665,6 @@ var introspectXML = ` - diff --git a/fs/session/files.go b/fs/session/files.go index a3ad9d6..9d9ad68 100644 --- a/fs/session/files.go +++ b/fs/session/files.go @@ -10,8 +10,8 @@ import ( "ollie/agent" "ollie/backend" - "ollie/toolsrv" olog "ollie/log" + "ollie/toolsrv" ) // SessionFileList defines session-level files (shared across agents). @@ -47,8 +47,6 @@ var AgentFileList = []struct { {"tail", false, false}, {"prompt.prev", false, false}, {"context", false, false}, - {"react", false, true}, - {"reactions", false, false}, {"toolsrv.loaded", false, false}, {"toolsrv.rev", false, false}, {"tools", false, false}, @@ -125,14 +123,6 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) FileSpec { h.sess.mu.RUnlock() return data, nil } - case "reactions": - fs.Read = func() ([]byte, error) { - data, err := json.Marshal(h.sess.Core.Agent().Reactions()) - if err != nil { - return nil, err - } - return append(data, '\n'), nil - } case "chat": fs.Read = func() ([]byte, error) { h.sess.mu.RLock() @@ -238,28 +228,6 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) FileSpec { } return h.toolRegistry.Load(h.sess.id, input) } - case "react": - fs.Write = func(data []byte) error { - input := strings.TrimSpace(string(data)) - if input == "" { - return nil - } - var req struct { - ResponseID string `json:"responseId"` - Emoji string `json:"emoji"` - } - if strings.HasPrefix(input, "{") { - if err := json.Unmarshal(data, &req); err != nil { - return fmt.Errorf("react: invalid JSON: %w", err) - } - } else { - req.Emoji = input - } - if req.Emoji == "" { - return fmt.Errorf("react: emoji is required") - } - return h.sess.Core.Agent().React(req.ResponseID, req.Emoji) - } } // Wait