mop-agent 0.1.15 → 0.1.16
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 +13 -5
- package/apps/web/app/api/apps/route.ts +23 -0
- package/apps/web/app/api/chat/route.ts +26 -4
- package/apps/web/app/api/graph/route.ts +8 -3
- package/apps/web/app/assistant/page.tsx +14 -19
- package/apps/web/app/brain/graph/page.tsx +144 -28
- package/apps/web/app/brain/page.tsx +106 -104
- package/apps/web/app/globals.css +418 -2
- package/apps/web/app/settings/page.tsx +102 -1
- package/apps/web/components/AppShell.tsx +75 -17
- package/apps/web/components/ui/chatgpt-prompt-input.tsx +290 -0
- package/apps/web/components.json +18 -0
- package/apps/web/lib/channels/config.ts +48 -0
- package/apps/web/lib/channels/index.ts +8 -4
- package/apps/web/lib/db/migrate.ts +9 -0
- package/apps/web/lib/providers/anthropic.ts +20 -1
- package/apps/web/lib/providers/openrouter.ts +11 -1
- package/apps/web/lib/providers/types.ts +2 -1
- package/apps/web/package.json +6 -0
- package/apps/web/postcss.config.mjs +5 -0
- package/npm-shrinkwrap.json +1646 -222
- package/package.json +3 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
|
|
5
5
|
type Project = {
|
|
6
6
|
id: string;
|
|
@@ -10,160 +10,162 @@ type Project = {
|
|
|
10
10
|
artifactCount: number;
|
|
11
11
|
mopFlowVersion?: string;
|
|
12
12
|
};
|
|
13
|
-
|
|
14
13
|
type SemanticNote = { id: string; title: string; body: string; sourceProjects: string[]; confidence: number };
|
|
15
14
|
type Action = { id: string; projectId: string; tool: string; summary: string; status: string; error?: string };
|
|
16
15
|
|
|
17
16
|
export default function BrainPage() {
|
|
18
17
|
const [projects, setProjects] = useState<Project[]>([]);
|
|
19
|
-
const [code, setCode] = useState
|
|
18
|
+
const [code, setCode] = useState("");
|
|
20
19
|
const [notes, setNotes] = useState<SemanticNote[]>([]);
|
|
21
20
|
const [actions, setActions] = useState<Action[]>([]);
|
|
22
21
|
const [consolidating, setConsolidating] = useState(false);
|
|
23
22
|
const [consolidateMsg, setConsolidateMsg] = useState("");
|
|
24
23
|
|
|
24
|
+
const memoryTotal = useMemo(() => projects.reduce((total, project) => total + project.memoryCount, 0), [projects]);
|
|
25
|
+
const onlineTotal = useMemo(() => projects.filter((project) => project.status === "online").length, [projects]);
|
|
26
|
+
|
|
25
27
|
function loadNotes() {
|
|
26
|
-
fetch("/api/semantic").then((
|
|
28
|
+
fetch("/api/semantic").then((response) => response.json()).then((result) => setNotes(result.notes ?? [])).catch(() => {});
|
|
27
29
|
}
|
|
28
30
|
function loadActions() {
|
|
29
|
-
fetch("/api/actions").then((
|
|
31
|
+
fetch("/api/actions").then((response) => response.json()).then((result) => setActions(result.actions ?? [])).catch(() => {});
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
useEffect(() => {
|
|
33
35
|
const load = () => {
|
|
34
36
|
fetch("/api/projects")
|
|
35
|
-
.then((
|
|
36
|
-
.then((
|
|
37
|
+
.then((response) => response.json())
|
|
38
|
+
.then((result: { projects: Project[] }) => setProjects(result.projects ?? []))
|
|
37
39
|
.catch(() => {});
|
|
38
40
|
loadActions();
|
|
39
41
|
};
|
|
40
42
|
load();
|
|
41
43
|
loadNotes();
|
|
42
|
-
const
|
|
43
|
-
return () => clearInterval(
|
|
44
|
+
const timer = setInterval(load, 4000);
|
|
45
|
+
return () => clearInterval(timer);
|
|
44
46
|
}, []);
|
|
45
47
|
|
|
46
|
-
async function decide(id: string,
|
|
47
|
-
await fetch(`/api/actions/${id}/${
|
|
48
|
+
async function decide(id: string, decision: "approve" | "deny") {
|
|
49
|
+
await fetch(`/api/actions/${id}/${decision}`, { method: "POST" });
|
|
48
50
|
loadActions();
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
async function
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
setCode(
|
|
53
|
+
async function generateCode() {
|
|
54
|
+
const response = await fetch("/api/link/code", { method: "POST" });
|
|
55
|
+
const result = await response.json();
|
|
56
|
+
setCode(response.ok ? result.code : `error: ${result.error}`);
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
async function
|
|
59
|
+
async function consolidate() {
|
|
58
60
|
setConsolidating(true);
|
|
59
|
-
setConsolidateMsg("…");
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
setConsolidateMsg(
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
setConsolidateMsg("Consolidating project memory…");
|
|
62
|
+
const response = await fetch("/api/consolidate", { method: "POST" });
|
|
63
|
+
const result = await response.json();
|
|
64
|
+
setConsolidateMsg(response.ok
|
|
65
|
+
? `${result.scanned} memories scanned · ${result.notesCreated} patterns promoted`
|
|
66
|
+
: `Unable to consolidate: ${result.error}`);
|
|
65
67
|
setConsolidating(false);
|
|
66
68
|
loadNotes();
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
return (
|
|
70
|
-
<main className="mop-page">
|
|
71
|
-
<header className="mop-page-heading">
|
|
72
|
+
<main className="mop-page mop-brain-page">
|
|
73
|
+
<header className="mop-page-heading mop-brain-heading">
|
|
72
74
|
<div>
|
|
73
|
-
<p className="mop-page-kicker">
|
|
75
|
+
<p className="mop-page-kicker">MEMORY WORKSPACE</p>
|
|
74
76
|
<h1>Brain</h1>
|
|
75
|
-
<p>Main Brain
|
|
77
|
+
<p>Main Brain is the shared memory core. Projects feed it context, patterns and skills.</p>
|
|
76
78
|
</div>
|
|
77
|
-
<a href="/brain/graph"
|
|
79
|
+
<a href="/brain/graph" className="mop-primary-link">GRAPH VIEW <span>↗</span></a>
|
|
78
80
|
</header>
|
|
79
81
|
|
|
80
|
-
<
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
<section className="mop-main-brain mop-panel">
|
|
83
|
+
<div className="mop-main-brain-orbit" aria-hidden="true">
|
|
84
|
+
<span className="mop-main-brain-core">M</span>
|
|
85
|
+
<i /><i /><i />
|
|
86
|
+
</div>
|
|
87
|
+
<div className="mop-main-brain-copy">
|
|
88
|
+
<p className="mop-page-kicker">PRIMARY KNOWLEDGE LAYER</p>
|
|
89
|
+
<h2>Main Brain</h2>
|
|
90
|
+
<p>Semantic memory shared across every conversation and linked project. Consolidation promotes recurring episodic knowledge into this core.</p>
|
|
91
|
+
<div className="mop-main-brain-actions">
|
|
92
|
+
<button type="button" onClick={consolidate} disabled={consolidating}>{consolidating ? "CONSOLIDATING…" : "⟳ CONSOLIDATE MEMORY"}</button>
|
|
93
|
+
<a href="/brain/graph">Explore connections →</a>
|
|
94
|
+
</div>
|
|
95
|
+
{consolidateMsg && <p className="mop-brain-message">{consolidateMsg}</p>}
|
|
96
|
+
</div>
|
|
97
|
+
<div className="mop-main-brain-stats">
|
|
98
|
+
<div><strong>{notes.length}</strong><span>Semantic patterns</span></div>
|
|
99
|
+
<div><strong>{memoryTotal}</strong><span>Project memories</span></div>
|
|
100
|
+
<div><strong>{onlineTotal}/{projects.length}</strong><span>Projects online</span></div>
|
|
101
|
+
</div>
|
|
102
|
+
</section>
|
|
88
103
|
|
|
89
|
-
<section className="mop-panel"
|
|
90
|
-
<div
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
{consolidating ? "consolidating…" : "⟳ Consolidate"}
|
|
94
|
-
</button>
|
|
95
|
-
{consolidateMsg && <span style={{ opacity: 0.65, fontSize: 13 }}>{consolidateMsg}</span>}
|
|
104
|
+
<section className="mop-brain-linker mop-panel">
|
|
105
|
+
<div>
|
|
106
|
+
<strong>Connect another project</strong>
|
|
107
|
+
<span>Generate a one-time pairing code for MOP-FLOW.</span>
|
|
96
108
|
</div>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{notes.length === 0 ? (
|
|
101
|
-
<p style={{ opacity: 0.5, fontSize: 13 }}>No patterns yet — link projects, then Consolidate.</p>
|
|
102
|
-
) : (
|
|
103
|
-
<ul style={{ listStyle: "none", padding: 0, margin: 0 }}>
|
|
104
|
-
{notes.map((n) => (
|
|
105
|
-
<li key={n.id} style={{ padding: "8px 0", borderTop: "1px solid #14202e" }}>
|
|
106
|
-
<strong>{n.title}</strong>{" "}
|
|
107
|
-
<span style={{ opacity: 0.5, fontSize: 12 }}>
|
|
108
|
-
· {n.confidence}% · {n.sourceProjects.length} project(s)
|
|
109
|
-
</span>
|
|
110
|
-
<div style={{ opacity: 0.65, fontSize: 13, marginTop: 2 }}>{n.body}</div>
|
|
111
|
-
</li>
|
|
112
|
-
))}
|
|
113
|
-
</ul>
|
|
109
|
+
<button type="button" onClick={generateCode}>+ LINK PROJECT</button>
|
|
110
|
+
{code && (
|
|
111
|
+
<code>mop-flow-dev link --url {typeof window !== "undefined" ? window.location.origin : ""} --code {code} --project <id></code>
|
|
114
112
|
)}
|
|
115
113
|
</section>
|
|
116
114
|
|
|
115
|
+
<div className="mop-brain-columns">
|
|
116
|
+
<section className="mop-panel mop-brain-section">
|
|
117
|
+
<header>
|
|
118
|
+
<div><p className="mop-page-kicker">SEMANTIC MEMORY</p><h2>Knowledge patterns</h2></div>
|
|
119
|
+
<span>{notes.length}</span>
|
|
120
|
+
</header>
|
|
121
|
+
{notes.length === 0 ? (
|
|
122
|
+
<div className="mop-brain-empty"><strong>No patterns yet</strong><p>Link projects and consolidate memory to grow Main Brain.</p></div>
|
|
123
|
+
) : (
|
|
124
|
+
<ul className="mop-brain-note-list">
|
|
125
|
+
{notes.map((note) => (
|
|
126
|
+
<li key={note.id}>
|
|
127
|
+
<span className="mop-brain-note-dot" />
|
|
128
|
+
<div><strong>{note.title}</strong><p>{note.body}</p><small>{note.confidence}% confidence · {note.sourceProjects.length} sources</small></div>
|
|
129
|
+
</li>
|
|
130
|
+
))}
|
|
131
|
+
</ul>
|
|
132
|
+
)}
|
|
133
|
+
</section>
|
|
134
|
+
|
|
135
|
+
<section className="mop-panel mop-brain-section">
|
|
136
|
+
<header>
|
|
137
|
+
<div><p className="mop-page-kicker">CONNECTED CONTEXT</p><h2>Projects</h2></div>
|
|
138
|
+
<span>{projects.length}</span>
|
|
139
|
+
</header>
|
|
140
|
+
{projects.length === 0 ? (
|
|
141
|
+
<div className="mop-brain-empty"><strong>No linked projects</strong><p>Use Link Project above to connect the first memory source.</p></div>
|
|
142
|
+
) : (
|
|
143
|
+
<ul className="mop-brain-project-list">
|
|
144
|
+
{projects.map((project) => (
|
|
145
|
+
<li key={project.id}>
|
|
146
|
+
<span className={`mop-project-status is-${project.status}`} />
|
|
147
|
+
<div><a href={`/brain/${project.id}`}>{project.name}</a><small>{project.memoryCount} memories · {project.artifactCount} artifacts</small></div>
|
|
148
|
+
<a href={`/chat/${project.id}`}>CHAT →</a>
|
|
149
|
+
</li>
|
|
150
|
+
))}
|
|
151
|
+
</ul>
|
|
152
|
+
)}
|
|
153
|
+
</section>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
117
156
|
{actions.length > 0 && (
|
|
118
|
-
<section
|
|
119
|
-
<
|
|
120
|
-
<ul
|
|
121
|
-
{actions.map((
|
|
122
|
-
<li key={
|
|
123
|
-
<code
|
|
124
|
-
<
|
|
125
|
-
{a.status === "pending" && (
|
|
126
|
-
<span style={{ float: "right" }}>
|
|
127
|
-
<button onClick={() => decide(a.id, "approve")} style={{ ...btn, padding: "4px 10px", background: "#2d4a3e", borderColor: "#2d4a3e" }}>Approve</button>{" "}
|
|
128
|
-
<button onClick={() => decide(a.id, "deny")} style={{ ...btn, padding: "4px 10px", background: "#742220", borderColor: "#742220" }}>Deny</button>
|
|
129
|
-
</span>
|
|
130
|
-
)}
|
|
157
|
+
<section className="mop-panel mop-brain-approvals">
|
|
158
|
+
<header><div><p className="mop-page-kicker">HUMAN GATE</p><h2>Pending actions</h2></div><span>{actions.filter((action) => action.status === "pending").length} pending</span></header>
|
|
159
|
+
<ul>
|
|
160
|
+
{actions.map((action) => (
|
|
161
|
+
<li key={action.id}>
|
|
162
|
+
<div><code>{action.tool}</code><strong>{action.summary}</strong><small>{action.projectId} · {action.status}{action.error ? ` · ${action.error}` : ""}</small></div>
|
|
163
|
+
{action.status === "pending" && <div><button type="button" onClick={() => decide(action.id, "approve")}>APPROVE</button><button type="button" onClick={() => decide(action.id, "deny")}>DENY</button></div>}
|
|
131
164
|
</li>
|
|
132
165
|
))}
|
|
133
166
|
</ul>
|
|
134
167
|
</section>
|
|
135
168
|
)}
|
|
136
|
-
|
|
137
|
-
<h2 style={{ fontSize: 16, opacity: 0.8 }}>Projects ({projects.length})</h2>
|
|
138
|
-
{projects.length === 0 && <p style={{ opacity: 0.5 }}>No projects linked yet.</p>}
|
|
139
|
-
<ul style={{ listStyle: "none", padding: 0 }}>
|
|
140
|
-
{projects.map((p) => (
|
|
141
|
-
<li key={p.id} style={card}>
|
|
142
|
-
<a href={`/brain/${p.id}`} style={{ color: "#742220", textDecoration: "none", fontWeight: 600 }}>
|
|
143
|
-
{p.name}
|
|
144
|
-
</a>
|
|
145
|
-
<span style={{ opacity: 0.6, marginLeft: 8 }}>
|
|
146
|
-
{p.status === "online" ? "🟢 online" : "⚪ offline"} · {p.memoryCount} memories · {p.artifactCount} artifacts
|
|
147
|
-
</span>
|
|
148
|
-
<a href={`/chat/${p.id}`} style={{ float: "right", color: "#742220" }}>chat →</a>
|
|
149
|
-
</li>
|
|
150
|
-
))}
|
|
151
|
-
</ul>
|
|
152
169
|
</main>
|
|
153
170
|
);
|
|
154
171
|
}
|
|
155
|
-
|
|
156
|
-
const card: React.CSSProperties = {
|
|
157
|
-
border: "1px solid rgba(45,74,62,.28)",
|
|
158
|
-
borderRadius: 8,
|
|
159
|
-
padding: "12px 16px",
|
|
160
|
-
marginBottom: 8,
|
|
161
|
-
};
|
|
162
|
-
const btn: React.CSSProperties = {
|
|
163
|
-
padding: "8px 14px",
|
|
164
|
-
borderRadius: 8,
|
|
165
|
-
border: "1px solid #742220",
|
|
166
|
-
background: "#742220",
|
|
167
|
-
color: "#fef9e1",
|
|
168
|
-
cursor: "pointer",
|
|
169
|
-
};
|