@oxecli/oxe 1.0.92 → 1.0.95
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/engine.js +18 -2
- package/dist/ui.js +73 -36
- package/package.json +1 -1
package/dist/engine.js
CHANGED
|
@@ -49,6 +49,10 @@ export class InferenceEngine {
|
|
|
49
49
|
queryHasOutput = false;
|
|
50
50
|
queryCalledTool = false;
|
|
51
51
|
temperature;
|
|
52
|
+
/** True once a "Worked for …" line has been committed during the current
|
|
53
|
+
* query, so subsequent tool iterations don't pile up duplicate working
|
|
54
|
+
* blocks. The total worked time is summarized in the final footer. */
|
|
55
|
+
workedCommitted = false;
|
|
52
56
|
storedResponseIds = [];
|
|
53
57
|
constructor(config) {
|
|
54
58
|
this.modelName = config["model_name"];
|
|
@@ -151,10 +155,18 @@ export class InferenceEngine {
|
|
|
151
155
|
let sawReasoning = false;
|
|
152
156
|
let status = null;
|
|
153
157
|
let thinkingStart = null;
|
|
154
|
-
|
|
158
|
+
// Only the first API pass in a query shows the "Working…" spinner and a
|
|
159
|
+
// committed "Worked for …" block. Subsequent tool iterations run silently
|
|
160
|
+
// (the tool labels/results already give feedback) so duplicate working
|
|
161
|
+
// blocks never stack; the total worked time lands in the final footer.
|
|
162
|
+
const showWorkSpinner = !this.workedCommitted;
|
|
163
|
+
if (showWorkSpinner)
|
|
164
|
+
dockTransientStart();
|
|
155
165
|
const workStatus = new Spinner();
|
|
156
166
|
const workingStarted = Date.now();
|
|
157
|
-
|
|
167
|
+
if (showWorkSpinner) {
|
|
168
|
+
workStatus.startWithRender(() => `Working ${tickDuration((Date.now() - workingStarted) / 1000)}`);
|
|
169
|
+
}
|
|
158
170
|
let workingReported = false;
|
|
159
171
|
let response = null;
|
|
160
172
|
let etype = null;
|
|
@@ -169,6 +181,9 @@ export class InferenceEngine {
|
|
|
169
181
|
workingReported = true;
|
|
170
182
|
const elapsed = (Date.now() - workingStarted) / 1000;
|
|
171
183
|
const t = tickDuration(elapsed);
|
|
184
|
+
if (!showWorkSpinner)
|
|
185
|
+
return;
|
|
186
|
+
this.workedCommitted = true;
|
|
172
187
|
story.push({ type: "worked", text: `Worked for ${t}` });
|
|
173
188
|
dockReplaceTransient(mutedMarkdown(`Worked for ${t}`) + "\n");
|
|
174
189
|
};
|
|
@@ -399,6 +414,7 @@ export class InferenceEngine {
|
|
|
399
414
|
this.interrupted = false;
|
|
400
415
|
this.queryHasOutput = false;
|
|
401
416
|
this.queryCalledTool = false;
|
|
417
|
+
this.workedCommitted = false;
|
|
402
418
|
this.activeAbort = new AbortController();
|
|
403
419
|
hideCursor();
|
|
404
420
|
inputItems.push({
|
package/dist/ui.js
CHANGED
|
@@ -603,21 +603,39 @@ export function dockTearDown() {
|
|
|
603
603
|
dockFrameLines = [];
|
|
604
604
|
}
|
|
605
605
|
}
|
|
606
|
-
/** Park a transient spinner
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
606
|
+
/** Park a transient spinner row above the box. "flush" parks it directly under
|
|
607
|
+
* the preceding content (so a tool result is adjacent to its label); "blank"
|
|
608
|
+
* gives it its own blank row above. The single blank gap between content and
|
|
609
|
+
* box is always preserved. Idempotent while parked.
|
|
610
|
+
*
|
|
611
|
+
* This dock uses an erase-and-redraw model (never insert-lines), so it stays
|
|
612
|
+
* stable when the box sits near the bottom of a real terminal, where
|
|
613
|
+
* inserting lines would otherwise scroll the box off-screen. */
|
|
610
614
|
export function dockTransientStart(mode = "blank") {
|
|
611
615
|
if (!docked || dockBoxRows < 1)
|
|
612
616
|
return;
|
|
613
617
|
if (dockTransient)
|
|
614
618
|
return;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
process.stdout.write("\x1b[1A");
|
|
619
|
-
|
|
620
|
-
|
|
619
|
+
dockEraseBox();
|
|
620
|
+
if (mode === "flush") {
|
|
621
|
+
// Park on the gap row directly under the preceding content (adjacent).
|
|
622
|
+
process.stdout.write("\x1b[1A\r");
|
|
623
|
+
process.stdout.write("\n");
|
|
624
|
+
process.stdout.write(dockFrameLines.join("\n"));
|
|
625
|
+
process.stdout.write(`\x1b[${dockBoxRows - 1}A`);
|
|
626
|
+
process.stdout.write("\x1b[1A\r");
|
|
627
|
+
dockRel = 1;
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
// Park on a fresh spinner row that keeps a blank above and below it.
|
|
631
|
+
process.stdout.write("\n\n");
|
|
632
|
+
process.stdout.write(dockFrameLines.join("\n"));
|
|
633
|
+
process.stdout.write(`\x1b[${dockBoxRows - 1}A`);
|
|
634
|
+
process.stdout.write("\x1b[2A\r");
|
|
635
|
+
dockRel = 2;
|
|
636
|
+
}
|
|
637
|
+
docked = true;
|
|
638
|
+
dockGap = false;
|
|
621
639
|
dockTransient = true;
|
|
622
640
|
}
|
|
623
641
|
/** Erase the box and any transient rows above it, leaving the cursor at boxTop
|
|
@@ -642,9 +660,37 @@ function dockEraseBox() {
|
|
|
642
660
|
dockGap = true;
|
|
643
661
|
dockTransient = false;
|
|
644
662
|
}
|
|
645
|
-
/**
|
|
646
|
-
* (
|
|
647
|
-
|
|
663
|
+
/** Erase the box and transient rows, leaving the cursor on the transient row
|
|
664
|
+
* (so dockReplaceTransient can write new content in its place). */
|
|
665
|
+
function dockEraseBoxKeep() {
|
|
666
|
+
if (!docked || dockBoxRows < 1)
|
|
667
|
+
return;
|
|
668
|
+
process.stdout.write(`\x1b[${dockBoxRows - 1 + dockRel}B`);
|
|
669
|
+
for (let i = 0; i < dockBoxRows; i++) {
|
|
670
|
+
process.stdout.write("\r\x1b[K");
|
|
671
|
+
if (i < dockBoxRows - 1)
|
|
672
|
+
process.stdout.write("\x1b[1A");
|
|
673
|
+
}
|
|
674
|
+
process.stdout.write(`\x1b[${dockRel}A`);
|
|
675
|
+
docked = false;
|
|
676
|
+
dockRel = 0;
|
|
677
|
+
dockGap = true;
|
|
678
|
+
dockTransient = false;
|
|
679
|
+
}
|
|
680
|
+
/** Write one blank gap row then the box frame below the current row, and park
|
|
681
|
+
* the cursor at the box top. */
|
|
682
|
+
function dockRenderBox() {
|
|
683
|
+
if (dockBoxRows < 1)
|
|
684
|
+
return;
|
|
685
|
+
process.stdout.write("\n\n" + dockFrameLines.join("\n"));
|
|
686
|
+
process.stdout.write(`\x1b[${dockBoxRows - 1}A\r`);
|
|
687
|
+
dockRel = 0;
|
|
688
|
+
docked = true;
|
|
689
|
+
dockGap = false;
|
|
690
|
+
dockTransient = false;
|
|
691
|
+
}
|
|
692
|
+
/** Commit content at the box top, pushing the box down, preserving exactly one
|
|
693
|
+
* blank row between the content and the box. */
|
|
648
694
|
export function dockAppendContent(text) {
|
|
649
695
|
if (!text)
|
|
650
696
|
return;
|
|
@@ -652,18 +698,15 @@ export function dockAppendContent(text) {
|
|
|
652
698
|
process.stdout.write(text);
|
|
653
699
|
return;
|
|
654
700
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
process.stdout.write("\x1b[1B\r");
|
|
701
|
+
dockEraseBox();
|
|
702
|
+
process.stdout.write(text);
|
|
703
|
+
const tb = displayRows(text) - displayRows(text.replace(/\n+$/, ""));
|
|
704
|
+
if (tb > 0)
|
|
705
|
+
process.stdout.write(`\x1b[${tb}A`);
|
|
706
|
+
dockRenderBox();
|
|
662
707
|
}
|
|
663
|
-
/** Replace a transient spinner row
|
|
664
|
-
*
|
|
665
|
-
* down by `rows-1` if the content is taller than the transient row, write the
|
|
666
|
-
* content, and park the cursor at the boxTop with one blank row above it. */
|
|
708
|
+
/** Replace a transient spinner row with real (possibly multi-row) content, then
|
|
709
|
+
* re-dock, keeping exactly one blank row between content and box. */
|
|
667
710
|
export function dockReplaceTransient(text) {
|
|
668
711
|
if (!text)
|
|
669
712
|
return;
|
|
@@ -675,18 +718,12 @@ export function dockReplaceTransient(text) {
|
|
|
675
718
|
dockAppendContent(text);
|
|
676
719
|
return;
|
|
677
720
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
if (push > 0)
|
|
685
|
-
process.stdout.write(`\x1b[${push}L`);
|
|
686
|
-
process.stdout.write(body);
|
|
687
|
-
process.stdout.write("\x1b[2B\r");
|
|
688
|
-
dockRel = 0;
|
|
689
|
-
dockTransient = false;
|
|
721
|
+
dockEraseBoxKeep();
|
|
722
|
+
process.stdout.write(text);
|
|
723
|
+
const tb = displayRows(text) - displayRows(text.replace(/\n+$/, ""));
|
|
724
|
+
if (tb > 0)
|
|
725
|
+
process.stdout.write(`\x1b[${tb}A`);
|
|
726
|
+
dockRenderBox();
|
|
690
727
|
}
|
|
691
728
|
// ---------------------------------------------------------------------------
|
|
692
729
|
// Cursor & Spinner
|