more-compute 0.4.4__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- frontend/app/globals.css +734 -27
- frontend/app/layout.tsx +13 -3
- frontend/components/Notebook.tsx +2 -14
- frontend/components/cell/MonacoCell.tsx +99 -5
- frontend/components/layout/Sidebar.tsx +39 -4
- frontend/components/panels/ClaudePanel.tsx +461 -0
- frontend/components/popups/ComputePopup.tsx +738 -447
- frontend/components/popups/FilterPopup.tsx +305 -189
- frontend/components/popups/MetricsPopup.tsx +20 -1
- frontend/components/popups/ProviderConfigModal.tsx +322 -0
- frontend/components/popups/ProviderDropdown.tsx +398 -0
- frontend/components/popups/SettingsPopup.tsx +1 -1
- frontend/contexts/ClaudeContext.tsx +392 -0
- frontend/contexts/PodWebSocketContext.tsx +16 -21
- frontend/hooks/useInlineDiff.ts +269 -0
- frontend/lib/api.ts +323 -12
- frontend/lib/settings.ts +5 -0
- frontend/lib/websocket-native.ts +4 -8
- frontend/lib/websocket.ts +1 -2
- frontend/package-lock.json +733 -36
- frontend/package.json +2 -0
- frontend/public/assets/icons/providers/lambda_labs.svg +22 -0
- frontend/public/assets/icons/providers/prime_intellect.svg +18 -0
- frontend/public/assets/icons/providers/runpod.svg +9 -0
- frontend/public/assets/icons/providers/vastai.svg +1 -0
- frontend/settings.md +54 -0
- frontend/tsconfig.tsbuildinfo +1 -0
- frontend/types/claude.ts +194 -0
- kernel_run.py +13 -0
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/METADATA +53 -11
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/RECORD +56 -37
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/WHEEL +1 -1
- morecompute/__init__.py +1 -1
- morecompute/__version__.py +1 -1
- morecompute/execution/executor.py +24 -67
- morecompute/execution/worker.py +6 -72
- morecompute/models/api_models.py +62 -0
- morecompute/notebook.py +11 -0
- morecompute/server.py +641 -133
- morecompute/services/claude_service.py +392 -0
- morecompute/services/pod_manager.py +168 -67
- morecompute/services/pod_monitor.py +67 -39
- morecompute/services/prime_intellect.py +0 -4
- morecompute/services/providers/__init__.py +92 -0
- morecompute/services/providers/base_provider.py +336 -0
- morecompute/services/providers/lambda_labs_provider.py +394 -0
- morecompute/services/providers/provider_factory.py +194 -0
- morecompute/services/providers/runpod_provider.py +504 -0
- morecompute/services/providers/vastai_provider.py +407 -0
- morecompute/utils/cell_magics.py +0 -3
- morecompute/utils/config_util.py +93 -3
- morecompute/utils/special_commands.py +5 -32
- morecompute/utils/version_check.py +117 -0
- frontend/styling_README.md +0 -23
- {more_compute-0.4.4.dist-info/licenses → more_compute-0.5.0.dist-info}/LICENSE +0 -0
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/entry_points.txt +0 -0
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/top_level.txt +0 -0
frontend/app/layout.tsx
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
PodWebSocketProvider,
|
|
15
15
|
usePodWebSocket,
|
|
16
16
|
} from "@/contexts/PodWebSocketContext";
|
|
17
|
+
import { ClaudeProvider, useClaude } from "@/contexts/ClaudeContext";
|
|
18
|
+
import ClaudePanel from "@/components/panels/ClaudePanel";
|
|
17
19
|
import { loadSettings, applyTheme, type NotebookSettings } from "@/lib/settings";
|
|
18
20
|
import { fetchMetrics, type MetricsSnapshot } from "@/lib/api";
|
|
19
21
|
import "./globals.css";
|
|
@@ -25,6 +27,7 @@ function AppContent({ children }: { children: React.ReactNode }) {
|
|
|
25
27
|
const [activePopup, setActivePopup] = useState<string | null>(null);
|
|
26
28
|
const [showRestartModal, setShowRestartModal] = useState(false);
|
|
27
29
|
const { connectionState, gpuPods, connectingPodId } = usePodWebSocket();
|
|
30
|
+
const { isPanelOpen: isClaudePanelOpen } = useClaude();
|
|
28
31
|
|
|
29
32
|
// Persistent metrics collection
|
|
30
33
|
const [metricsHistory, setMetricsHistory] = useState<MetricsSnapshot[]>([]);
|
|
@@ -74,7 +77,6 @@ function AppContent({ children }: { children: React.ReactNode }) {
|
|
|
74
77
|
}, [appSettings.metricsCollectionMode]);
|
|
75
78
|
|
|
76
79
|
const handleSettingsChange = (settings: NotebookSettings) => {
|
|
77
|
-
console.log("Settings updated:", settings);
|
|
78
80
|
setAppSettings(settings);
|
|
79
81
|
};
|
|
80
82
|
|
|
@@ -213,7 +215,13 @@ function AppContent({ children }: { children: React.ReactNode }) {
|
|
|
213
215
|
</span>
|
|
214
216
|
</div>
|
|
215
217
|
</div>
|
|
216
|
-
<div
|
|
218
|
+
<div
|
|
219
|
+
className="main-content"
|
|
220
|
+
style={{ marginRight: isClaudePanelOpen ? '400px' : '0' }}
|
|
221
|
+
>
|
|
222
|
+
{children}
|
|
223
|
+
</div>
|
|
224
|
+
<ClaudePanel />
|
|
217
225
|
<div style={{ display: "none" }}>
|
|
218
226
|
<span id="connection-status">Connected</span>
|
|
219
227
|
<span id="kernel-status">Ready</span>
|
|
@@ -267,7 +275,9 @@ export default function RootLayout({
|
|
|
267
275
|
</head>
|
|
268
276
|
<body data-notebook-path={notebookPath} data-notebook-root={notebookRoot}>
|
|
269
277
|
<PodWebSocketProvider>
|
|
270
|
-
<
|
|
278
|
+
<ClaudeProvider>
|
|
279
|
+
<AppContent>{children}</AppContent>
|
|
280
|
+
</ClaudeProvider>
|
|
271
281
|
</PodWebSocketProvider>
|
|
272
282
|
<Script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js" />
|
|
273
283
|
<Script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/python/python.min.js" />
|
frontend/components/Notebook.tsx
CHANGED
|
@@ -277,13 +277,9 @@ function notebookReducer(
|
|
|
277
277
|
const payload = action.payload || {};
|
|
278
278
|
const cell_index = payload.cell_index;
|
|
279
279
|
|
|
280
|
-
console.log(`[EXECUTION_COMPLETE] Processing completion for cell ${cell_index}`, payload);
|
|
281
|
-
|
|
282
280
|
// Support both shapes: { result: {...} } and flat payload {...}
|
|
283
281
|
const result = payload && payload.result ? payload.result : payload || {};
|
|
284
282
|
|
|
285
|
-
console.log(`[EXECUTION_COMPLETE] result.status=${result.status}, result.error=`, result.error);
|
|
286
|
-
|
|
287
283
|
// ALWAYS remove cell from executingCells when completion arrives
|
|
288
284
|
const newExecuting = new Set(state.executingCells);
|
|
289
285
|
newExecuting.delete(cell_index);
|
|
@@ -319,8 +315,6 @@ function notebookReducer(
|
|
|
319
315
|
case "EXECUTION_ERROR": {
|
|
320
316
|
const { cell_index, error } = action.payload;
|
|
321
317
|
|
|
322
|
-
console.log(`[EXECUTION_ERROR] Processing error for cell ${cell_index}`);
|
|
323
|
-
|
|
324
318
|
// ALWAYS remove cell from executingCells when error arrives
|
|
325
319
|
const newExecuting = new Set(state.executingCells);
|
|
326
320
|
newExecuting.delete(cell_index);
|
|
@@ -361,7 +355,7 @@ function notebookReducer(
|
|
|
361
355
|
...cell,
|
|
362
356
|
outputs: [],
|
|
363
357
|
execution_count: null,
|
|
364
|
-
execution_time:
|
|
358
|
+
execution_time: undefined,
|
|
365
359
|
error: null,
|
|
366
360
|
})),
|
|
367
361
|
};
|
|
@@ -400,10 +394,6 @@ export const Notebook: React.FC<NotebookProps> = ({
|
|
|
400
394
|
const deletionQueueRef = useRef<DeletedCell[]>([]);
|
|
401
395
|
const [showUndoHint, setShowUndoHint] = useState(false);
|
|
402
396
|
|
|
403
|
-
// DEBUG: Verify new code is loaded
|
|
404
|
-
useEffect(() => {
|
|
405
|
-
console.log("✅ NEW NOTEBOOK CODE LOADED - Undo functionality available");
|
|
406
|
-
}, []);
|
|
407
397
|
|
|
408
398
|
useEffect(() => {
|
|
409
399
|
const body = document.body;
|
|
@@ -454,10 +444,9 @@ export const Notebook: React.FC<NotebookProps> = ({
|
|
|
454
444
|
dispatch({ type: "RESET_KERNEL" });
|
|
455
445
|
}, []);
|
|
456
446
|
|
|
457
|
-
const handleHeartbeat = useCallback((
|
|
447
|
+
const handleHeartbeat = useCallback((_data: any) => {
|
|
458
448
|
// Heartbeat received - execution still in progress
|
|
459
449
|
// Cell spinner already showing via executingCells set
|
|
460
|
-
console.log("[Heartbeat]", data?.message || "Execution in progress");
|
|
461
450
|
}, []);
|
|
462
451
|
|
|
463
452
|
const handleKernelStatusUpdate = useCallback(
|
|
@@ -599,7 +588,6 @@ export const Notebook: React.FC<NotebookProps> = ({
|
|
|
599
588
|
const undoDelete = useCallback(() => {
|
|
600
589
|
const deletedCell = deletionQueueRef.current.shift(); // Get most recent deletion
|
|
601
590
|
if (!deletedCell) {
|
|
602
|
-
console.log("No deletions to undo");
|
|
603
591
|
return;
|
|
604
592
|
}
|
|
605
593
|
|
|
@@ -18,7 +18,9 @@ import {
|
|
|
18
18
|
} from "@radix-ui/react-icons";
|
|
19
19
|
import { Check, X } from "lucide-react";
|
|
20
20
|
import { loadMonacoThemes } from "@/lib/monaco-themes";
|
|
21
|
-
import { loadSettings } from "@/lib/settings";
|
|
21
|
+
import { loadSettings, type NotebookSettings } from "@/lib/settings";
|
|
22
|
+
import { useClaude } from "@/contexts/ClaudeContext";
|
|
23
|
+
import { useInlineDiff } from "@/hooks/useInlineDiff";
|
|
22
24
|
|
|
23
25
|
interface CellProps {
|
|
24
26
|
cell: CellType;
|
|
@@ -230,6 +232,10 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
230
232
|
const disposablesRef = useRef<monaco.IDisposable[]>([]);
|
|
231
233
|
const isUnmountingRef = useRef(false);
|
|
232
234
|
|
|
235
|
+
// Claude AI integration
|
|
236
|
+
const { pendingEdits, applyEdit, rejectEdit } = useClaude();
|
|
237
|
+
const pendingEdit = pendingEdits.get(index);
|
|
238
|
+
|
|
233
239
|
const [isEditing, setIsEditing] = useState(
|
|
234
240
|
() => cell.cell_type === "code" || !cell.source?.trim()
|
|
235
241
|
);
|
|
@@ -237,6 +243,93 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
237
243
|
cell.execution_time ?? null
|
|
238
244
|
);
|
|
239
245
|
|
|
246
|
+
// Track if we've applied the pending edit preview
|
|
247
|
+
const appliedEditIdRef = useRef<string | null>(null);
|
|
248
|
+
const originalCodeRef = useRef<string | null>(null);
|
|
249
|
+
const isApplyingPreviewRef = useRef(false);
|
|
250
|
+
|
|
251
|
+
// Handle pending edit: show new code in editor (only if claudeAutoPreview is enabled)
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
const editor = editorRef.current;
|
|
254
|
+
if (!editor) return;
|
|
255
|
+
|
|
256
|
+
const model = editor.getModel();
|
|
257
|
+
if (!model) return;
|
|
258
|
+
|
|
259
|
+
// Check if auto-preview is enabled in settings
|
|
260
|
+
const settings = loadSettings();
|
|
261
|
+
const autoPreviewEnabled = settings.claudeAutoPreview;
|
|
262
|
+
|
|
263
|
+
if (pendingEdit && pendingEdit.status === "pending" && autoPreviewEnabled) {
|
|
264
|
+
// Only apply if we haven't already applied this edit's preview
|
|
265
|
+
if (appliedEditIdRef.current !== pendingEdit.id) {
|
|
266
|
+
// Store original code for reverting
|
|
267
|
+
originalCodeRef.current = model.getValue();
|
|
268
|
+
// Update editor to show new code (skip the onUpdate callback)
|
|
269
|
+
const currentValue = model.getValue();
|
|
270
|
+
if (currentValue !== pendingEdit.newCode) {
|
|
271
|
+
isApplyingPreviewRef.current = true;
|
|
272
|
+
model.setValue(pendingEdit.newCode);
|
|
273
|
+
isApplyingPreviewRef.current = false;
|
|
274
|
+
}
|
|
275
|
+
appliedEditIdRef.current = pendingEdit.id;
|
|
276
|
+
}
|
|
277
|
+
} else if (appliedEditIdRef.current && !pendingEdit) {
|
|
278
|
+
// Edit was rejected or cleared - restore original if we have it
|
|
279
|
+
// Note: If applied, the notebook update will sync the content anyway
|
|
280
|
+
appliedEditIdRef.current = null;
|
|
281
|
+
originalCodeRef.current = null;
|
|
282
|
+
}
|
|
283
|
+
}, [pendingEdit]);
|
|
284
|
+
|
|
285
|
+
// Custom handlers for diff that restore original on reject
|
|
286
|
+
const handleApplyEdit = useCallback((editId: string) => {
|
|
287
|
+
appliedEditIdRef.current = null;
|
|
288
|
+
originalCodeRef.current = null;
|
|
289
|
+
applyEdit(editId);
|
|
290
|
+
}, [applyEdit]);
|
|
291
|
+
|
|
292
|
+
const handleRejectEdit = useCallback((editId: string) => {
|
|
293
|
+
const editor = editorRef.current;
|
|
294
|
+
const model = editor?.getModel();
|
|
295
|
+
|
|
296
|
+
// Restore original code before rejecting
|
|
297
|
+
if (model && originalCodeRef.current !== null) {
|
|
298
|
+
const original = originalCodeRef.current;
|
|
299
|
+
// Clear refs before setting value to prevent re-triggering preview
|
|
300
|
+
appliedEditIdRef.current = null;
|
|
301
|
+
originalCodeRef.current = null;
|
|
302
|
+
// Restore original - we DO want to trigger onUpdate here to sync state
|
|
303
|
+
model.setValue(original);
|
|
304
|
+
} else {
|
|
305
|
+
appliedEditIdRef.current = null;
|
|
306
|
+
originalCodeRef.current = null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
rejectEdit(editId);
|
|
310
|
+
}, [rejectEdit]);
|
|
311
|
+
|
|
312
|
+
// Check if auto-preview is enabled (for diff decorations)
|
|
313
|
+
const [autoPreviewEnabled, setAutoPreviewEnabled] = useState(() => loadSettings().claudeAutoPreview);
|
|
314
|
+
|
|
315
|
+
// Listen for settings changes
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
const handleSettingsChange = () => {
|
|
318
|
+
setAutoPreviewEnabled(loadSettings().claudeAutoPreview);
|
|
319
|
+
};
|
|
320
|
+
window.addEventListener('storage', handleSettingsChange);
|
|
321
|
+
return () => window.removeEventListener('storage', handleSettingsChange);
|
|
322
|
+
}, []);
|
|
323
|
+
|
|
324
|
+
// Inline diff for Claude AI edits (only when auto-preview is enabled)
|
|
325
|
+
const { hasDiff } = useInlineDiff({
|
|
326
|
+
editor: editorRef.current,
|
|
327
|
+
cellIndex: index,
|
|
328
|
+
pendingEdit: autoPreviewEnabled ? pendingEdit : undefined, // Only pass edit if auto-preview enabled
|
|
329
|
+
onApply: handleApplyEdit,
|
|
330
|
+
onReject: handleRejectEdit,
|
|
331
|
+
});
|
|
332
|
+
|
|
240
333
|
// ============================================================================
|
|
241
334
|
// UTILITIES
|
|
242
335
|
// ============================================================================
|
|
@@ -359,7 +452,8 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
359
452
|
|
|
360
453
|
// Handle content changes
|
|
361
454
|
const changeDisposable = editor.onDidChangeModelContent(() => {
|
|
362
|
-
|
|
455
|
+
// Skip update during preview application or unmounting
|
|
456
|
+
if (!isUnmountingRef.current && !isApplyingPreviewRef.current) {
|
|
363
457
|
onUpdate(indexRef.current, editor.getValue());
|
|
364
458
|
}
|
|
365
459
|
});
|
|
@@ -577,7 +671,7 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
577
671
|
|
|
578
672
|
{/* Main Cell Container */}
|
|
579
673
|
<div
|
|
580
|
-
className={`cell ${isActive ? "active" : ""} ${isExecuting ? "executing" : ""} ${isMarkdownWithContent ? "markdown-display-mode" : ""}`}
|
|
674
|
+
className={`cell ${isActive ? "active" : ""} ${isExecuting ? "executing" : ""} ${isMarkdownWithContent ? "markdown-display-mode" : ""} ${hasDiff ? "has-pending-diff" : ""}`}
|
|
581
675
|
data-cell-index={index}
|
|
582
676
|
>
|
|
583
677
|
{/* Hover Controls */}
|
|
@@ -687,7 +781,7 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
687
781
|
},
|
|
688
782
|
contextmenu: true,
|
|
689
783
|
folding: cell.cell_type === "code",
|
|
690
|
-
glyphMargin:
|
|
784
|
+
glyphMargin: hasDiff,
|
|
691
785
|
lineDecorationsWidth: 0,
|
|
692
786
|
lineNumbersMinChars: 3,
|
|
693
787
|
renderLineHighlight: "none", // Remove grey rectangle
|
|
@@ -698,7 +792,7 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
698
792
|
overviewRulerBorder: false,
|
|
699
793
|
overviewRulerLanes: 0,
|
|
700
794
|
// NOTE: fixedOverflowWidgets has known positioning bugs in 2024 - disabled
|
|
701
|
-
padding: { top: 8, bottom: 8
|
|
795
|
+
padding: { top: 8, bottom: 8 }, // All padding managed by Monaco
|
|
702
796
|
scrollbar: {
|
|
703
797
|
vertical: "auto",
|
|
704
798
|
horizontal: "auto",
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Folder,
|
|
4
|
+
Package,
|
|
5
|
+
Cpu,
|
|
6
|
+
Settings,
|
|
7
|
+
ChartArea,
|
|
8
|
+
Sparkles,
|
|
9
|
+
} from "lucide-react";
|
|
10
|
+
import { useClaude } from "@/contexts/ClaudeContext";
|
|
3
11
|
|
|
4
12
|
interface SidebarItemData {
|
|
5
13
|
id: string;
|
|
@@ -12,6 +20,7 @@ const sidebarItems: SidebarItemData[] = [
|
|
|
12
20
|
{ id: "packages", icon: <Package size={16} />, tooltip: "Packages" },
|
|
13
21
|
{ id: "compute", icon: <Cpu size={16} />, tooltip: "Compute" },
|
|
14
22
|
{ id: "metrics", icon: <ChartArea size={16} />, tooltip: "Metrics" },
|
|
23
|
+
{ id: "claude", icon: <Sparkles size={16} />, tooltip: "Claude" },
|
|
15
24
|
{ id: "settings", icon: <Settings size={16} />, tooltip: "Settings" },
|
|
16
25
|
];
|
|
17
26
|
|
|
@@ -21,7 +30,33 @@ interface SidebarProps {
|
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
const Sidebar: React.FC<SidebarProps> = ({ onTogglePopup, activePopup }) => {
|
|
24
|
-
const
|
|
33
|
+
const { isPanelOpen: isClaudePanelOpen, togglePanel: toggleClaudePanel } =
|
|
34
|
+
useClaude();
|
|
35
|
+
|
|
36
|
+
// Calculate active index, considering Claude panel state
|
|
37
|
+
const getActiveIndex = () => {
|
|
38
|
+
if (isClaudePanelOpen) {
|
|
39
|
+
return sidebarItems.findIndex((item) => item.id === "claude");
|
|
40
|
+
}
|
|
41
|
+
return sidebarItems.findIndex((item) => item.id === activePopup);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const activeIndex = getActiveIndex();
|
|
45
|
+
|
|
46
|
+
const handleItemClick = (itemId: string) => {
|
|
47
|
+
if (itemId === "claude") {
|
|
48
|
+
toggleClaudePanel();
|
|
49
|
+
} else {
|
|
50
|
+
onTogglePopup(itemId);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const isItemActive = (itemId: string) => {
|
|
55
|
+
if (itemId === "claude") {
|
|
56
|
+
return isClaudePanelOpen;
|
|
57
|
+
}
|
|
58
|
+
return activePopup === itemId;
|
|
59
|
+
};
|
|
25
60
|
|
|
26
61
|
return (
|
|
27
62
|
<div id="sidebar" className="sidebar">
|
|
@@ -36,9 +71,9 @@ const Sidebar: React.FC<SidebarProps> = ({ onTogglePopup, activePopup }) => {
|
|
|
36
71
|
{sidebarItems.map((item) => (
|
|
37
72
|
<div
|
|
38
73
|
key={item.id}
|
|
39
|
-
className={`sidebar-item ${
|
|
74
|
+
className={`sidebar-item ${isItemActive(item.id) ? "active" : ""} ${item.id === "claude" ? "claude-item" : ""}`}
|
|
40
75
|
data-popup={item.id}
|
|
41
|
-
onClick={() =>
|
|
76
|
+
onClick={() => handleItemClick(item.id)}
|
|
42
77
|
>
|
|
43
78
|
<span className="sidebar-icon-wrapper">{item.icon}</span>
|
|
44
79
|
<div className="sidebar-tooltip">{item.tooltip}</div>
|