This repository has been archived on 2026-07-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
codespace/internal/acp/history.go
T
tao.chen 2597d0d60c feat(backend): add opencode ACP (Agent Client Protocol) client
Adds a minimal but real ACP stack for the opencode process:

- pkg/config: process.args default ["acp"] (opencodeCommand still "opencode")
- internal/process: NewManager(command, args) — exec.Command uses args
- internal/acp (new): NDJSON transport + JSON-RPC client over the existing
  process stdio. Implements initialize / session/new / session/prompt /
  session/cancel. Serves fs/read_text_file and fs/write_text_file from the
  workspace's fs.FileSystem. terminal/* requests get MethodNotFound.
- internal/service/acp_service: per-workspace Client + mutex; starts the
  process on first prompt; transparently re-init on restart.
- internal/api/acp_handler: GET /acp/status, GET /acp/history,
  POST /acp/prompt, POST /acp/cancel.
- internal/model/acp: API DTOs.
- internal/acp/client_test: NDJSON split-lines, request/response correlation,
  notification dispatch, agent-initiated request handling (fs + terminal).

Existing process WS endpoint and Shell subsystem are unchanged.

Conversation: 019f354c-a51b-7ec3-83ad-c647e9b50b19
2026-07-06 11:03:59 +08:00

70 lines
1.4 KiB
Go

package acp
import (
"sync"
"time"
)
// Message is one entry in the conversation history.
type Message struct {
Role string `json:"role"`
Text string `json:"text"`
Time time.Time `json:"time"`
}
// History accumulates prompt/response messages in memory for a session.
type History struct {
mu sync.RWMutex
messages []Message
}
// NewHistory creates an empty History.
func NewHistory() *History {
return &History{}
}
// Add appends a message with the current time.
func (h *History) Add(role, text string) {
h.mu.Lock()
defer h.mu.Unlock()
h.messages = append(h.messages, Message{Role: role, Text: text, Time: time.Now()})
}
// List returns a copy of all messages, oldest first.
func (h *History) List() []Message {
h.mu.RLock()
defer h.mu.RUnlock()
out := make([]Message, len(h.messages))
copy(out, h.messages)
return out
}
// Len returns the number of stored messages.
func (h *History) Len() int {
h.mu.RLock()
defer h.mu.RUnlock()
return len(h.messages)
}
// Since returns messages starting at index idx.
func (h *History) Since(idx int) []Message {
h.mu.RLock()
defer h.mu.RUnlock()
if idx < 0 {
idx = 0
}
if idx > len(h.messages) {
idx = len(h.messages)
}
out := make([]Message, len(h.messages)-idx)
copy(out, h.messages[idx:])
return out
}
// Clear removes all stored messages.
func (h *History) Clear() {
h.mu.Lock()
defer h.mu.Unlock()
h.messages = h.messages[:0]
}