202 lines
5.5 KiB
TypeScript
202 lines
5.5 KiB
TypeScript
import { isBrowser } from "./env";
|
|
|
|
export type AgentConfig = {
|
|
server: {
|
|
endpoint: string;
|
|
requestHeaders: Record<string, string | number | boolean | null | undefined>;
|
|
requestTimeout: number;
|
|
};
|
|
completion: {
|
|
prompt: {
|
|
maxPrefixLines: number;
|
|
maxSuffixLines: number;
|
|
};
|
|
debounce: {
|
|
mode: "adaptive" | "fixed";
|
|
interval: number;
|
|
};
|
|
timeout: {
|
|
auto: number;
|
|
manually: number;
|
|
};
|
|
};
|
|
logs: {
|
|
level: "debug" | "error" | "silent";
|
|
};
|
|
anonymousUsageTracking: {
|
|
disable: boolean;
|
|
};
|
|
};
|
|
|
|
type RecursivePartial<T> = {
|
|
[P in keyof T]?: T[P] extends (infer U)[]
|
|
? RecursivePartial<U>[]
|
|
: T[P] extends object | undefined
|
|
? RecursivePartial<T[P]>
|
|
: T[P];
|
|
};
|
|
|
|
export type PartialAgentConfig = RecursivePartial<AgentConfig>;
|
|
|
|
export const defaultAgentConfig: AgentConfig = {
|
|
server: {
|
|
endpoint: "http://localhost:8080",
|
|
requestHeaders: {},
|
|
requestTimeout: 30000, // 30s
|
|
},
|
|
completion: {
|
|
prompt: {
|
|
maxPrefixLines: 20,
|
|
maxSuffixLines: 20,
|
|
},
|
|
debounce: {
|
|
mode: "adaptive",
|
|
interval: 250, // ms
|
|
},
|
|
// Deprecated: There is a timeout of 3s on the server side since v0.3.0.
|
|
timeout: {
|
|
auto: 4000, // 4s
|
|
manually: 4000, // 4s
|
|
},
|
|
},
|
|
logs: {
|
|
level: "silent",
|
|
},
|
|
anonymousUsageTracking: {
|
|
disable: false,
|
|
},
|
|
};
|
|
|
|
const oldConfigTomlTemplate = `## Tabby agent configuration file
|
|
|
|
## You can uncomment any block to enable settings.
|
|
## Configurations in this file has lower priority than in IDE settings.
|
|
|
|
## Server
|
|
## You can set the server endpoint and request timeout here.
|
|
# [server]
|
|
# endpoint = "http://localhost:8080" # http or https URL
|
|
# requestTimeout = 30000 # ms
|
|
|
|
## You can add custom request headers, e.g. for authentication.
|
|
# [server.requestHeaders]
|
|
# Authorization = "Bearer eyJhbGciOiJ..........."
|
|
|
|
## Completion
|
|
## You can set the prompt context to send to the server for completion.
|
|
# [completion.prompt]
|
|
# maxPrefixLines = 20
|
|
# maxSuffixLines = 20
|
|
|
|
## You can set the debounce mode for auto completion requests when typing.
|
|
# [completion.debounce]
|
|
# mode = "adaptive" # or "fixed"
|
|
# interval = 250 # ms, only used when mode is "fixed"
|
|
|
|
## You can set the timeout for completion requests.
|
|
# [completion.timeout]
|
|
# auto = 5000 # ms, for auto completion when typing
|
|
# manually = 30000 # ms, for manually triggered completion
|
|
|
|
## Logs
|
|
## You can set the log level here. The log file is located at ~/.tabby-client/agent/logs/.
|
|
# [logs]
|
|
# level = "silent" # or "error" or "debug"
|
|
|
|
## Anonymous usage tracking
|
|
## You can disable anonymous usage tracking here.
|
|
# [anonymousUsageTracking]
|
|
# disable = false # set to true to disable
|
|
|
|
`;
|
|
|
|
const configTomlTemplate = `## Tabby agent configuration file
|
|
|
|
## You can uncomment any block to enable settings.
|
|
## Configurations in this file has lower priority than in IDE settings.
|
|
|
|
## Server
|
|
## You can set the server endpoint here.
|
|
# [server]
|
|
# endpoint = "http://localhost:8080" # http or https URL
|
|
|
|
## You can add custom request headers, e.g. for authentication.
|
|
# [server.requestHeaders]
|
|
# Authorization = "Bearer eyJhbGciOiJ..........."
|
|
|
|
## Logs
|
|
## You can set the log level here. The log file is located at ~/.tabby-client/agent/logs/.
|
|
# [logs]
|
|
# level = "silent" # or "error" or "debug"
|
|
|
|
## Anonymous usage tracking
|
|
## You can disable anonymous usage tracking here.
|
|
# [anonymousUsageTracking]
|
|
# disable = false # set to true to disable
|
|
|
|
`;
|
|
|
|
export const userAgentConfig = isBrowser
|
|
? null
|
|
: (() => {
|
|
const EventEmitter = require("events");
|
|
const fs = require("fs-extra");
|
|
const toml = require("toml");
|
|
const chokidar = require("chokidar");
|
|
|
|
class ConfigFile extends EventEmitter {
|
|
filepath: string;
|
|
data: PartialAgentConfig = {};
|
|
watcher: ReturnType<typeof chokidar.watch> | null = null;
|
|
logger = require("./logger").rootLogger.child({ component: "ConfigFile" });
|
|
|
|
constructor(filepath: string) {
|
|
super();
|
|
this.filepath = filepath;
|
|
}
|
|
|
|
get config(): PartialAgentConfig {
|
|
return this.data;
|
|
}
|
|
|
|
async load() {
|
|
try {
|
|
const fileContent = await fs.readFile(this.filepath, "utf8");
|
|
// If the config file is the old template, and user has not modified it,
|
|
// Overwrite it with the new template.
|
|
if (fileContent.trim() === oldConfigTomlTemplate.trim()) {
|
|
await this.createTemplate();
|
|
return await this.load();
|
|
}
|
|
this.data = toml.parse(fileContent);
|
|
super.emit("updated", this.data);
|
|
} catch (error) {
|
|
if (error.code === "ENOENT") {
|
|
await this.createTemplate();
|
|
} else {
|
|
this.logger.error({ error }, "Failed to load config file");
|
|
}
|
|
}
|
|
}
|
|
|
|
async createTemplate() {
|
|
try {
|
|
await fs.outputFile(this.filepath, configTomlTemplate);
|
|
} catch (error) {
|
|
this.logger.error({ error }, "Failed to create config template file");
|
|
}
|
|
}
|
|
|
|
watch() {
|
|
this.watcher = chokidar.watch(this.filepath, {
|
|
interval: 1000,
|
|
});
|
|
this.watcher.on("add", this.load.bind(this));
|
|
this.watcher.on("change", this.load.bind(this));
|
|
}
|
|
}
|
|
|
|
const configFile = require("path").join(require("os").homedir(), ".tabby-client", "agent", "config.toml");
|
|
return new ConfigFile(configFile);
|
|
})();
|