dsh-coding-subscription-oauth 0.6.0 → 0.6.2

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.
Files changed (122) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/CONTRIBUTING.md +0 -0
  3. package/INSTALL.md +9 -8
  4. package/LICENSE +0 -0
  5. package/NOTICE +0 -0
  6. package/README.de.md +7 -8
  7. package/README.es.md +7 -8
  8. package/README.fr.md +7 -8
  9. package/README.ja.md +7 -8
  10. package/README.ko.md +7 -8
  11. package/README.md +8 -9
  12. package/README.pt-BR.md +7 -8
  13. package/README.ru.md +7 -8
  14. package/README.zh-CN.md +8 -9
  15. package/compatibility/dsh-bom.json +17 -30
  16. package/cordis.patch.yml +0 -0
  17. package/docs/00-project-rules.md +0 -0
  18. package/docs/02-architecture.md +1 -1
  19. package/docs/02-architecture.zh-CN.md +1 -1
  20. package/lib/adapter.d.ts.map +1 -1
  21. package/lib/alias-adapter.d.ts +3 -1
  22. package/lib/alias-adapter.d.ts.map +1 -1
  23. package/lib/bin.js +3 -3
  24. package/lib/bin.js.map +1 -1
  25. package/lib/client.js +3 -3
  26. package/lib/client.js.map +4 -4
  27. package/lib/compatibility.d.ts +14 -14
  28. package/lib/dsh-host-adapter.d.ts.map +1 -1
  29. package/lib/index.d.ts +1 -1
  30. package/lib/index.d.ts.map +1 -1
  31. package/lib/index.js +109 -79
  32. package/lib/index.js.map +3 -3
  33. package/media/en/settings_accounts.png +0 -0
  34. package/media/en/settings_capabilities.png +0 -0
  35. package/media/en/settings_gateway.png +0 -0
  36. package/media/settings_accounts.png +0 -0
  37. package/media/settings_capabilities.png +0 -0
  38. package/media/settings_gateway.png +0 -0
  39. package/media/settings_overview.png +0 -0
  40. package/media/zh-CN/settings_accounts.png +0 -0
  41. package/media/zh-CN/settings_capabilities.png +0 -0
  42. package/media/zh-CN/settings_gateway.png +0 -0
  43. package/package.json +38 -38
  44. package/patches/dsh-agy@0.1.2.patch +0 -0
  45. package/scripts/release.mjs +0 -0
  46. package/scripts/smoke-deployed-routes.mjs +0 -0
  47. package/scripts/verify-deployed-catalog.mjs +0 -0
  48. package/src/adapter.ts +75 -14
  49. package/src/alias-adapter.ts +17 -23
  50. package/src/auth-routes.ts +0 -0
  51. package/src/auth.ts +0 -0
  52. package/src/bin.ts +0 -0
  53. package/src/capability-routes.ts +0 -0
  54. package/src/capability-runtime.ts +0 -0
  55. package/src/capability-settings.ts +0 -0
  56. package/src/capability-tools.ts +0 -0
  57. package/src/catalog.ts +0 -0
  58. package/src/client/GrokBuildSettings.tsx +0 -0
  59. package/src/client/api.ts +0 -0
  60. package/src/client/components/AboutTab.tsx +0 -0
  61. package/src/client/components/AccountsTab.tsx +0 -0
  62. package/src/client/components/Badge.tsx +0 -0
  63. package/src/client/components/CapabilitiesTab.tsx +0 -0
  64. package/src/client/components/CliPullPreview.tsx +0 -0
  65. package/src/client/components/CopyButton.tsx +0 -0
  66. package/src/client/components/GatewayTab.tsx +0 -0
  67. package/src/client/components/NoticeBanner.tsx +0 -0
  68. package/src/client/components/ProgressBar.tsx +0 -0
  69. package/src/client/components/ProviderCard.tsx +0 -0
  70. package/src/client/components/SettingsTabs.tsx +0 -0
  71. package/src/client/components/ToggleSwitch.tsx +0 -0
  72. package/src/client/constants.ts +1 -1
  73. package/src/client/display.ts +0 -0
  74. package/src/client/dshClientAdapter.ts +32 -14
  75. package/src/client/gatewaySnippets.ts +0 -0
  76. package/src/client/index.tsx +3 -3
  77. package/src/client/locales.ts +0 -0
  78. package/src/client/microStyles.ts +0 -0
  79. package/src/client/parsers.ts +0 -0
  80. package/src/client/styles.ts +0 -0
  81. package/src/client/types.ts +0 -0
  82. package/src/codex-http.ts +0 -0
  83. package/src/codex-images.ts +0 -0
  84. package/src/codex-model-capabilities.ts +0 -0
  85. package/src/codex-search.ts +0 -0
  86. package/src/codex-usage.ts +0 -0
  87. package/src/compatibility.ts +14 -14
  88. package/src/dsh-host-adapter.ts +8 -6
  89. package/src/gateway-anthropic-messages.ts +0 -0
  90. package/src/gateway-auth.ts +0 -0
  91. package/src/gateway-backend.ts +0 -0
  92. package/src/gateway-body.ts +0 -0
  93. package/src/gateway-config.ts +0 -0
  94. package/src/gateway-http.ts +0 -0
  95. package/src/gateway-openai-chat.ts +0 -0
  96. package/src/gateway-openai-responses.ts +0 -0
  97. package/src/gateway-parse.ts +0 -0
  98. package/src/gateway-protocol.ts +0 -0
  99. package/src/gateway-routes.ts +0 -0
  100. package/src/gateway.ts +0 -0
  101. package/src/grok-errors.ts +0 -0
  102. package/src/grok-imagine.ts +0 -0
  103. package/src/grok-import.ts +0 -0
  104. package/src/http-json.ts +0 -0
  105. package/src/ids.ts +0 -0
  106. package/src/imagine-routes.ts +0 -0
  107. package/src/index.ts +26 -39
  108. package/src/invariant.ts +0 -0
  109. package/src/kimi-errors.ts +0 -0
  110. package/src/media-store.ts +0 -0
  111. package/src/oauth-import-routes.ts +0 -0
  112. package/src/oauth-providers.ts +0 -0
  113. package/src/oauth-session.ts +0 -0
  114. package/src/oauth-sources.ts +0 -0
  115. package/src/oauth.ts +0 -0
  116. package/src/provider.ts +0 -0
  117. package/src/proxy.ts +0 -0
  118. package/src/redact.ts +0 -0
  119. package/src/session.ts +0 -0
  120. package/src/store.ts +0 -0
  121. package/src/web-origin.ts +0 -0
  122. package/src/web-routes.ts +0 -0
