// SF — Memory tool registration
//
// Exposes the memory-layer tools (log_reasoning, memory_search, memory_graph)
// as native SF tools. All three degrade gracefully when the SF database is
// unavailable.
import { Type } from "@sinclair/typebox";
import {
	executeMemoryCapture,
	executeMemoryQuery,
	executeSfGraph,
} from "../tools/memory-tools.js";
import { ensureDbOpen } from "./dynamic-tools.js";
export function registerMemoryTools(pi) {
	// ─── log_reasoning ────────────────────────────────────────────────────
	pi.registerTool({
		name: "log_reasoning",
		label: "Capture Thought",
		description:
			"Save a reusable project insight — a decision, convention, pattern, gotcha, or environment detail — to persistent memory. " +
			"Use this once per genuinely new insight that will remain relevant across future tasks; skip transient or task-specific observations.",
		promptSnippet:
			"Capture a durable project insight into the SF memory store (categories: architecture, convention, gotcha, pattern, preference, environment)",
		promptGuidelines: [
			"Use log_reasoning for insights that will remain useful across future sessions.",
			"Do NOT capture one-off bug fixes, temporary state, secrets, or task-specific details.",
			"Keep content to 1–3 sentences.",
			"Set confidence: 0.6 tentative, 0.8 solid, 0.95 well-confirmed (default 0.8).",
		],
		parameters: Type.Object({
			category: Type.Union(
				[
					Type.Literal("architecture"),
					Type.Literal("convention"),
					Type.Literal("gotcha"),
					Type.Literal("preference"),
					Type.Literal("environment"),
					Type.Literal("pattern"),
				],
				{ description: "Memory category" },
			),
			content: Type.String({
				description: "The memory text (1–3 sentences, no secrets)",
			}),
			confidence: Type.Optional(
				Type.Number({
					description: "0.1–0.99, default 0.8",
					minimum: 0.1,
					maximum: 0.99,
				}),
			),
		}),
		async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
			const ok = await ensureDbOpen();
			if (!ok) {
				return {
					content: [
						{
							type: "text",
							text: "Error: SF database is not available. Cannot capture memory.",
						},
					],
					details: { operation: "memory_capture", error: "db_unavailable" },
					isError: true,
				};
			}
			return executeMemoryCapture(params);
		},
	});
	// ─── memory_search ───────────────────────────────────────────────────────
	pi.registerTool({
		name: "memory_search",
		label: "Query Memory",
		description:
			"Search persistent memory for stored insights and return matches ranked by relevance and confidence. " +
			"Use this before starting research to surface prior decisions, conventions, or environment details that apply to the current task.",
		promptSnippet:
			"Search the SF memory store by keyword; returns ranked memories with id, category, and content",
		promptGuidelines: [
			"Use memory_search when you need durable project context that may not be in the current prompt.",
			"Provide a short keyword-style query — not a full question.",
			"Use category to narrow results to gotchas, conventions, architecture notes, etc.",
		],
		parameters: Type.Object({
			query: Type.String({ description: "Keyword query (2+ char terms)" }),
			k: Type.Optional(
				Type.Number({
					description: "Max results (default 10, max 50)",
					minimum: 1,
					maximum: 50,
				}),
			),
			category: Type.Optional(
				Type.Union(
					[
						Type.Literal("architecture"),
						Type.Literal("convention"),
						Type.Literal("gotcha"),
						Type.Literal("preference"),
						Type.Literal("environment"),
						Type.Literal("pattern"),
					],
					{ description: "Restrict results to a single category" },
				),
			),
			reinforce_hits: Type.Optional(
				Type.Boolean({
					description:
						"Increment hit_count on returned memories (default false)",
				}),
			),
		}),
		async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
			const ok = await ensureDbOpen();
			if (!ok) {
				return {
					content: [
						{
							type: "text",
							text: "Error: SF database is not available. Cannot query memory.",
						},
					],
					details: { operation: "memory_search", error: "db_unavailable" },
					isError: true,
				};
			}
			return executeMemoryQuery(params);
		},
	});
	// ─── memory_graph ──────────────────────────────────────────────────────────
	pi.registerTool({
		name: "memory_graph",
		label: "SF Knowledge Graph",
		description:
			"Inspect the supersession graph between memory entries and return the chain of memories a given entry has replaced. " +
			"Use this when you need to understand how a stored insight has evolved or been overridden over time.",
		promptSnippet: "Query the memory relationship graph or trigger a rebuild",
		promptGuidelines: [
			"Use mode=query with a memoryId when you want to see how a memory relates to others.",
			"Phase 1 only exposes supersedes edges; additional relation types arrive in later phases.",
		],
		parameters: Type.Object({
			mode: Type.Union([Type.Literal("build"), Type.Literal("query")], {
				description:
					"build = recompute graph (placeholder), query = inspect edges",
			}),
			memoryId: Type.Optional(
				Type.String({ description: "Memory ID (required when mode=query)" }),
			),
			depth: Type.Optional(
				Type.Number({
					description: "Hops to traverse (0–5, default 1)",
					minimum: 0,
					maximum: 5,
				}),
			),
			rel: Type.Optional(
				Type.Union(
					[
						Type.Literal("related_to"),
						Type.Literal("depends_on"),
						Type.Literal("contradicts"),
						Type.Literal("elaborates"),
						Type.Literal("supersedes"),
					],
					{ description: "Only include edges with this relation type" },
				),
			),
		}),
		async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
			const ok = await ensureDbOpen();
			if (!ok) {
				return {
					content: [
						{
							type: "text",
							text: "Error: SF database is not available.",
						},
					],
					details: { operation: "memory_graph", error: "db_unavailable" },
					isError: true,
				};
			}
			return executeSfGraph(params);
		},
	});
}
