fix(ui): restore pills to-do in client/server mode

Christian Rocha created

Change summary

internal/proto/proto.go                |  2 
internal/proto/session.go              |  8 +++++++
internal/server/events.go              | 16 ++++++++++++++
internal/workspace/client_workspace.go | 32 ++++++++++++++++++++++++++++
4 files changed, 57 insertions(+), 1 deletion(-)

Detailed changes

internal/proto/proto.go 🔗

@@ -56,7 +56,7 @@ type AgentSession struct {
 
 // IsZero checks if the AgentSession is zero-valued.
 func (a AgentSession) IsZero() bool {
-	return a == AgentSession{}
+	return a.ID == "" && !a.IsBusy
 }
 
 // PermissionAction represents an action taken on a permission request.

internal/proto/session.go 🔗

@@ -10,6 +10,14 @@ type Session struct {
 	CompletionTokens int64   `json:"completion_tokens"`
 	SummaryMessageID string  `json:"summary_message_id"`
 	Cost             float64 `json:"cost"`
+	Todos            []Todo  `json:"todos,omitempty"`
 	CreatedAt        int64   `json:"created_at"`
 	UpdatedAt        int64   `json:"updated_at"`
 }
+
+// Todo represents a single todo entry on a session in the proto layer.
+type Todo struct {
+	Content    string `json:"content"`
+	Status     string `json:"status"`
+	ActiveForm string `json:"active_form"`
+}

internal/server/events.go 🔗

@@ -135,11 +135,27 @@ func sessionToProto(s session.Session) proto.Session {
 		PromptTokens:     s.PromptTokens,
 		CompletionTokens: s.CompletionTokens,
 		Cost:             s.Cost,
+		Todos:            todosToProto(s.Todos),
 		CreatedAt:        s.CreatedAt,
 		UpdatedAt:        s.UpdatedAt,
 	}
 }
 
+func todosToProto(todos []session.Todo) []proto.Todo {
+	if len(todos) == 0 {
+		return nil
+	}
+	out := make([]proto.Todo, len(todos))
+	for i, t := range todos {
+		out[i] = proto.Todo{
+			Content:    t.Content,
+			Status:     string(t.Status),
+			ActiveForm: t.ActiveForm,
+		}
+	}
+	return out
+}
+
 func fileToProto(f history.File) proto.File {
 	return proto.File{
 		ID:        f.ID,

internal/workspace/client_workspace.go 🔗

@@ -671,11 +671,27 @@ func protoToSession(s proto.Session) session.Session {
 		PromptTokens:     s.PromptTokens,
 		CompletionTokens: s.CompletionTokens,
 		Cost:             s.Cost,
+		Todos:            protoToTodos(s.Todos),
 		CreatedAt:        s.CreatedAt,
 		UpdatedAt:        s.UpdatedAt,
 	}
 }
 
+func protoToTodos(todos []proto.Todo) []session.Todo {
+	if len(todos) == 0 {
+		return nil
+	}
+	out := make([]session.Todo, len(todos))
+	for i, t := range todos {
+		out[i] = session.Todo{
+			Content:    t.Content,
+			Status:     session.TodoStatus(t.Status),
+			ActiveForm: t.ActiveForm,
+		}
+	}
+	return out
+}
+
 func protoToFile(f proto.File) history.File {
 	return history.File{
 		ID:        f.ID,
@@ -770,7 +786,23 @@ func sessionToProto(s session.Session) proto.Session {
 		PromptTokens:     s.PromptTokens,
 		CompletionTokens: s.CompletionTokens,
 		Cost:             s.Cost,
+		Todos:            todosToProto(s.Todos),
 		CreatedAt:        s.CreatedAt,
 		UpdatedAt:        s.UpdatedAt,
 	}
 }
+
+func todosToProto(todos []session.Todo) []proto.Todo {
+	if len(todos) == 0 {
+		return nil
+	}
+	out := make([]proto.Todo, len(todos))
+	for i, t := range todos {
+		out[i] = proto.Todo{
+			Content:    t.Content,
+			Status:     string(t.Status),
+			ActiveForm: t.ActiveForm,
+		}
+	}
+	return out
+}