@xqli02/mneme 0.1.9 → 0.1.10
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/package.json +1 -1
- package/src/commands/auto.mjs +62 -21
package/package.json
CHANGED
package/src/commands/auto.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* mneme auto — Dual-agent autonomous supervisor loop.
|
|
3
3
|
*
|
|
4
4
|
* Uses two agents in the same opencode session:
|
|
5
|
-
* - Planner (default: gpt-
|
|
5
|
+
* - Planner (default: gpt-4.1): analyzes goal, breaks down tasks, reviews results
|
|
6
6
|
* - Executor (default: claude-opus-4.6): writes code, runs commands, implements changes
|
|
7
7
|
*
|
|
8
8
|
* The planner and executor alternate turns via per-message model switching.
|
|
@@ -35,7 +35,7 @@ import { color, log, run, has } from "../utils.mjs";
|
|
|
35
35
|
|
|
36
36
|
// ── Default models ──────────────────────────────────────────────────────────
|
|
37
37
|
|
|
38
|
-
const DEFAULT_PLANNER = "github-copilot/gpt-
|
|
38
|
+
const DEFAULT_PLANNER = "github-copilot/gpt-4.1";
|
|
39
39
|
const DEFAULT_EXECUTOR = "github-copilot/claude-opus-4.6";
|
|
40
40
|
|
|
41
41
|
// ── Argument parsing ────────────────────────────────────────────────────────
|
|
@@ -584,6 +584,28 @@ async function executeTurn(
|
|
|
584
584
|
// Send async — returns immediately
|
|
585
585
|
await client.session.promptAsync(sessionId, body);
|
|
586
586
|
|
|
587
|
+
// Quick check: if model is invalid, the session may error out almost
|
|
588
|
+
// instantly but promptAsync still returns 204. Poll once after a short
|
|
589
|
+
// delay to catch this before entering the long wait loop.
|
|
590
|
+
await sleep(2000);
|
|
591
|
+
try {
|
|
592
|
+
const sessions = await client.session.list();
|
|
593
|
+
const s = sessions?.find?.((ss) => ss.id === sessionId);
|
|
594
|
+
if (s && s.status && s.status !== "running" && s.status !== "pending") {
|
|
595
|
+
// Session already finished — likely an immediate error
|
|
596
|
+
const msgs = await client.session.messages(sessionId);
|
|
597
|
+
const lastMsg = msgs?.[msgs.length - 1];
|
|
598
|
+
const errInfo = lastMsg?.info?.error;
|
|
599
|
+
if (errInfo) {
|
|
600
|
+
const errMsg = errInfo.data?.message || errInfo.name || "unknown";
|
|
601
|
+
log.fail(`Model error: ${errMsg}`);
|
|
602
|
+
return { status: "error", aborted: true, quit: false };
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
} catch {
|
|
606
|
+
// Ignore probe failures — fall through to normal wait
|
|
607
|
+
}
|
|
608
|
+
|
|
587
609
|
const HEARTBEAT_INTERVAL = 15_000; // print elapsed every 15s of silence
|
|
588
610
|
const SILENCE_WARN = 30_000; // warn after 30s of no output
|
|
589
611
|
const SILENCE_ABORT = 120_000; // auto-abort after 120s of no output
|
|
@@ -684,30 +706,49 @@ async function supervisorLoop(client, opts, inputQueue) {
|
|
|
684
706
|
const plannerModel = parseModelSpec(opts.planner);
|
|
685
707
|
const executorModel = parseModelSpec(opts.executor);
|
|
686
708
|
|
|
687
|
-
//
|
|
688
|
-
log.info("Validating models...");
|
|
689
|
-
const modelsOutput = run("opencode models 2>/dev/null") || "";
|
|
690
|
-
const validateModel = (label, spec) => {
|
|
691
|
-
// Look for the model ID in the output; opencode models lists "provider/model"
|
|
692
|
-
if (modelsOutput && !modelsOutput.includes(spec)) {
|
|
693
|
-
log.fail(`${label} model "${spec}" not found in available models.`);
|
|
694
|
-
console.log(color.dim(" Available models:"));
|
|
695
|
-
for (const line of modelsOutput.split("\n").filter(l => l.trim())) {
|
|
696
|
-
console.log(color.dim(` ${line.trim()}`));
|
|
697
|
-
}
|
|
698
|
-
throw new Error(`Invalid ${label.toLowerCase()} model: ${spec}`);
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
|
-
validateModel("Planner", opts.planner);
|
|
702
|
-
validateModel("Executor", opts.executor);
|
|
703
|
-
log.ok("Models validated");
|
|
704
|
-
|
|
705
|
-
// Create session
|
|
709
|
+
// Create session first (needed for model probing)
|
|
706
710
|
log.info("Creating session...");
|
|
707
711
|
const session = await client.session.create({ title: "mneme auto" });
|
|
708
712
|
const sessionId = session.id;
|
|
709
713
|
log.ok(`Session: ${sessionId}`);
|
|
710
714
|
|
|
715
|
+
// ── Validate models by sending a real test prompt ──
|
|
716
|
+
// opencode models lists theoretical models, but the provider may reject them
|
|
717
|
+
// at runtime (e.g. Copilot plan doesn't include gpt-5.x). Only a real API
|
|
718
|
+
// call reveals this — sync prompt returns the error, async silently fails.
|
|
719
|
+
log.info("Validating models (API probe)...");
|
|
720
|
+
const probeModels = [
|
|
721
|
+
{ label: "Planner", spec: opts.planner, parsed: plannerModel },
|
|
722
|
+
{ label: "Executor", spec: opts.executor, parsed: executorModel },
|
|
723
|
+
];
|
|
724
|
+
// Deduplicate if both use the same model
|
|
725
|
+
const seen = new Set();
|
|
726
|
+
for (const m of probeModels) {
|
|
727
|
+
if (seen.has(m.spec)) continue;
|
|
728
|
+
seen.add(m.spec);
|
|
729
|
+
try {
|
|
730
|
+
const result = await client.session.prompt(sessionId, {
|
|
731
|
+
parts: [{ type: "text", text: "Say OK" }],
|
|
732
|
+
model: m.parsed,
|
|
733
|
+
});
|
|
734
|
+
// Check if the response contains an error
|
|
735
|
+
const err = result?.info?.error;
|
|
736
|
+
if (err) {
|
|
737
|
+
const msg = err.data?.message || err.name || "unknown error";
|
|
738
|
+
log.fail(`${m.label} model "${m.spec}" rejected by provider: ${msg}`);
|
|
739
|
+
console.log(color.dim(" Tip: run 'opencode models' to see listed models, but not all may be available on your plan."));
|
|
740
|
+
throw new Error(`${m.label} model unavailable: ${msg}`);
|
|
741
|
+
}
|
|
742
|
+
log.ok(`${m.label} model verified: ${m.spec}`);
|
|
743
|
+
} catch (probeErr) {
|
|
744
|
+
if (probeErr.message.includes("unavailable") || probeErr.message.includes("rejected")) {
|
|
745
|
+
throw probeErr; // re-throw our own errors
|
|
746
|
+
}
|
|
747
|
+
// API call itself failed — might be a transient issue
|
|
748
|
+
log.warn(`${m.label} model probe inconclusive: ${probeErr.message}`);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
711
752
|
// Start SSE event display
|
|
712
753
|
const eventDisplay = createEventDisplay(client);
|
|
713
754
|
eventDisplay.start().catch(() => {});
|