Skip to content

feat(providers/pi): resolve models via Pi's ModelRegistry to support custom providers#1417

Closed
linlongtao8868 wants to merge 1 commit intocoleam00:devfrom
linlongtao8868:feat/pi-custom-provider-support
Closed

feat(providers/pi): resolve models via Pi's ModelRegistry to support custom providers#1417
linlongtao8868 wants to merge 1 commit intocoleam00:devfrom
linlongtao8868:feat/pi-custom-provider-support

Conversation

@linlongtao8868
Copy link
Copy Markdown

@linlongtao8868 linlongtao8868 commented Apr 26, 2026

Summary

  • Problem: Archon's Pi adapter looks up models via pi-ai's static catalog (getModel()). User-defined providers in ~/.pi/agent/models.json — the same file the pi CLI writes when you /models add a custom OpenAI-compatible or Anthropic-compatible proxy — fail with Pi model not found: provider='<x>' model='<y>' even though the pi CLI itself accepts them.
  • Why it matters: Blocks Archon workflows from routing through any endpoint not in the built-in catalog: company LLM gateways, internal proxies, third-party OpenAI-compatible shims, self-hosted Anthropic-compatible relays. Users who already have these configured in their pi CLI expect parity when the same account runs workflows through Archon.
  • What changed: Pi model resolution moves from pi-ai.getModel() (static catalog only) to piCodingAgent.ModelRegistry.create(authStorage).find(provider, modelId) (static catalog + ~/.pi/agent/models.json). Auth fast-fail moves from authStorage.getApiKey(provider) to modelRegistry.hasConfiguredAuth(model) so custom providers whose apiKey lives inside the models.json provider block aren't falsely rejected. Malformed models.json surfaces as a non-fatal system warning.
  • What did NOT change (scope boundary): No change to capabilities declared in PI_CAPABILITIES. No change to session resume, env-var precedence, extension loading, skills/tools resolution, structured output, or the Pi lazy-load contract (type-only import of ModelRegistry added; pi-ai static import removed because it's unused now). No change to Claude or Codex providers. No new env vars, no new config fields, no DB migration.

UX Journey

Before

User writes .archon/config.yaml:
  assistant: pi
  assistants.pi.model: my-proxy/claude-sonnet-4-6

User runs `pi --model my-proxy/claude-sonnet-4-6 "hi"` locally → works
  (pi CLI reads ~/.pi/agent/models.json, finds custom provider `my-proxy`)

User runs `archon workflow run archon-assist "hi"` → ERROR
  Pi model not found: provider='my-proxy' model='claude-sonnet-4-6'.
  See https://github.com/badlogic/pi-mono/.../models.generated.ts for the Pi model catalog.

User's workaround: switch every workflow back to a built-in provider
  (anthropic/…, openrouter/…) and re-enter credentials that were already
  set up in pi. Or: stop using Archon for pi-backed work.

After

User writes .archon/config.yaml (unchanged):
  assistant: pi
  assistants.pi.model: my-proxy/claude-sonnet-4-6

User runs `pi --model my-proxy/claude-sonnet-4-6 "hi"` locally → works

User runs `archon workflow run archon-assist "hi"` → [WORKS]
  provider.pi session_started {piProvider: "my-proxy", modelId: "claude-sonnet-4-6", …}
  我是 Claude,一个由 … 开发的 AI 助手 …
  Workflow completed successfully.

[new error surface] If ~/.pi/agent/models.json is malformed, user sees:
  ⚠️ Pi could not load custom providers from ~/.pi/agent/models.json:
  Invalid JSON at line 3, column 12
  Built-in providers still work; fix the file to use custom providers.
  (workflow still runs for any built-in model ref)

Architecture Diagram

Before

PiProvider.sendQuery()
    │
    ├─▶ AuthStorage.create()                 (reads ~/.pi/agent/auth.json)
    │
    ├─▶ pi-ai.getModel(provider, modelId)    [only Pi-mono static catalog]
    │       │
    │       └─▶ MODELS[provider][modelId]    ← user's ~/.pi/agent/models.json NOT consulted
    │
    ├─▶ authStorage.getApiKey(provider)      [auth.json api_key → oauth → env]
    │
    ├─▶ ModelRegistry.inMemory(authStorage)  (empty registry, unused for lookup)
    │
    └─▶ createAgentSession({ model, modelRegistry, … })

After

PiProvider.sendQuery()
    │
    ├─▶ AuthStorage.create()                        (reads ~/.pi/agent/auth.json)
    │
    ├─▶ [~] ModelRegistry.create(authStorage)       (reads ~/.pi/agent/models.json too)
    │        │
    │        ├─ getError()  ──▶ if parse error, yield system warning chunk
    │        └─ loads built-in catalog + user custom providers + provider overrides
    │
    ├─▶ [~] registry.find(provider, modelId)        (built-in ∪ custom)
    │
    ├─▶ [~] registry.hasConfiguredAuth(model)       (auth.json OR models.json apiKey)
    │
    └─▶ createAgentSession({ model, modelRegistry, … })
            └─▶ Pi SDK uses registry.getApiKeyAndHeaders(model) at request time
                 ─ picks up baseUrl/apiKey from the custom provider block transparently

[-] pi-ai static value import removed (model resolution no longer needs it)
[+] type-only import of ModelRegistry added (lazy-load contract preserved)

Connection inventory:

From To Status Notes
pi/provider.ts pi-ai.getModel removed Runtime import dropped; static type imports (Api, Model) remain
pi/provider.ts @mariozechner/pi-coding-agent ModelRegistry (type) new Type-only import for PiModelRegistry; preserves lazy-load
pi/provider.ts piCodingAgent.ModelRegistry.inMemory removed Replaced by .create()
pi/provider.ts piCodingAgent.ModelRegistry.create new Reads ~/.pi/agent/models.json via Pi's getAgentDir()
pi/provider.ts registry.find new Replaces pi-ai.getModel() for model resolution
pi/provider.ts registry.hasConfiguredAuth new Replaces authStorage.getApiKey() for auth fast-fail
pi/provider.ts registry.getError new Surfaces models.json parse errors as a system chunk

Label Snapshot

  • Risk: risk: low
  • Size: size: M
  • Scope: core (community provider code)
  • Module: providers:pi

Change Metadata

  • Change type: feature
  • Primary scope: core

Linked Issue

  • Closes #
  • Related #
  • Depends on #
  • Supersedes #

(No existing issue — raising this directly since the fix is small and self-contained. Happy to open an issue first if maintainers prefer that order.)

Validation Evidence (required)

$ bun run check:bundled
bundled-defaults.generated.ts is up to date (36 commands, 20 workflows).

$ bun run type-check
@archon/workflows type-check: Exited with code 0
@archon/core type-check: Exited with code 0
@archon/adapters type-check: Exited with code 0
@archon/server type-check: Exited with code 0
@archon/cli type-check: Exited with code 0
(providers, git, isolation, paths, web all 0)

$ bun run lint
(eslint clean, --max-warnings 0)

$ bun run format:check
All matched files use Prettier code style!

$ bun run test
(all packages — 0 fail across the monorepo)

@archon/providers pi test file: 58 pass / 0 fail (55 pre-existing + 2 new regressions around custom providers + 1 around malformed models.json).

  • Evidence provided: validation commands above; the new tests pin the contract pre-emptively so a future inMemory regression would fail loudly.
  • If any command is intentionally skipped: none.

Security Impact (required)

  • New permissions/capabilities? No — same filesystem surface as today. ModelRegistry.create() reads ~/.pi/agent/models.json, which the pi CLI already reads and writes; Archon's Pi adapter was already reading ~/.pi/agent/auth.json and ~/.pi/agent/sessions/** from the same directory.
  • New external network calls? No — model resolution is local. Custom providers' baseUrl is user-controlled via their own models.json; a user adding a malicious provider there has already compromised their pi credentials.
  • Secrets/tokens handling changed? Minor, intentional: credentials stored inside models.json's provider block (the apiKey field) are now consulted for auth fast-fail (hasConfiguredAuth) and at HTTP-request time (Pi SDK's getApiKeyAndHeaders). This is the same code path the pi CLI uses, and the same file the user already trusts pi to read. Archon does not log, copy, or re-emit the key.
  • File system access scope changed? No — same directory (~/.pi/agent/), same file (models.json) that Pi itself owns.

