Skip to content

feat(agent): add Maple (OpenSecret) provider - #6607

Open
benthecarman wants to merge 4 commits into
block:mainfrom
benthecarman:investigate-maple-inference
Open

feat(agent): add Maple (OpenSecret) provider#6607
benthecarman wants to merge 4 commits into
block:mainfrom
benthecarman:investigate-maple-inference

Conversation

@benthecarman

Copy link
Copy Markdown
Contributor

Summary

Adds Maple (OpenSecret) as a buzz-agent inference provider, and makes
model discovery provider-generic so the desktop picks up new providers
with no desktop-side discovery code.

  • feat(agent): add provider-generic model discoverycatalog::discover_models is the one dispatch point behind both ACP session/new availableModels and a new buzz-agent models subcommand. Frontends stop carrying per-provider discovery knowledge; a provider added to the agent reaches every picker automatically. The subcommand builds its config without requiring a model, via a split of provider connection resolution out of Config::from_env.
  • feat(desktop): discover models via agent binary — the desktop runs buzz-agent models before the ACP fallback when the runtime is buzz-agent. It needs no configured model, so draft configs in the create/edit dialog get live models too. Missing keys render through a generic config: <KEY>_API_KEY required matcher instead of per-provider copy.
  • feat(agent): add Maple inference provider — requests travel through the opensecret SDK instead of a plain HTTPS POST: the enclave's AWS Nitro attestation document is verified against pinned PCR0 trust roots, an X25519 key exchange runs with the attested enclave, and request/response bodies are end-to-end encrypted. Inside the envelope the wire format is OpenAI Chat Completions, so the existing body builder and parser are reused unchanged. Retries follow post() with two deliberate differences: auth rejections fail immediately (a static key cannot mint a different token), and an attestation verification failure is terminal with an explicit "request not sent" message.
  • feat(desktop): add Maple provider config UI — "Maple (encrypted)" entry in the persona provider picker with a Maple API Key credential field; the readiness mirror requires MAPLE_API_KEY plus a model, with MAPLE_MODEL as the provider-specific fallback.

Keyless discovery: the Maple enclave lists models for any attested
session, so a model picker can fill in before the user has entered a
key. Inference still requires the key.

Configuration: BUZZ_AGENT_PROVIDER=maple, MAPLE_API_KEY,
MAPLE_MODEL, MAPLE_BASE_URL (default
https://enclave.trymaple.ai), MAPLE_PCR0_ENVIRONMENT
(production | development, which PCR0 trust roots verify the
attestation).

Related issue

None found.

Testing

  • just ci passes locally (fmt, clippy, unit + integration tests, desktop/web/mobile builds and tests).
  • buzz-agent: Maple client construction (HTTPS enforcement for non-loopback hosts, keyless construction), SDK error retryability and terminal-error mapping, summary completion cap, and catalog filtering (audio, TTS, and embedding ids dropped). Full suite green.
  • Desktop: readiness mirror tests cover Maple key/model requirements, including the MAPLE_MODEL fallback; buzz-agent models stdout parsing; frontend tests for the generic missing-key matcher.
  • E2E (mock bridge): new maple-provider-ui screenshot spec covers the picker entry and the credential field. Screenshots posted in the comments below.
  • Not exercised live: a real Maple enclave call needs a key I don't have. The attested transport is covered at the SDK boundary (error classification, retry, and terminal mapping) rather than end-to-end.

benthecarman and others added 4 commits August 22, 2026 22:39
Model discovery lived in per-provider arms: the agent's session/new
response listed live models only for Databricks, and each frontend
carried its own per-provider discovery code. A new provider meant a
new special case in every frontend.

Move the dispatch into the agent, which owns every provider
transport. catalog::discover_models is the one dispatch point. The
session/new availableModels block consumes it generically, and a new
"buzz-agent models" subcommand exposes it to frontends as a JSON
array. The subcommand runs before a model is chosen, so provider
connection resolution splits out of Config::from_env into a path
that does not require a model. Providers without an agent-side
catalog report an empty list so callers fall back to the configured
model.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: benthecarman <benthecarman@live.com>
The desktop's model picker listed live models only for providers
with desktop-side HTTP discovery; anything else fell through to the
ACP subprocess, which requires a configured model and therefore
fails for draft configs in the create/edit dialog with
"config: <PROVIDER>_MODEL required", shown as "Could not load live
models".

Run "buzz-agent models" before the ACP fallback when the runtime is
buzz-agent. The agent owns every provider transport and needs no
configured model, so a provider added to the agent now loads models
in the dialog with no desktop changes. Missing API keys match a
generic "config: <KEY>_API_KEY required" pattern instead of
per-provider copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: benthecarman <benthecarman@live.com>
Add Maple (OpenSecret) as a provider in buzz-agent, selected with
BUZZ_AGENT_PROVIDER=maple and configured through MAPLE_API_KEY,
MAPLE_MODEL, MAPLE_BASE_URL, and MAPLE_PCR0_ENVIRONMENT.

Requests travel through the opensecret SDK instead of a plain HTTPS
POST: the SDK verifies the enclave's AWS Nitro attestation document
against pinned PCR0 trust roots, performs the key exchange, and
end-to-end encrypts request and response bodies. Inside the envelope
the wire format is OpenAI Chat Completions, so the existing body
builder and parser are reused unchanged.

Retries follow post() (retryable statuses, escalating timeout
budgets, malformed-body retries) with two deliberate differences:
auth rejections fail immediately because a static key cannot mint a
different token, and an attestation verification failure is terminal
with an explicit "request not sent" message. That guarantee is the
reason to use this provider.

Model discovery plugs into the provider-generic dispatch and lists
the enclave's catalog through the same attested transport; audio,
TTS, and embedding models are filtered out. The enclave lists
models for any attested session without a credential, so discovery
accepts an empty key and builds an attested-but-unauthenticated
client. The model picker can fill in before the user enters a key;
inference still requires one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: benthecarman <benthecarman@live.com>
Show the buzz-agent Maple provider in the desktop app: the persona
provider picker gains a "Maple (encrypted)" entry with a Maple API
Key credential field, and the readiness mirror requires
MAPLE_API_KEY plus a model, accepting MAPLE_MODEL as the
provider-specific fallback.

No model-discovery code is added here. The picker loads Maple's
catalog through the provider-generic "buzz-agent models" path.

The buzz-agent per-provider readiness tests (OpenRouter, Maple) move
to a sibling file, following the goose file-config convention, so
readiness.rs stays under the desktop file-size limit. A Playwright
screenshot spec covers the picker entry and the credential field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: benthecarman <benthecarman@live.com>
@benthecarman
benthecarman requested a review from a team as a code owner August 23, 2026 04:16
@benthecarman

Copy link
Copy Markdown
Contributor Author

Maple in the provider picker

The persona provider picker lists "Maple (encrypted)" alongside the existing providers.

01-maple-provider-option

Maple selected

Selecting Maple swaps the credential field to a Maple API Key input. The model picker loads through the provider-generic buzz-agent models path, which works before a key is entered.

02-maple-api-key-field

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.

1 participant