File without changes
File without changes
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-coding-subscription-oauth",
3
3
  "description": "DeepSeek Harness coding-subscription OAuth: SuperGrok/Grok Build, ChatGPT Plus Codex, Kimi Code, Claude Code. Fixes AUTH API key is invalid, INVALID_REPLAY_STATE, grok-4.6 xhigh, Kimi Bearer vs x-api-key.",
4
- "version": "0.6.0",
4
+ "version": "0.6.2",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "registry": "https://registry.npmjs.org/"
@@ -110,20 +110,20 @@
110
110
  "diagnostics": "standalone",
111
111
  "bom": {
112
112
  "@deepseek-ai/cordis": "4.0.1",
113
- "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.6",
114
- "@deepseek-ai/dsh-attachment": "0.1.0-rc.6",
115
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
116
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
117
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6",
118
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
119
- "@deepseek-ai/dsh-client-web": "0.1.0-rc.6",
120
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
121
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.6",
122
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
123
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
124
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
125
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
126
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
113
+ "@deepseek-ai/dsh-atomic-write": "0.1.1-rc.2",
114
+ "@deepseek-ai/dsh-attachment": "0.1.1-rc.2",
115
+ "@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
116
+ "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
117
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
118
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
119
+ "@deepseek-ai/dsh-client-web": "0.1.1-rc.2",
120
+ "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
121
+ "@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
122
+ "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
123
+ "@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
124
+ "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
125
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.1-rc.2",
126
+ "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
127
127
  "@deepseek-ai/schemastery": "3.18.1",
128
128
  "@earendil-works/pi-ai": "0.84.2",
129
129
  "react": "18.3.1",
@@ -148,15 +148,15 @@
148
148
  },
