A stateless safety monitor on a factory floor is bit more than an expensive alarm bell. When an AI flags an unfastened harness or an unblocked machinery zone, dispatches a notification, and immediately wipes its context window, it hasn't actually solved physical plant safety. When a repeat infraction occurs hours later in the same sector, the system treats it as an isolated anomaly. It cannot identify that a specific loading bay or warehouse aisle has suffered chronic violations across shift rotations.
When designing the Workplace Safety Sentinel dashboard and agent backend, our goal was to move beyond reactive incident recording toward an autonomous supervisor that understands temporal risk patterns. Here is how we structured persistent memory, how we bridged the gap inside Next.js route handlers, and why dedicated memory is essential for operational incident monitoring.
The Architectural Hurdle: Stateless Dashboards vs. Shift Memory
In standard web architectures, incident management dashboards pull raw relational rows (timestamps, severity labels, zone categories, resolved flags) from database backends. When managers open an analytics view or trigger an automated inspection summary, common systems run standard aggregation queries or push a raw slice of records into an LLM prompt.
This pattern breaks down quickly in multi-shift manufacturing environments:
- Context Window Inflation: Appending dozens of raw JSON incident logs into every shift briefing prompt explodes API latency and token consumption.
- Loss of Temporal Nuance: Passing flat relational rows to an LLM makes it difficult for the model to distinguish between routine, isolated slip alerts and systemic protocol drift occurring over multiple weeks.
- Session Amnesia: Once a supervisor signs off and the next shift begins, conversational context is reset.
We needed a dedicated persistence layer designed specifically for agent recall. Rather than building custom vector ingestion pipelines or semantic cache layers from scratch, we integrated the Hindsight engine. Understanding what is agent memory in this context means treating safety logs not just as inert records, but as indexed operational memories that an agent can retain and recall based on semantic relevance.
Implementation: Integrating Retain and Recall into Next.js
Our project architecture separates real-time dashboard state from agent intelligence:
-
Client Dashboard: Built with Next.js App Router, React hooks (
useIncidents), and UI components (IncidentsTable,Breakdown,SummaryPanel). - Data & Auth Layer: Supabase client and server utilities for base record persistence.
-
Agent Intelligence Layer: Server-side API route handlers (
app/api/summary/route.ts) orchestrating memory recall and contextual safety analysis.
1. Retaining Incident Semantics
When a PPE or new hazard breach is verified on the floor, the incident record is persisted alongside an explicit memory entry in Hindsight:
typescript
// lib/incidents.ts
export interface SafetyIncident {
id: string;
timestamp: string;
zone: string;
violationType: string;
severity: "low" | "medium" | "high" | "critical";
description: string;
}
export async function retainIncidentMemory(incident: SafetyIncident) {
const response = await fetch("[https://api.hindsight.vectorize.io/v1/retain](https://api.hindsight.vectorize.io/v1/retain)", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.HINDSIGHT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
workspace: "workplace-safety-sentinel",
content: `Incident [${incident.severity.toUpperCase()}]: ${incident.violationType} in ${incident.zone}. Details: ${incident.description}`,
metadata: {
incidentId: incident.id,
zone: incident.zone,
severity: incident.severity,
timestamp: incident.timestamp,
},
}),
});
if (!response.ok) {
throw new Error(`Failed to retain memory: ${response.statusText}`);
}
return response.json();
}
// app/api/summary/route.ts
import { NextResponse } from "next/server";
export async function POST(req: Request) {
try {
const { zone, shiftName } = await req.json();
// Query Hindsight for semantic memory recall regarding repeat incidents
const memoryResponse = await fetch("[https://api.hindsight.vectorize.io/v1/recall](https://api.hindsight.vectorize.io/v1/recall)", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.HINDSIGHT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
workspace: "workplace-safety-sentinel",
query: `Recurring safety violations, high severity incidents, and protocol breaches in ${zone}`,
limit: 5,
threshold: 0.7,
}),
});
const memoryData = await memoryResponse.json();
const relevantMemories = memoryData.results || [];
// Construct grounded brief for the shift supervisor
const briefingNotes = relevantMemories.length > 0
? relevantMemories.map((m: any) => `- ${m.content}`).join("\n")
: "No chronic safety hazards recalled for this sector.";
return NextResponse.json({
shift: shiftName,
targetZone: zone,
recalledIncidentsCount: relevantMemories.length,
briefingNotes,
generatedAt: new Date().toISOString(),
});
} catch (error) {
return NextResponse.json({ error: "Failed to compile summary" }, { status: 500 });
}
}
Top comments (0)