mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-11 06:30:25 +00:00
fix: stop artifact walk entering OS app-data dirs; context bar off by default
The artifacts scan used rglob and filtered after descending, so a home directory workspace walked into ~/Library and triggered the macOS App Data consent prompt on every turn. Walk with pruning instead, and skip Library / AppData in search too. The composer chip now shows the session total by default, with the context window bar behind a Settings toggle.
This commit is contained in:
@@ -165,6 +165,9 @@ export function App() {
|
||||
// {full model id → context window in tokens} from the curated matrix (verified only);
|
||||
// drives the composer usage chip's context-fill meter.
|
||||
const [modelContextWindows, setModelContextWindows] = useState<Record<string, number>>({});
|
||||
// Settings: show the composer's context-window fill bar. OFF by default (owner ask),
|
||||
// so an older backend without the field also shows the session total.
|
||||
const [contextBar, setContextBar] = useState(false);
|
||||
// Per-session token usage (OPE-42): rebuilt from the transcript on session load,
|
||||
// accumulated live from assistant_message events, reset with the transcript.
|
||||
const [usage, setUsage] = useState<SessionUsage>(emptyUsage());
|
||||
@@ -506,6 +509,7 @@ export function App() {
|
||||
setModels(s.models || []);
|
||||
setModelLabels(s.model_labels || {});
|
||||
setModelContextWindows(s.model_context_windows || {});
|
||||
setContextBar(s.context_bar === true);
|
||||
setModelReady(s.model_ready);
|
||||
if (s.surfaces) setSurfaces(s.surfaces);
|
||||
})
|
||||
@@ -1587,6 +1591,7 @@ export function App() {
|
||||
resetKey={sessionId}
|
||||
usage={usage}
|
||||
contextWindow={modelContextWindows[model]}
|
||||
contextBar={contextBar}
|
||||
placeholder={
|
||||
agent === "code"
|
||||
? "Ask the coder to build, fix, or explain… (drop or paste files)"
|
||||
|
||||
@@ -692,6 +692,9 @@ export interface ModelSettings {
|
||||
nav_layout?: "flat" | "grouped";
|
||||
// Sidebar: sessions shown per group before "Show more" (default 5, 1–50).
|
||||
sessions_peek?: number;
|
||||
// Composer: show the context-window fill bar (default FALSE; absent → the chip shows
|
||||
// the session total). The usage popover keeps both numbers regardless.
|
||||
context_bar?: boolean;
|
||||
// Curated-matrix display names ({full id → "GLM-5.2 · via Together"}); custom models absent.
|
||||
model_labels?: Record<string, string>;
|
||||
// {full id → context window in tokens}, verified matrix entries only — drives the
|
||||
@@ -758,6 +761,18 @@ export async function inspectPdf(
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/** Persist whether the composer shows the context-window fill bar. */
|
||||
export async function setContextBar(
|
||||
shown: boolean,
|
||||
): Promise<{ ok: boolean; context_bar?: boolean; error?: string }> {
|
||||
const res = await fetch(`${httpBase()}/v1/settings/context-bar`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ context_bar: shown }),
|
||||
});
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/** Persist how many sessions a sidebar group shows before "Show more". */
|
||||
export async function setSessionsPeek(
|
||||
n: number,
|
||||
|
||||
@@ -84,6 +84,8 @@ interface Props {
|
||||
// Context-window size (tokens) of the ACTIVE model, from the curated matrix;
|
||||
// undefined hides the fill meter (unverified/custom models) but keeps the counts.
|
||||
contextWindow?: number;
|
||||
// Settings toggle (default off): true shows the fill bar instead of the session total.
|
||||
contextBar?: boolean;
|
||||
}
|
||||
|
||||
export function Composer(props: Props) {
|
||||
@@ -469,13 +471,14 @@ export function Composer(props: Props) {
|
||||
|
||||
<span className="ml-auto" />
|
||||
|
||||
{/* token usage (OPE-42) — a quiet meter+count chip; hidden until the server
|
||||
reports usage. Fill = context-window occupancy (bounded), count = session
|
||||
consumption (unbounded, so never a fill). */}
|
||||
{/* token usage (OPE-42) — a quiet chip; hidden until the server reports usage.
|
||||
Shows the context-window fill bar alone (the session total lives in the
|
||||
popover), or the session total when there's no window / the bar is off. */}
|
||||
{!dictation?.recording && props.usage && totalTokens(props.usage) > 0 && (
|
||||
<UsageChip
|
||||
usage={props.usage}
|
||||
contextWindow={props.contextWindow}
|
||||
contextBar={props.contextBar}
|
||||
model={props.model}
|
||||
modelLabels={props.modelLabels}
|
||||
/>
|
||||
@@ -572,11 +575,13 @@ export function Composer(props: Props) {
|
||||
function UsageChip({
|
||||
usage,
|
||||
contextWindow,
|
||||
contextBar,
|
||||
model,
|
||||
modelLabels,
|
||||
}: {
|
||||
usage: SessionUsage;
|
||||
contextWindow?: number;
|
||||
contextBar?: boolean;
|
||||
model: string;
|
||||
modelLabels?: Record<string, string>;
|
||||
}) {
|
||||
@@ -585,6 +590,8 @@ function UsageChip({
|
||||
const pct = contextWindow
|
||||
? Math.min(100, Math.round((usage.context / contextWindow) * 100))
|
||||
: null;
|
||||
// Settings can hide the bar; without a known window there is nothing to fill either.
|
||||
const showBar = pct !== null && contextBar === true;
|
||||
const labelFor = (id: string) =>
|
||||
id === "unknown" ? "Unknown model" : modelLabels?.[id] || shortModel(id);
|
||||
// One field per line, session-summed (owner ask 2026-07-28). Values are cumulative
|
||||
@@ -605,21 +612,25 @@ function UsageChip({
|
||||
aria-expanded={open}
|
||||
aria-label="Token usage"
|
||||
title={
|
||||
pct !== null
|
||||
? `Token usage — ${pct}% of the context window used`
|
||||
: "Token usage this session"
|
||||
showBar
|
||||
? `Context window ${pct}% full · ${formatTokens(total)} tokens this session`
|
||||
: `Token usage this session: ${formatTokens(total)}`
|
||||
}
|
||||
data-testid="usage-chip"
|
||||
>
|
||||
{pct !== null && (
|
||||
<span className="w-7 h-1 rounded-full bg-line overflow-hidden" aria-hidden="true">
|
||||
{/* The bar is the context-window fill; pairing it with the session TOTAL read as
|
||||
"total is N% of the window", which it never was. Bar alone when we have a
|
||||
window, the session total only when we don't (so the chip is never empty). */}
|
||||
{showBar ? (
|
||||
<span className="w-12 h-1.5 rounded-full bg-line overflow-hidden" aria-hidden="true">
|
||||
<span
|
||||
className="block h-full bg-accent transition-all"
|
||||
style={{ width: `${Math.max(pct, 4)}%` }}
|
||||
style={{ width: `${Math.max(pct as number, 4)}%` }}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<span className="tabular-nums">{formatTokens(total)}</span>
|
||||
)}
|
||||
<span className="tabular-nums">{formatTokens(total)}</span>
|
||||
</button>
|
||||
{open && (
|
||||
<>
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
getSettings,
|
||||
getTrustedWorkspaces,
|
||||
setCompactionSettings,
|
||||
setContextBar,
|
||||
setOnboarded,
|
||||
setPdfSettings,
|
||||
setScratchBase,
|
||||
@@ -428,6 +429,8 @@ function AppearanceSection() {
|
||||
|
||||
<SidebarCard />
|
||||
|
||||
<ContextBarCard />
|
||||
|
||||
<FilesCard />
|
||||
|
||||
<TrustedWorkspacesCard />
|
||||
@@ -790,6 +793,48 @@ function CompactionCard() {
|
||||
);
|
||||
}
|
||||
|
||||
// -- Composer: context-window bar (owner ask 2026-07-30) ------------------------
|
||||
// The chip's bar is context-window occupancy; the session total (unbounded) lives in
|
||||
// the popover. Some people would rather not watch a meter at all, hence the toggle.
|
||||
function ContextBarCard() {
|
||||
const [shown, setShown] = useState<boolean | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
getSettings()
|
||||
.then((s) => setShown(s.context_bar === true))
|
||||
.catch(() => setShown(false));
|
||||
}, []);
|
||||
|
||||
const save = async (next: boolean) => {
|
||||
setShown(next);
|
||||
await setContextBar(next);
|
||||
};
|
||||
|
||||
if (shown === null) return null;
|
||||
return (
|
||||
<div className={CARD + " p-4 mb-4"} data-testid="context-bar-card">
|
||||
<div className={FIELD_LABEL}>Composer</div>
|
||||
<label className="flex items-start gap-3 py-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5"
|
||||
data-testid="context-bar-toggle"
|
||||
checked={shown}
|
||||
onChange={(e) => save(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="block text-[13px] text-ink">Show the context window bar</span>
|
||||
<span className="block text-[12px] text-muted">
|
||||
A small meter showing how full the model’s context window is. Turn it off
|
||||
to show this session’s token total instead; either way the full breakdown
|
||||
is one click away.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SidebarCard() {
|
||||
const [peek, setPeek] = useState<number | null>(null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user