shitton
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import axios from "axios";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("brave-search");
|
||||
import {Environment} from "../../common/environment";
|
||||
import {logError} from "../../util/utils";
|
||||
import {AiTool} from "../tool-types";
|
||||
@@ -264,7 +267,8 @@ function normalizeBraveResultFilter(value: unknown): string {
|
||||
}
|
||||
|
||||
export async function webSearch(args?: Record<string, unknown>) {
|
||||
console.log("braveSearch()");
|
||||
const startedAt = Date.now();
|
||||
logger.info("start", {args});
|
||||
|
||||
try {
|
||||
const query = asNonEmptyString(args?.query);
|
||||
@@ -370,7 +374,7 @@ export async function webSearch(args?: Record<string, unknown>) {
|
||||
response: data ?? null,
|
||||
};
|
||||
} finally {
|
||||
console.log("END: braveSearch()");
|
||||
logger.debug("done", {duration: logger.duration(startedAt)});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ import {readFile, writeFile} from "node:fs/promises";
|
||||
import {NOTES_HEADER, notesDir, notesRootFile} from "../../index";
|
||||
import {asNonEmptyString} from "./utils";
|
||||
import fs from "node:fs";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("create-note");
|
||||
|
||||
export type CreateNoteResult =
|
||||
| { success: true; filePath: string }
|
||||
@@ -38,7 +41,8 @@ export const createNoteTool = {
|
||||
export async function createNote(
|
||||
args?: Record<string, unknown>
|
||||
): Promise<CreateNoteResult> {
|
||||
console.log("CREATE_NOTE; ARGS: ", args);
|
||||
const startedAt = Date.now();
|
||||
logger.debug("start", {args});
|
||||
|
||||
const fileName = asNonEmptyString(args?.fileName) ?? "";
|
||||
if (!fileName.trim().length) {
|
||||
@@ -76,8 +80,10 @@ export async function createNote(
|
||||
}
|
||||
|
||||
await writeFile(notesRootFile, rootContent, "utf-8");
|
||||
logger.debug("done", {fileName, filePath: newFilePath, duration: logger.duration(startedAt)});
|
||||
return {success: true, filePath: newFilePath};
|
||||
} catch (error) {
|
||||
logger.error("failed", {duration: logger.duration(startedAt), error});
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
return {success: false, error: `Failed to process files: ${errorMessage}`};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ import path from "node:path";
|
||||
import {readdir, readFile, unlink, writeFile} from "node:fs/promises";
|
||||
import {notesDir, notesRootFile} from "../../index";
|
||||
import {asNonEmptyString} from "./utils";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("notes");
|
||||
|
||||
export type NoteListItem = {
|
||||
fileName: string;
|
||||
@@ -58,7 +61,8 @@ export const getNoteContentTool = {
|
||||
} satisfies AiTool;
|
||||
|
||||
export async function listNotes(): Promise<ListNotesResult> {
|
||||
console.log("LIST_NOTES");
|
||||
const startedAt = Date.now();
|
||||
logger.debug("list.start");
|
||||
|
||||
try {
|
||||
const entries = await readdir(notesDir, {withFileTypes: true});
|
||||
@@ -91,8 +95,10 @@ export async function listNotes(): Promise<ListNotesResult> {
|
||||
|
||||
notes.sort((a, b) => a.title.localeCompare(b.title));
|
||||
|
||||
logger.debug("list.done", {notes: notes.length, duration: logger.duration(startedAt)});
|
||||
return {success: true, notes};
|
||||
} catch (error) {
|
||||
logger.error("list.failed", {duration: logger.duration(startedAt), error});
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
return {success: false, error: `Failed to list notes: ${errorMessage}`};
|
||||
}
|
||||
@@ -101,7 +107,8 @@ export async function listNotes(): Promise<ListNotesResult> {
|
||||
export async function getNoteContent(
|
||||
args?: Record<string, unknown>,
|
||||
): Promise<GetNoteContentResult> {
|
||||
console.log("GET_NOTE_CONTENT; ARGS: ", args);
|
||||
const startedAt = Date.now();
|
||||
logger.debug("get_content.start", {args});
|
||||
|
||||
const fileName = asNonEmptyString(args?.fileName) ?? "";
|
||||
if (!fileName.trim().length) {
|
||||
@@ -118,6 +125,7 @@ export async function getNoteContent(
|
||||
const normalizedFileName = path.basename(noteFilePath);
|
||||
const relativePath = path.relative(path.dirname(notesRootFile), noteFilePath);
|
||||
|
||||
logger.debug("get_content.done", {fileName: normalizedFileName, relativePath, chars: content.length, duration: logger.duration(startedAt)});
|
||||
return {
|
||||
success: true,
|
||||
fileName: normalizedFileName,
|
||||
@@ -127,6 +135,7 @@ export async function getNoteContent(
|
||||
content,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("list.failed", {duration: logger.duration(startedAt), error});
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
return {success: false, error: `Failed to read note: ${errorMessage}`};
|
||||
}
|
||||
@@ -219,7 +228,8 @@ export const deleteNoteTool = {
|
||||
export async function updateNoteContent(
|
||||
args?: Record<string, unknown>,
|
||||
): Promise<UpdateNoteContentResult> {
|
||||
console.log("UPDATE_NOTE_CONTENT; ARGS: ", args);
|
||||
const startedAt = Date.now();
|
||||
logger.debug("update_content.start", {args});
|
||||
|
||||
const fileName = asNonEmptyString(args?.fileName) ?? "";
|
||||
if (!fileName.trim().length) {
|
||||
@@ -239,9 +249,11 @@ export async function updateNoteContent(
|
||||
try {
|
||||
await readFile(noteFilePath, "utf-8");
|
||||
await writeFile(noteFilePath, content, "utf-8");
|
||||
logger.debug("update_content.done", {fileName, filePath: noteFilePath, chars: content.length, duration: logger.duration(startedAt)});
|
||||
|
||||
return {success: true, filePath: noteFilePath};
|
||||
} catch (error) {
|
||||
logger.error("list.failed", {duration: logger.duration(startedAt), error});
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
return {success: false, error: `Failed to update note: ${errorMessage}`};
|
||||
}
|
||||
@@ -250,7 +262,8 @@ export async function updateNoteContent(
|
||||
export async function deleteNote(
|
||||
args?: Record<string, unknown>,
|
||||
): Promise<DeleteNoteResult> {
|
||||
console.log("DELETE_NOTE; ARGS: ", args);
|
||||
const startedAt = Date.now();
|
||||
logger.debug("delete.start", {args});
|
||||
|
||||
const fileName = asNonEmptyString(args?.fileName) ?? "";
|
||||
if (!fileName.trim().length) {
|
||||
@@ -265,9 +278,11 @@ export async function deleteNote(
|
||||
try {
|
||||
await unlink(noteFilePath);
|
||||
await removeNoteLinkFromRoot(noteFilePath);
|
||||
logger.debug("delete.done", {fileName, filePath: noteFilePath, duration: logger.duration(startedAt)});
|
||||
|
||||
return {success: true, filePath: noteFilePath};
|
||||
} catch (error) {
|
||||
logger.error("list.failed", {duration: logger.duration(startedAt), error});
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
return {success: false, error: `Failed to delete note: ${errorMessage}`};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import {AiTool} from "../tool-types";
|
||||
import axios from "axios";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("market-rates");
|
||||
|
||||
export const getMarketRatesTool = {
|
||||
type: "function",
|
||||
@@ -59,11 +62,14 @@ export const marketRatesToolPrompt = [
|
||||
].join("\n");
|
||||
|
||||
export async function getMarketRates(): Promise<unknown | undefined> {
|
||||
const startedAt = Date.now();
|
||||
try {
|
||||
logger.info("start");
|
||||
const response = await axios.get("https://apid.r00t.top/api/v2/currency/rates");
|
||||
logger.debug("done", {duration: logger.duration(startedAt), status: response.status});
|
||||
return response.data;
|
||||
} catch (e: unknown) {
|
||||
console.error("GET_MARKET_RATES", e);
|
||||
logger.error("failed", {duration: logger.duration(startedAt), error: e});
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ import path from "node:path";
|
||||
import {AiTool} from "../tool-types";
|
||||
import {Environment} from "../../common/environment";
|
||||
import {randomUUID} from "node:crypto";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("python-interpreter");
|
||||
|
||||
export const PYTHON_INTERPRETER_TOOL_NAME = "python_interpreter";
|
||||
|
||||
@@ -203,17 +206,17 @@ export async function runPythonInterpreter(
|
||||
};
|
||||
}
|
||||
|
||||
console.time("python.syntax");
|
||||
const syntaxStartedAt = Date.now();
|
||||
const syntax = await validatePythonSyntax(args.code, options);
|
||||
console.timeEnd("python.syntax");
|
||||
logger.debug("syntax.done", {duration: logger.duration(syntaxStartedAt), ok: syntax.ok});
|
||||
|
||||
if (!syntax.ok) {
|
||||
return syntax;
|
||||
}
|
||||
|
||||
console.time("python.execution");
|
||||
const executionStartedAt = Date.now();
|
||||
const result = await executePythonCode(args, options);
|
||||
console.timeEnd("python.execution");
|
||||
logger.debug("execution.done", {duration: logger.duration(executionStartedAt), ok: result.ok, phase: result.phase});
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -293,7 +296,8 @@ async function executePythonCode(
|
||||
args: PythonInterpreterArgs,
|
||||
options: PythonInterpreterOptions = {},
|
||||
): Promise<PythonToolResult> {
|
||||
console.log("EXECUTE_PYTHON_CODE", "ARGS: ", JSON.stringify(args), "; OPTIONS: ", JSON.stringify(options));
|
||||
const startedAt = Date.now();
|
||||
logger.info("execute.start", {args, options});
|
||||
|
||||
const pythonBinary =
|
||||
options.pythonBinary ?? process.env.PYTHON_INTERPRETER_BINARY ?? "C:\\Users\\meloda\\Desktop\\AI_BOT\\.venv\\Scripts\\python.exe";
|
||||
@@ -329,7 +333,7 @@ async function executePythonCode(
|
||||
mode: 0o600,
|
||||
});
|
||||
|
||||
console.log("EXECUTE_PYTHON_CODE", "SCRIPT FILE WRITTEN", new Date());
|
||||
logger.debug("script.written", {tempDir, userScriptPath, runnerPath, duration: logger.duration(startedAt)});
|
||||
|
||||
const result = await runProcess({
|
||||
command: pythonBinary,
|
||||
@@ -346,10 +350,10 @@ async function executePythonCode(
|
||||
},
|
||||
});
|
||||
|
||||
console.log("EXECUTE_PYTHON_CODE", "RESULT ACHIEVED", new Date());
|
||||
logger.debug("process.done", {duration: logger.duration(startedAt), exitCode: result.exitCode, timedOut: result.timedOut, outputTruncated: result.outputTruncated});
|
||||
|
||||
if (result.timedOut) {
|
||||
console.log("EXECUTE_PYTHON_CODE", "RESULT ERROR TIMED OUT", new Date());
|
||||
logger.warn("process.timeout", {duration: logger.duration(startedAt)});
|
||||
return {
|
||||
ok: false,
|
||||
phase: "execution",
|
||||
@@ -365,7 +369,7 @@ async function executePythonCode(
|
||||
}
|
||||
|
||||
if (result.outputTruncated) {
|
||||
console.log("EXECUTE_PYTHON_CODE", "RESULT ERROR TRUNCATED", new Date());
|
||||
logger.warn("process.output_truncated", {duration: logger.duration(startedAt), stdoutChars: result.stdout.length, stderrChars: result.stderr.length});
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
@@ -382,7 +386,7 @@ async function executePythonCode(
|
||||
}
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
console.log("EXECUTE_PYTHON_CODE", "RESULT ERROR EXIT CODE", new Date(), "\n", JSON.stringify(result, null, 2));
|
||||
logger.warn("process.non_zero_exit", {duration: logger.duration(startedAt), result});
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
@@ -398,7 +402,7 @@ async function executePythonCode(
|
||||
};
|
||||
}
|
||||
|
||||
console.log("EXECUTE_PYTHON_CODE", "RESULT NORMAL", new Date());
|
||||
logger.debug("process.ok", {duration: logger.duration(startedAt)});
|
||||
|
||||
const {
|
||||
artifacts,
|
||||
@@ -420,7 +424,7 @@ async function executePythonCode(
|
||||
skippedArtifacts,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log("EXECUTE_PYTHON_CODE", "RESULT ERROR", new Date());
|
||||
logger.error("execute.failed", {duration: logger.duration(startedAt), error});
|
||||
return {
|
||||
ok: false,
|
||||
phase: "internal",
|
||||
|
||||
+10
-2
@@ -1,6 +1,9 @@
|
||||
import {getToolHandlers} from "./registry";
|
||||
import {normalizeToolArguments} from "./utils";
|
||||
import {PYTHON_INTERPRETER_TOOL_NAME, PythonInterpreterInputFile, runPythonInterpreter} from "./python-interpretator";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("runtime");
|
||||
|
||||
export type ToolRuntimeContext = {
|
||||
pythonInputFiles?: PythonInterpreterInputFile[];
|
||||
@@ -16,7 +19,9 @@ export async function executeToolCall(
|
||||
args?: unknown,
|
||||
context: ToolRuntimeContext = {},
|
||||
): Promise<string> {
|
||||
const startedAt = Date.now();
|
||||
const handler = getToolHandlers()[name];
|
||||
logger.info("execute.start", {name, args});
|
||||
|
||||
if (!handler) {
|
||||
return stringifyToolResult({
|
||||
@@ -35,14 +40,17 @@ export async function executeToolCall(
|
||||
});
|
||||
|
||||
const s = stringifyToolResult(result);
|
||||
console.log("PYTHON_INTERPRETER_STRING_RESULT", s);
|
||||
logger.debug("execute.done", {name, chars: s.length, duration: logger.duration(startedAt)});
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const result = await handler(normalizeToolArguments(args));
|
||||
return stringifyToolResult(result);
|
||||
const s = stringifyToolResult(result);
|
||||
logger.debug("execute.done", {name, chars: s.length, duration: logger.duration(startedAt)});
|
||||
return s;
|
||||
} catch (error) {
|
||||
logger.error("execute.failed", {name, duration: logger.duration(startedAt), error});
|
||||
return stringifyToolResult({
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
|
||||
@@ -3,6 +3,9 @@ import path from "node:path";
|
||||
import {readdir, readFile} from "node:fs/promises";
|
||||
import {notesDir, notesRootFile} from "../../index";
|
||||
import {asNonEmptyString} from "./utils";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("search-notes");
|
||||
|
||||
export type SearchNoteMatchedField = "file_name" | "title" | "content";
|
||||
|
||||
@@ -51,7 +54,8 @@ export const searchNotesTool = {
|
||||
export async function searchNotes(
|
||||
args?: Record<string, unknown>,
|
||||
): Promise<SearchNotesResult> {
|
||||
console.log("SEARCH_NOTES; ARGS: ", args);
|
||||
const startedAt = Date.now();
|
||||
logger.debug("start", {args});
|
||||
|
||||
const query = asNonEmptyString(args?.query) ?? "";
|
||||
if (!query.trim().length) {
|
||||
@@ -127,6 +131,7 @@ export async function searchNotes(
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.slice(0, limit);
|
||||
|
||||
logger.debug("done", {query, limit, results: results.length, duration: logger.duration(startedAt)});
|
||||
return {success: true, results};
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
|
||||
@@ -5,6 +5,9 @@ import {notesRootFile} from "../../index";
|
||||
import {asNonEmptyString} from "./utils";
|
||||
import {buildSafeNoteFilePath} from "./list-notes";
|
||||
import z from "zod";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("get-note-file");
|
||||
|
||||
export type NoteFileAttachment = {
|
||||
type: "local_file";
|
||||
@@ -64,7 +67,7 @@ export const getNoteFileTool = {
|
||||
export async function getNoteFile(
|
||||
args?: Record<string, unknown>,
|
||||
): Promise<GetNoteFileResult> {
|
||||
console.log("GET_NOTE_FILE; ARGS: ", args);
|
||||
logger.debug("start", {args});
|
||||
|
||||
const fileName = asNonEmptyString(args?.fileName) ?? "";
|
||||
if (!fileName.trim().length) {
|
||||
@@ -100,7 +103,7 @@ export async function getNoteFile(
|
||||
},
|
||||
};
|
||||
|
||||
console.log("GET_NOTE_FILE; RESULT: ", result);
|
||||
logger.debug("done", {fileName: result.attachment.fileName, relativePath: result.attachment.relativePath, sizeBytes: result.attachment.sizeBytes});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import {Ollama} from "ollama";
|
||||
import {z} from "zod";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("utils");
|
||||
|
||||
export function asNonEmptyString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim().length > 0
|
||||
@@ -79,14 +82,15 @@ export async function unloadAllOllamaModels(ollama: Ollama, exceptFor?: string[]
|
||||
);
|
||||
|
||||
await Promise.all(unloadPromises);
|
||||
console.log("All models have been requested to unload" + (exceptFor?.length ? ` except for [${exceptFor?.join(", ")}].` : "."));
|
||||
logger.info("ollama.unload_all.done", {count: modelsToUnload.length, exceptFor});
|
||||
} catch (error) {
|
||||
console.error("Error unloading models:", error);
|
||||
logger.error("ollama.unload_all.failed", {exceptFor, error});
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadOllamaModel(model: string, ollama: Ollama, contextLength: number): Promise<boolean> {
|
||||
try {
|
||||
logger.info("ollama.load.start", {model, contextLength});
|
||||
await ollama.generate({
|
||||
model: model,
|
||||
stream: false,
|
||||
@@ -95,9 +99,10 @@ export async function loadOllamaModel(model: string, ollama: Ollama, contextLeng
|
||||
num_ctx: contextLength
|
||||
}
|
||||
});
|
||||
logger.info("ollama.load.done", {model, contextLength});
|
||||
return true;
|
||||
} catch (e: unknown) {
|
||||
console.error("Error loading Ollama model:", model);
|
||||
logger.error("ollama.load.failed", {model, contextLength, error: e});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import axios from "axios";
|
||||
import {toolsLogger} from "./tool-logger";
|
||||
|
||||
const logger = toolsLogger.child("weather");
|
||||
import {Environment} from "../../common/environment";
|
||||
import {logError} from "../../util/utils";
|
||||
import {AiTool} from "../tool-types";
|
||||
@@ -43,7 +46,8 @@ export const weatherToolPrompt = [
|
||||
].join("\n");
|
||||
|
||||
export async function getWeather(args?: Record<string, unknown>): Promise<Record<string, unknown> | null> {
|
||||
console.log("getWeather()");
|
||||
const startedAt = Date.now();
|
||||
logger.info("start", {args});
|
||||
try {
|
||||
const city = asNonEmptyString(args?.city);
|
||||
const lang = asNonEmptyString(args?.lang);
|
||||
@@ -61,7 +65,7 @@ export async function getWeather(args?: Record<string, unknown>): Promise<Record
|
||||
appid: apiKey,
|
||||
},
|
||||
})).data[0];
|
||||
console.log("GEOCODE_RESPONSE", geocodeResponse);
|
||||
logger.debug("geocode.done", {city, country: geocodeResponse?.country, hasResult: !!geocodeResponse, geocodeResponse});
|
||||
if (!geocodeResponse) {
|
||||
return {
|
||||
ok: false,
|
||||
@@ -83,7 +87,7 @@ export async function getWeather(args?: Record<string, unknown>): Promise<Record
|
||||
...(lang ? {lang} : {}),
|
||||
},
|
||||
})).data;
|
||||
console.log("RESPONSE: getWeather(lang=" + lang + "): ", response);
|
||||
logger.debug("weather_api.done", {city, country: geocodeResponse.country, lang, units: "metric", hasResponse: !!response});
|
||||
|
||||
const main = response.main;
|
||||
const sys = response.sys;
|
||||
@@ -138,9 +142,10 @@ export async function getWeather(args?: Record<string, unknown>): Promise<Record
|
||||
},
|
||||
};
|
||||
} catch (e: unknown) {
|
||||
logger.error("failed", {duration: logger.duration(startedAt), error: e});
|
||||
logError(e);
|
||||
return null;
|
||||
} finally {
|
||||
console.log("END: getWeather()");
|
||||
logger.debug("done", {duration: logger.duration(startedAt)});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user