ltcai 4.6.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -193
- package/docs/CHANGELOG.md +78 -1
- package/docs/V4_6_0_LIVING_BRAIN_EXPERIENCE_REPORT.md +33 -19
- package/docs/V4_6_1_RELEASE_REFRESH_REPORT.md +42 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +12 -11
- package/frontend/src/App.tsx +657 -173
- package/frontend/src/components/BrainConversation.tsx +10 -2
- package/frontend/src/components/LivingBrain.tsx +197 -106
- package/frontend/src/components/ProductFlow.tsx +188 -130
- package/frontend/src/styles.css +1327 -36
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/package.json +1 -1
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +5 -5
- package/static/app/assets/index-7U86v70r.css +2 -0
- package/static/app/assets/index-D1jAPQws.js +16 -0
- package/static/app/assets/index-D1jAPQws.js.map +1 -0
- package/static/app/index.html +2 -2
- package/static/app/assets/index-By-G-Kay.css +0 -2
- package/static/app/assets/index-CJx6WuQH.js +0 -336
- package/static/app/assets/index-CJx6WuQH.js.map +0 -1
|
@@ -3,13 +3,21 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
|
3
3
|
import { ImagePlus, MessageSquare, Plus, Send, Trash2 } from "lucide-react";
|
|
4
4
|
import { latticeApi } from "@/api/client";
|
|
5
5
|
import { EmptyState, EntityList, SourceBadge, StructuredView } from "@/components/primitives";
|
|
6
|
-
import {
|
|
6
|
+
import { type BrainState, LivingBrain } from "@/components/LivingBrain";
|
|
7
7
|
import { Badge } from "@/components/ui/badge";
|
|
8
8
|
import { Button } from "@/components/ui/button";
|
|
9
9
|
import { Textarea } from "@/components/ui/textarea";
|
|
10
10
|
import { asArray } from "@/lib/utils";
|
|
11
11
|
|
|
12
12
|
type Msg = { role?: string; content?: string; timestamp?: string };
|
|
13
|
+
type BrainActivity = BrainState;
|
|
14
|
+
type BrainVitals = {
|
|
15
|
+
connected: boolean;
|
|
16
|
+
memories: number;
|
|
17
|
+
knowledge: number;
|
|
18
|
+
conversations: number;
|
|
19
|
+
model: string | null;
|
|
20
|
+
};
|
|
13
21
|
|
|
14
22
|
function fileToDataUrl(file: File) {
|
|
15
23
|
return new Promise<string>((resolve, reject) => {
|
|
@@ -139,7 +147,7 @@ export function BrainConversation({ className }: { className?: string }) {
|
|
|
139
147
|
<div className={className}>
|
|
140
148
|
<div className="brain-conversation-grid">
|
|
141
149
|
<section className="brain-presence-column" aria-label="Living Brain presence">
|
|
142
|
-
<LivingBrain
|
|
150
|
+
<LivingBrain state={activity} size="normal" />
|
|
143
151
|
</section>
|
|
144
152
|
|
|
145
153
|
<section className="brain-chat-panel premium-surface" aria-label="Conversation with Lattice Brain">
|
|
@@ -1,121 +1,212 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const activityLabels: Record<BrainActivity, string> = {
|
|
18
|
-
idle: "Present",
|
|
19
|
-
listening: "Listening",
|
|
20
|
-
recalling: "Recalling",
|
|
21
|
-
thinking: "Thinking",
|
|
22
|
-
planning: "Planning",
|
|
23
|
-
acting: "Acting",
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
function readable(value: BrainVitals[keyof BrainVitals]) {
|
|
27
|
-
if (value === null || value === undefined || value === "") return "-";
|
|
28
|
-
if (typeof value === "number") return fmtNumber(value);
|
|
29
|
-
return String(value);
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
|
|
4
|
+
export type BrainState = "idle" | "listening" | "thinking" | "recalling" | "synthesizing" | "planning" | "acting" | "resting";
|
|
5
|
+
|
|
6
|
+
export interface LivingBrainProps {
|
|
7
|
+
state?: BrainState;
|
|
8
|
+
intensity?: number; // 0-1 how "alive" it feels right now
|
|
9
|
+
onPulse?: () => void; // allow parent to trigger a memory pulse
|
|
10
|
+
size?: "normal" | "large" | "trace";
|
|
11
|
+
label?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
showLabel?: boolean;
|
|
14
|
+
depth?: number; // 0-5 progressive exploration depth; higher = more "open" / revealing
|
|
15
|
+
onInteract?: () => void; // called on click to advance exploration (travel deeper)
|
|
30
16
|
}
|
|
31
17
|
|
|
18
|
+
/**
|
|
19
|
+
* The Living Brain — the primary visual and emotional object in the product.
|
|
20
|
+
* It is not decoration. It is the other participant.
|
|
21
|
+
* It breathes. It reacts. It remembers.
|
|
22
|
+
*/
|
|
32
23
|
export function LivingBrain({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
state = "idle",
|
|
25
|
+
intensity = 0.6,
|
|
26
|
+
onPulse,
|
|
27
|
+
size = "large",
|
|
28
|
+
label,
|
|
37
29
|
className,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
30
|
+
showLabel = true,
|
|
31
|
+
depth = 0,
|
|
32
|
+
onInteract,
|
|
33
|
+
}: LivingBrainProps) {
|
|
34
|
+
const [isPulsing, setIsPulsing] = React.useState(false);
|
|
35
|
+
const organismRef = React.useRef<HTMLButtonElement>(null);
|
|
36
|
+
|
|
37
|
+
// External trigger for memory / important recall moments
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
if (onPulse) {
|
|
40
|
+
const handler = () => firePulse();
|
|
41
|
+
// allow global window event too for simplicity across components
|
|
42
|
+
window.addEventListener("brain:recall", handler as EventListener);
|
|
43
|
+
return () => window.removeEventListener("brain:recall", handler as EventListener);
|
|
44
|
+
}
|
|
45
|
+
}, [onPulse]);
|
|
46
|
+
|
|
47
|
+
function firePulse() {
|
|
48
|
+
setIsPulsing(true);
|
|
49
|
+
if (organismRef.current) {
|
|
50
|
+
organismRef.current.classList.add("pulse");
|
|
51
|
+
// clean after animation
|
|
52
|
+
window.setTimeout(() => {
|
|
53
|
+
if (organismRef.current) organismRef.current.classList.remove("pulse");
|
|
54
|
+
setIsPulsing(false);
|
|
55
|
+
}, 1350);
|
|
56
|
+
}
|
|
57
|
+
onPulse?.();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Auto gentle pulse when recalling or high intensity
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
if ((state === "recalling" || intensity > 0.82) && !isPulsing) {
|
|
63
|
+
const t = window.setTimeout(() => firePulse(), 180);
|
|
64
|
+
return () => clearTimeout(t);
|
|
65
|
+
}
|
|
66
|
+
}, [state, intensity]);
|
|
67
|
+
|
|
68
|
+
const dataState = state;
|
|
69
|
+
const isLarge = size === "large";
|
|
70
|
+
const isTrace = size === "trace";
|
|
71
|
+
|
|
72
|
+
const dynamicIntensity = Math.max(0.35, Math.min(1, intensity));
|
|
73
|
+
const effectiveDepth = Math.max(0, Math.min(5, depth || 0));
|
|
74
|
+
const canTravel = state !== "thinking";
|
|
75
|
+
|
|
76
|
+
const handleClick = () => {
|
|
77
|
+
if (!canTravel) return;
|
|
78
|
+
firePulse();
|
|
79
|
+
onInteract?.();
|
|
80
|
+
};
|
|
47
81
|
|
|
48
82
|
return (
|
|
49
|
-
<
|
|
50
|
-
className={cn(
|
|
51
|
-
|
|
52
|
-
|
|
83
|
+
<div
|
|
84
|
+
className={cn(
|
|
85
|
+
"brain-presence select-none",
|
|
86
|
+
isLarge && "large",
|
|
87
|
+
isTrace && "trace",
|
|
88
|
+
className,
|
|
89
|
+
effectiveDepth > 0 && "is-exploring"
|
|
90
|
+
)}
|
|
91
|
+
aria-label="Your living Brain"
|
|
92
|
+
role="group"
|
|
93
|
+
data-depth={effectiveDepth}
|
|
53
94
|
>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
{activity === "thinking" ? <Loader2 className="h-4 w-4 animate-spin" /> : <CircleDotDashed className="h-4 w-4" />}
|
|
89
|
-
<span>{state}</span>
|
|
95
|
+
<button
|
|
96
|
+
type="button"
|
|
97
|
+
ref={organismRef}
|
|
98
|
+
className={cn("brain-organism", `size-${size}`, `depth-${effectiveDepth}`)}
|
|
99
|
+
data-state={dataState}
|
|
100
|
+
aria-label={effectiveDepth < 5 ? "Travel deeper into your Brain" : "Rest inside the Knowledge Graph"}
|
|
101
|
+
aria-disabled={!canTravel}
|
|
102
|
+
style={{
|
|
103
|
+
transform: `scale(${0.96 + (dynamicIntensity - 0.5) * 0.09 + effectiveDepth * 0.015})`,
|
|
104
|
+
}}
|
|
105
|
+
onClick={handleClick}
|
|
106
|
+
title={effectiveDepth < 5 ? "Travel deeper into your Brain" : "The core of your knowledge"}
|
|
107
|
+
>
|
|
108
|
+
{/* Living anatomical presence. The glow opens with depth; the folds make it unmistakably a Brain. */}
|
|
109
|
+
<div className="brain-core" style={{ transform: `scale(${1 + effectiveDepth * 0.045})` }}>
|
|
110
|
+
<svg className="brain-anatomy" viewBox="0 0 220 174" aria-hidden>
|
|
111
|
+
<path
|
|
112
|
+
className="brain-lobe brain-lobe-left"
|
|
113
|
+
d="M102 30c-13-20-44-19-55 1-18 1-29 16-28 33-13 8-18 25-11 39-9 16-1 36 17 42 5 19 27 26 43 15 13 10 33 8 43-5 5-7 8-16 8-27V52c0-8-6-17-17-22Z"
|
|
114
|
+
/>
|
|
115
|
+
<path
|
|
116
|
+
className="brain-lobe brain-lobe-right"
|
|
117
|
+
d="M118 30c13-20 44-19 55 1 18 1 29 16 28 33 13 8 18 25 11 39 9 16 1 36-17 42-5 19-27 26-43 15-13 10-33 8-43-5-5-7-8-16-8-27V52c0-8 6-17 17-22Z"
|
|
118
|
+
/>
|
|
119
|
+
<path className="brain-bridge" d="M103 48c9-8 24-8 33 0 7 6 9 16 5 25-5 11-16 15-31 12-15 3-26-1-31-12-4-9-2-19 5-25 5-4 12-6 19 0Z" />
|
|
120
|
+
<path className="brain-stem" d="M92 137c10 9 26 9 36 0 1 14 7 25 20 33H76c12-8 17-19 16-33Z" />
|
|
121
|
+
<path className="brain-fold fold-a" d="M48 50c18-11 38-8 47 8" />
|
|
122
|
+
<path className="brain-fold fold-b" d="M34 82c22-8 45-5 58 8" />
|
|
123
|
+
<path className="brain-fold fold-c" d="M43 119c18 5 35 2 49-11" />
|
|
124
|
+
<path className="brain-fold fold-d" d="M172 50c-18-11-38-8-47 8" />
|
|
125
|
+
<path className="brain-fold fold-e" d="M186 82c-22-8-45-5-58 8" />
|
|
126
|
+
<path className="brain-fold fold-f" d="M177 119c-18 5-35 2-49-11" />
|
|
127
|
+
<path className="brain-fold fold-mid" d="M110 38c-5 30-5 70 0 112" />
|
|
128
|
+
</svg>
|
|
90
129
|
</div>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
130
|
+
|
|
131
|
+
{/* Breathing field expands as we go deeper. */}
|
|
132
|
+
<div
|
|
133
|
+
className="brain-aura"
|
|
134
|
+
style={{
|
|
135
|
+
animationDuration: state === "thinking" ? "1.65s" : state === "recalling" ? "2.4s" : "6.8s",
|
|
136
|
+
transform: `scale(${1 + effectiveDepth * 0.12})`,
|
|
137
|
+
opacity: 0.65 + effectiveDepth * 0.05
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
{/* Thought activity — increases and starts to "resolve" into structure at higher depths */}
|
|
142
|
+
<div className="thought-activity" aria-hidden>
|
|
143
|
+
{Array.from({ length: Math.min(12, 5 + effectiveDepth * 2) }).map((_, i) => (
|
|
144
|
+
<div
|
|
145
|
+
key={i}
|
|
146
|
+
className={cn("thought-particle", effectiveDepth >= 3 && "resolving")}
|
|
147
|
+
style={{
|
|
148
|
+
left: `${18 + ((i * 13 + effectiveDepth * 4) % 64)}%`,
|
|
149
|
+
top: `${22 + (i % 5) * 14}%`,
|
|
150
|
+
animationDelay: `-${i * 0.55 + (intensity * 1.1) - effectiveDepth * 0.2}s`,
|
|
151
|
+
animationDuration: `${2.8 + (1 - dynamicIntensity) * 1.6 - effectiveDepth * 0.15}s`,
|
|
152
|
+
}}
|
|
153
|
+
/>
|
|
154
|
+
))}
|
|
110
155
|
</div>
|
|
111
|
-
) : null}
|
|
112
156
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
|
|
157
|
+
{/* Memory ripples — more and stronger as depth increases (echoes surfacing) */}
|
|
158
|
+
{Array.from({ length: 1 + Math.floor(effectiveDepth / 1.5) }).map((_, i) => (
|
|
159
|
+
<div
|
|
160
|
+
key={i}
|
|
161
|
+
className="memory-ripple"
|
|
162
|
+
aria-hidden
|
|
163
|
+
style={{
|
|
164
|
+
inset: `${18 + i * 6}%`,
|
|
165
|
+
animationDelay: `${180 + i * 220}ms`,
|
|
166
|
+
opacity: 0.55 + effectiveDepth * 0.06
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
))}
|
|
170
|
+
|
|
171
|
+
{/* Relationship structure appears only near the deepest layers. */}
|
|
172
|
+
{effectiveDepth >= 4 && (
|
|
173
|
+
<svg className="brain-inner-structure" viewBox="0 0 100 100" aria-hidden>
|
|
174
|
+
<g stroke="hsl(var(--brain-core) / 0.35)" strokeWidth="0.6" fill="none">
|
|
175
|
+
<circle cx="50" cy="50" r="18" />
|
|
176
|
+
<circle cx="50" cy="50" r="28" />
|
|
177
|
+
<path d="M32 50 Q50 32 68 50" />
|
|
178
|
+
<path d="M32 50 Q50 68 68 50" />
|
|
179
|
+
</g>
|
|
180
|
+
</svg>
|
|
181
|
+
)}
|
|
182
|
+
</button>
|
|
183
|
+
|
|
184
|
+
{showLabel && !isTrace && (
|
|
185
|
+
<div className="brain-presence-label" data-state={state}>
|
|
186
|
+
<span className="dot" />
|
|
187
|
+
{label || (effectiveDepth > 0 ? `Depth ${effectiveDepth}` : humanState(state))}
|
|
117
188
|
</div>
|
|
118
189
|
)}
|
|
119
|
-
</
|
|
190
|
+
</div>
|
|
120
191
|
);
|
|
121
192
|
}
|
|
193
|
+
|
|
194
|
+
function humanState(s: BrainState) {
|
|
195
|
+
switch (s) {
|
|
196
|
+
case "listening": return "Listening";
|
|
197
|
+
case "thinking": return "Thinking with you";
|
|
198
|
+
case "recalling": return "Remembering";
|
|
199
|
+
case "synthesizing": return "Making sense";
|
|
200
|
+
case "planning": return "Planning";
|
|
201
|
+
case "acting": return "Acting";
|
|
202
|
+
case "resting": return "With you";
|
|
203
|
+
default: return "Here";
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Helper to broadcast recall pulses from anywhere (conversation, memory surface, etc)
|
|
208
|
+
export function triggerBrainRecall() {
|
|
209
|
+
if (typeof window !== "undefined") {
|
|
210
|
+
window.dispatchEvent(new CustomEvent("brain:recall"));
|
|
211
|
+
}
|
|
212
|
+
}
|