promptimizer-cli 0.1.26 → 0.1.28
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 +84 -16
- package/package.json +1 -1
package/bin/promptimizer.mjs
CHANGED
|
@@ -190,10 +190,8 @@ function banner(session, version) {
|
|
|
190
190
|
if (hostCount > 1) out(` ${color(ANSI.dim, `${hostCount} hosts merged · router picks across all`)}`);
|
|
191
191
|
out(` ${color(ANSI.dim, `baseline ${baseline}`)}`);
|
|
192
192
|
out();
|
|
193
|
-
out(
|
|
194
|
-
|
|
195
|
-
);
|
|
196
|
-
out(` ${color(ANSI.dim, "Cache keys on full history — /clear then repeat a prompt to see cache hit")}`);
|
|
193
|
+
out(` ${color(ANSI.dim, "Type a prompt, or /help /hosts /models /connect /disconnect /clear /quit")}`);
|
|
194
|
+
out(` ${color(ANSI.dim, "Repeating the same last message hits prompt cache; /clear resets the chat thread")}`);
|
|
197
195
|
out();
|
|
198
196
|
}
|
|
199
197
|
|
|
@@ -302,8 +300,9 @@ function printMeta(result) {
|
|
|
302
300
|
if (meta.provider_id || meta.host) bits.push(String(meta.provider_id || meta.host));
|
|
303
301
|
if (saved != null) bits.push(`saved ${usd(saved)}`);
|
|
304
302
|
if (meta.exact_cache_hit) bits.push(color(ANSI.green, "cache hit"));
|
|
303
|
+
else if (meta.prompt_cache_hit) bits.push(color(ANSI.green, "prompt cache"));
|
|
305
304
|
else if (meta.semantic_cache_hit) {
|
|
306
|
-
const mode = meta.semantic_cache_mode === "full" ? "semantic full" : "semantic hybrid";
|
|
305
|
+
const mode = meta.semantic_cache_mode === "full" ? "semantic full" : meta.semantic_cache_mode === "prompt" ? "prompt cache" : "semantic hybrid";
|
|
307
306
|
const sim =
|
|
308
307
|
meta.semantic_similarity != null ? ` ${Math.round(Number(meta.semantic_similarity) * 100)}%` : "";
|
|
309
308
|
bits.push(color(ANSI.green, `${mode}${sim}`));
|
|
@@ -330,6 +329,76 @@ async function complete(flags, config, messages) {
|
|
|
330
329
|
});
|
|
331
330
|
}
|
|
332
331
|
|
|
332
|
+
/** Stream a completion; writes tokens to stdout as they arrive. Returns { text, result }. */
|
|
333
|
+
async function completeStream(flags, config, messages) {
|
|
334
|
+
const gatewayURL = gateway(flags, config);
|
|
335
|
+
const { apiKey, sessionId } = authFromConfig(flags, config);
|
|
336
|
+
const headers = { "content-type": "application/json" };
|
|
337
|
+
if (apiKey) headers.authorization = `Bearer ${apiKey}`;
|
|
338
|
+
else if (sessionId) {
|
|
339
|
+
headers.authorization = `Bearer ${sessionId}`;
|
|
340
|
+
headers["x-promptimizer-session"] = sessionId;
|
|
341
|
+
}
|
|
342
|
+
const response = await fetch(`${gatewayURL}/v1/chat/completions`, {
|
|
343
|
+
method: "POST",
|
|
344
|
+
headers,
|
|
345
|
+
body: JSON.stringify({ messages, stream: true }),
|
|
346
|
+
});
|
|
347
|
+
if (!response.ok) {
|
|
348
|
+
const data = await response.json().catch(() => ({}));
|
|
349
|
+
const detail =
|
|
350
|
+
typeof data === "object" && data && "detail" in data ? String(data.detail) : response.statusText;
|
|
351
|
+
throw Object.assign(new Error(detail), { status: response.status });
|
|
352
|
+
}
|
|
353
|
+
if (!response.body) {
|
|
354
|
+
const data = await response.json();
|
|
355
|
+
return { text: data.choices?.[0]?.message?.content?.trim() ?? "", result: data };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const reader = response.body.getReader();
|
|
359
|
+
const decoder = new TextDecoder();
|
|
360
|
+
let buffer = "";
|
|
361
|
+
let text = "";
|
|
362
|
+
let result = {
|
|
363
|
+
model: undefined,
|
|
364
|
+
usage: undefined,
|
|
365
|
+
promptimizer: undefined,
|
|
366
|
+
choices: [{ message: { role: "assistant", content: "" } }],
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
while (true) {
|
|
370
|
+
const { done, value } = await reader.read();
|
|
371
|
+
if (done) break;
|
|
372
|
+
buffer += decoder.decode(value, { stream: true });
|
|
373
|
+
const parts = buffer.split("\n");
|
|
374
|
+
buffer = parts.pop() ?? "";
|
|
375
|
+
for (const line of parts) {
|
|
376
|
+
const trimmed = line.trim();
|
|
377
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
378
|
+
const data = trimmed.slice(5).trim();
|
|
379
|
+
if (!data) continue;
|
|
380
|
+
if (data === "[DONE]") continue;
|
|
381
|
+
try {
|
|
382
|
+
const parsed = JSON.parse(data);
|
|
383
|
+
if (parsed.error?.message) throw new Error(parsed.error.message);
|
|
384
|
+
const delta = parsed.choices?.[0]?.delta?.content;
|
|
385
|
+
if (delta) {
|
|
386
|
+
text += delta;
|
|
387
|
+
process.stdout.write(delta);
|
|
388
|
+
}
|
|
389
|
+
if (parsed.promptimizer) result.promptimizer = parsed.promptimizer;
|
|
390
|
+
if (parsed.usage) result.usage = parsed.usage;
|
|
391
|
+
if (parsed.model) result.model = parsed.model;
|
|
392
|
+
} catch (err) {
|
|
393
|
+
if (err instanceof Error && err.message && !err.message.includes("JSON")) throw err;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
result.choices = [{ message: { role: "assistant", content: text } }];
|
|
399
|
+
return { text, result };
|
|
400
|
+
}
|
|
401
|
+
|
|
333
402
|
async function cmdLogin(flags) {
|
|
334
403
|
const apiKey = flags.key || flags.k || process.env.PROMPTIMIZER_API_KEY;
|
|
335
404
|
if (!apiKey) die("Missing --key. Create one at /account.");
|
|
@@ -466,10 +535,11 @@ async function cmdChat(flags, positional) {
|
|
|
466
535
|
const config = readConfig();
|
|
467
536
|
const prompt = String(flags.prompt || positional.join(" ")).trim();
|
|
468
537
|
if (!prompt) die('Usage: promptimizer chat "What is 17 * 24?"');
|
|
469
|
-
const result = await complete(flags, config, [{ role: "user", content: prompt }]);
|
|
470
|
-
const text = result.choices?.[0]?.message?.content?.trim() ?? "";
|
|
471
538
|
out();
|
|
472
|
-
out(
|
|
539
|
+
out(color(ANSI.magenta, "✦"));
|
|
540
|
+
const { text, result } = await completeStream(flags, config, [{ role: "user", content: prompt }]);
|
|
541
|
+
if (!text) process.stdout.write(color(ANSI.dim, "(empty)"));
|
|
542
|
+
process.stdout.write("\n");
|
|
473
543
|
out();
|
|
474
544
|
printMeta(result);
|
|
475
545
|
out();
|
|
@@ -674,20 +744,18 @@ async function interactive(flags) {
|
|
|
674
744
|
}
|
|
675
745
|
|
|
676
746
|
history.push({ role: "user", content: trimmed });
|
|
677
|
-
|
|
747
|
+
out();
|
|
748
|
+
out(color(ANSI.magenta, "✦"));
|
|
678
749
|
try {
|
|
679
|
-
const result = await
|
|
680
|
-
process.stdout.write("
|
|
681
|
-
|
|
750
|
+
const { text, result } = await completeStream(flags, readConfig(), history);
|
|
751
|
+
if (!text) process.stdout.write(color(ANSI.dim, "(empty)"));
|
|
752
|
+
process.stdout.write("\n");
|
|
682
753
|
history.push({ role: "assistant", content: text });
|
|
683
754
|
out();
|
|
684
|
-
out(color(ANSI.magenta, "✦"));
|
|
685
|
-
out(text);
|
|
686
|
-
out();
|
|
687
755
|
printMeta(result);
|
|
688
756
|
out();
|
|
689
757
|
} catch (error) {
|
|
690
|
-
process.stdout.write("
|
|
758
|
+
process.stdout.write("\n");
|
|
691
759
|
history.pop();
|
|
692
760
|
out(color(ANSI.yellow, ` ${error instanceof Error ? error.message : String(error)}`));
|
|
693
761
|
out();
|