novaprime 1.3.4 → 1.4.0
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/package.json +1 -1
- package/src/agent.js +18 -6
- package/src/ui.js +21 -2
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const ora = require('ora');
|
|
4
4
|
const tools = require('./tools');
|
|
5
|
-
const { c, aiLabel, error, warn } = require('./ui');
|
|
5
|
+
const { c, aiLabel, routeReport, error, warn } = require('./ui');
|
|
6
6
|
const { Renderer } = require('./render');
|
|
7
7
|
|
|
8
8
|
const SYSTEM_PROMPT =
|
|
@@ -50,8 +50,17 @@ async function streamMessage(server, key, messages) {
|
|
|
50
50
|
return { error: msg };
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// live model-switch report: show what the free Flash brain decided (only on a fresh prompt)
|
|
54
|
+
try {
|
|
55
|
+
const hdr = res.headers.get('x-novaprime-route');
|
|
56
|
+
if (hdr) {
|
|
57
|
+
const report = JSON.parse(decodeURIComponent(hdr));
|
|
58
|
+
if (report && report.fresh) { stopSpin(); routeReport(report); ensureSpin(c.muted('thinking')); }
|
|
59
|
+
}
|
|
60
|
+
} catch (_) {}
|
|
61
|
+
|
|
53
62
|
const blocks = [];
|
|
54
|
-
let stopReason = null, labelShown = false, buffer = '';
|
|
63
|
+
let stopReason = null, labelShown = false, buffer = '', usedModel = null;
|
|
55
64
|
const renderer = new Renderer();
|
|
56
65
|
const decoder = new TextDecoder();
|
|
57
66
|
const reader = res.body.getReader();
|
|
@@ -67,22 +76,25 @@ async function streamMessage(server, key, messages) {
|
|
|
67
76
|
if (!dataLine) continue;
|
|
68
77
|
let json; try { json = JSON.parse(dataLine.slice(5).trim()); } catch (_) { continue; }
|
|
69
78
|
|
|
70
|
-
if (json.type === '
|
|
79
|
+
if (json.type === 'message_start') {
|
|
80
|
+
usedModel = (json.message && json.message.model) || usedModel;
|
|
81
|
+
if (spinning) spinner.text = c.muted('thinking · ' + (usedModel || ''));
|
|
82
|
+
} else if (json.type === 'content_block_start') {
|
|
71
83
|
const cb = json.content_block || {};
|
|
72
84
|
blocks[json.index] = cb.type === 'tool_use'
|
|
73
85
|
? { type: 'tool_use', id: cb.id, name: cb.name, _json: '' }
|
|
74
86
|
: { type: 'text', text: '' };
|
|
75
|
-
if (cb.type === 'tool_use') ensureSpin(c.muted('
|
|
87
|
+
if (cb.type === 'tool_use') ensureSpin(c.muted('writing with ' + (usedModel || 'model') + '…'));
|
|
76
88
|
} else if (json.type === 'content_block_delta') {
|
|
77
89
|
const b = blocks[json.index]; if (!b) continue;
|
|
78
90
|
if (json.delta.type === 'text_delta') {
|
|
79
91
|
stopSpin();
|
|
80
|
-
if (!labelShown) { aiLabel(); labelShown = true; }
|
|
92
|
+
if (!labelShown) { aiLabel(usedModel); labelShown = true; }
|
|
81
93
|
b.text += json.delta.text;
|
|
82
94
|
renderer.feed(json.delta.text);
|
|
83
95
|
} else if (json.delta.type === 'input_json_delta') {
|
|
84
96
|
b._json += json.delta.partial_json;
|
|
85
|
-
ensureSpin(c.muted(
|
|
97
|
+
ensureSpin(c.muted('writing with ' + (usedModel || 'model') + '… ' + b._json.length + ' chars'));
|
|
86
98
|
}
|
|
87
99
|
} else if (json.type === 'message_delta') {
|
|
88
100
|
if (json.delta && json.delta.stop_reason) stopReason = json.delta.stop_reason;
|
package/src/ui.js
CHANGED
|
@@ -98,7 +98,26 @@ function inputBoxOpen() {
|
|
|
98
98
|
}
|
|
99
99
|
function inputBoxClose() { process.stdout.write('\n'); }
|
|
100
100
|
|
|
101
|
-
function aiLabel() { process.stdout.write('\n' + c.violet('● ') + c.violet.bold('Nova Prime') + '\n'); }
|
|
101
|
+
function aiLabel(model) { process.stdout.write('\n' + c.violet('● ') + c.violet.bold('Nova Prime') + (model ? c.dim(' · ' + model) : '') + '\n'); }
|
|
102
|
+
|
|
103
|
+
// Live "model switch" report — shows what the free Flash brain decided for this request.
|
|
104
|
+
function routeReport(r) {
|
|
105
|
+
if (!r) return;
|
|
106
|
+
const sep = c.dim(' → ');
|
|
107
|
+
const tag = c.violet('⚡ ') + c.muted('Flash analyzed');
|
|
108
|
+
let mid, model;
|
|
109
|
+
if (r.decision === 'build') {
|
|
110
|
+
mid = c.amber('new / heavy build');
|
|
111
|
+
model = c.white.bold('switched to ' + (r.chosenLabel || r.chosenModel));
|
|
112
|
+
} else if (r.escalated) {
|
|
113
|
+
mid = c.amber(r.reason || 'escalated');
|
|
114
|
+
model = c.white.bold('using ' + (r.chosenLabel || r.chosenModel));
|
|
115
|
+
} else {
|
|
116
|
+
mid = c.green('quick task');
|
|
117
|
+
model = c.body(r.chosenLabel || r.chosenModel) + (r.free ? c.dim(' · free') : '');
|
|
118
|
+
}
|
|
119
|
+
console.log('\n' + tag + sep + mid + sep + model);
|
|
120
|
+
}
|
|
102
121
|
|
|
103
122
|
function info(msg) { console.log(c.muted(msg)); }
|
|
104
123
|
function hint(msg) { console.log(c.dim(msg)); }
|
|
@@ -107,4 +126,4 @@ function error(msg) { console.log(c.red(' ✕ ') + c.red(msg)); }
|
|
|
107
126
|
function ok(msg) { console.log(c.green(' ✓ ') + c.body(msg)); }
|
|
108
127
|
function tool(name, detail) { console.log(c.dim(' · ' + name + (detail ? ' ' + detail : ''))); }
|
|
109
128
|
|
|
110
|
-
module.exports = { chalk, boxen, c, banner, maskKey, aiLabel, inputTop, inputBottom, inputPrompt, inputBoxOpen, inputBoxClose, info, hint, warn, error, ok, tool };
|
|
129
|
+
module.exports = { chalk, boxen, c, banner, maskKey, aiLabel, routeReport, inputTop, inputBottom, inputPrompt, inputBoxOpen, inputBoxClose, info, hint, warn, error, ok, tool };
|