Skip to content

Child sessions: model resolution misses providers registered by other extensions (and noExtensions:true skips request-transform hooks) #122

Description

@amchen2310

Summary

Dispatching an agent whose model: field names a provider registered by another extension (via pi.registerProvider) fails in the child session, while the same model works when it is the main session's model.

Two behaviors are involved, both specific to child sessions:

  1. The runtime used to resolve the child's model is created in this extension's init and does not include providers that other extensions register afterwards.
  2. Child sessions are built with noExtensions: true, so request-transform hooks (before_provider_request) installed by other extensions never run inside them.

Observed behavior

Dispatching such an agent through the subagent tool returns:

backend create failed: agent model '<provider>/<id>' not found in runtime (provider '<provider>', id '<id>').
Available: <providers from the built-in catalog and models.json>, … — pick one of these for the model param

The Available: list contains models from the built-in catalog and models.json, and does not contain any provider registered by another extension.

When the model id requires a request-time rewrite by an extension (for example an alias that maps to a different upstream id), the second behavior shows up as an upstream error instead:

model call ended with stopReason 'error' (provider/auth failure or rate limit) for model '<provider>/<id>'

with the upstream responding 400 for the alias id, i.e. the rewrite hook did not run.

Environment

  • armory-fleet 1.4.0
  • pi 0.85.1
  • Node v24.16.0
  • Linux 6.8.12-1021-tegra

Points in the code

  • src/index.ts:207const modelRuntime = await ModelRuntime.create(); runs during extension init.
  • src/index.ts:153model = modelRuntime.getModel(provider, id) resolves the child's model against that instance.
  • src/engine/child-loader.ts:83noExtensions: true for the child resource loader.

pi.registerProvider(...) in another extension registers into the host runtime; ModelRuntime.create() builds a separate instance from the built-in catalog + models.json + the models store. ExtensionContext.modelRegistry.getRegisteredProviderIds() / getRegisteredNativeProvider() / getRegisteredProviderConfig() do expose what the host has, and registering those onto the child-session runtime reproduces the missing models.

Separately, passing -e/--extension <path> on the pi CLI does not reach child loaders: that path is read from each loader's own additionalExtensionPaths (pi resource-loader.js:277), not from process argv.

Minimal reproduction

  1. An extension that registers a provider:
// ~/.pi/agent/extensions/demo-provider.ts
export default function (pi: any) {
  pi.registerProvider("demo", {
    api: "anthropic-messages",
    baseUrl: "https://example.invalid",
    models: [{ id: "demo-model", name: "Demo", contextWindow: 100000, maxTokens: 8000 }],
  });
}
  1. An agent that uses it:
<!-- ~/.pi/agent/agents/probe-demo.md -->
---
name: probe-demo
description: probe
model: demo/demo-model
tools: [read]
---
Reply OK.
  1. Dispatch it, e.g. through the subagent tool with agent: "probe-demo".

Result: not found in runtime (provider 'demo', id 'demo-model'), while pi -p --model demo/demo-model in the main session resolves and runs.

Notes

  • The same dispatch through the native Agent tool works, since that path runs with extensions loaded.
  • Passing the extension explicitly (-e) does not change the child-session result.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions