@@ -14,11 +14,9 @@ import (
16 "github.com/charmbracelet/crush/internal/config"
16 "github.com/charmbracelet/crush/internal/config"
17− "github.com/charmbracelet/crush/internal/history"
18 "github.com/charmbracelet/crush/internal/message"
17 "github.com/charmbracelet/crush/internal/message"
19 "github.com/charmbracelet/crush/internal/proto"
18 "github.com/charmbracelet/crush/internal/proto"
20 "github.com/charmbracelet/crush/internal/pubsub"
19 "github.com/charmbracelet/crush/internal/pubsub"
21− "github.com/charmbracelet/crush/internal/session"
22 "github.com/charmbracelet/x/powernap/pkg/lsp/protocol"
20 "github.com/charmbracelet/x/powernap/pkg/lsp/protocol"
@@ -404,8 +402,8 @@ func (c *Client) InitiateAgentProcessing(ctx context.Context, id string) error {
404 return nil
402 return nil
407−// ListMessages retrieves all messages for a session.
405+// ListMessages retrieves all messages for a session as proto types.
408−func (c *Client) ListMessages(ctx context.Context, id string, sessionID string) ([]message.Message, error) {
406+func (c *Client) ListMessages(ctx context.Context, id string, sessionID string) ([]proto.Message, error) {
409 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/messages", id, sessionID), nil, nil)
407 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/messages", id, sessionID), nil, nil)
410 if err != nil {
408 if err != nil {
411 return nil, fmt.Errorf("failed to get messages: %w", err)
409 return nil, fmt.Errorf("failed to get messages: %w", err)
@@ -414,15 +412,15 @@ func (c *Client) ListMessages(ctx context.Context, id string, sessionID string)
414 if rsp.StatusCode != http.StatusOK {
412 if rsp.StatusCode != http.StatusOK {
415 return nil, fmt.Errorf("failed to get messages: status code %d", rsp.StatusCode)
413 return nil, fmt.Errorf("failed to get messages: status code %d", rsp.StatusCode)
417− var protoMsgs []proto.Message
415+ var msgs []proto.Message
418− if err := json.NewDecoder(rsp.Body).Decode(&protoMsgs); err != nil && !errors.Is(err, io.EOF) {
416+ if err := json.NewDecoder(rsp.Body).Decode(&msgs); err != nil && !errors.Is(err, io.EOF) {
419 return nil, fmt.Errorf("failed to decode messages: %w", err)
417 return nil, fmt.Errorf("failed to decode messages: %w", err)
421− return protoToMessages(protoMsgs), nil
419+ return msgs, nil
424−// GetSession retrieves a specific session.
422+// GetSession retrieves a specific session as a proto type.
425−func (c *Client) GetSession(ctx context.Context, id string, sessionID string) (*session.Session, error) {
423+func (c *Client) GetSession(ctx context.Context, id string, sessionID string) (*proto.Session, error) {
426 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s", id, sessionID), nil, nil)
424 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s", id, sessionID), nil, nil)
427 if err != nil {
425 if err != nil {
428 return nil, fmt.Errorf("failed to get session: %w", err)
426 return nil, fmt.Errorf("failed to get session: %w", err)
@@ -431,15 +429,15 @@ func (c *Client) GetSession(ctx context.Context, id string, sessionID string) (*
431 if rsp.StatusCode != http.StatusOK {
429 if rsp.StatusCode != http.StatusOK {
432 return nil, fmt.Errorf("failed to get session: status code %d", rsp.StatusCode)
430 return nil, fmt.Errorf("failed to get session: status code %d", rsp.StatusCode)
434− var sess session.Session
432+ var sess proto.Session
435 if err := json.NewDecoder(rsp.Body).Decode(&sess); err != nil {
433 if err := json.NewDecoder(rsp.Body).Decode(&sess); err != nil {
436 return nil, fmt.Errorf("failed to decode session: %w", err)
434 return nil, fmt.Errorf("failed to decode session: %w", err)
438 return &sess, nil
436 return &sess, nil
441−// ListSessionHistoryFiles retrieves history files for a session.
439+// ListSessionHistoryFiles retrieves history files for a session as proto types.
442−func (c *Client) ListSessionHistoryFiles(ctx context.Context, id string, sessionID string) ([]history.File, error) {
440+func (c *Client) ListSessionHistoryFiles(ctx context.Context, id string, sessionID string) ([]proto.File, error) {
443 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/history", id, sessionID), nil, nil)
441 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/history", id, sessionID), nil, nil)
444 if err != nil {
442 if err != nil {
445 return nil, fmt.Errorf("failed to get session history files: %w", err)
443 return nil, fmt.Errorf("failed to get session history files: %w", err)
@@ -448,16 +446,16 @@ func (c *Client) ListSessionHistoryFiles(ctx context.Context, id string, session
448 if rsp.StatusCode != http.StatusOK {
446 if rsp.StatusCode != http.StatusOK {
449 return nil, fmt.Errorf("failed to get session history files: status code %d", rsp.StatusCode)
447 return nil, fmt.Errorf("failed to get session history files: status code %d", rsp.StatusCode)
451− var files []history.File
449+ var files []proto.File
452 if err := json.NewDecoder(rsp.Body).Decode(&files); err != nil {
450 if err := json.NewDecoder(rsp.Body).Decode(&files); err != nil {
453 return nil, fmt.Errorf("failed to decode session history files: %w", err)
451 return nil, fmt.Errorf("failed to decode session history files: %w", err)
455 return files, nil
453 return files, nil
458−// CreateSession creates a new session in a workspace.
456+// CreateSession creates a new session in a workspace as a proto type.
459−func (c *Client) CreateSession(ctx context.Context, id string, title string) (*session.Session, error) {
457+func (c *Client) CreateSession(ctx context.Context, id string, title string) (*proto.Session, error) {
460− rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/sessions", id), nil, jsonBody(session.Session{Title: title}), http.Header{"Content-Type": []string{"application/json"}})
458+ rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/sessions", id), nil, jsonBody(proto.Session{Title: title}), http.Header{"Content-Type": []string{"application/json"}})
461 if err != nil {
459 if err != nil {
462 return nil, fmt.Errorf("failed to create session: %w", err)
460 return nil, fmt.Errorf("failed to create session: %w", err)
@@ -465,15 +463,15 @@ func (c *Client) CreateSession(ctx context.Context, id string, title string) (*s
465 if rsp.StatusCode != http.StatusOK {
463 if rsp.StatusCode != http.StatusOK {
466 return nil, fmt.Errorf("failed to create session: status code %d", rsp.StatusCode)
464 return nil, fmt.Errorf("failed to create session: status code %d", rsp.StatusCode)
468− var sess session.Session
466+ var sess proto.Session
469 if err := json.NewDecoder(rsp.Body).Decode(&sess); err != nil {
467 if err := json.NewDecoder(rsp.Body).Decode(&sess); err != nil {
470 return nil, fmt.Errorf("failed to decode session: %w", err)
468 return nil, fmt.Errorf("failed to decode session: %w", err)
472 return &sess, nil
470 return &sess, nil
475−// ListSessions lists all sessions in a workspace.
473+// ListSessions lists all sessions in a workspace as proto types.
476−func (c *Client) ListSessions(ctx context.Context, id string) ([]session.Session, error) {
474+func (c *Client) ListSessions(ctx context.Context, id string) ([]proto.Session, error) {
477 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions", id), nil, nil)
475 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions", id), nil, nil)
478 if err != nil {
476 if err != nil {
479 return nil, fmt.Errorf("failed to get sessions: %w", err)
477 return nil, fmt.Errorf("failed to get sessions: %w", err)
@@ -482,7 +480,7 @@ func (c *Client) ListSessions(ctx context.Context, id string) ([]session.Session
482 if rsp.StatusCode != http.StatusOK {
480 if rsp.StatusCode != http.StatusOK {
483 return nil, fmt.Errorf("failed to get sessions: status code %d", rsp.StatusCode)
481 return nil, fmt.Errorf("failed to get sessions: status code %d", rsp.StatusCode)
485− var sessions []session.Session
483+ var sessions []proto.Session
486 if err := json.NewDecoder(rsp.Body).Decode(&sessions); err != nil {
484 if err := json.NewDecoder(rsp.Body).Decode(&sessions); err != nil {
487 return nil, fmt.Errorf("failed to decode sessions: %w", err)
485 return nil, fmt.Errorf("failed to decode sessions: %w", err)
@@ -556,8 +554,8 @@ func jsonBody(v any) *bytes.Buffer {
559−// SaveSession updates a session in a workspace.
557+// SaveSession updates a session in a workspace, returning a proto type.
560−func (c *Client) SaveSession(ctx context.Context, id string, sess session.Session) (*session.Session, error) {
558+func (c *Client) SaveSession(ctx context.Context, id string, sess proto.Session) (*proto.Session, error) {
561 rsp, err := c.put(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s", id, sess.ID), nil, jsonBody(sess), http.Header{"Content-Type": []string{"application/json"}})
559 rsp, err := c.put(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s", id, sess.ID), nil, jsonBody(sess), http.Header{"Content-Type": []string{"application/json"}})
562 if err != nil {
560 if err != nil {
563 return nil, fmt.Errorf("failed to save session: %w", err)
561 return nil, fmt.Errorf("failed to save session: %w", err)
@@ -566,7 +564,7 @@ func (c *Client) SaveSession(ctx context.Context, id string, sess session.Sessio
566 if rsp.StatusCode != http.StatusOK {
564 if rsp.StatusCode != http.StatusOK {
567 return nil, fmt.Errorf("failed to save session: status code %d", rsp.StatusCode)
565 return nil, fmt.Errorf("failed to save session: status code %d", rsp.StatusCode)
569− var saved session.Session
567+ var saved proto.Session
570 if err := json.NewDecoder(rsp.Body).Decode(&saved); err != nil {
568 if err := json.NewDecoder(rsp.Body).Decode(&saved); err != nil {
571 return nil, fmt.Errorf("failed to decode session: %w", err)
569 return nil, fmt.Errorf("failed to decode session: %w", err)
@@ -586,8 +584,8 @@ func (c *Client) DeleteSession(ctx context.Context, id string, sessionID string)
586 return nil
584 return nil
589−// ListUserMessages retrieves user-role messages for a session.
587+// ListUserMessages retrieves user-role messages for a session as proto types.
590−func (c *Client) ListUserMessages(ctx context.Context, id string, sessionID string) ([]message.Message, error) {
588+func (c *Client) ListUserMessages(ctx context.Context, id string, sessionID string) ([]proto.Message, error) {
591 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/messages/user", id, sessionID), nil, nil)
589 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/messages/user", id, sessionID), nil, nil)
592 if err != nil {
590 if err != nil {
593 return nil, fmt.Errorf("failed to get user messages: %w", err)
591 return nil, fmt.Errorf("failed to get user messages: %w", err)
@@ -596,15 +594,15 @@ func (c *Client) ListUserMessages(ctx context.Context, id string, sessionID stri
596 if rsp.StatusCode != http.StatusOK {
594 if rsp.StatusCode != http.StatusOK {
597 return nil, fmt.Errorf("failed to get user messages: status code %d", rsp.StatusCode)
595 return nil, fmt.Errorf("failed to get user messages: status code %d", rsp.StatusCode)
599− var protoMsgs []proto.Message
597+ var msgs []proto.Message
600− if err := json.NewDecoder(rsp.Body).Decode(&protoMsgs); err != nil && !errors.Is(err, io.EOF) {
598+ if err := json.NewDecoder(rsp.Body).Decode(&msgs); err != nil && !errors.Is(err, io.EOF) {
601 return nil, fmt.Errorf("failed to decode user messages: %w", err)
599 return nil, fmt.Errorf("failed to decode user messages: %w", err)
603− return protoToMessages(protoMsgs), nil
601+ return msgs, nil
606−// ListAllUserMessages retrieves all user-role messages across sessions.
604+// ListAllUserMessages retrieves all user-role messages across sessions as proto types.
607−func (c *Client) ListAllUserMessages(ctx context.Context, id string) ([]message.Message, error) {
605+func (c *Client) ListAllUserMessages(ctx context.Context, id string) ([]proto.Message, error) {
608 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/messages/user", id), nil, nil)
606 rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/messages/user", id), nil, nil)
609 if err != nil {
607 if err != nil {
610 return nil, fmt.Errorf("failed to get all user messages: %w", err)
608 return nil, fmt.Errorf("failed to get all user messages: %w", err)
@@ -613,11 +611,11 @@ func (c *Client) ListAllUserMessages(ctx context.Context, id string) ([]message.
613 if rsp.StatusCode != http.StatusOK {
611 if rsp.StatusCode != http.StatusOK {
614 return nil, fmt.Errorf("failed to get all user messages: status code %d", rsp.StatusCode)
612 return nil, fmt.Errorf("failed to get all user messages: status code %d", rsp.StatusCode)
616− var protoMsgs []proto.Message
614+ var msgs []proto.Message
617− if err := json.NewDecoder(rsp.Body).Decode(&protoMsgs); err != nil && !errors.Is(err, io.EOF) {
615+ if err := json.NewDecoder(rsp.Body).Decode(&msgs); err != nil && !errors.Is(err, io.EOF) {
618 return nil, fmt.Errorf("failed to decode all user messages: %w", err)
616 return nil, fmt.Errorf("failed to decode all user messages: %w", err)
620− return protoToMessages(protoMsgs), nil
618+ return msgs, nil
623// CancelAgentSession cancels an ongoing agent operation for a session.
621// CancelAgentSession cancels an ongoing agent operation for a session.
@@ -749,64 +747,3 @@ func (c *Client) LSPStopAll(ctx context.Context, id string) error {
750 return nil
748 return nil
753−func protoToMessages(msgs []proto.Message) []message.Message {
754− out := make([]message.Message, len(msgs))
755− for i, m := range msgs {
756− out[i] = protoToMessage(m)
761−func protoToMessage(m proto.Message) message.Message {
762− msg := message.Message{
764− SessionID: m.SessionID,
765− Role: message.MessageRole(m.Role),
767− Provider: m.Provider,
768− CreatedAt: m.CreatedAt,
769− UpdatedAt: m.UpdatedAt,
772− for _, p := range m.Parts {
773− switch v := p.(type) {
774− case proto.TextContent:
775− msg.Parts = append(msg.Parts, message.TextContent{Text: v.Text})
776− case proto.ReasoningContent:
777− msg.Parts = append(msg.Parts, message.ReasoningContent{
778− Thinking: v.Thinking,
779− Signature: v.Signature,
780− StartedAt: v.StartedAt,
781− FinishedAt: v.FinishedAt,
783− case proto.ToolCall:
784− msg.Parts = append(msg.Parts, message.ToolCall{
788− Finished: v.Finished,
790− case proto.ToolResult:
791− msg.Parts = append(msg.Parts, message.ToolResult{
792− ToolCallID: v.ToolCallID,
798− msg.Parts = append(msg.Parts, message.Finish{
799− Reason: message.FinishReason(v.Reason),
804− case proto.ImageURLContent:
805− msg.Parts = append(msg.Parts, message.ImageURLContent{URL: v.URL, Detail: v.Detail})
806− case proto.BinaryContent:
807− msg.Parts = append(msg.Parts, message.BinaryContent{Path: v.Path, MIMEType: v.MIMEType, Data: v.Data})