Warning: session_start(): Session cannot be started after headers have already been sent in /home/tvrreohg/public_html/manga.php on line 13
ensureAccess($request, $caseRecord);
$session = $this->sessionFor($request, $caseRecord);
$caseRecord->load(['documents', 'generatedPackets' => fn ($query) => $query->latest()]);
$session->load(['messages' => fn ($query) => $query->oldest()]);
return view('cases.assistant', compact('caseRecord', 'session'));
}
public function accept(Request $request, CaseRecord $caseRecord)
{
$this->ensureAccess($request, $caseRecord);
$session = $this->sessionFor($request, $caseRecord);
$session->update(['disclaimer_accepted_at' => now()]);
if ($session->messages()->doesntExist()) {
$session->messages()->create([
'role' => 'assistant',
'content' => "Welcome to the CaseReady Assistant. Let’s slow things down and organize this clearly.\n\nTo begin: what happened, what outcome are you hoping for, and what is your biggest concern right now?\n\n".CaseReadyAssistantService::DISCLAIMER,
]);
}
return redirect()->route('cases.assistant.show', $caseRecord)->with('success', 'CaseReady preparation disclaimer accepted.');
}
public function message(Request $request, CaseRecord $caseRecord, CaseReadyAssistantService $assistant)
{
$this->ensureAccess($request, $caseRecord);
$data = $request->validate([
'message' => ['required', 'string', 'max:12000'],
]);
$session = $this->sessionFor($request, $caseRecord);
if (! $session->disclaimer_accepted_at) {
return back()->withErrors(['assistant' => 'Please accept the CaseReady preparation disclaimer before using the assistant.']);
}
$session->messages()->create([
'user_id' => $request->user()->id,
'role' => 'user',
'content' => $data['message'],
]);
try {
$result = $assistant->reply($caseRecord, $session, $data['message']);
} catch (RuntimeException $exception) {
return back()->withErrors(['assistant' => $exception->getMessage()]);
}
$session->messages()->create([
'role' => 'assistant',
'content' => $result['content'],
'metadata' => [
'model' => $result['model'] ?? null,
'input_tokens' => $result['input_tokens'] ?? null,
'output_tokens' => $result['output_tokens'] ?? null,
],
]);
$session->update(['phase' => $this->guessPhase($result['content'])]);
return redirect()->route('cases.assistant.show', $caseRecord)->with('success', 'CaseReady Assistant replied.');
}
private function sessionFor(Request $request, CaseRecord $caseRecord): AssistantSession
{
return AssistantSession::firstOrCreate(
['case_record_id' => $caseRecord->id, 'user_id' => $request->user()->id, 'status' => 'active'],
['title' => 'CaseReady preparation chat', 'phase' => 'understand']
);
}
private function ensureAccess(Request $request, CaseRecord $caseRecord): void
{
abort_unless($request->user()->isAdmin() || $caseRecord->user_id === $request->user()->id, 403);
}
private function guessPhase(string $content): string
{
$lower = str($content)->lower();
return match (true) {
$lower->contains(['checklist', 'questions to ask', 'packet']) => 'prepare',
$lower->contains(['missing', 'document', 'unclear']) => 'organize',
default => 'understand',
};
}
}