dsh-coding-subscription-oauth 0.6.2 → 0.6.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.
@@ -117,6 +117,12 @@ export const CAPABILITY_TOGGLES: readonly {
117
117
  { key: "codexSearch", label: "capCodexSearch", hint: "capCodexSearchHint" },
118
118
  { key: "codexImages", label: "capCodexImages", hint: "capCodexImagesHint" },
119
119
  { key: "codexImageEdits", label: "capCodexImageEdits", hint: "capCodexImageEditsHint", requiresImages: true },
120
+ {
121
+ key: "codexImagesAnyModel",
122
+ label: "capCodexImagesAnyModel",
123
+ hint: "capCodexImagesAnyModelHint",
124
+ requiresImages: true,
125
+ },
120
126
  { key: "codexUsage", label: "capCodexUsage", hint: "capCodexUsageHint" },
121
127
  { key: "codexFast", label: "capCodexFast", hint: "capCodexFastHint" },
122
128
  { key: "grokImagineImage", label: "capGrokImagineImage", hint: "capGrokImagineImageHint" },
@@ -221,4 +227,4 @@ export const CONSUMED_PREVIEW_CODES = new Set([
221
227
  "unsafe_destination",
222
228
  ]);
223
229
 
224
- export const PLUGIN_VERSION = "0.6.2";
230
+ export const PLUGIN_VERSION = "0.6.4";
@@ -139,6 +139,9 @@ export const en = {
139
139
  capCodexImagesHint: "Generate images with ChatGPT/Codex quota.",
140
140
  capCodexImageEdits: "Codex image edits",
141
141
  capCodexImageEditsHint: "Edit images; requires Codex images.",
142
+ capCodexImagesAnyModel: "Allow any model to use image tools",
143
+ capCodexImagesAnyModelHint:
144
+ "Let non-Codex routes also call image generate/edit. Still uses your ChatGPT/Codex quota and requires Codex sign-in.",
142
145
  capCodexUsage: "Show Codex quota",
143
146
  capCodexUsageHint: "Show remaining quota on the Codex account card when available.",
144
147
  capCodexFast: "Fast requested",
@@ -404,6 +407,8 @@ export const zh: { [Key in GrokBuildSettingsKey]: string } = {
404
407
  capCodexImagesHint: "用 ChatGPT/Codex 配额出图。",
405
408
  capCodexImageEdits: "Codex 改图",
406
409
  capCodexImageEditsHint: "改图;需先打开 Codex 出图。",
410
+ capCodexImagesAnyModel: "允许任意模型调用出图工具",
411
+ capCodexImagesAnyModelHint: "非 Codex 渠道的模型也可调用图片生成/编辑。仍消耗 ChatGPT/Codex 配额,且需登录 Codex。",
407
412
  capCodexUsage: "显示 Codex 额度",
408
413
  capCodexUsageHint: "有数据时在 Codex 账户卡片上显示剩余额度。",
409
414
  capCodexFast: "已请求 Fast",
@@ -167,6 +167,7 @@ export function emptyCapabilitySettings(): CapabilitySettingsView {
167
167
  codexSearch: false,
168
168
  codexImages: false,
169
169
  codexImageEdits: false,
170
+ codexImagesAnyModel: false,
170
171
  codexUsage: false,
171
172
  codexFast: false,
172
173
  grokImagineImage: false,
@@ -183,6 +184,7 @@ export function parseCapabilitySettings(value: unknown): CapabilitySettingsView
183
184
  codexSearch: source["codexSearch"] === true,
184
185
  codexImages: source["codexImages"] === true,
185
186
  codexImageEdits: source["codexImageEdits"] === true,
187
+ codexImagesAnyModel: source["codexImagesAnyModel"] === true,
186
188
  codexUsage: source["codexUsage"] === true,
187
189
  codexFast: source["codexFast"] === true,
188
190
  grokImagineImage: source["grokImagineImage"] === true,
@@ -21,6 +21,7 @@ export type CapabilityFlagKey =
21
21
  | "codexSearch"
22
22
  | "codexImages"
23
23
  | "codexImageEdits"
24
+ | "codexImagesAnyModel"
24
25
  | "codexUsage"
25
26
  | "codexFast"
26
27
  | "grokImagineImage"
@@ -121,6 +122,7 @@ export interface CapabilityFlags {
121
122
  codexSearch: boolean;
122
123
  codexImages: boolean;
123
124
  codexImageEdits: boolean;
125
+ codexImagesAnyModel: boolean;
124
126
  codexUsage: boolean;
125
127
  codexFast: boolean;
126
128
  grokImagineImage: boolean;
@@ -71,6 +71,13 @@ export interface CodexImageSessionContext {
71
71
  route?: CodexImageRoute;
72
72
  }
73
73
 
74
+ /**
75
+ * Route gate for the image tools. `codex-capable` (default) requires a Codex
76
+ * OAuth route that declares image input; `any` lets any model route call the
77
+ * tools while the ChatGPT subscription backend still performs the work.
78
+ */
79
+ export type CodexImageRoutePolicy = "codex-capable" | "any";
80
+
74
81
  export interface CodexImageGenerateInput {
75
82
  readonly prompt: string;
76
83
  readonly n?: number;
@@ -101,6 +108,8 @@ export interface CodexImageControllerOptions {
101
108
  readonly auth: CodexAuthSession;
102
109
  readonly attachments: CodexImageAttachmentStore;
103
110
  readonly session: CodexImageSessionContext;
111
+ /** Route gate; defaults to `codex-capable`. Set `any` to allow non-Codex routes. */
112
+ readonly routePolicy?: CodexImageRoutePolicy;
104
113
  readonly http?: CodexHttpClient;
105
114
  readonly fetchImpl?: CodexFetch;
106
115
  readonly originator?: string;
@@ -283,6 +292,12 @@ function enumValue<const T extends string>(value: T | undefined, allowed: readon
283
292
  return value;
284
293
  }
285
294
 
295
+ async function assertSignedIn(auth: CodexAuthSession): Promise<void> {
296
+ if ((await auth.resolve()) === undefined) {
297
+ throw new LlmError("Codex image tools require a signed-in Codex account", "MISSING_CREDENTIAL");
298
+ }
299
+ }
300
+
286
301
  function imageEnvelopeLimit(maxImageBytes: number, n: number): number {
287
302
  return Math.ceil(maxImageBytes / 3) * 4 * Math.max(1, n) + 128 * 1024;
288
303
  }
@@ -301,7 +316,9 @@ async function prepareRequest(
301
316
  imageIds: readonly string[] | undefined,
302
317
  signal?: AbortSignal,
303
318
  ): Promise<PreparedImageRequest> {
304
- assertCodexImageCapableRoute(options.session.route);
319
+ if (options.routePolicy !== "any") {
320
+ assertCodexImageCapableRoute(options.session.route);
321
+ }
305
322
  const prompt = input.prompt.trim();
306
323
  if (prompt.length === 0) {
307
324
  throw new LlmError("Codex image generation requires a non-empty prompt", "INVALID_ARGS");
@@ -467,6 +484,7 @@ export function createCodexImageController(options: CodexImageControllerOptions)
467
484
  imageIds: readonly string[] | undefined,
468
485
  signal?: AbortSignal,
469
486
  ): Promise<CodexImageResult> => {
487
+ await assertSignedIn(options.auth);
470
488
  const prepared = await prepareRequest(options, input, imageIds, signal);
471
489
  const payload = await http.requestJson({
472
490
  url: prepared.operation === "generate" ? CODEX_IMAGE_GENERATION_URL : CODEX_IMAGE_EDIT_URL,
@@ -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.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",
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",
package/src/index.ts CHANGED
@@ -240,7 +240,7 @@ function fixedCredentialRef(value: string): CredentialRef {
240
240
  export { IMAGINE_MEDIA_STORE_DIRNAME } from "./ids.ts";
241
241
 
242
242
  /** Optional host services are acquired inside the elected child fiber. */
243
- export const inject = ["webServer"] as const;
243
+ export const inject = ["webServer"] as const;
244
244
 
245
245
  /** Plugin configuration; every field is optional. */
246
246
  export interface Config {
@@ -571,27 +571,27 @@ async function applyOwned(ctx: Context, config: Config): Promise<void> {
571
571
  return () => gateway.stop();
572
572
  }, "dsh-coding-subscription-oauth: local API gateway");
573
573
 
574
- registerCapabilityRoutes(ctx, {
575
- controller: capabilityRoutesController,
576
- usage: () => usage.read(),
577
- credentialInfo: () => describeImagineCredential(ctx.get("credentials") as CredentialProvider | undefined),
578
- ownerRequestPolicy,
579
- });
580
- registerGatewayRoutes(ctx, gateway, ownerRequestPolicy);
581
- registerCodingOAuthRoutes(ctx, grok, subscriptions, ownerRequestPolicy, (accessMode) =>
582
- host.compatibility({
583
- accessMode,
584
- uiOwner: "standalone",
585
- diagnostics: ownerRequestPolicy.diagnostics(),
586
- }),
587
- );
588
- registerOAuthImportRoutes(ctx, oauthImportDestinations(grok, subscriptions), {
589
- ownerRequestPolicy,
590
- onImported: (event) => {
591
- if (event.kind === "codex") invalidateOptionalAuthState();
592
- notifyCatalogChange();
593
- },
594
- });
574
+ registerCapabilityRoutes(ctx, {
575
+ controller: capabilityRoutesController,
576
+ usage: () => usage.read(),
577
+ credentialInfo: () => describeImagineCredential(ctx.get("credentials") as CredentialProvider | undefined),
578
+ ownerRequestPolicy,
579
+ });
580
+ registerGatewayRoutes(ctx, gateway, ownerRequestPolicy);
581
+ registerCodingOAuthRoutes(ctx, grok, subscriptions, ownerRequestPolicy, (accessMode) =>
582
+ host.compatibility({
583
+ accessMode,
584
+ uiOwner: "standalone",
585
+ diagnostics: ownerRequestPolicy.diagnostics(),
586
+ }),
587
+ );
588
+ registerOAuthImportRoutes(ctx, oauthImportDestinations(grok, subscriptions), {
589
+ ownerRequestPolicy,
590
+ onImported: (event) => {
591
+ if (event.kind === "codex") invalidateOptionalAuthState();
592
+ notifyCatalogChange();
593
+ },
594
+ });
595
595
 
596
596
  const search = createCodexSearchProvider({
597
597
  auth: codexAuth,
@@ -680,10 +680,10 @@ async function applyOwned(ctx: Context, config: Config): Promise<void> {
680
680
 
681
681
  // Only adapters and LLM-backed model resolution depend on this service. Its
682
682
  // child fiber may unload and reload without disturbing OAuth/Web ownership.
683
- ctx.inject(["llm"], (llmCtx) =>
684
- applyOwnedLlm(llmCtx, config, { grok, subscriptions, runtime, codexAuth, codexModels, logger }),
685
- );
686
- }
683
+ ctx.inject(["llm"], (llmCtx) =>
684
+ applyOwnedLlm(llmCtx, config, { grok, subscriptions, runtime, codexAuth, codexModels, logger }),
685
+ );
686
+ }
687
687
 
688
688
  interface OwnedLlmDependencies {
689
689
  readonly grok: GrokBuildSession;