149
149
  "peerDependencies": {
150
150
  "@deepseek-ai/cordis": "4.0.1",
151
- "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.6",
152
- "@deepseek-ai/dsh-attachment": "0.1.0-rc.6",
153
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
154
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.6",
155
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
156
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
157
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
158
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
159
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
151
+ "@deepseek-ai/dsh-atomic-write": "0.1.1-rc.2",
152
+ "@deepseek-ai/dsh-attachment": "0.1.1-rc.2",
153
+ "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
154
+ "@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
155
+ "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
156
+ "@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
157
+ "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
158
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.1-rc.2",
159
+ "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
160
160
  "@deepseek-ai/schemastery": "3.18.1",
161
161
  "@earendil-works/pi-ai": "0.84.2",
162
162
  "react": "18.3.1",
@@ -191,20 +191,20 @@
191
191
  "devDependencies": {
192
192
  "@biomejs/biome": "^2.5.8",
193
193
  "@deepseek-ai/cordis": "4.0.1",
194
- "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.6",
195
- "@deepseek-ai/dsh-attachment": "0.1.0-rc.6",
196
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
197
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
198
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6",
199
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
200
- "@deepseek-ai/dsh-client-web": "0.1.0-rc.6",
201
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
202
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.6",
203
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
204
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
205
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
206
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
207
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
194
+ "@deepseek-ai/dsh-atomic-write": "0.1.1-rc.2",
195
+ "@deepseek-ai/dsh-attachment": "0.1.1-rc.2",
196
+ "@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
197
+ "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
198
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
199
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
200
+ "@deepseek-ai/dsh-client-web": "0.1.1-rc.2",
201
+ "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
202
+ "@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
203
+ "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
204
+ "@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
205
+ "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
206
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.1-rc.2",
207
+ "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
208
208
  "@deepseek-ai/schemastery": "3.18.1",
209
209
  "@earendil-works/pi-ai": "0.84.2",
210
210
  "@types/node": "^22.20.0",
File without changes
File without changes
File without changes
File without changes
package/src/adapter.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  import type { AttachmentStore } from "@deepseek-ai/dsh-attachment";
4
4
  import type { RetryPolicyConfig } from "@deepseek-ai/dsh-llm";
5
5
  import { type LlmAdapter, LlmError, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
6
- import type { ResolvedPiAiProviderProfile } from "@deepseek-ai/dsh-llm-pi-ai";
6
+ import type { PiAiAdapterOptions, ResolvedPiAiProviderProfile } from "@deepseek-ai/dsh-llm-pi-ai";
7
7
  import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
8
8
  import type { AliasLlmRoutePolicy } from "./alias-adapter.ts";
9
9
  import { AliasLlmAdapter } from "./alias-adapter.ts";
@@ -25,7 +25,60 @@ import {
25
25
  import type { OAuthProviderSession } from "./oauth-session.ts";
26
26
  import { grokBuildBaselineModels, grokBuildFingerprintHeaders } from "./provider.ts";
27
27
  import { safeMessage } from "./redact.ts";
28
- import type { GrokBuildSession } from "./session.ts";
28
+ import type { GrokBuildSession } from "./session.ts";
29
+
30
+ type PiAiAuthInjection = PiAiAdapterOptions["auth"];
31
+ type PiAiCredentialStore = PiAiAuthInjection["credentials"];
32
+
33
+ const REQUEST_IMAGE_POLICY = {
34
+ maxRequestImageBytes: 20 * 1024 * 1024,
35
+ requestImagePixelBudget: 2048 * 2048,
36
+ requestImageMaxBytes: 1024 * 1024,
37
+ } as const;
38
+
39
+ /**
40
+ * Route pi-ai credential operations to the already owner-locked OAuth files.
41
+ * The adapter may ask its collection about every profile, so an unknown id is
42
+ * never allowed to reach a writable store. Reads are empty and writes fail
43
+ * closed, preserving the existing per-provider refresh lock and file policy.
44
+ */
45
+ function oauthAuthInjection(grok: GrokBuildSession, subscriptions: readonly OAuthProviderSession[]): PiAiAuthInjection {
46
+ const stores = new Map<string, PiAiCredentialStore>([
47
+ [XAI_PI_PROVIDER, grok.store],
48
+ ...subscriptions.map((session) => [session.definition.nativeProviderId, session.store] as const),
49
+ ]);
50
+ const storeFor = (providerId: string): PiAiCredentialStore | undefined => stores.get(providerId);
51
+ return {
52
+ credentials: {
53
+ async read(providerId, options) {
54
+ return storeFor(providerId)?.read(providerId, options);
55
+ },
56
+ async list(options) {
57
+ const entries = await Promise.all([...stores.values()].map((store) => store.list(options)));
58
+ return entries.flat();
59
+ },
60
+ async modify(providerId, fn, options) {
61
+ const store = storeFor(providerId);
62
+ if (store === undefined)
63
+ throw new Error(`refusing credential write for unknown OAuth provider "${providerId}"`);
64
+ return store.modify(providerId, fn, options);
65
+ },
66
+ async delete(providerId, options) {
67
+ const store = storeFor(providerId);
68
+ if (store === undefined)
69
+ throw new Error(`refusing credential deletion for unknown OAuth provider "${providerId}"`);
70
+ await store.delete(providerId, options);
71
+ },
72
+ },
73
+ authContext: {
74
+ // Subscription adapters obtain request credentials only from their
75
+ // owner-scoped stores. Do not let a foreign environment/file credential
76
+ // silently change a selected OAuth route.
77
+ env: async () => undefined,
78
+ fileExists: async () => false,
79
+ },
80
+ };
81
+ }
29
82
 
30
83
  /** Prefer grok-4.6 when the current (live or baseline) list has it. */
31
84
  export function preferredGrokBuildModel(models: readonly { id: string }[] = grokBuildBaselineModels()): string {
@@ -86,7 +139,8 @@ function profile(
86
139
  retryPolicy ?? CODING_OAUTH_RETRY_POLICY,
87
140
  "dsh-coding-subscription-oauth retryPolicy",
88
141
  ),
89
- configuredMaxTokens: new Map(),
142
+ configuredMaxTokens: new Map(),
143
+ ...REQUEST_IMAGE_POLICY,
90
144
  ...(headers === undefined ? {} : { headers }),
91
145
  piProvider,
92
146
  };
@@ -97,7 +151,7 @@ export function createGrokBuildAdapter(
97
151
  session: GrokBuildSession,
98
152
  resolveAttachments: () => AttachmentStore | undefined,
99
153
  ): PiAiAdapter {
100
- return new PiAiAdapter({
154
+ return new PiAiAdapter({
101
155
  profiles: () =>
102
156
  new Map<string, ResolvedPiAiProviderProfile>([
103
157
  [
@@ -105,12 +159,13 @@ export function createGrokBuildAdapter(
105
159
  profile(GROK_BUILD_ROUTE, "xAI Grok Build", session.provider(), undefined, grokBuildFingerprintHeaders()),
106
160
  ],
107
161
  ]),
108
- resolveApiKey: async () =>
162
+ resolveApiKey: async () =>
109
163
  resolveOAuthToken("Grok Build", async () => {
110
164
  const auth = await session.models.getAuth(XAI_PI_PROVIDER, { minOAuthValidityMs: MIN_OAUTH_VALIDITY_MS });
111
165
  return auth?.auth.apiKey;
112
- }),
113
- resolveAttachments,
166
+ }),
167
+ auth: oauthAuthInjection(session, []),
168
+ resolveAttachments,
114
169
  });
115
170
  }
116
171
 
@@ -201,7 +256,7 @@ export function createCodingOAuthAdapter(
201
256
  });
202
257
  }
203
258
 
204
- const inner = new PiAiAdapter({
259
+ const inner = new PiAiAdapter({
205
260
  profiles: () => {
206
261
  const profiles = new Map<string, ResolvedPiAiProviderProfile>();
207
262
  profiles.set(
@@ -244,7 +299,7 @@ export function createCodingOAuthAdapter(
244
299
  }
245
300
  return profiles;
246
301
  },
247
- resolveApiKey: async (provider) => {
302
+ resolveApiKey: async (provider) => {
248
303
  if (provider === GROK_BUILD_ROUTE) {
249
304
  return resolveOAuthToken("Grok Build", async () => {
250
305
  const auth = await grok.models.getAuth(XAI_PI_PROVIDER, { minOAuthValidityMs: MIN_OAUTH_VALIDITY_MS });
@@ -254,13 +309,19 @@ export function createCodingOAuthAdapter(
254
309
  const session =
255
310
  provider === CODEX_OAUTH_FAST_ROUTE ? byNativeId.get(CODEX_PI_PROVIDER) : byNativeId.get(provider);
256
311
  if (session === undefined) throw new LlmError(`Unknown OAuth provider "${provider}"`, "NO_ADAPTER");
257
- return resolveOAuthToken(session.definition.displayName, () => session.resolveAccessToken());
258
- },
259
- resolveAttachments,
312
+ return resolveOAuthToken(session.definition.displayName, () => session.resolveAccessToken());
313
+ },
314
+ auth: oauthAuthInjection(grok, subscriptions),
315
+ resolveAttachments,
260
316
  });
261
317
 
262
- return new AliasLlmAdapter(inner, aliases, policies);
263
- }
318
+ // The Fast wrapper restores wire/replay model identity to openai-codex.
319
+ // Keep the opaque envelope untouched and map public Fast source identity to
320
+ // that native replay provider before PiAiAdapter validates it.
321
+ const replayProviders = new Map(aliases);
322
+ replayProviders.set(CODEX_OAUTH_FAST_ROUTE, CODEX_PI_PROVIDER);
323
+ return new AliasLlmAdapter(inner, aliases, policies, replayProviders);
324
+ }
264
325
 
265
326
  /**
266
327
  * Resolve an OAuth access token for one route, translating a failed refresh
@@ -36,16 +36,10 @@ export interface AliasLlmRoutePolicy {
36
36
  onAuthFailure?: () => Promise<void>;
37
37
  }
38
38
 
39
- function routePiAiReplayState(value: unknown, route: string): unknown {
40
- if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
41
- const state = value as Record<string, unknown>;
42
- if (state["kind"] !== "pi-ai" || state["provider"] === route) return value;
43
- return { ...state, provider: route };
44
- }
45
-
46
- function normalizeReplayForRoute(
47
- message: GenerateOptions["messages"][number],
48
- route: string,
39
+ export function normalizeReplayForRoute(
40
+ message: GenerateOptions["messages"][number],
41
+ route: string,
42
+ nativeReplayProvider: string,
49
43
  ): GenerateOptions["messages"][number] {
50
44
  if (message.role !== "assistant" || message.source.kind !== "model") return message;
51
45
  if (message.source.provider !== route) {
@@ -53,9 +47,10 @@ function normalizeReplayForRoute(
53
47
  const { replayState: _foreignReplay, ...source } = message.source;
54
48
  return { ...message, source };
55
49
  }
56
- const replayState = routePiAiReplayState(message.source.replayState, route);
57
- if (replayState === message.source.replayState) return message;
58
- return { ...message, source: { ...message.source, replayState } };
50
+ // The rc.2 envelope stays entirely opaque. PiAiAdapter only keys replay
51
+ // validation from source.provider, so restore the native provider identity
52
+ // without inspecting or changing replayState.
53
+ return { ...message, source: { ...message.source, provider: nativeReplayProvider } };
59
54
  }
60
55
 
61
56
  /**
@@ -63,10 +58,11 @@ function normalizeReplayForRoute(
63
58
  * Harness route names. Every public operation translates exactly once.
64
59
  */
65
60
  export class AliasLlmAdapter extends LlmAdapter {
66
- constructor(
67
- private readonly inner: LlmAdapter,
68
- private readonly aliases: ReadonlyMap<string, string>,
69
- private readonly policies: ReadonlyMap<string, AliasLlmRoutePolicy> = new Map(),
61
+ constructor(
62
+ private readonly inner: LlmAdapter,
63
+ private readonly aliases: ReadonlyMap<string, string>,
64
+ private readonly policies: ReadonlyMap<string, AliasLlmRoutePolicy> = new Map(),
65
+ private readonly replayProviders: ReadonlyMap<string, string> = aliases,
70
66
  ) {
71
67
  super();
72
68
  }
@@ -113,7 +109,9 @@ export class AliasLlmAdapter extends LlmAdapter {
113
109
  async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
114
110
  const route = options.provider;
115
111
  const native = this.nativeProvider(route);
116
- const messages = options.messages.map((message) => normalizeReplayForRoute(message, route));
112
+ const messages = options.messages.map((message) =>
113
+ normalizeReplayForRoute(message, route, this.replayProviders.get(route) ?? native),
114
+ );
117
115
  let authFailureNotified = false;
118
116
  for await (const raw of this.inner.stream({ ...options, provider: native, messages })) {
119
117
  const chunk =
@@ -143,11 +141,7 @@ export class AliasLlmAdapter extends LlmAdapter {
143
141
  }
144
142
  }
145
143
  }
146
- if (chunk.type === "finish" && chunk.replayState !== undefined) {
147
- yield { ...chunk, replayState: routePiAiReplayState(chunk.replayState, route) };
148
- } else {
149
- yield chunk;
150
- }
144
+ yield chunk;
151
145
  }
152
146
  }
153
147
  }
File without changes
package/src/auth.ts CHANGED
File without changes
package/src/bin.ts CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
package/src/catalog.ts CHANGED
File without changes
File without changes
package/src/client/api.ts CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -221,4 +221,4 @@ export const CONSUMED_PREVIEW_CODES = new Set([
221
221
  "unsafe_destination",
222
222
  ]);
223
223
 
224
- export const PLUGIN_VERSION = "0.6.0";
224
+ export const PLUGIN_VERSION = "0.6.2";
File without changes
@@ -12,15 +12,32 @@ export interface DshClientCompatibilityDiagnostic {
12
12
  readonly actual: string;
13
13
  }
14
14
 
15
- function hasSlots(context: unknown): context is ClientContext {
16
- if (typeof context !== "object" || context === null) return false;
17
- const slots = (context as { readonly slots?: unknown }).slots;
18
- return (
15
+ type SlotsApi = ClientContext["slots"];
16
+
17
+ function slotsOf(context: unknown): SlotsApi | undefined {
18
+ if (typeof context !== "object" || context === null) return undefined;
19
+ let slots: unknown;
20
+ try {
21
+ const get = (context as { readonly get?: unknown }).get;
22
+ if (typeof get === "function") slots = get.call(context, "slots");
23
+ } catch {
24
+ // Older client runtimes may not expose the Cordis reflection helper.
25
+ }
26
+ if (slots === undefined) {
27
+ try {
28
+ slots = (context as { readonly slots?: unknown }).slots;
29
+ } catch {
30
+ // Strict Cordis rejects optional service reads outside an inject scope.
31
+ }
32
+ }
33
+ if (
19
34
  typeof slots === "object" &&
20
35
  slots !== null &&
21
36
  typeof (slots as { readonly inject?: unknown }).inject === "function" &&
22
37
  typeof (slots as { readonly register?: unknown }).register === "function"
23
- );
38
+ )
39
+ return slots as SlotsApi;
40
+ return undefined;
24
41
  }
25
42
 
26
43
  export interface DshClientAdapter {
@@ -30,7 +47,7 @@ export interface DshClientAdapter {
30
47
  diagnostics(): readonly DshClientCompatibilityDiagnostic[];
31
48
  assertCompatible(): void;
32
49
  installSlots(options: {
33
- readonly register: (context: ClientContext) => () => void;
50
+ readonly register: (slots: SlotsApi) => () => void;
34
51
  readonly mountFallback: () => () => void;
35
52
  }): void;
36
53
  }
@@ -40,11 +57,12 @@ type InstallSlotsOptions = Parameters<DshClientAdapter["installSlots"]>[0];
40
57
  export function createDshClientAdapter(context: ClientContext): DshClientAdapter {
41
58
  const candidate = context as unknown as Record<string, unknown>;
42
59
  const locale = candidate["locale"] as Record<string, unknown> | undefined;
60
+ const slots = slotsOf(context);
43
61
  const checks: Array<[string, unknown, DshClientCompatibilityDiagnostic["level"]]> = [
44
62
  ["client.effect", candidate["effect"], "error"],
45
63
  ["client.locale.register", locale?.["register"], "error"],
46
64
  ["client.locale.bind", locale?.["bind"], "error"],
47
- ["client.slots.inject", (candidate["slots"] as Record<string, unknown> | undefined)?.["inject"], "warning"],
65
+ ["client.slots.inject", slots?.inject, "warning"],
48
66
  ];
49
67
  const diagnostics = checks.flatMap(([id, value, level]): DshClientCompatibilityDiagnostic[] =>
50
68
  typeof value === "function"
@@ -78,21 +96,21 @@ export function createDshClientAdapter(context: ClientContext): DshClientAdapter
78
96
  let disposed = false;
79
97
  let installed = false;
80
98
  let disposeCurrent: () => void = () => undefined;
81
- const install = (slotContext: ClientContext): void => {
82
- if (disposed || installed) return;
99
+ const install = (slotContext: ClientContext): boolean => {
100
+ const slots = slotsOf(slotContext);
101
+ if (disposed || installed || slots === undefined) return false;
83
102
  installed = true;
84
103
  disposeCurrent();
85
- disposeCurrent = options.register(slotContext);
104
+ disposeCurrent = options.register(slots);
105
+ return true;
86
106
  };
87
107
 
88
- if (hasSlots(context)) {
89
- install(context);
90
- } else {
108
+ if (!install(context)) {
91
109
  disposeCurrent = options.mountFallback();
92
110
  const inject = candidate["inject"];
93
111
  if (typeof inject === "function") {
94
112
  (inject as ClientContext["inject"]).call(context, ["slots"], (slotContext) => {
95
- if (hasSlots(slotContext)) install(slotContext);
113
+ install(slotContext);
96
114
  });
97
115
  }
98
116
  }
File without changes
@@ -139,9 +139,9 @@ export function apply(ctx: ClientContext): void {
139
139
  const t = dsh.locale.bind(namespace) as GrokBuildSettingsInjected["t"];
140
140
  dsh.installSlots({
141
141
  mountFallback: () => mountIndependentEntry(t),
142
- register: (slotContext) =>
143
- slotContext.slots.inject("settings.section", () =>
144
- slotContext.slots.register(
142
+ register: (slots) =>
143
+ slots.inject("settings.section", () =>
144
+ slots.register(
145
145
  {
146
146
  name: "settings.section",
147
147
  id: "grok-build",
File without changes
File without changes
File without changes
File without changes
File without changes
package/src/codex-http.ts CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -28,20 +28,20 @@ export interface DshCompatibility {
28
28
 
29
29
  export const DSH_EXACT_BOM = Object.freeze({
30
30
  "@deepseek-ai/cordis": "4.0.1",
31
- "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.6",
32
- "@deepseek-ai/dsh-attachment": "0.1.0-rc.6",
33
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
34
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
35
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6",
36
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
37
- "@deepseek-ai/dsh-client-web": "0.1.0-rc.6",
38
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
39
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.6",
40
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
41
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
42
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
43
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
44
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
31
+ "@deepseek-ai/dsh-atomic-write": "0.1.1-rc.2",
32
+ "@deepseek-ai/dsh-attachment": "0.1.1-rc.2",
33
+ "@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
34
+ "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
35
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
36
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
37
+ "@deepseek-ai/dsh-client-web": "0.1.1-rc.2",
38
+ "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
39
+ "@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
40
+ "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
41
+ "@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
42
+ "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
43
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.1-rc.2",
44
+ "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
45
45
  "@deepseek-ai/schemastery": "3.18.1",
46
46
  "@earendil-works/pi-ai": "0.84.2",
47
47
  react: "18.3.1",
@@ -44,9 +44,13 @@ function record(value: unknown): Record<string, unknown> | undefined {
44
44
 
45
45
  function service(context: Context, name: string): unknown {
46
46
  try {
47
- return context.get(name);
48
- } catch {
47
+ const value = context.get(name);
48
+ if (value !== undefined && value !== null) return value;
49
+ } catch {}
50
+ try {
49
51
  return record(context)?.[name];
52
+ } catch {
53
+ return undefined;
50
54
  }
51
55
  }
52
56
 
@@ -92,7 +96,7 @@ export function createDshHostAdapter(context: Context): DshHostAdapter {
92
96
  });
93
97
  }
94
98
  }
95
- const llm = record(service(context, "llm")) ?? (candidate["llm"] as Record<string, unknown> | undefined);
99
+ const llm = record(service(context, "llm"));
96
100
  if (llm === undefined || typeof llm["registerAdapter"] !== "function") {
97
101
  diagnostics.push({
98
102
  id: "host.api.llm.registerAdapter",
@@ -120,9 +124,7 @@ export function createDshHostAdapter(context: Context): DshHostAdapter {
120
124
  webServer: capability(service(context, "webServer"), "exact-route-v1", ["register"]),
121
125
  settings: capability(service(context, "settings"), "settings-register-v1", ["register"]),
122
126
  credentials: capability(service(context, "credentials"), "credential-resolver-v1", ["resolve"]),
123
- llm: capability(service(context, "llm") ?? record(context)?.["llm"], "llm-adapter-registry-v1", [
124
- "registerAdapter",
125
- ]),
127
+ llm: capability(service(context, "llm"), "llm-adapter-registry-v1", ["registerAdapter"]),
126
128
  ownerRequestPolicy: capability(service(context, "ownerRequestPolicy"), "owner-request-policy-v1", [
127
129
  "authorize",
128
130
  "diagnostics",
File without changes
File without changes