@eduwork/dsh-oidc 0.2.1 → 0.2.3

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.
@@ -1,42 +1,44 @@
1
- # Development and release preparation
2
-
3
- [简体中文](development.md) | **English**
4
-
5
- The plugin version is `0.2.0`. 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. This stable-version freeze does not change dev.7 runtime sources or replace earlier frozen artifacts.
6
-
7
- ## Verify a clean checkout
8
-
9
- Use Node.js 22 or 24 in this repository:
10
-
11
- ```sh
12
- npm ci
13
- npm run check
14
- ```
15
-
16
- The manifest declares exact development dependencies for the required DSH test closure, and the lock records public-registry URLs and integrity. Upstream prerelease carets may select a later RC, so pinning only direct peers is insufficient. `check:lock` rejects mixed versions, machine paths and missing integrity; `check:dsh` verifies the actually loaded baseline. Do not substitute junctions into a running desktop for a clean installation, or suppress conflicts with `--force` or `--legacy-peer-deps`.
17
-
18
- This is the plugin's development/CI closure, not a full desktop product. Consumers still reuse the host through peerDependencies. The [compatibility matrix](compatibility.en.md) distinguishes historical evidence; a historical peer declaration does not mean every old combination was rerun for each commit.
19
-
20
- The complete check covers TypeScript, the dependency lock and official contracts, Host/Client builds and loading, Node tests, schemas/examples, document links, sensitive-data/license scans, and package inspection. Optional `npm run check:browser` uses Playwright Core with a locally installed Edge/Chrome; `DSH_OIDC_BROWSER_CHANNEL` selects the installed channel (default `msedge`). It downloads no browser and does not replace real distribution login acceptance.
21
-
22
- ## Source map
23
-
24
- | Path | Responsibility |
25
- | --- | --- |
26
- | `src/host/profile.js` | Trusted Profile, bounded branding/models and common credential reference |
27
- | `src/host/oidc.js` | PKCE, Token/UserInfo, Key Binding, sessions and credential ownership |
28
- | `src/host/desktop-oidc.js` | Temporary loopback login shared by both desktop shells |
29
- | `src/host/resources.js` | Conservative model-catalog normalization |
30
- | `src/host/provider/` | Official PiAi Provider and explicit image-transform boundary |
31
- | `src/host/index.js`, `typert.*.js` | Host service, official lifecycle and public RPC |
32
- | `src/client/` | Official settings slots, account/login UI and bounded branding |
33
- | `test/` | Synthetic IdP/gateway, HTTP, Host, migration and race regressions |
34
- | `schema/`, `protocol/` | Profile Schema and implemented resource HTTP contracts |
35
-
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
-
38
- ## Public scope and remaining release work
39
-
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
-
42
- CI defines Windows/Linux × Node 22/24. A local Windows result does not cover unexecuted matrix cells. Before joint publication, complete the matrix, deployment acceptance and history/supply-chain review on the selected commit, then freeze the stable version, tag and tarball using the [release checklist](release-checklist.en.md). Existing npm versions and frozen artifacts are not rewritten. Local preparation does not push, release or publish.
1
+ # Development and release preparation
2
+
3
+ [简体中文](development.md) | **English**
4
+
5
+ The plugin version is `0.2.0`. 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. This stable-version freeze does not change dev.7 runtime sources or replace earlier frozen artifacts.
6
+
7
+ ## Verify a clean checkout
8
+
9
+ Use Node.js 22 or 24 in this repository:
10
+
11
+ ```sh
12
+ npm ci
13
+ npm run check
14
+ ```
15
+
16
+ The manifest declares exact development dependencies for the required DSH test closure, and the lock records public-registry URLs and integrity. Upstream prerelease carets may select a later RC, so pinning only direct peers is insufficient. `check:lock` rejects mixed versions, machine paths and missing integrity; `check:dsh` verifies the actually loaded baseline. Do not substitute junctions into a running desktop for a clean installation, or suppress conflicts with `--force` or `--legacy-peer-deps`.
17
+
18
+ This is the plugin's development/CI closure, not a full desktop product. Consumers still reuse the host through peerDependencies. The [compatibility matrix](compatibility.en.md) distinguishes historical evidence; a historical peer declaration does not mean every old combination was rerun for each commit.
19
+
20
+ The complete check covers TypeScript, the dependency lock and official contracts, Host/Client builds and loading, Node tests, schemas/examples, document links, sensitive-data/license scans, and package inspection. Optional `npm run check:browser` uses Playwright Core with a locally installed Edge/Chrome; `DSH_OIDC_BROWSER_CHANNEL` selects the installed channel (default `msedge`). It downloads no browser and does not replace real distribution login acceptance.
21
+
22
+ ## Source map
23
+
24
+ | Path | Responsibility |
25
+ | --- | --- |
26
+ | `src/host/profile.js` | Trusted Profile, bounded branding/models and common credential reference |
27
+ | `src/host/oidc.js` | PKCE, Token/UserInfo, Key Binding, sessions and credential ownership |
28
+ | `src/host/desktop-oidc.js` | Temporary loopback login shared by both desktop shells |
29
+ | `src/host/resources.js` | Conservative model-catalog normalization |
30
+ | `src/host/provider/` | Official PiAi Provider and explicit image-transform boundary |
31
+ | `src/host/index.js`, `typert.*.js` | Host service, official lifecycle and public RPC |
32
+ | `src/client/` | Official settings slots, account/login UI and bounded branding |
33
+ | `test/` | Synthetic IdP/gateway, HTTP, Host, migration and race regressions |
34
+ | `schema/`, `protocol/` | Profile Schema and implemented resource HTTP contracts |
35
+
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
+
38
+ ## Public scope and remaining release work
39
+
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
+
42
+ CI defines Windows/Linux × Node 22/24. A local Windows result does not cover unexecuted matrix cells. Before joint publication, complete the matrix, deployment acceptance and history/supply-chain review on the selected commit, then freeze the stable version, tag and tarball using the [release checklist](release-checklist.en.md). Existing npm versions and frozen artifacts are not rewritten. Local preparation does not push, release or publish.
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.
@@ -35,6 +35,8 @@ npm run check
35
35
 
