@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tjamescouch/gro",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "Provider-agnostic LLM runtime with context management",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -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 — pass through
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
  }