@tjamescouch/gro 1.3.10 → 1.3.12

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/dist/main.js CHANGED
@@ -22,7 +22,8 @@ import { groError, asError, isGroError, errorLogFields } from "./errors.js";
22
22
  import { bashToolDefinition, executeBash } from "./tools/bash.js";
23
23
  import { agentpatchToolDefinition, executeAgentpatch } from "./tools/agentpatch.js";
24
24
  import { groVersionToolDefinition, executeGroVersion, getGroVersion } from "./tools/version.js";
25
- import { createMarkerParser } from "./stream-markers.js";
25
+ // Stream marker imports parser disabled for now, markers pass through as visible text.
26
+ // import { createMarkerParser, extractMarkers } from "./stream-markers.js";
26
27
  const VERSION = getGroVersion();
27
28
  // ---------------------------------------------------------------------------
28
29
  // Graceful shutdown state — module-level so signal handlers can save sessions.
@@ -520,29 +521,15 @@ async function executeTurn(driver, memory, mcp, cfg, sessionId) {
520
521
  let brokeCleanly = false;
521
522
  let idleNudges = 0;
522
523
  for (let round = 0; round < cfg.maxToolRounds; round++) {
523
- // Create a fresh marker parser per round so partial state doesn't leak
524
- const markerParser = createMarkerParser({
525
- onToken: rawOnToken,
526
- onMarker(marker) {
527
- if (marker.name === "model-change") {
528
- const newModel = resolveModelAlias(marker.arg);
529
- Logger.info(`Stream marker: model-change '${marker.arg}' → ${newModel}`);
530
- activeModel = newModel;
531
- cfg.model = newModel; // persist across turns
532
- memory.setModel(newModel); // persist in session metadata on save
533
- }
534
- else {
535
- Logger.debug(`Stream marker: ${marker.name}('${marker.arg}')`);
536
- }
537
- },
538
- });
524
+ // Stream markers: currently pass-through (visible in output).
525
+ // Model-change and other marker actions are disabled until the
526
+ // infrastructure is ready for hot-swapping.
527
+ const onToken = rawOnToken;
539
528
  const output = await driver.chat(memory.messages(), {
540
529
  model: activeModel,
541
530
  tools: tools.length > 0 ? tools : undefined,
542
- onToken: markerParser.onToken,
531
+ onToken,
543
532
  });
544
- // Flush any remaining buffered tokens from the marker parser
545
- markerParser.flush();
546
533
  // Track token usage for niki budget enforcement
547
534
  if (output.usage) {
548
535
  turnTokensIn += output.usage.inputTokens;
@@ -550,13 +537,10 @@ async function executeTurn(driver, memory, mcp, cfg, sessionId) {
550
537
  // Log cumulative usage to stderr — niki parses these patterns for budget enforcement
551
538
  process.stderr.write(`"input_tokens": ${turnTokensIn}, "output_tokens": ${turnTokensOut}\n`);
552
539
  }
553
- // Accumulate clean text (markers stripped) for the return value
554
- const cleanText = markerParser.getCleanText();
555
- if (cleanText)
556
- finalText += cleanText;
557
- // Store clean text in memory — markers are runtime directives, not conversation content.
558
- // The original output.text is preserved in case we need it for debugging.
559
- const assistantMsg = { role: "assistant", from: "Assistant", content: cleanText || "" };
540
+ // Accumulate output text
541
+ if (output.text)
542
+ finalText += output.text;
543
+ const assistantMsg = { role: "assistant", from: "Assistant", content: output.text || "" };
560
544
  if (output.toolCalls.length > 0) {
561
545
  assistantMsg.tool_calls = output.toolCalls;
562
546
  }
@@ -686,12 +670,6 @@ async function singleShot(cfg, driver, mcp, sessionId, positionalArgs) {
686
670
  // Resume existing session if requested
687
671
  if (cfg.continueSession || cfg.resumeSession) {
688
672
  await memory.load(sessionId);
689
- const sess = loadSession(sessionId);
690
- if (sess?.meta.model && sess.meta.model !== cfg.model) {
691
- Logger.info(`Restoring model from session: ${cfg.model} → ${sess.meta.model}`);
692
- cfg.model = sess.meta.model;
693
- memory.setModel(sess.meta.model);
694
- }
695
673
  }
696
674
  await memory.add({ role: "user", from: "User", content: prompt });
697
675
  let text;
@@ -741,12 +719,6 @@ async function interactive(cfg, driver, mcp, sessionId) {
741
719
  if (sess) {
742
720
  const msgCount = sess.messages.filter((m) => m.role !== "system").length;
743
721
  Logger.info(C.gray(`Resumed session ${sessionId} (${msgCount} messages)`));
744
- // Restore model from session metadata (e.g. after a stream marker model-change)
745
- if (sess.meta.model && sess.meta.model !== cfg.model) {
746
- Logger.info(`Restoring model from session: ${cfg.model} → ${sess.meta.model}`);
747
- cfg.model = sess.meta.model;
748
- memory.setModel(sess.meta.model);
749
- }
750
722
  }
751
723
  }
752
724
  const rl = readline.createInterface({
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tjamescouch/gro",
3
- "version": "1.3.10",
3
+ "version": "1.3.12",
4
4
  "description": "Provider-agnostic LLM runtime with context management",
5
5
  "bin": {
6
6
  "gro": "./dist/main.js"
@@ -27,6 +27,31 @@ import { Logger } from "./logger.js";
27
27
  const MARKER_RE = /@@([a-zA-Z][a-zA-Z0-9_-]*)\((?:'([^']*)'|"([^"]*)"|([^)]*?))\)@@/g;
28
28
  /** Partial marker detection — we might be mid-stream in a marker */
29
29
  const PARTIAL_MARKER_RE = /@@[a-zA-Z][a-zA-Z0-9_-]*(?:\([^)]*)?$/;
30
+ /**
31
+ * Scan a string for markers, fire the handler for each, and return cleaned text.
32
+ * Unlike the streaming parser, this operates on a complete string (e.g. tool call arguments).
33
+ */
34
+ export function extractMarkers(text, onMarker) {
35
+ let cleaned = "";
36
+ let lastIndex = 0;
37
+ const regex = new RegExp(MARKER_RE.source, "g");
38
+ let match;
39
+ while ((match = regex.exec(text)) !== null) {
40
+ cleaned += text.slice(lastIndex, match.index);
41
+ const marker = {
42
+ name: match[1],
43
+ arg: match[2] ?? match[3] ?? match[4] ?? "",
44
+ raw: match[0],
45
+ };
46
+ try {
47
+ onMarker(marker);
48
+ }
49
+ catch { /* handled by caller */ }
50
+ lastIndex = match.index + match[0].length;
51
+ }
52
+ cleaned += text.slice(lastIndex);
53
+ return cleaned;
54
+ }
30
55
  export function createMarkerParser(opts) {
31
56
  const { onMarker, onToken } = opts;
32
57
  let buffer = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tjamescouch/gro",
3
- "version": "1.3.10",
3
+ "version": "1.3.12",
4
4
  "description": "Provider-agnostic LLM runtime with context management",
5
5
  "bin": {
6
6
  "gro": "./dist/main.js"