feat(recorder): aggiunti tool di registrazione e analisi attivita BiDi (JSONL)

This commit is contained in:
Matteo Benedetto
2026-08-22 12:37:53 +02:00
parent c3eea04bf1
commit 7dc7601102
+153
View File
@@ -720,6 +720,159 @@ export default function (pi: ExtensionAPI) {
},
});
// -------------------------------------------------------------------------
// Registrazione e analisi attività di navigazione (Activity Recorder JSONL)
// -------------------------------------------------------------------------
pi.registerTool({
name: "browser_record_start",
label: "Browser Record Start",
description:
"Avvia o riconfigura la registrazione continua degli eventi e delle attività di navigazione " +
"(URL, domini, navigazioni, caricamento DOM, errori e log di console) su un file JSONL.",
parameters: Type.Object({
path: Type.Optional(
Type.String({
description:
"Percorso assoluto del file JSONL (default: ~/.local/state/pi-firefox-bidi/activity.jsonl)",
}),
),
events: Type.Optional(
Type.Array(Type.String(), {
description: "Lista di eventi BiDi da registrare (opzionale)",
}),
),
}),
async execute(_id, params) {
await ensureBridge();
const r = await bridge("/recorder/start", {
method: "POST",
body: JSON.stringify(params),
});
return {
content: [
{
type: "text",
text: `Registrazione attività attiva su file: ${r.file}`,
},
],
details: r,
};
},
});
pi.registerTool({
name: "browser_record_stop",
label: "Browser Record Stop",
description: "Sospende la registrazione delle attività di navigazione su file.",
parameters: Type.Object({}),
async execute() {
await ensureBridge();
const r = await bridge("/recorder/stop", { method: "POST" });
return {
content: [
{
type: "text",
text: `Registrazione attività sospesa. Eventi totali registrati: ${r.totalEvents} (${r.file})`,
},
],
details: r,
};
},
});
pi.registerTool({
name: "browser_record_status",
label: "Browser Record Status",
description: "Mostra lo stato del registratore attività, il percorso del file JSONL e il numero di eventi.",
parameters: Type.Object({}),
async execute() {
await ensureBridge();
const r = await bridge("/recorder/status");
return {
content: [{ type: "text", text: JSON.stringify(r, null, 2) }],
details: r,
};
},
});
pi.registerTool({
name: "browser_record_get",
label: "Browser Record Get",
description:
"Recupera le attività di navigazione registrate dal file JSONL per analisi (formato compatto o JSON grezzo).",
parameters: Type.Object({
limit: Type.Optional(
Type.Number({ description: "Numero massimo di eventi recenti da recuperare (default 30)", default: 30 }),
),
format: Type.Optional(
Type.Enum(
{ summary: "summary", json: "json" },
{ description: "Formato: 'summary' (timeline compatta) o 'json' (oggetti completi)", default: "summary" },
),
),
}),
async execute(_id, params) {
await ensureBridge();
const r = await bridge("/recorder/get", {
method: "POST",
body: JSON.stringify({ limit: params.limit ?? 30 }),
});
const records: any[] = r.records ?? [];
if (params.format === "json") {
return {
content: [{ type: "text", text: JSON.stringify(r, null, 2) }],
details: r,
};
}
if (records.length === 0) {
return {
content: [{ type: "text", text: `Nessuna attività registrata nel log (${r.file}).` }],
details: r,
};
}
const lines = records.map((rec) => {
const timeStr = rec.timestamp ? rec.timestamp.split("T")[1]?.slice(0, 8) : "--:--:--";
if (rec.event === "navigation_started") {
return `[${timeStr}] 🌐 Navigazione: ${rec.url} (dominio: ${rec.domain ?? "-"})`;
} else if (rec.event === "page_loaded") {
return `[${timeStr}] ⏱ Caricato: ${rec.url ?? ""} in ${rec.durationMs ?? "?"}ms`;
} else if (rec.event === "dom_ready") {
return `[${timeStr}] 📄 DOM Ready: ${rec.url ?? ""}`;
} else if (rec.event === "console_log") {
return `[${timeStr}] 💬 [Console ${rec.level ?? "log"}]: ${rec.text ?? ""}`;
}
return `[${timeStr}] ⚡ ${rec.event}: ${rec.url ?? JSON.stringify(rec)}`;
});
return {
content: [
{
type: "text",
text: `Ultime ${records.length} attività registrate (${r.file}):\n\n` + lines.join("\n"),
},
],
details: r,
};
},
});
pi.registerTool({
name: "browser_record_clear",
label: "Browser Record Clear",
description: "Svuota il file di log delle attività e azzera il contatore.",
parameters: Type.Object({}),
async execute() {
await ensureBridge();
const r = await bridge("/recorder/clear", { method: "POST" });
return {
content: [{ type: "text", text: "Log attività svuotato con successo." }],
details: r,
};
},
});
// -------------------------------------------------------------------------
// Notifica asincrona (agy/bridge → pi): webhook locale
// -------------------------------------------------------------------------