Files
podman/backend/src/live-conversation/context.ts
T
Yahya Alhinai 454fdab13b chore(box): snapshot in-progress auth + user-learning WIP before deploy
Captures uncommitted work present on the live droplet so origin/main can be integrated and the new control toolbar deployed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 17:51:21 +00:00

96 lines
2.8 KiB
TypeScript

import { getDb } from '../memory/db.js';
import { getMemberWorkHistory } from '../activity/member-history.js';
import {
buildUserLearningProfile,
getUserLearningProfileByIdentity,
} from '../memory/user-learning.js';
const DEFAULT_LIMIT = 8;
function sinceIso(hours: number): string {
return new Date(Date.now() - hours * 60 * 60 * 1000).toISOString();
}
export async function getLiveConversationContext(podId: string, identity: string) {
const db = await getDb();
const since = sinceIso(12);
const [pod, history, gitState, collisions, interventions, outcomes, userLearningProfile] =
await Promise.all([
db.collection('pods').findOne({ id: podId }, { projection: { _id: 0 } }),
getMemberWorkHistory(podId, identity, { hours: 24, limit: 30 }).catch(() => null),
db.collection('engineer_states').findOne(
{ podId, name: identity },
{
projection: {
_id: 0,
name: 1,
branch: 1,
changedFiles: 1,
recentCommit: 1,
gitUpdatedAt: 1,
},
},
),
db
.collection('collisions')
.find({ podId, detectedAt: { $gte: since } }, { projection: { _id: 0, embedding: 0 } })
.sort({ detectedAt: -1 })
.limit(DEFAULT_LIMIT)
.toArray(),
db
.collection('interventions')
.find({ podId, createdAt: { $gte: since } }, { projection: { _id: 0 } })
.sort({ createdAt: -1 })
.limit(DEFAULT_LIMIT)
.toArray(),
db
.collection('outcomes')
.find({ podId, recordedAt: { $gte: since } }, { projection: { _id: 0 } })
.sort({ recordedAt: -1 })
.limit(DEFAULT_LIMIT)
.toArray(),
getUserLearningProfileByIdentity(identity).catch(() => null),
]);
return {
pod,
identity,
generatedAt: new Date().toISOString(),
currentGitState: gitState,
userLearningProfile,
memberHistory: history,
recentCollisions: collisions,
recentInterventions: interventions,
recentOutcomes: outcomes,
};
}
export async function recordLiveConversationNote(input: {
podId: string;
sessionId: string;
identity?: string;
note: string;
kind?: string;
}) {
const note = input.note.trim();
if (!note) throw new Error('note is required');
const doc = {
podId: input.podId,
sessionId: input.sessionId,
identity: input.identity,
kind: input.kind || 'summary',
note: note.slice(0, 4000),
createdAt: new Date().toISOString(),
};
await (await getDb()).collection('conversation_notes').insertOne(doc);
if (input.identity) {
const profile = await getUserLearningProfileByIdentity(input.identity);
if (profile) {
void buildUserLearningProfile(profile.clerkUserId).catch((err) =>
console.warn(`[memory] note user learning refresh failed: ${(err as Error).message}`),
);
}
}
return { ...doc, _id: undefined };
}