@eduwork/dsh-oidc 0.2.2 → 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/CHANGELOG.en.md +6 -38
- package/CHANGELOG.md +7 -39
- package/CODE_OF_CONDUCT.en.md +1 -1
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTING.en.md +1 -1
- package/CONTRIBUTING.md +1 -1
- package/README.md +19 -16
- package/{README.en.md → README_EN.md} +15 -8
- package/SECURITY.en.md +1 -1
- package/SECURITY.md +1 -1
- package/SUPPORT.en.md +1 -1
- package/SUPPORT.md +1 -1
- package/docs/EDUWORK-MIGRATION.en.md +2 -8
- package/docs/EDUWORK-MIGRATION.md +2 -8
- package/docs/compatibility.en.md +3 -25
- package/docs/compatibility.md +3 -25
- package/docs/desktop-host.en.md +55 -55
- package/docs/desktop-host.md +64 -64
- package/docs/development.en.md +6 -4
- package/docs/development.md +6 -4
- package/docs/dsh-integration.en.md +2 -2
- package/docs/dsh-integration.md +2 -2
- package/docs/getting-started.en.md +4 -4
- package/docs/getting-started.md +4 -4
- package/docs/open-integration.en.md +73 -0
- package/docs/open-integration.md +73 -0
- package/docs/reasoning-replay.en.md +13 -0
- package/docs/reasoning-replay.md +17 -0
- package/docs/release-checklist.en.md +7 -61
- package/docs/release-checklist.md +7 -61
- package/docs/server-integration-contract.en.md +4 -2
- package/docs/server-integration-contract.md +5 -3
- package/examples/enterprise-profile.example.json +78 -78
- package/examples/identity-only.example.json +1 -1
- package/examples/resources-discovery.example.json +1 -1
- package/lib/provider/core.js +1 -0
- package/lib/provider/transform-adapter.js +27 -1
- package/lib/provider/transforms.js +0 -1
- package/lib/typert.host.js +38 -38
- package/lib/typert.remote-client.js +37 -37
- package/package.json +6 -5
- package/schema/enterprise-profile.v1alpha1.schema.json +193 -193
package/docs/desktop-host.en.md
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
# Desktop hosts without a persistent Web server
|
|
2
|
-
|
|
3
|
-
[简体中文](desktop-host.md)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```yaml
|
|
8
|
-
- id: enterprise-oidc
|
|
9
|
-
name: '@eduwork/dsh-oidc'
|
|
10
|
-
config:
|
|
11
|
-
backend: desktop
|
|
12
|
-
allowEmptyProfiles: true
|
|
13
|
-
profilePathEnv: EDUWORK_OIDC_PROFILE
|
|
14
|
-
desktop:
|
|
15
|
-
callbackPort: 0
|
|
16
|
-
flowTimeoutMs: 600000
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
The host supplies a Cordis `desktopServices` service with `openExternal(url: string): Promise<void>`. OIDC builds the authorization URL from reviewed Profile discovery; the renderer cannot submit an arbitrary URL. The shell opens the system browser, rejects non-HTTP(S) and userinfo URLs, and never logs authorization query parameters. The plugin does not execute shell commands or import Electron/Wails. The service can arrive later; removing it cancels pending sign-ins.
|
|
20
|
-
|
|
21
|
-
When the distribution provides `configFile: {path, examplesPath}`, organization settings stay read-only and are loaded again on restart. The optional Host method `openConfiguration(target: 'config' | 'examples'): Promise<void>` enables configuration-file and example-folder buttons. The RPC accepts these two fixed targets only; the host resolves its own paths, and the renderer cannot send a path or command. `configuration().configFile.canOpen` reports availability. Web hosts without this capability show the configuration-file location instead. Personal models and configured organization sign-in remain available.
|
|
22
|
-
|
|
23
|
-
Resource binding accepts the original `worker.user-center.v1`, the transitional `worker-user-center/v1`, and `eduwork-resources/v1`. Unknown versions and mismatched Provider IDs are rejected before creating a model credential. Completed identity sign-in is retained, with an error identifying the separate resource/configuration problem.
|
|
24
|
-
|
|
25
|
-
The host must implement `credentials.resolve/set/unset`, backed by its operating-system vault. The plugin has no plaintext credential file or fallback on storage failure. OAuth tokens remain Host-only. Personal API keys remain independent of the organization's managed credential. The public `oidcAccounts.authorizedFetch()` capability remains Host-only.
|
|
26
|
-
|
|
27
|
-
Only an explicit sign-in starts an IPv4 `127.0.0.1` listener. The callback is `http://127.0.0.1:<port>/oauth/callback`, using a random port by default. Register a public PKCE client supporting dynamic loopback ports with the IdP. For providers requiring an exact registered URI, a trusted `callbackPort` can pin the port; a conflict fails explicitly instead of switching to an unregistered port. Other bind addresses are not configurable. Cancellation, expiry, success, a valid failed callback, service disposal and host shutdown close the listener. Invalid Host, Origin, state, method or path cannot consume the legitimate attempt.
|
|
28
|
-
|
|
29
|
-
Shared Host/Client RPC additions:
|
|
30
|
-
|
|
31
|
-
- `begin(profileID)` returns `{mode:'external', loginID, expiresAt}` for desktop. Existing Web `redirect` and legacy `completed` variants remain supported.
|
|
32
|
-
- `loginStatus(loginID)` returns `{loginID, profileID, state, expiresAt, status?, errorCode?}`. State is pending/completed/cancelled/expired/failed.
|
|
33
|
-
- `cancelLogin(loginID)` returns the same safe projection and waits for an in-flight credential write to roll back.
|
|
34
|
-
- `openConfiguration(target)` returns `{opened:true}` in file-managed mode; the only targets are `config` and `examples`. System-opening failures produce a concise message.
|
|
35
|
-
- `selectEnterpriseModel(profileID, {onlyIfMissing?})` returns `{changed, selection?}` on DSH 0.1.5 and persists the default through `agentDefaultModel.saveSelection()`.
|
|
36
|
-
|
|
37
|
-
Sign-in, sidebar and organization settings share one account snapshot. Credential Providers should emit the official `credentials/reference-updated` event after set/unset. The client listens to that forwarded Remote event and `connection/reset`; it does not depend on a custom account event that the official Remote transport does not forward.
|
|
38
|
-
|
|
39
|
-
Explicit sign-in with a connected key, or confirmed key provisioning, selects the first resolvable enterprise model. A default is saved even when no session exists. For a current main session, the client also uses the official `modelDirectories.directoryFor(sessionID).select()` API; addressed subagents are left alone. Load the official `agentDefaultModel` and writable `settings` services. Older hosts without this capability show a message asking the user to choose from the model menu.
|
|
40
|
-
|
|
41
|
-
Initial upgrade recovery uses `onlyIfMissing:true`: it preserves an existing resolvable default and repairs only an absent or unavailable one. A valid personal selection in the current session is also preserved. Credential events, connection checks and subsequent status refreshes never select a model. Personal credentials and unrelated settings remain unchanged.
|
|
42
|
-
|
|
43
|
-
For desktop acceptance run `node scripts/serve-desktop-oidc-fixture.mjs --config <new test configuration file>`. It binds a random loopback port, serves synthetic HTTP PKCE/Key/models/quota and writes a public JSONC profile. The file must not exist; user configuration is never overwritten. Use isolated data directories for each shell and Ctrl+C to stop. No real accounts or model credits are used.
|
|
44
|
-
|
|
45
|
-
The independent random login handle is not OAuth state. Results never carry an authorization URL, code, nonce, verifier or token. The client polls once per second, displays browser completion instructions and a cancel button, and cancels on unmount. Sign-in expires within ten minutes. Closing a system browser cannot reliably be detected across platforms; the app cancel action and expiry bound the listener lifetime.
|
|
46
|
-
|
|
47
|
-
An empty Profile list is valid: no listener or organization login is needed. Identity-only profiles need no resource endpoints. Logout preserves personal keys. A resource outage after successful identity verification keeps the identity connected so resource access can be retried.
|
|
48
|
-
|
|
49
|
-
Run `node --test test/desktop.test.js test/desktop-host.test.js`. To test a frozen installation, set `DSH_OIDC_PACKAGE_ROOT` to its package directory and `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`. The latter test uses the installed package's actual Host dependencies without WebServer, optional browser-service lifecycle and HTTP PKCE. All credentials and identities are synthetic. Shell vault, window and system-browser integration still require product acceptance.
|
|
50
|
-
|
|
51
|
-
The `.20260910.6` public avatar menu provides account refresh and sign-out; quota UI requires an institution extension. A portal supports narrow sidebars; arrows, Home/End, Escape and outside click/focus are supported. Logout clears this profile's local identity, managed key and cached model metadata, serializes vault writes and rejects late writes. Personal keys remain untouched.
|
|
52
|
-
|
|
53
|
-
The temporary HTTP callback page reads `brand.productName/organizationName/logoURL/mark/primaryColor` from this attempt's Profile and chooses Chinese or English from Accept-Language. It has no external fonts, scripts or raw error reflection and directs the user back to the app. Ordinary Web validation still redirects into its local app; model keys never enter the browser.
|
|
54
|
-
|
|
1
|
+
# Desktop hosts without a persistent Web server
|
|
2
|
+
|
|
3
|
+
[简体中文](desktop-host.md)
|
|
4
|
+
|
|
5
|
+
`backend: desktop` uses a temporary loopback callback for desktop sign-in. OIDC validation, host credentials, Key Binding, model discovery and `authorizedFetch()` reuse the Web implementation; existing `web` and legacy native bridge modes remain supported.
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
- id: enterprise-oidc
|
|
9
|
+
name: '@eduwork/dsh-oidc'
|
|
10
|
+
config:
|
|
11
|
+
backend: desktop
|
|
12
|
+
allowEmptyProfiles: true
|
|
13
|
+
profilePathEnv: EDUWORK_OIDC_PROFILE
|
|
14
|
+
desktop:
|
|
15
|
+
callbackPort: 0
|
|
16
|
+
flowTimeoutMs: 600000
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The host supplies a Cordis `desktopServices` service with `openExternal(url: string): Promise<void>`. OIDC builds the authorization URL from reviewed Profile discovery; the renderer cannot submit an arbitrary URL. The shell opens the system browser, rejects non-HTTP(S) and userinfo URLs, and never logs authorization query parameters. The plugin does not execute shell commands or import Electron/Wails. The service can arrive later; removing it cancels pending sign-ins.
|
|
20
|
+
|
|
21
|
+
When the distribution provides `configFile: {path, examplesPath}`, organization settings stay read-only and are loaded again on restart. The optional Host method `openConfiguration(target: 'config' | 'examples'): Promise<void>` enables configuration-file and example-folder buttons. The RPC accepts these two fixed targets only; the host resolves its own paths, and the renderer cannot send a path or command. `configuration().configFile.canOpen` reports availability. Web hosts without this capability show the configuration-file location instead. Personal models and configured organization sign-in remain available.
|
|
22
|
+
|
|
23
|
+
Resource binding accepts the original `worker.user-center.v1`, the transitional `worker-user-center/v1`, and `eduwork-resources/v1`. Unknown versions and mismatched Provider IDs are rejected before creating a model credential. Completed identity sign-in is retained, with an error identifying the separate resource/configuration problem.
|
|
24
|
+
|
|
25
|
+
The host must implement `credentials.resolve/set/unset`, backed by its operating-system vault. The plugin has no plaintext credential file or fallback on storage failure. OAuth tokens remain Host-only. Personal API keys remain independent of the organization's managed credential. The public `oidcAccounts.authorizedFetch()` capability remains Host-only.
|
|
26
|
+
|
|
27
|
+
Only an explicit sign-in starts an IPv4 `127.0.0.1` listener. The callback is `http://127.0.0.1:<port>/oauth/callback`, using a random port by default. Register a public PKCE client supporting dynamic loopback ports with the IdP. For providers requiring an exact registered URI, a trusted `callbackPort` can pin the port; a conflict fails explicitly instead of switching to an unregistered port. Other bind addresses are not configurable. Cancellation, expiry, success, a valid failed callback, service disposal and host shutdown close the listener. Invalid Host, Origin, state, method or path cannot consume the legitimate attempt.
|
|
28
|
+
|
|
29
|
+
Shared Host/Client RPC additions:
|
|
30
|
+
|
|
31
|
+
- `begin(profileID)` returns `{mode:'external', loginID, expiresAt}` for desktop. Existing Web `redirect` and legacy `completed` variants remain supported.
|
|
32
|
+
- `loginStatus(loginID)` returns `{loginID, profileID, state, expiresAt, status?, errorCode?}`. State is pending/completed/cancelled/expired/failed.
|
|
33
|
+
- `cancelLogin(loginID)` returns the same safe projection and waits for an in-flight credential write to roll back.
|
|
34
|
+
- `openConfiguration(target)` returns `{opened:true}` in file-managed mode; the only targets are `config` and `examples`. System-opening failures produce a concise message.
|
|
35
|
+
- `selectEnterpriseModel(profileID, {onlyIfMissing?})` returns `{changed, selection?}` on DSH 0.1.5 and persists the default through `agentDefaultModel.saveSelection()`.
|
|
36
|
+
|
|
37
|
+
Sign-in, sidebar and organization settings share one account snapshot. Credential Providers should emit the official `credentials/reference-updated` event after set/unset. The client listens to that forwarded Remote event and `connection/reset`; it does not depend on a custom account event that the official Remote transport does not forward.
|
|
38
|
+
|
|
39
|
+
Explicit sign-in with a connected key, or confirmed key provisioning, selects the first resolvable enterprise model. A default is saved even when no session exists. For a current main session, the client also uses the official `modelDirectories.directoryFor(sessionID).select()` API; addressed subagents are left alone. Load the official `agentDefaultModel` and writable `settings` services. Older hosts without this capability show a message asking the user to choose from the model menu.
|
|
40
|
+
|
|
41
|
+
Initial upgrade recovery uses `onlyIfMissing:true`: it preserves an existing resolvable default and repairs only an absent or unavailable one. A valid personal selection in the current session is also preserved. Credential events, connection checks and subsequent status refreshes never select a model. Personal credentials and unrelated settings remain unchanged.
|
|
42
|
+
|
|
43
|
+
For desktop acceptance run `node scripts/serve-desktop-oidc-fixture.mjs --config <new test configuration file>`. It binds a random loopback port, serves synthetic HTTP PKCE/Key/models/quota and writes a public JSONC profile. The file must not exist; user configuration is never overwritten. Use isolated data directories for each shell and Ctrl+C to stop. No real accounts or model credits are used.
|
|
44
|
+
|
|
45
|
+
The independent random login handle is not OAuth state. Results never carry an authorization URL, code, nonce, verifier or token. The client polls once per second, displays browser completion instructions and a cancel button, and cancels on unmount. Sign-in expires within ten minutes. Closing a system browser cannot reliably be detected across platforms; the app cancel action and expiry bound the listener lifetime.
|
|
46
|
+
|
|
47
|
+
An empty Profile list is valid: no listener or organization login is needed. Identity-only profiles need no resource endpoints. Logout preserves personal keys. A resource outage after successful identity verification keeps the identity connected so resource access can be retried.
|
|
48
|
+
|
|
49
|
+
Run `node --test test/desktop.test.js test/desktop-host.test.js`. To test a frozen installation, set `DSH_OIDC_PACKAGE_ROOT` to its package directory and `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`. The latter test uses the installed package's actual Host dependencies without WebServer, optional browser-service lifecycle and HTTP PKCE. All credentials and identities are synthetic. Shell vault, window and system-browser integration still require product acceptance.
|
|
50
|
+
|
|
51
|
+
The `.20260910.6` public avatar menu provides account refresh and sign-out; quota UI requires an institution extension. A portal supports narrow sidebars; arrows, Home/End, Escape and outside click/focus are supported. Logout clears this profile's local identity, managed key and cached model metadata, serializes vault writes and rejects late writes. Personal keys remain untouched.
|
|
52
|
+
|
|
53
|
+
The temporary HTTP callback page reads `brand.productName/organizationName/logoURL/mark/primaryColor` from this attempt's Profile and chooses Chinese or English from Accept-Language. It has no external fonts, scripts or raw error reflection and directs the user back to the app. Ordinary Web validation still redirects into its local app; model keys never enter the browser.
|
|
54
|
+
|
|
55
55
|
Run `npm run check` from an isolated dependency tree coherent with the exact target DSH. Do not relabel a bundle built using old root dependencies. `npm run check:browser` additionally uses that Runtime's `playwright-core` and locally installed headless Edge (or Chrome through `DSH_OIDC_BROWSER_CHANNEL`) to load the compiled client, verify menu/shared state/logout and capture branded callback pages. It does not replace native vault/system-browser acceptance.
|
|
56
56
|
|
|
57
|
-
## macOS
|
|
57
|
+
## macOS integration requirements
|
|
58
58
|
|
|
59
59
|
The OIDC npm package is platform-independent JavaScript. It bundles no Electron, Wails, Keychain or Windows credential binary; macOS consumes the same exact version and integrity. The plugin has no platform branch: the Host interfaces above own shell differences. Windows validation does not establish macOS readiness.
|
|
60
60
|
|
package/docs/desktop-host.md
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
# 无常驻 Web 服务的桌面宿主
|
|
2
|
-
|
|
3
|
-
[English](desktop-host.en.md)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```yaml
|
|
8
|
-
- id: enterprise-oidc
|
|
9
|
-
name: '@eduwork/dsh-oidc'
|
|
10
|
-
config:
|
|
11
|
-
backend: desktop
|
|
12
|
-
allowEmptyProfiles: true
|
|
13
|
-
profilePathEnv: EDUWORK_OIDC_PROFILE
|
|
14
|
-
desktop:
|
|
15
|
-
callbackPort: 0
|
|
16
|
-
flowTimeoutMs: 600000
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
宿主应注册 Cordis `desktopServices` 服务,提供 Host-only 方法:
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
openExternal(url: string): Promise<void>
|
|
23
|
-
// 可选:仅打开宿主预先确定的配置文件或示例目录。
|
|
24
|
-
openConfiguration(target: 'config' | 'examples'): Promise<void>
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
OIDC 从受信 Profile 对应的 Discovery 构造 HTTP(S) 授权 URL。此 URL 只交给 Host 服务;浏览器侧不能传入自选 URL。外壳负责用系统浏览器打开,拒绝非 HTTP(S)、userinfo URL,并且不得记录授权查询参数。插件不自行执行系统命令,不依赖 Electron/Wails 的 JavaScript 包。服务可以稍后加载;移除服务会取消尚未完成的登录。
|
|
28
|
-
|
|
29
|
-
发行方提供 `configFile: {path, examplesPath}` 时,企业服务保持只读,由用户编辑文件后重启应用。若宿主提供 `openConfiguration`,设置显示“打开配置文件”和“查看示例”;RPC 只接收 `config` / `examples`,由宿主解析固定路径,不允许 renderer 传路径或命令。`configuration().configFile.canOpen` 声明是否可直接打开;Web 或未提供该能力的宿主显示配置文件位置作为备用。个人 API Key 设置和已配置企业的身份登录继续可用。
|
|
30
|
-
|
|
31
|
-
资源绑定兼容既有 `worker.user-center.v1`、过渡写法 `worker-user-center/v1` 与 `eduwork-resources/v1`。未知版本或不匹配的 Provider ID 在创建模型凭据前拒绝,保留已完成的身份登录,并提示检查模型资源服务或企业配置;它们不是身份验证失败。
|
|
32
|
-
|
|
33
|
-
宿主必须提供 `credentials.resolve/set/unset`。本插件没有明文凭据文件或存储失败后的备用路径;桌面发行方负责接入操作系统保险库。模型调用仍使用独立运行 Key,OAuth token 不经 RPC 返回 renderer。`oidcAccounts.authorizedFetch()` 仍是 Host-only 公共授权请求入口。
|
|
34
|
-
|
|
35
|
-
只有用户点击登录时才监听 `127.0.0.1`。默认随机端口,回调为 `http://127.0.0.1:<port>/oauth/callback`;需在身份提供方注册支持动态 loopback 端口的公共 PKCE 客户端。若身份提供方只接受精确回调端口,可在受信配置固定 `callbackPort`(端口占用时明确失败,不改用未注册端口)。不支持配置其他监听地址。取消、失效、成功、合法回调失败、服务卸载和 Host 退出均清理监听。错误路径、Host、Origin、state 或 HTTP 方法不会消费合法的待登录状态。
|
|
36
|
-
|
|
37
|
-
RPC 扩展(共用 Host/Client Typert schema):
|
|
38
|
-
|
|
39
|
-
| 方法 | 返回 |
|
|
40
|
-
| --- | --- |
|
|
41
|
-
| `begin(profileID)` | 桌面返回 `{mode:'external', loginID, expiresAt}`;Web 仍返回 `redirect`,旧 native 仍可返回 `completed`。 |
|
|
42
|
-
| `loginStatus(loginID)` | `{loginID, profileID, state, expiresAt, status?, errorCode?}`。state 为 pending/completed/cancelled/expired/failed。 |
|
|
43
|
-
| `cancelLogin(loginID)` | 同上;等待正在写入的登录撤回,避免取消后重新出现凭据。 |
|
|
44
|
-
| `openConfiguration(target)` | 文件管理模式下返回 `{opened:true}`;目标仅为 `config` / `examples`。系统打开失败时返回简短提示。 |
|
|
45
|
-
| `selectEnterpriseModel(profileID, {onlyIfMissing?})` | DSH 0.1.5 上返回 `{changed, selection?}`,通过官方 `agentDefaultModel.saveSelection()` 保存企业默认模型。 |
|
|
46
|
-
|
|
47
|
-
客户端账号快照由登录页、侧栏和企业设置共享。宿主凭据 Provider 应在 set/unset 后按官方契约发出 `credentials/reference-updated`;客户端监听该标准 Remote 事件及 `connection/reset`,不依赖不会由官方 Remote 转发的自定义账号事件。
|
|
48
|
-
|
|
49
|
-
明确登录并连接 Key 或确认创建 Key 后,自动选择企业目录中第一个可解析模型。还没有会话时也会保存未来会话的默认值;存在主会话时通过官方 `modelDirectories.directoryFor(sessionID).select()` 同步当前选择,不改子代理。宿主应加载官方 `agentDefaultModel` 和可写 `settings` 服务。旧宿主缺少此能力时明确提示从模型菜单选择。
|
|
50
|
-
|
|
51
|
-
升级后的首次加载使用 `onlyIfMissing:true`:已有有效默认值则保留,缺失或已不能解析才修复;当前会话中可用的个人选择也保留。凭据事件、检查连接和后续状态刷新不会切模型,个人 Key 与其他设置不受影响。
|
|
52
|
-
|
|
53
|
-
双桌面联调可运行 `node scripts/serve-desktop-oidc-fixture.mjs --config <新的测试配置文件>`。脚本只绑定本机随机端口,生成合成身份、完整 HTTP PKCE/Key/模型/配额服务及公开 JSONC 配置;配置文件必须不存在,不覆盖用户配置。每套外壳使用独立测试数据目录;用 Ctrl+C 关闭服务。服务不接触真实账号,也不消耗模型额度。
|
|
54
|
-
|
|
55
|
-
`loginID` 是独立随机句柄,不是 OAuth state。响应不包含授权 URL、code、nonce、PKCE verifier 或 token。前端以一秒间隔轮询,显示在浏览器中完成登录与取消按钮;登录最长十分钟,页面卸载取消尚未完成的尝试。关闭外部浏览器无法被跨平台可靠检测,用户可在应用中取消,或等待短时监听过期。
|
|
56
|
-
|
|
57
|
-
空 Profile 是有效配置,不会监听端口,也不要求机构登录。纯身份 Profile 不要求资源端点;登出仅移除该机构的身份/托管 Key,个人 API Key 保留。身份登录成功后资源接口暂不可用时保留已登录身份,后续可以重试资源连接。
|
|
58
|
-
|
|
59
|
-
验证入口:`node --test test/desktop.test.js test/desktop-host.test.js`。后者可通过 `DSH_OIDC_PACKAGE_ROOT` 指向安装的冻结包目录,并设置 `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`,使用该安装目录的真实 DSH 依赖运行无 WebServer 的 Host、可选浏览器服务和 loopback PKCE 验证。所有凭据与用户均为测试合成值;产品主进程保险库、窗口和操作系统浏览器行为仍由发行方联合验收。
|
|
60
|
-
|
|
61
|
-
`.20260910.6` 的公共侧栏头像显示账户刷新和注销;配额内容由可选机构扩展提供。菜单通过 portal 支持收窄侧栏;支持方向键、Home/End、Escape、外部点击/失焦关闭。注销清理该机构本地身份、模型 Key、模型元数据缓存,序列化保险库写操作并拒绝旧请求写回;个人 Key 不受影响。
|
|
62
|
-
|
|
63
|
-
临时 HTTP 回调页读取本次 Profile 的 `brand.productName/organizationName/logoURL/mark/primaryColor`,按浏览器 Accept-Language 选择中英文。没有外部字体、脚本或原始错误回显,清楚提示返回应用。普通 Web 验证仍跳回本地应用;不会把生产模型 Key 交给浏览器。
|
|
64
|
-
|
|
1
|
+
# 无常驻 Web 服务的桌面宿主
|
|
2
|
+
|
|
3
|
+
[English](desktop-host.en.md)
|
|
4
|
+
|
|
5
|
+
`backend: desktop` 通过临时 loopback 回调接入桌面登录,复用 Web 后端的 OIDC 校验、Host credentials、Key Binding 和模型发现协议。既有 `web` 和 Go 桥 `native` 配置继续可用。
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
- id: enterprise-oidc
|
|
9
|
+
name: '@eduwork/dsh-oidc'
|
|
10
|
+
config:
|
|
11
|
+
backend: desktop
|
|
12
|
+
allowEmptyProfiles: true
|
|
13
|
+
profilePathEnv: EDUWORK_OIDC_PROFILE
|
|
14
|
+
desktop:
|
|
15
|
+
callbackPort: 0
|
|
16
|
+
flowTimeoutMs: 600000
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
宿主应注册 Cordis `desktopServices` 服务,提供 Host-only 方法:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
openExternal(url: string): Promise<void>
|
|
23
|
+
// 可选:仅打开宿主预先确定的配置文件或示例目录。
|
|
24
|
+
openConfiguration(target: 'config' | 'examples'): Promise<void>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
OIDC 从受信 Profile 对应的 Discovery 构造 HTTP(S) 授权 URL。此 URL 只交给 Host 服务;浏览器侧不能传入自选 URL。外壳负责用系统浏览器打开,拒绝非 HTTP(S)、userinfo URL,并且不得记录授权查询参数。插件不自行执行系统命令,不依赖 Electron/Wails 的 JavaScript 包。服务可以稍后加载;移除服务会取消尚未完成的登录。
|
|
28
|
+
|
|
29
|
+
发行方提供 `configFile: {path, examplesPath}` 时,企业服务保持只读,由用户编辑文件后重启应用。若宿主提供 `openConfiguration`,设置显示“打开配置文件”和“查看示例”;RPC 只接收 `config` / `examples`,由宿主解析固定路径,不允许 renderer 传路径或命令。`configuration().configFile.canOpen` 声明是否可直接打开;Web 或未提供该能力的宿主显示配置文件位置作为备用。个人 API Key 设置和已配置企业的身份登录继续可用。
|
|
30
|
+
|
|
31
|
+
资源绑定兼容既有 `worker.user-center.v1`、过渡写法 `worker-user-center/v1` 与 `eduwork-resources/v1`。未知版本或不匹配的 Provider ID 在创建模型凭据前拒绝,保留已完成的身份登录,并提示检查模型资源服务或企业配置;它们不是身份验证失败。
|
|
32
|
+
|
|
33
|
+
宿主必须提供 `credentials.resolve/set/unset`。本插件没有明文凭据文件或存储失败后的备用路径;桌面发行方负责接入操作系统保险库。模型调用仍使用独立运行 Key,OAuth token 不经 RPC 返回 renderer。`oidcAccounts.authorizedFetch()` 仍是 Host-only 公共授权请求入口。
|
|
34
|
+
|
|
35
|
+
只有用户点击登录时才监听 `127.0.0.1`。默认随机端口,回调为 `http://127.0.0.1:<port>/oauth/callback`;需在身份提供方注册支持动态 loopback 端口的公共 PKCE 客户端。若身份提供方只接受精确回调端口,可在受信配置固定 `callbackPort`(端口占用时明确失败,不改用未注册端口)。不支持配置其他监听地址。取消、失效、成功、合法回调失败、服务卸载和 Host 退出均清理监听。错误路径、Host、Origin、state 或 HTTP 方法不会消费合法的待登录状态。
|
|
36
|
+
|
|
37
|
+
RPC 扩展(共用 Host/Client Typert schema):
|
|
38
|
+
|
|
39
|
+
| 方法 | 返回 |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `begin(profileID)` | 桌面返回 `{mode:'external', loginID, expiresAt}`;Web 仍返回 `redirect`,旧 native 仍可返回 `completed`。 |
|
|
42
|
+
| `loginStatus(loginID)` | `{loginID, profileID, state, expiresAt, status?, errorCode?}`。state 为 pending/completed/cancelled/expired/failed。 |
|
|
43
|
+
| `cancelLogin(loginID)` | 同上;等待正在写入的登录撤回,避免取消后重新出现凭据。 |
|
|
44
|
+
| `openConfiguration(target)` | 文件管理模式下返回 `{opened:true}`;目标仅为 `config` / `examples`。系统打开失败时返回简短提示。 |
|
|
45
|
+
| `selectEnterpriseModel(profileID, {onlyIfMissing?})` | DSH 0.1.5 上返回 `{changed, selection?}`,通过官方 `agentDefaultModel.saveSelection()` 保存企业默认模型。 |
|
|
46
|
+
|
|
47
|
+
客户端账号快照由登录页、侧栏和企业设置共享。宿主凭据 Provider 应在 set/unset 后按官方契约发出 `credentials/reference-updated`;客户端监听该标准 Remote 事件及 `connection/reset`,不依赖不会由官方 Remote 转发的自定义账号事件。
|
|
48
|
+
|
|
49
|
+
明确登录并连接 Key 或确认创建 Key 后,自动选择企业目录中第一个可解析模型。还没有会话时也会保存未来会话的默认值;存在主会话时通过官方 `modelDirectories.directoryFor(sessionID).select()` 同步当前选择,不改子代理。宿主应加载官方 `agentDefaultModel` 和可写 `settings` 服务。旧宿主缺少此能力时明确提示从模型菜单选择。
|
|
50
|
+
|
|
51
|
+
升级后的首次加载使用 `onlyIfMissing:true`:已有有效默认值则保留,缺失或已不能解析才修复;当前会话中可用的个人选择也保留。凭据事件、检查连接和后续状态刷新不会切模型,个人 Key 与其他设置不受影响。
|
|
52
|
+
|
|
53
|
+
双桌面联调可运行 `node scripts/serve-desktop-oidc-fixture.mjs --config <新的测试配置文件>`。脚本只绑定本机随机端口,生成合成身份、完整 HTTP PKCE/Key/模型/配额服务及公开 JSONC 配置;配置文件必须不存在,不覆盖用户配置。每套外壳使用独立测试数据目录;用 Ctrl+C 关闭服务。服务不接触真实账号,也不消耗模型额度。
|
|
54
|
+
|
|
55
|
+
`loginID` 是独立随机句柄,不是 OAuth state。响应不包含授权 URL、code、nonce、PKCE verifier 或 token。前端以一秒间隔轮询,显示在浏览器中完成登录与取消按钮;登录最长十分钟,页面卸载取消尚未完成的尝试。关闭外部浏览器无法被跨平台可靠检测,用户可在应用中取消,或等待短时监听过期。
|
|
56
|
+
|
|
57
|
+
空 Profile 是有效配置,不会监听端口,也不要求机构登录。纯身份 Profile 不要求资源端点;登出仅移除该机构的身份/托管 Key,个人 API Key 保留。身份登录成功后资源接口暂不可用时保留已登录身份,后续可以重试资源连接。
|
|
58
|
+
|
|
59
|
+
验证入口:`node --test test/desktop.test.js test/desktop-host.test.js`。后者可通过 `DSH_OIDC_PACKAGE_ROOT` 指向安装的冻结包目录,并设置 `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`,使用该安装目录的真实 DSH 依赖运行无 WebServer 的 Host、可选浏览器服务和 loopback PKCE 验证。所有凭据与用户均为测试合成值;产品主进程保险库、窗口和操作系统浏览器行为仍由发行方联合验收。
|
|
60
|
+
|
|
61
|
+
`.20260910.6` 的公共侧栏头像显示账户刷新和注销;配额内容由可选机构扩展提供。菜单通过 portal 支持收窄侧栏;支持方向键、Home/End、Escape、外部点击/失焦关闭。注销清理该机构本地身份、模型 Key、模型元数据缓存,序列化保险库写操作并拒绝旧请求写回;个人 Key 不受影响。
|
|
62
|
+
|
|
63
|
+
临时 HTTP 回调页读取本次 Profile 的 `brand.productName/organizationName/logoURL/mark/primaryColor`,按浏览器 Accept-Language 选择中英文。没有外部字体、脚本或原始错误回显,清楚提示返回应用。普通 Web 验证仍跳回本地应用;不会把生产模型 Key 交给浏览器。
|
|
64
|
+
|
|
65
65
|
在与目标 DSH 完全一致的隔离依赖树运行 `npm run check`,不要从旧版本根依赖构建后标为新基线。可再运行 `npm run check:browser`:使用该 Runtime 的 `playwright-core` 和本机 Edge 无头浏览器(可用 `DSH_OIDC_BROWSER_CHANNEL` 指定 Chrome),直接加载编译客户端,验证菜单/多个组件共享状态/注销,并生成品牌回调截图。本检查不替代主进程保险库与真实操作系统浏览器联验。
|
|
66
66
|
|
|
67
67
|
## macOS 接手验收
|
package/docs/development.en.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](development.md) | **English**
|
|
4
4
|
|
|
5
|
-
The plugin version is `0.2.
|
|
5
|
+
The plugin version is `0.2.3`. Its development baseline is DSH `0.1.5-rc.1`, Cordis `4.0.2`, and pi-ai `0.85.1`. Product versions do not determine plugin versions; consult the registry for npm publication status. Source is maintained in EduWork; migration does not overwrite published npm packages.
|
|
6
6
|
|
|
7
7
|
## Verify a clean checkout
|
|
8
8
|
|
|
9
|
-
Use Node.js 22 or 24 in
|
|
9
|
+
Use Node.js 22 or 24 in `EduWork/packages/dsh-oidc`:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
12
|
npm ci
|
|
@@ -35,8 +35,10 @@ The complete check covers TypeScript, the dependency lock and official contracts
|
|
|
35
35
|
|
|
36
36
|
`scripts/build-host.mjs` copies native Host ESM to `lib`; tsdown bundles the Client. Do not edit `lib` by hand. New wire fields require corresponding implementation, Schema/OpenAPI, bilingual documentation and contract tests. Avoid mechanical tests for simple presentation/documentation changes.
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Extensions and publication
|
|
39
39
|
|
|
40
40
|
The public package owns identity, managed keys, model discovery/inference and their account UI. Quota, heartbeat, campus search and speech business services belong in institution/product plugins. [Account extensions](account-extensions.en.md) are Host transport and slot contracts, not hidden institution-feature switches. Examples contain placeholder domains, public client IDs and no secrets.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
Module checks and publication use the [shared EduWork workflow](https://github.com/ecnu/EduWork/blob/main/docs/PACKAGES_EN.md). Validate deployment-specific sign-in separately; published npm versions are immutable.
|
|
43
|
+
|
|
44
|
+
Reasoning-field compatibility and its regression checks are documented in [Reasoning replay compatibility](reasoning-replay.en.md). The guide distinguishes a source fix from the installed npm package.
|
package/docs/development.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**简体中文** | [English](development.en.md)
|
|
4
4
|
|
|
5
|
-
当前插件版本为 `0.2.
|
|
5
|
+
当前插件版本为 `0.2.3`,开发基线是 DSH `0.1.5-rc.1`、Cordis `4.0.2`、pi-ai `0.85.1`。产品版本不决定插件版本;npm 发布状态以 registry 为准。源码位于 EduWork 的 `packages/dsh-oidc`。
|
|
6
6
|
|
|
7
7
|
## 从干净 checkout 验证
|
|
8
8
|
|
|
9
|
-
使用 Node.js 22 或 24
|
|
9
|
+
使用 Node.js 22 或 24,在 `EduWork/packages/dsh-oidc` 执行:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
12
|
npm ci
|
|
@@ -35,8 +35,10 @@ npm run check
|
|
|
35
35
|
|
|
36
36
|
Host ESM 由 `scripts/build-host.mjs` 复制至 `lib`,Client 由 tsdown 打包;不要手改 `lib`。新增网络字段时应同步实现、Schema/OpenAPI、中英文规范与合约测试。UI/文档调整不需要添加机械重复实现的测试。
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
思考内容的字段兼容与回归入口见[思考内容回传兼容](reasoning-replay.md)。该说明区分源码修复与已安装插件包,避免沿用旧 npm 锁时误判为修复已交付。
|
|
39
|
+
|
|
40
|
+
## 扩展与发布
|
|
39
41
|
|
|
40
42
|
公共包只拥有身份、托管 Key、模型目录/调用及对应账号 UI。配额、心跳、校内检索和语音业务由机构/产品插件负责;[账户扩展](account-extensions.md)是 Host 运输与插槽边界,不是暗中启用机构功能的开关。所有示例均使用占位域名、Public Client ID 与无秘密配置。
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
模块通过 EduWork 的统一工作流检查和发布,参见[包维护说明](https://github.com/ecnu/EduWork/blob/main/docs/PACKAGES.md)。依赖锁、合成测试与实际部署登录分别验证;发布包使用新版本,不覆盖已有 npm 版本。
|
|
@@ -71,8 +71,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
|
|
|
71
71
|
For auditing, development, or validating unpublished changes, install a reviewed local checkout instead:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
git clone https://github.com/
|
|
75
|
-
cd dsh-oidc
|
|
74
|
+
git clone https://github.com/ecnu/EduWork.git
|
|
75
|
+
cd EduWork/packages/dsh-oidc
|
|
76
76
|
npm ci
|
|
77
77
|
npm run check
|
|
78
78
|
dsh plugin --profile web add .
|
package/docs/dsh-integration.md
CHANGED
|
@@ -71,8 +71,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
|
|
|
71
71
|
需要审计、开发或验证尚未发布的改动时,可以安装经过审查的本地 checkout:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
git clone https://github.com/
|
|
75
|
-
cd dsh-oidc
|
|
74
|
+
git clone https://github.com/ecnu/EduWork.git
|
|
75
|
+
cd EduWork/packages/dsh-oidc
|
|
76
76
|
npm ci
|
|
77
77
|
npm run check
|
|
78
78
|
dsh plugin --profile web add .
|
|
@@ -65,8 +65,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
|
|
|
65
65
|
For auditing, development, or testing unpublished changes, install from a local checkout instead:
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
git clone https://github.com/
|
|
69
|
-
cd dsh-oidc
|
|
68
|
+
git clone https://github.com/ecnu/EduWork.git
|
|
69
|
+
cd EduWork/packages/dsh-oidc
|
|
70
70
|
npm ci
|
|
71
71
|
npm run check
|
|
72
72
|
dsh plugin --profile web add .
|
|
@@ -75,7 +75,7 @@ dsh plugin --profile web add .
|
|
|
75
75
|
From the parent directory, the equivalent explicit relative-path command is:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
-
dsh plugin --profile web add ./dsh-oidc
|
|
78
|
+
dsh plugin --profile web add ./EduWork/packages/dsh-oidc
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
DSH links the checkout into `$DSH_HOME/profiles/web`; it does not scan or copy the invoking directory. Keep the checkout in place and pin a reviewed commit for source-based deployments. Production and team Profiles should use an exact npm version and must not mix another DSH prerelease line.
|
|
@@ -89,7 +89,7 @@ dsh --profile web --host 127.0.0.1 --port 3080 --no-open
|
|
|
89
89
|
|
|
90
90
|
The plugin constructs `http://127.0.0.1:<port>/oauth/callback` from the DSH WebServer port. It does not accept `publicBaseURL` and does not infer an address from proxy headers. If the startup port changes, update the OIDC Public Client registration to the same port.
|
|
91
91
|
|
|
92
|
-
The package's `cordis.patch.yml` mounts one `enterprise-oidc` plugin instance. It does not traverse the current workspace or replace DSH Web, sessions, Workspace, LLM services, the Credential Provider, or other official capabilities. The invoking directory matters only when resolving a relative package path such as `.` or `./dsh-oidc`.
|
|
92
|
+
The package's `cordis.patch.yml` mounts one `enterprise-oidc` plugin instance. It does not traverse the current workspace or replace DSH Web, sessions, Workspace, LLM services, the Credential Provider, or other official capabilities. The invoking directory matters only when resolving a relative package path such as `.` or `./EduWork/packages/dsh-oidc`.
|
|
93
93
|
|
|
94
94
|
## 6. Advanced product composition
|
|
95
95
|
|
package/docs/getting-started.md
CHANGED
|
@@ -130,8 +130,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
|
|
|
130
130
|
需要审计、开发或测试尚未发布的改动时,再从本地 checkout 安装:
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
-
git clone https://github.com/
|
|
134
|
-
cd dsh-oidc
|
|
133
|
+
git clone https://github.com/ecnu/EduWork.git
|
|
134
|
+
cd EduWork/packages/dsh-oidc
|
|
135
135
|
npm ci
|
|
136
136
|
npm run check
|
|
137
137
|
dsh plugin --profile web add .
|
|
@@ -140,7 +140,7 @@ dsh plugin --profile web add .
|
|
|
140
140
|
也可以在项目父目录中显式传入相对路径:
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
|
-
dsh plugin --profile web add ./dsh-oidc
|
|
143
|
+
dsh plugin --profile web add ./EduWork/packages/dsh-oidc
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
DSH 会把本地 checkout 链接到 `$DSH_HOME/profiles/web`,不会扫描或复制当前目录;安装完成后不要移动或删除 checkout。源码部署应固定经过审核的 commit。生产或团队 Profile 应使用精确 npm 版本,不要混装其他 DSH 预发布线。
|
|
@@ -161,7 +161,7 @@ dsh --profile web --host 127.0.0.1 --port 3080 --no-open
|
|
|
161
161
|
|
|
162
162
|
插件会从 DSH WebServer 的端口构造 `http://127.0.0.1:<port>/oauth/callback`,不接受 `publicBaseURL`,也不会从代理 header 推断地址。若启动参数改变端口,必须同步修改 OIDC Public Client 的登记值。
|
|
163
163
|
|
|
164
|
-
安装命令会把 `dsh-oidc` 作为 Bundle 加到 Profile,并由包内 `cordis.patch.yml` 挂载插件。它不会遍历当前工作目录,也不会替换 DSH 的 Web、会话、Workspace、LLM、Credential Provider 或其他官方能力;当前目录只用于解析 `.`、`./dsh-oidc` 等相对安装路径。
|
|
164
|
+
安装命令会把 `dsh-oidc` 作为 Bundle 加到 Profile,并由包内 `cordis.patch.yml` 挂载插件。它不会遍历当前工作目录,也不会替换 DSH 的 Web、会话、Workspace、LLM、Credential Provider 或其他官方能力;当前目录只用于解析 `.`、`./EduWork/packages/dsh-oidc` 等相对安装路径。
|
|
165
165
|
|
|
166
166
|
## 6. 高级组合:自定义 Bundle 或桌面宿主
|
|
167
167
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Open Identity and Model Integration Initiative
|
|
2
|
+
|
|
3
|
+
[简体中文](open-integration.md) | **English**
|
|
4
|
+
|
|
5
|
+
**Make institutional accounts and model services reusable across AI clients.**
|
|
6
|
+
|
|
7
|
+
Schools and businesses already have identity systems and are building model services. Users want to sign in with a familiar account and start working in their chosen AI client. Our aim is for one server implementation of an open contract to serve multiple compatible clients, and for a client to connect another organization primarily through configuration.
|
|
8
|
+
|
|
9
|
+
EduWork puts this into practice through `dsh-oidc`. We invite identity platforms, model gateways, client developers, and plugin authors to improve the contract together.
|
|
10
|
+
|
|
11
|
+
> Status: this is a community initiative. The accompanying RFC EW-IDENTITY-1 documents implemented interfaces, with future protocol changes open for discussion. It is not a standard published by DSH, the OpenID Foundation, or the IETF, and does not imply that other clients are already compatible.
|
|
12
|
+
|
|
13
|
+
## The experience we want to enable
|
|
14
|
+
|
|
15
|
+
A user selects an organization, signs in through the system browser, grants authorization, and confirms credential creation when required. The client then loads the organization's models so the user can start a task. Personal API keys and other models remain available.
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
A[Choose an organization] --> B[Browser sign-in and authorization]
|
|
20
|
+
B --> C[Confirm when needed and obtain model credentials]
|
|
21
|
+
C --> D[Load available models]
|
|
22
|
+
D --> E[Start working]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This is the intended managed-model experience. An organization that only needs identity can start with OIDC alone and let users configure their models, without first building a model-credential service.
|
|
26
|
+
|
|
27
|
+
| Participant | Work we hope to reduce together |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Users | Repeatedly copying keys, finding endpoint addresses, and entering model parameters. |
|
|
30
|
+
| Schools and businesses | Reimplementing identity and model integration for each client. |
|
|
31
|
+
| Client developers | Maintaining a separate sign-in, credential, and model adapter for every organization. |
|
|
32
|
+
| Plugin authors | Implementing another sign-in flow or storing another copy of a user's credentials in a tool plugin. |
|
|
33
|
+
|
|
34
|
+
## What we propose to agree on
|
|
35
|
+
|
|
36
|
+
1. **Use existing identity standards.** Use OpenID Connect with PKCE for local public clients, and derive identity from verified OIDC results. Resource services authorize model access without replacing the identity source.
|
|
37
|
+
2. **Define an open model-access contract.** Specify requests and responses for credential state, provisioning, resolution, renewal, and model catalogs. OIDC handles identity; model credentials and catalogs require separate resource APIs. Successful sign-in alone does not establish model integration.
|
|
38
|
+
3. **Keep institution configuration as data.** Declare branding, trusted endpoints, and model policy in local configuration. Configuration cannot deliver scripts, install tools, or replace executable modules. Add behavior through explicitly installed plugins.
|
|
39
|
+
4. **Preserve user choice and institution boundaries.** Institutional and personal models can coexist. Public integration does not require a particular school, desktop shell, quota system, or activity heartbeat. Institution-specific capabilities remain optional extensions.
|
|
40
|
+
5. **Make compatibility verifiable.** Document fields, errors, versions, and migrations in specifications, OpenAPI, examples, and tests. Follow the [compatibility policy](compatibility.en.md) when changing the protocol, so clients do not have to guess.
|
|
41
|
+
|
|
42
|
+
## Build on the existing implementation
|
|
43
|
+
|
|
44
|
+
The protocol and client implementation are available for server integration and client interoperability work.
|
|
45
|
+
|
|
46
|
+
| Part | Current scope | Start here |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| Identity | OIDC Discovery, Authorization Code + PKCE, Token, JWKS, and UserInfo, including identity-only mode. | [OIDC interoperability requirements](oidc-interoperability.en.md) |
|
|
49
|
+
| Managed credentials | Bootstrap and the provision, resolve, and renew lifecycle endpoints. | [Complete server interfaces and requests](server-integration-contract.en.md) · [Key Binding OpenAPI](../protocol/openapi.yaml) |
|
|
50
|
+
| Model catalog | A static catalog in trusted configuration, or explicitly enabled `/models` discovery. | [Client modes and model discovery](public-resource-protocol.en.md) |
|
|
51
|
+
| DSH client | The independent npm package `@eduwork/dsh-oidc`, used by EduWork and available to other compatible DSH hosts. | [Module guide](../README_EN.md) · [Desktop host integration](desktop-host.en.md) |
|
|
52
|
+
| Institution extensions | Configuration, skills, and plugins that reuse public integration capabilities. | [EduWork@ECNU example](https://github.com/ecnu/EduWork-ECNU) |
|
|
53
|
+
|
|
54
|
+
A server must implement the interfaces required by its selected mode. This repository does not include a deployable OIDC or Key Binding server. Current clients are single-user local applications; local Web is for validation and does not provide shared multi-user sign-in sessions.
|
|
55
|
+
|
|
56
|
+
Remote organization-profile discovery and remote model-key revocation remain optional proposals in the RFC. Quota and activity heartbeats remain institution extensions. Proposals or capability declarations do not activate unimplemented features. The model gateway uses the documented OpenAI Chat Completions compatible contract; other model and media APIs require separate validation against their own contracts.
|
|
57
|
+
|
|
58
|
+
Other clients can implement these network interfaces without adopting EduWork's UI or desktop shell. Interoperability depends on the declared protocol versions and actual integration results.
|
|
59
|
+
|
|
60
|
+
## How to participate
|
|
61
|
+
|
|
62
|
+
- **Identity and model platform developers:** start with the [server specification](server-integration-contract.en.md) and [integration guide](getting-started.en.md). Contribute sanitized examples and explain constraints that are difficult for existing platforms to meet.
|
|
63
|
+
- **Client developers:** integrate `dsh-oidc` or implement the network protocol independently. Verify sign-in, credential lifecycle, model catalogs, and error handling; share interoperability results with explicit version information.
|
|
64
|
+
- **Plugin authors:** connect institution capabilities through the [account extension interfaces](account-extensions.en.md), reusing the host's authorized transport and account state where possible.
|
|
65
|
+
- **Specification contributors:** describe use cases and compatibility issues in [EduWork Issues](https://github.com/ecnu/EduWork/issues). Discuss interface changes first, then update the specification, machine-readable contract, examples, and necessary tests following the [contribution guide](../CONTRIBUTING.en.md).
|
|
66
|
+
|
|
67
|
+
Implementations from different organizations and clients are welcome. Use placeholder configuration and synthetic data in examples; report authentication vulnerabilities and credential issues through the [security reporting process](../SECURITY.en.md).
|
|
68
|
+
|
|
69
|
+
## Relationship to the DSH plugin ecosystem
|
|
70
|
+
|
|
71
|
+
[DSH Desktop's plugin ecosystem initiative](https://github.com/anywhere-labs/dsh-desktop/blob/master/docs/plugin-ecosystem.en.md) promotes plugin composition and collaboration. We share that direction and aim to contribute implementable, discussable public interfaces for identity and model access. The initiatives are independent; this reference does not imply that DSH Desktop has adopted this protocol.
|
|
72
|
+
|
|
73
|
+
The next result we hope to establish together is that one institutional service can connect to more clients through a clear protocol and a small amount of configuration, and continue working across upgrades.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# 开放身份与模型接入倡议
|
|
2
|
+
|
|
3
|
+
**简体中文** | [English](open-integration.en.md)
|
|
4
|
+
|
|
5
|
+
**让机构的账号与模型服务,被更多 AI 客户端复用。**
|
|
6
|
+
|
|
7
|
+
学校和企业已经有自己的账号体系,也在建设模型服务。用户希望用熟悉的账号登录,在自己选择的 AI 客户端里开始工作。我们希望服务端实现一套公开接口后,能够服务多个遵循同一约定的客户端;客户端新增一个机构时,也能主要通过配置完成接入。
|
|
8
|
+
|
|
9
|
+
EduWork 从 `dsh-oidc` 开始实践这件事,并邀请身份平台、模型网关、客户端和插件作者一起完善这套约定。
|
|
10
|
+
|
|
11
|
+
> 状态:这是一份面向社区的倡议。配套的 RFC EW-IDENTITY-1 描述已有实现的接口,后续协议演进开放讨论;它不是 DSH 官方、OpenID Foundation 或 IETF 发布的标准,也不代表其他客户端已经兼容。
|
|
12
|
+
|
|
13
|
+
## 用户应当得到什么
|
|
14
|
+
|
|
15
|
+
用户选择机构,在系统浏览器完成登录,授权并在必要时确认创建模型凭据。客户端随后加载机构提供的模型,用户即可开始任务。个人 API Key 和其他模型仍然可以使用。
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
A[选择机构] --> B[浏览器登录与授权]
|
|
20
|
+
B --> C[按需确认并领取模型凭据]
|
|
21
|
+
C --> D[加载可用模型]
|
|
22
|
+
D --> E[开始工作]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
这是托管模型模式的目标体验。只需登录身份的机构可以从纯 OIDC 模式开始,用户自行配置模型;不必先建设模型凭据服务。
|
|
26
|
+
|
|
27
|
+
| 参与者 | 我们希望共同减少的工作 |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| 使用者 | 反复复制 Key、查找接口地址和填写模型参数。 |
|
|
30
|
+
| 学校与企业 | 为每个客户端重复编写身份和模型接入逻辑。 |
|
|
31
|
+
| 客户端作者 | 为每个机构维护一套专有登录、凭据和模型适配。 |
|
|
32
|
+
| 插件作者 | 在工具插件里再次实现登录或另存一份用户凭据。 |
|
|
33
|
+
|
|
34
|
+
## 共同约定什么
|
|
35
|
+
|
|
36
|
+
1. **身份遵循已有标准。** 使用 OpenID Connect 与适合本机公共客户端的 PKCE 登录流程,用户身份以经过验证的 OIDC 结果为准。资源服务负责模型授权,不替换身份来源。
|
|
37
|
+
2. **模型接入有公开契约。** 明确凭据状态、申请、读取、轮换和模型目录的请求与响应。OIDC 负责身份;模型凭据与目录使用另外定义的资源接口,不能把完成登录等同于完成模型接入。
|
|
38
|
+
3. **机构配置保持为数据。** 品牌、受信任端点和模型策略由本地配置声明;配置不能下发脚本、安装工具或替换执行模块。需要新增行为时,通过显式安装的插件接入。
|
|
39
|
+
4. **保留用户选择和机构边界。** 机构模型与个人模型可以共存。公共接入不要求某所学校、某个桌面壳、配额系统或活跃心跳;机构专属能力按需扩展。
|
|
40
|
+
5. **兼容性可以核验。** 字段、错误、版本和迁移方式写入规范、OpenAPI、示例与测试。协议变化遵循[兼容性策略](compatibility.md),不让客户端靠猜测完成接入。
|
|
41
|
+
|
|
42
|
+
## 从现有实现开始共建
|
|
43
|
+
|
|
44
|
+
协议和客户端实现随源码提供,可以据此开展服务端接入及客户端互操作验证。
|
|
45
|
+
|
|
46
|
+
| 部分 | 当前范围 | 阅读入口 |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| 身份接入 | OIDC Discovery、Authorization Code + PKCE、Token、JWKS、UserInfo;支持纯身份模式。 | [OIDC 兼容要求](oidc-interoperability.md) |
|
|
49
|
+
| 托管凭据 | Bootstrap,以及 provision、resolve、renew 生命周期接口。 | [服务端完整接口与请求示例](server-integration-contract.md) · [Key Binding OpenAPI](../protocol/openapi.yaml) |
|
|
50
|
+
| 模型目录 | 可信配置中的静态目录,或显式启用的 `/models` 自动发现。 | [客户端模式与模型发现](public-resource-protocol.md) |
|
|
51
|
+
| DSH 客户端 | 独立 npm 包 `@eduwork/dsh-oidc`,由 EduWork 使用,也供其他兼容 DSH 宿主集成。 | [模块说明](../README.md) · [桌面宿主接入](desktop-host.md) |
|
|
52
|
+
| 机构扩展 | 配置、技能和插件组合,复用公共接入能力。 | [EduWork@ECNU 示例](https://github.com/ecnu/EduWork-ECNU) |
|
|
53
|
+
|
|
54
|
+
服务端需要按所选模式提供相应接口;本仓库不包含可直接部署的 OIDC 或 Key Binding 服务端。现有客户端都是单机应用,本机 Web 用于验证,不提供多人共享的登录会话服务。
|
|
55
|
+
|
|
56
|
+
远程机构配置发现、远端模型 Key 注销等内容仍在 RFC 的可选扩展提案中;配额和活跃心跳继续由机构扩展处理。文档中的提案和能力声明不会自动启用未实现的功能。模型网关采用本文档规定的 OpenAI Chat Completions 兼容接口,其他模型及媒体接口须按各自契约另行核验。
|
|
57
|
+
|
|
58
|
+
其他客户端可以独立实现这些网络接口,不必采用 EduWork 的界面或桌面壳。能否互通,以双方声明的协议版本和实际联调结果为准。
|
|
59
|
+
|
|
60
|
+
## 你可以从哪里参与
|
|
61
|
+
|
|
62
|
+
- **身份或模型平台开发者**:从[服务端接口规范](server-integration-contract.md)和[接入指南](getting-started.md)开始,提供经过脱敏的接入示例,反馈现有平台难以满足的约束。
|
|
63
|
+
- **客户端作者**:尝试复用 `dsh-oidc`,或独立实现网络协议;验证登录、凭据生命周期、模型目录及错误处理,分享注明版本的互操作结果。
|
|
64
|
+
- **插件作者**:通过[账户扩展接口](account-extensions.md)接入机构能力,优先复用宿主授权传输与账户状态。
|
|
65
|
+
- **规范贡献者**:在 [EduWork Issues](https://github.com/ecnu/EduWork/issues) 描述场景与兼容性问题;修改接口前先讨论设计,并按[贡献指南](../CONTRIBUTING.md)同步规范、机器契约、示例和必要测试。
|
|
66
|
+
|
|
67
|
+
我们欢迎不同机构、不同客户端的实现参与。示例请使用占位配置和合成数据;认证漏洞与凭据问题通过[安全报告入口](../SECURITY.md)反馈。
|
|
68
|
+
|
|
69
|
+
## 与 DSH 插件生态的关系
|
|
70
|
+
|
|
71
|
+
[DSH Desktop 的插件生态倡议](https://github.com/anywhere-labs/dsh-desktop/blob/master/docs/plugin-ecosystem.md)推动插件之间的组合与协作。我们认同这个方向,希望在身份与模型接入这一环节提供可实现、可讨论的公共接口。这两份倡议各自独立;引用并不表示对方已经采纳本协议。
|
|
72
|
+
|
|
73
|
+
下一步希望共同验证的是:同一个机构服务能否通过清晰的协议和少量配置,接入更多客户端,并在升级后继续工作。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Reasoning replay compatibility
|
|
2
|
+
|
|
3
|
+
**English** | [简体中文](reasoning-replay.md)
|
|
4
|
+
|
|
5
|
+
DeepSeek Chat Completions requires the complete `reasoning_content` when tools are supplied in thinking mode; see the [official guide](https://api-docs.deepseek.com/guides/thinking_mode/). This is not a universal OpenAI-compatible field convention. The adapter follows each model's `compat.requiresReasoningContentOnAssistantMessages` setting.
|
|
6
|
+
|
|
7
|
+
pi-ai 0.85.1 preserves the original response field in replay metadata. A response using `reasoning` or `reasoning_text` is replayed under that alias. If the model also requires `reasoning_content`, pi-ai adds an empty canonical field. A strict gateway treating these fields as aliases can reject the pair with `duplicate field reasoning`. Retrying unchanged history repeats the conflict.
|
|
8
|
+
|
|
9
|
+
For affected models, the shared enterprise adapter normalizes those two plain-text aliases to `reasoning_content` before dispatch, preserving the full text. It does not clear reasoning or disable thinking. Only matching provider/model messages with version-2 pi-ai Chat Completions replay metadata are changed in the outgoing copy. Stored sessions, other API signatures and structured encrypted reasoning are untouched. Models explicitly disabling the compatibility requirement retain their original fields.
|
|
10
|
+
|
|
11
|
+
`test/provider.test.js` checks synthetic history through real pi-ai HTTP serialization, all three field spellings, immutable history, route/API boundaries, and the unmodified adapter's conflicting baseline. No institution account or real model request is required.
|
|
12
|
+
|
|
13
|
+
This fix belongs to the plugin source. A product must consume a new plugin package containing it; UI/configuration changes or unchanged npm locks do not upgrade an installed adapter. Follow the plugin publication process and update product dependency locks before shipping. Never overwrite published packages or rewrite user session files.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# 思考内容回传兼容
|
|
2
|
+
|
|
3
|
+
**简体中文** | [English](reasoning-replay.en.md)
|
|
4
|
+
|
|
5
|
+
DeepSeek Chat Completions 的思考模式在请求带有工具时要求完整回传 `reasoning_content`,见[官方说明](https://api-docs.deepseek.com/zh-cn/guides/thinking_mode/)。这不是所有 OpenAI 兼容服务共同遵循的字段约定,插件按模型的 `compat.requiresReasoningContentOnAssistantMessages` 配置决定是否采用这一规则。
|
|
6
|
+
|
|
7
|
+
## 修复的情况
|
|
8
|
+
|
|
9
|
+
pi-ai 0.85.1 会把服务端响应中的原始字段名记录为 replay metadata。某次响应使用 `reasoning` 或 `reasoning_text` 时,历史回传会继续使用该别名;若模型又要求 `reasoning_content`,pi-ai 会补入一个空的 `reasoning_content`。将这些字段视为同义词的严格网关因此可能报告 `duplicate field reasoning`。重试相同历史仍会生成冲突请求。
|
|
10
|
+
|
|
11
|
+
公共企业适配层在发送前将这两种纯文本别名统一为 `reasoning_content`,完整保留思考文本,不靠清空内容或关闭思考模式规避问题。只转换当前 provider/model 的、版本为 2 的 pi-ai Chat Completions replay metadata;不修改持久会话,不转换其他 API 的签名或结构化加密思考数据。显式关闭该兼容项的模型继续使用原有字段。
|
|
12
|
+
|
|
13
|
+
## 验证与交付
|
|
14
|
+
|
|
15
|
+
`test/provider.test.js` 包含合成消息与真实 pi-ai HTTP 编码检查:三种响应字段、旧历史不可变、不同模型/API 的范围限制,以及未修复适配器同时发出两个字段的基线。测试不需要机构账号,不向真实模型上传对话。
|
|
16
|
+
|
|
17
|
+
该修复在插件源码中维护。产品必须使用包含修复的新插件包后才能生效;只修改产品 UI 或配置文件、只更新本地源码、沿用旧 npm 锁,均不会自动更新已安装客户端。发布前需要按独立插件版本流程同步 npm 包和产品依赖锁,不改写已发布包,也不修改用户会话文件。
|