mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 06:04:51 +00:00
Fix SessionListDialog behavior and document PersistentStorageDialog bug
- Fix SessionListDialog to not reload when user selects a session after deleting others - Track if dialog closed via selection vs other means - Only call delete callback if not closed via selection - Batch deletions to avoid reload on every delete - Comment out PersistentStorageDialog in both web-ui example and browser extension (TODO: fix) - Add Known Bugs section to both README.md files documenting PersistentStorageDialog issue - Clean up navigation tracking variable names in browser extension
This commit is contained in:
parent
2d68594711
commit
5f04960f6d
5 changed files with 94 additions and 25 deletions
|
|
@ -1182,3 +1182,7 @@ Error: Refused to evaluate a string as JavaScript because this document requires
|
||||||
---
|
---
|
||||||
|
|
||||||
This CSP section should help both developers and LLMs understand the security constraints when working on extension features, especially those involving dynamic code execution or user-generated content.
|
This CSP section should help both developers and LLMs understand the security constraints when working on extension features, especially those involving dynamic code execution or user-generated content.
|
||||||
|
|
||||||
|
## Known Bugs
|
||||||
|
|
||||||
|
- **PersistentStorageDialog**: Currently broken and commented out in sidepanel.ts. The dialog for requesting persistent storage does not work correctly and needs to be fixed.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
AppStorage,
|
AppStorage,
|
||||||
ChatPanel,
|
ChatPanel,
|
||||||
ChromeStorageBackend,
|
ChromeStorageBackend,
|
||||||
PersistentStorageDialog,
|
// PersistentStorageDialog, // TODO: Fix - currently broken
|
||||||
ProviderTransport,
|
ProviderTransport,
|
||||||
ProxyTab,
|
ProxyTab,
|
||||||
SessionIndexedDBBackend,
|
SessionIndexedDBBackend,
|
||||||
|
|
@ -71,9 +71,9 @@ let agent: Agent;
|
||||||
let chatPanel: ChatPanel;
|
let chatPanel: ChatPanel;
|
||||||
let agentUnsubscribe: (() => void) | undefined;
|
let agentUnsubscribe: (() => void) | undefined;
|
||||||
|
|
||||||
// Track last navigation for inserting navigation messages
|
// Track current active tab for real-time navigation updates
|
||||||
let lastSubmittedUrl: string | undefined;
|
let currentTabUrl: string | undefined;
|
||||||
let lastSubmittedTabIndex: number | undefined;
|
let currentTabIndex: number | undefined;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// HELPERS
|
// HELPERS
|
||||||
|
|
@ -204,7 +204,7 @@ const renderApp = () => {
|
||||||
loadSession(sessionId);
|
loadSession(sessionId);
|
||||||
},
|
},
|
||||||
(deletedSessionId) => {
|
(deletedSessionId) => {
|
||||||
// If the deleted session is the current one, start a new session
|
// Only reload if the current session was deleted
|
||||||
if (deletedSessionId === currentSessionId) {
|
if (deletedSessionId === currentSessionId) {
|
||||||
newSession();
|
newSession();
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +294,41 @@ const renderApp = () => {
|
||||||
render(appHtml, document.body);
|
render(appHtml, document.body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TAB NAVIGATION TRACKING
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// Listen for tab updates to insert navigation messages in real-time
|
||||||
|
chrome.tabs.onUpdated.addListener((_tabId, changeInfo, tab) => {
|
||||||
|
// Only care about URL changes on the active tab
|
||||||
|
if (changeInfo.url && tab.active && tab.url) {
|
||||||
|
handleTabNavigation(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen for tab activation (user switches tabs)
|
||||||
|
chrome.tabs.onActivated.addListener(async (activeInfo) => {
|
||||||
|
const tab = await chrome.tabs.get(activeInfo.tabId);
|
||||||
|
if (tab.url) {
|
||||||
|
handleTabNavigation(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleTabNavigation(url: string, title: string, favicon?: string, tabIndex?: number) {
|
||||||
|
// Update current tab tracking
|
||||||
|
const urlChanged = currentTabUrl !== url;
|
||||||
|
const tabChanged = currentTabIndex !== tabIndex;
|
||||||
|
|
||||||
|
currentTabUrl = url;
|
||||||
|
currentTabIndex = tabIndex;
|
||||||
|
|
||||||
|
// Only insert navigation message if something changed and we have an agent
|
||||||
|
if ((urlChanged || tabChanged) && agent) {
|
||||||
|
const navMessage = createNavigationMessage(url, title, favicon, tabIndex);
|
||||||
|
agent.appendMessage(navMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// INIT
|
// INIT
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -308,10 +343,11 @@ async function initApp() {
|
||||||
document.body,
|
document.body,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Fix PersistentStorageDialog - currently broken
|
||||||
// Request persistent storage
|
// Request persistent storage
|
||||||
if (storage.sessions) {
|
// if (storage.sessions) {
|
||||||
await PersistentStorageDialog.request();
|
// await PersistentStorageDialog.request();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Create ChatPanel
|
// Create ChatPanel
|
||||||
chatPanel = new ChatPanel();
|
chatPanel = new ChatPanel();
|
||||||
|
|
@ -322,21 +358,33 @@ async function initApp() {
|
||||||
chatPanel.onBeforeSend = async () => {
|
chatPanel.onBeforeSend = async () => {
|
||||||
// Get current tab info
|
// Get current tab info
|
||||||
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||||
if (!tab || !tab.url) return;
|
if (!tab?.url) return;
|
||||||
|
|
||||||
// Check if navigation changed since last submit
|
// Find last navigation message in messages (reverse loop)
|
||||||
if (lastSubmittedUrl !== tab.url || lastSubmittedTabIndex !== tab.index) {
|
const messages = agent.state.messages;
|
||||||
// Insert navigation message
|
let lastNavMessage: ReturnType<typeof createNavigationMessage> | undefined;
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
if (messages[i].role === "navigation") {
|
||||||
|
lastNavMessage = messages[i] as ReturnType<typeof createNavigationMessage>;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only insert if URL or tab changed
|
||||||
|
if (lastNavMessage?.url !== tab.url || lastNavMessage?.tabIndex !== tab.index) {
|
||||||
const navMessage = createNavigationMessage(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
const navMessage = createNavigationMessage(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
||||||
agent.appendMessage(navMessage);
|
agent.appendMessage(navMessage);
|
||||||
|
|
||||||
// Update tracking
|
|
||||||
lastSubmittedUrl = tab.url;
|
|
||||||
lastSubmittedTabIndex = tab.index;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
chatPanel.additionalTools = [browserJavaScriptTool];
|
chatPanel.additionalTools = [browserJavaScriptTool];
|
||||||
|
|
||||||
|
// Initialize current tab state
|
||||||
|
const [currentTab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||||
|
if (currentTab?.url) {
|
||||||
|
currentTabUrl = currentTab.url;
|
||||||
|
currentTabIndex = currentTab.index;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for session in URL
|
// Check for session in URL
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
let sessionIdFromUrl = urlParams.get("session");
|
let sessionIdFromUrl = urlParams.get("session");
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,10 @@ setAppStorage(storage);
|
||||||
|
|
||||||
See [src/index.ts](src/index.ts) for the full public API.
|
See [src/index.ts](src/index.ts) for the full public API.
|
||||||
|
|
||||||
|
## Known Bugs
|
||||||
|
|
||||||
|
- **PersistentStorageDialog**: Currently broken and commented out in examples. The dialog for requesting persistent storage does not work correctly and needs to be fixed.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
type AppMessage,
|
type AppMessage,
|
||||||
AppStorage,
|
AppStorage,
|
||||||
ChatPanel,
|
ChatPanel,
|
||||||
PersistentStorageDialog,
|
// PersistentStorageDialog, // TODO: Fix - currently broken
|
||||||
ProviderTransport,
|
ProviderTransport,
|
||||||
ProxyTab,
|
ProxyTab,
|
||||||
SessionIndexedDBBackend,
|
SessionIndexedDBBackend,
|
||||||
|
|
@ -192,7 +192,7 @@ const renderApp = () => {
|
||||||
await loadSession(sessionId);
|
await loadSession(sessionId);
|
||||||
},
|
},
|
||||||
(deletedSessionId) => {
|
(deletedSessionId) => {
|
||||||
// If the deleted session is the current one, start a new session
|
// Only reload if the current session was deleted
|
||||||
if (deletedSessionId === currentSessionId) {
|
if (deletedSessionId === currentSessionId) {
|
||||||
newSession();
|
newSession();
|
||||||
}
|
}
|
||||||
|
|
@ -311,10 +311,11 @@ async function initApp() {
|
||||||
app,
|
app,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Fix PersistentStorageDialog - currently broken
|
||||||
// Request persistent storage
|
// Request persistent storage
|
||||||
if (storage.sessions) {
|
// if (storage.sessions) {
|
||||||
await PersistentStorageDialog.request();
|
// await PersistentStorageDialog.request();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Create ChatPanel
|
// Create ChatPanel
|
||||||
chatPanel = new ChatPanel();
|
chatPanel = new ChatPanel();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ export class SessionListDialog extends DialogBase {
|
||||||
|
|
||||||
private onSelectCallback?: (sessionId: string) => void;
|
private onSelectCallback?: (sessionId: string) => void;
|
||||||
private onDeleteCallback?: (sessionId: string) => void;
|
private onDeleteCallback?: (sessionId: string) => void;
|
||||||
|
private deletedSessions = new Set<string>();
|
||||||
|
private closedViaSelection = false;
|
||||||
|
|
||||||
protected modalWidth = "min(600px, 90vw)";
|
protected modalWidth = "min(600px, 90vw)";
|
||||||
protected modalHeight = "min(700px, 90vh)";
|
protected modalHeight = "min(700px, 90vh)";
|
||||||
|
|
@ -57,16 +59,26 @@ export class SessionListDialog extends DialogBase {
|
||||||
await storage.sessions.deleteSession(sessionId);
|
await storage.sessions.deleteSession(sessionId);
|
||||||
await this.loadSessions();
|
await this.loadSessions();
|
||||||
|
|
||||||
// Notify callback that session was deleted
|
// Track deleted session
|
||||||
if (this.onDeleteCallback) {
|
this.deletedSessions.add(sessionId);
|
||||||
this.onDeleteCallback(sessionId);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to delete session:", err);
|
console.error("Failed to delete session:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override close() {
|
||||||
|
super.close();
|
||||||
|
|
||||||
|
// Only notify about deleted sessions if dialog wasn't closed via selection
|
||||||
|
if (!this.closedViaSelection && this.onDeleteCallback && this.deletedSessions.size > 0) {
|
||||||
|
for (const sessionId of this.deletedSessions) {
|
||||||
|
this.onDeleteCallback(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private handleSelect(sessionId: string) {
|
private handleSelect(sessionId: string) {
|
||||||
|
this.closedViaSelection = true;
|
||||||
if (this.onSelectCallback) {
|
if (this.onSelectCallback) {
|
||||||
this.onSelectCallback(sessionId);
|
this.onSelectCallback(sessionId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue