initial 2
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-06-26 09:26:50 +01:00
parent 194330fb47
commit 3b37368e7d
213 changed files with 14688 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { getWhatAiKnows } from "@/lib/services/ai-chat";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
return getWhatAiKnows(user.id);
});
}

View File

@@ -0,0 +1,40 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { getChatSession, sendChatMessage, archiveChatSession } from "@/lib/services/ai-chat";
export async function GET(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
const data = await getChatSession(user.id, id);
if (!data) throw new Error("Session not found");
return data;
});
}
export async function DELETE(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
await archiveChatSession(user.id, id);
return { ok: true };
});
}
export async function POST(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
return sendChatMessage(user.id, id, body.content ?? "");
});
}

View File

@@ -0,0 +1,19 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { listChatSessions, createChatSession } from "@/lib/services/ai-chat";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
const sessions = await listChatSessions(user.id);
return { sessions };
});
}
export async function POST(request: Request) {
const body = await request.json().catch(() => ({}));
return handleApi(async () => {
const { user } = await requireUser();
return createChatSession(user.id, body.title, body.featureContext);
});
}

View File

@@ -0,0 +1,33 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import {
getAiBehaviorConfig,
getAiProviderConfig,
saveAiBehaviorConfig,
saveAiProviderConfig,
} from "@/lib/services/ai-config";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
const behavior = await getAiBehaviorConfig(user.id);
const provider = await getAiProviderConfig(user.id);
return { behavior, provider };
});
}
export async function PATCH(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
let behavior = await getAiBehaviorConfig(user.id);
let provider = await getAiProviderConfig(user.id);
if (body.behavior) {
behavior = await saveAiBehaviorConfig(user.id, body.behavior);
}
if (body.provider) {
provider = await saveAiProviderConfig(user.id, body.provider);
}
return { behavior, provider };
});
}

View File

@@ -0,0 +1,19 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { buildMentorContext, formatContextForPrompt } from "@/lib/services/ai-context";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const message = searchParams.get("message") ?? "";
const feature = searchParams.get("feature") ?? "mentor";
return handleApi(async () => {
const { user } = await requireUser();
const ctx = await buildMentorContext(user.id, { userMessage: message, feature, logContext: false });
return {
layers: ctx.layers,
tokenEstimate: ctx.tokenEstimate,
memoryIds: ctx.memoryIds,
formatted: formatContextForPrompt(ctx),
};
});
}

View File

@@ -0,0 +1,21 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { getCachedHealth, runHealthCheck } from "@/lib/services/ai-config";
import { getLastHealthLogs } from "@/lib/services/ai-config";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
const cached = await getCachedHealth(user.id);
const logs = await getLastHealthLogs(user.id, 5);
return { health: cached, logs };
});
}
export async function POST() {
return handleApi(async () => {
const { user } = await requireUser();
const health = await runHealthCheck(user.id);
return { health };
});
}

View File

@@ -0,0 +1,40 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { getMemory, updateMemory, archiveMemory } from "@/lib/services/ai-memory";
export async function GET(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
const memory = await getMemory(user.id, id);
if (!memory) throw new Error("Memory not found");
return memory;
});
}
export async function PATCH(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
return updateMemory(user.id, id, body);
});
}
export async function DELETE(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
await archiveMemory(user.id, id);
return { ok: true };
});
}

View File

@@ -0,0 +1,21 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import {
getMemoryLearningSettings,
saveMemoryLearningSettings,
} from "@/lib/services/ai-memory";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
return getMemoryLearningSettings(user.id);
});
}
export async function PATCH(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
return saveMemoryLearningSettings(user.id, body);
});
}

View File

@@ -0,0 +1,13 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { resetAllMemories } from "@/lib/services/ai-memory";
export async function POST(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
if (!body.confirm) throw new Error("Confirmation required");
await resetAllMemories(user.id);
return { ok: true };
});
}

View File

@@ -0,0 +1,32 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import {
listMemories,
createMemory,
getProfileSummary,
listSuggestions,
exportMemories,
} from "@/lib/services/ai-memory";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
return handleApi(async () => {
const { user } = await requireUser();
const category = searchParams.get("category") ?? undefined;
const q = searchParams.get("q") ?? undefined;
const enabledParam = searchParams.get("enabled");
const enabled = enabledParam === null ? undefined : enabledParam === "true";
const memories = await listMemories(user.id, { category, q, enabled });
const summary = await getProfileSummary(user.id);
const pending = await listSuggestions(user.id, "pending");
return { memories, summary, pendingCount: pending.length };
});
}
export async function POST(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
return createMemory(user.id, body);
});
}

View File

@@ -0,0 +1,15 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { acceptSuggestion } from "@/lib/services/ai-memory";
export async function POST(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const body = await request.json().catch(() => ({}));
return handleApi(async () => {
const { user } = await requireUser();
return acceptSuggestion(user.id, id, body);
});
}

View File

@@ -0,0 +1,15 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { ignoreSuggestion } from "@/lib/services/ai-memory";
export async function POST(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
await ignoreSuggestion(user.id, id);
return { ok: true };
});
}

View File

@@ -0,0 +1,15 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { rejectSuggestion } from "@/lib/services/ai-memory";
export async function POST(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
await rejectSuggestion(user.id, id);
return { ok: true };
});
}

View File

@@ -0,0 +1,13 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { listSuggestions } from "@/lib/services/ai-memory";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const status = searchParams.get("status") ?? "pending";
return handleApi(async () => {
const { user } = await requireUser();
const suggestions = await listSuggestions(user.id, status);
return { suggestions };
});
}

View File

@@ -0,0 +1,54 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { listMemories, saveProfileSummary } from "@/lib/services/ai-memory";
import { getProvider } from "@/lib/ai/provider-registry";
import { getAiBehaviorConfig, getAiProviderConfig, buildSystemPrompt } from "@/lib/services/ai-config";
import { getTemplateBody } from "@/lib/services/ai-templates";
import { renderTemplate } from "@/lib/ai/prompts/render";
export async function POST() {
return handleApi(async () => {
const { user } = await requireUser();
const memories = await listMemories(user.id, { enabled: true });
const verified = memories.filter((m) => m.userVerified);
const bulletList = verified
.map((m) => `- [${m.category}] ${m.title}: ${m.content.slice(0, 120)}`)
.join("\n");
const behavior = await getAiBehaviorConfig(user.id);
const providerConfig = await getAiProviderConfig(user.id);
let summaryText = verified.length === 0
? "No verified memories yet. Add memories manually to build your profile."
: bulletList.slice(0, 1500);
if (behavior.enabled && providerConfig.enabled && verified.length > 0) {
try {
const coreSystem = await getTemplateBody(user.id, "system_core");
const templateBody = await getTemplateBody(user.id, "mentor_summary");
const system = buildSystemPrompt(behavior, coreSystem);
const prompt = renderTemplate(templateBody, {
user_name: user.displayName,
context: bulletList,
});
const provider = getProvider(providerConfig.type);
const res = await provider.generateText(providerConfig, {
model: providerConfig.model,
prompt,
system,
format: "text",
temperature: 0.5,
maxTokens: 400,
timeoutMs: providerConfig.timeoutMs,
});
if (res.text.trim()) summaryText = res.text.trim();
} catch {
/* use bullet list fallback */
}
}
const summary = await saveProfileSummary(user.id, summaryText);
return { ...summary, sourceMemoryCount: verified.length };
});
}

View File

@@ -0,0 +1,34 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import {
getProfileSummary,
saveProfileSummary,
exportMemories,
importMemories,
} from "@/lib/services/ai-memory";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
return getProfileSummary(user.id);
});
}
export async function PATCH(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
return saveProfileSummary(user.id, body.summary ?? "");
});
}
export async function POST(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
if (body.action === "import") {
return importMemories(user.id, body.data, body.overwrite);
}
return exportMemories(user.id);
});
}

