new task lag
This commit is contained in:
+100
-36
@@ -380,6 +380,20 @@ func (m *Manager) Recover(ctx context.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
pending, err := m.store.SessionPending(ctx, sess.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pending {
|
||||
found, err := m.deliverRecorded(ctx, sess, task)
|
||||
if err != nil {
|
||||
slog.Error("resume session: deliver its recorded message", "session", sess.Id, "task", task.Id, "err", err)
|
||||
}
|
||||
if found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
l, err := m.ensureLive(ctx, sess, task)
|
||||
if err != nil {
|
||||
ferr := m.failResume(ctx, sess, task, err)
|
||||
@@ -399,7 +413,7 @@ func (m *Manager) Recover(ctx context.Context) error {
|
||||
notice = discardRestartPrompt
|
||||
}
|
||||
}
|
||||
err = m.message(ctx, l, "byre", notice, nil)
|
||||
err = m.message(ctx, sess, task, l, "byre", notice, nil)
|
||||
if err != nil {
|
||||
ferr := m.failResume(ctx, sess, task, err)
|
||||
if ferr != nil {
|
||||
@@ -566,28 +580,67 @@ func (m *Manager) startRunning(ctx context.Context, sess api.AgentSession, taskI
|
||||
}
|
||||
|
||||
func (m *Manager) launch(ctx context.Context, sess api.AgentSession, task api.Task, actor, text string, images []string) (api.AgentSession, error) {
|
||||
imgs, compacting, err := m.recordMessage(ctx, sess, task, actor, text, images)
|
||||
if err != nil {
|
||||
m.failStart(ctx, sess.Id, actor, err)
|
||||
return api.AgentSession{}, err
|
||||
}
|
||||
err = m.deliver(ctx, sess, task, actor, text, imgs, compacting)
|
||||
if err != nil {
|
||||
return api.AgentSession{}, err
|
||||
}
|
||||
return m.store.GetSession(ctx, sess.Id)
|
||||
}
|
||||
|
||||
func (m *Manager) deliver(ctx context.Context, sess api.AgentSession, task api.Task, actor, text string, imgs []image, compacting bool) error {
|
||||
l, err := m.ensureLive(ctx, sess, task)
|
||||
if err == nil {
|
||||
err = m.syncModel(ctx, l, sess.Model)
|
||||
}
|
||||
if err != nil {
|
||||
m.failStart(ctx, sess.Id, actor, err)
|
||||
return api.AgentSession{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
imgs, err := m.prepareMessage(ctx, l, actor, text, images)
|
||||
if err != nil {
|
||||
m.failStart(ctx, sess.Id, actor, err)
|
||||
return api.AgentSession{}, err
|
||||
}
|
||||
|
||||
err = l.sess.send(ctx, text, imgs)
|
||||
m.beginTurn(l, compacting)
|
||||
err = m.send(ctx, l, text, imgs)
|
||||
if err != nil {
|
||||
m.endMergeTurn(sess.Id, false)
|
||||
return api.AgentSession{}, err
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.store.GetSession(ctx, sess.Id)
|
||||
func (m *Manager) deliverRecorded(ctx context.Context, sess api.AgentSession, task api.Task) (bool, error) {
|
||||
ev, found, err := m.store.LastMessage(ctx, sess.Id)
|
||||
if err != nil || !found {
|
||||
return false, err
|
||||
}
|
||||
text, _ := ev.Payload["text"].(string)
|
||||
ids := []string{}
|
||||
raw, _ := ev.Payload["images"].([]any)
|
||||
for _, id := range raw {
|
||||
s, _ := id.(string)
|
||||
ids = append(ids, s)
|
||||
}
|
||||
imgs, err := m.readImages(ctx, ids)
|
||||
if err != nil {
|
||||
m.failStart(ctx, sess.Id, ev.Actor, err)
|
||||
return true, err
|
||||
}
|
||||
return true, m.deliver(ctx, sess, task, ev.Actor, text, imgs, isHandoffPrompt(ev.Actor, text))
|
||||
}
|
||||
|
||||
func (m *Manager) readImages(ctx context.Context, ids []string) ([]image, error) {
|
||||
imgs := []image{}
|
||||
for _, id := range ids {
|
||||
b, data, err := m.store.ReadBlob(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imgs = append(imgs, image{mediaType: b.ContentType, data: data})
|
||||
}
|
||||
return imgs, nil
|
||||
}
|
||||
|
||||
func (m *Manager) failStart(ctx context.Context, sessionID, actor string, err error) {
|
||||
@@ -625,32 +678,38 @@ func transition(ctx context.Context, st *store.Store, id string, from, to api.Ag
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Manager) message(ctx context.Context, l *live, actor, text string, images []string) error {
|
||||
imgs, err := m.prepareMessage(ctx, l, actor, text, images)
|
||||
func (m *Manager) message(ctx context.Context, sess api.AgentSession, task api.Task, l *live, actor, text string, images []string) error {
|
||||
imgs, compacting, err := m.recordMessage(ctx, sess, task, actor, text, images)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.sess.send(ctx, text, imgs)
|
||||
m.beginTurn(l, compacting)
|
||||
return m.send(ctx, l, text, imgs)
|
||||
}
|
||||
|
||||
func (m *Manager) prepareMessage(ctx context.Context, l *live, actor, text string, images []string) ([]image, error) {
|
||||
if l.implementer() && isMergeInPrompt(actor, text) {
|
||||
m.takeMergeTurn(l)
|
||||
func (m *Manager) send(ctx context.Context, l *live, text string, imgs []image) error {
|
||||
err := l.sess.send(ctx, text, imgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imgs := []image{}
|
||||
for _, id := range images {
|
||||
b, data, err := m.store.ReadBlob(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imgs = append(imgs, image{mediaType: b.ContentType, data: data})
|
||||
return m.store.MarkSessionDelivered(ctx, l.id)
|
||||
}
|
||||
|
||||
func (m *Manager) recordMessage(ctx context.Context, sess api.AgentSession, task api.Task, actor, text string, images []string) ([]image, bool, error) {
|
||||
implementer := sess.Role == api.Implementer
|
||||
if implementer && isMergeInPrompt(actor, text) {
|
||||
m.ownMerge(sess.Id, task.Id, task.WorktreePath)
|
||||
}
|
||||
imgs, err := m.readImages(ctx, images)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
payload := map[string]any{"text": text}
|
||||
if l.implementer() {
|
||||
head, err := git.Head(l.dir)
|
||||
if implementer {
|
||||
head, err := git.Head(task.WorktreePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
payload["head"] = head
|
||||
}
|
||||
@@ -664,11 +723,14 @@ func (m *Manager) prepareMessage(ctx context.Context, l *live, actor, text strin
|
||||
if isContinuation(actor, text) {
|
||||
payload["continuation"] = true
|
||||
}
|
||||
err := m.emit(ctx, l, actor, "user.message", payload)
|
||||
err = m.store.RecordTurnMessage(ctx, sess.Id, newEvent(sess.Id, sess.Owner, task.ProjectId, task.Id, actor, "user.message", payload))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
return imgs, compacting, nil
|
||||
}
|
||||
|
||||
func (m *Manager) beginTurn(l *live, compacting bool) {
|
||||
m.mu.Lock()
|
||||
l.interrupted = false
|
||||
l.asked = false
|
||||
@@ -678,8 +740,6 @@ func (m *Manager) prepareMessage(ctx context.Context, l *live, actor, text strin
|
||||
l.rateLimited = nil
|
||||
l.lastText = ""
|
||||
m.mu.Unlock()
|
||||
|
||||
return imgs, nil
|
||||
}
|
||||
|
||||
func (m *Manager) ensureLive(ctx context.Context, sess api.AgentSession, task api.Task) (*live, error) {
|
||||
@@ -1357,18 +1417,22 @@ func (m *Manager) emit(ctx context.Context, l *live, actor, kind string, payload
|
||||
}
|
||||
|
||||
func (m *Manager) event(l *live, actor, kind string, payload map[string]any) api.Event {
|
||||
return newEvent(l.id, l.owner, l.projectID, l.taskID, actor, kind, payload)
|
||||
}
|
||||
|
||||
func newEvent(sessionID, owner, projectID, taskID, actor, kind string, payload map[string]any) api.Event {
|
||||
ev := api.Event{
|
||||
Kind: kind,
|
||||
AgentSessionId: &l.id,
|
||||
AgentSessionId: &sessionID,
|
||||
Actor: actor,
|
||||
Payload: payload,
|
||||
}
|
||||
if l.owner != "" {
|
||||
ev.Owner = &l.owner
|
||||
if owner != "" {
|
||||
ev.Owner = &owner
|
||||
return ev
|
||||
}
|
||||
ev.ProjectId = &l.projectID
|
||||
ev.TaskId = &l.taskID
|
||||
ev.ProjectId = &projectID
|
||||
ev.TaskId = &taskID
|
||||
return ev
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user