Keep queued messages visible across task switches
This commit is contained in:
+2
-2
File diff suppressed because one or more lines are too long
@@ -63,7 +63,11 @@ func (m *Manager) Message(ctx context.Context, sessionID, actor, text, model str
|
|||||||
sess.Model = model
|
sess.Model = model
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.store.AddTaskInput(ctx, store.TaskInput{TaskID: sess.TaskId, Actor: actor, Text: text, Images: images})
|
task, err := m.store.GetTask(ctx, sess.TaskId)
|
||||||
|
if err != nil {
|
||||||
|
return api.AgentSession{}, err
|
||||||
|
}
|
||||||
|
err = m.store.AddTaskInput(ctx, store.TaskInput{TaskID: sess.TaskId, Actor: actor, Text: text, Images: images}, task.ProjectId, sess.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.AgentSession{}, err
|
return api.AgentSession{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,15 +16,22 @@ type TaskInput struct {
|
|||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) AddTaskInput(ctx context.Context, in TaskInput) error {
|
func (s *Store) AddTaskInput(ctx context.Context, in TaskInput, projectID, sessionID string) error {
|
||||||
images, err := json.Marshal(append([]string{}, in.Images...))
|
images, err := json.Marshal(append([]string{}, in.Images...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
payload := map[string]any{"text": in.Text}
|
||||||
|
if len(in.Images) > 0 {
|
||||||
|
payload["images"] = in.Images
|
||||||
|
}
|
||||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||||
_, err := tx.ExecContext(ctx, `INSERT INTO task_inputs (task_id, actor, text, images, created_at) VALUES (?, ?, ?, ?, ?)`,
|
_, err := tx.ExecContext(ctx, `INSERT INTO task_inputs (task_id, actor, text, images, created_at) VALUES (?, ?, ?, ?, ?)`,
|
||||||
in.TaskID, in.Actor, in.Text, string(images), now())
|
in.TaskID, in.Actor, in.Text, string(images), now())
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return emit(sessionEvent("user.queued", projectID, in.TaskID, "", sessionID, in.Actor, payload))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -667,6 +667,9 @@ private struct PendingView: View {
|
|||||||
}
|
}
|
||||||
.padding(.vertical, 4)
|
.padding(.vertical, 4)
|
||||||
}
|
}
|
||||||
|
if !pending.imageIds.isEmpty {
|
||||||
|
MessageImages(ids: pending.imageIds)
|
||||||
|
}
|
||||||
if !pending.md.isEmpty {
|
if !pending.md.isEmpty {
|
||||||
MarkdownView(blocks: pending.md)
|
MarkdownView(blocks: pending.md)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,8 @@ struct PendingSend: Identifiable {
|
|||||||
let id: Int
|
let id: Int
|
||||||
let text: String
|
let text: String
|
||||||
let images: [PendingImage]
|
let images: [PendingImage]
|
||||||
|
let imageIds: [String]
|
||||||
|
let local: Bool
|
||||||
let queued: Bool
|
let queued: Bool
|
||||||
let md: [MDBlock]
|
let md: [MDBlock]
|
||||||
}
|
}
|
||||||
@@ -221,7 +223,7 @@ final class TranscriptBuilder {
|
|||||||
|
|
||||||
func showPending(_ text: String, _ images: [PendingImage]) -> () -> Void {
|
func showPending(_ text: String, _ images: [PendingImage]) -> () -> Void {
|
||||||
pendingIds += 1
|
pendingIds += 1
|
||||||
let entry = PendingSend(id: pendingIds, text: text, images: images, queued: running(), md: trimmed(text).isEmpty ? [] : parseMarkdown(text))
|
let entry = PendingSend(id: pendingIds, text: text, images: images, imageIds: [], local: true, queued: running(), md: trimmed(text).isEmpty ? [] : parseMarkdown(text))
|
||||||
pending.append(entry)
|
pending.append(entry)
|
||||||
ctx.run = nil
|
ctx.run = nil
|
||||||
return { [weak self] in
|
return { [weak self] in
|
||||||
@@ -229,8 +231,9 @@ final class TranscriptBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func confirmPending(_ text: String) {
|
private func confirmPending(_ text: String, queued: Bool, local: Bool) {
|
||||||
if let i = pending.firstIndex(where: { $0.text == text }) {
|
let i = queued ? pending.firstIndex { !$0.local && $0.text == text } : nil
|
||||||
|
if let i = i ?? (local ? pending.firstIndex { $0.local && $0.text == text } : nil) {
|
||||||
pending.remove(at: i)
|
pending.remove(at: i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -402,8 +405,21 @@ final class TranscriptBuilder {
|
|||||||
if sink == nil && ((ev.kind == "agent.message" && parent.isEmpty) || ev.kind == "turn.ended" || ev.kind == "user.message") {
|
if sink == nil && ((ev.kind == "agent.message" && parent.isEmpty) || ev.kind == "turn.ended" || ev.kind == "user.message") {
|
||||||
dropStream()
|
dropStream()
|
||||||
}
|
}
|
||||||
if sink == nil && ev.kind == "user.message" && ev.actor != "byre" {
|
if sink == nil && ev.kind == "user.message" {
|
||||||
confirmPending(str(p, "text") ?? "")
|
confirmPending(str(p, "text") ?? "", queued: true, local: ev.actor != "byre")
|
||||||
|
}
|
||||||
|
if sink == nil && (ev.kind == "task.merged" || ev.kind == "task.discarded") {
|
||||||
|
pending.removeAll { !$0.local }
|
||||||
|
}
|
||||||
|
if ev.kind == "user.queued" {
|
||||||
|
if sink == nil {
|
||||||
|
let text = str(p, "text") ?? ""
|
||||||
|
confirmPending(text, queued: false, local: true)
|
||||||
|
pendingIds += 1
|
||||||
|
let images = (p["images"] as? [(any Sendable)?] ?? []).map { jsString($0) }
|
||||||
|
pending.append(PendingSend(id: pendingIds, text: text, images: [], imageIds: images, local: false, queued: true, md: trimmed(text).isEmpty ? [] : parseMarkdown(text)))
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if ev.kind == "session.context" && sink != nil {
|
if ev.kind == "session.context" && sink != nil {
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user