@oxecli/oxe 1.0.94 → 1.0.96
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/api.js +1 -2
- package/dist/config.js +2 -1
- package/dist/engine.js +32 -3
- package/dist/ui.js +25 -2
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -4,8 +4,7 @@ export async function validateOxeApiKey(apiKey) {
|
|
|
4
4
|
if (!key.startsWith(OXE_KEY_PREFIX)) {
|
|
5
5
|
return {
|
|
6
6
|
valid: false,
|
|
7
|
-
error: "Invalid API key format.
|
|
8
|
-
"Generate your key at: http://localhost:5173/dashboard/api-keys",
|
|
7
|
+
error: "Invalid API key format. Generate your key at: http://localhost:5173/dashboard/api-keys",
|
|
9
8
|
};
|
|
10
9
|
}
|
|
11
10
|
try {
|
package/dist/config.js
CHANGED
|
@@ -98,7 +98,8 @@ export function detectedShell() {
|
|
|
98
98
|
export function osPrefix() {
|
|
99
99
|
return (`Running environment: ${runtimeOsSummary()}. ` +
|
|
100
100
|
`Shell commands run via ${detectedShell()} ` +
|
|
101
|
-
|
|
101
|
+
`with \`shell=True\`, from the working directory \`${process.cwd()}\`; ` +
|
|
102
|
+
"use commands, quoting, and path separators " +
|
|
102
103
|
"appropriate to this OS.\n\n");
|
|
103
104
|
}
|
|
104
105
|
export const IGNORED_DIRS_BY_CATEGORY = [
|
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,19 @@ export class InferenceEngine {
|
|
|
151
155
|
let sawReasoning = false;
|
|
152
156
|
let status = null;
|
|
153
157
|
let thinkingStart = null;
|
|
154
|
-
|
|
158
|
+
// A "Worked for …" block is committed once per working phase. Each phase is
|
|
159
|
+
// interrupted (and the flag reset) by either real answer text or a tool
|
|
160
|
+
// call, so unlimited working blocks can appear — but never two in a row
|
|
161
|
+
// without an answer or tool call in between. The total worked time also
|
|
162
|
+
// lands in the final footer.
|
|
163
|
+
const showWorkSpinner = !this.workedCommitted;
|
|
164
|
+
if (showWorkSpinner)
|
|
165
|
+
dockTransientStart();
|
|
155
166
|
const workStatus = new Spinner();
|
|
156
167
|
const workingStarted = Date.now();
|
|
157
|
-
|
|
168
|
+
if (showWorkSpinner) {
|
|
169
|
+
workStatus.startWithRender(() => `Working ${tickDuration((Date.now() - workingStarted) / 1000)}`);
|
|
170
|
+
}
|
|
158
171
|
let workingReported = false;
|
|
159
172
|
let response = null;
|
|
160
173
|
let etype = null;
|
|
@@ -169,6 +182,12 @@ export class InferenceEngine {
|
|
|
169
182
|
workingReported = true;
|
|
170
183
|
const elapsed = (Date.now() - workingStarted) / 1000;
|
|
171
184
|
const t = tickDuration(elapsed);
|
|
185
|
+
if (!showWorkSpinner)
|
|
186
|
+
return;
|
|
187
|
+
// Reset immediately so a later working phase (after an answer or a tool
|
|
188
|
+
// call) may commit a fresh block; the per-streamOnce guard above keeps
|
|
189
|
+
// the current phase from duplicating.
|
|
190
|
+
this.workedCommitted = false;
|
|
172
191
|
story.push({ type: "worked", text: `Worked for ${t}` });
|
|
173
192
|
dockReplaceTransient(mutedMarkdown(`Worked for ${t}`) + "\n");
|
|
174
193
|
};
|
|
@@ -399,6 +418,7 @@ export class InferenceEngine {
|
|
|
399
418
|
this.interrupted = false;
|
|
400
419
|
this.queryHasOutput = false;
|
|
401
420
|
this.queryCalledTool = false;
|
|
421
|
+
this.workedCommitted = false;
|
|
402
422
|
this.activeAbort = new AbortController();
|
|
403
423
|
hideCursor();
|
|
404
424
|
inputItems.push({
|
|
@@ -521,7 +541,13 @@ export class InferenceEngine {
|
|
|
521
541
|
conversation.push(rp);
|
|
522
542
|
inputItems.push(rp);
|
|
523
543
|
retryPrompts.push(rp);
|
|
524
|
-
|
|
544
|
+
// Always retry with the full transcript in visible context (which
|
|
545
|
+
// includes the original user prompt), instead of relying solely on
|
|
546
|
+
// previous_response_id continuation. Server-side continuation of a
|
|
547
|
+
// cut-off response can lose the task context, leaving the model with
|
|
548
|
+
// "no context about what was being worked on."
|
|
549
|
+
prevId = null;
|
|
550
|
+
pending = conversation;
|
|
525
551
|
continue;
|
|
526
552
|
}
|
|
527
553
|
dropRetryPrompts(conversation, inputItems, retryPrompts);
|
|
@@ -546,6 +572,9 @@ export class InferenceEngine {
|
|
|
546
572
|
const toolSpinner = new Spinner();
|
|
547
573
|
toolSpinner.startDots("\x1b[90m╰─\x1b[0m Working");
|
|
548
574
|
const rawResult = await this.runTool(c.name, c.arguments);
|
|
575
|
+
// A tool call was made, which interrupts any current working phase,
|
|
576
|
+
// so the next agent iteration may commit a fresh "Worked for …" block.
|
|
577
|
+
this.workedCommitted = false;
|
|
549
578
|
if (this.interrupted) {
|
|
550
579
|
toolSpinner.stop();
|
|
551
580
|
throw new Error("interrupt");
|
package/dist/ui.js
CHANGED
|
@@ -1299,6 +1299,9 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = [], hin
|
|
|
1299
1299
|
if (done)
|
|
1300
1300
|
return;
|
|
1301
1301
|
done = true;
|
|
1302
|
+
const sentValue = isErr
|
|
1303
|
+
? null
|
|
1304
|
+
: value;
|
|
1302
1305
|
process.stdout.write("\x1b[?2004l");
|
|
1303
1306
|
process.stdin.setRawMode(false);
|
|
1304
1307
|
if (pasteBurstTimer)
|
|
@@ -1308,10 +1311,30 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = [], hin
|
|
|
1308
1311
|
dockSetInactive();
|
|
1309
1312
|
}
|
|
1310
1313
|
else {
|
|
1314
|
+
// Clear the sent prompt from the box immediately, so the field shows an
|
|
1315
|
+
// empty prompt as soon as the user sends it while the query streams
|
|
1316
|
+
// above the dock. The resolved value still carries the original sent
|
|
1317
|
+
// buffer/paste spans so the query and draft-restore keep working.
|
|
1318
|
+
const { frame, totalRows } = renderBufferWithCursor("", [], prefix, label, 0, hints);
|
|
1319
|
+
const newLines = frame.split("\n");
|
|
1311
1320
|
if (lastCursorRow > 0)
|
|
1312
1321
|
process.stdout.write(`\x1b[${lastCursorRow}A`);
|
|
1313
1322
|
process.stdout.write("\r");
|
|
1314
|
-
|
|
1323
|
+
const oldLines = prevFrameLines ?? [];
|
|
1324
|
+
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
1325
|
+
for (let i = 0; i < maxLen; i++) {
|
|
1326
|
+
process.stdout.write("\r\x1b[K" + (newLines[i] ?? ""));
|
|
1327
|
+
if (i < maxLen - 1)
|
|
1328
|
+
process.stdout.write("\n");
|
|
1329
|
+
}
|
|
1330
|
+
// Reposition at the box's top row so the dock can manage it. The erase
|
|
1331
|
+
// loop above ends with the cursor at row (maxLen - 1), so move up by
|
|
1332
|
+
// that many rows — NOT newLines.length - 1, which is too few whenever
|
|
1333
|
+
// the sent (old) box was taller than the emptied box (e.g. a wrapped or
|
|
1334
|
+
// multi-line prompt). Using the wrong count leaves the cursor below the
|
|
1335
|
+
// box top, desyncing the dock and corrupting later redraws.
|
|
1336
|
+
process.stdout.write(`\x1b[${maxLen - 1}A\r`);
|
|
1337
|
+
dockSetFrame(frame, totalRows);
|
|
1315
1338
|
dockEnterDocked();
|
|
1316
1339
|
}
|
|
1317
1340
|
process.stdin.removeListener("keypress", onKeypress);
|
|
@@ -1320,7 +1343,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = [], hin
|
|
|
1320
1343
|
if (isErr)
|
|
1321
1344
|
reject(value);
|
|
1322
1345
|
else
|
|
1323
|
-
resolve(
|
|
1346
|
+
resolve(sentValue);
|
|
1324
1347
|
};
|
|
1325
1348
|
const repaint = (isFirst = false) => {
|
|
1326
1349
|
const { frame, cursorRow, cursorCol, totalRows } = renderBufferWithCursor(buffer, pasteSpans, prefix, label, cursor, hints);
|