Add usage commands, a vendor-neutral usage format and a knowledge base
This commit is contained in:
+29
-42
@@ -46,22 +46,23 @@ type Manager struct {
|
||||
clients *clients.Registry
|
||||
terminals *terminal.Terminals
|
||||
|
||||
mu sync.Mutex
|
||||
live map[string]*live
|
||||
starting map[string]*start
|
||||
closing bool
|
||||
rateLimits map[api.AgentSessionVendor]map[string]any
|
||||
leadAnswered map[string]bool
|
||||
paneFocus map[string]api.PaneFocus
|
||||
paneReported map[string]time.Time
|
||||
paneMoved map[string]time.Time
|
||||
humanMoved map[string]time.Time
|
||||
moveRefused map[string]bool
|
||||
startedTodo map[string]time.Time
|
||||
startRefused map[string]bool
|
||||
finishing map[string]bool
|
||||
handoffModel map[string]string
|
||||
mergeTurns map[string]mergeTurn
|
||||
mu sync.Mutex
|
||||
live map[string]*live
|
||||
starting map[string]*start
|
||||
closing bool
|
||||
rateLimits map[api.AgentSessionVendor]api.Usage
|
||||
usageCommands map[api.AgentSessionVendor]string
|
||||
leadAnswered map[string]bool
|
||||
paneFocus map[string]api.PaneFocus
|
||||
paneReported map[string]time.Time
|
||||
paneMoved map[string]time.Time
|
||||
humanMoved map[string]time.Time
|
||||
moveRefused map[string]bool
|
||||
startedTodo map[string]time.Time
|
||||
startRefused map[string]bool
|
||||
finishing map[string]bool
|
||||
handoffModel map[string]string
|
||||
mergeTurns map[string]mergeTurn
|
||||
|
||||
deliverMu sync.Mutex
|
||||
deliverLocks map[string]*sessionLock
|
||||
@@ -76,6 +77,8 @@ type Manager struct {
|
||||
|
||||
reviewMu sync.Mutex
|
||||
|
||||
usageMu map[api.AgentSessionVendor]*sync.Mutex
|
||||
|
||||
workflowMu sync.Mutex
|
||||
|
||||
bad *badLines
|
||||
@@ -141,7 +144,9 @@ func New(st *store.Store, worktreeRoot, leadRoot, handsRoot, codexHome, antigrav
|
||||
live: map[string]*live{},
|
||||
starting: map[string]*start{},
|
||||
deliverLocks: map[string]*sessionLock{},
|
||||
rateLimits: map[api.AgentSessionVendor]map[string]any{},
|
||||
rateLimits: map[api.AgentSessionVendor]api.Usage{},
|
||||
usageCommands: map[api.AgentSessionVendor]string{},
|
||||
usageMu: map[api.AgentSessionVendor]*sync.Mutex{api.Claude: {}, api.Codex: {}, api.Antigravity: {}},
|
||||
leadAnswered: map[string]bool{},
|
||||
paneFocus: map[string]api.PaneFocus{},
|
||||
paneReported: map[string]time.Time{},
|
||||
@@ -160,8 +165,7 @@ func New(st *store.Store, worktreeRoot, leadRoot, handsRoot, codexHome, antigrav
|
||||
watchStop: make(chan struct{}),
|
||||
}
|
||||
go m.signalLoop()
|
||||
go m.readCodexRateLimit()
|
||||
go m.readAgyRateLimit()
|
||||
go m.loadUsage()
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -504,13 +508,13 @@ func (m *Manager) LiveCount() int {
|
||||
|
||||
type Usage struct {
|
||||
Running []api.TurnRef
|
||||
RateLimits map[string]map[string]any
|
||||
RateLimits map[string]api.Usage
|
||||
}
|
||||
|
||||
func (m *Manager) Usage(ctx context.Context) (Usage, error) {
|
||||
u := Usage{
|
||||
Running: []api.TurnRef{},
|
||||
RateLimits: map[string]map[string]any{},
|
||||
RateLimits: map[string]api.Usage{},
|
||||
}
|
||||
|
||||
running, err := m.store.SessionsInState(ctx, api.AgentSessionStateRunning)
|
||||
@@ -738,7 +742,7 @@ func (m *Manager) startLive(ctx context.Context, sess api.AgentSession, task api
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tools := append([]mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.mergeToMainTool(l), m.setTaskSummaryTool(l), m.searchClosedTool(l), m.exposePortTool(l), m.takeSnapshotTool(l), m.terminalReadTool(l), m.terminalTypeTool(l), m.bashTool(l)}, append(m.subtaskTools(l), m.clientTools(l)...)...)
|
||||
tools := append([]mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.mergeToMainTool(l), m.setTaskSummaryTool(l), m.searchClosedTool(l), m.exposePortTool(l), m.takeSnapshotTool(l), m.terminalReadTool(l), m.terminalTypeTool(l), m.bashTool(l), m.readKnowledgeTool()}, append(m.subtaskTools(l), m.clientTools(l)...)...)
|
||||
lead := true
|
||||
if sess.Role == api.Implementer {
|
||||
g += longTitleGuidance(task)
|
||||
@@ -806,7 +810,7 @@ func (m *Manager) startLive(ctx context.Context, sess api.AgentSession, task api
|
||||
return nil, err
|
||||
}
|
||||
l.notes = "\n\n" + notes
|
||||
tools = m.leadTools(l)
|
||||
tools = append(m.leadTools(l), m.readKnowledgeTool())
|
||||
env = nil
|
||||
}
|
||||
servers := []*mcp.Server{{Name: "byre", Version: "0.0.0", Tools: tools}}
|
||||
@@ -1001,14 +1005,12 @@ func (m *Manager) handle(ctx context.Context, l *live, ev claude.Event) error {
|
||||
return err
|
||||
}
|
||||
|
||||
addClaudeWindowMins(info.RateLimitInfo)
|
||||
|
||||
m.mu.Lock()
|
||||
m.rateLimits[l.vendor] = info.RateLimitInfo
|
||||
if info.RateLimitInfo["status"] == "rejected" {
|
||||
l.rateLimited = info.RateLimitInfo
|
||||
}
|
||||
m.mu.Unlock()
|
||||
m.setVendorUsage(l.vendor, claudeUsage(info.RateLimitInfo))
|
||||
|
||||
case "system":
|
||||
if ev.Subtype == "init" {
|
||||
@@ -1057,6 +1059,7 @@ type endResult struct {
|
||||
}
|
||||
|
||||
func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
go m.readUsage(l.vendor)
|
||||
if l.owner != "" {
|
||||
return m.leadTurnEnded(ctx, l, res)
|
||||
}
|
||||
@@ -1339,22 +1342,6 @@ func (m *Manager) event(l *live, actor, kind string, payload map[string]any) api
|
||||
return ev
|
||||
}
|
||||
|
||||
func addClaudeWindowMins(info map[string]any) {
|
||||
windows, _ := info["unifiedWindows"].(map[string]any)
|
||||
for name, w := range windows {
|
||||
window, ok := w.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(name, "five_hour"):
|
||||
window["windowMins"] = 5 * 60
|
||||
case strings.HasPrefix(name, "seven_day"):
|
||||
window["windowMins"] = 7 * 24 * 60
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decode(raw json.RawMessage) (any, error) {
|
||||
if len(raw) == 0 {
|
||||
return nil, nil
|
||||
|
||||
Reference in New Issue
Block a user