triage remaining tracker fixes

This commit is contained in:
Advait Paliwal
2026-04-09 10:34:29 -07:00
parent 96234425ba
commit bfa538fa00
9 changed files with 157 additions and 1 deletions

View File

@@ -140,3 +140,12 @@ Use this file to track chronology, not release notes. Keep entries short, factua
- Failed / learned: The first packaged `search status` smoke test still showed the user home path because the native bundle had been built before the `FEYNMAN_HOME` path fix; rebuilding the native bundle resolved that mismatch. - Failed / learned: The first packaged `search status` smoke test still showed the user home path because the native bundle had been built before the `FEYNMAN_HOME` path fix; rebuilding the native bundle resolved that mismatch.
- Blockers: PowerShell runtime was unavailable locally, so Windows installer execution remained code-path validated rather than actually executed. - Blockers: PowerShell runtime was unavailable locally, so Windows installer execution remained code-path validated rather than actually executed.
- Next: Push the second-pass hardening commit, then keep issue `#46` and issue `#47` open until users on the affected Linux/CJK environments confirm whether the launcher/header fixes fully resolve them. - Next: Push the second-pass hardening commit, then keep issue `#46` and issue `#47` open until users on the affected Linux/CJK environments confirm whether the launcher/header fixes fully resolve them.
### 2026-04-09 10:36 PDT — remaining-tracker-triage-pass
- Objective: Reduce the remaining open tracker items by landing the lowest-risk missing docs/catalog updates and a targeted Cloud Code Assist compatibility patch instead of only hand-triaging them.
- Changed: Added MiniMax M2.7 recommendation preferences in `src/model/catalog.ts`; documented model switching, authenticated-provider visibility, and `/feynman-model` subagent overrides in `website/src/content/docs/getting-started/configuration.md` and `website/src/content/docs/reference/slash-commands.md`; added a runtime patch helper in `scripts/lib/pi-google-legacy-schema-patch.mjs` and wired `scripts/patch-embedded-pi.mjs` to normalize JSON Schema `const` into `enum` for the legacy `parameters` field used by Cloud Code Assist Claude models.
- Verified: Ran `npm test`, `npm run typecheck`, `npm run build`, and `cd website && npm run build` after the patch/helper/docs changes.
- Failed / learned: The MiniMax provider catalog in Pi already uses canonical IDs like `MiniMax-M2.7`, so the only failure during validation was a test assertion using the wrong casing rather than a runtime bug.
- Blockers: The Cloud Code Assist fix is validated by targeted patch tests and code-path review rather than an end-to-end Google account repro in this environment.
- Next: Push the tracker-triage commit, close the docs/MiniMax PRs as superseded by main, close the support-style model issues against the new docs, and decide whether the remaining feature requests should be left open or closed as not planned/upstream-dependent.

View File

@@ -0,0 +1 @@
export function patchPiGoogleLegacySchemaSource(source: string): string;

View File

@@ -0,0 +1,44 @@
const HELPER = [
"function normalizeLegacyToolSchema(schema) {",
" if (Array.isArray(schema)) return schema.map((item) => normalizeLegacyToolSchema(item));",
' if (!schema || typeof schema !== "object") return schema;',
" const normalized = {};",
" for (const [key, value] of Object.entries(schema)) {",
' if (key === "const") {',
" normalized.enum = [value];",
" continue;",
" }",
" normalized[key] = normalizeLegacyToolSchema(value);",
" }",
" return normalized;",
"}",
].join("\n");
const ORIGINAL =
' ...(useParameters ? { parameters: tool.parameters } : { parametersJsonSchema: tool.parameters }),';
const PATCHED = [
" ...(useParameters",
" ? { parameters: normalizeLegacyToolSchema(tool.parameters) }",
" : { parametersJsonSchema: tool.parameters }),",
].join("\n");
export function patchPiGoogleLegacySchemaSource(source) {
let patched = source;
if (patched.includes("function normalizeLegacyToolSchema(schema) {")) {
return patched;
}
if (!patched.includes(ORIGINAL)) {
return source;
}
patched = patched.replace(ORIGINAL, PATCHED);
const marker = "export function convertTools(tools, useParameters = false) {";
const markerIndex = patched.indexOf(marker);
if (markerIndex === -1) {
return source;
}
return `${patched.slice(0, markerIndex)}${HELPER}\n\n${patched.slice(markerIndex)}`;
}

View File

