5809ad3adb
Shared runtime - One agent entry point (runtime.invoke_agent_for_user / prepare_agent_turn) for web, email, iMessage, WhatsApp, scheduled and cron, so identity, permissions, memories, summaries and metrics match across channels. - Serialize turns per checkpoint thread; /query validates input and returns 409 while a durable run owns the conversation. Reconnectable chat (durable runs) - POST /runs creates an idempotent, owner-scoped run; GET .../events replays an ordered SSE log by cursor, so generation survives refresh and device switches. Stop cancels; disconnect only detaches. /stream-query is a compatibility adapter. - Coalesce streamed deltas (150 ms) and wake same-process subscribers instead of polling; keep buffered text when a run is stopped. - Drain runs on shutdown; serve via Hypercorn with a shutdown timeout covering the drain (and no longer in debug mode). CHAT_RUN_* settings are forwarded. Scheduled messages and cron - Atomic delivery claims, attempt history and explicit retries; ambiguous sends become "uncertain" and are never resent automatically. - Cron triggers need a run_id/Idempotency-Key; legacy jobs need an explicit owner. - Cancelling never rewrites a started delivery; series stop via tombstones. Legacy sent rows are not forked into new series. Malformed bodies return 400. History, integrations and retrieval - Message-content search, pinned conversations, JSON/Markdown export and a memory editor. - Integration status panel and YNAB data-freshness provenance. - Date-filtered document/note search with stable citations and a source viewer. Migration 20 is generated by aerich. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import { Route, Routes } from "react-router-dom";
|
|
import "./App.css";
|
|
import { AuthProvider } from "./contexts/AuthContext";
|
|
import { ChatScreen } from "./components/ChatScreen";
|
|
import { ConversationsPage } from "./components/ConversationsPage";
|
|
import { LoginScreen } from "./components/LoginScreen";
|
|
import { SourceViewer } from "./components/SourceViewer";
|
|
import { useAuthCheck } from "./hooks/useAuthCheck";
|
|
import catIcon from "./assets/cat.png";
|
|
|
|
const AppContainer = () => {
|
|
const { isAuthenticated, isChecking, isAdmin, setAuthenticated } = useAuthCheck();
|
|
|
|
if (isChecking) {
|
|
return (
|
|
<div className="h-screen flex flex-col items-center justify-center bg-cream gap-4">
|
|
<img
|
|
src={catIcon}
|
|
alt="Simba"
|
|
className="w-16 h-16 animate-bounce"
|
|
/>
|
|
<p className="text-warm-gray font-medium text-lg tracking-wide">
|
|
waking up simba...
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!isAuthenticated) {
|
|
return <LoginScreen setAuthenticated={setAuthenticated} />;
|
|
}
|
|
|
|
return (
|
|
<Routes>
|
|
<Route path="/conversations" element={<ConversationsPage />} />
|
|
<Route path="/sources/:sourceId" element={<SourceViewer />} />
|
|
{/* One ChatScreen instance serves both the home ("/") and per-conversation
|
|
("/c/:id") routes. Using a single catch-all route keeps that instance
|
|
mounted across the navigate() that fires when the first message creates
|
|
a conversation — a remount here would abort the in-flight SSE stream
|
|
(and drop the answer before it's persisted). */}
|
|
<Route
|
|
path="*"
|
|
element={<ChatScreen setAuthenticated={setAuthenticated} isAdmin={isAdmin} />}
|
|
/>
|
|
</Routes>
|
|
);
|
|
};
|
|
|
|
const App = () => {
|
|
return (
|
|
<AuthProvider>
|
|
<AppContainer />
|
|
</AuthProvider>
|
|
);
|
|
};
|
|
|
|
export default App;
|