diff --git a/extensions/index.ts b/extensions/index.ts index c80115f..baf377a 100644 --- a/extensions/index.ts +++ b/extensions/index.ts @@ -15,7 +15,7 @@ import { registerQmemTree } from "./tools/tree"; import { registerQmemRules } from "./rules"; import { registerQmemLocal } from "./local-command"; import { flushQueueIfPending, localDbPath } from "./local-db.ts"; -import { loadConfig } from "./shared.ts"; +import { localIsoTimestamp, loadConfig } from "./shared.ts"; export default function qmemExtension(pi: ExtensionAPI) { registerQmemStore(pi); @@ -28,6 +28,25 @@ export default function qmemExtension(pi: ExtensionAPI) { registerQmemLocal(pi); registerQmemRules(pi); + // Aggiunge un timestamp locale a ogni risultato finale dei tool qmem. + pi.on("tool_result", (event) => { + if (!event.toolName.startsWith("qmem_")) return; + + const timestamp = localIsoTimestamp(); + const previousDetails = event.details; + const details = + previousDetails && typeof previousDetails === "object" && !Array.isArray(previousDetails) + ? (previousDetails as Record) + : previousDetails === undefined || previousDetails === null + ? {} + : { qmem_previous_details: previousDetails }; + + return { + content: [...event.content, { type: "text" as const, text: `Ora output qmem: ${timestamp}` }], + details: { ...details, qmem_output_timestamp: timestamp }, + }; + }); + // Outbox: al ritorno della connessione (nuova sessione/reload) i record // accodati offline vengono inviati al gateway. In background: l'avvio della // sessione non deve mai attendere la rete. diff --git a/extensions/rules.ts b/extensions/rules.ts index 98da10c..8ca96a3 100644 --- a/extensions/rules.ts +++ b/extensions/rules.ts @@ -1,7 +1,12 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; -import { MACHINE } from "./shared"; +import { localIsoTimestamp, MACHINE } from "./shared"; export function registerQmemRules(pi: ExtensionAPI) { + let sessionStartedAt = localIsoTimestamp(); + pi.on("session_start", () => { + sessionStartedAt = localIsoTimestamp(); + }); + const QMEM_RULES = `### pi-qmem rules (binding) MUST: - Run qmem_search before starting a task and before retrying after an error/block. @@ -33,8 +38,14 @@ Before any substantive answer or state-changing action, in order: pi.on("before_agent_start", async (event) => { const tools = event.systemPromptOptions?.selectedTools ?? []; - const hasQmem = ["qmem_store", "qmem_search", "qmem_get", "qmem_correct", "qmem_meta"].some((t) => tools.includes(t)); + const hasQmem = ["qmem_store", "qmem_search", "qmem_get", "qmem_correct", "qmem_meta", "qmem_tree"].some((t) => tools.includes(t)); if (!hasQmem) return {}; - return { systemPrompt: event.systemPrompt + QMEM_RULES }; + const runtimeContext = ` +### Contesto runtime sessione +- Host di questa sessione: ${MACHINE}. +- Sessione avviata: ${sessionStartedAt} (ISO 8601, fuso locale). +- Ora locale attuale: ${localIsoTimestamp()}. +- Usa questi valori runtime come contesto; non stimare né inventare host o date/ore.`; + return { systemPrompt: event.systemPrompt + runtimeContext + "\n" + QMEM_RULES }; }); } diff --git a/extensions/shared.ts b/extensions/shared.ts index 639d071..7a4cd15 100644 --- a/extensions/shared.ts +++ b/extensions/shared.ts @@ -207,6 +207,16 @@ export function detectMachine(): string { export const MACHINE = detectMachine(); +/** Timestamp ISO 8601 con offset del fuso locale della macchina. */ +export function localIsoTimestamp(date = new Date()): string { + const offsetMinutes = -date.getTimezoneOffset(); + const sign = offsetMinutes >= 0 ? "+" : "-"; + const absOffset = Math.abs(offsetMinutes); + const offset = `${sign}${String(Math.floor(absOffset / 60)).padStart(2, "0")}:${String(absOffset % 60).padStart(2, "0")}`; + const localTime = new Date(date.getTime() + offsetMinutes * 60_000).toISOString().slice(0, -1); + return `${localTime}${offset}`; +} + export async function gatewayRequest( cfg: MemoryConfig, method: string,