@companion-ai/feynman 0.5.12 → 0.5.14

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/RELEASES.md CHANGED
@@ -6,6 +6,16 @@ GitHub release notes are generated from the matching `## vX.Y.Z` section in this
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## v0.5.14 - 2026-09-28
10
+
11
+ - **The Windows installer no longer fails on slow networks (#309).** When usage telemetry could not reach PostHog quickly, the PostHog library printed a timeout to stderr, and Windows PowerShell treats stderr from the installer's `feynman --help` check as a failure. Each telemetry send now has a 1.5 s budget and ends quietly, so no command waits on telemetry (on a stalled network `feynman --help` took 11 s and printed two errors; it now takes about 2 s and prints nothing). The installers also run their checks with telemetry off and judge them by exit code.
12
+ - pi-subagents 0.73.1 (no longer discards the prompt cache when subagents turn on; caps very large workflow output) and pi-web-access 0.33.0 (resumed sessions keep their tools; no false Pi version warnings). undici is overridden to a patched version for GHSA-3wwx-pv8p-q78v in the standalone installers; npm installs get the fix when pi-subagents releases its bump (nicobailon/pi-subagents#2548); pi-subagents only uses undici's HTTP proxy agent, not the affected WebSocket client.
13
+
14
+ ## v0.5.13 - 2026-09-28
15
+
16
+ - **OpenCode no longer recommends a retired Kimi model.** OpenCode Go and OpenCode Zen retired `kimi-k2.6` ("Use kimi-k2.7-code instead"), but Feynman still picked it as the default for new OpenCode users. It now recommends `kimi-k2.7-code`. If `feynman status` shows `kimi-k2.6`, switch with `feynman model set opencode-go/kimi-k2.7-code`. Three model preferences that no longer exist in the catalog were removed.
17
+ - A failed literature database request now names the service, for example `www.ebi.ac.uk request failed: 503`, instead of "Science database request failed".
18
+
9
19
  ## v0.5.12 - 2026-09-28
10
20
 
11
21
  - Crossref pacing leaves a margin over the pool's limit and retries a rate-limited request once after the server's `Retry-After`. A stress test of three bursts of 10 parallel searches on the public pool now succeeds on all 30; 0.5.11 still lost about one in six to network jitter.
@@ -72,9 +72,9 @@ const RESEARCH_MODEL_FAMILY_PREFERENCES = [
72
72
  },
73
73
  ];
74
74
  const RESEARCH_MODEL_FALLBACK_PREFERENCES = [
75
- exactResearchModel("opencode/kimi-k2.6", "good OpenCode Zen fallback for coding and research work"),
75
+ exactResearchModel("opencode/kimi-k2.7-code", "good OpenCode Zen fallback for coding and research work"),
76
76
  exactResearchModel("opencode/minimax-m2.7", "good OpenCode Zen fallback for source-heavy research work"),
77
- exactResearchModel("opencode-go/kimi-k2.6", "recommended OpenCode Go model for coding and research work"),
77
+ exactResearchModel("opencode-go/kimi-k2.7-code", "recommended OpenCode Go model for coding and research work"),
78
78
  exactResearchModel("opencode-go/minimax-m3", "good OpenCode Go fallback for source-heavy research work"),
79
79
  exactResearchModel("opencode-go/qwen3.7-max", "good OpenCode Go fallback for source-heavy research work"),
80
80
  exactResearchModel("opencode-go/glm-5.1", "good OpenCode Go fallback for GLM-backed research work"),
@@ -83,13 +83,10 @@ const RESEARCH_MODEL_FALLBACK_PREFERENCES = [
83
83
  matches: (model) => model.provider === "openrouter" && /^openai\/gpt-\d+(?:\.\d+)*(?:-.+)?$/i.test(model.id),
84
84
  reason: "newest OpenRouter OpenAI GPT fallback when direct OpenAI access is unavailable",
85
85
  },
86
- exactResearchModel("zai/glm-5", "good fallback when GLM is the available research model"),
87
86
  exactResearchModel("minimax/MiniMax-M3", "good fallback when MiniMax is the available research model"),
88
87
  exactResearchModel("minimax/MiniMax-M2.7", "good fallback when MiniMax is the available research model"),
89
88
  exactResearchModel("minimax/MiniMax-M2.7-highspeed", "good fallback when MiniMax is the available research model"),
90
89
  exactResearchModel("kimi-coding/kimi-for-coding", "Kimi Coding Plan stable ID, auto-maps to the latest backend model"),
91
- exactResearchModel("kimi-coding/k2p6", "Kimi K2.6 with strong reasoning for coding and research tasks"),
92
- exactResearchModel("kimi-coding/kimi-k2-thinking", "good fallback when Kimi is the available research model"),
93
90
  ];
94
91
  const PROVIDER_SORT_ORDER = [
95
92
  "anthropic",
@@ -21,13 +21,20 @@ let telemetryInitialized = false;
21
21
  let telemetryStartWarningPrinted = false;
22
22
  let telemetryTransportFailed = false;
23
23
  let telemetryNoticeThisProcess;
24
+ // On a slow or filtered network a pending send made every command wait for
25
+ // posthog-node's 10s deadline, and the library then printed its timeout to
26
+ // stderr, which Windows PowerShell treats as a failure (#309). Give each send
27
+ // a short budget and end it here, where it counts as a quiet transport failure.
28
+ export const TELEMETRY_REQUEST_BUDGET_MS = 1500;
24
29
  /** One silent attempt per session: after the first failure, later requests are dropped. */
25
- export function createTelemetryCircuitBreakerFetch(fetchImpl, onTransportFailure) {
30
+ export function createTelemetryCircuitBreakerFetch(fetchImpl, onTransportFailure, budgetMs = TELEMETRY_REQUEST_BUDGET_MS) {
26
31
  let open = false;
27
32
  return async (url, options) => {
28
33
  if (!open) {
29
34
  try {
30
- const response = await fetchImpl(url, options);
35
+ const budget = AbortSignal.timeout(budgetMs);
36
+ const signal = options.signal ? AbortSignal.any([options.signal, budget]) : budget;
37
+ const response = await fetchImpl(url, { ...options, signal });
31
38
  if (response.status >= 200 && response.status < 400)
32
39
  return response;
33
40
  throw new Error(`PostHog transport returned HTTP ${response.status}`);
@@ -36,7 +36,7 @@ async function fetchText(url: URL, accept: string): Promise<string> {
36
36
  signal: controller.signal,
37
37
  });
38
38
  if (!response.ok) {
39
- throw new Error(`Science database request failed: ${response.status} ${response.statusText}`);
39
+ throw new Error(`${url.hostname} request failed: ${response.status} ${response.statusText}`);
40
40
  }
41
41
  return response.text();
42
42
  } finally {
@@ -95,7 +95,7 @@ async function fetchJson(url: URL, headers: Record<string, string> = {}): Promis
95
95
  });
96
96
  if (!response.ok) {
97
97
  throw new ScienceDatabaseRequestError(
98
- `Science database request failed: ${response.status} ${response.statusText}`,
98
+ `${url.hostname} request failed: ${response.status} ${response.statusText}`,
99
99
  response.status,
100
100
  retryAfterMs(response.headers.get("retry-after")),
101
101
  );
@@ -56,7 +56,11 @@ function createPostHogClient(config: ResearchTelemetryConfig): ResearchTelemetry
56
56
  const fetchOnce: NonNullable<PostHogOptions["fetch"]> = async (url, options) => {
57
57
  if (!transportFailed) {
58
58
  try {
59
- const response = await fetch(url, options as RequestInit);
59
+ // A short budget per send, so a slow network ends quietly instead of
60
+ // hitting posthog-node's 10s deadline, which logs to stderr.
61
+ const budget = AbortSignal.timeout(1500);
62
+ const signal = options.signal ? AbortSignal.any([options.signal as AbortSignal, budget]) : budget;
63
+ const response = await fetch(url, { ...(options as RequestInit), signal });
60
64
  if (response.status >= 200 && response.status < 400) return response;
61
65
  } catch {}
62
66
  transportFailed = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@companion-ai/feynman",
3
- "version": "0.5.12",
3
+ "version": "0.5.14",
4
4
  "description": "Research-first CLI agent built on Pi and alphaXiv",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -84,8 +84,8 @@
84
84
  "fast-xml-parser": "5.11.1",
85
85
  "pi-btw": "0.6.1",
86
86
  "pi-docparser": "4.0.0",
87
- "pi-subagents": "0.71.0",
88
- "pi-web-access": "0.31.0",
87
+ "pi-subagents": "0.73.1",
88
+ "pi-web-access": "0.33.0",
89
89
  "posthog-node": "^5.53.0"
90
90
  },
91
91
  "peerDependencies": {
@@ -115,5 +115,8 @@
115
115
  "author": "Advait Paliwal",
116
116
  "publishConfig": {
117
117
  "access": "public"
118
+ },
119
+ "overrides": {
120
+ "undici": "^8.10.2"
118
121
  }
119
122
  }
@@ -325,39 +325,51 @@ Workarounds:
325
325
  throw "Downloaded archive did not contain the expected launcher: $candidate"
326
326
  }
327
327
  }
328
- $candidateVersionOutput = @(& $candidateCmd --version 2>&1)
329
- if ($LASTEXITCODE -ne 0) {
330
- throw "Downloaded launcher failed --version: $candidateCmd"
331
- }
332
- $candidateVersion = ($candidateVersionOutput | Select-Object -Last 1).ToString().Trim()
333
- if ($candidateVersion -ne $resolvedVersion) {
334
- throw "Downloaded bundle version mismatch: expected=$resolvedVersion actual=$candidateVersion"
335
- }
336
- $candidateHelp = @(& $candidateCmd --help 2>&1)
337
- if ($LASTEXITCODE -ne 0 -or $candidateHelp.Count -eq 0) {
338
- throw "Downloaded launcher failed --help: $candidateCmd"
339
- }
340
-
341
- # The public one-line installer can run under Windows PowerShell's default
342
- # Restricted policy because it executes an in-memory scriptblock. Validate
343
- # the packaged PowerShell launcher in a child host with an explicit process-
344
- # scoped bypass rather than invoking the downloaded .ps1 file directly.
345
- $powerShellExecutable = (Get-Process -Id $PID).Path
346
- $candidateVersionOutput = @(
347
- & $powerShellExecutable -NoProfile -ExecutionPolicy Bypass -File $candidatePs1 --version 2>&1
348
- )
349
- if ($LASTEXITCODE -ne 0) {
350
- throw "Downloaded launcher failed --version: $candidatePs1"
351
- }
352
- $candidateVersion = ($candidateVersionOutput | Select-Object -Last 1).ToString().Trim()
353
- if ($candidateVersion -ne $resolvedVersion) {
354
- throw "Downloaded bundle version mismatch: expected=$resolvedVersion actual=$candidateVersion"
355
- }
356
- $candidateHelp = @(
357
- & $powerShellExecutable -NoProfile -ExecutionPolicy Bypass -File $candidatePs1 --help 2>&1
358
- )
359
- if ($LASTEXITCODE -ne 0 -or $candidateHelp.Count -eq 0) {
360
- throw "Downloaded launcher failed --help: $candidatePs1"
328
+ # Verify with telemetry off: the check is not usage, and under
329
+ # $ErrorActionPreference = "Stop" any stderr line from a native command
330
+ # aborts the install (#309). Judge the launcher by its exit code instead.
331
+ $previousTelemetry = $env:FEYNMAN_TELEMETRY
332
+ $previousErrorAction = $ErrorActionPreference
333
+ try {
334
+ $env:FEYNMAN_TELEMETRY = "off"
335
+ $ErrorActionPreference = "Continue"
336
+ $candidateVersionOutput = @(& $candidateCmd --version 2>&1)
337
+ if ($LASTEXITCODE -ne 0) {
338
+ throw "Downloaded launcher failed --version: $candidateCmd"
339
+ }
340
+ $candidateVersion = ($candidateVersionOutput | Select-Object -Last 1).ToString().Trim()
341
+ if ($candidateVersion -ne $resolvedVersion) {
342
+ throw "Downloaded bundle version mismatch: expected=$resolvedVersion actual=$candidateVersion"
343
+ }
344
+ $candidateHelp = @(& $candidateCmd --help 2>&1)
345
+ if ($LASTEXITCODE -ne 0 -or $candidateHelp.Count -eq 0) {
346
+ throw "Downloaded launcher failed --help: $candidateCmd"
347
+ }
348
+
349
+ # The public one-line installer can run under Windows PowerShell's default
350
+ # Restricted policy because it executes an in-memory scriptblock. Validate
351
+ # the packaged PowerShell launcher in a child host with an explicit process-
352
+ # scoped bypass rather than invoking the downloaded .ps1 file directly.
353
+ $powerShellExecutable = (Get-Process -Id $PID).Path
354
+ $candidateVersionOutput = @(
355
+ & $powerShellExecutable -NoProfile -ExecutionPolicy Bypass -File $candidatePs1 --version 2>&1
356
+ )
357
+ if ($LASTEXITCODE -ne 0) {
358
+ throw "Downloaded launcher failed --version: $candidatePs1"
359
+ }
360
+ $candidateVersion = ($candidateVersionOutput | Select-Object -Last 1).ToString().Trim()
361
+ if ($candidateVersion -ne $resolvedVersion) {
362
+ throw "Downloaded bundle version mismatch: expected=$resolvedVersion actual=$candidateVersion"
363
+ }
364
+ $candidateHelp = @(
365
+ & $powerShellExecutable -NoProfile -ExecutionPolicy Bypass -File $candidatePs1 --help 2>&1
366
+ )
367
+ if ($LASTEXITCODE -ne 0 -or $candidateHelp.Count -eq 0) {
368
+ throw "Downloaded launcher failed --help: $candidatePs1"
369
+ }
370
+ } finally {
371
+ $ErrorActionPreference = $previousErrorAction
372
+ $env:FEYNMAN_TELEMETRY = $previousTelemetry
361
373
  }
362
374
 
363
375
  New-Item -ItemType Directory -Path $installRoot -Force | Out-Null
@@ -320,12 +320,12 @@ if [ ! -x "$candidate_bundle/feynman" ]; then
320
320
  echo "Downloaded archive did not contain the expected executable: ${bundle_name}/feynman" >&2
321
321
  exit 1
322
322
  fi
323
- candidate_version="$("$candidate_bundle/feynman" --version | tail -n 1)"
323
+ candidate_version="$(FEYNMAN_TELEMETRY=off "$candidate_bundle/feynman" --version | tail -n 1)"
324
324
  if [ "$candidate_version" != "$resolved_version" ]; then
325
325
  echo "Downloaded bundle version mismatch: expected ${resolved_version}, found ${candidate_version}." >&2
326
326
  exit 1
327
327
  fi
328
- "$candidate_bundle/feynman" --help >/dev/null
328
+ FEYNMAN_TELEMETRY=off "$candidate_bundle/feynman" --help >/dev/null
329
329
 
330
330
  mkdir -p "$INSTALL_APP_DIR"
331
331
  mkdir -p "$INSTALL_BIN_DIR"