dsh-oauth-login 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +59 -0
- package/INSTALL.zh.md +45 -0
- package/LICENSE +201 -0
- package/README.en.md +104 -0
- package/README.md +104 -0
- package/README.zh.md +3 -0
- package/SECURITY.md +33 -0
- package/cordis.patch.yml +5 -0
- package/docs/network-proxy.md +45 -0
- package/docs/openrouter-sync.md +84 -0
- package/docs/screenshots/01-providers-signed-out.png +0 -0
- package/docs/screenshots/03-copilot-signing-in.png +0 -0
- package/docs/screenshots/04-mixed-live-states.png +0 -0
- package/docs/screenshots/05-copilot-sign-in.gif +0 -0
- package/docs/screenshots/06-cli-status-store.png +0 -0
- package/lib/bin.d.ts +5 -0
- package/lib/bin.js +2132 -0
- package/lib/client.js +1915 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +482 -0
- package/lib/index.js +3105 -0
- package/lib/invariant.d.ts +7 -0
- package/lib/invariant.js +8 -0
- package/package.json +180 -0
- package/src/adapter.ts +207 -0
- package/src/auth-routes.ts +654 -0
- package/src/auth.ts +76 -0
- package/src/bin.ts +185 -0
- package/src/catalog.ts +129 -0
- package/src/client/OpenRouterSyncStatus.tsx +66 -0
- package/src/client/PiLoginSettings.tsx +470 -0
- package/src/client/ProxySettings.tsx +123 -0
- package/src/client/SearchableModelSelect.tsx +595 -0
- package/src/client/draft-input.ts +12 -0
- package/src/client/index.tsx +71 -0
- package/src/client/locales.ts +176 -0
- package/src/client/login-input-copy.ts +34 -0
- package/src/client/login-window.ts +24 -0
- package/src/client/model-filter.ts +45 -0
- package/src/client/openrouter-store.ts +122 -0
- package/src/client/proxy-draft.ts +57 -0
- package/src/extra-models.ts +201 -0
- package/src/hosted-capture.ts +41 -0
- package/src/hosted-images.ts +154 -0
- package/src/http.ts +241 -0
- package/src/ids.ts +17 -0
- package/src/index.ts +183 -0
- package/src/invariant.ts +12 -0
- package/src/model-error-hint.ts +98 -0
- package/src/native-tools.ts +442 -0
- package/src/oauth-refresh.ts +49 -0
- package/src/openrouter-catalog.ts +245 -0
- package/src/openrouter-free.ts +76 -0
- package/src/openrouter-models.ts +155 -0
- package/src/openrouter-types.ts +40 -0
- package/src/plugin-config.ts +30 -0
- package/src/provider.ts +137 -0
- package/src/proxy-config.ts +61 -0
- package/src/proxy-store.ts +45 -0
- package/src/proxy-transport.ts +220 -0
- package/src/redact.ts +22 -0
- package/src/responses-tap.ts +97 -0
- package/src/session.ts +104 -0
- package/src/store.ts +234 -0
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/invariant.ts
|
|
2
|
+
const PACKAGE_NAME = "dsh-oauth-login";
|
|
3
|
+
const name = "pi-login-invariant";
|
|
4
|
+
const inject = ["invariants"];
|
|
5
|
+
const install = () => {};
|
|
6
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
7
|
+
//#endregion
|
|
8
|
+
export { apply, inject, name };
|
package/package.json
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-oauth-login",
|
|
3
|
+
"description": "DSH-owned subscription login powered by Pi AI adapters: OAuth plus official Plan API keys, with an independent credential store.",
|
|
4
|
+
"version": "0.2.4",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"registry": "https://registry.npmjs.org/"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/aa2246740/dsh-oauth-login.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/aa2246740/dsh-oauth-login#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/aa2246740/dsh-oauth-login/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"deepseek-harness",
|
|
19
|
+
"oauth",
|
|
20
|
+
"zhipu",
|
|
21
|
+
"glm",
|
|
22
|
+
"coding-plan",
|
|
23
|
+
"pi-agent",
|
|
24
|
+
"codex",
|
|
25
|
+
"openrouter"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22.19.0"
|
|
29
|
+
},
|
|
30
|
+
"type": "module",
|
|
31
|
+
"main": "lib/index.js",
|
|
32
|
+
"types": "lib/index.d.ts",
|
|
33
|
+
"bin": {
|
|
34
|
+
"dsh-oauth-login": "lib/bin.js"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "npm run typecheck && tsdown",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.client.json",
|
|
40
|
+
"check": "npm run typecheck && npm run test && npm run build",
|
|
41
|
+
"link:harness": "node scripts/link-harness-dependencies.mjs"
|
|
42
|
+
},
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types": "./lib/index.d.ts",
|
|
46
|
+
"default": "./lib/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./invariant": {
|
|
49
|
+
"types": "./lib/invariant.d.ts",
|
|
50
|
+
"default": "./lib/invariant.js"
|
|
51
|
+
},
|
|
52
|
+
"./client": "./lib/client.js",
|
|
53
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
54
|
+
"./package.json": "./package.json"
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"lib",
|
|
58
|
+
"src",
|
|
59
|
+
"cordis.patch.yml",
|
|
60
|
+
"INSTALL.md",
|
|
61
|
+
"INSTALL.zh.md",
|
|
62
|
+
"README.md",
|
|
63
|
+
"README.en.md",
|
|
64
|
+
"README.zh.md",
|
|
65
|
+
"SECURITY.md",
|
|
66
|
+
"LICENSE",
|
|
67
|
+
"docs/screenshots",
|
|
68
|
+
"docs/openrouter-sync.md",
|
|
69
|
+
"docs/network-proxy.md"
|
|
70
|
+
],
|
|
71
|
+
"license": "Apache-2.0",
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"undici": "^8.5.0"
|
|
74
|
+
},
|
|
75
|
+
"dsh": {
|
|
76
|
+
"bundle": {
|
|
77
|
+
"patch": "./cordis.patch.yml"
|
|
78
|
+
},
|
|
79
|
+
"client": {
|
|
80
|
+
"inject": [
|
|
81
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
82
|
+
"@deepseek-ai/dsh-client-ui-model-selection",
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
84
|
+
"@deepseek-ai/dsh-client-ui-session",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
86
|
+
"@deepseek-ai/dsh-client-locale"
|
|
87
|
+
],
|
|
88
|
+
"platform": "web"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"peerDependencies": {
|
|
92
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
93
|
+
"@deepseek-ai/dsh-atomic-write": "*",
|
|
94
|
+
"@deepseek-ai/dsh-attachment": "*",
|
|
95
|
+
"@deepseek-ai/dsh-client-connection": ">=0.1.5-rc.3 <0.1.6",
|
|
96
|
+
"@deepseek-ai/dsh-home-paths": "*",
|
|
97
|
+
"@deepseek-ai/dsh-host-webserver": "*",
|
|
98
|
+
"@deepseek-ai/dsh-invariants": "*",
|
|
99
|
+
"@deepseek-ai/dsh-llm": "*",
|
|
100
|
+
"@deepseek-ai/dsh-llm-pi-ai": "*",
|
|
101
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
102
|
+
"@earendil-works/pi-ai": "^0.85.1",
|
|
103
|
+
"react": "^18.2.0"
|
|
104
|
+
},
|
|
105
|
+
"peerDependenciesMeta": {
|
|
106
|
+
"@earendil-works/pi-ai": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"@deepseek-ai/cordis": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"@deepseek-ai/dsh-atomic-write": {
|
|
113
|
+
"optional": true
|
|
114
|
+
},
|
|
115
|
+
"@deepseek-ai/dsh-attachment": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"@deepseek-ai/dsh-client-connection": {
|
|
119
|
+
"optional": true
|
|
120
|
+
},
|
|
121
|
+
"@deepseek-ai/dsh-home-paths": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"@deepseek-ai/dsh-host-webserver": {
|
|
125
|
+
"optional": true
|
|
126
|
+
},
|
|
127
|
+
"@deepseek-ai/dsh-invariants": {
|
|
128
|
+
"optional": true
|
|
129
|
+
},
|
|
130
|
+
"@deepseek-ai/dsh-llm": {
|
|
131
|
+
"optional": true
|
|
132
|
+
},
|
|
133
|
+
"@deepseek-ai/dsh-llm-pi-ai": {
|
|
134
|
+
"optional": true
|
|
135
|
+
},
|
|
136
|
+
"@deepseek-ai/schemastery": {
|
|
137
|
+
"optional": true
|
|
138
|
+
},
|
|
139
|
+
"react": {
|
|
140
|
+
"optional": true
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"devDependencies": {
|
|
144
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
145
|
+
"@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.3",
|
|
146
|
+
"@deepseek-ai/dsh-atomic-write": "0.1.5-rc.3",
|
|
147
|
+
"@deepseek-ai/dsh-attachment": "0.1.5-rc.3",
|
|
148
|
+
"@deepseek-ai/dsh-authorization": "0.1.5-rc.3",
|
|
149
|
+
"@deepseek-ai/dsh-brand": "0.1.5-rc.3",
|
|
150
|
+
"@deepseek-ai/dsh-client-connection": "0.1.5-rc.3",
|
|
151
|
+
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.3",
|
|
152
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.3",
|
|
153
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.5-rc.3",
|
|
154
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.3",
|
|
155
|
+
"@deepseek-ai/dsh-client-ui-session": "0.1.5-rc.3",
|
|
156
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.3",
|
|
157
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.3",
|
|
158
|
+
"@deepseek-ai/dsh-credentials": "0.1.5-rc.3",
|
|
159
|
+
"@deepseek-ai/dsh-fs": "0.1.5-rc.3",
|
|
160
|
+
"@deepseek-ai/dsh-home-paths": "0.1.5-rc.3",
|
|
161
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.5-rc.3",
|
|
162
|
+
"@deepseek-ai/dsh-invariants": "0.1.5-rc.3",
|
|
163
|
+
"@deepseek-ai/dsh-launch-environment": "0.1.5-rc.3",
|
|
164
|
+
"@deepseek-ai/dsh-llm": "0.1.5-rc.3",
|
|
165
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.1.5-rc.3",
|
|
166
|
+
"@deepseek-ai/dsh-settings": "0.1.5-rc.3",
|
|
167
|
+
"@deepseek-ai/dsh-timeout": "0.1.5-rc.3",
|
|
168
|
+
"@deepseek-ai/dsh-util-values": "0.1.5-rc.3",
|
|
169
|
+
"@deepseek-ai/schemastery": "3.18.2",
|
|
170
|
+
"@earendil-works/pi-ai": "0.85.1",
|
|
171
|
+
"@types/node": "^22.20.0",
|
|
172
|
+
"@types/react": "~18.3.1",
|
|
173
|
+
"@types/semver": "7.7.1",
|
|
174
|
+
"react": "^18.2.0",
|
|
175
|
+
"semver": "^7.7.2",
|
|
176
|
+
"tsdown": "^0.22.2",
|
|
177
|
+
"typescript": "^6.0.3",
|
|
178
|
+
"vitest": "^4.1.8"
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/** One PiAiAdapter covering every Pi-login harness route. */
|
|
2
|
+
|
|
3
|
+
import { LlmError, ReasoningEffortId, resolveRetryPolicy } from '@deepseek-ai/dsh-llm'
|
|
4
|
+
import { defaultProviderAuthContext } from '@earendil-works/pi-ai'
|
|
5
|
+
import type {
|
|
6
|
+
GenerateOptions,
|
|
7
|
+
LlmResolvedModelInfo,
|
|
8
|
+
PreparedAdapterCall,
|
|
9
|
+
RetryPolicyConfig,
|
|
10
|
+
StreamChunk,
|
|
11
|
+
} from '@deepseek-ai/dsh-llm'
|
|
12
|
+
import { PiAiAdapter } from '@deepseek-ai/dsh-llm-pi-ai'
|
|
13
|
+
import type {
|
|
14
|
+
PiAiAdapterOptions as BasePiAiAdapterOptions,
|
|
15
|
+
ResolvedPiAiProviderProfile,
|
|
16
|
+
} from '@deepseek-ai/dsh-llm-pi-ai'
|
|
17
|
+
import type { AttachmentStore } from '@deepseek-ai/dsh-attachment'
|
|
18
|
+
import { PI_LOGIN_PROVIDERS, piLoginProviderByRoute } from './catalog.ts'
|
|
19
|
+
import { defaultReasoningEffortFor } from './extra-models.ts'
|
|
20
|
+
import { iterateInCapture } from './hosted-capture.ts'
|
|
21
|
+
import type { HostedCapture } from './hosted-capture.ts'
|
|
22
|
+
import { injectHostedImages, stripAssistantImages } from './hosted-images.ts'
|
|
23
|
+
import {
|
|
24
|
+
PI_LOGIN_MAX_REQUEST_IMAGE_BYTES,
|
|
25
|
+
PI_LOGIN_STREAM_IDLE_TIMEOUT_MS,
|
|
26
|
+
} from './ids.ts'
|
|
27
|
+
import { hintFailure, withModelErrorHint } from './model-error-hint.ts'
|
|
28
|
+
import type { PiLoginSession } from './session.ts'
|
|
29
|
+
import { openRouterDefaultEffort } from './openrouter-models.ts'
|
|
30
|
+
import { OPENROUTER_ROUTE } from './openrouter-types.ts'
|
|
31
|
+
import { filterHostedServerToolTraces, nativePlanForRoute } from './native-tools.ts'
|
|
32
|
+
import type { NativeToolPolicy } from './native-tools.ts'
|
|
33
|
+
|
|
34
|
+
export interface PiLoginAdapterOptions {
|
|
35
|
+
streamIdleTimeoutMs?: number
|
|
36
|
+
retryPolicy?: RetryPolicyConfig
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Keep provider failures routable for both direct and snapshot-prepared requests. */
|
|
40
|
+
async function* withFailureHints(source: AsyncIterable<StreamChunk>, provider: string): AsyncIterable<StreamChunk> {
|
|
41
|
+
try {
|
|
42
|
+
for await (const chunk of source) {
|
|
43
|
+
if (chunk.type === 'finish' && chunk.reason.kind === 'error') {
|
|
44
|
+
yield { ...chunk, reason: { ...chunk.reason, failure: hintFailure(chunk.reason.failure, provider) } }
|
|
45
|
+
} else {
|
|
46
|
+
yield chunk
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch (error: unknown) {
|
|
50
|
+
throw withModelErrorHint(error, provider)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Official Pi adapter plus bounded provider compatibility and Chat copy.
|
|
56
|
+
* `dsh-llm-retry` owns the attempt budget and routes on `code`. Finish chunks
|
|
57
|
+
* and thrown errors receive the same route-specific correction and hint.
|
|
58
|
+
*/
|
|
59
|
+
class PiLoginAdapter extends PiAiAdapter {
|
|
60
|
+
constructor(
|
|
61
|
+
config: BasePiAiAdapterOptions,
|
|
62
|
+
private readonly native: NativeToolPolicy,
|
|
63
|
+
private readonly resolveAttachments: () => AttachmentStore | undefined,
|
|
64
|
+
private readonly session: PiLoginSession,
|
|
65
|
+
) {
|
|
66
|
+
super(config)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
override resolveModel(
|
|
70
|
+
provider: string,
|
|
71
|
+
model: string,
|
|
72
|
+
signal?: AbortSignal,
|
|
73
|
+
): Promise<LlmResolvedModelInfo> {
|
|
74
|
+
return super.resolveModel(provider, model, signal).then((info) => {
|
|
75
|
+
const defaultEffort = this.defaultEffort(provider, model)
|
|
76
|
+
if (defaultEffort === undefined || info.reasoning === undefined) return info
|
|
77
|
+
return {
|
|
78
|
+
...info,
|
|
79
|
+
reasoning: {
|
|
80
|
+
...info.reasoning,
|
|
81
|
+
defaultEffort: ReasoningEffortId(defaultEffort),
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private defaultEffort(provider: string, model: string): string | undefined {
|
|
88
|
+
return (provider === OPENROUTER_ROUTE ? openRouterDefaultEffort(this.session.openRouter.model(model)) : undefined)
|
|
89
|
+
?? defaultReasoningEffortFor(model)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private sanitize(options: GenerateOptions): GenerateOptions {
|
|
93
|
+
const defaultEffort = this.defaultEffort(options.provider, options.model)
|
|
94
|
+
return {
|
|
95
|
+
...options,
|
|
96
|
+
messages: stripAssistantImages(options.messages),
|
|
97
|
+
...options.reasoningEffort === undefined && defaultEffort !== undefined
|
|
98
|
+
? { reasoningEffort: ReasoningEffortId(defaultEffort) }
|
|
99
|
+
: {},
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Live `llm.stream` dispatches `prepareCall().stream`, not `adapter.stream()`.
|
|
105
|
+
* Hosted X Search / web_search traces must be stripped on that path too,
|
|
106
|
+
* or Harness executes them as UNKNOWN_TOOL.
|
|
107
|
+
*/
|
|
108
|
+
private async * decorateStream(
|
|
109
|
+
options: GenerateOptions,
|
|
110
|
+
source: AsyncIterable<StreamChunk>,
|
|
111
|
+
): AsyncIterable<StreamChunk> {
|
|
112
|
+
const capture: HostedCapture = { images: [] }
|
|
113
|
+
try {
|
|
114
|
+
const raw = iterateInCapture(capture, this.session.proxy.iterate(
|
|
115
|
+
source,
|
|
116
|
+
options.provider === 'pi-openai-codex' && options.sessionId !== undefined
|
|
117
|
+
? String(options.sessionId)
|
|
118
|
+
: undefined,
|
|
119
|
+
))
|
|
120
|
+
const spec = piLoginProviderByRoute(options.provider)
|
|
121
|
+
const api = spec === undefined
|
|
122
|
+
? undefined
|
|
123
|
+
: this.session.visibleModels(spec.id).find(model => model.id === options.model)?.api
|
|
124
|
+
const plan = nativePlanForRoute(options.provider, api, this.native)
|
|
125
|
+
const filtered = plan === undefined ? raw : filterHostedServerToolTraces(raw)
|
|
126
|
+
const attachments = this.native.image ? this.resolveAttachments() : undefined
|
|
127
|
+
const decorated = attachments === undefined
|
|
128
|
+
? filtered
|
|
129
|
+
: injectHostedImages(filtered, capture, input => attachments.saveImage(input))
|
|
130
|
+
yield* withFailureHints(decorated, options.provider)
|
|
131
|
+
} catch (error: unknown) {
|
|
132
|
+
throw withModelErrorHint(error, options.provider)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
override async prepareCall(provider: string, model: string, signal?: AbortSignal): Promise<PreparedAdapterCall> {
|
|
137
|
+
const prepared = await this.session.proxy.run(() => super.prepareCall(provider, model, signal))
|
|
138
|
+
return {
|
|
139
|
+
...prepared,
|
|
140
|
+
stream: options => {
|
|
141
|
+
const sanitized = this.sanitize(options)
|
|
142
|
+
return this.decorateStream(sanitized, prepared.stream(sanitized))
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
override async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
|
|
148
|
+
const sanitized = this.sanitize(options)
|
|
149
|
+
yield* this.decorateStream(sanitized, super.stream(sanitized))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function createPiLoginAdapter(
|
|
154
|
+
session: PiLoginSession,
|
|
155
|
+
resolveAttachments: () => AttachmentStore | undefined,
|
|
156
|
+
options: PiLoginAdapterOptions = {},
|
|
157
|
+
): PiAiAdapter {
|
|
158
|
+
const streamIdleTimeoutMs = options.streamIdleTimeoutMs ?? PI_LOGIN_STREAM_IDLE_TIMEOUT_MS
|
|
159
|
+
const retryPolicy = resolveRetryPolicy(options.retryPolicy, 'dsh-oauth-login retryPolicy')
|
|
160
|
+
const requestImageLimits = {
|
|
161
|
+
requestImagePixelBudget: 2048 * 2048,
|
|
162
|
+
requestImageMaxBytes: 1024 * 1024,
|
|
163
|
+
}
|
|
164
|
+
const auth = {
|
|
165
|
+
auth: {
|
|
166
|
+
credentials: session.store,
|
|
167
|
+
authContext: defaultProviderAuthContext(),
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
return new PiLoginAdapter({
|
|
171
|
+
profiles: () => {
|
|
172
|
+
const profiles = new Map<string, ResolvedPiAiProviderProfile>()
|
|
173
|
+
for (const spec of PI_LOGIN_PROVIDERS) {
|
|
174
|
+
profiles.set(spec.route, {
|
|
175
|
+
provider: spec.route,
|
|
176
|
+
displayName: spec.displayName,
|
|
177
|
+
streamIdleTimeoutMs,
|
|
178
|
+
maxRequestImageBytes: PI_LOGIN_MAX_REQUEST_IMAGE_BYTES,
|
|
179
|
+
...requestImageLimits,
|
|
180
|
+
retryPolicy,
|
|
181
|
+
configuredMaxTokens: new Map(),
|
|
182
|
+
modelErrors: new Map(),
|
|
183
|
+
piProvider: session.provider(spec.id),
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
return profiles
|
|
187
|
+
},
|
|
188
|
+
resolveApiKey: async (route) => {
|
|
189
|
+
await session.ensureTransport()
|
|
190
|
+
const spec = piLoginProviderByRoute(route)
|
|
191
|
+
if (spec === undefined) {
|
|
192
|
+
throw new LlmError(`dsh-oauth-login: unknown route "${route}"`, 'MISSING_CREDENTIAL')
|
|
193
|
+
}
|
|
194
|
+
const auth = await session.models.getAuth(spec.id)
|
|
195
|
+
const apiKey = auth?.auth.apiKey
|
|
196
|
+
if (apiKey === undefined || apiKey.length === 0) {
|
|
197
|
+
throw new LlmError(
|
|
198
|
+
`${spec.displayName} is not connected. Open Settings → Subscription Login and connect it.`,
|
|
199
|
+
'MISSING_CREDENTIAL',
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
return apiKey
|
|
203
|
+
},
|
|
204
|
+
resolveAttachments,
|
|
205
|
+
...auth,
|
|
206
|
+
}, session.native, resolveAttachments, session)
|
|
207
|
+
}
|