improve prompt caching by computing a deterministic hash (+ other bug fixes) (#2509)

This commit is contained in:
Mike Sawka 2025-11-03 14:56:19 -08:00 committed by GitHub
parent 8768269e2f
commit 956bf9587c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 48 additions and 8 deletions

View file

@ -193,6 +193,9 @@ ipcMain.on("get-data-dir", (event) => {
ipcMain.on("get-config-dir", (event) => {
event.returnValue = getWaveConfigDir();
});
ipcMain.on("get-home-dir", (event) => {
event.returnValue = app.getPath("home");
});
/**
* Gets the value of the XDG_CURRENT_DESKTOP environment variable. If ORIGINAL_XDG_CURRENT_DESKTOP is set, it will be returned instead.

View file

@ -12,6 +12,7 @@ contextBridge.exposeInMainWorld("api", {
getHostName: () => ipcRenderer.sendSync("get-host-name"),
getDataDir: () => ipcRenderer.sendSync("get-data-dir"),
getConfigDir: () => ipcRenderer.sendSync("get-config-dir"),
getHomeDir: () => ipcRenderer.sendSync("get-home-dir"),
getAboutModalDetails: () => ipcRenderer.sendSync("get-about-modal-details"),
getDocsiteUrl: () => ipcRenderer.sendSync("get-docsite-url"),
getWebviewPreload: () => ipcRenderer.sendSync("get-webview-preload"),

View file

@ -10,11 +10,34 @@ type EndpointInfo = {
schema: object;
};
function prependWildcard(path: string): string {
return path.startsWith("/") ? `*${path}` : `*/${path}`;
}
function convertToTildePath(absolutePath: string): string {
const homeDir = getApi().getHomeDir();
if (absolutePath.startsWith(homeDir)) {
return "~" + absolutePath.slice(homeDir.length);
}
return absolutePath;
}
function makeConfigPathMatches(suffix: string): Array<string> {
const configPath = `${getApi().getConfigDir()}${suffix}`;
const tildePath = convertToTildePath(configPath);
const paths = [configPath, prependWildcard(configPath)];
if (tildePath !== configPath) {
paths.push(tildePath);
paths.push(prependWildcard(tildePath));
}
return paths;
}
const allFilepaths: Map<string, Array<string>> = new Map();
allFilepaths.set(`${getWebServerEndpoint()}/schema/settings.json`, [`${getApi().getConfigDir()}/settings.json`]);
allFilepaths.set(`${getWebServerEndpoint()}/schema/connections.json`, [`${getApi().getConfigDir()}/connections.json`]);
allFilepaths.set(`${getWebServerEndpoint()}/schema/aipresets.json`, [`${getApi().getConfigDir()}/presets/ai.json`]);
allFilepaths.set(`${getWebServerEndpoint()}/schema/widgets.json`, [`${getApi().getConfigDir()}/widgets.json`]);
allFilepaths.set(`${getWebServerEndpoint()}/schema/settings.json`, makeConfigPathMatches("/settings.json"));
allFilepaths.set(`${getWebServerEndpoint()}/schema/connections.json`, makeConfigPathMatches("/connections.json"));
allFilepaths.set(`${getWebServerEndpoint()}/schema/aipresets.json`, makeConfigPathMatches("/presets/ai.json"));
allFilepaths.set(`${getWebServerEndpoint()}/schema/widgets.json`, makeConfigPathMatches("/widgets.json"));
async function getSchemaEndpointInfo(endpoint: string): Promise<EndpointInfo> {
let schema: Object;

View file

@ -83,6 +83,7 @@ declare global {
getHostName: () => string; // get-host-name
getDataDir: () => string; // get-data-dir
getConfigDir: () => string; // get-config-dir
getHomeDir: () => string; // get-home-dir
getWebviewPreload: () => string; // get-webview-preload
getAboutModalDetails: () => AboutModalDetails; // get-about-modal-details
getDocsiteUrl: () => string; // get-docsite-url

View file

@ -6,7 +6,9 @@ package openai
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@ -58,6 +60,16 @@ func extractXmlAttribute(tag, attrName string) (string, bool) {
return value, true
}
// generateDeterministicSuffix creates an 8-character hash from input strings
func generateDeterministicSuffix(inputs ...string) string {
hasher := sha256.New()
for _, input := range inputs {
hasher.Write([]byte(input))
}
hash := hasher.Sum(nil)
return hex.EncodeToString(hash)[:8]
}
// ---------- OpenAI Request Types ----------
type StreamOptionsType struct {
@ -388,8 +400,8 @@ func convertFileAIMessagePart(part uctypes.AIMessagePart) (*OpenAIMessageContent
encodedFileName := strings.ReplaceAll(fileName, `"`, "&quot;")
quotedFileName := strconv.Quote(encodedFileName)
randomSuffix := uuid.New().String()[0:8]
formattedText := fmt.Sprintf("<AttachedTextFile_%s file_name=%s>\n%s\n</AttachedTextFile_%s>", randomSuffix, quotedFileName, textContent, randomSuffix)
deterministicSuffix := generateDeterministicSuffix(textContent, fileName)
formattedText := fmt.Sprintf("<AttachedTextFile_%s file_name=%s>\n%s\n</AttachedTextFile_%s>", deterministicSuffix, quotedFileName, textContent, deterministicSuffix)
return &OpenAIMessageContent{
Type: "input_text",
@ -412,8 +424,8 @@ func convertFileAIMessagePart(part uctypes.AIMessagePart) (*OpenAIMessageContent
encodedDirName := strings.ReplaceAll(directoryName, `"`, "&quot;")
quotedDirName := strconv.Quote(encodedDirName)
randomSuffix := uuid.New().String()[0:8]
formattedText := fmt.Sprintf("<AttachedDirectoryListing_%s directory_name=%s>\n%s\n</AttachedDirectoryListing_%s>", randomSuffix, quotedDirName, jsonContent, randomSuffix)
deterministicSuffix := generateDeterministicSuffix(jsonContent, directoryName)
formattedText := fmt.Sprintf("<AttachedDirectoryListing_%s directory_name=%s>\n%s\n</AttachedDirectoryListing_%s>", deterministicSuffix, quotedDirName, jsonContent, deterministicSuffix)
return &OpenAIMessageContent{
Type: "input_text",