@tjamescouch/gro 1.3.2 → 1.3.3
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/drivers/anthropic.ts +6 -1
- package/src/main.ts +44 -5
package/package.json
CHANGED
package/src/drivers/anthropic.ts
CHANGED
|
@@ -26,12 +26,14 @@ function convertToolDefs(tools: any[]): any[] {
|
|
|
26
26
|
return tools.map(t => {
|
|
27
27
|
if (t.type === "function" && t.function) {
|
|
28
28
|
return {
|
|
29
|
+
type: "custom",
|
|
29
30
|
name: t.function.name,
|
|
30
31
|
description: t.function.description || "",
|
|
31
32
|
input_schema: t.function.parameters || { type: "object", properties: {} },
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
|
-
// Already in Anthropic format —
|
|
35
|
+
// Already in Anthropic format — ensure type is set
|
|
36
|
+
if (!t.type) return { type: "custom", ...t };
|
|
35
37
|
return t;
|
|
36
38
|
});
|
|
37
39
|
}
|
|
@@ -122,6 +124,9 @@ export function makeAnthropicDriver(cfg: AnthropicDriverConfig): ChatDriver {
|
|
|
122
124
|
|
|
123
125
|
const body: any = {
|
|
124
126
|
model: resolvedModel,
|
|
127
|
+
thinking: {
|
|
128
|
+
type: "adaptive"
|
|
129
|
+
},
|
|
125
130
|
max_tokens: maxTokens,
|
|
126
131
|
messages: apiMessages,
|
|
127
132
|
};
|
package/src/main.ts
CHANGED
|
@@ -28,6 +28,16 @@ import { agentpatchToolDefinition, executeAgentpatch } from "./tools/agentpatch.
|
|
|
28
28
|
|
|
29
29
|
const VERSION = "0.3.1";
|
|
30
30
|
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Graceful shutdown state — module-level so signal handlers can save sessions.
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
let _shutdownMemory: AgentMemory | null = null;
|
|
35
|
+
let _shutdownSessionId: string | null = null;
|
|
36
|
+
let _shutdownSessionPersistence = false;
|
|
37
|
+
|
|
38
|
+
/** Auto-save interval: save session every N tool rounds in persistent mode */
|
|
39
|
+
const AUTO_SAVE_INTERVAL = 10;
|
|
40
|
+
|
|
31
41
|
// Wake notes: a runner-global file that is prepended to the system prompt on process start
|
|
32
42
|
// so agents reliably see dev workflow + memory pointers on wake.
|
|
33
43
|
const WAKE_NOTES_DEFAULT_PATH = join(process.env.HOME || "", ".claude", "WAKE.md");
|
|
@@ -477,6 +487,7 @@ async function executeTurn(
|
|
|
477
487
|
memory: AgentMemory,
|
|
478
488
|
mcp: McpManager,
|
|
479
489
|
cfg: GroConfig,
|
|
490
|
+
sessionId?: string,
|
|
480
491
|
): Promise<string> {
|
|
481
492
|
const tools = mcp.getToolDefinitions();
|
|
482
493
|
tools.push(agentpatchToolDefinition());
|
|
@@ -573,6 +584,16 @@ async function executeTurn(
|
|
|
573
584
|
name: fnName,
|
|
574
585
|
});
|
|
575
586
|
}
|
|
587
|
+
|
|
588
|
+
// Auto-save periodically in persistent mode to survive SIGTERM/crashes
|
|
589
|
+
if (cfg.persistent && cfg.sessionPersistence && sessionId && round > 0 && round % AUTO_SAVE_INTERVAL === 0) {
|
|
590
|
+
try {
|
|
591
|
+
await memory.save(sessionId);
|
|
592
|
+
Logger.debug(`Auto-saved session ${sessionId} at round ${round}`);
|
|
593
|
+
} catch (e: unknown) {
|
|
594
|
+
Logger.warn(`Auto-save failed at round ${round}: ${asError(e).message}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
576
597
|
}
|
|
577
598
|
|
|
578
599
|
// If we exhausted maxToolRounds (loop didn't break via no-tool-calls),
|
|
@@ -619,6 +640,11 @@ async function singleShot(
|
|
|
619
640
|
|
|
620
641
|
const memory = createMemory(cfg, driver);
|
|
621
642
|
|
|
643
|
+
// Register for graceful shutdown
|
|
644
|
+
_shutdownMemory = memory;
|
|
645
|
+
_shutdownSessionId = sessionId;
|
|
646
|
+
_shutdownSessionPersistence = cfg.sessionPersistence;
|
|
647
|
+
|
|
622
648
|
// Resume existing session if requested
|
|
623
649
|
if (cfg.continueSession || cfg.resumeSession) {
|
|
624
650
|
await memory.load(sessionId);
|
|
@@ -628,7 +654,7 @@ async function singleShot(
|
|
|
628
654
|
|
|
629
655
|
let text: string | undefined;
|
|
630
656
|
try {
|
|
631
|
-
text = await executeTurn(driver, memory, mcp, cfg);
|
|
657
|
+
text = await executeTurn(driver, memory, mcp, cfg, sessionId);
|
|
632
658
|
} catch (e: unknown) {
|
|
633
659
|
const ge = isGroError(e) ? e : groError("provider_error", asError(e).message, { cause: e });
|
|
634
660
|
Logger.error(C.red(`error: ${ge.message}`), errorLogFields(ge));
|
|
@@ -661,6 +687,11 @@ async function interactive(
|
|
|
661
687
|
const memory = createMemory(cfg, driver);
|
|
662
688
|
const readline = await import("readline");
|
|
663
689
|
|
|
690
|
+
// Register for graceful shutdown
|
|
691
|
+
_shutdownMemory = memory;
|
|
692
|
+
_shutdownSessionId = sessionId;
|
|
693
|
+
_shutdownSessionPersistence = cfg.sessionPersistence;
|
|
694
|
+
|
|
664
695
|
// Resume existing session if requested
|
|
665
696
|
if (cfg.continueSession || cfg.resumeSession) {
|
|
666
697
|
await memory.load(sessionId);
|
|
@@ -691,7 +722,7 @@ async function interactive(
|
|
|
691
722
|
|
|
692
723
|
try {
|
|
693
724
|
await memory.add({ role: "user", from: "User", content: input });
|
|
694
|
-
await executeTurn(driver, memory, mcp, cfg);
|
|
725
|
+
await executeTurn(driver, memory, mcp, cfg, sessionId);
|
|
695
726
|
} catch (e: unknown) {
|
|
696
727
|
const ge = isGroError(e) ? e : groError("provider_error", asError(e).message, { cause: e });
|
|
697
728
|
Logger.error(C.red(`error: ${ge.message}`), errorLogFields(ge));
|
|
@@ -808,10 +839,18 @@ async function main() {
|
|
|
808
839
|
}
|
|
809
840
|
}
|
|
810
841
|
|
|
811
|
-
// Graceful shutdown on signals
|
|
842
|
+
// Graceful shutdown on signals — save session before exiting
|
|
812
843
|
for (const sig of ["SIGTERM", "SIGHUP"] as const) {
|
|
813
|
-
process.on(sig, () => {
|
|
814
|
-
Logger.info(C.gray(`\nreceived ${sig}, shutting down...`));
|
|
844
|
+
process.on(sig, async () => {
|
|
845
|
+
Logger.info(C.gray(`\nreceived ${sig}, saving session and shutting down...`));
|
|
846
|
+
if (_shutdownMemory && _shutdownSessionId && _shutdownSessionPersistence) {
|
|
847
|
+
try {
|
|
848
|
+
await _shutdownMemory.save(_shutdownSessionId);
|
|
849
|
+
Logger.info(C.gray(`session ${_shutdownSessionId} saved on ${sig}`));
|
|
850
|
+
} catch (e: unknown) {
|
|
851
|
+
Logger.error(C.red(`session save on ${sig} failed: ${asError(e).message}`));
|
|
852
|
+
}
|
|
853
|
+
}
|
|
815
854
|
process.exit(0);
|
|
816
855
|
});
|
|
817
856
|
}
|