diff options
| author | adamdottv <[email protected]> | 2025-05-28 15:36:31 -0500 |
|---|---|---|
| committer | adamdottv <[email protected]> | 2025-05-28 15:36:36 -0500 |
| commit | 9d7c5efb9b0b60c62aef3777b65b458a31ebbc88 (patch) | |
| tree | 0f5acb5b8093d872b30178ded53df719be40cf44 /internal/app | |
| parent | 8863a499a9e311a48d6ab8bc05d267fb2a01f060 (diff) | |
| download | opencode-9d7c5efb9b0b60c62aef3777b65b458a31ebbc88.tar.gz opencode-9d7c5efb9b0b60c62aef3777b65b458a31ebbc88.zip | |
wip: refactoring tui
Diffstat (limited to 'internal/app')
| -rw-r--r-- | internal/app/app.go | 180 | ||||
| -rw-r--r-- | internal/app/app_new.go | 203 | ||||
| -rw-r--r-- | internal/app/interfaces.go | 42 | ||||
| -rw-r--r-- | internal/app/lsp.go | 134 | ||||
| -rw-r--r-- | internal/app/services_bridge.go | 245 |
5 files changed, 0 insertions, 804 deletions
diff --git a/internal/app/app.go b/internal/app/app.go deleted file mode 100644 index 7aed6fb10..000000000 --- a/internal/app/app.go +++ /dev/null @@ -1,180 +0,0 @@ -package app - -import ( - "context" - "maps" - "sync" - "time" - - "log/slog" - - "github.com/sst/opencode/internal/config" - "github.com/sst/opencode/internal/fileutil" - "github.com/sst/opencode/internal/lsp" - "github.com/sst/opencode/internal/session" - "github.com/sst/opencode/internal/status" - "github.com/sst/opencode/internal/tui/theme" - "github.com/sst/opencode/pkg/client" -) - -type App struct { - State map[string]any - - CurrentSession *session.Session - Logs any // TODO: Define LogService interface when needed - Sessions SessionService - Messages MessageService - History any // TODO: Define HistoryService interface when needed - Permissions any // TODO: Define PermissionService interface when needed - Status status.Service - Client *client.ClientWithResponses - Events *client.Client - - PrimaryAgent AgentService - - LSPClients map[string]*lsp.Client - - clientsMutex sync.RWMutex - - watcherCancelFuncs []context.CancelFunc - cancelFuncsMutex sync.Mutex - watcherWG sync.WaitGroup - - // UI state - filepickerOpen bool - completionDialogOpen bool -} - -func New(ctx context.Context) (*App, error) { - // Initialize status service (still needed for UI notifications) - err := status.InitService() - if err != nil { - slog.Error("Failed to initialize status service", "error", err) - return nil, err - } - - // Initialize file utilities - fileutil.Init() - - // Create HTTP client - url := "http://localhost:16713" - httpClient, err := client.NewClientWithResponses(url) - if err != nil { - slog.Error("Failed to create client", "error", err) - return nil, err - } - eventClient, err := client.NewClient(url) - if err != nil { - slog.Error("Failed to create event client", "error", err) - return nil, err - } - - // Create service bridges - sessionBridge := NewSessionServiceBridge(httpClient) - messageBridge := NewMessageServiceBridge(httpClient) - agentBridge := NewAgentServiceBridge(httpClient) - - app := &App{ - State: make(map[string]any), - Client: httpClient, - Events: eventClient, - CurrentSession: &session.Session{}, - Sessions: sessionBridge, - Messages: messageBridge, - PrimaryAgent: agentBridge, - Status: status.GetService(), - LSPClients: make(map[string]*lsp.Client), - - // TODO: These services need API endpoints: - Logs: nil, // logging.GetService(), - History: nil, // history.GetService(), - Permissions: nil, // permission.GetService(), - } - - // Initialize theme based on configuration - app.initTheme() - - // Initialize LSP clients in the background - go app.initLSPClients(ctx) - - // TODO: Remove this once agent is fully replaced by API - // app.PrimaryAgent, err = agent.NewAgent( - // config.AgentPrimary, - // app.Sessions, - // app.Messages, - // agent.PrimaryAgentTools( - // app.Permissions, - // app.Sessions, - // app.Messages, - // app.History, - // app.LSPClients, - // ), - // ) - // if err != nil { - // slog.Error("Failed to create primary agent", "error", err) - // return nil, err - // } - - return app, nil -} - -// initTheme sets the application theme based on the configuration -func (app *App) initTheme() { - cfg := config.Get() - if cfg == nil || cfg.TUI.Theme == "" { - return // Use default theme - } - - // Try to set the theme from config - err := theme.SetTheme(cfg.TUI.Theme) - if err != nil { - slog.Warn("Failed to set theme from config, using default theme", "theme", cfg.TUI.Theme, "error", err) - } else { - slog.Debug("Set theme from config", "theme", cfg.TUI.Theme) - } -} - -// IsFilepickerOpen returns whether the filepicker is currently open -func (app *App) IsFilepickerOpen() bool { - return app.filepickerOpen -} - -// SetFilepickerOpen sets the state of the filepicker -func (app *App) SetFilepickerOpen(open bool) { - app.filepickerOpen = open -} - -// IsCompletionDialogOpen returns whether the completion dialog is currently open -func (app *App) IsCompletionDialogOpen() bool { - return app.completionDialogOpen -} - -// SetCompletionDialogOpen sets the state of the completion dialog -func (app *App) SetCompletionDialogOpen(open bool) { - app.completionDialogOpen = open -} - -// Shutdown performs a clean shutdown of the application -func (app *App) Shutdown() { - // Cancel all watcher goroutines - app.cancelFuncsMutex.Lock() - for _, cancel := range app.watcherCancelFuncs { - cancel() - } - app.cancelFuncsMutex.Unlock() - app.watcherWG.Wait() - - // Perform additional cleanup for LSP clients - app.clientsMutex.RLock() - clients := make(map[string]*lsp.Client, len(app.LSPClients)) - maps.Copy(clients, app.LSPClients) - app.clientsMutex.RUnlock() - - for name, client := range clients { - shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - if err := client.Shutdown(shutdownCtx); err != nil { - slog.Error("Failed to shutdown LSP client", "name", name, "error", err) - } - cancel() - } -} diff --git a/internal/app/app_new.go b/internal/app/app_new.go deleted file mode 100644 index 1568b4d57..000000000 --- a/internal/app/app_new.go +++ /dev/null @@ -1,203 +0,0 @@ -package app - -import ( - "context" - "encoding/json" - "fmt" - "sync" - - "log/slog" - - "github.com/sst/opencode/pkg/client" -) - -// AppNew is the new app structure that uses the TypeScript backend -type AppNew struct { - Client *client.Client - CurrentSession *client.SessionInfo - - // Event handling - eventCtx context.Context - eventCancel context.CancelFunc - eventChan <-chan any - - // UI state - filepickerOpen bool - completionDialogOpen bool - - // Mutex for thread-safe operations - mu sync.RWMutex -} - -// NewApp creates a new app instance connected to the TypeScript backend -func NewApp(ctx context.Context) (*AppNew, error) { - httpClient, err := client.NewClient("http://localhost:16713") - if err != nil { - slog.Error("Failed to create client", "error", err) - return nil, err - } - - app := &AppNew{ - Client: httpClient, - } - - // Start event listener - if err := app.startEventListener(ctx); err != nil { - return nil, err - } - - return app, nil -} - -// startEventListener connects to the SSE endpoint and processes events -func (a *AppNew) startEventListener(ctx context.Context) error { - a.eventCtx, a.eventCancel = context.WithCancel(ctx) - - eventChan, err := a.Client.Event(a.eventCtx) - if err != nil { - return err - } - - a.eventChan = eventChan - - // Start processing events in background - go a.processEvents() - - return nil -} - -// processEvents handles incoming SSE events -func (a *AppNew) processEvents() { - for event := range a.eventChan { - switch e := event.(type) { - case *client.EventStorageWrite: - // Handle storage write events - slog.Debug("Storage write event", "key", e.Key) - // TODO: Update local state based on storage events - default: - slog.Debug("Unknown event type", "event", e) - } - } -} - -// CreateSession creates a new session via the API -func (a *AppNew) CreateSession(ctx context.Context) error { - resp, err := a.Client.PostSessionCreate(ctx) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("failed to create session: %d", resp.StatusCode) - } - - var session client.SessionInfo - if err := json.NewDecoder(resp.Body).Decode(&session); err != nil { - return err - } - - a.mu.Lock() - a.CurrentSession = &session - a.mu.Unlock() - - return nil -} - -// SendMessage sends a message to the current session -func (a *AppNew) SendMessage(ctx context.Context, text string) error { - if a.CurrentSession == nil { - if err := a.CreateSession(ctx); err != nil { - return err - } - } - - a.mu.RLock() - sessionID := a.CurrentSession.Id - a.mu.RUnlock() - - parts := interface{}([]map[string]interface{}{ - { - "type": "text", - "text": text, - }, - }) - - resp, err := a.Client.PostSessionChat(ctx, client.PostSessionChatJSONRequestBody{ - SessionID: sessionID, - Parts: &parts, - }) - if err != nil { - return err - } - defer resp.Body.Close() - - // The response will be streamed via SSE - return nil -} - -// GetSessions retrieves all sessions -func (a *AppNew) GetSessions(ctx context.Context) ([]client.SessionInfo, error) { - resp, err := a.Client.PostSessionList(ctx) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var sessions []client.SessionInfo - if err := json.NewDecoder(resp.Body).Decode(&sessions); err != nil { - return nil, err - } - - return sessions, nil -} - -// GetMessages retrieves messages for a session -func (a *AppNew) GetMessages(ctx context.Context, sessionID string) (interface{}, error) { - resp, err := a.Client.PostSessionMessages(ctx, client.PostSessionMessagesJSONRequestBody{ - SessionID: sessionID, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var messages interface{} - if err := json.NewDecoder(resp.Body).Decode(&messages); err != nil { - return nil, err - } - - return messages, nil -} - -// Close shuts down the app and its connections -func (a *AppNew) Close() { - if a.eventCancel != nil { - a.eventCancel() - } -} - -// UI state methods -func (a *AppNew) SetFilepickerOpen(open bool) { - a.mu.Lock() - defer a.mu.Unlock() - a.filepickerOpen = open -} - -func (a *AppNew) IsFilepickerOpen() bool { - a.mu.RLock() - defer a.mu.RUnlock() - return a.filepickerOpen -} - -func (a *AppNew) SetCompletionDialogOpen(open bool) { - a.mu.Lock() - defer a.mu.Unlock() - a.completionDialogOpen = open -} - -func (a *AppNew) IsCompletionDialogOpen() bool { - a.mu.RLock() - defer a.mu.RUnlock() - return a.completionDialogOpen -}
\ No newline at end of file diff --git a/internal/app/interfaces.go b/internal/app/interfaces.go deleted file mode 100644 index 2f4287078..000000000 --- a/internal/app/interfaces.go +++ /dev/null @@ -1,42 +0,0 @@ -package app - -import ( - "context" - "time" - - "github.com/sst/opencode/internal/message" - "github.com/sst/opencode/internal/pubsub" - "github.com/sst/opencode/internal/session" -) - -// SessionService defines the interface for session operations -type SessionService interface { - Create(ctx context.Context, title string) (session.Session, error) - Get(ctx context.Context, id string) (session.Session, error) - List(ctx context.Context) ([]session.Session, error) - Update(ctx context.Context, id, title string) error - Delete(ctx context.Context, id string) error -} - -// MessageService defines the interface for message operations -type MessageService interface { - pubsub.Subscriber[message.Message] - - GetBySession(ctx context.Context, sessionID string) ([]message.Message, error) - List(ctx context.Context, sessionID string) ([]message.Message, error) - Create(ctx context.Context, sessionID string, params message.CreateMessageParams) (message.Message, error) - Update(ctx context.Context, msg message.Message) (message.Message, error) - Delete(ctx context.Context, id string) error - DeleteSessionMessages(ctx context.Context, sessionID string) error - Get(ctx context.Context, id string) (message.Message, error) - ListAfter(ctx context.Context, sessionID string, timestamp time.Time) ([]message.Message, error) -} - -// AgentService defines the interface for agent operations -type AgentService interface { - Run(ctx context.Context, sessionID string, text string, attachments ...message.Attachment) (string, error) - Cancel(sessionID string) error - IsBusy() bool - IsSessionBusy(sessionID string) bool - CompactSession(ctx context.Context, sessionID string, force bool) error -}
\ No newline at end of file diff --git a/internal/app/lsp.go b/internal/app/lsp.go deleted file mode 100644 index 214f104b8..000000000 --- a/internal/app/lsp.go +++ /dev/null @@ -1,134 +0,0 @@ -package app - -import ( - "context" - "time" - - "log/slog" - - "github.com/sst/opencode/internal/config" - "github.com/sst/opencode/internal/logging" - "github.com/sst/opencode/internal/lsp" - "github.com/sst/opencode/internal/lsp/watcher" -) - -func (app *App) initLSPClients(ctx context.Context) { - cfg := config.Get() - - // Initialize LSP clients - for name, clientConfig := range cfg.LSP { - // Start each client initialization in its own goroutine - go app.createAndStartLSPClient(ctx, name, clientConfig.Command, clientConfig.Args...) - } - slog.Info("LSP clients initialization started in background") -} - -// createAndStartLSPClient creates a new LSP client, initializes it, and starts its workspace watcher -func (app *App) createAndStartLSPClient(ctx context.Context, name string, command string, args ...string) { - // Create a specific context for initialization with a timeout - slog.Info("Creating LSP client", "name", name, "command", command, "args", args) - - // Create the LSP client - lspClient, err := lsp.NewClient(ctx, command, args...) - if err != nil { - slog.Error("Failed to create LSP client for", name, err) - return - } - - // Create a longer timeout for initialization (some servers take time to start) - initCtx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - - // Initialize with the initialization context - _, err = lspClient.InitializeLSPClient(initCtx, config.WorkingDirectory()) - if err != nil { - slog.Error("Initialize failed", "name", name, "error", err) - // Clean up the client to prevent resource leaks - lspClient.Close() - return - } - - // Wait for the server to be ready - if err := lspClient.WaitForServerReady(initCtx); err != nil { - slog.Error("Server failed to become ready", "name", name, "error", err) - // We'll continue anyway, as some functionality might still work - lspClient.SetServerState(lsp.StateError) - } else { - slog.Info("LSP server is ready", "name", name) - lspClient.SetServerState(lsp.StateReady) - } - - slog.Info("LSP client initialized", "name", name) - - // Create a child context that can be canceled when the app is shutting down - watchCtx, cancelFunc := context.WithCancel(ctx) - - // Create a context with the server name for better identification - watchCtx = context.WithValue(watchCtx, "serverName", name) - - // Create the workspace watcher - workspaceWatcher := watcher.NewWorkspaceWatcher(lspClient) - - // Store the cancel function to be called during cleanup - app.cancelFuncsMutex.Lock() - app.watcherCancelFuncs = append(app.watcherCancelFuncs, cancelFunc) - app.cancelFuncsMutex.Unlock() - - // Add the watcher to a WaitGroup to track active goroutines - app.watcherWG.Add(1) - - // Add to map with mutex protection before starting goroutine - app.clientsMutex.Lock() - app.LSPClients[name] = lspClient - app.clientsMutex.Unlock() - - go app.runWorkspaceWatcher(watchCtx, name, workspaceWatcher) -} - -// runWorkspaceWatcher executes the workspace watcher for an LSP client -func (app *App) runWorkspaceWatcher(ctx context.Context, name string, workspaceWatcher *watcher.WorkspaceWatcher) { - defer app.watcherWG.Done() - defer logging.RecoverPanic("LSP-"+name, func() { - // Try to restart the client - app.restartLSPClient(ctx, name) - }) - - workspaceWatcher.WatchWorkspace(ctx, config.WorkingDirectory()) - slog.Info("Workspace watcher stopped", "client", name) -} - -// restartLSPClient attempts to restart a crashed or failed LSP client -func (app *App) restartLSPClient(ctx context.Context, name string) { - // Get the original configuration - cfg := config.Get() - clientConfig, exists := cfg.LSP[name] - if !exists { - slog.Error("Cannot restart client, configuration not found", "client", name) - return - } - - // Clean up the old client if it exists - app.clientsMutex.Lock() - oldClient, exists := app.LSPClients[name] - if exists { - delete(app.LSPClients, name) // Remove from map before potentially slow shutdown - } - app.clientsMutex.Unlock() - - if exists && oldClient != nil { - // Try to shut it down gracefully, but don't block on errors - shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - _ = oldClient.Shutdown(shutdownCtx) - cancel() - - // Ensure we close the client to free resources - _ = oldClient.Close() - } - - // Wait a moment before restarting to avoid rapid restart cycles - time.Sleep(1 * time.Second) - - // Create a new client using the shared function - app.createAndStartLSPClient(ctx, name, clientConfig.Command, clientConfig.Args...) - slog.Info("Successfully restarted LSP client", "client", name) -} diff --git a/internal/app/services_bridge.go b/internal/app/services_bridge.go deleted file mode 100644 index d3f2e9a23..000000000 --- a/internal/app/services_bridge.go +++ /dev/null @@ -1,245 +0,0 @@ -package app - -import ( - "context" - "encoding/json" - "fmt" - "time" - - "github.com/sst/opencode/internal/message" - "github.com/sst/opencode/internal/pubsub" - "github.com/sst/opencode/internal/session" - "github.com/sst/opencode/pkg/client" -) - -// SessionServiceBridge adapts the HTTP API to the old session.Service interface -type SessionServiceBridge struct { - client *client.ClientWithResponses -} - -// NewSessionServiceBridge creates a new session service bridge -func NewSessionServiceBridge(client *client.ClientWithResponses) *SessionServiceBridge { - return &SessionServiceBridge{client: client} -} - -// Create creates a new session -func (s *SessionServiceBridge) Create(ctx context.Context, title string) (session.Session, error) { - resp, err := s.client.PostSessionCreateWithResponse(ctx) - if err != nil { - return session.Session{}, err - } - if resp.StatusCode() != 200 { - return session.Session{}, fmt.Errorf("failed to create session: %d", resp.StatusCode) - } - info := resp.JSON200 - - // Convert to old session type - return session.Session{ - ID: info.Id, - Title: info.Title, - CreatedAt: time.Now(), // API doesn't provide this yet - UpdatedAt: time.Now(), // API doesn't provide this yet - }, nil -} - -// Get retrieves a session by ID -func (s *SessionServiceBridge) Get(ctx context.Context, id string) (session.Session, error) { - // TODO: API doesn't have a get by ID endpoint yet - // For now, list all and find the one we want - sessions, err := s.List(ctx) - if err != nil { - return session.Session{}, err - } - - for _, sess := range sessions { - if sess.ID == id { - return sess, nil - } - } - - return session.Session{}, fmt.Errorf("session not found: %s", id) -} - -// List retrieves all sessions -func (s *SessionServiceBridge) List(ctx context.Context) ([]session.Session, error) { - resp, err := s.client.PostSessionListWithResponse(ctx) - if err != nil { - return nil, err - } - - if resp.StatusCode() != 200 { - return nil, fmt.Errorf("failed to list sessions: %d", resp.StatusCode()) - } - - if resp.JSON200 == nil { - return []session.Session{}, nil - } - - infos := *resp.JSON200 - - // Convert to old session type - sessions := make([]session.Session, len(infos)) - for i, info := range infos { - sessions[i] = session.Session{ - ID: info.Id, - Title: info.Title, - CreatedAt: time.Now(), // API doesn't provide this yet - UpdatedAt: time.Now(), // API doesn't provide this yet - } - } - - return sessions, nil -} - -// Update updates a session - NOT IMPLEMENTED IN API YET -func (s *SessionServiceBridge) Update(ctx context.Context, id, title string) error { - // TODO: Not implemented in TypeScript API yet - return fmt.Errorf("session update not implemented in API") -} - -// Delete deletes a session - NOT IMPLEMENTED IN API YET -func (s *SessionServiceBridge) Delete(ctx context.Context, id string) error { - // TODO: Not implemented in TypeScript API yet - return fmt.Errorf("session delete not implemented in API") -} - -// AgentServiceBridge provides a minimal agent service that sends messages to the API -type AgentServiceBridge struct { - client *client.ClientWithResponses -} - -// NewAgentServiceBridge creates a new agent service bridge -func NewAgentServiceBridge(client *client.ClientWithResponses) *AgentServiceBridge { - return &AgentServiceBridge{client: client} -} - -// Run sends a message to the chat API -func (a *AgentServiceBridge) Run(ctx context.Context, sessionID string, text string, attachments ...message.Attachment) (string, error) { - // TODO: Handle attachments when API supports them - if len(attachments) > 0 { - // For now, ignore attachments - // return "", fmt.Errorf("attachments not supported yet") - } - - parts := any([]map[string]any{ - { - "type": "text", - "text": text, - }, - }) - - go a.client.PostSessionChatWithResponse(ctx, client.PostSessionChatJSONRequestBody{ - SessionID: sessionID, - Parts: &parts, - }) - - // The actual response will come through SSE - // For now, just return success - return "", nil -} - -// Cancel cancels the current generation - NOT IMPLEMENTED IN API YET -func (a *AgentServiceBridge) Cancel(sessionID string) error { - // TODO: Not implemented in TypeScript API yet - return nil -} - -// IsBusy checks if the agent is busy - NOT IMPLEMENTED IN API YET -func (a *AgentServiceBridge) IsBusy() bool { - // TODO: Not implemented in TypeScript API yet - return false -} - -// IsSessionBusy checks if the agent is busy for a specific session - NOT IMPLEMENTED IN API YET -func (a *AgentServiceBridge) IsSessionBusy(sessionID string) bool { - // TODO: Not implemented in TypeScript API yet - return false -} - -// CompactSession compacts a session - NOT IMPLEMENTED IN API YET -func (a *AgentServiceBridge) CompactSession(ctx context.Context, sessionID string, force bool) error { - // TODO: Not implemented in TypeScript API yet - return fmt.Errorf("session compaction not implemented in API") -} - -// MessageServiceBridge provides a minimal message service that fetches from the API -type MessageServiceBridge struct { - client *client.ClientWithResponses - broker *pubsub.Broker[message.Message] -} - -// NewMessageServiceBridge creates a new message service bridge -func NewMessageServiceBridge(client *client.ClientWithResponses) *MessageServiceBridge { - return &MessageServiceBridge{ - client: client, - broker: pubsub.NewBroker[message.Message](), - } -} - -// GetBySession retrieves messages for a session -func (m *MessageServiceBridge) GetBySession(ctx context.Context, sessionID string) ([]message.Message, error) { - return m.List(ctx, sessionID) -} - -// List retrieves messages for a session -func (m *MessageServiceBridge) List(ctx context.Context, sessionID string) ([]message.Message, error) { - resp, err := m.client.PostSessionMessages(ctx, client.PostSessionMessagesJSONRequestBody{ - SessionID: sessionID, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - // The API returns a different format, we'll need to adapt it - var rawMessages any - if err := json.NewDecoder(resp.Body).Decode(&rawMessages); err != nil { - return nil, err - } - - // TODO: Convert the API message format to our internal format - // For now, return empty to avoid compilation errors - return []message.Message{}, nil -} - -// Create creates a new message - NOT NEEDED, handled by chat API -func (m *MessageServiceBridge) Create(ctx context.Context, sessionID string, params message.CreateMessageParams) (message.Message, error) { - // Messages are created through the chat API - return message.Message{}, fmt.Errorf("use chat API to send messages") -} - -// Update updates a message - NOT IMPLEMENTED IN API YET -func (m *MessageServiceBridge) Update(ctx context.Context, msg message.Message) (message.Message, error) { - // TODO: Not implemented in TypeScript API yet - return message.Message{}, fmt.Errorf("message update not implemented in API") -} - -// Delete deletes a message - NOT IMPLEMENTED IN API YET -func (m *MessageServiceBridge) Delete(ctx context.Context, id string) error { - // TODO: Not implemented in TypeScript API yet - return fmt.Errorf("message delete not implemented in API") -} - -// DeleteSessionMessages deletes all messages for a session - NOT IMPLEMENTED IN API YET -func (m *MessageServiceBridge) DeleteSessionMessages(ctx context.Context, sessionID string) error { - // TODO: Not implemented in TypeScript API yet - return fmt.Errorf("delete session messages not implemented in API") -} - -// Get retrieves a message by ID - NOT IMPLEMENTED IN API YET -func (m *MessageServiceBridge) Get(ctx context.Context, id string) (message.Message, error) { - // TODO: Not implemented in TypeScript API yet - return message.Message{}, fmt.Errorf("get message by ID not implemented in API") -} - -// ListAfter retrieves messages after a timestamp - NOT IMPLEMENTED IN API YET -func (m *MessageServiceBridge) ListAfter(ctx context.Context, sessionID string, timestamp time.Time) ([]message.Message, error) { - // TODO: Not implemented in TypeScript API yet - return []message.Message{}, fmt.Errorf("list messages after timestamp not implemented in API") -} - -// Subscribe subscribes to message events -func (m *MessageServiceBridge) Subscribe(ctx context.Context) <-chan pubsub.Event[message.Message] { - return m.broker.Subscribe(ctx) -} - |
