zelari-code 1.8.0 → 1.8.3
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/app.js +44 -24
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/components/LiveRegion.js +9 -1
- package/dist/cli/components/LiveRegion.js.map +1 -1
- package/dist/cli/components/Sidebar.js +38 -7
- package/dist/cli/components/Sidebar.js.map +1 -1
- package/dist/cli/components/brandArt.js +62 -0
- package/dist/cli/components/brandArt.js.map +1 -0
- package/dist/cli/hooks/chatStats.js +7 -0
- package/dist/cli/hooks/chatStats.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +58 -28
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useTerminalSize.js +17 -10
- package/dist/cli/hooks/useTerminalSize.js.map +1 -1
- package/dist/cli/main.bundled.js +496 -130
- package/dist/cli/main.bundled.js.map +4 -4
- package/package.json +2 -2
package/dist/cli/app.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
// the v3-N monolithic app. Behavior is correct; a future pass will tighten the
|
|
3
3
|
// hook signatures and remove this annotation. The split is documented in
|
|
4
4
|
// `docs/plans/2026-07-01-app-split.md`.
|
|
5
|
-
import React, { useState, useMemo, useCallback, useEffect } from 'react';
|
|
5
|
+
import React, { useState, useMemo, useCallback, useEffect, useRef } from 'react';
|
|
6
6
|
import { Box, Static, useInput, useStdin } from 'ink';
|
|
7
7
|
import { InputBar } from './components/InputBar.js';
|
|
8
8
|
import { LiveRegion } from './components/LiveRegion.js';
|
|
9
9
|
import { StatusBar } from './components/StatusBar.js';
|
|
10
10
|
import { SelectList } from './components/SelectList.js';
|
|
11
|
-
import { Sidebar,
|
|
11
|
+
import { Sidebar, sidebarVisibility } from './components/Sidebar.js';
|
|
12
|
+
import { formatBannerWithLogoRight } from './components/brandArt.js';
|
|
12
13
|
import { discoverModelsInBackground, isModelsCacheStale } from './modelDiscovery.js';
|
|
13
14
|
import { renderMessage } from './components/ChatStream.js';
|
|
14
15
|
import { listCodingSkills } from '@zelari/core/skills';
|
|
@@ -63,7 +64,12 @@ export function App() {
|
|
|
63
64
|
const [input, setInput] = useState('');
|
|
64
65
|
const [busy, setBusy] = useState(false);
|
|
65
66
|
const [providerConfig, setProviderConfig] = useState(() => getProviderConfig());
|
|
66
|
-
const [sessionStats, setSessionStats] = useState({
|
|
67
|
+
const [sessionStats, setSessionStats] = useState({
|
|
68
|
+
totalTokens: 0,
|
|
69
|
+
totalCostUsd: 0,
|
|
70
|
+
cachedTokens: 0,
|
|
71
|
+
contextTokens: 0,
|
|
72
|
+
});
|
|
67
73
|
// v0.7.0: bump on /clear to remount <Static> (resets its internal "already
|
|
68
74
|
// printed" index so the ANSI-cleared scrollback stays in sync). Also bumped
|
|
69
75
|
// implicitly by a sessionId change (/new).
|
|
@@ -193,24 +199,40 @@ export function App() {
|
|
|
193
199
|
}
|
|
194
200
|
setPicker(null);
|
|
195
201
|
}, [picker]);
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
202
|
+
// Freeze banner layout to the FIRST measured size. Re-wrapping the ASCII
|
|
203
|
+
// logo on every resize rewrites the Static item identity chain and, with
|
|
204
|
+
// Ink's dynamic region reflow, corrupts native scrollback on Windows.
|
|
205
|
+
const bannerColsRef = useRef(null);
|
|
206
|
+
if (bannerColsRef.current === null) {
|
|
207
|
+
bannerColsRef.current = size.columns > 0 ? size.columns : 80;
|
|
208
|
+
}
|
|
209
|
+
// The one-shot banner: printed once as the first Static item. v1.8.x:
|
|
210
|
+
// ASCII logo restored, right-aligned at the TOP of the scrollback (only
|
|
211
|
+
// place a multi-line mark can sit "top-right" under static-scrollback).
|
|
199
212
|
const banner = useMemo(() => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
213
|
+
const cols = bannerColsRef.current ?? 80;
|
|
214
|
+
const content = formatBannerWithLogoRight({
|
|
215
|
+
leftLines: [
|
|
216
|
+
`zelari-code · ${activeProviderSpec.id}/${activeModel}`,
|
|
217
|
+
`cwd: ${cwd}`,
|
|
218
|
+
`/help · /plan · /build · /view-plan · shift+tab mode`,
|
|
219
|
+
],
|
|
220
|
+
version: VERSION,
|
|
221
|
+
columns: cols,
|
|
222
|
+
compact: cols < 72,
|
|
223
|
+
});
|
|
205
224
|
return {
|
|
206
225
|
id: 'banner-once',
|
|
207
226
|
role: 'system',
|
|
208
227
|
ts: 0,
|
|
209
|
-
content
|
|
210
|
-
`cwd: ${cwd}\n` +
|
|
211
|
-
`/help · /plan · /build · /view-plan · shift+tab mode (agent/council/zelari)`,
|
|
228
|
+
content,
|
|
212
229
|
};
|
|
213
230
|
}, [activeProviderSpec.id, activeModel, cwd]);
|
|
231
|
+
// Sidebar visibility with hysteresis — avoid flapping at the 96-col edge.
|
|
232
|
+
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
setSidebarOpen((prev) => sidebarVisibility(size.columns, size.rows, prev));
|
|
235
|
+
}, [size.columns, size.rows]);
|
|
214
236
|
// The Static feed: banner first, then finalized messages. `key` lets /clear
|
|
215
237
|
// remount Static so its internal "already printed" index resets. clearEpoch
|
|
216
238
|
// is composed in so /clear forces a remount even within the same session.
|
|
@@ -224,19 +246,17 @@ export function App() {
|
|
|
224
246
|
const staticItems = session.sessionId
|
|
225
247
|
? [banner, ...session.messages]
|
|
226
248
|
: [];
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
// on narrow/short terminals to keep the dynamic region under one screen.
|
|
231
|
-
const showSidebar = shouldShowSidebar(size.columns, size.rows);
|
|
249
|
+
// Cap dynamic-region height so Ink never clear-screens on resize.
|
|
250
|
+
// Live + input + status ≈ 14 lines max; leave the rest to native scrollback.
|
|
251
|
+
const dynamicMaxRows = Math.max(8, Math.min(18, size.rows - 2));
|
|
232
252
|
return (React.createElement(React.Fragment, null,
|
|
233
253
|
React.createElement(Static, { key: staticKey, items: staticItems }, (item) => renderMessage(item)),
|
|
234
|
-
React.createElement(Box, { flexDirection: "row" },
|
|
235
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1 },
|
|
254
|
+
React.createElement(Box, { flexDirection: "row", width: size.columns > 0 ? size.columns : undefined, height: dynamicMaxRows, overflow: "hidden" },
|
|
255
|
+
React.createElement(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, overflow: "hidden" },
|
|
236
256
|
React.createElement(LiveRegion, { live: session.live, busy: busy, elapsedMs: timer.elapsedMs }),
|
|
237
|
-
picker ? (React.createElement(SelectList, { title: picker.title, items: picker.items, onSelect: onPickerSelect, onCancel: onPickerCancel, maxVisible: Math.max(
|
|
238
|
-
React.createElement(StatusBar, { model: activeModel, provider: activeProviderSpec.id, sessionId: session.sessionId ? session.sessionId.slice(0, 8) : '...', sessionActive: session.sessionActive, queueCount: chatTurn.queueCount, busy: busy, mode: mode, phase: phase, cwd: cwd, elapsedMs: timer.elapsedMs, lastMs: timer.lastMs, costUsd: sessionStats.totalCostUsd, cachedTokens: sessionStats.cachedTokens, contextUsed: sessionStats.
|
|
239
|
-
|
|
257
|
+
picker ? (React.createElement(SelectList, { title: picker.title, items: picker.items, onSelect: onPickerSelect, onCancel: onPickerCancel, maxVisible: Math.max(3, Math.min(8, size.rows - 12)) })) : (React.createElement(InputBar, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: busy })),
|
|
258
|
+
React.createElement(StatusBar, { model: activeModel, provider: activeProviderSpec.id, sessionId: session.sessionId ? session.sessionId.slice(0, 8) : '...', sessionActive: session.sessionActive, queueCount: chatTurn.queueCount, busy: busy, mode: mode, phase: phase, cwd: cwd, elapsedMs: timer.elapsedMs, lastMs: timer.lastMs, costUsd: sessionStats.totalCostUsd, cachedTokens: sessionStats.cachedTokens, contextUsed: sessionStats.contextTokens || 0, contextLimit: Number(process.env.ZELARI_CONTEXT_LIMIT) || 200_000, brandVersion: VERSION })),
|
|
259
|
+
sidebarOpen && (React.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })))));
|
|
240
260
|
}
|
|
241
261
|
// Re-export so legacy imports keep working (Task v0.4.2 audit split).
|
|
242
262
|
// New code should import directly from src/cli/hooks/* instead.
|
package/dist/cli/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,+EAA+E;AAC/E,yEAAyE;AACzE,wCAAwC;AACxC,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,8 @@ const LIVE_STREAM_TAIL_LINES = 10;
|
|
|
22
22
|
* repaint → no flicker, by construction. Finalized messages live in the
|
|
23
23
|
* terminal's native scrollback via `<Static>` (printed exactly once).
|
|
24
24
|
*/
|
|
25
|
+
/** Cap concurrent tool lines so resize + many tools never blow the viewport. */
|
|
26
|
+
const MAX_LIVE_TOOLS = 4;
|
|
25
27
|
export function LiveRegion({ live, busy, elapsedMs = null }) {
|
|
26
28
|
const { streaming, runningTools } = live;
|
|
27
29
|
// v0.7.10: `busy` keeps the region alive so the animated WorkingIndicator
|
|
@@ -29,9 +31,15 @@ export function LiveRegion({ live, busy, elapsedMs = null }) {
|
|
|
29
31
|
// old check dropped `busy`, which made the fallback line dead code.)
|
|
30
32
|
if (!streaming && runningTools.length === 0 && !busy)
|
|
31
33
|
return null;
|
|
34
|
+
const visibleTools = runningTools.slice(0, MAX_LIVE_TOOLS);
|
|
35
|
+
const hiddenTools = runningTools.length - visibleTools.length;
|
|
32
36
|
return (React.createElement(Box, { flexDirection: "column", paddingX: 1 },
|
|
33
37
|
streaming && streaming.role === 'assistant' && (React.createElement(StreamingTail, { id: streaming.id, content: streaming.content, ts: streaming.ts, memberName: streaming.memberName, memberId: streaming.memberId })),
|
|
34
|
-
|
|
38
|
+
visibleTools.map((t) => (React.createElement(Box, { key: t.id, flexDirection: "column" }, renderMessage(t, true)))),
|
|
39
|
+
hiddenTools > 0 ? (React.createElement(Text, { dimColor: true },
|
|
40
|
+
" \u2026 +",
|
|
41
|
+
hiddenTools,
|
|
42
|
+
" more tools")) : null,
|
|
35
43
|
busy && runningTools.length === 0 && !streaming && (React.createElement(WorkingIndicator, { elapsedMs: elapsedMs }))));
|
|
36
44
|
}
|
|
37
45
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveRegion.js","sourceRoot":"","sources":["../../../src/cli/components/LiveRegion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,EAAE,CAAC;AASlC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,EAAmB;IAC1E,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEzC,0EAA0E;IAC1E,wEAAwE;IACxE,qEAAqE;IACrE,IAAI,CAAC,SAAS,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAElE,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC;QACpC,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,IAAI,CAC9C,oBAAC,aAAa,IACZ,EAAE,EAAE,SAAS,CAAC,EAAE,EAChB,OAAO,EAAE,SAAS,CAAC,OAAO,EAC1B,EAAE,EAAE,SAAS,CAAC,EAAE,EAChB,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,QAAQ,EAAE,SAAS,CAAC,QAAQ,GAC5B,CACH;QACA,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACvB,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,aAAa,EAAC,QAAQ,IACnC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CACnB,CACP,CAAC;QACD,IAAI,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAClD,oBAAC,gBAAgB,IAAC,SAAS,EAAE,SAAS,GAAI,CAC3C,CACG,CACP,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,CAMtB;IACC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,sBAAsB,CAAC;IACxD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtE,OAAO,CACL,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC;QACpD,oBAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI;;YAErB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,SAAS;;gBAAK,CAAC,CAAC,UAAU,CAAQ,CAAC,CAAC,CAAC,IAAI,CAChE;QACP,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ;YACvC,SAAS,IAAI,oBAAC,IAAI,IAAC,QAAQ,mBAAS;YACrC,oBAAC,IAAI,QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAQ,CAC1B,CACF,CACP,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"LiveRegion.js","sourceRoot":"","sources":["../../../src/cli/components/LiveRegion.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,18 +4,47 @@ import { Box, Text } from 'ink';
|
|
|
4
4
|
export const SIDEBAR_WIDTH = 28;
|
|
5
5
|
/** Sidebar only renders on terminals at least this wide. */
|
|
6
6
|
export const SIDEBAR_MIN_COLUMNS = 96;
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Hysteresis floor: once visible, stay visible until width drops below this.
|
|
9
|
+
* Prevents show/hide thrash while the user drags the window across 96 cols
|
|
10
|
+
* (each toggle reflows the dynamic region and can trash Static scrollback).
|
|
11
|
+
*/
|
|
12
|
+
export const SIDEBAR_HIDE_COLUMNS = 88;
|
|
13
|
+
/** Min rows to show; hide below this. */
|
|
14
|
+
export const SIDEBAR_MIN_ROWS = 16;
|
|
15
|
+
export const SIDEBAR_HIDE_ROWS = 14;
|
|
9
16
|
/** Max file rows before collapsing to "+N more". */
|
|
10
|
-
const MAX_FILES_SHORT =
|
|
11
|
-
const MAX_FILES_TALL =
|
|
17
|
+
const MAX_FILES_SHORT = 4;
|
|
18
|
+
const MAX_FILES_TALL = 8;
|
|
19
|
+
/** Absolute cap: sidebar chrome + files must stay short vs terminal rows. */
|
|
20
|
+
const SIDEBAR_CHROME_LINES = 4;
|
|
12
21
|
/**
|
|
13
22
|
* Pure helper: should the sidebar render at all? It lives in the dynamic
|
|
14
23
|
* region (Ink repaints it), so it must never make that region taller than
|
|
15
24
|
* the terminal — narrow or tiny panes skip it entirely.
|
|
25
|
+
*
|
|
26
|
+
* Prefer {@link sidebarVisibility} when you have the previous visibility
|
|
27
|
+
* (hysteresis). This boolean form is the strict "enter" threshold.
|
|
16
28
|
*/
|
|
17
29
|
export function shouldShowSidebar(columns, rows) {
|
|
18
|
-
return columns >= SIDEBAR_MIN_COLUMNS && rows >=
|
|
30
|
+
return columns >= SIDEBAR_MIN_COLUMNS && rows >= SIDEBAR_MIN_ROWS;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Hysteresis visibility: once shown, requires a clearer "leave" signal
|
|
34
|
+
* (narrower / shorter) before hiding — stops resize-edge flicker.
|
|
35
|
+
*/
|
|
36
|
+
export function sidebarVisibility(columns, rows, currentlyVisible) {
|
|
37
|
+
if (currentlyVisible) {
|
|
38
|
+
return columns >= SIDEBAR_HIDE_COLUMNS && rows >= SIDEBAR_HIDE_ROWS;
|
|
39
|
+
}
|
|
40
|
+
return shouldShowSidebar(columns, rows);
|
|
41
|
+
}
|
|
42
|
+
/** How many file rows fit without blowing the dynamic-region budget. */
|
|
43
|
+
export function maxSidebarFiles(rows) {
|
|
44
|
+
// Reserve room for LiveRegion (~12) + input + status + chrome.
|
|
45
|
+
const budget = Math.max(2, rows - 14 - SIDEBAR_CHROME_LINES);
|
|
46
|
+
const cap = rows >= 28 ? MAX_FILES_TALL : MAX_FILES_SHORT;
|
|
47
|
+
return Math.min(cap, budget);
|
|
19
48
|
}
|
|
20
49
|
/** Truncate a repo-relative path to `max` chars keeping the tail (filename). */
|
|
21
50
|
export function truncatePath(p, max) {
|
|
@@ -32,13 +61,15 @@ export function truncatePath(p, max) {
|
|
|
32
61
|
*/
|
|
33
62
|
export function Sidebar({ version, changes, rows }) {
|
|
34
63
|
void version; // brand lives in StatusBar; keep prop for API stability
|
|
35
|
-
const maxFiles = rows
|
|
64
|
+
const maxFiles = maxSidebarFiles(rows);
|
|
36
65
|
const visible = changes.files.slice(0, maxFiles);
|
|
37
66
|
const hidden = changes.files.length - visible.length;
|
|
38
67
|
// Width available for the path inside the box: total − border(2) − padding(2)
|
|
39
68
|
// − the " +NNN -NNN" tail (~11 chars).
|
|
40
69
|
const innerWidth = SIDEBAR_WIDTH - 4;
|
|
41
|
-
return (React.createElement(Box, { flexDirection: "column", width: SIDEBAR_WIDTH, borderStyle: "single", borderColor: "gray", paddingX: 1, flexShrink: 0
|
|
70
|
+
return (React.createElement(Box, { flexDirection: "column", width: SIDEBAR_WIDTH, borderStyle: "single", borderColor: "gray", paddingX: 1, flexShrink: 0,
|
|
71
|
+
// Hard cap so a huge git status never makes Ink clear the whole screen.
|
|
72
|
+
height: Math.min(rows - 8, SIDEBAR_CHROME_LINES + maxFiles + 2), overflow: "hidden" },
|
|
42
73
|
React.createElement(Box, { justifyContent: "center" },
|
|
43
74
|
React.createElement(Text, { dimColor: true }, changes.branch ? truncatePath(changes.branch, 18) : 'git')),
|
|
44
75
|
React.createElement(Text, { dimColor: true }, '─'.repeat(innerWidth)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../../src/cli/components/Sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAGhC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC,
|
|
1
|
+
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../../src/cli/components/Sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAGhC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,yCAAyC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,oDAAoD;AACpD,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,6EAA6E;AAC7E,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,IAAY;IAC7D,OAAO,OAAO,IAAI,mBAAmB,IAAI,IAAI,IAAI,gBAAgB,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAY,EACZ,gBAAyB;IAEzB,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,OAAO,IAAI,oBAAoB,IAAI,IAAI,IAAI,iBAAiB,CAAC;IACtE,CAAC;IACD,OAAO,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,+DAA+D;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,EAAE,GAAG,oBAAoB,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC;IAC1D,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,GAAW;IACjD,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AACnC,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAgB;IAC9D,KAAK,OAAO,CAAC,CAAC,wDAAwD;IACtE,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACrD,8EAA8E;IAC9E,uCAAuC;IACvC,MAAM,UAAU,GAAG,aAAa,GAAG,CAAC,CAAC;IAErC,OAAO,CACL,oBAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,KAAK,EAAE,aAAa,EACpB,WAAW,EAAC,QAAQ,EACpB,WAAW,EAAC,MAAM,EAClB,QAAQ,EAAE,CAAC,EACX,UAAU,EAAE,CAAC;QACb,wEAAwE;QACxE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,oBAAoB,GAAG,QAAQ,GAAG,CAAC,CAAC,EAC/D,QAAQ,EAAC,QAAQ;QAEjB,oBAAC,GAAG,IAAC,cAAc,EAAC,QAAQ;YAC1B,oBAAC,IAAI,IAAC,QAAQ,UACX,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CACrD,CACH;QACN,oBAAC,IAAI,IAAC,QAAQ,UAAE,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAQ;QAC7C,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CACjB,oBAAC,IAAI,IAAC,QAAQ,QAAC,MAAM,2BAAsB,CAC5C,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC/B,oBAAC,IAAI,IAAC,QAAQ,QAAC,MAAM,uBAAkB,CACxC,CAAC,CAAC,CAAC,CACF;YACE,oBAAC,IAAI,IAAC,QAAQ;;gBAAW,OAAO,CAAC,KAAK,CAAC,MAAM;oBAAS;YACrD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,oBAAC,OAAO,IAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,UAAU,GAAG,EAAE,GAAI,CAC9D,CAAC;YACD,MAAM,GAAG,CAAC,IAAI,oBAAC,IAAI,IAAC,QAAQ;;gBAAK,MAAM;8BAAc,CACrD,CACJ,CACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAA8C;IAC9E,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7D,OAAO,CACL,oBAAC,GAAG;QACF,oBAAC,IAAI,IAAC,IAAI,EAAC,UAAU;YACnB,oBAAC,IAAI,IAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAG,IAAI,CAAQ;YAC9D,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAChB,oBAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,WAAY,CACjC,CAAC,CAAC,CAAC,CACF;gBACE,oBAAC,IAAI,IAAC,KAAK,EAAC,OAAO;;oBAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAQ;gBAChD,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK;;oBAAI,IAAI,CAAC,OAAO,IAAI,GAAG,CAAQ,CAC/C,CACJ,CACI,CACH,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* brandArt — Zelari CODE ASCII emblem for the TUI banner (top-right).
|
|
3
|
+
*
|
|
4
|
+
* Kept pure (no React) so the Static banner can compose a multi-line string
|
|
5
|
+
* with the logo right-aligned without Ink layout constraints.
|
|
6
|
+
*
|
|
7
|
+
* Source: compact splash art (EMBLEM_MICRO lineage) — the classic %-glyph logo.
|
|
8
|
+
*/
|
|
9
|
+
/** Classic ASCII emblem (trimmed for right-alignment). */
|
|
10
|
+
export const BRAND_LOGO_ASCII = [
|
|
11
|
+
' -#%=',
|
|
12
|
+
' +%%%%#.',
|
|
13
|
+
' :#%%%%%%%-',
|
|
14
|
+
':%%@@@@@@@@=',
|
|
15
|
+
'-%@@@@@@@@@@@+',
|
|
16
|
+
':%@@@@@@%@@@@@@=',
|
|
17
|
+
'-%%@@@@@.+%@@%@+',
|
|
18
|
+
' -@@@@@@:%++%@=',
|
|
19
|
+
'=*%@@@@@@:@@%=*@#+.',
|
|
20
|
+
'%%%%%@@@@:+++-*%@@*',
|
|
21
|
+
'.%%%%%@@@@@+%+=:%@@@@:',
|
|
22
|
+
'*@@@@@@@@@@@@@%@@@@@@*',
|
|
23
|
+
].join('\n');
|
|
24
|
+
/** Compact 4-line mark for narrow terminals. */
|
|
25
|
+
export const BRAND_LOGO_COMPACT = [
|
|
26
|
+
' -#%=',
|
|
27
|
+
' +%%%%#.',
|
|
28
|
+
':%%@@@@=',
|
|
29
|
+
'*@@@@@@*',
|
|
30
|
+
].join('\n');
|
|
31
|
+
/**
|
|
32
|
+
* Compose a multi-line banner: left column (meta) top-aligned, logo block
|
|
33
|
+
* right-aligned within `columns`.
|
|
34
|
+
*/
|
|
35
|
+
export function formatBannerWithLogoRight(opts) {
|
|
36
|
+
const logoSrc = opts.compact ? BRAND_LOGO_COMPACT : BRAND_LOGO_ASCII;
|
|
37
|
+
const logoLines = logoSrc.split('\n');
|
|
38
|
+
const logoWidth = Math.max(...logoLines.map((l) => l.length));
|
|
39
|
+
const cols = Math.max(logoWidth + 20, Math.min(opts.columns, 120));
|
|
40
|
+
const left = [...opts.leftLines];
|
|
41
|
+
// Wordmark under the logo, right-aligned with the art.
|
|
42
|
+
const wordmark = `ZELARI CODE v${opts.version}`;
|
|
43
|
+
const rightExtra = [wordmark];
|
|
44
|
+
const rightBlock = [...logoLines, ...rightExtra];
|
|
45
|
+
const rows = Math.max(left.length, rightBlock.length);
|
|
46
|
+
const out = [];
|
|
47
|
+
for (let i = 0; i < rows; i++) {
|
|
48
|
+
const L = left[i] ?? '';
|
|
49
|
+
const R = rightBlock[i] ?? '';
|
|
50
|
+
if (!R) {
|
|
51
|
+
out.push(L);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Right-align R within cols; leave at least 2 spaces after L when both present.
|
|
55
|
+
const maxLeft = Math.max(0, cols - R.length - 2);
|
|
56
|
+
const leftClipped = L.length > maxLeft ? L.slice(0, Math.max(0, maxLeft - 1)) + '…' : L;
|
|
57
|
+
const pad = Math.max(2, cols - leftClipped.length - R.length);
|
|
58
|
+
out.push(leftClipped + ' '.repeat(pad) + R);
|
|
59
|
+
}
|
|
60
|
+
return out.join('\n');
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=brandArt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brandArt.js","sourceRoot":"","sources":["../../../src/cli/components/brandArt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,UAAU;IACV,YAAY;IACZ,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,qBAAqB;IACrB,qBAAqB;IACrB,wBAAwB;IACxB,wBAAwB;CACzB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,gDAAgD;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ;IACR,UAAU;IACV,UAAU;IACV,UAAU;CACX,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAMzC;IACC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACrE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAEnE,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,uDAAuD;IACvD,MAAM,QAAQ,GAAG,iBAAiB,IAAI,CAAC,OAAO,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,CAAC,GAAG,SAAS,EAAE,GAAG,UAAU,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACZ,SAAS;QACX,CAAC;QACD,gFAAgF;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9D,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -23,10 +23,17 @@ export function computeSessionStatsDelta(realUsage, userText, assistantContent,
|
|
|
23
23
|
// char/4 fallback can't distinguish them, so assume 0 there.
|
|
24
24
|
const cachedPromptTokens = realUsage?.cachedPromptTokens ?? 0;
|
|
25
25
|
const turnCost = calculateCost(model, promptTokens, completionTokens, cachedPromptTokens);
|
|
26
|
+
// Context meter = this turn's prompt+completion (provider context window
|
|
27
|
+
// occupancy proxy), NOT the session cumulative total (which always grows
|
|
28
|
+
// and produced absurd "474k/200k" displays).
|
|
29
|
+
const contextTokens = realUsage
|
|
30
|
+
? realUsage.totalTokens || promptTokens + completionTokens
|
|
31
|
+
: promptTokens + completionTokens;
|
|
26
32
|
return {
|
|
27
33
|
totalTokens: prev.totalTokens + promptTokens + completionTokens,
|
|
28
34
|
totalCostUsd: prev.totalCostUsd + turnCost,
|
|
29
35
|
cachedTokens: (prev.cachedTokens ?? 0) + cachedPromptTokens,
|
|
36
|
+
contextTokens,
|
|
30
37
|
};
|
|
31
38
|
}
|
|
32
39
|
//# sourceMappingURL=chatStats.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatStats.js","sourceRoot":"","sources":["../../../src/cli/hooks/chatStats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAKQ,EACR,QAAgB,EAChB,gBAAwB,EACxB,KAAa,EACb,
|
|
1
|
+
{"version":3,"file":"chatStats.js","sourceRoot":"","sources":["../../../src/cli/hooks/chatStats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAKQ,EACR,QAAgB,EAChB,gBAAwB,EACxB,KAAa,EACb,IAMC;IAOD,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzF,MAAM,gBAAgB,GAAG,SAAS;QAChC,CAAC,CAAC,SAAS,CAAC,gBAAgB;QAC5B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,oEAAoE;IACpE,6DAA6D;IAC7D,MAAM,kBAAkB,GAAG,SAAS,EAAE,kBAAkB,IAAI,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IAC1F,yEAAyE;IACzE,yEAAyE;IACzE,6CAA6C;IAC7C,MAAM,aAAa,GAAG,SAAS;QAC7B,CAAC,CAAC,SAAS,CAAC,WAAW,IAAI,YAAY,GAAG,gBAAgB;QAC1D,CAAC,CAAC,YAAY,GAAG,gBAAgB,CAAC;IACpC,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW,GAAG,YAAY,GAAG,gBAAgB;QAC/D,YAAY,EAAE,IAAI,CAAC,YAAY,GAAG,QAAQ;QAC1C,YAAY,EAAE,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,kBAAkB;QAC3D,aAAa;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -311,9 +311,13 @@ export function useChatTurn(params) {
|
|
|
311
311
|
default: 25,
|
|
312
312
|
min: 1,
|
|
313
313
|
});
|
|
314
|
-
// v1.5.2 / v1.8.0: tool-loop
|
|
315
|
-
//
|
|
314
|
+
// v1.5.2 / v1.8.0 / v1.8.3: soft tool-loop + optional hard ceiling.
|
|
315
|
+
// Soft can auto-extend until hard so multi-step work finishes.
|
|
316
316
|
const maxToolLoopIterations = budget.maxToolLoopIterations;
|
|
317
|
+
const maxToolLoopHardCap = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_HARD, {
|
|
318
|
+
default: 0, // 0 → harness default (soft×3, min soft+60)
|
|
319
|
+
min: 0,
|
|
320
|
+
});
|
|
317
321
|
const harness = new AgentHarness({
|
|
318
322
|
model: envConfig.model,
|
|
319
323
|
provider: "openai-compatible",
|
|
@@ -335,6 +339,7 @@ export function useChatTurn(params) {
|
|
|
335
339
|
cwd,
|
|
336
340
|
maxToolCallsPerTurn,
|
|
337
341
|
maxToolLoopIterations,
|
|
342
|
+
...(maxToolLoopHardCap > 0 ? { maxToolLoopHardCap } : {}),
|
|
338
343
|
});
|
|
339
344
|
harnessRef.current = harness;
|
|
340
345
|
setQueueCount(harness.queueLength);
|
|
@@ -405,17 +410,21 @@ export function useChatTurn(params) {
|
|
|
405
410
|
if (event.type === "message_delta") {
|
|
406
411
|
assistantContent += event.delta;
|
|
407
412
|
streamContent += event.delta;
|
|
413
|
+
// v1.8.1: hide <think>… from the live bubble while streaming so
|
|
414
|
+
// private reasoning never flashes in the TUI (full scrub also
|
|
415
|
+
// runs on turn end).
|
|
416
|
+
const displayContent = cleanAgentContent(streamContent);
|
|
408
417
|
// Route through the throttled setter so per-token deltas (50-200/sec)
|
|
409
418
|
// coalesce into ≤60 renders/sec instead of flickering the TUI.
|
|
410
419
|
if (useLiveModel) {
|
|
411
|
-
setStreaming(commitStreaming,
|
|
420
|
+
setStreaming(commitStreaming, displayContent, Date.now(), {
|
|
412
421
|
...(event.memberId ? { memberId: event.memberId } : {}),
|
|
413
422
|
...(event.memberName ? { memberName: event.memberName } : {}),
|
|
414
423
|
});
|
|
415
424
|
}
|
|
416
425
|
else {
|
|
417
426
|
// Legacy single-array fallback (existing tests).
|
|
418
|
-
appendOrExtendStreamingAssistant(commitStreaming,
|
|
427
|
+
appendOrExtendStreamingAssistant(commitStreaming, displayContent, Date.now(), {
|
|
419
428
|
...(event.memberId ? { memberId: event.memberId } : {}),
|
|
420
429
|
...(event.memberName
|
|
421
430
|
? { memberName: event.memberName }
|
|
@@ -425,7 +434,13 @@ export function useChatTurn(params) {
|
|
|
425
434
|
}
|
|
426
435
|
else if (event.type === "error") {
|
|
427
436
|
flushStreaming();
|
|
428
|
-
|
|
437
|
+
// Budget extension is informational, not a hard error.
|
|
438
|
+
if (event.code === "tool_budget_extended") {
|
|
439
|
+
appendSystem(setMessages, `[budget] ${event.message}`, Date.now());
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
appendSystem(setMessages, `[error] ${event.message}`, Date.now());
|
|
443
|
+
}
|
|
429
444
|
}
|
|
430
445
|
else if (event.type === "tool_execution_start") {
|
|
431
446
|
toolNameById.set(event.toolCallId, event.toolName);
|
|
@@ -478,39 +493,54 @@ export function useChatTurn(params) {
|
|
|
478
493
|
const all = h.getMessages();
|
|
479
494
|
const seedLen = 1 /*system*/ + historySeedLen + 1 /*user*/;
|
|
480
495
|
if (all.length > seedLen) {
|
|
481
|
-
|
|
496
|
+
// Strip think blocks from history so the next turn does not
|
|
497
|
+
// re-feed private reasoning — but KEEP ---QUESTION--- so the
|
|
498
|
+
// model can bind short answers ("full") to its own choices.
|
|
499
|
+
appendMessages(all.slice(seedLen).map((m) => m.role === "assistant" && m.content
|
|
500
|
+
? {
|
|
501
|
+
...m,
|
|
502
|
+
content: cleanAgentContent(m.content, {
|
|
503
|
+
stripQuestion: false,
|
|
504
|
+
}),
|
|
505
|
+
}
|
|
506
|
+
: m));
|
|
482
507
|
}
|
|
483
508
|
}
|
|
484
509
|
}
|
|
485
510
|
catch {
|
|
486
511
|
// Non-fatal: a snapshot failure must never break the turn.
|
|
487
512
|
}
|
|
488
|
-
// v1.
|
|
489
|
-
//
|
|
490
|
-
//
|
|
513
|
+
// v1.8.1: ALWAYS strip <think>/QUESTION private channels from the
|
|
514
|
+
// display transcript after a successful turn — not only when a
|
|
515
|
+
// clarifying picker opens. Otherwise GLM/MiniMax reasoning leaks
|
|
516
|
+
// into the TUI as visible assistant prose.
|
|
517
|
+
// Only call setMessages when at least one bubble needs scrubbing —
|
|
518
|
+
// returning the same `prev` array ref from a functional updater is
|
|
519
|
+
// fine for React, but breaks test harnesses that wipe-then-push.
|
|
491
520
|
if (turnSucceeded && assistantContent) {
|
|
492
521
|
try {
|
|
522
|
+
const needsScrub = assistantContent.includes("<think") ||
|
|
523
|
+
assistantContent.includes("<thinking") ||
|
|
524
|
+
assistantContent.includes("---QUESTION---");
|
|
525
|
+
if (needsScrub) {
|
|
526
|
+
setMessages((prev) => prev.map((m) => {
|
|
527
|
+
if (m.role !== "assistant")
|
|
528
|
+
return m;
|
|
529
|
+
if (!m.content.includes("<think") &&
|
|
530
|
+
!m.content.includes("<thinking") &&
|
|
531
|
+
!m.content.includes("---QUESTION---")) {
|
|
532
|
+
return m;
|
|
533
|
+
}
|
|
534
|
+
const cleaned = cleanAgentContent(m.content);
|
|
535
|
+
return cleaned === m.content ? m : { ...m, content: cleaned };
|
|
536
|
+
}));
|
|
537
|
+
}
|
|
493
538
|
const clar = parseClarificationRequest(assistantContent);
|
|
494
539
|
if (clar && clar.choices && clar.choices.length >= 2) {
|
|
495
540
|
setLastClarification({
|
|
496
541
|
question: clar.question,
|
|
497
542
|
choices: clar.choices,
|
|
498
543
|
});
|
|
499
|
-
// Strip the raw ---QUESTION--- block from the finalized
|
|
500
|
-
// assistant message so the display shows prose, not JSON.
|
|
501
|
-
const cleaned = cleanAgentContent(assistantContent);
|
|
502
|
-
if (cleaned !== assistantContent) {
|
|
503
|
-
setMessages((prev) => {
|
|
504
|
-
const next = [...prev];
|
|
505
|
-
for (let i = next.length - 1; i >= 0; i--) {
|
|
506
|
-
if (next[i].role === "assistant") {
|
|
507
|
-
next[i] = { ...next[i], content: cleaned };
|
|
508
|
-
break;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return next;
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
544
|
if (setPicker) {
|
|
515
545
|
setPicker({
|
|
516
546
|
kind: "clarification",
|
|
@@ -523,7 +553,6 @@ export function useChatTurn(params) {
|
|
|
523
553
|
}
|
|
524
554
|
}
|
|
525
555
|
else {
|
|
526
|
-
// Free-form answer path next turn — clear stale question.
|
|
527
556
|
setLastClarification(null);
|
|
528
557
|
}
|
|
529
558
|
}
|
|
@@ -813,7 +842,7 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
813
842
|
streamMemberId = memberId;
|
|
814
843
|
}
|
|
815
844
|
streamContent += event.delta;
|
|
816
|
-
setStreaming(commitStreaming, streamContent, event.ts, {
|
|
845
|
+
setStreaming(commitStreaming, cleanAgentContent(streamContent), event.ts, {
|
|
817
846
|
...(event.memberId ? { memberId: event.memberId } : {}),
|
|
818
847
|
...(event.memberName ? { memberName: event.memberName } : {}),
|
|
819
848
|
});
|
|
@@ -828,9 +857,10 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
828
857
|
last.role === "assistant" &&
|
|
829
858
|
last.id.startsWith("streaming-") &&
|
|
830
859
|
(last.memberId ?? null) === (event.memberId ?? null)) {
|
|
860
|
+
const nextContent = cleanAgentContent(last.content + event.delta);
|
|
831
861
|
return [
|
|
832
862
|
...prev.slice(0, -1),
|
|
833
|
-
{ ...last, content:
|
|
863
|
+
{ ...last, content: nextContent },
|
|
834
864
|
];
|
|
835
865
|
}
|
|
836
866
|
return [
|
|
@@ -838,7 +868,7 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
838
868
|
{
|
|
839
869
|
id: `streaming-${crypto.randomUUID()}`,
|
|
840
870
|
role: "assistant",
|
|
841
|
-
content: event.delta,
|
|
871
|
+
content: cleanAgentContent(event.delta),
|
|
842
872
|
ts: event.ts,
|
|
843
873
|
...(event.memberId ? { memberId: event.memberId } : {}),
|
|
844
874
|
...(event.memberName ? { memberName: event.memberName } : {}),
|