promptimizer-cli 0.1.50 → 0.1.51
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/bin/promptimizer.mjs +85 -6
- package/package.json +1 -1
package/bin/promptimizer.mjs
CHANGED
|
@@ -153,6 +153,74 @@ function printAnswer(text) {
|
|
|
153
153
|
process.stdout.write(`${rendered}\n`);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
function sleep(ms) {
|
|
157
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Split so ANSI escapes stay intact while typewriting. */
|
|
161
|
+
function ansiChunks(text) {
|
|
162
|
+
const parts = [];
|
|
163
|
+
const re = /\x1b\[[0-9;]*m|[^\x1b]+/g;
|
|
164
|
+
let match;
|
|
165
|
+
while ((match = re.exec(String(text)))) parts.push(match[0]);
|
|
166
|
+
return parts;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Stream clean markdown to the terminal. Cache hits use a very high CPS so
|
|
171
|
+
* the replay feels snappy instead of dumping raw markdown source.
|
|
172
|
+
*/
|
|
173
|
+
async function streamAnswer(text, opts = {}) {
|
|
174
|
+
if (!text) {
|
|
175
|
+
out(color(ANSI.dim, "(empty)"));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!ANSI_OK) {
|
|
179
|
+
process.stdout.write(`${text}\n`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const rendered = renderMarkdown(text);
|
|
183
|
+
const cacheHit = Boolean(opts.cacheHit);
|
|
184
|
+
// ~chars per second for the visible body (escapes are free)
|
|
185
|
+
const cps = cacheHit ? 14_000 : opts.fast ? 9_000 : 5_500;
|
|
186
|
+
const chunkSize = Math.max(8, Math.floor(cps / 80));
|
|
187
|
+
let pending = "";
|
|
188
|
+
let visible = 0;
|
|
189
|
+
|
|
190
|
+
for (const part of ansiChunks(rendered)) {
|
|
191
|
+
if (part.startsWith("\x1b")) {
|
|
192
|
+
process.stdout.write(part);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
for (let i = 0; i < part.length; ) {
|
|
196
|
+
const slice = part.slice(i, i + chunkSize);
|
|
197
|
+
pending += slice;
|
|
198
|
+
visible += slice.length;
|
|
199
|
+
i += slice.length;
|
|
200
|
+
if (pending.length >= chunkSize || slice.includes("\n")) {
|
|
201
|
+
process.stdout.write(pending);
|
|
202
|
+
pending = "";
|
|
203
|
+
await sleep(Math.max(4, Math.round((1000 * chunkSize) / cps)));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (pending) process.stdout.write(pending);
|
|
208
|
+
process.stdout.write("\n");
|
|
209
|
+
// silence unused when tiny answers finish in one tick
|
|
210
|
+
void visible;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function isCacheHit(meta) {
|
|
214
|
+
if (!meta || typeof meta !== "object") return false;
|
|
215
|
+
return Boolean(
|
|
216
|
+
meta.exact_cache_hit ||
|
|
217
|
+
meta.prompt_cache_hit ||
|
|
218
|
+
meta.semantic_cache_hit ||
|
|
219
|
+
meta.prefix_cache_hit ||
|
|
220
|
+
meta.cache_hit,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
156
224
|
const COMMANDS = [
|
|
157
225
|
["", "Start interactive session (Gemini-style REPL)"],
|
|
158
226
|
["login", "Save a Promptimizer API key"],
|
|
@@ -462,7 +530,7 @@ async function complete(flags, config, messages) {
|
|
|
462
530
|
});
|
|
463
531
|
}
|
|
464
532
|
|
|
465
|
-
/** Stream a completion; buffers tokens
|
|
533
|
+
/** Stream a completion; buffers tokens (no raw dump), returns { text, result }. */
|
|
466
534
|
async function completeStream(flags, config, messages) {
|
|
467
535
|
const gatewayURL = gateway(flags, config);
|
|
468
536
|
const { apiKey, sessionId } = authFromConfig(flags, config);
|
|
@@ -500,6 +568,7 @@ async function completeStream(flags, config, messages) {
|
|
|
500
568
|
};
|
|
501
569
|
let spinTimer = null;
|
|
502
570
|
let spinFrame = 0;
|
|
571
|
+
const started = Date.now();
|
|
503
572
|
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
504
573
|
if (ANSI_OK) {
|
|
505
574
|
spinTimer = setInterval(() => {
|
|
@@ -542,7 +611,7 @@ async function completeStream(flags, config, messages) {
|
|
|
542
611
|
}
|
|
543
612
|
|
|
544
613
|
result.choices = [{ message: { role: "assistant", content: text } }];
|
|
545
|
-
return { text, result };
|
|
614
|
+
return { text, result, elapsedMs: Date.now() - started };
|
|
546
615
|
}
|
|
547
616
|
|
|
548
617
|
async function cmdLogin(flags) {
|
|
@@ -684,8 +753,14 @@ async function cmdChat(flags, positional) {
|
|
|
684
753
|
if (!prompt) die('Usage: promptimizer chat "What is 17 * 24?"');
|
|
685
754
|
out();
|
|
686
755
|
out(color(ANSI.magenta, "✦"));
|
|
687
|
-
const { text, result } = await completeStream(flags, config, [
|
|
688
|
-
|
|
756
|
+
const { text, result, elapsedMs } = await completeStream(flags, config, [
|
|
757
|
+
{ role: "user", content: prompt },
|
|
758
|
+
]);
|
|
759
|
+
const meta = result.promptimizer ?? {};
|
|
760
|
+
await streamAnswer(text, {
|
|
761
|
+
cacheHit: isCacheHit(meta),
|
|
762
|
+
fast: (elapsedMs ?? 0) < 500,
|
|
763
|
+
});
|
|
689
764
|
out();
|
|
690
765
|
printMeta(result);
|
|
691
766
|
out();
|
|
@@ -893,8 +968,12 @@ async function interactive(flags) {
|
|
|
893
968
|
out();
|
|
894
969
|
out(color(ANSI.magenta, "✦"));
|
|
895
970
|
try {
|
|
896
|
-
const { text, result } = await completeStream(flags, readConfig(), history);
|
|
897
|
-
|
|
971
|
+
const { text, result, elapsedMs } = await completeStream(flags, readConfig(), history);
|
|
972
|
+
const meta = result.promptimizer ?? {};
|
|
973
|
+
await streamAnswer(text, {
|
|
974
|
+
cacheHit: isCacheHit(meta),
|
|
975
|
+
fast: (elapsedMs ?? 0) < 500,
|
|
976
|
+
});
|
|
898
977
|
history.push({ role: "assistant", content: text });
|
|
899
978
|
out();
|
|
900
979
|
printMeta(result);
|