summaryrefslogtreecommitdiff
path: root/internal/lsp/chat_service.go
blob: fd39e144d870a0ddbcf0395c8f7aae438ed57c7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package lsp

import (
	"sync"
	"time"
)

// chatService owns the in-editor chat subsystem that used to be inlined on
// Server. It tracks editor input activity (used by the completion debounce
// gate) and reaches back into the Server (via srv) for shared infrastructure
// such as configuration, LLM clients, document access and edit dispatch.
//
// Pulling this out of Server keeps the chat detection/history/command logic
// cohesive and gives the input-activity clock its own small mutex instead of
// piggy-backing on Server.mu.
type chatService struct {
	srv *Server

	activityMu sync.RWMutex
	lastInput  time.Time
}

// newChatService constructs the chat subsystem bound to srv.
func newChatService(srv *Server) *chatService {
	return &chatService{srv: srv}
}

// markActivity records that the editor just sent input. The completion
// debounce gate uses this timestamp to decide how long to wait before issuing
// an LLM request.
func (c *chatService) markActivity() {
	c.activityMu.Lock()
	c.lastInput = time.Now()
	c.activityMu.Unlock()
}

// lastActivity returns the most recent input timestamp (zero if none yet).
func (c *chatService) lastActivity() time.Time {
	c.activityMu.RLock()
	defer c.activityMu.RUnlock()
	return c.lastInput
}

// chatSvc returns the chat subsystem, lazily constructing it for the bare
// Server literals used in some tests. Production code always has it wired up
// by NewServer.
func (s *Server) chatSvc() *chatService {
	if s.chat == nil {
		s.chat = newChatService(s)
	}
	return s.chat
}