From a286b9cdcec8b091129cc582384d2b0ab3242abd Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 5 May 2026 15:18:48 +1000 Subject: [PATCH] aifirst: lift context/agents/tools runtime to lib-aifirst-ui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mechanism (context surface registry, persona storage + hooks, tool parser/dispatcher) is now generic and lives in @crema/aifirst-ui/{context, agents,tools}. This template keeps only the arcadia-shaped configuration: - agents.ts — owns DEFAULT_AGENTS + legacy/retired migration sets, calls configureAgents() at module load, re-exports the runtime - admin-tools.ts — keeps the 19 arcadia tool definitions, binds the runtime via createToolRuntime(TOOLS), re-exports the bound functions - admin-context.ts — deleted; 18 routes now import directly from @crema/aifirst-ui/context Routes that import from ~/lib/agents and ~/lib/admin-tools are unchanged (wrapper modules preserve the existing import surface). Co-Authored-By: Claude Opus 4.7 (1M context) --- app/lib/admin-context.ts | 76 ----------------- app/lib/admin-tools.ts | 147 ++++---------------------------- app/lib/agents.ts | 148 +++++---------------------------- app/routes/activity.tsx | 4 +- app/routes/ai.tsx | 4 +- app/routes/announcements.tsx | 4 +- app/routes/assistant.tsx | 4 +- app/routes/buckets.tsx | 4 +- app/routes/home.tsx | 4 +- app/routes/memberships.tsx | 4 +- app/routes/monitoring.tsx | 4 +- app/routes/networking.tsx | 4 +- app/routes/scheduled-tasks.tsx | 4 +- app/routes/search.tsx | 4 +- app/routes/secrets.tsx | 4 +- app/routes/sso.tsx | 4 +- app/routes/status-page.tsx | 4 +- app/routes/storage.tsx | 4 +- app/routes/tenants.tsx | 4 +- app/routes/users.tsx | 4 +- app/routes/webhooks.tsx | 4 +- 21 files changed, 73 insertions(+), 370 deletions(-) delete mode 100644 app/lib/admin-context.ts diff --git a/app/lib/admin-context.ts b/app/lib/admin-context.ts deleted file mode 100644 index 6489cba..0000000 --- a/app/lib/admin-context.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Shared state surface that any admin page can publish to so the assistant -// can read live data without scraping the DOM. -// -// Pages call `useRegisterAdminContext("tenants", { tenants: [...] })` while -// mounted; the assistant calls `getAdminContextSnapshot()` each turn to -// inject a structured snapshot into the system prompt. - -import { useEffect } from "react" - -type Surface = Record - -export type AdminContextSnapshot = { - route: string - surfaces: Record -} - -const surfaces = new Map() - -export function publishAdminSurface(name: string, data: Surface): void { - surfaces.set(name, data) - if (typeof window !== "undefined") { - ;(window as unknown as { __adminContext?: unknown }).__adminContext = getAdminContextSnapshot() - } -} - -export function clearAdminSurface(name: string): void { - surfaces.delete(name) - if (typeof window !== "undefined") { - ;(window as unknown as { __adminContext?: unknown }).__adminContext = getAdminContextSnapshot() - } -} - -export function getAdminContextSnapshot(): AdminContextSnapshot { - const route = typeof window !== "undefined" ? window.location.pathname : "" - return { - route, - surfaces: Object.fromEntries(surfaces.entries()), - } -} - -/** - * Render a snapshot as a markdown block for the LLM system prompt. - * Keeps it compact: route, then one section per surface with JSON. - */ -export function formatAdminContextForPrompt(snapshot = getAdminContextSnapshot()): string { - const sections: string[] = [`Admin context (read-only — for answering factual questions):`] - sections.push(`Route: ${snapshot.route || "?"}`) - const names = Object.keys(snapshot.surfaces) - if (names.length === 0) { - sections.push(`Surfaces: (none registered)`) - } else { - for (const name of names) { - const json = safeJson(snapshot.surfaces[name]) - sections.push(`Surface "${name}":\n${json}`) - } - } - return sections.join("\n\n") -} - -function safeJson(value: unknown): string { - try { - const text = JSON.stringify(value, null, 2) - if (text.length > 4000) return text.slice(0, 4000) + "\n…(truncated)" - return text - } catch { - return "(unserializable)" - } -} - -/** Hook: publish a surface while the component is mounted. */ -export function useRegisterAdminContext(name: string, data: Surface): void { - useEffect(() => { - publishAdminSurface(name, data) - return () => clearAdminSurface(name) - }, [name, data]) -} diff --git a/app/lib/admin-tools.ts b/app/lib/admin-tools.ts index f31a229..98f87bf 100644 --- a/app/lib/admin-tools.ts +++ b/app/lib/admin-tools.ts @@ -6,7 +6,10 @@ // raw HTTP — only the menu below. import type { ArcadiaClient } from "@crema/arcadia-client" -import type { Tool, ToolCall as LLMToolCall } from "@crema/llm-ui" +import { + createToolRuntime, + type ToolDef, +} from "@crema/aifirst-ui/tools" import { activateTenant, @@ -163,30 +166,9 @@ async function kbRead(chunkId: string, corpus: string): Promise { return await res.json() } -export type ToolCall = { - name: string - args: Record -} - -export type ToolResult = { - name: string - args: Record - ok: boolean - data?: unknown - error?: string -} - -type ToolDef = { - name: string - description: string - parameters: Record // JSON Schema for OpenAI tool calling - isWrite: boolean - run: (args: Record, ctx: ToolCtx) => Promise -} - type ToolCtx = { arcadia: ArcadiaClient } -const TOOLS: ToolDef[] = [ +const TOOLS: ToolDef[] = [ { name: "list_tenants", description: @@ -927,58 +909,6 @@ interface UserEntry { roles?: { slug?: string; name?: string }[] } -/** OpenAI-format tool list to pass into ChatRequest.tools. */ -export function getOpenAITools(): Tool[] { - return TOOLS.map((t) => ({ - name: t.name, - description: t.description, - parameters: t.parameters, - })) -} - -/** Split an LLM tool-call list into reads (run automatically) and writes - * (held for user confirmation). Unknown tools fall into reads so the runner - * can surface a structured "unknown tool" error to the model. */ -export function classifyCalls(calls: LLMToolCall[]): { - reads: LLMToolCall[] - writes: LLMToolCall[] -} { - const reads: LLMToolCall[] = [] - const writes: LLMToolCall[] = [] - for (const c of calls) { - const def = TOOL_BY_NAME.get(c.name) - if (def?.isWrite) writes.push(c) - else reads.push(c) - } - return { reads, writes } -} - -/** Synthesise tool-result messages saying the user denied a write call. */ -export function buildDenialMessages( - calls: LLMToolCall[], -): { role: "tool"; content: string; toolCallId: string; name: string }[] { - return calls.map((c) => ({ - role: "tool", - content: JSON.stringify({ - error: "User denied this write. Do not retry without re-asking the user.", - }), - toolCallId: c.id, - name: c.name, - })) -} - -/** Pretty-print args for the confirm UI. */ -export function formatToolCallArgs(c: LLMToolCall): string { - try { - const parsed = c.arguments ? JSON.parse(c.arguments) : {} - const keys = Object.keys(parsed) - if (keys.length === 0) return "" - return keys.map((k) => `${k}=${JSON.stringify(parsed[k])}`).join(", ") - } catch { - return c.arguments - } -} - function summarize(t: Tenant) { return { id: t.id, @@ -990,62 +920,15 @@ function summarize(t: Tenant) { } } -const TOOL_BY_NAME = new Map(TOOLS.map((t) => [t.name, t])) +const runtime = createToolRuntime(TOOLS) -function safeJson(value: unknown): string { - try { - const text = JSON.stringify(value, null, 2) - if (text.length > 6000) return text.slice(0, 6000) + "\n…(truncated)" - return text - } catch { - return "(unserializable)" - } -} +export const getOpenAITools = runtime.getOpenAITools +export const classifyCalls = runtime.classifyCalls +export const runLLMToolCalls = runtime.runLLMToolCalls -/** Run a list of provider-native tool calls and return `tool` role messages - * ready to push back into useChat history. */ -export async function runLLMToolCalls( - calls: LLMToolCall[], - ctx: ToolCtx, - opts: { allowWrites?: boolean } = {}, -): Promise<{ - results: ToolResult[] - toolMessages: { role: "tool"; content: string; toolCallId: string; name: string }[] -}> { - const results: ToolResult[] = [] - const toolMessages: { role: "tool"; content: string; toolCallId: string; name: string }[] = [] - for (const call of calls) { - const def = TOOL_BY_NAME.get(call.name) - let parsed: Record = {} - try { - parsed = call.arguments ? (JSON.parse(call.arguments) as Record) : {} - } catch { - const err = `Could not parse arguments JSON: ${call.arguments}` - results.push({ name: call.name, args: {}, ok: false, error: err }) - toolMessages.push({ role: "tool", content: JSON.stringify({ error: err }), toolCallId: call.id, name: call.name }) - continue - } - if (!def) { - const err = `Unknown tool: ${call.name}` - results.push({ name: call.name, args: parsed, ok: false, error: err }) - toolMessages.push({ role: "tool", content: JSON.stringify({ error: err }), toolCallId: call.id, name: call.name }) - continue - } - if (def.isWrite && !opts.allowWrites) { - const err = "Write tools require user confirmation." - results.push({ name: call.name, args: parsed, ok: false, error: err }) - toolMessages.push({ role: "tool", content: JSON.stringify({ error: err }), toolCallId: call.id, name: call.name }) - continue - } - try { - const data = await def.run(parsed, ctx) - results.push({ name: call.name, args: parsed, ok: true, data }) - toolMessages.push({ role: "tool", content: safeJson(data), toolCallId: call.id, name: call.name }) - } catch (err) { - const msg = err instanceof Error ? err.message : String(err) - results.push({ name: call.name, args: parsed, ok: false, error: msg }) - toolMessages.push({ role: "tool", content: JSON.stringify({ error: msg }), toolCallId: call.id, name: call.name }) - } - } - return { results, toolMessages } -} +export { + buildDenialMessages, + formatToolCallArgs, + type ToolCall, + type ToolResult, +} from "@crema/aifirst-ui/tools" diff --git a/app/lib/agents.ts b/app/lib/agents.ts index 6430347..f0f0c27 100644 --- a/app/lib/agents.ts +++ b/app/lib/agents.ts @@ -1,15 +1,9 @@ -// Agent personas — named, role-scoped sub-system prompts. -// Each persona stacks on top of the main systemPrompt to specialize the -// assistant for a task. Persisted in localStorage; reactive across tabs. +// Arcadia Admin's agent roster + migration config. +// The persona machinery lives in @crema/aifirst-ui/agents — this file +// just owns the *which personas* config and re-exports the runtime so +// route code keeps importing from "~/lib/agents". -import { useEffect, useSyncExternalStore } from "react" - -export type Agent = { - id: string - name: string - role: string - prompt: string -} +import { configureAgents, type Agent } from "@crema/aifirst-ui/agents" export const DEFAULT_AGENTS: Agent[] = [ { @@ -49,21 +43,6 @@ export const DEFAULT_AGENTS: Agent[] = [ }, ] -const STORAGE_KEY = "crema.agents" -const ACTIVE_KEY = "crema.assistant.activeAgent" -const CHANGE_EVENT = "crema:agents-change" - -function isAgent(v: unknown): v is Agent { - return ( - !!v && - typeof v === "object" && - typeof (v as Agent).id === "string" && - typeof (v as Agent).name === "string" && - typeof (v as Agent).role === "string" && - typeof (v as Agent).prompt === "string" - ) -} - // Old Vibespace agent ids — used to auto-migrate operators stuck on the // generic defaults from before Arcadia Admin had its own personas. const LEGACY_AGENT_IDS = new Set(["generalist", "coder", "writer", "researcher"]) @@ -73,104 +52,21 @@ const LEGACY_AGENT_IDS = new Set(["generalist", "coder", "writer", "researcher"] // so a rename in DEFAULT_AGENTS actually reaches the UI. const RETIRED_AGENT_NAMES = new Set(["Ledger", "Beacon", "Tally", "Cursor"]) -function isLegacyDefaultSet(agents: Agent[]): boolean { - return ( - agents.some((a) => LEGACY_AGENT_IDS.has(a.id)) || - agents.some((a) => RETIRED_AGENT_NAMES.has(a.name)) - ) -} +configureAgents({ + defaults: DEFAULT_AGENTS, + shouldReseed: (stored) => + stored.some((a) => LEGACY_AGENT_IDS.has(a.id)) || + stored.some((a) => RETIRED_AGENT_NAMES.has(a.name)), +}) -function readFromStorage(): Agent[] { - if (typeof window === "undefined") return DEFAULT_AGENTS - try { - const raw = localStorage.getItem(STORAGE_KEY) - if (!raw) return DEFAULT_AGENTS - const parsed = JSON.parse(raw) - if (!Array.isArray(parsed)) return DEFAULT_AGENTS - const cleaned = parsed.filter(isAgent) - if (cleaned.length === 0) return DEFAULT_AGENTS - if (isLegacyDefaultSet(cleaned)) { - // Auto-migrate: stored set still contains pre-arcadia personas. - localStorage.setItem(STORAGE_KEY, JSON.stringify(DEFAULT_AGENTS)) - localStorage.removeItem(ACTIVE_KEY) - return DEFAULT_AGENTS - } - return cleaned - } catch { - return DEFAULT_AGENTS - } -} - -export function loadAgents(): Agent[] { - return readFromStorage() -} - -export function saveAgents(next: Agent[]) { - if (typeof window === "undefined") return - localStorage.setItem(STORAGE_KEY, JSON.stringify(next)) - window.dispatchEvent(new CustomEvent(CHANGE_EVENT)) -} - -export function resetAgents() { - saveAgents(DEFAULT_AGENTS) -} - -let cached: Agent[] | null = null - -function subscribe(cb: () => void): () => void { - const onChange = () => { - cached = null - cb() - } - window.addEventListener(CHANGE_EVENT, onChange) - window.addEventListener("storage", (e) => { - if (e.key === STORAGE_KEY || e.key === ACTIVE_KEY) onChange() - }) - return () => { - window.removeEventListener(CHANGE_EVENT, onChange) - } -} - -function getSnapshot(): Agent[] { - if (!cached) cached = readFromStorage() - return cached -} - -function getServerSnapshot(): Agent[] { - return DEFAULT_AGENTS -} - -export function useAgents(): Agent[] { - const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) - useEffect(() => { - cached = null - }, []) - return value -} - -export function loadActiveAgentId(): string { - if (typeof window === "undefined") return DEFAULT_AGENTS[0].id - try { - return localStorage.getItem(ACTIVE_KEY) ?? DEFAULT_AGENTS[0].id - } catch { - return DEFAULT_AGENTS[0].id - } -} - -export function saveActiveAgentId(id: string) { - if (typeof window === "undefined") return - localStorage.setItem(ACTIVE_KEY, id) - window.dispatchEvent(new CustomEvent(CHANGE_EVENT)) -} - -export function composeSystemPrompt( - base: string, - agent: Agent | undefined, -): string { - if (!agent) return base - return `${base}\n\nActive persona: ${agent.name} — ${agent.role}\n${agent.prompt}` -} - -export function newAgentId(): string { - return `agent-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}` -} +export { + composeSystemPrompt, + loadActiveAgentId, + loadAgents, + newAgentId, + resetAgents, + saveActiveAgentId, + saveAgents, + useAgents, + type Agent, +} from "@crema/aifirst-ui/agents" diff --git a/app/routes/activity.tsx b/app/routes/activity.tsx index 9b603ae..e2234c8 100644 --- a/app/routes/activity.tsx +++ b/app/routes/activity.tsx @@ -47,7 +47,7 @@ import { } from "~/lib/arcadia/audit-logs" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Audit log") @@ -187,7 +187,7 @@ export default function ActivityRoute() { }), [logs], ) - useRegisterAdminContext("audit_log", summary) + useRegisterContext("audit_log", summary) const table = useTable({ data: logs, diff --git a/app/routes/ai.tsx b/app/routes/ai.tsx index eeda1ef..a2a747e 100644 --- a/app/routes/ai.tsx +++ b/app/routes/ai.tsx @@ -101,7 +101,7 @@ import { subscribeActiveReasoning, type ReasoningEffort, } from "~/lib/arcadia/llm-configs" -import { formatAdminContextForPrompt } from "~/lib/admin-context" +import { formatContextForPrompt } from "@crema/aifirst-ui/context" import { ConfirmCard } from "~/components/assistant/confirm-card" import { renderToolResult } from "~/components/assistant/tool-result-renderers" @@ -722,7 +722,7 @@ function ChatSurface({ ARCADIA_KNOWLEDGE, persona, handoffNote, - formatAdminContextForPrompt(), + formatContextForPrompt(), ] .filter(Boolean) .join("\n\n") diff --git a/app/routes/announcements.tsx b/app/routes/announcements.tsx index 6e4366e..3ea8235 100644 --- a/app/routes/announcements.tsx +++ b/app/routes/announcements.tsx @@ -63,7 +63,7 @@ import { import { listTenants, type Tenant } from "~/lib/arcadia/tenants" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Announcements") @@ -218,7 +218,7 @@ export default function AnnouncementsRoute() { }), [items], ) - useRegisterAdminContext("announcements", summary) + useRegisterContext("announcements", summary) const table = useTable({ data: items, diff --git a/app/routes/assistant.tsx b/app/routes/assistant.tsx index 9d2ef4f..05c6510 100644 --- a/app/routes/assistant.tsx +++ b/app/routes/assistant.tsx @@ -90,7 +90,7 @@ wait_for assistant-ui-control \`\`\`"` -import { formatAdminContextForPrompt } from "~/lib/admin-context" +import { formatContextForPrompt } from "@crema/aifirst-ui/context" import { buildDenialMessages, classifyCalls, @@ -111,7 +111,7 @@ function buildAdminPreface(activeAgent: Agent | undefined, uiControl: boolean): const persona = activeAgent ? `Active persona: ${activeAgent.name} — ${activeAgent.role}\n${activeAgent.prompt}` : "" - const ctx = formatAdminContextForPrompt() + const ctx = formatContextForPrompt() const parts = [ "You are the operator's assistant inside Arcadia Admin. Be precise and direct. You have native function tools attached to this conversation — call them whenever the user asks about live platform state (counts, statuses, listings, lookups). Never invent tenant slugs, user counts, or statuses; if you need data, call a tool.", "Two retrieval surfaces exist for documentation/knowledge: `search_docs` (browser-side, BM25 over the bundled arcadia docs — fast, always available, small corpus) and `search_kb` (server-side, BM25 over arcadia-search — `docs` (arcadia parity), `operator-tools` (arcadia-search + arcadia-admin admin docs), `files` (uploaded files), plus any custom corpora the operator adds via /search). For questions about the bundled arcadia docs either is fine; prefer `search_kb` for richer hits or for content outside the bundled docs (uploaded files, the admin tooling itself, tenant-specific knowledge). If unsure what corpora exist, call `list_search_corpora`. When `search_kb` returns a chunk_id you want to expand, call `read_chunk(chunk_id, corpus)`. When the operator says results look stale or after they've uploaded new files, call `rebuild_search_corpus(tenant, corpus)`.", diff --git a/app/routes/buckets.tsx b/app/routes/buckets.tsx index 3e4ff2a..cfe4ff2 100644 --- a/app/routes/buckets.tsx +++ b/app/routes/buckets.tsx @@ -84,7 +84,7 @@ import { } from "~/lib/arcadia/storage-configs" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Buckets") @@ -194,7 +194,7 @@ export default function BucketsRoute() { }), [activeConfig, buckets], ) - useRegisterAdminContext("buckets", summary) + useRegisterContext("buckets", summary) return ( diff --git a/app/routes/home.tsx b/app/routes/home.tsx index 27db105..3d144aa 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -35,7 +35,7 @@ import { } from "~/lib/arcadia/health" import { listTenants, type Tenant } from "~/lib/arcadia/tenants" import { listUsers, type User } from "~/lib/arcadia/users" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" @@ -96,7 +96,7 @@ export default function HomeRoute() { } }, [data]) - useRegisterAdminContext("overview", stats) + useRegisterContext("overview", stats) return ( diff --git a/app/routes/memberships.tsx b/app/routes/memberships.tsx index 0870791..414aa5d 100644 --- a/app/routes/memberships.tsx +++ b/app/routes/memberships.tsx @@ -65,7 +65,7 @@ import { listUsers, type User } from "~/lib/arcadia/users" import { listRoles, type Role } from "~/lib/arcadia/roles" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Memberships") @@ -272,7 +272,7 @@ export default function MembershipsRoute() { }), [memberships], ) - useRegisterAdminContext("memberships", summary) + useRegisterContext("memberships", summary) const table = useTable({ data: filtered, diff --git a/app/routes/monitoring.tsx b/app/routes/monitoring.tsx index 3671013..43bf544 100644 --- a/app/routes/monitoring.tsx +++ b/app/routes/monitoring.tsx @@ -81,7 +81,7 @@ import { } from "~/lib/arcadia/health" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Monitoring") @@ -193,7 +193,7 @@ export default function MonitoringRoute() { }), [data], ) - useRegisterAdminContext("monitoring", summary) + useRegisterContext("monitoring", summary) return ( diff --git a/app/routes/networking.tsx b/app/routes/networking.tsx index c6f9e60..5b85014 100644 --- a/app/routes/networking.tsx +++ b/app/routes/networking.tsx @@ -61,7 +61,7 @@ import { import { listDroplets, type Droplet } from "~/lib/arcadia/monitoring" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Networking") @@ -107,7 +107,7 @@ export default function NetworkingRoute() { if (session) refresh() }, [session, refresh]) - useRegisterAdminContext("networking", { + useRegisterContext("networking", { firewalls: firewalls.length, vpcs: vpcs.length, domains: domains.length, diff --git a/app/routes/scheduled-tasks.tsx b/app/routes/scheduled-tasks.tsx index 21e7ed7..83a335d 100644 --- a/app/routes/scheduled-tasks.tsx +++ b/app/routes/scheduled-tasks.tsx @@ -72,7 +72,7 @@ import { } from "~/lib/arcadia/scheduled-tasks" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Scheduled tasks") @@ -227,7 +227,7 @@ export default function ScheduledTasksRoute() { }), [tasks], ) - useRegisterAdminContext("scheduled_tasks", summary) + useRegisterContext("scheduled_tasks", summary) const table = useTable({ data: tasks, diff --git a/app/routes/search.tsx b/app/routes/search.tsx index 2974f85..29e0b63 100644 --- a/app/routes/search.tsx +++ b/app/routes/search.tsx @@ -60,7 +60,7 @@ import { } from "~/lib/search-admin" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Search") @@ -157,7 +157,7 @@ export default function SearchRoute() { }), [tenants, corpora], ) - useRegisterAdminContext("search", adminSurface) + useRegisterContext("search", adminSurface) const rebuild = useCallback( async (tenant: string, corpus: string) => { diff --git a/app/routes/secrets.tsx b/app/routes/secrets.tsx index 04548c2..e6aff59 100644 --- a/app/routes/secrets.tsx +++ b/app/routes/secrets.tsx @@ -77,7 +77,7 @@ import { } from "~/lib/arcadia/secrets" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Secrets") @@ -234,7 +234,7 @@ export default function SecretsRoute() { }), [secrets], ) - useRegisterAdminContext("secrets", summary) + useRegisterContext("secrets", summary) const table = useTable({ data: filtered, diff --git a/app/routes/sso.tsx b/app/routes/sso.tsx index a4cc4d7..1db2bd3 100644 --- a/app/routes/sso.tsx +++ b/app/routes/sso.tsx @@ -59,7 +59,7 @@ import { } from "~/lib/arcadia/sso" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("SSO") @@ -102,7 +102,7 @@ export default function SsoRoute() { if (session) refresh() }, [session, refresh]) - useRegisterAdminContext("sso", { + useRegisterContext("sso", { identity_providers: idps.length, enabled_idps: idps.filter((i) => i.enabled).length, active_sessions: sessions.length, diff --git a/app/routes/status-page.tsx b/app/routes/status-page.tsx index dd2f185..583a2df 100644 --- a/app/routes/status-page.tsx +++ b/app/routes/status-page.tsx @@ -70,7 +70,7 @@ import { } from "~/lib/arcadia/status-page" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Status page") @@ -129,7 +129,7 @@ export default function StatusPageRoute() { if (session) refresh() }, [session, refresh]) - useRegisterAdminContext("status_page", { + useRegisterContext("status_page", { components: components.length, open_incidents: incidents.filter((i) => i.status !== "resolved").length, subscribers: subscribers.length, diff --git a/app/routes/storage.tsx b/app/routes/storage.tsx index a12b78f..7eae9bb 100644 --- a/app/routes/storage.tsx +++ b/app/routes/storage.tsx @@ -77,7 +77,7 @@ import { } from "~/lib/arcadia/storage-configs" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Storage") @@ -250,7 +250,7 @@ export default function StorageRoute() { }), [configs], ) - useRegisterAdminContext("storage", summary) + useRegisterContext("storage", summary) const table = useTable({ data: configs, diff --git a/app/routes/tenants.tsx b/app/routes/tenants.tsx index 1e0ec9e..c2e5574 100644 --- a/app/routes/tenants.tsx +++ b/app/routes/tenants.tsx @@ -36,7 +36,7 @@ import { } from "~/lib/arcadia/tenants" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Tenants") @@ -160,7 +160,7 @@ export default function TenantsRoute() { }), [tenants], ) - useRegisterAdminContext("tenants", tenantSummary) + useRegisterContext("tenants", tenantSummary) const table = useTable({ data: tenants, diff --git a/app/routes/users.tsx b/app/routes/users.tsx index 774c134..6e54e99 100644 --- a/app/routes/users.tsx +++ b/app/routes/users.tsx @@ -87,7 +87,7 @@ import { } from "~/lib/arcadia/users" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" import { UserDetailSheet } from "~/components/users/user-detail-sheet" export const meta = () => pageTitle("Users") @@ -167,7 +167,7 @@ export default function UsersRoute() { }), [users, invitations, roles], ) - useRegisterAdminContext("users", summary) + useRegisterContext("users", summary) return ( diff --git a/app/routes/webhooks.tsx b/app/routes/webhooks.tsx index d5b76c4..23ec4b8 100644 --- a/app/routes/webhooks.tsx +++ b/app/routes/webhooks.tsx @@ -77,7 +77,7 @@ import { } from "~/lib/arcadia/webhooks" import { pageTitle } from "~/lib/page-meta" import { useSession } from "~/lib/session" -import { useRegisterAdminContext } from "~/lib/admin-context" +import { useRegisterContext } from "@crema/aifirst-ui/context" export const meta = () => pageTitle("Webhooks") @@ -228,7 +228,7 @@ export default function WebhooksRoute() { }), [webhooks], ) - useRegisterAdminContext("webhooks", summary) + useRegisterContext("webhooks", summary) const table = useTable({ data: webhooks,