Skip to content

Commit acb6f67

Browse files
authored
feat: add show_ui and show_trace_link config settings (#4)
Add two new boolean configuration options: - show_ui (env: BRAINTRUST_SHOW_UI, default: true): controls whether the extension renders any UI at all (status bar + trace link widget). When false, both the status indicator and the trace link widget are hidden. - show_trace_link (env: BRAINTRUST_SHOW_TRACE_LINK, default: true): controls whether the clickable trace link widget is shown below the editor. When false, the status bar still appears but the trace URL widget is suppressed. Both settings follow the existing config precedence: defaults → global config → project config → environment variables.
1 parent ea12f50 commit acb6f67

6 files changed

Lines changed: 144 additions & 4 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ Example:
108108
| `additional_metadata` | `BRAINTRUST_ADDITIONAL_METADATA` | `{}` |
109109
| `log_file` | `BRAINTRUST_LOG_FILE` | unset |
110110
| `state_dir` | `BRAINTRUST_STATE_DIR` | `~/.pi/agent/state/braintrust-pi-extension` |
111+
| `show_ui` | `BRAINTRUST_SHOW_UI` | `true` |
112+
| `show_trace_link` | `BRAINTRUST_SHOW_TRACE_LINK` | `true` |
111113
| `parent_span_id` | `PI_PARENT_SPAN_ID` | unset |
112114
| `root_span_id` | `PI_ROOT_SPAN_ID` | unset |
113115

src/config.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const ENV_KEYS = [
1616
"BRAINTRUST_DEBUG",
1717
"BRAINTRUST_LOG_FILE",
1818
"BRAINTRUST_STATE_DIR",
19+
"BRAINTRUST_SHOW_UI",
20+
"BRAINTRUST_SHOW_TRACE_LINK",
1921
"PI_PARENT_SPAN_ID",
2022
"PI_ROOT_SPAN_ID",
2123
"BRAINTRUST_ADDITIONAL_METADATA",
@@ -257,6 +259,53 @@ describe("loadConfig", () => {
257259
});
258260
});
259261

