Ely-Eye — local multimodal context operating system on Qwen3.5-9B
Real-models implementation: multimodal ingestion, Context Cartridge memory, sparse + Qwen embedding retrieval, Cache Fabric, Qwen runtime adapters, verifier contracts, Visual HashHop proofs, BF16 LoRA fine-tuning, and a local dashboard. Verified by a 15-check PRD proof suite on the live model.
This commit is contained in:
commit
0ee99e271d
64 files changed
+14890
No files matched your search
@@ -0,0 +1,517 @@
|
||||
import {
|
||||
Activity,
|
||||
Archive,
|
||||
Braces,
|
||||
CheckCircle,
|
||||
Cpu,
|
||||
Database,
|
||||
FileSearch,
|
||||
Gauge,
|
||||
GitBranch,
|
||||
Image as ImageIcon,
|
||||
Play,
|
||||
RefreshCw,
|
||||
Send,
|
||||
Server,
|
||||
ShieldCheck,
|
||||
Upload,
|
||||
} from 'lucide-react';
|
||||
import { FormEvent, ReactNode, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
askQuestion,
|
||||
getAdapters,
|
||||
getLatestProofSuite,
|
||||
getMemoryMap,
|
||||
getStatus,
|
||||
ingestPath,
|
||||
runHashHop,
|
||||
runProofSuite,
|
||||
uploadFiles,
|
||||
} from './api';
|
||||
import type {
|
||||
AdapterStatus,
|
||||
AnswerResponse,
|
||||
HashHopProof,
|
||||
IngestResponse,
|
||||
MemoryMap,
|
||||
ProofSuiteReport,
|
||||
RuntimeProfile,
|
||||
SystemStatus,
|
||||
} from './types';
|
||||
|
||||
const profiles: Array<{ id: RuntimeProfile; label: string }> = [
|
||||
{ id: 'live_demo', label: 'Live Demo' },
|
||||
{ id: 'extreme_context', label: 'Extreme' },
|
||||
{ id: 'library_100m', label: '100M Library' },
|
||||
{ id: 'research_theater', label: 'Research' },
|
||||
];
|
||||
|
||||
export function App() {
|
||||
const [status, setStatus] = useState<SystemStatus | null>(null);
|
||||
const [memoryMap, setMemoryMap] = useState<MemoryMap | null>(null);
|
||||
const [adapters, setAdapters] = useState<AdapterStatus[]>([]);
|
||||
const [profile, setProfile] = useState<RuntimeProfile>('library_100m');
|
||||
const [path, setPath] = useState('');
|
||||
const [cartridgeName, setCartridgeName] = useState('ely-eye-cartridge');
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
const [question, setQuestion] = useState('');
|
||||
const [answer, setAnswer] = useState<AnswerResponse | null>(null);
|
||||
const [hashHop, setHashHop] = useState<HashHopProof | null>(null);
|
||||
const [proofSuite, setProofSuite] = useState<ProofSuiteReport | null>(null);
|
||||
const [lastIngest, setLastIngest] = useState<IngestResponse | null>(null);
|
||||
const [busy, setBusy] = useState<string | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const refresh = async () => {
|
||||
setError(null);
|
||||
const [nextStatus, nextMap, nextAdapters, nextProofSuite] = await Promise.all([
|
||||
getStatus(),
|
||||
getMemoryMap(),
|
||||
getAdapters(),
|
||||
getLatestProofSuite().catch(() => null),
|
||||
]);
|
||||
setStatus(nextStatus);
|
||||
setMemoryMap(nextMap);
|
||||
setAdapters(nextAdapters);
|
||||
setProofSuite(nextProofSuite);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
async function loadInitial() {
|
||||
try {
|
||||
const [nextStatus, nextMap, nextAdapters, nextProofSuite] = await Promise.all([
|
||||
getStatus(),
|
||||
getMemoryMap(),
|
||||
getAdapters(),
|
||||
getLatestProofSuite().catch(() => null),
|
||||
]);
|
||||
if (!cancelled) {
|
||||
setStatus(nextStatus);
|
||||
setMemoryMap(nextMap);
|
||||
setAdapters(nextAdapters);
|
||||
setProofSuite(nextProofSuite);
|
||||
}
|
||||
} catch (err) {
|
||||
if (!cancelled) {
|
||||
setError(errorMessage(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
void loadInitial();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const memoryLayers = useMemo(() => status?.memory.layers ?? [], [status]);
|
||||
const boundAdapters = useMemo(() => adapters.filter((adapter) => adapter.cartridge_bound).length, [adapters]);
|
||||
const passedProofChecks = useMemo(
|
||||
() => proofSuite?.checks.filter((check) => check.status === 'passed').length ?? 0,
|
||||
[proofSuite],
|
||||
);
|
||||
|
||||
async function submitPath(event: FormEvent) {
|
||||
event.preventDefault();
|
||||
setBusy('ingest-path');
|
||||
setError(null);
|
||||
try {
|
||||
const result = await ingestPath(path, cartridgeName);
|
||||
setLastIngest(result);
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
} finally {
|
||||
setBusy(null);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitUpload(event: FormEvent) {
|
||||
event.preventDefault();
|
||||
setBusy('upload');
|
||||
setError(null);
|
||||
try {
|
||||
const result = await uploadFiles(files, cartridgeName);
|
||||
setLastIngest(result);
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
} finally {
|
||||
setBusy(null);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitQuestion(event: FormEvent) {
|
||||
event.preventDefault();
|
||||
setBusy('chat');
|
||||
setError(null);
|
||||
try {
|
||||
const result = await askQuestion(question, profile);
|
||||
setAnswer(result);
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
} finally {
|
||||
setBusy(null);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitHashHop(kind: 'text' | 'visual') {
|
||||
setBusy(`hashhop-${kind}`);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await runHashHop(kind, kind === 'visual' ? 2 : 2, kind === 'visual' ? 262144 : 1010000);
|
||||
setHashHop(result);
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
} finally {
|
||||
setBusy(null);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitProofSuite() {
|
||||
setBusy('proof-suite');
|
||||
setError(null);
|
||||
try {
|
||||
const cartridgeId = memoryMap?.cartridges[0]?.cartridge_id;
|
||||
const result = await runProofSuite(cartridgeId);
|
||||
setProofSuite(result);
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
} finally {
|
||||
setBusy(null);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="app-shell">
|
||||
<header className="topbar">
|
||||
<div>
|
||||
<p className="eyebrow">Ely-Eye v4.0</p>
|
||||
<h1>Local VLM Context OS</h1>
|
||||
</div>
|
||||
<button className="icon-button" title="Refresh status" onClick={() => refresh().catch((err) => setError(errorMessage(err)))}>
|
||||
<RefreshCw size={18} />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
{error && <div className="error-line">{error}</div>}
|
||||
|
||||
<section className="kpi-grid" aria-label="system status">
|
||||
<Kpi icon={<Server size={18} />} label="Runtime" value={status?.runtime.available ? 'ready' : 'offline'} detail={formatRuntimeDetail(status)} />
|
||||
<Kpi icon={<Gauge size={18} />} label="GPU" value={status?.runtime.gpu_name ?? 'unknown'} detail={formatVram(status)} />
|
||||
<Kpi icon={<Database size={18} />} label="Library" value={formatNumber(status?.memory.library_token_equivalent ?? 0)} detail="token eq" />
|
||||
<Kpi icon={<Archive size={18} />} label="Cartridges" value={String(status?.memory.cartridges ?? 0)} detail={`${boundAdapters} adapters bound`} />
|
||||
</section>
|
||||
|
||||
<section className="workspace-grid">
|
||||
<Panel title="Input Stream" icon={<Upload size={17} />}>
|
||||
<form className="stack" onSubmit={submitPath}>
|
||||
<label>
|
||||
Cartridge
|
||||
<input value={cartridgeName} onChange={(event) => setCartridgeName(event.target.value)} />
|
||||
</label>
|
||||
<label>
|
||||
Local path
|
||||
<input value={path} onChange={(event) => setPath(event.target.value)} />
|
||||
</label>
|
||||
<button className="action-button" disabled={!path || busy === 'ingest-path'}>
|
||||
<FileSearch size={16} />
|
||||
Ingest Path
|
||||
</button>
|
||||
</form>
|
||||
<form className="stack" onSubmit={submitUpload}>
|
||||
<label>
|
||||
Files
|
||||
<input type="file" multiple onChange={(event) => setFiles(Array.from(event.target.files ?? []))} />
|
||||
</label>
|
||||
<button className="action-button secondary" disabled={files.length === 0 || busy === 'upload'}>
|
||||
<Upload size={16} />
|
||||
Upload Files
|
||||
</button>
|
||||
</form>
|
||||
{lastIngest && (
|
||||
<div className="metric-strip">
|
||||
<span>{lastIngest.source_count} sources</span>
|
||||
<span>{lastIngest.atom_count} atoms</span>
|
||||
<span>{formatNumber(lastIngest.token_equivalent)} tokens</span>
|
||||
</div>
|
||||
)}
|
||||
</Panel>
|
||||
|
||||
<Panel title="Context Compiler" icon={<Braces size={17} />}>
|
||||
<div className="segments">
|
||||
{profiles.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
className={profile === item.id ? 'segment active' : 'segment'}
|
||||
onClick={() => setProfile(item.id)}
|
||||
type="button"
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<form className="stack" onSubmit={submitQuestion}>
|
||||
<textarea value={question} onChange={(event) => setQuestion(event.target.value)} rows={6} />
|
||||
<button className="action-button" disabled={!question || busy === 'chat'}>
|
||||
<Send size={16} />
|
||||
Ask
|
||||
</button>
|
||||
</form>
|
||||
{answer && (
|
||||
<div className="answer-box">
|
||||
<p>{answer.answer}</p>
|
||||
<div className="metric-strip">
|
||||
<span>{answer.context.hits.length} hits</span>
|
||||
<span>{Math.round(answer.verifier.citation_accuracy * 100)}% citations</span>
|
||||
<span>{answer.runtime_backend}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Panel>
|
||||
|
||||
<Panel title="Memory OS" icon={<Database size={17} />}>
|
||||
<div className="layer-list">
|
||||
{memoryLayers.map((layer) => (
|
||||
<div className="layer-row" key={layer.layer}>
|
||||
<span>{layer.layer}</span>
|
||||
<strong>{layer.entries}</strong>
|
||||
<small>{layer.hit_count} hit / {layer.miss_count} miss</small>
|
||||
</div>
|
||||
))}
|
||||
{memoryLayers.length === 0 && <div className="quiet-line">No cache events</div>}
|
||||
</div>
|
||||
<div className="atom-list">
|
||||
{(memoryMap?.atoms ?? []).slice(0, 8).map((atom) => (
|
||||
<div className="atom-row" key={atom.atom_id}>
|
||||
<span>{atom.modality}</span>
|
||||
<strong>{atom.atom_id}</strong>
|
||||
<small>{atom.source}</small>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<Panel title="Adapter Matrix" icon={<Cpu size={17} />}>
|
||||
<div className="adapter-list">
|
||||
{adapters.map((adapter) => (
|
||||
<div className="adapter-row" key={adapter.adapter_id}>
|
||||
<header>
|
||||
<span>{adapter.kind.replaceAll('_', '-')}</span>
|
||||
{adapter.cartridge_bound && <CheckCircle size={16} aria-label="bound" />}
|
||||
</header>
|
||||
<strong>{adapter.base_model}</strong>
|
||||
<div className="adapter-metrics">
|
||||
<small>{adapter.training_method}</small>
|
||||
<small>{adapter.precision}</small>
|
||||
<small title={adapter.unsloth_model_type ?? adapter.framework}>{formatFramework(adapter.framework)}</small>
|
||||
<small title={adapter.optimizer_family ?? adapter.optimizer ?? undefined}>{formatOptimizer(adapter)}</small>
|
||||
<small title={adapter.gradient_checkpointing_mode ?? undefined}>{formatCheckpointing(adapter)}</small>
|
||||
<small title={adapter.triton_version ?? undefined}>{adapter.triton_version ? `triton ${adapter.triton_version}` : 'triton pending'}</small>
|
||||
<small>{formatBytes(adapter.weight_bytes)}</small>
|
||||
<small>{formatNumber(adapter.trainable_params)} params</small>
|
||||
<small>{adapter.final_loss?.toFixed(3) ?? 'loss pending'}</small>
|
||||
<small>{adapter.training_trace_steps}/{adapter.max_steps} trace</small>
|
||||
<small>{formatNumber(adapter.optimizer_update_count)} updates</small>
|
||||
<small>{adapter.loss_delta == null ? 'loss delta pending' : `loss delta ${adapter.loss_delta.toFixed(3)}`}</small>
|
||||
<small>{adapter.bf16 ? 'cuda bf16' : 'precision pending'}</small>
|
||||
<small>{formatNumber(adapter.adapter_lora_tensor_count)} LoRA tensors</small>
|
||||
<small>{formatNumber(adapter.adapter_nonzero_elements)} nonzero</small>
|
||||
<small>{adapter.adapter_weights_finite ? 'finite weights' : 'weights pending'}</small>
|
||||
<small>{adapter.adapter_weight_sha256 ? `sha ${shortHash(adapter.adapter_weight_sha256)}` : 'sha pending'}</small>
|
||||
<small>{formatDuration(adapter.training_wall_seconds)}</small>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{adapters.length === 0 && <div className="quiet-line">No adapters found</div>}
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<Panel title="PRD Proof Suite" icon={<ShieldCheck size={17} />}>
|
||||
<div className="proof-suite-header">
|
||||
<button className="action-button secondary" onClick={submitProofSuite} disabled={busy === 'proof-suite'}>
|
||||
<Play size={16} />
|
||||
Run Suite
|
||||
</button>
|
||||
<div className={proofSuite?.status === 'passed' ? 'proof-pill passed' : 'proof-pill'}>
|
||||
{proofSuite ? `${passedProofChecks}/${proofSuite.checks.length} passed` : 'pending'}
|
||||
</div>
|
||||
</div>
|
||||
{proofSuite && (
|
||||
<div className="proof-list">
|
||||
{proofSuite.checks.map((check) => (
|
||||
<article className="proof-row" key={check.name}>
|
||||
<header>
|
||||
<strong>{check.name}</strong>
|
||||
<span className={check.status === 'passed' ? 'proof-status passed' : 'proof-status'}>
|
||||
{check.status}
|
||||
</span>
|
||||
</header>
|
||||
<p>{check.detail}</p>
|
||||
<small>{check.evidence[0]}</small>
|
||||
</article>
|
||||
))}
|
||||
<div className="proof-box">
|
||||
<strong>{proofSuite.proof_id}</strong>
|
||||
<span>{proofSuite.status}</span>
|
||||
<small>{proofSuite.cartridge_id}</small>
|
||||
<small>{proofSuite.dna_after ?? proofSuite.dna_before}</small>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!proofSuite && <div className="quiet-line">Proof suite has not run yet</div>}
|
||||
</Panel>
|
||||
|
||||
<Panel title="Evidence Viewer" icon={<ImageIcon size={17} />}>
|
||||
<div className="evidence-list">
|
||||
{(answer?.context.hits ?? []).slice(0, 8).map((hit) => (
|
||||
<article key={hit.atom.atom_id} className="evidence-row">
|
||||
<header>
|
||||
<span>{hit.atom.modality}</span>
|
||||
<strong>{hit.final_score.toFixed(3)}</strong>
|
||||
</header>
|
||||
<p>{hit.atom.text.slice(0, 280)}</p>
|
||||
<small>{hit.atom.source}</small>
|
||||
</article>
|
||||
))}
|
||||
{!answer && <div className="quiet-line">Evidence appears after a compiled answer</div>}
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<Panel title="Visual HashHop Arena" icon={<GitBranch size={17} />}>
|
||||
<div className="button-row">
|
||||
<button className="action-button secondary" onClick={() => submitHashHop('visual')} disabled={busy === 'hashhop-visual'}>
|
||||
<Play size={16} />
|
||||
Visual 2-hop
|
||||
</button>
|
||||
<button className="action-button secondary" onClick={() => submitHashHop('text')} disabled={busy === 'hashhop-text'}>
|
||||
<Play size={16} />
|
||||
Text 2-hop
|
||||
</button>
|
||||
</div>
|
||||
{hashHop && (
|
||||
<div className="proof-box">
|
||||
<strong>{hashHop.proof_id}</strong>
|
||||
<span>{hashHop.kind}</span>
|
||||
<span>{hashHop.hops} hops</span>
|
||||
<span>{formatNumber(hashHop.token_equivalent)} token eq</span>
|
||||
<small>{hashHop.expected_target_id}</small>
|
||||
</div>
|
||||
)}
|
||||
</Panel>
|
||||
|
||||
<Panel title="Cache Trace" icon={<Activity size={17} />}>
|
||||
<div className="trace-list">
|
||||
{memoryLayers.map((layer) => (
|
||||
<div key={layer.layer} className="trace-row">
|
||||
<span>{layer.layer}</span>
|
||||
<meter min={0} max={Math.max(1, layer.hit_count + layer.miss_count)} value={layer.hit_count} />
|
||||
<small>{formatBytes(layer.bytes_estimate)}</small>
|
||||
</div>
|
||||
))}
|
||||
{memoryLayers.length === 0 && <div className="quiet-line">Waiting for retrieval</div>}
|
||||
</div>
|
||||
</Panel>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function Panel({ title, icon, children }: { title: string; icon: ReactNode; children: ReactNode }) {
|
||||
return (
|
||||
<section className="panel">
|
||||
<header className="panel-header">
|
||||
<span className="panel-icon">{icon}</span>
|
||||
<h2>{title}</h2>
|
||||
</header>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function Kpi({ icon, label, value, detail }: { icon: ReactNode; label: string; value: string; detail: string }) {
|
||||
return (
|
||||
<section className="kpi">
|
||||
<span className="panel-icon">{icon}</span>
|
||||
<div>
|
||||
<p>{label}</p>
|
||||
<strong>{value}</strong>
|
||||
<small>{detail}</small>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function errorMessage(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return err.message;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
function formatNumber(value: number): string {
|
||||
return new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(value);
|
||||
}
|
||||
|
||||
function formatBytes(value: number): string {
|
||||
if (value < 1024) {
|
||||
return `${value} B`;
|
||||
}
|
||||
if (value < 1024 * 1024) {
|
||||
return `${(value / 1024).toFixed(1)} KiB`;
|
||||
}
|
||||
return `${(value / 1024 / 1024).toFixed(1)} MiB`;
|
||||
}
|
||||
|
||||
function formatDuration(value: number | null): string {
|
||||
if (typeof value !== 'number') {
|
||||
return 'time pending';
|
||||
}
|
||||
if (value < 60) {
|
||||
return `${value.toFixed(1)}s`;
|
||||
}
|
||||
return `${Math.round(value / 60)}m`;
|
||||
}
|
||||
|
||||
function shortHash(value: string): string {
|
||||
return value.slice(0, 8);
|
||||
}
|
||||
|
||||
function formatOptimizer(adapter: AdapterStatus): string {
|
||||
if (adapter.optimizer === 'paged_adamw_8bit') {
|
||||
return 'paged 8-bit AdamW';
|
||||
}
|
||||
return adapter.optimizer_family ?? adapter.optimizer ?? 'optimizer pending';
|
||||
}
|
||||
|
||||
function formatFramework(value: string): string {
|
||||
if (value === 'unsloth_patched_transformers_peft') {
|
||||
return 'Unsloth patch + PEFT';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function formatCheckpointing(adapter: AdapterStatus): string {
|
||||
if (adapter.gradient_checkpointing_mode === 'unsloth') {
|
||||
return 'ckpt unsloth';
|
||||
}
|
||||
return adapter.gradient_checkpointing ? 'ckpt on' : 'ckpt pending';
|
||||
}
|
||||
|
||||
function formatRuntimeDetail(status: SystemStatus | null): string {
|
||||
const model = status?.runtime.model_id ?? 'Qwen/Qwen3.5-9B';
|
||||
const adapter = status?.runtime.adapter_kind?.replaceAll('_', '-');
|
||||
return adapter ? `${model} · ${adapter}` : model;
|
||||
}
|
||||
|
||||
function formatVram(status: SystemStatus | null): string {
|
||||
const total = status?.runtime.vram_total_mb;
|
||||
const used = status?.runtime.vram_used_mb;
|
||||
if (typeof total === 'number' && typeof used === 'number') {
|
||||
return `${used} / ${total} MiB`;
|
||||
}
|
||||
return status?.runtime.cuda ?? 'CUDA';
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import type {
|
||||
AdapterStatus,
|
||||
AnswerResponse,
|
||||
HashHopProof,
|
||||
IngestResponse,
|
||||
MemoryMap,
|
||||
ProofSuiteReport,
|
||||
RuntimeProfile,
|
||||
SystemStatus,
|
||||
} from './types';
|
||||
|
||||
async function request<T>(url: string, init?: RequestInit): Promise<T> {
|
||||
const response = await fetch(url, init);
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => ({ detail: response.statusText }));
|
||||
throw new Error(typeof payload.detail === 'string' ? payload.detail : JSON.stringify(payload.detail));
|
||||
}
|
||||
return (await response.json()) as T;
|
||||
}
|
||||
|
||||
export function getStatus(): Promise<SystemStatus> {
|
||||
return request<SystemStatus>('/api/status');
|
||||
}
|
||||
|
||||
export function getMemoryMap(): Promise<MemoryMap> {
|
||||
return request<MemoryMap>('/api/memory-map');
|
||||
}
|
||||
|
||||
export function getAdapters(): Promise<AdapterStatus[]> {
|
||||
return request<AdapterStatus[]>('/api/adapters');
|
||||
}
|
||||
|
||||
export function ingestPath(path: string, cartridgeName: string): Promise<IngestResponse> {
|
||||
return request<IngestResponse>('/api/ingest/path', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path, cartridge_name: cartridgeName || null }),
|
||||
});
|
||||
}
|
||||
|
||||
export function uploadFiles(files: File[], cartridgeName: string): Promise<IngestResponse> {
|
||||
const form = new FormData();
|
||||
for (const file of files) {
|
||||
form.append('files', file);
|
||||
}
|
||||
const query = new URLSearchParams();
|
||||
if (cartridgeName) {
|
||||
query.set('cartridge_name', cartridgeName);
|
||||
}
|
||||
return request<IngestResponse>(`/api/ingest/upload?${query.toString()}`, {
|
||||
method: 'POST',
|
||||
body: form,
|
||||
});
|
||||
}
|
||||
|
||||
export function askQuestion(question: string, profile: RuntimeProfile): Promise<AnswerResponse> {
|
||||
return request<AnswerResponse>('/api/chat', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ question, profile }),
|
||||
});
|
||||
}
|
||||
|
||||
export function runHashHop(kind: 'text' | 'visual', hops: number, tokenEquivalent: number): Promise<HashHopProof> {
|
||||
return request<HashHopProof>('/api/hashhop', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ kind, hops, token_equivalent: tokenEquivalent }),
|
||||
});
|
||||
}
|
||||
|
||||
export function runProofSuite(cartridgeId?: string): Promise<ProofSuiteReport> {
|
||||
return request<ProofSuiteReport>('/api/proof-suite', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ cartridge_id: cartridgeId ?? null }),
|
||||
});
|
||||
}
|
||||
|
||||
export function getLatestProofSuite(): Promise<ProofSuiteReport> {
|
||||
return request<ProofSuiteReport>('/api/proof-suite/latest');
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { App } from './App';
|
||||
import './styles.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
@@ -0,0 +1,444 @@
|
||||
:root {
|
||||
font-family:
|
||||
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
color: #17201b;
|
||||
background: #f4f3ee;
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
max-width: 1480px;
|
||||
margin: 0 auto 18px;
|
||||
border-bottom: 1px solid #c9d2c4;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 3px;
|
||||
color: #476a58;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(1.7rem, 3vw, 2.7rem);
|
||||
font-weight: 760;
|
||||
}
|
||||
|
||||
.icon-button,
|
||||
.action-button,
|
||||
.segment {
|
||||
border: 1px solid #8fa091;
|
||||
background: #fffdf7;
|
||||
color: #17201b;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.error-line {
|
||||
max-width: 1480px;
|
||||
margin: 0 auto 14px;
|
||||
border: 1px solid #be6a5b;
|
||||
background: #fff5f1;
|
||||
color: #7f2e21;
|
||||
border-radius: 7px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.kpi-grid,
|
||||
.workspace-grid {
|
||||
max-width: 1480px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.kpi-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.kpi,
|
||||
.panel {
|
||||
border: 1px solid #c9d2c4;
|
||||
background: #fffdf7;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.kpi {
|
||||
display: grid;
|
||||
grid-template-columns: 34px minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
padding: 14px;
|
||||
min-height: 104px;
|
||||
}
|
||||
|
||||
.kpi p,
|
||||
.kpi small,
|
||||
.atom-row small,
|
||||
.trace-row small,
|
||||
.layer-row small,
|
||||
.evidence-row small,
|
||||
.proof-box small {
|
||||
color: #607166;
|
||||
}
|
||||
|
||||
.kpi strong {
|
||||
display: block;
|
||||
margin: 4px 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.workspace-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.25fr 1fr;
|
||||
gap: 12px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.panel {
|
||||
padding: 14px;
|
||||
min-height: 260px;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.panel-header h2 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.panel-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 6px;
|
||||
color: #1f5a45;
|
||||
background: #dfe8dc;
|
||||
}
|
||||
|
||||
.stack {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
color: #46554b;
|
||||
font-size: 0.86rem;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: 1px solid #aebba9;
|
||||
border-radius: 7px;
|
||||
padding: 9px 10px;
|
||||
background: #fff;
|
||||
color: #17201b;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 132px;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
min-height: 40px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
font-weight: 720;
|
||||
background: #214f3f;
|
||||
color: #fffdf7;
|
||||
border-color: #214f3f;
|
||||
}
|
||||
|
||||
.action-button.secondary {
|
||||
background: #fffdf7;
|
||||
color: #214f3f;
|
||||
}
|
||||
|
||||
.action-button:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.segments,
|
||||
.button-row,
|
||||
.metric-strip {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.segments {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.segment {
|
||||
min-height: 34px;
|
||||
padding: 7px 10px;
|
||||
font-weight: 680;
|
||||
}
|
||||
|
||||
.segment.active {
|
||||
background: #214f3f;
|
||||
color: #fffdf7;
|
||||
border-color: #214f3f;
|
||||
}
|
||||
|
||||
.metric-strip span,
|
||||
.proof-box span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
border: 1px solid #cbd7c6;
|
||||
border-radius: 999px;
|
||||
padding: 4px 9px;
|
||||
color: #284338;
|
||||
background: #f5f8f2;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 680;
|
||||
}
|
||||
|
||||
.answer-box,
|
||||
.proof-box,
|
||||
.quiet-line {
|
||||
border: 1px solid #d5c8ac;
|
||||
background: #fff9ea;
|
||||
border-radius: 7px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.answer-box {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.layer-list,
|
||||
.atom-list,
|
||||
.evidence-list,
|
||||
.trace-list,
|
||||
.adapter-list,
|
||||
.proof-list,
|
||||
.proof-box {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.layer-row,
|
||||
.atom-row,
|
||||
.trace-row,
|
||||
.adapter-row,
|
||||
.proof-row,
|
||||
.evidence-row {
|
||||
border: 1px solid #d7ded2;
|
||||
border-radius: 7px;
|
||||
background: #ffffff;
|
||||
padding: 9px;
|
||||
}
|
||||
|
||||
.layer-row,
|
||||
.trace-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 4px 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layer-row small,
|
||||
.trace-row small {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.atom-row {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.atom-row span,
|
||||
.adapter-row span,
|
||||
.evidence-row span {
|
||||
color: #7a4e29;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 760;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.atom-row strong,
|
||||
.adapter-row strong,
|
||||
.evidence-row p,
|
||||
.evidence-row small {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.adapter-row {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.adapter-row header,
|
||||
.proof-row header,
|
||||
.evidence-row header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.adapter-row header,
|
||||
.proof-row header {
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.adapter-row svg {
|
||||
color: #1f5a45;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.adapter-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.adapter-metrics small {
|
||||
border: 1px solid #d7ded2;
|
||||
border-radius: 6px;
|
||||
background: #f5f8f2;
|
||||
color: #284338;
|
||||
padding: 5px 6px;
|
||||
font-size: 0.76rem;
|
||||
font-weight: 650;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.proof-suite-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.proof-pill,
|
||||
.proof-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #c9b6a0;
|
||||
border-radius: 999px;
|
||||
background: #fff5f1;
|
||||
color: #7f2e21;
|
||||
font-size: 0.76rem;
|
||||
font-weight: 760;
|
||||
min-height: 28px;
|
||||
padding: 4px 9px;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.proof-pill.passed,
|
||||
.proof-status.passed {
|
||||
border-color: #b8c7ae;
|
||||
background: #f5f8f2;
|
||||
color: #214f3f;
|
||||
}
|
||||
|
||||
.proof-row {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.proof-row p,
|
||||
.proof-row small {
|
||||
color: #607166;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.evidence-row p {
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
meter {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
.kpi-grid,
|
||||
.workspace-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.app-shell {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.kpi-grid,
|
||||
.workspace-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
export type RuntimeProfile = 'live_demo' | 'extreme_context' | 'library_100m' | 'research_theater';
|
||||
|
||||
export interface RuntimeStatus {
|
||||
backend: string;
|
||||
model_id: string;
|
||||
available: boolean;
|
||||
detail: string;
|
||||
adapter_path: string | null;
|
||||
adapter_kind: string | null;
|
||||
adapter_id: string | null;
|
||||
adapter_sha256: string | null;
|
||||
gpu_name: string | null;
|
||||
cuda: string | null;
|
||||
vram_total_mb: number | null;
|
||||
vram_used_mb: number | null;
|
||||
}
|
||||
|
||||
export interface CacheLayerStatus {
|
||||
layer: string;
|
||||
entries: number;
|
||||
bytes_estimate: number;
|
||||
hit_count: number;
|
||||
miss_count: number;
|
||||
last_event_at: string | null;
|
||||
}
|
||||
|
||||
export interface MemoryStatus {
|
||||
active_atoms: number;
|
||||
active_token_equivalent: number;
|
||||
cartridges: number;
|
||||
library_token_equivalent: number;
|
||||
layers: CacheLayerStatus[];
|
||||
}
|
||||
|
||||
export interface SystemStatus {
|
||||
app: string;
|
||||
version: string;
|
||||
runtime: RuntimeStatus;
|
||||
memory: MemoryStatus;
|
||||
profiles: Record<string, Record<string, unknown>>;
|
||||
data_home: string;
|
||||
}
|
||||
|
||||
export interface AdapterStatus {
|
||||
name: string;
|
||||
kind: string;
|
||||
proof_version: number;
|
||||
training_method: string;
|
||||
precision: string;
|
||||
framework: string;
|
||||
base_model: string;
|
||||
path: string;
|
||||
adapter_id: string;
|
||||
sample_count: number;
|
||||
max_steps: number;
|
||||
trainable_params: number;
|
||||
final_loss: number | null;
|
||||
sha256: string;
|
||||
weight_bytes: number;
|
||||
safetensor_keys: number;
|
||||
cartridge_id: string | null;
|
||||
cartridge_bound: boolean;
|
||||
training_trace_path: string | null;
|
||||
training_trace_sha256: string | null;
|
||||
training_trace_steps: number;
|
||||
training_proof_path: string | null;
|
||||
training_proof_sha256: string | null;
|
||||
optimizer: string | null;
|
||||
optimizer_family: string | null;
|
||||
gradient_checkpointing: boolean;
|
||||
gradient_checkpointing_mode: string | null;
|
||||
autocast_dtype: string | null;
|
||||
unsloth_version: string | null;
|
||||
triton_version: string | null;
|
||||
xformers_version: string | null;
|
||||
unsloth_model_type: string | null;
|
||||
optimizer_update_count: number;
|
||||
max_optimizer_update_l2: number | null;
|
||||
loss_delta: number | null;
|
||||
training_summary_path: string | null;
|
||||
training_wall_seconds: number | null;
|
||||
training_device: string | null;
|
||||
bf16: boolean;
|
||||
torch_version: string | null;
|
||||
cuda_version: string | null;
|
||||
adapter_weight_sha256: string | null;
|
||||
adapter_tensor_count: number;
|
||||
adapter_lora_tensor_count: number;
|
||||
adapter_total_elements: number;
|
||||
adapter_nonzero_elements: number;
|
||||
adapter_max_abs: number | null;
|
||||
adapter_weights_finite: boolean;
|
||||
}
|
||||
|
||||
export interface IngestResponse {
|
||||
source_count: number;
|
||||
atom_count: number;
|
||||
cartridge_id: string | null;
|
||||
token_equivalent: number;
|
||||
}
|
||||
|
||||
export interface LayoutBox {
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
page?: number | null;
|
||||
frame_second?: number | null;
|
||||
}
|
||||
|
||||
export interface EvidenceAtom {
|
||||
atom_id: string;
|
||||
modality: string;
|
||||
source: string;
|
||||
text: string;
|
||||
image_ref: string | null;
|
||||
layout: LayoutBox | null;
|
||||
token_equivalent: number;
|
||||
}
|
||||
|
||||
export interface RetrievalHit {
|
||||
atom: EvidenceAtom;
|
||||
sparse_score: number;
|
||||
dense_score: number;
|
||||
graph_score: number;
|
||||
final_score: number;
|
||||
}
|
||||
|
||||
export interface AnswerResponse {
|
||||
answer: string;
|
||||
citations: string[];
|
||||
context: {
|
||||
hits: RetrievalHit[];
|
||||
token_equivalent: number;
|
||||
cache_trace_id: string;
|
||||
};
|
||||
verifier: {
|
||||
cited_atom_ids: string[];
|
||||
missing_atom_ids: string[];
|
||||
citation_accuracy: number;
|
||||
contradiction_notes: string[];
|
||||
confidence: number;
|
||||
};
|
||||
runtime_backend: string;
|
||||
}
|
||||
|
||||
export interface HashHopProof {
|
||||
proof_id: string;
|
||||
kind: string;
|
||||
hops: number;
|
||||
token_equivalent: number;
|
||||
query_id: string;
|
||||
expected_target_id: string;
|
||||
model_target_id: string | null;
|
||||
passed: boolean | null;
|
||||
artifacts: string[];
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface ProofCheck {
|
||||
name: string;
|
||||
requirement: string;
|
||||
status: 'passed' | 'failed';
|
||||
evidence: string[];
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export interface ProofSuiteReport {
|
||||
proof_id: string;
|
||||
cartridge_id: string;
|
||||
status: 'passed' | 'failed';
|
||||
created_at: string;
|
||||
checks: ProofCheck[];
|
||||
artifacts: Record<string, string>;
|
||||
dna_before: string | null;
|
||||
dna_after: string | null;
|
||||
}
|
||||
|
||||
export interface MemoryMap {
|
||||
atoms: EvidenceAtom[];
|
||||
layers: CacheLayerStatus[];
|
||||
cartridges: Array<{
|
||||
cartridge_id: string;
|
||||
name: string;
|
||||
token_equivalent: number;
|
||||
dna: string | null;
|
||||
}>;
|
||||
}
|
||||
Reference in new issue
Block a user