Skip to content

Commit

Permalink
in-progress chat history storing/loading
Browse files Browse the repository at this point in the history
  • Loading branch information
robgruen committed Feb 4, 2025
1 parent ae4fa7e commit cf3eea3
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 5 deletions.
43 changes: 38 additions & 5 deletions ts/packages/shell/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
} from "default-agent-provider";
import { ShellSettings } from "./shellSettings.js";
import { unlinkSync } from "fs";
import { existsSync } from "node:fs";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { shellAgentProvider } from "./agent.js";
import { BrowserAgentIpc } from "./browserIpc.js";
import { WebSocketMessageV2 } from "common-utils";
Expand Down Expand Up @@ -59,6 +59,10 @@ process.argv.forEach((arg) => {
}
});

export function runningTests(): boolean {
return process.env["INSTANCE_NAME"] !== undefined && process.env["INSTANCE_NAME"].startsWith("test_") === true;
}

let mainWindow: BrowserWindow | null = null;
let inlineWebContentView: WebContentsView | null = null;
let chatView: WebContentsView | null = null;
Expand Down Expand Up @@ -614,6 +618,15 @@ async function initialize() {
// Send settings asap
ShellSettings.getinstance().onSettingsChanged!();

// Load chat history if enabled
const chatHistory: string = path.join(getInstanceDir(), "chat_history.html")
if (ShellSettings.getinstance().chatHistory && existsSync(chatHistory)) {
chatView?.webContents.send(
"chat-history",
readFileSync(path.join(getInstanceDir(), "chat_history.html"), "utf-8"),
);
}

// make sure links are opened in the external browser
mainWindow.webContents.setWindowOpenHandler((details) => {
require("electron").shell.openExternal(details.url);
Expand All @@ -623,8 +636,31 @@ async function initialize() {
// The dispatcher can be use now that dom is ready and the client is ready to receive messages
const dispatcher = await dispatcherP;
updateSummary(dispatcher);

// send the agent greeting if it's turned on
if (ShellSettings.getinstance().agentGreeting) {
dispatcher.processCommand("@greeting", "agent-0", []);
}
});

// Store the chat history whenever the DOM changes
// this let's us rehydrate the chat when reopening the shell
ipcMain.on("dom changed", async(_event, html) => {
// store the modified DOM contents
const file: string = path.join(getInstanceDir(), "chat_history.html");

debugShell(
`Saving chat history to '${file}'.`,
performance.now(),
);

try {
writeFileSync(file, html);
} catch (e) {
debugShell(
`Unable to save history to '${file}'. Error: ${e}`,
performance.now(),
);
}
});

Expand Down Expand Up @@ -674,10 +710,7 @@ async function initialize() {
// for pen events which will trigger speech reco
// Don't spin this up during testing
if (
process.platform == "win32" &&
(process.env["INSTANCE_NAME"] == undefined ||
process.env["INSTANCE_NAME"].startsWith("test_") == false)
) {
process.platform == "win32" && !runningTests()) {
const pipePath = path.join("\\\\.\\pipe\\TypeAgent", "speech");
const server = net.createServer((stream) => {
stream.on("data", (c) => {
Expand Down
2 changes: 2 additions & 0 deletions ts/packages/shell/src/main/shellSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class ShellSettings
public onOpenInlineBrowser: ((targetUrl: URL) => void) | null;
public onCloseInlineBrowser: EmptyFunction | null;
public darkMode: boolean;
public chatHistory: boolean;

public get width(): number {
return this.size[0] ?? defaultSettings.size[0];
Expand Down Expand Up @@ -91,6 +92,7 @@ export class ShellSettings
this.onOpenInlineBrowser = null;
this.onCloseInlineBrowser = null;
this.darkMode = settings.darkMode;
this.chatHistory = settings.chatHistory;
}

public static get filePath(): string {
Expand Down
2 changes: 2 additions & 0 deletions ts/packages/shell/src/main/shellSettingsType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type ShellSettingsType = {
partialCompletion: boolean;
disallowedDisplayType: DisplayType[];
darkMode: boolean;
chatHistory: boolean;
};

export const defaultSettings: ShellSettingsType = {
Expand All @@ -38,4 +39,5 @@ export const defaultSettings: ShellSettingsType = {
partialCompletion: true,
disallowedDisplayType: [],
darkMode: false,
chatHistory: true
};
1 change: 1 addition & 0 deletions ts/packages/shell/src/preload/electronTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface ClientAPI {
settings: ShellSettings,
) => void,
): void;
onChatHistory(callback: (e: Electron.IpcRendererEvent, chatHistory: string) => void): void;
registerClientIO(clientIO: ClientIO);
}

Expand Down
3 changes: 3 additions & 0 deletions ts/packages/shell/src/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const api: ClientAPI = {
onSettingsChanged(callback) {
ipcRenderer.on("settings-changed", callback);
},
onChatHistory(callback) {
ipcRenderer.on("chat-history", callback);
},
registerClientIO: (clientIO: ClientIO) => {
if (clientIORegistered) {
throw new Error("ClientIO already registered");
Expand Down
3 changes: 3 additions & 0 deletions ts/packages/shell/src/renderer/src/chatView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ export class ChatView {
getMessageElm() {
return this.topDiv;
}
getScollContainer() {
return this.messageDiv;
}

async showInputText(message: string) {
const input = this.inputContainer.querySelector(
Expand Down
37 changes: 37 additions & 0 deletions ts/packages/shell/src/renderer/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ function addEvents(

settingsView.shellSettings = value;
});
api.onChatHistory((_, history: string) => {
// TODO: rehydrate these into the UI
console.log(history);
});
}

function showNotifications(
Expand Down Expand Up @@ -425,7 +429,40 @@ document.addEventListener("DOMContentLoaded", async function () {
}
}

watchForDOMChanges(chatView.getScollContainer());

if ((window as any).electron) {
(window as any).electron.ipcRenderer.send("dom ready");
}
});

function watchForDOMChanges(element: HTMLDivElement) {

// ignore attribute changes but wach for
const config = { attributes: false, childList: true, subtree: true };

// timeout
let idleCounter: number = 0;

// observer callback
const observer = new MutationObserver(() => {

// increment the idle counter
idleCounter++;

// decrement the idle counter
setTimeout(() => {
if (--idleCounter == 0) {
// last one notifies main process
if ((window as any).electron) {
(window as any).electron.ipcRenderer.send("dom changed", element.innerHTML);
}
}
}, 3000);
});

// start observing
observer.observe(element!, config);

// observer.disconnect();
}
4 changes: 4 additions & 0 deletions ts/packages/shell/src/renderer/src/webSocketAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export const webapi: ClientAPI = {
// TODO: figure out solution for mobile
fnMap.set("settings-changed", callback);
},
onChatHistory(callback) {
// TODO: implement proper message rehydration on mobile
fnMap.set("chat-history", callback);
},
registerClientIO(clientIO: ClientIO) {
if (clientIORegistered) {
throw new Error("ClientIO already registered");
Expand Down

0 comments on commit cf3eea3

Please sign in to comment.