262+
it("defaults showUi and showTraceLink to true", () => {
263+
const home = makeTempDir("pi-extension-home-");
264+
process.env.HOME = home;
265+
process.env.BRAINTRUST_STATE_DIR = join(home, "state");
266+
267+
const config = loadConfig(home);
268+
269+
expect(config.showUi).toBe(true);
270+
expect(config.showTraceLink).toBe(true);
271+
});
272+
273+
it("applies show_ui and show_trace_link from config files", () => {
274+
const home = makeTempDir("pi-extension-home-");
275+
const cwd = join(home, "workspace");
276+
277+
process.env.HOME = home;
278+
process.env.BRAINTRUST_STATE_DIR = join(home, "state");
279+
280+
writeJson(join(home, ".pi", "agent", "braintrust.json"), {
281+
show_ui: false,
282+
});
283+
284+
const config = loadConfig(cwd);
285+
286+
expect(config.showUi).toBe(false);
287+
expect(config.showTraceLink).toBe(true);
288+
});
289+
290+
it("overrides show_ui and show_trace_link from environment variables", () => {
291+
const home = makeTempDir("pi-extension-home-");
292+
const cwd = join(home, "workspace");
293+
294+
process.env.HOME = home;
295+
process.env.BRAINTRUST_STATE_DIR = join(home, "state");
296+
process.env.BRAINTRUST_SHOW_UI = "true";
297+
process.env.BRAINTRUST_SHOW_TRACE_LINK = "false";
298+
299+
writeJson(join(home, ".pi", "agent", "braintrust.json"), {
300+
show_ui: false,
301+
});
302+
303+
const config = loadConfig(cwd);
304+
305+
expect(config.showUi).toBe(true);
306+
expect(config.showTraceLink).toBe(false);
307+
});
308+
260309
it("warns when tracing is enabled without an API key", () => {
261310
const home = makeTempDir("pi-extension-home-");
262311
process.env.HOME = home;
@@ -290,6 +339,8 @@ describe("createLogger", () => {
290339
additionalMetadata: {},
291340
parentSpanId: undefined,
292341
rootSpanId: undefined,
342+
showUi: true,
343+
showTraceLink: true,
293344
configIssues: [],
294345
};
295346

src/config.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,17 @@ function applyConfig(
218218
);
219219
if (additionalMetadata !== undefined) target.additionalMetadata = additionalMetadata;
220220

221+
const showUi = validateOptionalBoolean(source.show_ui, issues, path, "show_ui");
222+
if (showUi !== undefined) target.showUi = showUi;
223+
224+
const showTraceLink = validateOptionalBoolean(
225+
source.show_trace_link,
226+
issues,
227+
path,
228+
"show_trace_link",
229+
);
230+
if (showTraceLink !== undefined) target.showTraceLink = showTraceLink;
231+
221232
return {
222233
parentSpanConfigured: parentSpanId !== undefined,
223234
rootSpanConfigured: rootSpanId !== undefined,
@@ -238,6 +249,8 @@ export function loadConfig(cwd = process.cwd()): TraceConfig {
238249
additionalMetadata: {},
239250
parentSpanId: undefined,
240251
rootSpanId: undefined,
252+
showUi: true,
253+
showTraceLink: true,
241254
configIssues: [],
242255
};
243256

@@ -344,6 +357,22 @@ export function loadConfig(cwd = process.cwd()): TraceConfig {
344357
);
345358
if (envStateDir !== undefined) config.stateDir = envStateDir;
346359

360+
const envShowUi = validateOptionalBoolean(
361+
process.env.BRAINTRUST_SHOW_UI,
362+
config.configIssues,
363+
"BRAINTRUST_SHOW_UI",
364+
"BRAINTRUST_SHOW_UI",
365+
);
366+
if (envShowUi !== undefined) config.showUi = envShowUi;
367+
368+
const envShowTraceLink = validateOptionalBoolean(
369+
process.env.BRAINTRUST_SHOW_TRACE_LINK,
370+
config.configIssues,
371+
"BRAINTRUST_SHOW_TRACE_LINK",
372+
"BRAINTRUST_SHOW_TRACE_LINK",
373+
);
374+
if (envShowTraceLink !== undefined) config.showTraceLink = envShowTraceLink;
375+
347376
const envParentSpanId = validateOptionalNonEmptyString(
348377
process.env.PI_PARENT_SPAN_ID,
349378
config.configIssues,

src/index.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const mockState = vi.hoisted(() => ({
2222
additionalMetadata: {},
2323
parentSpanId: undefined,
2424
rootSpanId: undefined,
25+
showUi: true,
26+
showTraceLink: true,
2527
configIssues: [] as Array<{ path: string; message: string; severity: "error" | "warning" }>,
2628
},
2729
}));
@@ -117,6 +119,8 @@ beforeEach(() => {
117119
additionalMetadata: {},
118120
parentSpanId: undefined,
119121
rootSpanId: undefined,
122+
showUi: true,
123+
showTraceLink: true,
120124
configIssues: [],
121125
};
122126
vi.resetModules();
@@ -406,4 +410,49 @@ describe("braintrustPiExtension", () => {
406410
undefined,
407411
);
408412
});
413+
414+
it("hides all UI when showUi is false", async () => {
415+
mockState.config.showUi = false;
416+
417+
const { emit } = await createHarness();
418+
419+
await emit("session_start");
420+
await emit("before_agent_start", {
421+
prompt: "Inspect the package",
422+
images: [],
423+
});
424+
425+
const statusUpdates = mockState.statuses.filter(
426+
(s) => s.key === "braintrust-tracing" && s.text !== undefined,
427+
);
428+
const widgetUpdates = mockState.widgets.filter(
429+
(w) => w.key === "braintrust-trace-link" && w.content !== undefined,
430+
);
431+
432+
expect(statusUpdates).toEqual([]);
433+
expect(widgetUpdates).toEqual([]);
434+
});
435+
436+
it("hides just the trace link when showTraceLink is false", async () => {
437+
mockState.config.showTraceLink = false;
438+
439+
const { emit } = await createHarness();
440+
441+
await emit("session_start");
442+
await emit("before_agent_start", {
443+
prompt: "Inspect the package",
444+
images: [],
445+
});
446+
447+
const statusUpdates = mockState.statuses.filter(
448+
(s) => s.key === "braintrust-tracing" && s.text !== undefined,
449+
);
450+
expect(statusUpdates.length).toBeGreaterThan(0);
451+
expect(statusUpdates[0]?.text).toContain("Braintrust");
452+
453+
const widgetUpdates = mockState.widgets.filter(
454+
(w) => w.key === "braintrust-trace-link" && w.content !== undefined,
455+
);
456+
expect(widgetUpdates).toEqual([]);
457+
});
409458
});

src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,10 @@ function setTracingStatus(
193193
configIssue?: ConfigIssue;
194194
},
195195
): void {
196-
if (!ctx.hasUI) return;
196+
if (!ctx.hasUI || !config.showUi) {
197+
if (ctx.hasUI) ctx.ui.setStatus(TRACING_STATUS_KEY, undefined);
198+
return;
199+
}
197200

198201
const theme = ctx.ui.theme;
199202

@@ -269,15 +272,19 @@ function displayPath(path: string): string {
269272

270273
function setTraceWidget(
271274
ctx: ExtensionContext,
275+
config: TraceConfig,
272276
traceUrl: string | undefined,
273277
configIssue: ConfigIssue | undefined,
274278
): void {
275-
if (!ctx.hasUI) return;
279+
if (!ctx.hasUI || !config.showUi) {
280+
if (ctx.hasUI) ctx.ui.setWidget(TRACING_WIDGET_KEY, undefined);
281+
return;
282+
}
276283

277284
const theme = ctx.ui.theme;
278285
const lines: string[] = [];
279286

280-
if (traceUrl) {
287+
if (traceUrl && config.showTraceLink) {
281288
const label = makeHyperlink(
282289
traceUrl,
283290
theme.fg("accent", theme.underline("Braintrust trace ↗")),
@@ -334,7 +341,7 @@ export default function braintrustPiExtension(pi: ExtensionAPI): void {
334341
missingApiKey: Boolean(config.enabled && !config.apiKey),
335342
configIssue,
336343
});
337-
setTraceWidget(ctx, activeSession?.traceUrl, configIssue);
344+
setTraceWidget(ctx, config, activeSession?.traceUrl, configIssue);
338345
}
339346

340347
function persistTraceUrl(session: ActiveSession, traceUrl: string): void {

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export interface TraceConfig {
2626
additionalMetadata: JsonObject;
2727
parentSpanId?: string;
2828
rootSpanId?: string;
29+
showUi: boolean;
30+
showTraceLink: boolean;
2931
configIssues: ConfigIssue[];
3032
}
3133

0 commit comments

Comments
 (0)