Compatibility / Migration

  • Backward compatible? Yes — model refs that resolved before (anthropic/…, openrouter/…, etc.) resolve identically through registry.find(). Error messages changed shape but still include the built-in catalog URL.
  • Config/env changes? No.archon/config.yaml schema unchanged. A user who does not have ~/.pi/agent/models.json sees identical behavior (the file is optional; ModelRegistry.create() tolerates its absence).
  • Database migration needed? No.
  • If yes, exact upgrade steps: n/a.

Human Verification (required)

  • Verified scenarios (on macOS arm64, Bun 1.3.x, dev mode):

    • Built-in provider regression: pi --print with anthropic/claude-* (both 200 and 403 responses) surfaces through unchanged — the same auth resolution path runs.
    • Custom provider happy path: .archon/config.yaml with model: <custom-provider>/<model>, where <custom-provider> is defined in my local ~/.pi/agent/models.json with baseUrl: https://<redacted-proxy> and an apiKey. bun run cli workflow run archon-assist "hi" completed successfully; logs show provider.pi session_started {piProvider: "<custom>", modelId: "<m>", …} and the response is the real model's self-identification.
    • Model-not-found: ref <valid-provider>/<bogus-model> surfaces the new error text containing both the built-in catalog URL and the models.json self-service hint.
    • Malformed models.json (intentionally broken file): workflow still runs for built-in refs; the system-chunk warning appears in the transcript. Fixing the file and re-running clears the warning.
    • Env-var overrides (ANTHROPIC_API_KEY etc.) still fire setRuntimeApiKey for built-in providers and are still ignored for custom providers whose auth lives in models.json — behavior pinned by the existing and new tests.
  • Edge cases checked:

    • hasConfiguredAuth false path (no auth.json entry, no env var, no models.json apiKey) still hits the original fast-fail error; the message was updated to mention the custom-provider route.
    • Lazy-load regression: provider-lazy-load.test.ts still asserts neither @mariozechner/pi-coding-agent nor @mariozechner/pi-ai are eagerly loaded when just registering and instantiating the provider; replacing the ModelRegistry.inMemory call with .create did not change this (the call site is inside sendQuery).
    • ModelRegistry.create is called from inside sendQuery after the PI_PACKAGE_DIR shim is installed — same ordering contract as before; the compiled-binary smoke path is unaffected.
  • What was not verified:

    • I did not build and run the full compiled binary (scripts/build-binaries.sh) locally — but the lazy-load test covers the critical invariant the binary build depends on (no eager Pi SDK imports).
    • I have not tested against every Pi-supported provider; the hasConfiguredAuth/find contract is Pi's to honor, and I leaned on Pi's own tests for that.