@@ -6,6 +6,7 @@ import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { FEYNMAN_LOGO_HTML } from "../logo.mjs"; import { FEYNMAN_LOGO_HTML } from "../logo.mjs";
import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs"; import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs";
import { patchPiGoogleLegacySchemaSource } from "./lib/pi-google-legacy-schema-patch.mjs";
import { PI_WEB_ACCESS_PATCH_TARGETS, patchPiWebAccessSource } from "./lib/pi-web-access-patch.mjs"; import { PI_WEB_ACCESS_PATCH_TARGETS, patchPiWebAccessSource } from "./lib/pi-web-access-patch.mjs";
import { PI_SUBAGENTS_PATCH_TARGETS, patchPiSubagentsSource } from "./lib/pi-subagents-patch.mjs"; import { PI_SUBAGENTS_PATCH_TARGETS, patchPiSubagentsSource } from "./lib/pi-subagents-patch.mjs";
@@ -616,6 +617,7 @@ if (existsSync(sessionSearchIndexerPath)) {
} }
const oauthPagePath = piAiRoot ? resolve(piAiRoot, "dist", "utils", "oauth", "oauth-page.js") : null; const oauthPagePath = piAiRoot ? resolve(piAiRoot, "dist", "utils", "oauth", "oauth-page.js") : null;
const googleSharedPath = piAiRoot ? resolve(piAiRoot, "dist", "providers", "google-shared.js") : null;
if (oauthPagePath && existsSync(oauthPagePath)) { if (oauthPagePath && existsSync(oauthPagePath)) {
let source = readFileSync(oauthPagePath, "utf8"); let source = readFileSync(oauthPagePath, "utf8");
@@ -628,6 +630,14 @@ if (oauthPagePath && existsSync(oauthPagePath)) {
if (changed) writeFileSync(oauthPagePath, source, "utf8"); if (changed) writeFileSync(oauthPagePath, source, "utf8");
} }
if (googleSharedPath && existsSync(googleSharedPath)) {
const source = readFileSync(googleSharedPath, "utf8");
const patched = patchPiGoogleLegacySchemaSource(source);
if (patched !== source) {
writeFileSync(googleSharedPath, patched, "utf8");
}
}
const alphaHubAuthPath = findPackageRoot("@companion-ai/alpha-hub") const alphaHubAuthPath = findPackageRoot("@companion-ai/alpha-hub")
? resolve(findPackageRoot("@companion-ai/alpha-hub"), "src", "lib", "auth.js") ? resolve(findPackageRoot("@companion-ai/alpha-hub"), "src", "lib", "auth.js")
: null; : null;

View File

@@ -95,6 +95,14 @@ const RESEARCH_MODEL_PREFERENCES = [
spec: "zai/glm-5", spec: "zai/glm-5",
reason: "good fallback when GLM is the available research model", reason: "good fallback when GLM is the available research model",
}, },
{
spec: "minimax/minimax-m2.7",
reason: "good fallback when MiniMax is the available research model",
},
{
spec: "minimax/minimax-m2.7-highspeed",
reason: "good fallback when MiniMax is the available research model",
},
{ {
spec: "kimi-coding/kimi-k2-thinking", spec: "kimi-coding/kimi-k2-thinking",
reason: "good fallback when Kimi is the available research model", reason: "good fallback when Kimi is the available research model",

View File

@@ -57,6 +57,16 @@ test("buildModelStatusSnapshotFromRecords flags an invalid current model and sug
assert.ok(snapshot.guidance.some((line) => line.includes("Configured default model is unavailable"))); assert.ok(snapshot.guidance.some((line) => line.includes("Configured default model is unavailable")));
}); });
test("chooseRecommendedModel prefers MiniMax M2.7 over highspeed when that is the authenticated provider", () => {
const authPath = createAuthPath({
minimax: { type: "api_key", key: "minimax-test-key" },
});
const recommendation = chooseRecommendedModel(authPath);
assert.equal(recommendation?.spec, "minimax/MiniMax-M2.7");
});
test("resolveInitialPrompt maps top-level research commands to Pi slash workflows", () => { test("resolveInitialPrompt maps top-level research commands to Pi slash workflows", () => {
const workflows = new Set(["lit", "watch", "jobs", "deepresearch"]); const workflows = new Set(["lit", "watch", "jobs", "deepresearch"]);
assert.equal(resolveInitialPrompt("lit", ["tool-using", "agents"], undefined, workflows), "/lit tool-using agents"); assert.equal(resolveInitialPrompt("lit", ["tool-using", "agents"], undefined, workflows), "/lit tool-using agents");
@@ -65,4 +75,3 @@ test("resolveInitialPrompt maps top-level research commands to Pi slash workflow
assert.equal(resolveInitialPrompt("chat", ["hello"], undefined, workflows), "hello"); assert.equal(resolveInitialPrompt("chat", ["hello"], undefined, workflows), "hello");
assert.equal(resolveInitialPrompt("unknown", ["topic"], undefined, workflows), "unknown topic"); assert.equal(resolveInitialPrompt("unknown", ["topic"], undefined, workflows), "unknown topic");
}); });

View File

@@ -0,0 +1,42 @@
import test from "node:test";
import assert from "node:assert/strict";
import { patchPiGoogleLegacySchemaSource } from "../scripts/lib/pi-google-legacy-schema-patch.mjs";
test("patchPiGoogleLegacySchemaSource rewrites legacy parameters conversion to normalize const", () => {
const input = [
"export function convertTools(tools, useParameters = false) {",
" if (tools.length === 0) return undefined;",
" return [",
" {",
" functionDeclarations: tools.map((tool) => ({",
" name: tool.name,",
" description: tool.description,",
' ...(useParameters ? { parameters: tool.parameters } : { parametersJsonSchema: tool.parameters }),',
" })),",
" },",
" ];",
"}",
"",
].join("\n");
const patched = patchPiGoogleLegacySchemaSource(input);
assert.match(patched, /function normalizeLegacyToolSchema\(schema\)/);
assert.match(patched, /normalized\.enum = \[value\]/);
assert.match(patched, /parameters: normalizeLegacyToolSchema\(tool\.parameters\)/);
});
test("patchPiGoogleLegacySchemaSource is idempotent", () => {
const input = [
"export function convertTools(tools, useParameters = false) {",
' ...(useParameters ? { parameters: tool.parameters } : { parametersJsonSchema: tool.parameters }),',
"}",
"",
].join("\n");
const once = patchPiGoogleLegacySchemaSource(input);
const twice = patchPiGoogleLegacySchemaSource(once);
assert.equal(twice, once);
});

View File

@@ -41,6 +41,36 @@ To see all models you have configured:
feynman model list feynman model list
``` ```
Only authenticated/configured providers appear in `feynman model list`. If you only see OpenAI models, it usually means only OpenAI auth is configured so far.
To add another provider, authenticate it first:
```bash
feynman model login anthropic
feynman model login google
```
Then switch the default model:
```bash
feynman model set anthropic/claude-opus-4-6
```
## Subagent model overrides
Feynman's bundled subagents inherit the main default model unless you override them explicitly. Inside the REPL, run:
```bash
/feynman-model
```
This opens an interactive picker where you can either:
- change the main default model for the session environment
- assign a different model to a specific bundled subagent such as `researcher`, `reviewer`, `writer`, or `verifier`
Per-subagent overrides are persisted in the synced agent files under `~/.feynman/agent/agents/` with a `model:` frontmatter field. Removing that field makes the subagent inherit the main default model again.
## Thinking levels ## Thinking levels
The `thinkingLevel` field controls how much reasoning the model does before responding. Available levels are `off`, `minimal`, `low`, `medium`, `high`, and `xhigh`. Higher levels produce more thorough analysis at the cost of latency and token usage. You can override per-session: The `thinkingLevel` field controls how much reasoning the model does before responding. Available levels are `off`, `minimal`, `low`, `medium`, `high`, and `xhigh`. Higher levels produce more thorough analysis at the cost of latency and token usage. You can override per-session:

View File

@@ -30,6 +30,7 @@ These are the primary commands you will use day-to-day. Each workflow dispatches
| `/log` | Write a durable session log with completed work, findings, open questions, and next steps | | `/log` | Write a durable session log with completed work, findings, open questions, and next steps |
| `/jobs` | Inspect active background work: running processes, scheduled follow-ups, and active watches | | `/jobs` | Inspect active background work: running processes, scheduled follow-ups, and active watches |
| `/help` | Show grouped Feynman commands and prefill the editor with a selected command | | `/help` | Show grouped Feynman commands and prefill the editor with a selected command |
| `/feynman-model` | Open the model picker for the main default model and per-subagent overrides |
| `/init` | Bootstrap `AGENTS.md` and session-log folders for a new research project | | `/init` | Bootstrap `AGENTS.md` and session-log folders for a new research project |
| `/outputs` | Browse all research artifacts (papers, outputs, experiments, notes) | | `/outputs` | Browse all research artifacts (papers, outputs, experiments, notes) |
| `/search` | Search prior session transcripts for past research and findings | | `/search` | Search prior session transcripts for past research and findings |
@@ -37,6 +38,8 @@ These are the primary commands you will use day-to-day. Each workflow dispatches
Session management commands help you organize ongoing work. The `/log` command is particularly useful at the end of a research session to capture what was accomplished and what remains. Session management commands help you organize ongoing work. The `/log` command is particularly useful at the end of a research session to capture what was accomplished and what remains.
The `/feynman-model` command opens an interactive picker that lets you either change the main default model or assign a different model to a bundled subagent like `researcher`, `reviewer`, `writer`, or `verifier`.
## Running workflows from the CLI ## Running workflows from the CLI
All research workflow slash commands can also be run directly from the command line: All research workflow slash commands can also be run directly from the command line: