pi-advisor-flow 0.8.1 → 0.8.2-dev.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project are documented here.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
6
6
 
7
+ ## Unreleased
8
+
9
+ ### Added
10
+
11
+ - Added a configurable Advisor Scout response-stream timeout in `/advisor-settings` and `advisor.json`, defaulting to 30 seconds. Model and auth resolution remain outside the timeout window.
12
+
13
+ ### Fixed
14
+
15
+ - Scout timeout fallbacks now report that the original conversation was retained instead of showing a misleading zero-kept/all-omitted selection count.
16
+
7
17
  ## 0.8.1 - 2026-09-23
8
18
 
9
19
  ### Fixed
package/dist/index.js CHANGED
@@ -14,6 +14,8 @@ var DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES = PI_DEFAULT_MAX_BYTES;
14
14
  var DEFAULT_ADVISOR_GIT_CONTEXT_MAX_CHARS = 20000;
15
15
  var DEFAULT_JEV_MODEL = "jev-latest";
16
16
  var DEFAULT_JEV_TIMEOUT_MS = 8000;
17
+ var DEFAULT_SCOUT_TIMEOUT_MS = 30000;
18
+ var MAX_SCOUT_TIMEOUT_MS = 2147483647;
17
19
  var DEFAULT_JEV_DIGEST_MAX_CHARS = 4000;
18
20
  var DEFAULT_JEV_PRICE_PER_MTOK = 0.042;
19
21
  var DEFAULT_JEV_FILTER_SKIP_CONFIDENCE = 0.85;
@@ -82,6 +84,7 @@ var advisorOutcomeLoggingRef = false;
82
84
  var advisorUntrackedContentRef = false;
83
85
  var advisorTrackedFileContentRef = false;
84
86
  var advisorScoutEnabledRef = false;
87
+ var advisorScoutTimeoutMsRef = DEFAULT_SCOUT_TIMEOUT_MS;
85
88
  var showUsageDetailsRef = true;
86
89
  var showUsageFooterRef = false;
