CrossRelay stage 0+1: Go gateway with Anthropic<->Chat Completions relay, Tauri shell, bilingual management UI
- Go gateway (stdlib only): /v1/messages non-stream + SSE, /v1/messages/count_tokens, management API /api/* (providers CRUD, apply/restore, settings, backups, logs) - Protocol conversion: Anthropic Messages <-> Chat Completions with a streaming state machine keyed by content block index (text, tool_use, parallel calls) - ~/.claude/settings.json guarded read/write: timestamped backups, managed env keys only, one-click restore - Tauri 2 shell: spawns the gateway sidecar, parses the random port from stdout, stdin pipe watchdog prevents orphans, kills the child on exit - React frontend: Dashboard/Providers/Settings, zh-CN + en-US, TanStack Query - Tests: Go table-driven + httptest integration (all green), vitest + RTL
This commit is contained in:
1 parent
8ee5e98ea3
commit
f8acf31ebc
71 files changed
+15727
-1
No files matched your search
@@ -0,0 +1,34 @@
|
||||
package gateway
|
||||
|
||||
import "sync"
|
||||
|
||||
// logRing keeps the most recent log entries in memory.
|
||||
type logRing struct {
|
||||
mu sync.Mutex
|
||||
entries []LogEntry
|
||||
cap int
|
||||
}
|
||||
|
||||
func newLogRing(capacity int) *logRing {
|
||||
return &logRing{cap: capacity}
|
||||
}
|
||||
|
||||
func (r *logRing) add(entry LogEntry) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.entries = append(r.entries, entry)
|
||||
if len(r.entries) > r.cap {
|
||||
r.entries = r.entries[len(r.entries)-r.cap:]
|
||||
}
|
||||
}
|
||||
|
||||
// list returns entries newest first.
|
||||
func (r *logRing) list() []LogEntry {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
out := make([]LogEntry, len(r.entries))
|
||||
for i, e := range r.entries {
|
||||
out[len(r.entries)-1-i] = e
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in new issue
Block a user