aiden-runtime 4.1.3 → 4.1.4
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/cli/v4/callbacks.js +70 -13
- package/dist/cli/v4/chatSession.js +130 -22
- package/dist/cli/v4/defaultSoul.js +69 -2
- package/dist/cli/v4/display/frame.js +234 -0
- package/dist/cli/v4/display/progressBar.js +137 -0
- package/dist/cli/v4/display.js +427 -21
- package/dist/cli/v4/replyRenderer.js +196 -26
- package/dist/cli/v4/skinEngine.js +15 -4
- package/dist/cli/v4/toolPreview.js +68 -19
- package/dist/core/v4/aidenAgent.js +9 -0
- package/dist/core/v4/promptBuilder.js +2 -1
- package/dist/core/version.js +1 -1
- package/dist/providers/v4/anthropicAdapter.js +25 -2
- package/package.json +2 -1
|
@@ -27,10 +27,16 @@
|
|
|
27
27
|
*/
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.getReplyRenderer = getReplyRenderer;
|
|
30
|
+
exports.normalizeBlankLines = normalizeBlankLines;
|
|
30
31
|
exports._resetForTests = _resetForTests;
|
|
31
32
|
const marked_1 = require("marked");
|
|
32
33
|
const skinEngine_1 = require("./skinEngine");
|
|
33
34
|
const syntaxHighlight_1 = require("./syntaxHighlight");
|
|
35
|
+
// v4.1.4 reply-quality polish: single source of truth for frame math.
|
|
36
|
+
// Replaces 3 inline `Math.min(process.stdout.columns ?? 80, 100) - 4`
|
|
37
|
+
// callsites in this file with `getBodyWidth()` and adds soft-wrap for
|
|
38
|
+
// code-block lines that previously overflowed the viewport.
|
|
39
|
+
const frame_1 = require("./display/frame");
|
|
34
40
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
35
41
|
const TerminalRenderer = require('marked-terminal').default ?? require('marked-terminal');
|
|
36
42
|
function paint(kind) {
|
|
@@ -120,7 +126,11 @@ const CODE_BG_ON = '\x1b[48;2;50;50;60m';
|
|
|
120
126
|
const CODE_BG_OFF = '\x1b[49m';
|
|
121
127
|
function renderCodeBlock(code, lang) {
|
|
122
128
|
const sk = (0, skinEngine_1.getSkinEngine)();
|
|
123
|
-
|
|
129
|
+
// v4.1.4 reply-quality polish: width sourced from frame.ts. Same
|
|
130
|
+
// visual budget as the v4.1.3 formula (cols capped at 100, minus
|
|
131
|
+
// gutter+2) — but expressed via the shared helper so it tracks any
|
|
132
|
+
// future width-policy change in one place.
|
|
133
|
+
const width = (0, frame_1.getBodyWidth)();
|
|
124
134
|
const langLabel = (lang ?? '').trim();
|
|
125
135
|
// v4.1.3-essentials reply-polish: language tag on the top rule
|
|
126
136
|
// already shipped; keep it. Bottom rule unlabeled (closing fence).
|
|
@@ -131,26 +141,43 @@ function renderCodeBlock(code, lang) {
|
|
|
131
141
|
const body = (0, syntaxHighlight_1.isSupportedLang)(langLabel)
|
|
132
142
|
? (0, syntaxHighlight_1.highlightCode)(code, langLabel)
|
|
133
143
|
: code;
|
|
134
|
-
// v4.1.
|
|
135
|
-
//
|
|
144
|
+
// v4.1.4 reply-quality polish: per-line soft wrap. The rail + bg
|
|
145
|
+
// chrome adds 4 visible columns (` │ `, padding spaces around the
|
|
146
|
+
// line). Subtract those so wrap math targets the actual content
|
|
147
|
+
// budget. `hard: true` ensures even pathological long tokens
|
|
148
|
+
// (minified JS, hashes) break instead of escaping the frame.
|
|
149
|
+
//
|
|
150
|
+
// Width inside the body of a code line:
|
|
151
|
+
// gutter (3) + `│ ` (2) + leading-space (1) + CONTENT + trailing-space (1)
|
|
152
|
+
// → content budget = width - gutter - 4. We further cap at width to
|
|
153
|
+
// keep the fence rule aligned with the body's right margin.
|
|
154
|
+
const contentBudget = Math.max(8, width - frame_1.GUTTER - 4);
|
|
155
|
+
// v4.1.3-essentials reply-polish (preserved): each body line gets:
|
|
156
|
+
// - frame gutter (was 2-space outer indent; now uses shared GUTTER)
|
|
136
157
|
// - left rail `│ ` painted muted (mirrors blockquote's `┃ ` rail
|
|
137
158
|
// with a different glyph so they're visually distinct)
|
|
138
159
|
// - 24-bit dark background wrapping the rail + content (subtle
|
|
139
160
|
// "this is code" affordance without going full TUI box-frame)
|
|
140
|
-
//
|
|
141
|
-
// Strip the optional ANSI-only NO_COLOR gate by emitting bg codes
|
|
142
|
-
// unconditionally — the skin engine already short-circuits inner
|
|
143
|
-
// paint calls when NO_COLOR is set, and bare bg codes degrade
|
|
144
|
-
// gracefully on terminals that don't render them.
|
|
145
161
|
const rail = sk.applyColors('│', 'muted');
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
162
|
+
const gutter = (0, frame_1.getIndent)(0);
|
|
163
|
+
// Wrap each source line independently — code-block semantics demand
|
|
164
|
+
// that a "logical line" remains visible as one continued unit even
|
|
165
|
+
// when soft-wrapped. The CODE_BG painting closes per VISUAL line so
|
|
166
|
+
// a wrap break doesn't bleed bg across the rail of the next row.
|
|
167
|
+
const wrappedLines = [];
|
|
168
|
+
for (const srcLine of body.split('\n')) {
|
|
169
|
+
const wrapped = (0, frame_1.wrap)(srcLine, contentBudget, { trim: false, hard: true });
|
|
170
|
+
for (const visualLine of wrapped.split('\n')) {
|
|
171
|
+
wrappedLines.push(`${gutter}${rail} ${CODE_BG_ON} ${visualLine} ${CODE_BG_OFF}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const indented = wrappedLines.join('\n');
|
|
175
|
+
// Top + bottom fence rules sit at the gutter too — visually anchors
|
|
176
|
+
// the block as a unit inside the assistant frame.
|
|
150
177
|
return [
|
|
151
|
-
sk.applyColors(top, 'muted')
|
|
178
|
+
`${gutter}${sk.applyColors(top, 'muted')}`,
|
|
152
179
|
indented,
|
|
153
|
-
sk.applyColors(bot, 'muted')
|
|
180
|
+
`${gutter}${sk.applyColors(bot, 'muted')}`,
|
|
154
181
|
'',
|
|
155
182
|
].join('\n') + '\n';
|
|
156
183
|
}
|
|
@@ -222,6 +249,97 @@ function renderHeading(text, depth) {
|
|
|
222
249
|
function renderListItem(text) {
|
|
223
250
|
return text;
|
|
224
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* v4.1.4 reply-quality polish — Fix C helper.
|
|
254
|
+
*
|
|
255
|
+
* Render a single list item's tokens correctly, expanding inline
|
|
256
|
+
* emphasis (strong, em, codespan) that the prior `parser.parse` path
|
|
257
|
+
* silently stranded as raw text.
|
|
258
|
+
*
|
|
259
|
+
* Marked v15 token shapes for list items:
|
|
260
|
+
*
|
|
261
|
+
* Tight list (default — no blank lines between items):
|
|
262
|
+
* list_item.tokens = [
|
|
263
|
+
* { type: 'text', text: '**bold**',
|
|
264
|
+
* tokens: [ { type: 'strong', ... } ] ← inline children
|
|
265
|
+
* }
|
|
266
|
+
* ]
|
|
267
|
+
*
|
|
268
|
+
* Loose list (blank line between items, OR an item with multiple
|
|
269
|
+
* paragraphs):
|
|
270
|
+
* list_item.tokens = [
|
|
271
|
+
* { type: 'paragraph', tokens: [ inline children… ] },
|
|
272
|
+
* { type: 'paragraph', tokens: [ … ] },
|
|
273
|
+
* ]
|
|
274
|
+
*
|
|
275
|
+
* Nested list (a list-token inside an item):
|
|
276
|
+
* list_item.tokens = [
|
|
277
|
+
* { type: 'text', tokens: [...] }, ← the item's own text first
|
|
278
|
+
* { type: 'list', items: [...] }, ← then the nested list
|
|
279
|
+
* ]
|
|
280
|
+
*
|
|
281
|
+
* Item with fenced code block:
|
|
282
|
+
* list_item.tokens = [
|
|
283
|
+
* { type: 'text', ... },
|
|
284
|
+
* { type: 'code', text: '…', lang: '…' },
|
|
285
|
+
* ]
|
|
286
|
+
*
|
|
287
|
+
* Dispatch rules:
|
|
288
|
+
* - `text` with nested `.tokens` → parseInline(tokens)
|
|
289
|
+
* - `text` with only `.text` → fall through to raw text
|
|
290
|
+
* - `paragraph` → parseInline(paragraph.tokens) + '\n'
|
|
291
|
+
* - `list` / `code` / other block → parser.parse([token]) (block path)
|
|
292
|
+
*
|
|
293
|
+
* Returns the joined rendered string. Pure-ish: depends on marked's
|
|
294
|
+
* parser instance (closure-captured) but never mutates it.
|
|
295
|
+
*/
|
|
296
|
+
function renderListItemTokens(it, parser) {
|
|
297
|
+
const toks = Array.isArray(it.tokens) ? it.tokens : [];
|
|
298
|
+
if (toks.length === 0)
|
|
299
|
+
return it.text ?? '';
|
|
300
|
+
const out = [];
|
|
301
|
+
for (const raw of toks) {
|
|
302
|
+
if (typeof raw !== 'object' || raw === null)
|
|
303
|
+
continue;
|
|
304
|
+
const tk = raw;
|
|
305
|
+
const type = tk.type;
|
|
306
|
+
// Inline-only wrapper (tight-list common case). The `text` outer
|
|
307
|
+
// token holds inline children we want to expand into ANSI.
|
|
308
|
+
if (type === 'text') {
|
|
309
|
+
if (Array.isArray(tk.tokens) && tk.tokens.length > 0 && parser.parseInline) {
|
|
310
|
+
out.push(parser.parseInline(tk.tokens));
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
out.push(tk.text ?? '');
|
|
314
|
+
}
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
// Paragraph block (loose-list case). Marked wraps each paragraph's
|
|
318
|
+
// inline content in `.tokens`; render those inline + append a
|
|
319
|
+
// newline so multi-paragraph items stack visually.
|
|
320
|
+
if (type === 'paragraph') {
|
|
321
|
+
if (Array.isArray(tk.tokens) && tk.tokens.length > 0 && parser.parseInline) {
|
|
322
|
+
out.push(parser.parseInline(tk.tokens));
|
|
323
|
+
out.push('\n');
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
out.push(tk.text ?? '');
|
|
327
|
+
}
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
// Nested list, fenced code, or any other block-level token. The
|
|
331
|
+
// block parser handles these via the normal dispatch (which calls
|
|
332
|
+
// back into our own `renderer.list` override for nested lists —
|
|
333
|
+
// depth counter is already incremented before we got here).
|
|
334
|
+
if (parser.parse) {
|
|
335
|
+
out.push(parser.parse([tk]));
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
// Last-resort fallback: drop the token's text in raw.
|
|
339
|
+
out.push(tk.text ?? '');
|
|
340
|
+
}
|
|
341
|
+
return out.join('');
|
|
342
|
+
}
|
|
225
343
|
/**
|
|
226
344
|
* Singleton — caching is fine since options bind to the active skin
|
|
227
345
|
* via paint callbacks (which read getSkinEngine() each call).
|
|
@@ -246,7 +364,7 @@ function getReplyRenderer() {
|
|
|
246
364
|
// need for the 4-tier hierarchy. The prototype-level `renderer.heading`
|
|
247
365
|
// override below owns the depth extraction + tier selection end-to-end.
|
|
248
366
|
// marked-terminal's stripped-args call path never reaches our callback.
|
|
249
|
-
hr: () => paint('muted')('─'.repeat(
|
|
367
|
+
hr: () => paint('muted')('─'.repeat((0, frame_1.getBodyWidth)())) + '\n',
|
|
250
368
|
listitem: renderListItem,
|
|
251
369
|
paragraph: (text) => `${text}\n\n`,
|
|
252
370
|
// v4.1.3-essentials: bold renders as ANSI bold + underline
|
|
@@ -274,7 +392,12 @@ function getReplyRenderer() {
|
|
|
274
392
|
link: (assembled) => paint('accent')(assembled),
|
|
275
393
|
href: paint('accent'),
|
|
276
394
|
text: (text) => text,
|
|
277
|
-
|
|
395
|
+
// v4.1.4 reply-quality polish: marked-terminal's `width` is the
|
|
396
|
+
// *outer* canvas it formats into. Frame-aware body width keeps the
|
|
397
|
+
// tables / hr / hard-wrap targets inside our gutter envelope.
|
|
398
|
+
// `reflowText: false` (below) stays off — we own prose wrap via
|
|
399
|
+
// frame.wrap() in the display layer, not here.
|
|
400
|
+
width: (0, frame_1.getBodyWidth)(),
|
|
278
401
|
showSectionPrefix: false,
|
|
279
402
|
reflowText: false,
|
|
280
403
|
tab: 2,
|
|
@@ -417,17 +540,32 @@ function getReplyRenderer() {
|
|
|
417
540
|
const tok = body;
|
|
418
541
|
isOrdered = tok.ordered === true;
|
|
419
542
|
startNum = typeof tok.start === 'number' ? tok.start : 1;
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
//
|
|
423
|
-
//
|
|
424
|
-
// the
|
|
543
|
+
// v4.1.4 reply-quality polish — Fix C (token-type dispatch).
|
|
544
|
+
//
|
|
545
|
+
// Prior implementation called `parser.parse(it.tokens)` and let
|
|
546
|
+
// marked's block-parser dispatch each token. For tight-list items
|
|
547
|
+
// marked v15 wraps the item's content in a `text`-type outer
|
|
548
|
+
// token whose `.tokens` array holds the actual inline tokens
|
|
549
|
+
// (strong, em, codespan…). `parser.parse` dispatched the outer
|
|
550
|
+
// wrapper to `renderer.text` (our `opts.text` = identity), which
|
|
551
|
+
// returned the RAW raw `**bold**` source string — never recursing
|
|
552
|
+
// into the inline children. Result: literal asterisks in every
|
|
553
|
+
// bullet that contained inline emphasis.
|
|
554
|
+
//
|
|
555
|
+
// Fix: walk each top-level token by type. Tight-list items have
|
|
556
|
+
// a `text` wrapper → use `parseInline` on its nested tokens to
|
|
557
|
+
// expand strong/em/codespan. Loose-list items have block-level
|
|
558
|
+
// `paragraph`/`list`/`code` tokens → those need block-level
|
|
559
|
+
// recursion (delegates back to our list override for nested
|
|
560
|
+
// lists, preserving the depth counter).
|
|
561
|
+
//
|
|
562
|
+
// Confirmed against marked v15 token shapes from `marked.lexer`
|
|
563
|
+
// (see scripts/smoke-issue-c-tokens.ts).
|
|
425
564
|
const parser = this.parser;
|
|
426
565
|
items = (tok.items ?? []).map((it) => {
|
|
427
|
-
if (
|
|
428
|
-
return
|
|
429
|
-
|
|
430
|
-
return it.text ?? '';
|
|
566
|
+
if (!parser)
|
|
567
|
+
return it.text ?? '';
|
|
568
|
+
return renderListItemTokens(it, parser);
|
|
431
569
|
});
|
|
432
570
|
}
|
|
433
571
|
else {
|
|
@@ -485,7 +623,21 @@ function getReplyRenderer() {
|
|
|
485
623
|
// if other code transiently swaps the renderer.
|
|
486
624
|
marked_1.marked.setOptions({ renderer: renderer });
|
|
487
625
|
const out = marked_1.marked.parse(text);
|
|
488
|
-
|
|
626
|
+
const raw = typeof out === 'string' ? out : String(out);
|
|
627
|
+
// v4.1.4 Part 1.6 Issue I — collapse excess vertical spacing.
|
|
628
|
+
//
|
|
629
|
+
// Our `opts.paragraph` callback emits `text\n\n`, our
|
|
630
|
+
// `renderCodeBlock` ends with `\n\n`, and marked-terminal's
|
|
631
|
+
// outer block dispatch ALSO emits `\n\n` between adjacent
|
|
632
|
+
// blocks. Result: 4 newlines (3 visible blank lines) between
|
|
633
|
+
// paragraphs, after code blocks, between paragraphs and lists.
|
|
634
|
+
// Root-cause fix would require auditing marked-terminal's
|
|
635
|
+
// between-block separator across every override (risk-prone).
|
|
636
|
+
// Band-aid: collapse any run of 3+ newlines down to exactly 2
|
|
637
|
+
// (= one blank line). Mechanically safe — can only REMOVE
|
|
638
|
+
// excess whitespace, never add bad spacing. Existing single-
|
|
639
|
+
// blank-line gaps pass through unchanged.
|
|
640
|
+
return normalizeBlankLines(raw);
|
|
489
641
|
}
|
|
490
642
|
catch {
|
|
491
643
|
return text;
|
|
@@ -494,6 +646,24 @@ function getReplyRenderer() {
|
|
|
494
646
|
};
|
|
495
647
|
return cachedRenderer;
|
|
496
648
|
}
|
|
649
|
+
/**
|
|
650
|
+
* v4.1.4 Part 1.6 Issue I — collapse runs of 3+ consecutive newlines
|
|
651
|
+
* down to exactly 2 (a single blank line). Exported for unit-test
|
|
652
|
+
* access; pure with no side effects.
|
|
653
|
+
*
|
|
654
|
+
* Confirmed via `scripts/smoke-issue-i-spacing.ts`:
|
|
655
|
+
* - "A\n\n\n\nB" → "A\n\nB" (2 paras → 1 blank line)
|
|
656
|
+
* - "A\n\n\n\n\nB" → "A\n\nB" (3+ blanks all collapse)
|
|
657
|
+
* - "A\n\nB" → "A\n\nB" (already correct, unchanged)
|
|
658
|
+
* - "A\nB" → "A\nB" (single newline preserved)
|
|
659
|
+
* - "A\n" → "A\n" (trailing pass-through)
|
|
660
|
+
*
|
|
661
|
+
* Does NOT touch the list-under-padding case (lists ending with a
|
|
662
|
+
* single `\n` before a paragraph) — that's a v4.1.5 follow-up.
|
|
663
|
+
*/
|
|
664
|
+
function normalizeBlankLines(text) {
|
|
665
|
+
return text.replace(/\n{3,}/g, '\n\n');
|
|
666
|
+
}
|
|
497
667
|
/** Test reset — drops the cached renderer so a skin change picks up. */
|
|
498
668
|
function _resetForTests() {
|
|
499
669
|
cachedRenderer = null;
|
|
@@ -49,9 +49,15 @@ const DEFAULT_SKIN = {
|
|
|
49
49
|
error: [0xf4, 0x47, 0x47],
|
|
50
50
|
warn: [0xff, 0xc1, 0x07],
|
|
51
51
|
success: [0x4c, 0xaf, 0x50],
|
|
52
|
-
// v4.1.
|
|
53
|
-
//
|
|
54
|
-
|
|
52
|
+
// v4.1.4 reply-quality polish: muted shifts from neutral grey
|
|
53
|
+
// (#888888) to warm Aiden-tinted dim (#b8a89a). Mid-grey at +56
|
|
54
|
+
// brightness on red/green channels with a slight cool-down on
|
|
55
|
+
// blue, putting muted in the same warm family as brand orange
|
|
56
|
+
// (#FF6B35) without competing with it. Reads as "intentional
|
|
57
|
+
// dim" rather than washed-out terminal grey. Used by tool-trail
|
|
58
|
+
// gutter, status footer, code-block rail, blockquote rail, and
|
|
59
|
+
// display.dim() — surfaces the user reads constantly.
|
|
60
|
+
muted: [0xb8, 0xa8, 0x9a],
|
|
55
61
|
heading: BRAND_ORANGE,
|
|
56
62
|
// v4.1.3-repl-polish: session = soft cyan (ex-muted); used for IDs
|
|
57
63
|
// and the session-end card header labels.
|
|
@@ -84,7 +90,12 @@ const LIGHT_SKIN = {
|
|
|
84
90
|
error: [0xb0, 0x10, 0x10],
|
|
85
91
|
warn: [0x80, 0x60, 0x00],
|
|
86
92
|
success: [0x1b, 0x5e, 0x20],
|
|
87
|
-
|
|
93
|
+
// v4.1.4 reply-quality polish: proportional warm-shift for the
|
|
94
|
+
// light skin too. Was neutral #606060; new value #7a6e5e keeps the
|
|
95
|
+
// dark-on-light contrast budget but adds the same warm tint as the
|
|
96
|
+
// default skin's muted so themed surfaces feel coherent across
|
|
97
|
+
// skin switches.
|
|
98
|
+
muted: [0x7a, 0x6e, 0x5e],
|
|
88
99
|
heading: [0xc4, 0x42, 0x10],
|
|
89
100
|
session: [0x00, 0x55, 0x88],
|
|
90
101
|
degraded: [0x80, 0x60, 0x00],
|
|
@@ -29,9 +29,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.TOOL_PRIMARY_ARG = void 0;
|
|
30
30
|
exports.buildToolPreview = buildToolPreview;
|
|
31
31
|
/**
|
|
32
|
-
* Map of tool-name →
|
|
33
|
-
*
|
|
34
|
-
* entries.
|
|
32
|
+
* Map of tool-name → preview extractor (string key OR function).
|
|
33
|
+
* Stable contract; tests assert specific entries.
|
|
35
34
|
*/
|
|
36
35
|
exports.TOOL_PRIMARY_ARG = {
|
|
37
36
|
// ── terminal / execution ─────────────────────────────────────────────
|
|
@@ -100,6 +99,37 @@ exports.TOOL_PRIMARY_ARG = {
|
|
|
100
99
|
media_transport: 'target',
|
|
101
100
|
media_key: 'action',
|
|
102
101
|
app_input: 'app',
|
|
102
|
+
// ── v4.1.4 Phase 3b' (Issue H) ───────────────────────────────────────
|
|
103
|
+
// app_launch needs custom logic: when `app === 'explorer.exe'` the
|
|
104
|
+
// binary is just the URI dispatcher and the meaningful target is in
|
|
105
|
+
// `args[0]` (e.g. 'spotify:track/...'). Surface the protocol scheme
|
|
106
|
+
// ('spotify') rather than the dispatch binary. Falls through to the
|
|
107
|
+
// app name for normal exe launches.
|
|
108
|
+
app_launch: (args) => {
|
|
109
|
+
if (!args || typeof args !== 'object')
|
|
110
|
+
return '';
|
|
111
|
+
const a = args;
|
|
112
|
+
const appRaw = typeof a.app === 'string' ? a.app.trim() : '';
|
|
113
|
+
// URI-protocol case: explorer.exe + 'scheme:...' in args[0].
|
|
114
|
+
if (appRaw.toLowerCase() === 'explorer.exe' && Array.isArray(a.args)) {
|
|
115
|
+
const first = a.args[0];
|
|
116
|
+
if (typeof first === 'string' && first.length > 0) {
|
|
117
|
+
// Scheme requires ≥2 chars so Windows drive letters
|
|
118
|
+
// (`C:/path`) don't mis-detect as the scheme `C`. Real URI
|
|
119
|
+
// schemes (spotify, vscode, http, file, etc.) are all
|
|
120
|
+
// multi-char by RFC.
|
|
121
|
+
const m = first.match(/^([A-Za-z][A-Za-z0-9+.-]+):/);
|
|
122
|
+
if (m)
|
|
123
|
+
return m[1]; // 'spotify:track/...' → 'spotify'
|
|
124
|
+
return first; // No protocol — surface the raw arg
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return appRaw;
|
|
128
|
+
},
|
|
129
|
+
// Clipboard write — the actual text being copied is the meaningful
|
|
130
|
+
// target. Reads have no args worth showing (empty schema).
|
|
131
|
+
clipboard_write: 'text',
|
|
132
|
+
clipboard_read: '',
|
|
103
133
|
};
|
|
104
134
|
/**
|
|
105
135
|
* Maximum visible characters for the preview value. Long commands /
|
|
@@ -121,28 +151,47 @@ function buildToolPreview(toolName, args) {
|
|
|
121
151
|
if (!Object.prototype.hasOwnProperty.call(exports.TOOL_PRIMARY_ARG, toolName)) {
|
|
122
152
|
return null;
|
|
123
153
|
}
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return '';
|
|
129
|
-
const raw = args[argKey];
|
|
130
|
-
if (raw === undefined || raw === null)
|
|
131
|
-
return '';
|
|
154
|
+
const extractor = exports.TOOL_PRIMARY_ARG[toolName];
|
|
155
|
+
// v4.1.4 Phase 3b' (Issue H1): function extractor path. Used by
|
|
156
|
+
// tools whose preview can't be expressed as a single key lookup
|
|
157
|
+
// (e.g. app_launch with URI-protocol routing through explorer.exe).
|
|
132
158
|
let str;
|
|
133
|
-
if (typeof
|
|
134
|
-
str = raw;
|
|
135
|
-
}
|
|
136
|
-
else if (typeof raw === 'number' || typeof raw === 'boolean') {
|
|
137
|
-
str = String(raw);
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
159
|
+
if (typeof extractor === 'function') {
|
|
140
160
|
try {
|
|
141
|
-
|
|
161
|
+
const out = extractor(args);
|
|
162
|
+
str = typeof out === 'string' ? out : '';
|
|
142
163
|
}
|
|
143
164
|
catch {
|
|
165
|
+
// Extractor threw — degrade to empty preview rather than crash
|
|
166
|
+
// the tool-row render. The tool name + state cluster still
|
|
167
|
+
// carries enough info.
|
|
168
|
+
str = '';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// String-key path (legacy, unchanged behaviour).
|
|
173
|
+
const argKey = extractor;
|
|
174
|
+
if (argKey === '')
|
|
175
|
+
return '';
|
|
176
|
+
if (!args || typeof args !== 'object')
|
|
177
|
+
return '';
|
|
178
|
+
const raw = args[argKey];
|
|
179
|
+
if (raw === undefined || raw === null)
|
|
180
|
+
return '';
|
|
181
|
+
if (typeof raw === 'string') {
|
|
182
|
+
str = raw;
|
|
183
|
+
}
|
|
184
|
+
else if (typeof raw === 'number' || typeof raw === 'boolean') {
|
|
144
185
|
str = String(raw);
|
|
145
186
|
}
|
|
187
|
+
else {
|
|
188
|
+
try {
|
|
189
|
+
str = JSON.stringify(raw);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
str = String(raw);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
146
195
|
}
|
|
147
196
|
// Collapse whitespace so multi-line commands stay on one preview row.
|
|
148
197
|
str = str.replace(/\s+/g, ' ').trim();
|
|
@@ -650,6 +650,15 @@ class AidenAgent {
|
|
|
650
650
|
else if (evt.type === 'tool_call') {
|
|
651
651
|
runOptions.onToolCallStart?.(evt.toolCall);
|
|
652
652
|
}
|
|
653
|
+
else if (evt.type === 'progress') {
|
|
654
|
+
// v4.1.4 Part 1.6 — drive the per-turn token progress bar.
|
|
655
|
+
// Defensive try/catch — a misbehaving display sink must not
|
|
656
|
+
// tear down the stream consumer.
|
|
657
|
+
try {
|
|
658
|
+
runOptions.onProgress?.(evt.outputTokens, evt.maxTokens);
|
|
659
|
+
}
|
|
660
|
+
catch { /* progress sink errors don't block streaming */ }
|
|
661
|
+
}
|
|
653
662
|
else if (evt.type === 'done') {
|
|
654
663
|
finalOutput = evt.output;
|
|
655
664
|
}
|
|
@@ -128,7 +128,8 @@ const EXECUTION_DISCIPLINE_PROSE = [
|
|
|
128
128
|
'file"), you MUST immediately make the corresponding tool call in the same response.',
|
|
129
129
|
'Never end your turn with a promise of future action — execute it now. Every',
|
|
130
130
|
'response should either contain tool calls that make progress, or deliver a final',
|
|
131
|
-
'result.
|
|
131
|
+
'result. When the user requests an action, take it. When the user requests',
|
|
132
|
+
'discussion, discuss.',
|
|
132
133
|
].join('\n');
|
|
133
134
|
/**
|
|
134
135
|
* Llama-3.3-specific tool-call format guard. Adapter-side recovery picks
|
package/dist/core/version.js
CHANGED
|
@@ -114,7 +114,7 @@ class AnthropicAdapter {
|
|
|
114
114
|
};
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
|
-
yield* decodeStream(reply.body);
|
|
117
|
+
yield* decodeStream(reply.body, input.maxTokens ?? DEFAULT_MAX_TOKENS);
|
|
118
118
|
}
|
|
119
119
|
// ── Request body assembly ────────────────────────────────────────────────
|
|
120
120
|
buildBody(input, streaming) {
|
|
@@ -404,13 +404,20 @@ function decodeUsage(u) {
|
|
|
404
404
|
}
|
|
405
405
|
return out;
|
|
406
406
|
}
|
|
407
|
-
async function* decodeStream(body) {
|
|
407
|
+
async function* decodeStream(body, maxTokens) {
|
|
408
408
|
const blocks = new Map();
|
|
409
409
|
const toolCalls = [];
|
|
410
410
|
let stopReason;
|
|
411
411
|
let usage = undefined;
|
|
412
412
|
// Stable text emission order: walk content blocks by index at end-of-stream.
|
|
413
413
|
const textOrder = [];
|
|
414
|
+
// v4.1.4 Part 1.6: track the last-emitted output-token count so we
|
|
415
|
+
// only yield a `progress` event when the counter actually advances.
|
|
416
|
+
// Anthropic emits `message_delta.usage.output_tokens` as a running
|
|
417
|
+
// total — multiple deltas may carry the same value if no new tokens
|
|
418
|
+
// were produced between them. Deduping keeps the event stream
|
|
419
|
+
// proportional to real progress.
|
|
420
|
+
let lastProgressEmitted = -1;
|
|
414
421
|
for await (const payload of (0, chatCompletionsAdapter_1.parseSseStream)(body)) {
|
|
415
422
|
if (!payload || payload === '[DONE]')
|
|
416
423
|
continue;
|
|
@@ -490,6 +497,22 @@ async function* decodeStream(body) {
|
|
|
490
497
|
stopReason = evt.delta.stop_reason;
|
|
491
498
|
if (evt.usage) {
|
|
492
499
|
usage = { ...(usage ?? {}), ...evt.usage };
|
|
500
|
+
// v4.1.4 Part 1.6 — emit a `progress` event when the running
|
|
501
|
+
// output-token counter advances. The display layer uses these
|
|
502
|
+
// for the ▰▱ progress bar. Deduped via `lastProgressEmitted`
|
|
503
|
+
// so a stream of message_delta events with no real progress
|
|
504
|
+
// doesn't flood the consumer.
|
|
505
|
+
const outputTokens = typeof evt.usage.output_tokens === 'number'
|
|
506
|
+
? evt.usage.output_tokens
|
|
507
|
+
: -1;
|
|
508
|
+
if (outputTokens > lastProgressEmitted) {
|
|
509
|
+
lastProgressEmitted = outputTokens;
|
|
510
|
+
yield {
|
|
511
|
+
type: 'progress',
|
|
512
|
+
outputTokens,
|
|
513
|
+
maxTokens,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
493
516
|
}
|
|
494
517
|
break;
|
|
495
518
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiden-runtime",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -277,6 +277,7 @@
|
|
|
277
277
|
"twilio": "^5.13.1",
|
|
278
278
|
"uuid": "^9.0.0",
|
|
279
279
|
"whatsapp-web.js": "^1.26.0",
|
|
280
|
+
"wrap-ansi": "^9.0.2",
|
|
280
281
|
"ws": "^8.20.0"
|
|
281
282
|
},
|
|
282
283
|
"optionalDependencies": {
|