View File

@@ -0,0 +1,23 @@
import { handleApi } from "@/lib/api";
import { listProviderTypes } from "@/lib/ai/provider-registry";
import { requireUser } from "@/lib/services/user";
import { getAiProviderConfig } from "@/lib/services/ai-config";
import { getProvider } from "@/lib/ai/provider-registry";
export async function GET() {
return handleApi(async () => {
const providers = listProviderTypes();
return { providers };
});
}
export async function POST() {
return handleApi(async () => {
const { user } = await requireUser();
const config = await getAiProviderConfig(user.id);
const provider = getProvider(config.type);
if (!provider.listModels) return { models: [config.model] };
const models = await provider.listModels(config);
return { models };
});
}

View File

@@ -0,0 +1,15 @@
import { handleApi } from "@/lib/api";
import { dismissSuggestion } from "@/lib/services/explorations";
import { requireUser } from "@/lib/services/user";
export async function POST(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return handleApi(async () => {
const { user } = await requireUser();
await dismissSuggestion(id, user.id);
return { ok: true };
});
}

View File

@@ -0,0 +1,26 @@
import { handleApi, jsonError } from "@/lib/api";
import { getSuggestions, dismissSuggestion, generateDailyQuests } from "@/lib/services/explorations";
import { requireUser } from "@/lib/services/user";
import { isOllamaAvailable } from "@/lib/services/ai";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const role = searchParams.get("role") ?? undefined;
return handleApi(async () => {
const { user } = await requireUser();
const suggestions = await getSuggestions(user.id, role);
const ollamaAvailable = await isOllamaAvailable();
return { suggestions, ollamaAvailable };
});
}
export async function POST(request: Request) {
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
if (body.action === "generate_quests") {
return generateDailyQuests(user.id);
}
throw new Error("Unknown action");
});
}

View File

@@ -0,0 +1,64 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import {
getPromptTemplate,
updatePromptTemplate,
resetPromptTemplate,
previewTemplate,
getTemplateVersions,
restoreTemplateVersion,
} from "@/lib/services/ai-templates";
export async function GET(
_request: Request,
{ params }: { params: Promise<{ key: string }> }
) {
const { key } = await params;
return handleApi(async () => {
const { user } = await requireUser();
const template = await getPromptTemplate(user.id, key);
const versions = await getTemplateVersions(user.id, key);
return { template, versions };
});
}
export async function PATCH(
request: Request,
{ params }: { params: Promise<{ key: string }> }
) {
const { key } = await params;
const body = await request.json();
return handleApi(async () => {
const { user } = await requireUser();
const template = await updatePromptTemplate(user.id, key, body);
return { template };
});
}
export async function POST(
request: Request,
{ params }: { params: Promise<{ key: string }> }
) {
const { key } = await params;
const { searchParams } = new URL(request.url);
const action = searchParams.get("action");
const body = await request.json().catch(() => ({}));
return handleApi(async () => {
const { user } = await requireUser();
if (action === "reset") {
const template = await resetPromptTemplate(user.id, key);
return { template };
}
if (action === "preview") {
const rendered = await previewTemplate(user.id, key, body.body);
return { rendered };
}
if (action === "restore" && body.version) {
const template = await restoreTemplateVersion(user.id, key, body.version);
return { template };
}
throw new Error("Unknown action");
});
}

View File

@@ -0,0 +1,12 @@
import { handleApi } from "@/lib/api";
import { requireUser } from "@/lib/services/user";
import { getPromptTemplates } from "@/lib/services/ai-templates";
import { PLACEHOLDER_DOCS } from "@/lib/ai/prompts/defaults";
export async function GET() {
return handleApi(async () => {
const { user } = await requireUser();
const templates = await getPromptTemplates(user.id);
return { templates, placeholders: PLACEHOLDER_DOCS };
});
}