Skip to content

feat(provider): split USAi provider facts from agent config rendering #481

Closed

Description

@mogul

Intent

Implement ADR-0030's provider-configuration split: usai-provider exports provider facts, and each agent kit renders those facts into the agent's native config format.

Parent: #473
ADR: #474

Scope

  • Define the neutral provider facts exported by usai-provider: endpoint, key environment variable, model catalog, and any required metadata.
  • Stop treating usai-provider as the owner of every agent's rendered config format.
  • Have the OpenCode agent kit render the OpenCode-specific provider config from those facts.
  • Keep agent config merge semantics inside the agent layer; acq must not deep-merge agent config files.

Deferred Decisions

  • Additional agents beyond OpenCode can be added incrementally once the fact/render split exists.
  • Exact model-catalog refresh behavior remains governed by existing USAi model-sync decisions unless this increment proves a gap.

Acceptance Criteria

  • The provider facts are represented once in neutral form.
  • OpenCode config is rendered by the OpenCode agent kit.
  • Existing provider behavior remains stable for users.
  • Tests cover fact export and OpenCode rendering without requiring network access.

Orchestration Notes

Implementation should be done by an authoring sub-agent and reviewed by an independent adversarial review sub-agent. Review findings must be addressed before the increment is accepted.

Activity

  1. wz-gsa commented on Sep 17, 2026

    @wz-gsa
    Contributor

    Status check against what's already landed on refactor/acq-devenv-base-image (ADR-0030 PR #474), so this issue's scope stays accurate:

    Already shipped on that branch (commit 31d0588f, "feat(provider): centralize usai provider facts"): acq.backends/common.sh now exposes named USAi provider facts — USAI_PROVIDER_HOST, USAI_PROVIDER_BASE_URL, USAI_PROVIDER_KEY_ENV, USAI_PROVIDER_MODELS_URL, USAI_PROVIDER_KEY_MGMT_URL — replacing scattered hardcoded constants. A follow-up commit (77ee43df) also defines a concrete artifact contract for the usai-provider kit to publish these facts to acq: provider-facts/usai.env, parsed as inert data, with explicit precedence (--host/--env flag > artifact > acq fallback).

    Scope this covers: endpoint/host/key-env-NAME facts consumed by acq for its own lifecycle and credential plumbing (secret binding, key validation, network/DNS diagnostics).

    Scope this does NOT cover, and is still open: the model catalog itself — which models exist, their context/output limits, and pricing. That's still owned entirely inside the usai-provider kit today, which renders opencode.jsonc directly (agentic-coding-patterns#417, just merged, refreshes that catalog under the current architecture). The "each agent kit renders provider facts into its own config format" half of this issue's scope — specifically for the model catalog — hasn't started yet.

    I looked at going further and proposing a 3-tier split (facts / cross-harness defaults / live-polling adapter per harness) and ran it through a 7-role adversarial consensus review before writing anything. Unanimous reject (7-0) — not on the facts/render idea itself, which several voters said they'd approve, but on: (a) live in-guest polling trading a determinism/reproducibility guarantee for a freshness gain that a maintainer-run sync + PR already gets at zero new runtime surface, (b) a harness-agnostic permission vocabulary designed against exactly one consumer, (c) sequencing — holding a CI-green user-facing fix (#417) behind a speculative refactor, and (d) pulling #485's install/entrypoint scope into this issue.

    Given that and what's already landed, I'd suggest this issue's remaining scope stay narrow: extend the existing facts artifact (or a sibling one) to include the model catalog, and have the OpenCode agent kit render it — no new runtime-fetch pattern, no new cross-harness vocabulary, both deferred until a second harness kit actually needs them.

  2. mogul commented on Sep 17, 2026

    @mogul
    ContributorAuthor

    Implemented the quickstart-side provider-facts consumer path on refactor/acq-devenv-base-image.

    Commit: c8150e3 feat(provider): load usai facts artifact

    What landed:

    • Added acq_provider_facts_load FILE to parse provider-facts/usai.env-style metadata as data, not shell.
    • Validates schema version, provider id, host/bind hosts, HTTPS URLs, and key env names before mutating the active USAi provider facts.
    • Missing artifact returns a distinct status and leaves fallback defaults intact.
    • Present-but-invalid artifact fails closed without partially overriding fallback defaults.
    • Added USAI_PROVIDER_BIND_HOSTS so future provider facts can distinguish API host from credential binding hosts.
    • SBX/MSB default USAi binding now uses USAI_PROVIDER_BIND_HOSTS, preserving current defaults and existing explicit --host/--env sidecar precedence.
    • Added Bats coverage for fallback, valid artifact, missing artifact, and invalid artifact behavior.

    Verification:

    • PASS: bash -n acq.backends/common.sh acq.backends/sbx.sh acq.backends/msb.sh
    • PASS: git diff --check
    • PASS: printf %s\\n acq.backends/common.sh acq.backends/sbx.sh acq.backends/msb.sh test/bats/50-kit-list-completeness.bats | xargs -r -n8 shellcheck --severity=warning
    • PASS: ./scripts/test-acq-bats test/bats/50-kit-list-completeness.bats test/bats/40-secret-set.bats test/bats/71-msb-provision-secrets.bats test/bats/77-usai-rotate.bats test/bats/30-dispatch-routing.bats (98/98)

    Still deferred:

    • Fetching the artifact from the pinned usai-provider kit ref and calling the loader automatically.
    • Removing/demoting fallback defaults after the patterns-side artifact exists at the pinned ref.
  3. mogul commented on Sep 17, 2026

    @mogul
    ContributorAuthor

    Added the second quickstart-side provider-facts consumer increment.

    Commit: 08a00b4 feat(provider): load facts from usai kit

    What landed:

    • acq now calls acq_provider_facts_load_from_kit "$USAI_KIT" after backend resolution.
    • If provider-facts/usai.env is absent in the pinned usai-provider kit, acq keeps the transitional fallback defaults.
    • If the artifact is present but invalid, acq refuses to continue rather than partially applying bad provider facts.
    • Added tests for loading from a fetched kit directory, absent artifact fallback, and invalid artifact fail-closed behavior.

    Verification:

    • PASS: bash -n acq.backends/common.sh acq.backends/sbx.sh acq.backends/msb.sh
    • PASS: git diff --check
    • PASS: focused ShellCheck on changed shell/test files
    • PASS: ./scripts/test-acq-bats test/bats/50-kit-list-completeness.bats test/bats/40-secret-set.bats test/bats/71-msb-provision-secrets.bats test/bats/77-usai-rotate.bats test/bats/30-dispatch-routing.bats (101/101)

    Still deferred:

    • Removing/demoting fallback defaults once the patterns-side usai-provider artifact exists at the pinned ref.
    • Re-rendering agent-specific config from facts; that remains agent-kit work.
  4. wz-gsa commented on Sep 21, 2026

    @wz-gsa
    Contributor

    @mogul — found a concrete shape mismatch between your two increments here and our patterns-side producer (GSA-TTS/agentic-coding-patterns#436, merged), while checking in on this issue.

    Your acq_provider_facts_load_from_kit() (commit 08a00b4) fetches the pinned usai-provider kit ref host-side and looks for:

    <fetched-kit-dir>/provider-facts/usai.env
    

    ...a flat KEY=value file with keys ACQ_PROVIDER_FACTS_SCHEMA, ACQ_PROVIDER_ID, ACQ_PROVIDER_HOST, ACQ_PROVIDER_BASE_URL, ACQ_PROVIDER_MODELS_URL, ACQ_PROVIDER_KEY_ENV, ACQ_PROVIDER_KEY_MGMT_URL, optional ACQ_PROVIDER_BIND_HOSTS — read at the pinned kit ref, before any sandbox exists.

    usai-provider's actual producer (#436, Layer 1 of ADR 0003 — GSA-TTS/agentic-coding-patterns#423) writes /var/lib/acq/models/providers/usai.json — JSON, inside the running guest, at sandbox startup. Different path, different format, different producer timing entirely. Your loader is fully wired into acq run's dispatch path (confirmed) and currently finds nothing, silently falling back to the transitional defaults you built for exactly that case — which is working as designed, just not yet doing anything real.

    These need to converge on one artifact. Given your loader already fails closed on a malformed file and is tested (101/101), and it's the piece other things (secret binding, USAI_PROVIDER_BIND_HOSTS) already depend on, I'd lean toward making usai-provider ship a static, kit-tree provider-facts/usai.env file in your exact shape (in addition to or instead of the current runtime JSON write) rather than asking your loader to also understand a guest-runtime artifact it can't reach pre-create anyway. Want me to open a patterns-side issue to add that file in your exact format, or do you have a preference on which side changes?

  5. mogul commented on Oct 6, 2026

    @mogul
    ContributorAuthor

    Implemented and shipped in v4.0.0 via #474 (with corrective #549). Provider facts are split via acq_provider_facts_load_from_kit reading provider-facts/usai.env, with fallback. The PR's Closes: footer did not auto-close this because the collapsed-stack squash merge dropped the closing keyword references; closing manually now that the work is on main and released.

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