* initialize * expand tool result text limit | add syntax highlighting and json formatting to tool result rendering * fix onError jsdoc * lint * fix unread icon * route protection * improve form handling for NewJobModal * safeJsonParse * remove unneeded comments * remove trycatch * add truncateText helper * add explicit fallback value tos safeJsonParse * add shared cron constant and helpers * reduce frontend indirection * use isLight to compute syntax highlighting theme * remove dead code * remove forJob and make job limit to 50 * create recomputeNextRunAt helper method * add comment about nextRunAt recomputation * add job queue and concurrency control to scheduled jobs * use p-queue * change default max concurrent value to 1 * add comment explaining internal scheduling system * add recomputeNextRunAt on boot * add generated documents to run details * Modify toolsOverride functionality where no tools selected means no tools are given to the agent add a select all/deselect all toggle button for easily selecting all tools in the cerate job form * create usePolling hook * add polling to scheduled jobs and scheduled job runs pages * add cron generation feature in job form * remove cron generation feature | add cron builder feature | add max active scheduled jobs limit * set MAX_ACTIVE to null * replace hour and minute input fields with input with type time * simplify * organize components * move components to bottom of page component * change Generated Documents to Generated Files * add i18n to cronstrue * add i18n * add type="button" to button elements * refactor fileSource retrieval logic * one scheduled job run can have status "running" * add protection of file retrieveal from scheduled job in multiuser mode * fix comments * make job status default to queued * add queued status * fix bug with result trace rendering * store timeout ref and clearTimeout once race settles * remove unneeded handlerPromise tracking * move imports to top level * refactor hardcoded paths to path resolve functions * implement new job form design * simplify * fix button styles * fix runJob bug * implement styles for scheduled jobs page * apply dark mode figma styles * delete unused translation key * implement light mode for new new job modal, run history, and run details * lint * fix light mode scroll bar in tool call card * adjust table header contrast * fix type in subtitle * kill workers when job is in-flight before deleting job * add border-none to buttons * change locale time to iso string * import BackgroundService module level | instatiate backgroundService singltone once and reuse across handlers * add p-queue, @breejs/later and cron-validate as core deps * parse cron expression to a builder state once * add theme to day buttons in cron builder * fix stale tools selection caption * flip popover when popover clips screen height * make ScheduleJob.trigger() await the run insertion | disable run now button if job is in flight * regen table * refactor generated file card * refactor frontend * remove logs * major refactor for tool picking, fix bree/later bug * combine action endpoints, move contine to method * fix unoptimized query with include + take + order * fix dangerous use, refactor job to utils * add copy content to text response * improve notification system subscription for browser * remove unused translations * prevent gen-file cleanup job from deleting active job file generated references * rich text copy * Scheduled Jobs: Translations (#5482) * add locales for scheduled jobs * i18n --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com> * add config flag with UI notice * update README * telemetry datapoints * Always use UTC on backend, convert to local in frontend * fix tz render * Add job killing * cleanup thinking text in job notifications and break out reasoning in response text. Also hide zero metrics since that is useless * Port generatedFile schema to the normalized workspace chat `outputs` file format so porting to thread is simple and implem between chats <> jobs is 1:1 * what the fuck * compiled bug * fixed thinking oddity in complied frontend * supress multi-toast * fix duration call * Revert "fix duration call" This reverts commit 0491bc71f4223e65ea4046561b15b268fefb8da2. * revert and reapply fix --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
149 lines
4.3 KiB
JavaScript
149 lines
4.3 KiB
JavaScript
const { v4 } = require("uuid");
|
|
const { SystemSettings } = require("./systemSettings");
|
|
|
|
// Map of events and last sent time to check if the event is on cooldown
|
|
// This will be cleared on server restart - but that is fine since it is mostly to just
|
|
// prevent spamming the logs.
|
|
const TelemetryCooldown = new Map();
|
|
|
|
const Telemetry = {
|
|
// Write-only key. It can't read events or any of your other data, so it's safe to use in public apps.
|
|
pubkey: "phc_9qu7QLpV8L84P3vFmEiZxL020t2EqIubP7HHHxrSsqS",
|
|
stubDevelopmentEvents: true, // [DO NOT TOUCH] Core team only.
|
|
label: "telemetry_id",
|
|
/*
|
|
Key value pairs of events that should be debounced to prevent spamming the logs.
|
|
This should be used for events that could be triggered in rapid succession that are not useful to atomically log.
|
|
The value is the number of seconds to debounce the event
|
|
*/
|
|
debounced: {
|
|
sent_chat: 1800,
|
|
agent_chat_sent: 1800,
|
|
agent_chat_started: 1800,
|
|
agent_tool_call: 1800,
|
|
|
|
// Document mgmt events
|
|
document_uploaded: 30,
|
|
documents_embedded_in_workspace: 30,
|
|
link_uploaded: 30,
|
|
raw_document_uploaded: 30,
|
|
document_parsed: 30,
|
|
agent_generated_file_downloaded: 30,
|
|
},
|
|
|
|
id: async function () {
|
|
const result = await SystemSettings.get({ label: this.label });
|
|
return result?.value || null;
|
|
},
|
|
|
|
connect: async function () {
|
|
const client = this.client();
|
|
const distinctId = await this.findOrCreateId();
|
|
return { client, distinctId };
|
|
},
|
|
|
|
isDev: function () {
|
|
return process.env.NODE_ENV === "development" && this.stubDevelopmentEvents;
|
|
},
|
|
|
|
client: function () {
|
|
if (process.env.DISABLE_TELEMETRY === "true" || this.isDev()) return null;
|
|
const { PostHog } = require("posthog-node");
|
|
return new PostHog(this.pubkey);
|
|
},
|
|
|
|
runtime: function () {
|
|
if (process.env.ANYTHING_LLM_RUNTIME === "docker") return "docker";
|
|
if (process.env.NODE_ENV === "production") return "production";
|
|
return "other";
|
|
},
|
|
|
|
/**
|
|
* Checks if the event is on cooldown
|
|
* @param {string} event - The event to check
|
|
* @returns {boolean} - True if the event is on cooldown, false otherwise
|
|
*/
|
|
isOnCooldown: function (event) {
|
|
// If the event is not debounced, return false
|
|
if (!this.debounced[event]) return false;
|
|
|
|
// If the event is not in the cooldown map, return false
|
|
const lastSent = TelemetryCooldown.get(event);
|
|
if (!lastSent) return false;
|
|
|
|
// If the event is in the cooldown map, check if it has expired
|
|
const now = Date.now();
|
|
const cooldown = this.debounced[event] * 1000;
|
|
return now - lastSent < cooldown;
|
|
},
|
|
|
|
/**
|
|
* Marks the event as on cooldown - will check if the event is debounced first
|
|
* @param {string} event - The event to mark
|
|
*/
|
|
markOnCooldown: function (event) {
|
|
if (!this.debounced[event]) return;
|
|
TelemetryCooldown.set(event, Date.now());
|
|
},
|
|
|
|
sendTelemetry: async function (
|
|
event,
|
|
eventProperties = {},
|
|
subUserId = null,
|
|
silent = false
|
|
) {
|
|
try {
|
|
const { client, distinctId: systemId } = await this.connect();
|
|
if (!client) return;
|
|
const distinctId = !!subUserId ? `${systemId}::${subUserId}` : systemId;
|
|
const properties = { ...eventProperties, runtime: this.runtime() };
|
|
|
|
// If the event is on cooldown, return
|
|
if (this.isOnCooldown(event)) return;
|
|
|
|
// Silence some events to keep logs from being too messy in production
|
|
// eg: Tool calls from agents spamming the logs.
|
|
if (!silent) {
|
|
console.log(`\x1b[32m[TELEMETRY SENT]\x1b[0m`, {
|
|
event,
|
|
distinctId,
|
|
properties,
|
|
});
|
|
}
|
|
|
|
client.capture({
|
|
event,
|
|
distinctId,
|
|
properties,
|
|
});
|
|
} catch {
|
|
return;
|
|
} finally {
|
|
// Mark the event as on cooldown if needed
|
|
this.markOnCooldown(event);
|
|
}
|
|
},
|
|
|
|
flush: async function () {
|
|
const client = this.client();
|
|
if (!client) return;
|
|
await client.shutdownAsync();
|
|
},
|
|
|
|
setUid: async function () {
|
|
const newId = v4();
|
|
await SystemSettings._updateSettings({ [this.label]: newId });
|
|
return newId;
|
|
},
|
|
|
|
findOrCreateId: async function () {
|
|
let currentId = await this.id();
|
|
if (currentId) return currentId;
|
|
|
|
currentId = await this.setUid();
|
|
return currentId;
|
|
},
|
|
};
|
|
|
|
module.exports = { Telemetry };
|