@polderlabs/bizar 5.0.0 → 5.0.2
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/bizar-dash/dist/assets/{icons-CFqu2M-c.js → icons-Bo0iH9EC.js} +166 -121
- package/bizar-dash/dist/assets/icons-Bo0iH9EC.js.map +1 -0
- package/bizar-dash/dist/assets/main-C1cpttnv.js +19 -0
- package/bizar-dash/dist/assets/main-C1cpttnv.js.map +1 -0
- package/bizar-dash/dist/assets/main-DTkNlLrw.css +1 -0
- package/bizar-dash/dist/assets/mobile-BtxQJftK.js +2 -0
- package/bizar-dash/dist/assets/mobile-BtxQJftK.js.map +1 -0
- package/bizar-dash/dist/assets/{mobile-DHXXbn1A.js → mobile-DD-FZrTC.js} +1 -1
- package/bizar-dash/dist/assets/{mobile-DHXXbn1A.js.map → mobile-DD-FZrTC.js.map} +1 -1
- package/bizar-dash/dist/index.html +4 -4
- package/bizar-dash/dist/mobile.html +3 -3
- package/bizar-dash/node_modules/.package-lock.json +6 -0
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/package-lock.json +6 -0
- package/bizar-dash/src/server/api.mjs +7 -0
- package/bizar-dash/src/server/diagnostics-store.mjs +452 -2
- package/bizar-dash/src/server/memory-store.mjs +46 -0
- package/bizar-dash/src/server/providers-store.mjs +11 -4
- package/bizar-dash/src/server/routes/_shared.mjs +2 -2
- package/bizar-dash/src/server/routes/doctor.mjs +71 -0
- package/bizar-dash/src/server/routes/env-vars.mjs +67 -1
- package/bizar-dash/src/server/routes/memory.mjs +3 -0
- package/bizar-dash/src/server/routes/opencode-session-detail.mjs +61 -42
- package/bizar-dash/src/server/routes/schedules.mjs +55 -0
- package/bizar-dash/src/server/serve-info.mjs +172 -0
- package/bizar-dash/src/web/App.tsx +48 -11
- package/bizar-dash/src/web/components/AutosaveField.tsx +50 -0
- package/bizar-dash/src/web/components/DoctorPanel.tsx +160 -0
- package/bizar-dash/src/web/components/EnvVarManager.tsx +245 -62
- package/bizar-dash/src/web/components/ScheduleTemplateCard.tsx +71 -0
- package/bizar-dash/src/web/components/SettingsNav.tsx +101 -0
- package/bizar-dash/src/web/components/Sidebar.tsx +25 -1
- package/bizar-dash/src/web/components/StatusBadge.tsx +33 -2
- package/bizar-dash/src/web/components/Topbar.tsx +11 -0
- package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +64 -0
- package/bizar-dash/src/web/components/chat/Composer.tsx +1 -1
- package/bizar-dash/src/web/components/chat/useChat.ts +118 -1
- package/bizar-dash/src/web/hooks/useAutosave.ts +107 -0
- package/bizar-dash/src/web/lib/types.ts +134 -0
- package/bizar-dash/src/web/styles/chat.css +8 -5
- package/bizar-dash/src/web/styles/main.css +77 -2
- package/bizar-dash/src/web/styles/settings.css +265 -0
- package/bizar-dash/src/web/views/Chat.tsx +15 -1
- package/bizar-dash/src/web/views/Doctor.tsx +317 -0
- package/bizar-dash/src/web/views/MiniMaxUsage.tsx +1 -0
- package/bizar-dash/src/web/views/Schedules.tsx +94 -12
- package/bizar-dash/src/web/views/Settings.tsx +76 -46
- package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +114 -133
- package/bizar-dash/src/web/views/settings/AgentSection.tsx +23 -12
- package/bizar-dash/src/web/views/settings/EnvVarsSection.tsx +5 -6
- package/bizar-dash/src/web/views/settings/GeneralSection.tsx +38 -15
- package/bizar-dash/src/web/views/settings/MemorySection.tsx +92 -8
- package/bizar-dash/tests/autosave.test.tsx +276 -0
- package/bizar-dash/tests/chat-composer.test.tsx +140 -0
- package/bizar-dash/tests/components/doctor-panel.test.tsx +105 -0
- package/bizar-dash/tests/diagnostics-store.test.mjs +206 -0
- package/bizar-dash/tests/env-vars-extended.test.mjs +190 -0
- package/bizar-dash/tests/layout-spacing.test.mjs +101 -0
- package/bizar-dash/tests/memory-default-vault.test.mjs +98 -0
- package/bizar-dash/tests/minimax-bar.test.tsx +113 -0
- package/bizar-dash/tests/minimax-models.test.mjs +123 -0
- package/bizar-dash/tests/opencode-sessions-detail.test.mjs +158 -0
- package/bizar-dash/tests/routes-doctor.test.mjs +159 -0
- package/bizar-dash/tests/schedules-templates.test.mjs +144 -0
- package/bizar-dash/tests/settings-layout.test.tsx +129 -0
- package/bizar-dash/tests/settings-mode-wiring.test.tsx +151 -0
- package/bizar-dash/tests/settings-nav.test.tsx +126 -0
- package/cli/commands/dash.mjs +5 -1
- package/cli/commands/minimax.mjs +5 -2
- package/cli/tests/minimax-cli.test.mjs +79 -0
- package/config/agents/frigg.md +1 -1
- package/config/agents/heimdall.md +1 -1
- package/config/agents/mimir.md +1 -1
- package/config/agents/quick.md +1 -1
- package/config/agents/semble-search.md +1 -1
- package/config/agents/vor.md +1 -1
- package/config/opencode.json +28 -21
- package/config/opencode.json.template +8 -1
- package/package.json +1 -1
- package/plugins/bizar/index.ts +77 -0
- package/plugins/bizar/src/compaction.d.mts +48 -0
- package/plugins/bizar/src/compaction.mjs +192 -0
- package/plugins/bizar/tests/compaction.test.ts +264 -0
- package/templates/schedules/daily-backup.json +12 -0
- package/templates/schedules/daily-cleanup.json +12 -0
- package/templates/schedules/hourly-health-check.json +12 -0
- package/templates/schedules/webhook-on-push.json +13 -0
- package/templates/schedules/weekly-digest.json +13 -0
- package/bizar-dash/dist/assets/icons-CFqu2M-c.js.map +0 -1
- package/bizar-dash/dist/assets/main-Dl8yY5_H.js +0 -16
- package/bizar-dash/dist/assets/main-Dl8yY5_H.js.map +0 -1
- package/bizar-dash/dist/assets/main-ZAfGKENE.css +0 -1
- package/bizar-dash/dist/assets/mobile-C2gysFOZ.js +0 -2
- package/bizar-dash/dist/assets/mobile-C2gysFOZ.js.map +0 -1
- package/bizar-dash/src/web/views/settings/BackupSection.tsx +0 -16
- package/bizar-dash/src/web/views/settings/ProvidersSection.tsx +0 -16
- package/bizar-dash/src/web/views/settings/SkillsSection.tsx +0 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as r}from"./mobile-
|
|
1
|
+
import{m as r}from"./mobile-BtxQJftK.js";import{b as e,j as o,r as m}from"./react-vendor-DZRUXSPQ.js";import"./icons-Bo0iH9EC.js";import"./markdown-DIquRulQ.js";const t=document.getElementById("root");if(!t)throw new Error("Root element #root not found");e(t).render(o.jsx(m.StrictMode,{children:o.jsx(r,{})}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-
|
|
1
|
+
{"version":3,"file":"mobile-DD-FZrTC.js","sources":["../../src/web/mobile.tsx"],"sourcesContent":["// src/mobile.tsx — entry point for mobile dashboard.\nimport { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { MobileApp } from './MobileApp';\nimport './styles/mobile.css';\n\nconst root = document.getElementById('root');\nif (!root) throw new Error('Root element #root not found');\ncreateRoot(root).render(\n <StrictMode>\n <MobileApp />\n </StrictMode>,\n);\n"],"names":["root","createRoot","jsx","StrictMode","MobileApp"],"mappings":"iKAMA,MAAMA,EAAO,SAAS,eAAe,MAAM,EAC3C,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,8BAA8B,EACzDC,EAAWD,CAAI,EAAE,OACfE,EAAAA,IAACC,EAAAA,WAAA,CACC,SAAAD,EAAAA,IAACE,EAAA,CAAA,CAAU,CAAA,CACb,CACF"}
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
}
|
|
30
30
|
})();
|
|
31
31
|
</script>
|
|
32
|
-
<script type="module" crossorigin src="/assets/main-
|
|
32
|
+
<script type="module" crossorigin src="/assets/main-C1cpttnv.js"></script>
|
|
33
33
|
<link rel="modulepreload" crossorigin href="/assets/react-vendor-DZRUXSPQ.js">
|
|
34
|
-
<link rel="modulepreload" crossorigin href="/assets/icons-
|
|
34
|
+
<link rel="modulepreload" crossorigin href="/assets/icons-Bo0iH9EC.js">
|
|
35
35
|
<link rel="modulepreload" crossorigin href="/assets/markdown-DIquRulQ.js">
|
|
36
|
-
<link rel="modulepreload" crossorigin href="/assets/mobile-
|
|
36
|
+
<link rel="modulepreload" crossorigin href="/assets/mobile-BtxQJftK.js">
|
|
37
37
|
<link rel="stylesheet" crossorigin href="/assets/mobile-CsZQAswA.css">
|
|
38
|
-
<link rel="stylesheet" crossorigin href="/assets/main-
|
|
38
|
+
<link rel="stylesheet" crossorigin href="/assets/main-DTkNlLrw.css">
|
|
39
39
|
</head>
|
|
40
40
|
<body>
|
|
41
41
|
<div id="root"></div>
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
13
13
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
14
14
|
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
|
|
15
|
-
<script type="module" crossorigin src="/assets/mobile-
|
|
15
|
+
<script type="module" crossorigin src="/assets/mobile-DD-FZrTC.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="/assets/react-vendor-DZRUXSPQ.js">
|
|
17
|
-
<link rel="modulepreload" crossorigin href="/assets/icons-
|
|
17
|
+
<link rel="modulepreload" crossorigin href="/assets/icons-Bo0iH9EC.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="/assets/markdown-DIquRulQ.js">
|
|
19
|
-
<link rel="modulepreload" crossorigin href="/assets/mobile-
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/mobile-BtxQJftK.js">
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/assets/mobile-CsZQAswA.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"4.1.9","results":[[":tests/lib/utils.test.ts",{"duration":24.
|
|
1
|
+
{"version":"4.1.9","results":[[":tests/lib/utils.test.ts",{"duration":24.401755999999978,"failed":false}],[":tests/components/Button.test.tsx",{"duration":94.65935400000001,"failed":false}],[":tests/components/Card.test.tsx",{"duration":33.34148499999992,"failed":false}],[":tests/hooks/useModal.test.tsx",{"duration":122.76268099999993,"failed":false}],[":tests/components/Toast.test.tsx",{"duration":154.32516699999996,"failed":false}],[":tests/components/Modal.test.tsx",{"duration":154.48290899999995,"failed":false}],[":tests/lib/i18n.test.ts",{"duration":2.5646790000000124,"failed":false}],[":tests/components/StatusBadge.test.tsx",{"duration":35.74290199999996,"failed":false}],[":tests/hooks/useToast.test.tsx",{"duration":102.97662300000002,"failed":false}],[":tests/components/Spinner.test.tsx",{"duration":61.05561799999998,"failed":false}],[":tests/backup-restore.test.tsx",{"duration":172.59814500000005,"failed":false}],[":tests/a11y.test.tsx",{"duration":604.525834,"failed":false}],[":tests/lib/search-fuzzy.test.ts",{"duration":5.145660000000021,"failed":false}],[":tests/components/settings-search.test.tsx",{"duration":706.8917600000001,"failed":false}],[":tests/memory-graph-view.test.tsx",{"duration":47.21873400000004,"failed":false}],[":tests/components/workspace-selector.test.tsx",{"duration":117.41044699999998,"failed":false}],[":tests/components/screenshot-ocr.test.tsx",{"duration":54.35712199999989,"failed":false}],[":tests/voice-recorder.test.tsx",{"duration":120.104243,"failed":false}],[":tests/autosave.test.tsx",{"duration":246.61124700000005,"failed":false}],[":tests/settings-layout.test.tsx",{"duration":193.1172640000001,"failed":false}],[":tests/settings-nav.test.tsx",{"duration":243.567592,"failed":false}],[":tests/components/doctor-panel.test.tsx",{"duration":76.46435400000007,"failed":false}],[":tests/chat-composer.test.tsx",{"duration":167.8578,"failed":false}],[":tests/settings-mode-wiring.test.tsx",{"duration":187.096763,"failed":false}],[":tests/minimax-bar.test.ts",{"duration":0,"failed":true}],[":tests/minimax-bar.test.tsx",{"duration":21.815285000000017,"failed":false}]]}
|
|
@@ -46,6 +46,7 @@ import { createDialogsRouter } from './routes/dialogs.mjs';
|
|
|
46
46
|
import { createSkillsRouter } from './routes/skills.mjs';
|
|
47
47
|
import { createObsidianRouter } from './routes/obsidian.mjs';
|
|
48
48
|
import { createDiagnosticsRouter } from './routes/diagnostics.mjs';
|
|
49
|
+
import { createDoctorRouter } from './routes/doctor.mjs';
|
|
49
50
|
import { createPairRouter } from './routes/pair.mjs';
|
|
50
51
|
import { createThemesRouter } from './routes/themes.mjs';
|
|
51
52
|
import { createNotificationsRouter } from './routes/notifications.mjs';
|
|
@@ -144,6 +145,12 @@ export async function createApiRouter({
|
|
|
144
145
|
// v5.0.0 — Voice notes (record, transcribe, list, delete, stream audio).
|
|
145
146
|
router.use(createVoiceRouter({}));
|
|
146
147
|
router.use(createDiagnosticsRouter());
|
|
148
|
+
// v6.0.0 — Doctor page API. Mounted right after diagnostics so the
|
|
149
|
+
// /doctor/* paths live next to the legacy /diagnostics/* surface
|
|
150
|
+
// they conceptually extend. Each route inside is at its bare path
|
|
151
|
+
// (e.g. '/health'), which becomes '/api/doctor/health' at the top
|
|
152
|
+
// level once /api is prepended by server.mjs.
|
|
153
|
+
router.use('/doctor', createDoctorRouter());
|
|
147
154
|
router.use(createPairRouter({ state, broadcast }));
|
|
148
155
|
router.use(createThemesRouter({ state }));
|
|
149
156
|
router.use(createNotificationsRouter({ broadcast }));
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
* src/server/diagnostics-store.mjs
|
|
3
3
|
*
|
|
4
4
|
* v3.0.0 — Health check, version info, and last-N errors.
|
|
5
|
+
* v6.0.0 — Doctor surface: full system snapshot (`collectDiagnostics()`),
|
|
6
|
+
* per-check dispatch (`runCheck(name)`), and a timestamped
|
|
7
|
+
* recent-errors feed (`getRecentErrors({ since })`) for the
|
|
8
|
+
* Doctor page in the dashboard.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
10
|
+
* The legacy `snapshot()` and `health()` methods are preserved so the
|
|
11
|
+
* v3 `/api/diagnostics` routes keep working unchanged. The Doctor routes
|
|
12
|
+
* call the richer `collectDiagnostics()` / `runCheck()` / `health()`.
|
|
7
13
|
*/
|
|
8
14
|
import { existsSync, readFileSync, statSync, readdirSync } from 'node:fs';
|
|
9
15
|
import { join, dirname } from 'node:path';
|
|
@@ -77,6 +83,450 @@ function serviceStatus() {
|
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
|
|
86
|
+
/**
|
|
87
|
+
* v6.0.0 — Timestamped error feed. Reads the recent service log and
|
|
88
|
+
* returns entries whose `[ts]` prefix (if any) is >= `since`. Each
|
|
89
|
+
* entry carries a parsed epoch ms to make filtering cheap for the
|
|
90
|
+
* UI's "last hour" widget.
|
|
91
|
+
*
|
|
92
|
+
* Capped at 200 entries to keep the response bounded — the dashboard
|
|
93
|
+
* only ever displays ~30. Returns `[]` on any read failure so the UI
|
|
94
|
+
* can render an empty state instead of crashing.
|
|
95
|
+
*
|
|
96
|
+
* @param {{ since?: number, limit?: number }} opts
|
|
97
|
+
* @returns {Array<{ line: string, ts: string | null, tsMs: number | null }>}
|
|
98
|
+
*/
|
|
99
|
+
export function getRecentErrors({ since = 0, limit = 200 } = {}) {
|
|
100
|
+
if (!existsSync(SERVICE_LOG)) return [];
|
|
101
|
+
try {
|
|
102
|
+
const text = readFileSync(SERVICE_LOG, 'utf8');
|
|
103
|
+
const lines = text.split(/\r?\n/);
|
|
104
|
+
const out = [];
|
|
105
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
106
|
+
const line = lines[i];
|
|
107
|
+
if (!line.trim()) continue;
|
|
108
|
+
if (!/\b(failed|error|err)\b/i.test(line)) continue;
|
|
109
|
+
const tsStr = parseLogTs(line);
|
|
110
|
+
const tsMs = tsStr ? Date.parse(tsStr) : null;
|
|
111
|
+
if (since && tsMs !== null && tsMs < since) continue;
|
|
112
|
+
out.push({ line, ts: tsStr, tsMs });
|
|
113
|
+
if (out.length >= limit) break;
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
} catch {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* v6.0.0 — Probe the local headroom proxy on `host:port`. Returns a
|
|
123
|
+
* `{ running, port?, error? }` shape so the Doctor page can show a
|
|
124
|
+
* "Headroom proxy on 8787 ✓" line without forcing the route to
|
|
125
|
+
* swallow a 1.5s timeout on every poll.
|
|
126
|
+
*
|
|
127
|
+
* @param {string} host
|
|
128
|
+
* @param {number} port
|
|
129
|
+
* @param {number} timeoutMs
|
|
130
|
+
* @returns {Promise<{ running: boolean, port?: number, error?: string }>}
|
|
131
|
+
*/
|
|
132
|
+
async function probeTcp(host, port, timeoutMs = 800) {
|
|
133
|
+
// Lazy import so unit tests that don't need TCP probing still load
|
|
134
|
+
// the module under environments that can't resolve `node:net`.
|
|
135
|
+
const { connect } = await import('node:net');
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
let settled = false;
|
|
138
|
+
const finish = (ok, error) => {
|
|
139
|
+
if (settled) return;
|
|
140
|
+
settled = true;
|
|
141
|
+
resolve(ok ? { running: true, port } : { running: false, error: error || 'unreachable' });
|
|
142
|
+
};
|
|
143
|
+
const sock = connect(port, host);
|
|
144
|
+
const timer = setTimeout(() => {
|
|
145
|
+
sock.destroy();
|
|
146
|
+
finish(false, 'timeout');
|
|
147
|
+
}, timeoutMs);
|
|
148
|
+
sock.once('connect', () => {
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
sock.destroy();
|
|
151
|
+
finish(true);
|
|
152
|
+
});
|
|
153
|
+
sock.once('error', (err) => {
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
finish(false, err.message);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* v6.0.0 — LightRAG port probe. The dashboard doesn't always have a
|
|
162
|
+
* lightrag server running, so the probe is best-effort. Returns the
|
|
163
|
+
* port from settings if known, plus a `running` boolean.
|
|
164
|
+
*
|
|
165
|
+
* @returns {Promise<{ running: boolean, port?: number, error?: string }>}
|
|
166
|
+
*/
|
|
167
|
+
async function probeLightRAG() {
|
|
168
|
+
try {
|
|
169
|
+
// Avoid a hard dependency on the memory router module: just read
|
|
170
|
+
// the same `.bizar/memory.json` it would consult. Fall back to
|
|
171
|
+
// a no-port default.
|
|
172
|
+
const cfgPath = join(HOME, '.config', 'bizar', 'memory.json');
|
|
173
|
+
let port = 0;
|
|
174
|
+
if (existsSync(cfgPath)) {
|
|
175
|
+
try {
|
|
176
|
+
const parsed = JSON.parse(readFileSync(cfgPath, 'utf8'));
|
|
177
|
+
port = Number(parsed?.lightrag?.port || 0);
|
|
178
|
+
} catch { /* malformed JSON — ignore */ }
|
|
179
|
+
}
|
|
180
|
+
if (!port) return { running: false, port: undefined, error: 'port unknown' };
|
|
181
|
+
return await probeTcp('127.0.0.1', port, 800);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
return { running: false, error: err.message };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function probeHeadroom() {
|
|
188
|
+
// Headroom's default port — matches headroom.mjs's
|
|
189
|
+
// DEFAULT_HEADROOM_PORT. Settings override takes precedence.
|
|
190
|
+
let port = 8787;
|
|
191
|
+
let host = '127.0.0.1';
|
|
192
|
+
try {
|
|
193
|
+
const settingsPath = join(HOME, '.config', 'bizar', 'settings.json');
|
|
194
|
+
if (existsSync(settingsPath)) {
|
|
195
|
+
const parsed = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
196
|
+
port = Number(parsed?.headroom?.port) || port;
|
|
197
|
+
host = String(parsed?.headroom?.host) || host;
|
|
198
|
+
}
|
|
199
|
+
} catch { /* ignore */ }
|
|
200
|
+
const result = await probeTcp(host, port, 800);
|
|
201
|
+
return { ...result, port, host };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* v6.0.0 — Probe whether the opencode plugin's `serve-info.json` is
|
|
206
|
+
* reachable on disk and parseable. The dashboard reads serve-info to
|
|
207
|
+
* dispatch agent tasks; if it's missing or stale, the Doctor page
|
|
208
|
+
* flags it as a warning (not a failure) since some installs don't use
|
|
209
|
+
* the plugin.
|
|
210
|
+
*/
|
|
211
|
+
function opencodeServeInfo() {
|
|
212
|
+
const candidates = [
|
|
213
|
+
join(HOME, '.cache', 'bizar', 'serve.json'),
|
|
214
|
+
join(HOME, '.cache', 'bizar', 'serve-info.json'),
|
|
215
|
+
];
|
|
216
|
+
for (const path of candidates) {
|
|
217
|
+
if (!existsSync(path)) continue;
|
|
218
|
+
try {
|
|
219
|
+
const raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
220
|
+
const port = Number(raw?.port || 0);
|
|
221
|
+
return { reachable: true, path, port: port || undefined, baseUrl: raw?.baseUrl || null };
|
|
222
|
+
} catch (err) {
|
|
223
|
+
return { reachable: false, path, error: err.message };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return { reachable: false, path: null };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* v6.0.0 — Aggregate counts across every dashboard store. The Doctor
|
|
231
|
+
* page surfaces this as a one-line-per-row table. All counts return
|
|
232
|
+
* 0 (never throw) when the underlying store is empty or unreachable,
|
|
233
|
+
* so a partial outage still gives the operator a useful readout.
|
|
234
|
+
*/
|
|
235
|
+
function collectCounts() {
|
|
236
|
+
const projects = projectsStore.list();
|
|
237
|
+
const active = projectsStore.active();
|
|
238
|
+
const tasks = active ? tasksStore.loadTasks(active.id) : [];
|
|
239
|
+
const schedules = active ? schedulesStore.list(active.id) : [];
|
|
240
|
+
let workspacesCount = 0;
|
|
241
|
+
try {
|
|
242
|
+
// listWorkspaces is async and requires a userId — fall back to the
|
|
243
|
+
// index file size if we can't resolve one cheaply.
|
|
244
|
+
const indexPath = join(HOME, '.config', 'bizar', 'workspaces', 'index.json');
|
|
245
|
+
if (existsSync(indexPath)) {
|
|
246
|
+
const parsed = JSON.parse(readFileSync(indexPath, 'utf8'));
|
|
247
|
+
workspacesCount = Array.isArray(parsed?.workspaces) ? parsed.workspaces.length : 0;
|
|
248
|
+
}
|
|
249
|
+
} catch { /* ignore */ }
|
|
250
|
+
let voiceNotes = 0;
|
|
251
|
+
try {
|
|
252
|
+
const voiceDir = join(HOME, '.config', 'bizar', 'voice');
|
|
253
|
+
if (existsSync(voiceDir)) {
|
|
254
|
+
voiceNotes = readdirSync(voiceDir).filter((f) => f.endsWith('.json')).length;
|
|
255
|
+
}
|
|
256
|
+
} catch { /* ignore */ }
|
|
257
|
+
let evalRuns = 0;
|
|
258
|
+
try {
|
|
259
|
+
const evalDir = join(HOME, '.config', 'bizar', 'eval');
|
|
260
|
+
if (existsSync(evalDir)) {
|
|
261
|
+
evalRuns = readdirSync(evalDir).filter((f) => f.endsWith('.json')).length;
|
|
262
|
+
}
|
|
263
|
+
} catch { /* ignore */ }
|
|
264
|
+
let backups = 0;
|
|
265
|
+
try {
|
|
266
|
+
const backupDir = join(HOME, '.local', 'share', 'bizar', 'backups');
|
|
267
|
+
if (existsSync(backupDir)) {
|
|
268
|
+
backups = readdirSync(backupDir).filter((f) => f.startsWith('bizar-')).length;
|
|
269
|
+
}
|
|
270
|
+
} catch { /* ignore */ }
|
|
271
|
+
return {
|
|
272
|
+
tasks: tasks.length,
|
|
273
|
+
schedules: schedules.length,
|
|
274
|
+
mods: modsLoader.list().length,
|
|
275
|
+
providers: providersStore.list().length,
|
|
276
|
+
mcps: mcpsStore.list().length,
|
|
277
|
+
agents: agentsStore.list().length,
|
|
278
|
+
projects: projects.projects.length,
|
|
279
|
+
activeProject: active?.id || null,
|
|
280
|
+
workspaces: workspacesCount,
|
|
281
|
+
voiceNotes,
|
|
282
|
+
evalRuns,
|
|
283
|
+
backups,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* v6.0.0 — Static config-health checks. Each check is a name +
|
|
289
|
+
* `{ status, message }` pair. `status` is `ok` / `warn` / `fail`,
|
|
290
|
+
* matching the `DoctorCheck` shape consumed by the frontend.
|
|
291
|
+
*
|
|
292
|
+
* Used by `health()` and exposed individually via `runCheck(name)`.
|
|
293
|
+
*/
|
|
294
|
+
async function runConfigChecks() {
|
|
295
|
+
const opencodeConfig = providersStore.OPENCODE_JSON;
|
|
296
|
+
const agentsDir = agentsStore.AGENTS_DIR;
|
|
297
|
+
const checks = [];
|
|
298
|
+
checks.push({
|
|
299
|
+
name: 'opencode-config',
|
|
300
|
+
status: existsSync(opencodeConfig) ? 'ok' : 'fail',
|
|
301
|
+
message: existsSync(opencodeConfig) ? `present at ${opencodeConfig}` : `${opencodeConfig} not found`,
|
|
302
|
+
});
|
|
303
|
+
checks.push({
|
|
304
|
+
name: 'opencode-agents',
|
|
305
|
+
status: existsSync(agentsDir) ? 'ok' : 'warn',
|
|
306
|
+
message: existsSync(agentsDir) ? `${agentsDir} present` : `${agentsDir} missing — agents will fall back to defaults`,
|
|
307
|
+
});
|
|
308
|
+
const bizarHome = join(HOME, '.config', 'bizar');
|
|
309
|
+
checks.push({
|
|
310
|
+
name: 'bizar-home',
|
|
311
|
+
status: existsSync(bizarHome) ? 'ok' : 'fail',
|
|
312
|
+
message: existsSync(bizarHome) ? bizarHome : `${bizarHome} missing`,
|
|
313
|
+
});
|
|
314
|
+
const memoryConfig = join(HOME, '.config', 'bizar', 'memory.json');
|
|
315
|
+
checks.push({
|
|
316
|
+
name: 'memory-config',
|
|
317
|
+
status: existsSync(memoryConfig) ? 'ok' : 'warn',
|
|
318
|
+
message: existsSync(memoryConfig) ? 'memory.json configured' : 'no memory.json — running with defaults',
|
|
319
|
+
});
|
|
320
|
+
return checks;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* v6.0.0 — Service health checks. TCP probes for headroom and
|
|
325
|
+
* lightrag (both best-effort), opencode plugin file probe, and the
|
|
326
|
+
* dashboard itself (always `ok` — we're running because we got here).
|
|
327
|
+
*/
|
|
328
|
+
async function runServiceChecks() {
|
|
329
|
+
const headroom = await probeHeadroom();
|
|
330
|
+
const lightrag = await probeLightRAG();
|
|
331
|
+
const serveInfo = opencodeServeInfo();
|
|
332
|
+
const checks = [
|
|
333
|
+
{
|
|
334
|
+
name: 'dashboard',
|
|
335
|
+
status: 'ok',
|
|
336
|
+
message: `running on pid ${process.pid}, up ${Math.floor(process.uptime())}s`,
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: 'headroom',
|
|
340
|
+
status: headroom.running ? 'ok' : 'warn',
|
|
341
|
+
message: headroom.running
|
|
342
|
+
? `proxy on ${headroom.host}:${headroom.port}`
|
|
343
|
+
: `not running on ${headroom.host}:${headroom.port}${headroom.error ? ` (${headroom.error})` : ''}`,
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: 'lightrag',
|
|
347
|
+
status: lightrag.running ? 'ok' : 'warn',
|
|
348
|
+
message: lightrag.running
|
|
349
|
+
? `running on port ${lightrag.port}`
|
|
350
|
+
: `not running${lightrag.port ? ` on port ${lightrag.port}` : ''}${lightrag.error ? ` (${lightrag.error})` : ''}`,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: 'opencode',
|
|
354
|
+
status: serveInfo.reachable ? 'ok' : 'warn',
|
|
355
|
+
message: serveInfo.reachable
|
|
356
|
+
? `serve-info at ${serveInfo.path}${serveInfo.port ? ` (port ${serveInfo.port})` : ''}`
|
|
357
|
+
: `serve-info missing${serveInfo.error ? `: ${serveInfo.error}` : ''} — plugin may not be running`,
|
|
358
|
+
},
|
|
359
|
+
];
|
|
360
|
+
return checks;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* v6.0.0 — Overall system checks. Pure: no I/O, no probes. Reports
|
|
365
|
+
* Node version, platform, arch, and uptime.
|
|
366
|
+
*/
|
|
367
|
+
function runSystemChecks() {
|
|
368
|
+
return [
|
|
369
|
+
{
|
|
370
|
+
name: 'node',
|
|
371
|
+
status: 'ok',
|
|
372
|
+
message: `${process.version} on ${process.platform}/${process.arch}`,
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
name: 'uptime',
|
|
376
|
+
status: 'ok',
|
|
377
|
+
message: `${Math.floor(process.uptime())}s`,
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
name: 'memory',
|
|
381
|
+
status: process.memoryUsage().rss < 512 * 1024 * 1024 ? 'ok' : 'warn',
|
|
382
|
+
message: `rss ${(process.memoryUsage().rss / 1024 / 1024).toFixed(1)} MB`,
|
|
383
|
+
},
|
|
384
|
+
];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* v6.0.0 — Run a single named check. Returns a single
|
|
389
|
+
* `{ name, status, message }` entry, or `null` if the name is unknown.
|
|
390
|
+
* Used by `POST /api/doctor/check`.
|
|
391
|
+
*
|
|
392
|
+
* @param {string} name
|
|
393
|
+
* @returns {Promise<{ name: string, status: string, message: string } | { name: string, status: 'fail', message: string, error: string }>}
|
|
394
|
+
*/
|
|
395
|
+
export async function runCheck(name) {
|
|
396
|
+
if (!name || typeof name !== 'string') {
|
|
397
|
+
return { name: String(name || ''), status: 'fail', message: 'unknown check', error: 'checkName required' };
|
|
398
|
+
}
|
|
399
|
+
const system = runSystemChecks();
|
|
400
|
+
const config = await runConfigChecks();
|
|
401
|
+
const services = await runServiceChecks();
|
|
402
|
+
const all = [...system, ...config, ...services];
|
|
403
|
+
const hit = all.find((c) => c.name === name);
|
|
404
|
+
if (!hit) {
|
|
405
|
+
return {
|
|
406
|
+
name,
|
|
407
|
+
status: 'fail',
|
|
408
|
+
message: 'unknown check',
|
|
409
|
+
error: `no check named "${name}". Available: ${all.map((c) => c.name).join(', ')}`,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
return hit;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* v6.0.0 — Top-level health rollup. Aggregates every check group,
|
|
417
|
+
* collapses to a single `ok | warn | fail` status, and returns the
|
|
418
|
+
* structured list of issues so the UI can show "3 warnings" without
|
|
419
|
+
* having to re-derive the math client-side.
|
|
420
|
+
*
|
|
421
|
+
* @returns {Promise<{ status: 'ok'|'warn'|'fail', issues: Array<{ name: string, status: string, message: string }>, groups: Record<string, Array<{ name: string, status: string, message: string }>>, ts: string }>}
|
|
422
|
+
*/
|
|
423
|
+
export async function health() {
|
|
424
|
+
const system = runSystemChecks();
|
|
425
|
+
const config = await runConfigChecks();
|
|
426
|
+
const services = await runServiceChecks();
|
|
427
|
+
const groups = { system, config, services };
|
|
428
|
+
const flat = [...system, ...config, ...services];
|
|
429
|
+
const issues = flat.filter((c) => c.status !== 'ok');
|
|
430
|
+
let status = 'ok';
|
|
431
|
+
if (issues.some((c) => c.status === 'fail')) status = 'fail';
|
|
432
|
+
else if (issues.length > 0) status = 'warn';
|
|
433
|
+
return { ts: new Date().toISOString(), status, issues, groups };
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* v6.0.0 — Full Doctor snapshot. One call collects everything the
|
|
438
|
+
* Doctor page renders, with bounded response size so the dashboard
|
|
439
|
+
* auto-refresh (every 30s) stays cheap.
|
|
440
|
+
*
|
|
441
|
+
* @returns {Promise<{
|
|
442
|
+
* timestamp: string,
|
|
443
|
+
* bizarVersion: string,
|
|
444
|
+
* nodeVersion: string,
|
|
445
|
+
* platform: string,
|
|
446
|
+
* arch: string,
|
|
447
|
+
* uptime: number,
|
|
448
|
+
* memory: NodeJS.MemoryUsage,
|
|
449
|
+
* disk: { exists: boolean, path: string, sizeBytes: number },
|
|
450
|
+
* services: { dashboard: object, headroom: object, lightrag: object, opencode: object },
|
|
451
|
+
* counts: ReturnType<typeof collectCounts>,
|
|
452
|
+
* recentErrors: ReturnType<typeof getRecentErrors>,
|
|
453
|
+
* configHealth: Array<{ name: string, status: string, message: string }>,
|
|
454
|
+
* opencode: { configExists: boolean, agentsDir: string, agentFiles: string[], dashboardConnected: boolean },
|
|
455
|
+
* checks: { system: Array, config: Array, services: Array },
|
|
456
|
+
* health: { status: string, issues: Array }
|
|
457
|
+
* }>}
|
|
458
|
+
*/
|
|
459
|
+
export async function collectDiagnostics() {
|
|
460
|
+
const counts = collectCounts();
|
|
461
|
+
const system = runSystemChecks();
|
|
462
|
+
const config = await runConfigChecks();
|
|
463
|
+
const services = await runServiceChecks();
|
|
464
|
+
const rollup = { system, config, services };
|
|
465
|
+
const flat = [...system, ...config, ...services];
|
|
466
|
+
const issues = flat.filter((c) => c.status !== 'ok');
|
|
467
|
+
let status = 'ok';
|
|
468
|
+
if (issues.some((c) => c.status === 'fail')) status = 'fail';
|
|
469
|
+
else if (issues.length > 0) status = 'warn';
|
|
470
|
+
const headroom = await probeHeadroom();
|
|
471
|
+
const lightrag = await probeLightRAG();
|
|
472
|
+
const serveInfo = opencodeServeInfo();
|
|
473
|
+
const opencodeConfig = providersStore.OPENCODE_JSON;
|
|
474
|
+
const agentsDir = agentsStore.AGENTS_DIR;
|
|
475
|
+
let agentFiles = [];
|
|
476
|
+
try {
|
|
477
|
+
if (existsSync(agentsDir)) {
|
|
478
|
+
agentFiles = readdirSync(agentsDir).filter((f) => f.endsWith('.md'));
|
|
479
|
+
}
|
|
480
|
+
} catch { /* ignore */ }
|
|
481
|
+
const dashboardLogPath = join(HOME, '.config', 'bizar', 'dashboard.log');
|
|
482
|
+
const disk = {
|
|
483
|
+
path: join(HOME, '.config'),
|
|
484
|
+
exists: existsSync(join(HOME, '.config')),
|
|
485
|
+
sizeBytes: 0,
|
|
486
|
+
};
|
|
487
|
+
try {
|
|
488
|
+
if (disk.exists) disk.sizeBytes = statSync(join(HOME, '.config')).size;
|
|
489
|
+
} catch { /* ignore */ }
|
|
490
|
+
const dashboardLogExists = existsSync(dashboardLogPath);
|
|
491
|
+
return {
|
|
492
|
+
timestamp: new Date().toISOString(),
|
|
493
|
+
bizarVersion: dashboardVersion(),
|
|
494
|
+
nodeVersion: process.version,
|
|
495
|
+
platform: process.platform,
|
|
496
|
+
arch: process.arch,
|
|
497
|
+
uptime: Math.floor(process.uptime()),
|
|
498
|
+
memory: process.memoryUsage(),
|
|
499
|
+
disk,
|
|
500
|
+
services: {
|
|
501
|
+
dashboard: {
|
|
502
|
+
running: true,
|
|
503
|
+
pid: process.pid,
|
|
504
|
+
uptime: Math.floor(process.uptime()),
|
|
505
|
+
logPath: dashboardLogPath,
|
|
506
|
+
logExists: dashboardLogExists,
|
|
507
|
+
},
|
|
508
|
+
headroom,
|
|
509
|
+
lightrag,
|
|
510
|
+
opencode: serveInfo,
|
|
511
|
+
},
|
|
512
|
+
counts,
|
|
513
|
+
recentErrors: getRecentErrors({ since: Date.now() - 3600_000, limit: 50 }),
|
|
514
|
+
configHealth: config,
|
|
515
|
+
opencode: {
|
|
516
|
+
configExists: existsSync(opencodeConfig),
|
|
517
|
+
configPath: opencodeConfig,
|
|
518
|
+
agentsDir,
|
|
519
|
+
agentFiles,
|
|
520
|
+
dashboardConnected: serveInfo.reachable,
|
|
521
|
+
},
|
|
522
|
+
checks: rollup,
|
|
523
|
+
health: {
|
|
524
|
+
status,
|
|
525
|
+
issues,
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
80
530
|
export const diagnosticsStore = {
|
|
81
531
|
/** Build the full diagnostics snapshot. */
|
|
82
532
|
snapshot(extra = {}) {
|
|
@@ -145,4 +595,4 @@ export const diagnosticsStore = {
|
|
|
145
595
|
};
|
|
146
596
|
|
|
147
597
|
// Add MOD_DIR alias for older access
|
|
148
|
-
modsLoader.MOD_DIR = modsLoader.MOD_DIR || modsLoader.MODS_DIR;
|
|
598
|
+
modsLoader.MOD_DIR = modsLoader.MOD_DIR || modsLoader.MODS_DIR;
|
|
@@ -20,10 +20,56 @@ import { validateNote } from './memory-schema.mjs';
|
|
|
20
20
|
import { scan as scanSecrets, hasHighFindings } from './memory-secrets.mjs';
|
|
21
21
|
import { atomicWriteJson, safeReadJSON, safeReadText } from '../../../cli/atomic.mjs';
|
|
22
22
|
import * as memoryGit from './memory-git.mjs';
|
|
23
|
+
import { warn as loggerWarn } from './logger.mjs';
|
|
23
24
|
|
|
24
25
|
const HOME = homedir();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Default vault root — auto-created on first use.
|
|
29
|
+
* Override with BIZAR_MEMORY_VAULT env var.
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_MEMORY_VAULT = join(HOME, '.local', 'share', 'bizar', 'memory');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Default git remote — set via BIZAR_MEMORY_GIT_REMOTE to enable sync.
|
|
35
|
+
*/
|
|
36
|
+
export const DEFAULT_GIT_REMOTE = process.env.BIZAR_MEMORY_GIT_REMOTE || null;
|
|
37
|
+
|
|
25
38
|
const BIZAR_MEMORY_ROOT = join(HOME, '.local', 'share', 'bizar', 'memory');
|
|
26
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Return the effective vault root for the default memory vault.
|
|
42
|
+
* Override with BIZAR_MEMORY_VAULT env var.
|
|
43
|
+
*
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
export function currentVault() {
|
|
47
|
+
return process.env.BIZAR_MEMORY_VAULT || DEFAULT_MEMORY_VAULT;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Ensure the default memory vault directory exists and is git-initialised.
|
|
52
|
+
* Idempotent — calling multiple times is safe.
|
|
53
|
+
*
|
|
54
|
+
* @returns {string} the vault path that was ensured
|
|
55
|
+
*/
|
|
56
|
+
export function ensureVaultExists() {
|
|
57
|
+
const vault = currentVault();
|
|
58
|
+
if (!existsSync(vault)) {
|
|
59
|
+
mkdirSync(vault, { recursive: true, mode: 0o700 });
|
|
60
|
+
if (!existsSync(join(vault, '.git'))) {
|
|
61
|
+
try {
|
|
62
|
+
execFileSync('git', ['init'], { cwd: vault, stdio: 'pipe' });
|
|
63
|
+
execFileSync('git', ['config', 'user.email', 'bizar@localhost'], { cwd: vault, stdio: 'pipe' });
|
|
64
|
+
execFileSync('git', ['config', 'user.name', 'BizarHarness'], { cwd: vault, stdio: 'pipe' });
|
|
65
|
+
} catch (err) {
|
|
66
|
+
loggerWarn('failed to init git in vault', { vault, err: err.message });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return vault;
|
|
71
|
+
}
|
|
72
|
+
|
|
27
73
|
/**
|
|
28
74
|
* Path safety: reject any relPath that would escape the vault root.
|
|
29
75
|
*
|
|
@@ -326,6 +326,11 @@ export function syncLegacyKeys(p) {
|
|
|
326
326
|
return next;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
// ── MiniMax model constants ──────────────────────────────────────────────────
|
|
330
|
+
//
|
|
331
|
+
// Cheap/fast everyday model — agents that need a lightweight workhorse.
|
|
332
|
+
export const MINIMAX_DEFAULT = 'MiniMax-M2.7';
|
|
333
|
+
|
|
329
334
|
// ── v4.6.0 Provider catalog ─────────────────────────────────────────────────
|
|
330
335
|
//
|
|
331
336
|
// Curated list of well-known providers. The dashboard's "Add provider"
|
|
@@ -406,9 +411,10 @@ export const PROVIDER_CATALOG = Object.freeze([
|
|
|
406
411
|
keyHint: 'sk-cp-…, sk-ant-…, or sk-or-…',
|
|
407
412
|
docs: 'https://api.minimax.io',
|
|
408
413
|
models: [
|
|
409
|
-
|
|
410
|
-
'MiniMax-M2.
|
|
411
|
-
'MiniMax-
|
|
414
|
+
Object.freeze({ id: 'MiniMax-M2.7-Flash', name: 'MiniMax M2.7 Flash', tier: 'cheap', recommended: true }),
|
|
415
|
+
Object.freeze({ id: 'MiniMax-M2.7', name: 'MiniMax M2.7', tier: 'cheap' }),
|
|
416
|
+
Object.freeze({ id: 'MiniMax-M3', name: 'MiniMax M3', tier: 'mid' }),
|
|
417
|
+
Object.freeze({ id: 'MiniMax-M3-Reasoning', name: 'MiniMax M3 Reasoning', tier: 'premium' }),
|
|
412
418
|
],
|
|
413
419
|
requiresKey: true,
|
|
414
420
|
}),
|
|
@@ -1543,7 +1549,8 @@ export const providersStore = {
|
|
|
1543
1549
|
keyPattern: /^sk-(cp|ant|or)-[A-Za-z0-9_-]{20,}$/,
|
|
1544
1550
|
defaultModel: 'MiniMax-M3',
|
|
1545
1551
|
defaultModels: [
|
|
1546
|
-
'MiniMax-
|
|
1552
|
+
'MiniMax-M2.7-Flash', 'MiniMax-M2.7', 'MiniMax-M2.7-highspeed',
|
|
1553
|
+
'MiniMax-M3', 'MiniMax-M3-Reasoning',
|
|
1547
1554
|
'MiniMax-M2.5', 'MiniMax-M2.5-highspeed', 'MiniMax-M2.1',
|
|
1548
1555
|
'MiniMax-M2.1-highspeed', 'MiniMax-M2',
|
|
1549
1556
|
],
|