36
36
  Host ESM 由 `scripts/build-host.mjs` 复制至 `lib`,Client 由 tsdown 打包;不要手改 `lib`。新增网络字段时应同步实现、Schema/OpenAPI、中英文规范与合约测试。UI/文档调整不需要添加机械重复实现的测试。
37
37
 
38
+ 思考内容的字段兼容与回归入口见[思考内容回传兼容](reasoning-replay.md)。该说明区分源码修复与已安装插件包,避免沿用旧 npm 锁时误判为修复已交付。
39
+
38
40
  ## 开源边界与发布待办
39
41
 
40
42
  公共包只拥有身份、托管 Key、模型目录/调用及对应账号 UI。配额、心跳、校内检索和语音业务由机构/产品插件负责;[账户扩展](account-extensions.md)是 Host 运输与插槽边界,不是暗中启用机构功能的开关。所有示例均使用占位域名、Public Client ID 与无秘密配置。
@@ -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 包和产品依赖锁,不改写已发布包,也不修改用户会话文件。
package/lib/client.js CHANGED
@@ -6076,7 +6076,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6076
6076
  width: size,
6077
6077
  height: size,
6078
6078
  borderRadius: Math.max(5, Math.round(size * .18)),
6079
- background: brand.primaryColor || "var(--dsw-alias-brand-primary, #5157af)",
6079
+ background: brand.primaryColor || "var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4d6bfe)",
6080
6080
  color: "white",
6081
6081
  fontSize: Math.max(11, Math.round(size * .52)),
6082
6082
  fontWeight: 750
@@ -161,6 +161,7 @@ export function resolveEnterpriseProfiles(raw = {}) {
161
161
  compat,
162
162
  modelPolicy: {
163
163
  reasoning, supportsReasoningEffort, reasoningEfforts: efforts, defaultReasoningEffort,
164
+ requiresReasoningContent: reasoning && compat.requiresReasoningContentOnAssistantMessages === true,
164
165
  ...(internalThinkingEffort === undefined ? {} : { internalThinkingEffort }),
165
166
  },
166
167
  }
@@ -1,5 +1,31 @@
1
1
  import { LlmError } from '@deepseek-ai/dsh-llm'
2
2
 
3
+ /** pi-ai preserves the response's raw reasoning alias in replay metadata.
4
+ * Routes requiring reasoning_content must replay that same text under the
5
+ * canonical field, otherwise pi-ai adds an empty alias and strict gateways
6
+ * reject the pair. Change only the outgoing copy; durable history is untouched.
7
+ */
8
+ export function canonicalReasoningReplay(request, policy) {
9
+ if (!policy.requiresReasoningContent) return request
10
+ let changed = false
11
+ const messages = request.messages.map(message => {
12
+ const source = message.source, replay = source?.replayState
13
+ if (message.role !== 'assistant' || source?.kind !== 'model' || source.provider !== request.provider || source.model !== request.model
14
+ || replay?.response?.kind !== 'pi-ai' || replay.response.version !== 2 || replay.response.api !== 'openai-completions'
15
+ || !Array.isArray(replay.blocks)) return message
16
+ let replaced = false
17
+ const blocks = replay.blocks.map(block => {
18
+ if (block.type !== 'reasoning' || !['reasoning', 'reasoning_text'].includes(block.thinkingSignature)) return block
19
+ replaced = true
20
+ return { ...block, thinkingSignature: 'reasoning_content' }
21
+ })
22
+ if (!replaced) return message
23
+ changed = true
24
+ return { ...message, source: { ...source, replayState: { ...replay, blocks } } }
25
+ })
26
+ return changed ? { ...request, messages } : request
27
+ }
28
+
3
29
  /** Delegate one enterprise route while applying capabilities contributed by replaceable feature plugins. */
4
30
  export class TransformingEnterpriseAdapter {
5
31
  constructor(inner, transforms, modelPolicy = () => ({})) {
@@ -73,7 +99,7 @@ export class TransformingEnterpriseAdapter {
73
99
  }
74
100
  request = { ...options, reasoningEffort: effort }
75
101
  }
76
- yield* prepared.stream(await this.transforms.apply(request, nativeModelInfo))
102
+ yield* prepared.stream(canonicalReasoningReplay(await this.transforms.apply(request, nativeModelInfo), policy))
77
103
  }
78
104
 
79
105
  async * stream(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eduwork/dsh-oidc",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Standards-based OIDC identity, enterprise API-key binding, declarative branding, and OpenAI-compatible model integration for DeepSeek Harness",
5
5
  "keywords": [
6
6
  "deepseek-harness",