87
90
  var setExecutorRef = (ref) => {
@@ -218,6 +221,9 @@ var setAdvisorTrackedFileContentRef = (enabled) => {
218
221
  var setAdvisorScoutEnabledRef = (enabled) => {
219
222
  advisorScoutEnabledRef = enabled;
220
223
  };
224
+ var setAdvisorScoutTimeoutMsRef = (value) => {
225
+ advisorScoutTimeoutMsRef = value;
226
+ };
221
227
  var setShowUsageDetailsRef = (enabled) => {
222
228
  showUsageDetailsRef = enabled;
223
229
  };
@@ -256,6 +262,7 @@ var getAdvisorSettings = () => ({
256
262
  planGate: advisorPlanGateRef,
257
263
  redactSecrets: advisorRedactSecretsRef,
258
264
  scoutEnabled: advisorScoutEnabledRef,
265
+ scoutTimeoutMs: advisorScoutTimeoutMsRef,
259
266
  sessionSummary: advisorSessionSummaryRef,
260
267
  showUsageDetails: showUsageDetailsRef,
261
268
  showUsageFooter: showUsageFooterRef,
@@ -436,6 +443,7 @@ var isValidGateFailureMode = (value) => isString(value) && GATE_FAILURE_MODE_NAM
436
443
  var isValidToolResultMaxLines = (value) => nonNegativeSafeInteger(value);
437
444
  var isValidToolResultMaxBytes = (value) => nonNegativeSafeInteger(value);
438
445
  var isValidJevTimeoutMs = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
446
+ var isValidScoutTimeoutMs = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 1 && value <= MAX_SCOUT_TIMEOUT_MS;
439
447
  var isValidJevDigestMaxChars = (value) => nonNegativeSafeInteger(value);
440
448
  var isValidJevPricePerMtok = (value) => typeof value === "number" && Number.isFinite(value) && value > 0;
441
449
  var isValidJevSkipConfidence = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0.5 && value <= 1;
@@ -631,6 +639,13 @@ var CONFIG_SCHEMA = {
631
639
  persisted: true,
632
640
  type: "boolean"
633
641
  },
642
+ advisorScoutTimeoutMs: {
643
+ accepted: `a positive safe integer no greater than ${MAX_SCOUT_TIMEOUT_MS} milliseconds`,
644
+ current: () => advisorScoutTimeoutMsRef,
645
+ persisted: true,
646
+ type: "number",
647
+ validate: isValidScoutTimeoutMs
648
+ },
634
649
  advisorSessionSummary: {
635
650
  accepted: "true or false",
636
651
  current: () => advisorSessionSummaryRef,
@@ -869,6 +884,7 @@ var resetDefaults = () => {
869
884
  setAdvisorUntrackedContentRef(false);
870
885
  setAdvisorTrackedFileContentRef(false);
871
886
  setAdvisorScoutEnabledRef(false);
887
+ setAdvisorScoutTimeoutMsRef(DEFAULT_SCOUT_TIMEOUT_MS);
872
888
  setShowUsageDetailsRef(true);
873
889
  setShowUsageFooterRef(false);
874
890
  };
@@ -901,6 +917,7 @@ var applyConfig = (config) => {
901
917
  applyOptionalConfig(config, "advisorModelWhitelist", setAdvisorModelWhitelistRef);
902
918
  applyOptionalConfig(config, "advisorSessionSummary", setAdvisorSessionSummaryRef);
903
919
  applyOptionalConfig(config, "advisorScoutEnabled", setAdvisorScoutEnabledRef);
920
+ applyOptionalConfig(config, "advisorScoutTimeoutMs", setAdvisorScoutTimeoutMsRef);
904
921
  applyOptionalConfig(config, "showUsageDetails", setShowUsageDetailsRef);
905
922
  applyOptionalConfig(config, "showUsageFooter", setShowUsageFooterRef);
906
923
  applyOptionalConfig(config, "simpleMode", setSimpleModeRef);
@@ -2701,7 +2718,6 @@ var formatAdvisorUsageStatus = (totals) => {
2701
2718
  };
2702
2719
 
2703
2720
  // src/scout.ts
2704
- var SCOUT_TIMEOUT_MS = 30000;
2705
2721
  var SCOUT_SYSTEM = [
2706
2722
  "You are Scout, a context curator serving a separate engineering Advisor.",
2707
2723
  "Select only conversation groups materially relevant to the current request, unresolved decisions, attempted work, diagnostics, and validation.",
@@ -2853,7 +2869,7 @@ var streamScoutResponse = async (dependencies, resolved, executorModel, executor
2853
2869
  teardown();
2854
2870
  }
2855
2871
  };
2856
- var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = SCOUT_TIMEOUT_MS, dependencies = defaultDependencies) => {
2872
+ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = advisorScoutTimeoutMsRef, dependencies = defaultDependencies) => {
2857
2873
  const startedAt = Date.now();
2858
2874
  const publish = (event) => {
2859
2875
  onEvent?.(event);
@@ -3500,7 +3516,6 @@ var scoutDetailsFromEvent = (event, previous) => {
3500
3516
  latencyMs: outcome.metrics.latencyMs,
3501
3517
  model: outcome.model,
3502
3518
  omittedBeforeScout: outcome.metrics.omittedBeforeScout,
3503
- selectedCount: 0,
3504
3519
  status: "fallback",
3505
3520
  usage: snapshotAdvisorUsage(outcome.metrics.usage)
3506
3521
  };
@@ -3572,7 +3587,16 @@ var scoutTitle = (scout, frame) => {
3572
3587
  }
3573
3588
  return "◆ SCOUT · FALLBACK";
3574
3589
  };
3575
- var scoutSummaryLine = (scout) => ` ${scout.model}${scout.selectedCount === undefined ? "" : ` · ${scout.selectedCount} kept / ${Math.max(0, (scout.availableCount ?? 0) - scout.selectedCount)} omitted`}${scout.latencyMs === undefined ? "" : ` · ${(scout.latencyMs / 1000).toFixed(1)}s`}`;
3590
+ var scoutSelectionSummary = (scout) => {
3591
+ if (scout.status === "fallback") {
3592
+ return " · original conversation retained";
3593
+ }
3594
+ if (scout.status !== "curated" || scout.selectedCount === undefined) {
3595
+ return "";
3596
+ }
3597
+ return ` · ${scout.selectedCount} kept / ${Math.max(0, (scout.availableCount ?? 0) - scout.selectedCount)} omitted`;
3598
+ };
3599
+ var scoutSummaryLine = (scout) => ` ${scout.model}${scoutSelectionSummary(scout)}${scout.latencyMs === undefined ? "" : ` · ${(scout.latencyMs / 1000).toFixed(1)}s`}`;
3576
3600
  var scoutExpandedLines = (scout, expanded, theme) => {
3577
3601
  const lines = [];
3578
3602
  if (expanded && scout.selectedLabels?.length) {
@@ -6055,6 +6079,16 @@ var toggle = (id, label, description, value, defaultValue) => ({
6055
6079
  label,
6056
6080
  values: TOGGLE_VALUES
6057
6081
  });
6082
+ var scoutTimeoutItem = (settings) => {
6083
+ const timeoutMs = settings.scoutTimeoutMs ?? DEFAULT_SCOUT_TIMEOUT_MS;
6084
+ return {
6085
+ currentValue: String(timeoutMs),
6086
+ description: "Maximum time for Scout's response stream; model and auth resolution happen before this timeout starts.",
6087
+ id: "scoutTimeoutMs",
6088
+ label: "Scout timeout ms",
6089
+ values: numericValues(timeoutMs, [5000, 1e4, 15000, 30000, 45000, 60000, 90000, 120000])
6090
+ };
6091
+ };
6058
6092
  var jevItems = (settings, theme, tui) => [
6059
6093
  {
6060
6094
  currentValue: settingValue(settings.jevFilterEnabled, false),
@@ -6212,7 +6246,7 @@ var createSettingsItems = ({
6212
6246
  id: "effort",
6213
6247
  label: "Advisor reasoning",
6214
6248
  values: withCurrentValue(currentEffort(settings.effort), effortLevels)
6215
- }, modelWhitelist, toggle("scoutEnabled", "Experimental Advisor Scout", "Enable the experimental Scout before Advisor calls.", settings.scoutEnabled, false), toggle("showUsageDetails", "Show usage and cost details", "Show token usage and cost details in Advisor responses.", settings.showUsageDetails, true), toggle("showUsageFooter", "Show usage in footer", "Show the current Advisor usage summary in the footer.", settings.showUsageFooter, false), toggle("planGate", "Plan gate", "Ask the Advisor to review implementation plans.", settings.planGate, true), toggle("failureGate", "Failure gate", "Ask the Advisor to review repeated failures.", settings.failureGate, true), toggle("completionGate", "Completion gate", "Ask the Advisor to review work before declaring success.", settings.completionGate, true), toggle("collapseResponses", "Collapse long responses", "Collapse long Advisor responses in the transcript.", settings.collapseResponses, false), {
6249
+ }, modelWhitelist, toggle("scoutEnabled", "Experimental Advisor Scout", "Enable the experimental Scout before Advisor calls.", settings.scoutEnabled, false), scoutTimeoutItem(settings), toggle("showUsageDetails", "Show usage and cost details", "Show token usage and cost details in Advisor responses.", settings.showUsageDetails, true), toggle("showUsageFooter", "Show usage in footer", "Show the current Advisor usage summary in the footer.", settings.showUsageFooter, false), toggle("planGate", "Plan gate", "Ask the Advisor to review implementation plans.", settings.planGate, true), toggle("failureGate", "Failure gate", "Ask the Advisor to review repeated failures.", settings.failureGate, true), toggle("completionGate", "Completion gate", "Ask the Advisor to review work before declaring success.", settings.completionGate, true), toggle("collapseResponses", "Collapse long responses", "Collapse long Advisor responses in the transcript.", settings.collapseResponses, false), {
6216
6250
  currentValue: settings.customRule || "None",
6217
6251
  description: "Add a rule that triggers Advisor involvement.",
6218
6252
  id: "customRule",
@@ -6510,6 +6544,10 @@ var applyJevMutation = (settings, id, value) => {
6510
6544
  settings.jevTimeoutMs = Number(value);
6511
6545
  return true;
6512
6546
  }
6547
+ case "scoutTimeoutMs": {
6548
+ settings.scoutTimeoutMs = Number(value);
6549
+ return true;
6550
+ }
6513
6551
  case "jevDigestMaxChars": {
6514
6552
  settings.jevDigestMaxChars = Number(value);
6515
6553
  return true;
@@ -6667,6 +6705,7 @@ var applySessionSettings = (settings) => {
6667
6705
  setAdvisorModelWhitelistRef(settings.modelWhitelist ?? []);
6668
6706
  setAdvisorSessionSummaryRef(settings.sessionSummary ?? false);
6669
6707
  setAdvisorScoutEnabledRef(settings.scoutEnabled ?? false);
6708
+ setAdvisorScoutTimeoutMsRef(settings.scoutTimeoutMs ?? DEFAULT_SCOUT_TIMEOUT_MS);
6670
6709
  setShowUsageDetailsRef(settings.showUsageDetails ?? true);
6671
6710
  setShowUsageFooterRef(settings.showUsageFooter ?? false);
6672
6711
  setSimpleModeRef(settings.simpleMode ?? false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-advisor-flow",
3
- "version": "0.8.1",
3
+ "version": "0.8.2-dev.1",
4
4
  "description": "Advanced Executor/Advisor flow for Pi, fully configurable and extendable.",
5
5
  "keywords": [
6
6
  "advisor",
@@ -31,6 +31,7 @@ import {
31
31
  setAdvisorPlanGateRef,
32
32
  setAdvisorRedactSecretsRef,
33
33
  setAdvisorScoutEnabledRef,
34
+ setAdvisorScoutTimeoutMsRef,
34
35
  setAdvisorSessionSummaryRef,
35
36
  setAdvisorToolPoliciesRef,
36
37
  setAdvisorToolResultMaxBytesRef,
@@ -55,6 +56,7 @@ import {
55
56
  DEFAULT_JEV_TRANSPORT,
56
57
  DEFAULT_JEV_TURN_GATE_EVERY_TURNS,
57
58
  DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
59
+ DEFAULT_SCOUT_TIMEOUT_MS,
58
60
  } from "../config/types.ts";
59
61
  import type { AdvisorSettings } from "../ui/types.ts";
60
62
 
@@ -75,6 +77,9 @@ const applySessionSettings = (settings: AdvisorSettings) => {
75
77
  setAdvisorModelWhitelistRef(settings.modelWhitelist ?? []);
76
78
  setAdvisorSessionSummaryRef(settings.sessionSummary ?? false);
77
79
  setAdvisorScoutEnabledRef(settings.scoutEnabled ?? false);
80
+ setAdvisorScoutTimeoutMsRef(
81
+ settings.scoutTimeoutMs ?? DEFAULT_SCOUT_TIMEOUT_MS
82
+ );
78
83
  setShowUsageDetailsRef(settings.showUsageDetails ?? true);
79
84
  setShowUsageFooterRef(settings.showUsageFooter ?? false);
80
85
  setSimpleModeRef(settings.simpleMode ?? false);
@@ -29,6 +29,7 @@ import {
29
29
  setAdvisorRedactSecretsRef,
30
30
  setAdvisorRef,
31
31
  setAdvisorScoutEnabledRef,
32
+ setAdvisorScoutTimeoutMsRef,
32
33
  setAdvisorSessionSummaryRef,
33
34
  setAdvisorToolPoliciesRef,
34
35
  setAdvisorToolResultMaxBytesRef,
@@ -60,6 +61,7 @@ import {
60
61
  DEFAULT_JEV_TRANSPORT,
61
62
  DEFAULT_JEV_TURN_GATE_EVERY_TURNS,
62
63
  DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
64
+ DEFAULT_SCOUT_TIMEOUT_MS,
63
65
  } from "./types.ts";
64
66
 
65
67
  export const resetDefaults = () => {
@@ -105,6 +107,7 @@ export const resetDefaults = () => {
105
107
  setAdvisorUntrackedContentRef(false);
106
108
  setAdvisorTrackedFileContentRef(false);
107
109
  setAdvisorScoutEnabledRef(false);
110
+ setAdvisorScoutTimeoutMsRef(DEFAULT_SCOUT_TIMEOUT_MS);
108
111
  setShowUsageDetailsRef(true);
109
112
  setShowUsageFooterRef(false);
110
113
  };
@@ -179,6 +182,11 @@ export const applyConfig = (config: AdvisorConfig) => {
179
182
  setAdvisorSessionSummaryRef
180
183
  );
181
184
  applyOptionalConfig(config, "advisorScoutEnabled", setAdvisorScoutEnabledRef);
185
+ applyOptionalConfig(
186
+ config,
187
+ "advisorScoutTimeoutMs",
188
+ setAdvisorScoutTimeoutMsRef
189
+ );
182
190
  applyOptionalConfig(config, "showUsageDetails", setShowUsageDetailsRef);
183
191
  applyOptionalConfig(config, "showUsageFooter", setShowUsageFooterRef);
184
192
  applyOptionalConfig(config, "simpleMode", setSimpleModeRef);
@@ -32,6 +32,7 @@ import {
32
32
  advisorRedactSecretsRef,
33
33
  advisorRef,
34
34
  advisorScoutEnabledRef,
35
+ advisorScoutTimeoutMsRef,
35
36
  advisorSessionSummaryRef,
36
37
  advisorToolPoliciesRef,
37
38
  advisorToolResultMaxBytesRef,
@@ -56,6 +57,7 @@ import {
56
57
  GATE_FAILURE_MODES,
57
58
  JEV_TRANSPORTS,
58
59
  MAX_CONTEXT_MAX_CHARS,
60
+ MAX_SCOUT_TIMEOUT_MS,
59
61
  } from "./types.ts";
60
62
 
61
63
  /** An empty ref means no model has been selected yet. */
@@ -116,6 +118,12 @@ export const isValidToolResultMaxBytes = (value: unknown): value is number =>
116
118
  export const isValidJevTimeoutMs = (value: unknown): value is number =>
117
119
  typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
118
120
 
121
+ const isValidScoutTimeoutMs = (value: unknown): value is number =>
122
+ typeof value === "number" &&
123
+ Number.isSafeInteger(value) &&
124
+ value >= 1 &&
125
+ value <= MAX_SCOUT_TIMEOUT_MS;
126
+
119
127
  export const isValidJevDigestMaxChars = (value: unknown): value is number =>
120
128
  nonNegativeSafeInteger(value);
121
129
 
@@ -344,6 +352,13 @@ export const CONFIG_SCHEMA = {
344
352
  persisted: true,
345
353
  type: "boolean",
346
354
  },
355
+ advisorScoutTimeoutMs: {
356
+ accepted: `a positive safe integer no greater than ${MAX_SCOUT_TIMEOUT_MS} milliseconds`,
357
+ current: () => advisorScoutTimeoutMsRef,
358
+ persisted: true,
359
+ type: "number",
360
+ validate: isValidScoutTimeoutMs,
361
+ },
347
362
  advisorSessionSummary: {
348
363
  accepted: "true or false",
349
364
  current: () => advisorSessionSummaryRef,
@@ -14,6 +14,7 @@ import {
14
14
  DEFAULT_JEV_TRANSPORT,
15
15
  DEFAULT_JEV_TURN_GATE_EVERY_TURNS,
16
16
  DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
17
+ DEFAULT_SCOUT_TIMEOUT_MS,
17
18
  } from "./types.ts";
18
19
  import type {
19
20
  AdvisorToolPolicies,
@@ -68,6 +69,7 @@ export let advisorOutcomeLoggingRef = false;
68
69
  export let advisorUntrackedContentRef = false;
69
70
  export let advisorTrackedFileContentRef = false;
70
71
  export let advisorScoutEnabledRef = false;
72
+ export let advisorScoutTimeoutMsRef = DEFAULT_SCOUT_TIMEOUT_MS;
71
73
  export let showUsageDetailsRef = true;
72
74
  export let showUsageFooterRef = false;
73
75
 
@@ -213,6 +215,9 @@ export const setAdvisorTrackedFileContentRef = (enabled: boolean) => {
213
215
  export const setAdvisorScoutEnabledRef = (enabled: boolean) => {
214
216
  advisorScoutEnabledRef = enabled;
215
217
  };
218
+ export const setAdvisorScoutTimeoutMsRef = (value: number) => {
219
+ advisorScoutTimeoutMsRef = value;
220
+ };
216
221
  export const setShowUsageDetailsRef = (enabled: boolean) => {
217
222
  showUsageDetailsRef = enabled;
218
223
  };
@@ -256,6 +261,7 @@ export const getAdvisorSettings = () => ({
256
261
  planGate: advisorPlanGateRef,
257
262
  redactSecrets: advisorRedactSecretsRef,
258
263
  scoutEnabled: advisorScoutEnabledRef,
264
+ scoutTimeoutMs: advisorScoutTimeoutMsRef,
259
265
  sessionSummary: advisorSessionSummaryRef,
260
266
  showUsageDetails: showUsageDetailsRef,
261
267
  showUsageFooter: showUsageFooterRef,
@@ -23,6 +23,8 @@ export const DEFAULT_JEV_MODEL = "jev-latest";
23
23
  // Provisional: the latency benchmark was dropped from scope; revisit if live
24
24
  // measurements suggest a different bound.
25
25
  export const DEFAULT_JEV_TIMEOUT_MS = 8000;
26
+ export const DEFAULT_SCOUT_TIMEOUT_MS = 30_000;
27
+ export const MAX_SCOUT_TIMEOUT_MS = 2_147_483_647;
26
28
  export const DEFAULT_JEV_DIGEST_MAX_CHARS = 4000;
27
29
  export const DEFAULT_JEV_PRICE_PER_MTOK = 0.042;
28
30
  export const DEFAULT_JEV_FILTER_SKIP_CONFIDENCE = 0.85;
@@ -86,6 +88,7 @@ export interface AdvisorConfig {
86
88
  advisorPlanGate?: boolean;
87
89
  advisorRedactSecrets?: boolean;
88
90
  advisorScoutEnabled?: boolean;
91
+ advisorScoutTimeoutMs?: number;
89
92
  advisorSessionSummary?: boolean;
90
93
  advisorToolPolicies?: AdvisorToolPolicies;
91
94
  advisorToolResultMaxBytes?: number;
package/src/scout.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  effectiveExecutorEffort,
6
6
  effectiveExecutorRef,
7
7
  } from "./child-session.ts";
8
+ import { advisorScoutTimeoutMsRef } from "./config/state.ts";
8
9
  import { isRecord, isString } from "./content-utils.ts";
9
10
  import { collectTextStream, resolveConfiguredModel } from "./model-stream.ts";
10
11
  import type {
@@ -21,8 +22,6 @@ import type { ScoutManifest } from "./scout-types.ts";
21
22
  import { snapshotAdvisorUsage } from "./usage.ts";
22
23
  import type { AdvisorUsageSnapshot } from "./usage.ts";
23
24
 
24
- const SCOUT_TIMEOUT_MS = 30_000;
25
-
26
25
  export const SCOUT_SYSTEM = [
27
26
  "You are Scout, a context curator serving a separate engineering Advisor.",
28
27
  "Select only conversation groups materially relevant to the current request, unresolved decisions, attempted work, diagnostics, and validation.",
@@ -299,7 +298,7 @@ export const runAdvisorScout = async (
299
298
  manifest: ScoutManifest,
300
299
  parentSignal?: AbortSignal,
301
300
  onEvent?: (event: ScoutLifecycleEvent) => void,
302
- timeoutMs = SCOUT_TIMEOUT_MS,
301
+ timeoutMs = advisorScoutTimeoutMsRef,
303
302
  dependencies: ScoutDependencies = defaultDependencies
304
303
  ): Promise<ScoutOutcome> => {
305
304
  const startedAt = Date.now();
@@ -53,7 +53,6 @@ export const scoutDetailsFromEvent = (
53
53
  latencyMs: outcome.metrics.latencyMs,
54
54
  model: outcome.model,
55
55
  omittedBeforeScout: outcome.metrics.omittedBeforeScout,
56
- selectedCount: 0,
57
56
  status: "fallback",
58
57
  usage: snapshotAdvisorUsage(outcome.metrics.usage),
59
58
  };
@@ -144,12 +143,18 @@ const scoutTitle = (scout: ScoutToolDetails, frame: string) => {
144
143
  return "◆ SCOUT · FALLBACK";
145
144
  };
146
145
 
146
+ const scoutSelectionSummary = (scout: ScoutToolDetails) => {
147
+ if (scout.status === "fallback") {
148
+ return " · original conversation retained";
149
+ }
150
+ if (scout.status !== "curated" || scout.selectedCount === undefined) {
151
+ return "";
152
+ }
153
+ return ` · ${scout.selectedCount} kept / ${Math.max(0, (scout.availableCount ?? 0) - scout.selectedCount)} omitted`;
154
+ };
155
+
147
156
  const scoutSummaryLine = (scout: ScoutToolDetails) =>
148
- ` ${scout.model}${
149
- scout.selectedCount === undefined
150
- ? ""
151
- : ` · ${scout.selectedCount} kept / ${Math.max(0, (scout.availableCount ?? 0) - scout.selectedCount)} omitted`
152
- }${scout.latencyMs === undefined ? "" : ` · ${(scout.latencyMs / 1000).toFixed(1)}s`}`;
157
+ ` ${scout.model}${scoutSelectionSummary(scout)}${scout.latencyMs === undefined ? "" : ` · ${(scout.latencyMs / 1000).toFixed(1)}s`}`;
153
158
 
154
159
  const scoutExpandedLines = (
155
160
  scout: ScoutToolDetails,
@@ -12,6 +12,7 @@ import {
12
12
  DEFAULT_JEV_TIMEOUT_MS,
13
13
  DEFAULT_JEV_TRANSPORT,
14
14
  DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
15
+ DEFAULT_SCOUT_TIMEOUT_MS,
15
16
  } from "../config/types.ts";
16
17
  import { isValidAdvisorToolPolicies } from "../config/validation.ts";
17
18
  import { JevSetupSubmenu } from "./jev-setup-submenu.ts";
@@ -56,6 +57,21 @@ const toggle = (
56
57
  values: TOGGLE_VALUES,
57
58
  });
58
59
 
60
+ const scoutTimeoutItem = (settings: AdvisorSettings): SettingItem => {
61
+ const timeoutMs = settings.scoutTimeoutMs ?? DEFAULT_SCOUT_TIMEOUT_MS;
62
+ return {
63
+ currentValue: String(timeoutMs),
64
+ description:
65
+ "Maximum time for Scout's response stream; model and auth resolution happen before this timeout starts.",
66
+ id: "scoutTimeoutMs",
67
+ label: "Scout timeout ms",
68
+ values: numericValues(
69
+ timeoutMs,
70
+ [5000, 10_000, 15_000, 30_000, 45_000, 60_000, 90_000, 120_000]
71
+ ),
72
+ };
73
+ };
74
+
59
75
  const jevItems = (
60
76
  settings: AdvisorSettings,
61
77
  theme: Theme,
@@ -288,6 +304,7 @@ export const createSettingsItems = ({
288
304
  settings.scoutEnabled,
289
305
  false
290
306
  ),
307
+ scoutTimeoutItem(settings),
291
308
  toggle(
292
309
  "showUsageDetails",
293
310
  "Show usage and cost details",
@@ -161,6 +161,10 @@ const applyJevMutation = (
161
161
  settings.jevTimeoutMs = Number(value);
162
162
  return true;
163
163
  }
164
+ case "scoutTimeoutMs": {
165
+ settings.scoutTimeoutMs = Number(value);
166
+ return true;
167
+ }
164
168
  case "jevDigestMaxChars": {
165
169
  settings.jevDigestMaxChars = Number(value);
166
170
  return true;
package/src/ui/types.ts CHANGED
@@ -98,6 +98,7 @@ export interface AdvisorSettings {
98
98
  planGate: boolean;
99
99
  redactSecrets?: boolean;
100
100
  scoutEnabled?: boolean;
101
+ scoutTimeoutMs?: number;
101
102
  sessionSummary?: boolean;
102
103
  showUsageDetails?: boolean;
103
104
  showUsageFooter?: boolean;