Side Effects / Blast Radius (required)

  • Affected subsystems/workflows: Pi community provider only. Any .archon/workflows/*.yaml with provider: pi — both chat-flow archon-assist-style nodes and DAG nodes — inherits the new resolution path. Claude/Codex workflows untouched.
  • Potential unintended effects:
    • A user with a malformed ~/.pi/agent/models.json who was previously unaware of the file will now see a system warning. This is intentional and actionable; a hidden parse error is worse than a visible one.
    • A user with a custom provider whose baseUrl or apiKey was wrong but who never tried to use it through Archon before will now surface the underlying 401/403/DNS error at request time. Also intentional — same error surface as pi CLI.
  • Guardrails/monitoring for early detection: provider.pi structured logs (session_started, prompt_completed, prompt_failed) already include piProvider and modelId; existing log-level filtering is enough to spot regressions. The new regression test in provider.test.ts fails loudly if someone reintroduces inMemory() or reverts to pi-ai.getModel().

Rollback Plan (required)

  • Fast rollback: revert the single commit. The change is confined to one file (packages/providers/src/community/pi/provider.ts) plus its test. No schema, no migration, no config flag.
  • Feature flags or config toggles: none intentionally — the behavior change is "honor an additional file Pi already owns", and gating it behind a flag would ship dead code. A user who wants the old behavior can remove ~/.pi/agent/models.json (or use only built-in refs); both paths still work after this PR.
  • Observable failure symptoms: a regression would show up as Pi model not found for a ref that worked under pi CLI, or as a spurious Pi auth: no credentials error on a custom provider whose apiKey is set in models.json. Either symptom is surfaced by the two new tests.

Risks and Mitigations

  • Risk: Future Pi SDK bumps might change ModelRegistry.create()'s default path away from ~/.pi/agent/models.json.
    • Mitigation: We rely on Pi's getAgentDir() (honored by both create() and the pi CLI). If Pi changes the location, both pi and Archon will pick up the new location together — same parity guarantee the PR is delivering.
  • Risk: A malicious or broken models.json entry with an unreachable baseUrl could stall a workflow until the request times out.
    • Mitigation: Pi's own HTTP client applies timeouts; Archon's existing abort-signal wiring (requestOptions.abortSignal) still plumbs through to session.abort(). Same failure shape as pi CLI with the same models.json.
  • Risk: An organization redistributing a pre-configured ~/.pi/agent/models.json as part of onboarding could unintentionally route agent traffic through an unexpected endpoint.
    • Mitigation: This is a pi-level trust boundary, not Archon's. The file is user-owned and user-managed; this PR does not widen or narrow that trust — it brings Archon in line with what pi already does.

Summary by CodeRabbit

  • New Features

    • Custom providers can now be defined in local configuration and participate in model resolution alongside built-in options.
  • Bug Fixes

    • Graceful error handling for malformed configuration files—warnings are now issued instead of halting execution.
    • Enhanced error messages when requested models cannot be resolved.
  • Refactor

    • Model registry and authentication validation mechanisms updated for improved extensibility.

…custom providers

Previously the Pi adapter looked up models via pi-ai's static catalog
(getModel), so user-defined providers in ~/.pi/agent/models.json — the
same file the `pi` CLI writes when you add a custom OpenAI-compatible
or Anthropic-compatible proxy — failed with 'Pi model not found' even
though `pi` CLI accepted them. This made it impossible to route Archon
workflows through an internal LLM gateway, a company proxy, or any
OpenAI-compatible endpoint that isn't in the built-in catalog.

Now the adapter constructs ModelRegistry.create(authStorage) instead of
inMemory(), which loads ~/.pi/agent/models.json on its own. Model lookup
goes through registry.find(provider, modelId), covering both the
built-in catalog AND user-defined custom providers. Auth fast-fail uses
registry.hasConfiguredAuth(model), which picks up apiKey fields inside
models.json's provider block so the adapter doesn't reject a model that
carries its own credentials.

Error messages distinguish the two code paths: missing models point at
both the built-in catalog URL and the models.json self-service route;
missing credentials hint at env vars / OAuth for built-in providers and
at the models.json apiKey field for custom providers. Malformed
models.json is surfaced as a system warning rather than aborting
workflows that only use built-in providers.

Removed the static import of pi-ai — model resolution no longer needs
it. Added type-only import of ModelRegistry so the lazy-load contract
is preserved (see the file's header comment on why value imports from
@mariozechner/* are forbidden at module scope).

Tests: replaced mockGetModel / mockModelRegistryInMemory with a single
configurable mockModelRegistryCreate that exposes find /
hasConfiguredAuth / getError. All 58 existing PiProvider assertions
retained; added two new regression tests — one pinning the custom-
provider end-to-end flow (baseUrl threaded to createAgentSession) and
one verifying malformed-models.json becomes a system chunk without
aborting the run.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

The Pi provider's model-resolution mechanism migrates from @mariozechner/pi-ai's static getModel catalog to a dynamic ModelRegistry from @mariozechner/pi-coding-agent, enabling custom providers from models.json to participate in lookup. Credential validation shifts to modelRegistry.hasConfiguredAuth and malformed configuration now yields warnings instead of failures.

Changes

Cohort / File(s) Summary
Pi Provider Implementation & Tests
packages/providers/src/community/pi/provider.ts, packages/providers/src/community/pi/provider.test.ts
Replaces static getModel-based model resolution with dynamic ModelRegistry.create(authStorage) to incorporate custom providers from models.json. Auth validation updates to use modelRegistry.hasConfiguredAuth(). Malformed models.json now produces warnings rather than failures. Test suite refactored to mock ModelRegistry behavior via per-test controls, removing @mariozechner/pi-ai mocking and validating registry.find() and hasConfiguredAuth() calls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A hop through the meadow of model resolution!

Registry finds the way,
Custom providers at play,
models.json no longer blocks the day—
With warnings that guide, all paths stay aligned! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: moving from pi-ai's getModel() to ModelRegistry-based resolution with explicit mention of custom provider support.
Description check ✅ Passed The description comprehensively covers all template sections: Problem, Why it matters, What changed, scope boundaries, detailed UX flows, architecture diagrams, change metadata, validation evidence, security analysis, compatibility notes, and rollback plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/providers/src/community/pi/provider.ts`:
- Around line 289-296: The user-facing messages currently hardcode
"~/.pi/agent/models.json" even though ModelRegistry.create(authStorage) respects
PI_CODING_AGENT_DIR; update the warning texts (the block that checks
modelRegistry.getError() and the similar messages later) to compute the actual
path used by ModelRegistry by resolving process.env.PI_CODING_AGENT_DIR or
falling back to path.join(os.homedir(), '.pi', 'agent', 'models.json'), and
include that resolved path in the process/yielded error content so users see the
real file to fix; locate references around piCodingAgent.ModelRegistry.create
and modelRegistry.getError to apply the change consistently for all three
messages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8d179e5a-58cf-490a-b646-5dac6bd222cf

📥 Commits

Reviewing files that changed from the base of the PR and between 9122673 and b57ddef.

📒 Files selected for processing (2)
  • packages/providers/src/community/pi/provider.test.ts
  • packages/providers/src/community/pi/provider.ts

Comment on lines +289 to +296
const modelRegistry = piCodingAgent.ModelRegistry.create(authStorage);
const modelsJsonError = modelRegistry.getError();
if (modelsJsonError) {
yield {
type: 'system',
content: `⚠️ Pi could not load custom providers from ~/.pi/agent/models.json:\n${modelsJsonError}\nBuilt-in providers still work; fix the file to use custom providers.`,
};
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

@mariozechner/pi-coding-agent ModelRegistry.create default models.json path PI_CODING_AGENT_DIR

💡 Result:

The default path for models.json in ModelRegistry.create(authStorage) is join(getAgentDir, "models.json"), where getAgentDir returns the directory specified by the PI_CODING_AGENT_DIR environment variable (default: ~/.pi/agent). Thus, the default full path is $PI_CODING_AGENT_DIR/models.json or ~/.pi/agent/models.json.

Citations:


🏁 Script executed:

# First, let's examine the file at the specified lines
head -320 packages/providers/src/community/pi/provider.ts | tail -50

Repository: coleam00/Archon

Length of output: 3126


🏁 Script executed:

# Also search for all occurrences of the hardcoded path and PI_CODING_AGENT_DIR in the file
rg -n "\.pi/agent" packages/providers/src/community/pi/provider.ts

Repository: coleam00/Archon

Length of output: 1566


🏁 Script executed:

# Check for PI_CODING_AGENT_DIR usage in the file
rg -n "PI_CODING_AGENT_DIR" packages/providers/src/community/pi/provider.ts

Repository: coleam00/Archon

Length of output: 222


🏁 Script executed:

# Check imports in the file to see what's available from piCodingAgent
head -50 packages/providers/src/community/pi/provider.ts | grep -E "import|from"

Repository: coleam00/Archon

Length of output: 1312


🏁 Script executed:

# Search for how PI_CODING_AGENT_DIR is used elsewhere in the codebase
rg -n "PI_CODING_AGENT_DIR" packages/ --type ts

Repository: coleam00/Archon

Length of output: 444


🏁 Script executed:

# Check if os.homedir() or path expansion is used elsewhere for similar cases
rg -n "homedir|expandUser|~/" packages/providers/src/community/pi/ --type ts -A 2

Repository: coleam00/Archon

Length of output: 11298


🏁 Script executed:

# Check if piCodingAgent exports a getAgentDir function
rg "getAgentDir|agentDir" packages/providers/src/community/pi/ --type ts

Repository: coleam00/Archon

Length of output: 174


🏁 Script executed:

# Check the pi-coding-agent package to see what's exported
npm list `@mariozechner/pi-coding-agent` 2>/dev/null || echo "Checking package.json for version"

Repository: coleam00/Archon

Length of output: 138


🏁 Script executed:

# Look for how the codebase resolves home paths for Pi directories
grep -r "homedir\|HOME" packages/providers/src/community/pi/ --include="*.ts" -B 2 -A 2

Repository: coleam00/Archon

Length of output: 2879


🏁 Script executed:

# Check package.json for pi-coding-agent dependency
grep -A 2 "pi-coding-agent" packages/providers/package.json

Repository: coleam00/Archon

Length of output: 180


🏁 Script executed:

# Look for any getAgentDir or similar exports used in the codebase
rg "piCodingAgent\." packages/providers/src/community/pi/provider.ts | head -20

Repository: coleam00/Archon

Length of output: 417


🏁 Script executed:

# Check if there's a way to get the resolved path from the ModelRegistry
rg "getAgentDir" packages/ --type ts -B 2 -A 2

Repository: coleam00/Archon

Length of output: 645


🏁 Script executed:

# Check if there's documentation or examples of how to get the agent dir
npm view `@mariozechner/pi-coding-agent`@0.67.5 | grep -A 20 "getAgentDir\|agent.*dir" || echo "Not found in npm"

Repository: coleam00/Archon

Length of output: 76


🏁 Script executed:

# Search for any usage of PI_CODING_AGENT_DIR with actual path construction
rg "process\.env\.PI_CODING_AGENT_DIR" packages/ -B 3 -A 3 --type ts

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

# Check how the Pi library documentation handles this in examples/tests
rg "ModelRegistry|getAgentDir" packages/providers/src/community/pi/provider.test.ts -B 2 -A 2

Repository: coleam00/Archon

Length of output: 2775


🏁 Script executed:

# Check if there's a helper or utility function that could resolve this
rg "homedir|join.*\.pi.*agent" packages/providers/src/community/pi/ --type ts -B 2 -A 2

Repository: coleam00/Archon

Length of output: 1999


🏁 Script executed:

# Look at the full context around the paths to see if we should use a helper
sed -n '275,330p' packages/providers/src/community/pi/provider.ts

Repository: coleam00/Archon

Length of output: 3451


🏁 Script executed:

# Check what's imported at the top of provider.ts to see if we need to add imports
head -30 packages/providers/src/community/pi/provider.ts

Repository: coleam00/Archon

Length of output: 1434


Fix hardcoded path to reflect PI_CODING_AGENT_DIR env var in all user-facing messages.

The warning at line 294 and similar messages at lines 304 and 316 hardcode ~/.pi/agent/models.json, but the code comments explicitly document that ModelRegistry.create() respects the PI_CODING_AGENT_DIR environment variable. Users setting this env var see incorrect paths in error messages and may edit the wrong file.

The suggested fix needs correction: tilde (~) is not expanded in Node.js. Use homedir() from node:os instead:

Corrected fix
+import { homedir } from 'node:os';
+
+    const piAgentDir = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), '.pi', 'agent');
+    const modelsJsonPath = join(piAgentDir, 'models.json');
     const modelRegistry = piCodingAgent.ModelRegistry.create(authStorage);
     const modelsJsonError = modelRegistry.getError();
     if (modelsJsonError) {
       yield {
         type: 'system',
-        content: `⚠️ Pi could not load custom providers from ~/.pi/agent/models.json:\n${modelsJsonError}\nBuilt-in providers still work; fix the file to use custom providers.`,
+        content: `⚠️ Pi could not load custom providers from ${modelsJsonPath}:\n${modelsJsonError}\nBuilt-in providers still work; fix the file to use custom providers.`,
       };
     }

Apply the same path resolution to lines 304 and 316.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/providers/src/community/pi/provider.ts` around lines 289 - 296, The
user-facing messages currently hardcode "~/.pi/agent/models.json" even though
ModelRegistry.create(authStorage) respects PI_CODING_AGENT_DIR; update the
warning texts (the block that checks modelRegistry.getError() and the similar
messages later) to compute the actual path used by ModelRegistry by resolving
process.env.PI_CODING_AGENT_DIR or falling back to path.join(os.homedir(),
'.pi', 'agent', 'models.json'), and include that resolved path in the
process/yielded error content so users see the real file to fix; locate
references around piCodingAgent.ModelRegistry.create and modelRegistry.getError
to apply the change consistently for all three messages.

@loopyd
Copy link
Copy Markdown

loopyd commented Apr 26, 2026

Duplicate of #1284

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Apr 28, 2026

Closing as resolved by #1284

@Wirasm Wirasm closed this Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants