You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Unified OAuth sign-in for all providers & working implementation on a fork
Hi all. CONTRIBUTING points feature work here since the repo isn't taking external PRs yet, so sharing this for feedback — everything described below is built, tested, and sitting ready if it's useful.
The gap I hit
Running dsh web locally, the Models page handles API keys well, but there's no way to sign in to providers whose credential needs a conversation — Anthropic Pro/Max OAuth being the one I wanted first. The interesting part: almost everything needed already ships in 0.1.1-rc.2. The ctx.authorization seam owns the conversation/lifecycle, and llm-pi-ai registers one flow per installed provider (packages/llm/llm-pi-ai/src/login.ts). The CLI can drive these; the browser can't, because no apiproxy domain exposes the seam.
Inventory from pi-ai's catalog, for reference:
OAuth today (7): anthropic, github-copilot, kimi-coding, openai-codex (OAuth-only — currently unusable from settings at all without this), openrouter, radius, xai
API-key login (31): deepseek, openai, google, mistral, etc. — unchanged by this work
What I built (fork branch, PR: mastaan66#2, issue with the full plan: #1)
One new apiproxy domain — five unary methods, no mux frames:
authorization.list / begin / cancel / status / answer
begin resolves only at settlement and runs caller-paced (no 30s unary deadline) since an OAuth attempt legitimately stays open for minutes
progress goes through a polled status({key}) side channel carrying buffered notices + at most one pending prompt; answer({key, promptRpcId, value}) correlates the reply
withdrawal has a single funnel: the authorization/settled listener declines any open question of that key, so endpoint cancel, caller abort, service teardown, and flow failure all unwind identically into a cancelled settlement
credentials never cross the wire — flows still write through ctx.credentials Host-side
On the client, each Models-page row joins the flow claiming its <settingsNs>/<route> record address and renders sign-in buttons per OAuth method, live notice/code/link progress, inline text/secret/select prompts, and cancel. API-key cards are untouched.
Design choice worth flagging for review: polling instead of pushing through the mux stream. The mux belongs to the sessions' single consumer in the client object layer, and threading auth frames through it couples a settings control to session transport for a dialog that only exists while someone watches it. Wire types were chosen so status's prompt projection can become a frame payload unchanged if push is ever wanted. Full rationale + alternatives in the Agent Note included in the branch (2026-08-26-authorization-web-wire, en/zh).
Testing
Host specs drive the real AuthorizationService through createApiProxy: refusal mapping (NO_FLOW/UNKNOWN_METHOD/ALREADY_IN_FLIGHT/NOT_COMMITTED), side channel, answer correlation, endpoint cancel, caller abort, late-settle guard
SignInControl at 100% file coverage; page-level spec covers join → card → begin → settle → credential-refresh loop
All keyless lanes: ~880 tests green across touched packages, both tsc aggregates clean
Because every flow comes from the installed catalog, all seven OAuth providers work with zero per-provider code, and anything pi-ai adds later shows up automatically. deepseek-official stays API-key by design.
Would love feedback on the polling-vs-mux call specifically, and whether the maintainer view prefers this as one domain or split differently. Happy to rework anything — the branch is small enough to move fast.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Unified OAuth sign-in for all providers & working implementation on a fork
Hi all. CONTRIBUTING points feature work here since the repo isn't taking external PRs yet, so sharing this for feedback — everything described below is built, tested, and sitting ready if it's useful.
The gap I hit
Running
dsh weblocally, the Models page handles API keys well, but there's no way to sign in to providers whose credential needs a conversation — Anthropic Pro/Max OAuth being the one I wanted first. The interesting part: almost everything needed already ships in0.1.1-rc.2. Thectx.authorizationseam owns the conversation/lifecycle, andllm-pi-airegisters one flow per installed provider (packages/llm/llm-pi-ai/src/login.ts). The CLI can drive these; the browser can't, because no apiproxy domain exposes the seam.Inventory from pi-ai's catalog, for reference:
What I built (fork branch, PR: mastaan66#2, issue with the full plan: #1)
One new apiproxy domain — five unary methods, no mux frames:
authorization.list / begin / cancel / status / answerbeginresolves only at settlement and runs caller-paced (no 30s unary deadline) since an OAuth attempt legitimately stays open for minutesstatus({key})side channel carrying buffered notices + at most one pending prompt;answer({key, promptRpcId, value})correlates the replyauthorization/settledlistener declines any open question of that key, so endpoint cancel, caller abort, service teardown, and flow failure all unwind identically into acancelledsettlementctx.credentialsHost-sideOn the client, each Models-page row joins the flow claiming its
<settingsNs>/<route>record address and renders sign-in buttons per OAuth method, live notice/code/link progress, inline text/secret/select prompts, and cancel. API-key cards are untouched.Design choice worth flagging for review: polling instead of pushing through the mux stream. The mux belongs to the sessions' single consumer in the client object layer, and threading auth frames through it couples a settings control to session transport for a dialog that only exists while someone watches it. Wire types were chosen so
status's prompt projection can become a frame payload unchanged if push is ever wanted. Full rationale + alternatives in the Agent Note included in the branch (2026-08-26-authorization-web-wire, en/zh).Testing
AuthorizationServicethroughcreateApiProxy: refusal mapping (NO_FLOW/UNKNOWN_METHOD/ALREADY_IN_FLIGHT/NOT_COMMITTED), side channel, answer correlation, endpoint cancel, caller abort, late-settle guardSignInControlat 100% file coverage; page-level spec covers join → card → begin → settle → credential-refresh loopBecause every flow comes from the installed catalog, all seven OAuth providers work with zero per-provider code, and anything pi-ai adds later shows up automatically.
deepseek-officialstays API-key by design.Would love feedback on the polling-vs-mux call specifically, and whether the maintainer view prefers this as one domain or split differently. Happy to rework anything — the branch is small enough to move fast.
All reactions