dsh-subscriptions 0.2.2 → 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.
package/lib/index.js CHANGED
@@ -3834,7 +3834,13 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
3834
3834
  accounts: [],
3835
3835
  detail: error instanceof Error ? error.message : String(error)
3836
3836
  }))]));
3837
- return ok({ providers: Object.fromEntries(entries) });
3837
+ return ok({ providers: Object.fromEntries(entries.map(([provider, status]) => {
3838
+ const visibleModels = providerSettings?.visibleModels?.(provider);
3839
+ return [provider, {
3840
+ ...status,
3841
+ ...visibleModels === void 0 ? {} : { visibleModels }
3842
+ }];
3843
+ })) });
3838
3844
  }
3839
3845
  case "login": {
3840
3846
  const provider = readProvider(payload);
@@ -3931,7 +3937,7 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
3931
3937
  return ok({ ok: true });
3932
3938
  case "image": return ok(await controller.readImage(readImageRef(payload), signal));
3933
3939
  case "video": return ok(await controller.readVideo(readVideoName(payload), signal));
3934
- case "speed": return ok(await speed.speed(readSessionId(payload)));
3940
+ case "speed": return ok(await speed.speed(readSessionId(payload), payload.model === void 0 ? void 0 : readString(payload, "model")));
3935
3941
  case "setSpeed":
3936
3942
  await speed.setSpeed(readSessionId(payload), readSpeedTier(payload));
3937
3943
  return ok({ ok: true });
@@ -13038,9 +13044,17 @@ function toAntigravityTools(tools, model = "gemini") {
13038
13044
  })) }];
13039
13045
  }
13040
13046
  const SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
13041
- /** Gemini 3 validates the first function call in every model tool-call step. */
13047
+ /**
13048
+ * Whether this model validates thought signatures on replayed function calls.
13049
+ *
13050
+ * Gemini 3 and 4 require a signature on the first function call of each step;
13051
+ * foreign history uses the documented placeholder when no signature can be reused.
13052
+ * https://ai.google.dev/gemini-api/docs/generate-content/thought-signatures
13053
+ * Keep this scoped to these model families; future versions and unversioned aliases
13054
+ * need verification before enabling the same fallback.
13055
+ */
13042
13056
  function requiresThoughtSignatures(model) {
13043
- return model !== void 0 && /^gemini-3(?:[.-]|$)/i.test(model);
13057
+ return model !== void 0 && /^gemini-[34](?:[.-]|$)/i.test(model.trim());
13044
13058
  }
13045
13059
  /**
13046
13060
  * Convert resolved harness messages into Gemini contents. Function response
@@ -14749,6 +14763,15 @@ function validatePreferences(provider, input) {
14749
14763
  if (raw.promptCacheTtl !== "5m" && raw.promptCacheTtl !== "1h") throw new Error("promptCacheTtl must be \"5m\" or \"1h\"");
14750
14764
  result.promptCacheTtl = raw.promptCacheTtl;
14751
14765
  }
14766
+ if (raw.subagentSpeeds !== void 0) {
14767
+ if (provider !== "codex") throw new Error("subagent speeds are currently supported only for Codex");
14768
+ if (!raw.subagentSpeeds || typeof raw.subagentSpeeds !== "object" || Array.isArray(raw.subagentSpeeds)) throw new Error("subagent speeds must be a model-to-speed map");
14769
+ result.subagentSpeeds = Object.create(null);
14770
+ for (const [model, tier] of Object.entries(raw.subagentSpeeds)) {
14771
+ if (!model.trim() || tier !== "standard" && tier !== "fast") throw new Error("subagent speeds require a model id and either \"standard\" or \"fast\"");
14772
+ result.subagentSpeeds[model] = tier;
14773
+ }
14774
+ }
14752
14775
  if (raw.tools !== void 0) {
14753
14776
  if (!raw.tools || typeof raw.tools !== "object" || Array.isArray(raw.tools)) throw new Error("tools must be an object");
14754
14777
  result.tools = {};
@@ -14797,6 +14820,11 @@ var ProviderSettingsStore = class {
14797
14820
  const windows = this.current.providers[provider]?.contextWindows;
14798
14821
  return windows && Object.hasOwn(windows, model) ? windows[model] : void 0;
14799
14822
  }
14823
+ /** Read on every request so saved changes apply to the next subagent request. */
14824
+ subagentSpeed(model) {
14825
+ const speeds = this.current.providers.codex?.subagentSpeeds;
14826
+ return speeds && Object.hasOwn(speeds, model) ? speeds[model] : "standard";
14827
+ }
14800
14828
  /**
14801
14829
  * The Claude route's prompt-cache TTL override, read live so a saved change
14802
14830
  * takes effect from the next request without a restart. Absent means follow
@@ -15401,6 +15429,13 @@ function apply(ctx, config) {
15401
15429
  let grokTokens;
15402
15430
  const usageFetchers = {};
15403
15431
  const speedBySession = /* @__PURE__ */ new Map();
15432
+ const selectedSpeed = (sessionId, model) => {
15433
+ const explicit = speedBySession.get(sessionId);
15434
+ if (explicit !== void 0) return explicit;
15435
+ const agent = ctx.get("agents")?.get(sessionId);
15436
+ if (model !== void 0 && agent?.session.header.origin === "subagent") return preferences.subagentSpeed(parseAccountModelId(model)?.model ?? model);
15437
+ return "standard";
15438
+ };
15404
15439
  let codexAdapter;
15405
15440
  let claudeAdapter;
15406
15441
  let copilotAdapter;
@@ -15466,7 +15501,7 @@ function apply(ctx, config) {
15466
15501
  defaultEffortOf: (model) => defaultEffortOf("codex", model),
15467
15502
  contextWindowOf: (model) => preferences.contextWindow(model),
15468
15503
  pool: () => poolAdapter,
15469
- speedFor: (sessionId, model) => sessionId !== void 0 && speedBySession.get(sessionId) === "fast" && adapter.supportsFastTier(model)
15504
+ speedFor: (sessionId, model) => sessionId !== void 0 && selectedSpeed(sessionId, model) === "fast" && adapter.supportsFastTier(model)
15470
15505
  });
15471
15506
  codexAdapter = adapter;
15472
15507
  adapters.set("codex", adapter);
@@ -15682,24 +15717,23 @@ function apply(ctx, config) {
15682
15717
  adapter.listModels = async (route) => (await list(route)).filter((model) => preferences.visible(provider, model.id));
15683
15718
  }
15684
15719
  const speed = {
15685
- async speed(sessionId) {
15720
+ async speed(sessionId, model) {
15686
15721
  const fastModels = await codexAdapter?.fastCapableModels() ?? [];
15687
15722
  const accountPreferences = preferences.get("codex").accounts;
15688
15723
  for (const { key } of await codexTokens?.list() ?? []) {
15689
15724
  if (!accountPreferences || !Object.hasOwn(accountPreferences, key) || accountPreferences[key].independentEntry !== true) continue;
15690
- for (const model of [...fastModels]) {
15691
- if (parseAccountModelId(model)) continue;
15692
- if (await codexAdapter?.supportsFastTier(model, key)) fastModels.push(accountModelId(key, model));
15725
+ for (const model$1 of [...fastModels]) {
15726
+ if (parseAccountModelId(model$1)) continue;
15727
+ if (await codexAdapter?.supportsFastTier(model$1, key)) fastModels.push(accountModelId(key, model$1));
15693
15728
  }
15694
15729
  }
15695
15730
  return {
15696
- tier: speedBySession.get(sessionId) ?? "standard",
15731
+ tier: selectedSpeed(sessionId, model),
15697
15732
  fastModels
15698
15733
  };
15699
15734
  },
15700
15735
  async setSpeed(sessionId, tier) {
15701
- if (tier === "standard") speedBySession.delete(sessionId);
15702
- else speedBySession.set(sessionId, tier);
15736
+ speedBySession.set(sessionId, tier);
15703
15737
  }
15704
15738
  };
15705
15739
  const modelDefaults = {
@@ -15831,6 +15865,7 @@ function apply(ctx, config) {
15831
15865
  }) } : {},
15832
15866
  ...providers.includes("claude") ? { claude: presentedVersion(claudeVersion) } : {}
15833
15867
  }, resetRedemption, (provider, account) => poolHealth?.clear(provider, account)), speed, modelDefaults, {
15868
+ visibleModels: (provider) => preferences.get(provider).visibleModels,
15834
15869
  async get(provider, force) {
15835
15870
  await loadModelDefaults();
15836
15871
  const adapter = adapters.get(provider);
@@ -15849,6 +15884,7 @@ function apply(ctx, config) {
15849
15884
  models: await withTimeout((signal) => adapter.listOwnModels(provider, account.key, signal), DISCOVERY_TIMEOUT_MS).catch(() => void 0)
15850
15885
  })));
15851
15886
  const tierIds = new Set((await poolAdapter?.modelsForProvider(provider).catch(() => []) ?? []).map((model) => model.id));
15887
+ const fastModels = new Set(provider === "codex" ? await codexAdapter?.fastCapableModels() ?? [] : []);
15852
15888
  const rows = await Promise.all(models.map(async (model) => {
15853
15889
  const contexts = [];
15854
15890
  if (provider === "codex" && codexAdapter) {
@@ -15873,6 +15909,7 @@ function apply(ctx, config) {
15873
15909
  name: name$1
15874
15910
  })) ?? [],
15875
15911
  configured: defaultEffortOf(provider, model.id),
15912
+ ...provider === "codex" ? { fastTier: !tierIds.has(model.id) && fastModels.has(model.id) } : {},
15876
15913
  ...contexts.length ? {
15877
15914
  defaultContextWindow: Math.min(...contexts.map((entry) => entry.default)),
15878
15915
  maxContextWindow: Math.min(...contexts.map((entry) => entry.max))
@@ -8,6 +8,7 @@ export declare const PROVIDER_TOOLS: {
8
8
  readonly antigravity: readonly [];
9
9
  };
10
10
  export type SubscriptionTool = 'image_generate' | 'video_generate' | 'x_search' | 'web_search';
11
+ export type SubagentSpeedTier = 'standard' | 'fast';
11
12
  export interface AccountPreferences {
12
13
  alias?: string;
13
14
  /** Absent means included. */
@@ -22,6 +23,8 @@ export interface ProviderPreferences {
22
23
  /** Absent follows discovery; an explicit selection hides newly discovered models. */
23
24
  visibleModels?: string[];
24
25
  contextWindows?: Record<string, number>;
26
+ /** Codex only: per-model defaults for subagents, independent of main-session speed. */
27
+ subagentSpeeds?: Record<string, SubagentSpeedTier>;
25
28
  tools?: Partial<Record<SubscriptionTool, boolean>>;
26
29
  /**
27
30
  * Claude only: overrides the `claudePromptCacheTtl` plugin config for this
@@ -40,6 +43,8 @@ export declare class ProviderSettingsStore {
40
43
  visible(provider: ProviderId, model: string): boolean;
41
44
  /** The user's local context-window override for one model; absent follows the provider. */
42
45
  contextWindow(model: string, provider?: ProviderId): number | undefined;
46
+ /** Read on every request so saved changes apply to the next subagent request. */
47
+ subagentSpeed(model: string): SubagentSpeedTier;
43
48
  /**
44
49
  * The Claude route's prompt-cache TTL override, read live so a saved change
45
50
  * takes effect from the next request without a restart. Absent means follow
@@ -85,6 +85,22 @@ export function validatePreferences(provider, input) {
85
85
  }
86
86
  result.promptCacheTtl = raw.promptCacheTtl;
87
87
  }
88
+ if (raw.subagentSpeeds !== undefined) {
89
+ if (provider !== 'codex')
90
+ throw new Error('subagent speeds are currently supported only for Codex');
91
+ if (!raw.subagentSpeeds ||
92
+ typeof raw.subagentSpeeds !== 'object' ||
93
+ Array.isArray(raw.subagentSpeeds)) {
94
+ throw new Error('subagent speeds must be a model-to-speed map');
95
+ }
96
+ result.subagentSpeeds = Object.create(null);
97
+ for (const [model, tier] of Object.entries(raw.subagentSpeeds)) {
98
+ if (!model.trim() || (tier !== 'standard' && tier !== 'fast')) {
99
+ throw new Error('subagent speeds require a model id and either "standard" or "fast"');
100
+ }
101
+ result.subagentSpeeds[model] = tier;
102
+ }
103
+ }
88
104
  if (raw.tools !== undefined) {
89
105
  if (!raw.tools || typeof raw.tools !== 'object' || Array.isArray(raw.tools))
90
106
  throw new Error('tools must be an object');
@@ -144,6 +160,11 @@ export class ProviderSettingsStore {
144
160
  const windows = this.current.providers[provider]?.contextWindows;
145
161
  return windows && Object.hasOwn(windows, model) ? windows[model] : undefined;
146
162
  }
163
+ /** Read on every request so saved changes apply to the next subagent request. */
164
+ subagentSpeed(model) {
165
+ const speeds = this.current.providers.codex?.subagentSpeeds;
166
+ return speeds && Object.hasOwn(speeds, model) ? speeds[model] : 'standard';
167
+ }
147
168
  /**
148
169
  * The Claude route's prompt-cache TTL override, read live so a saved change
149
170
  * takes effect from the next request without a restart. Absent means follow
@@ -88,9 +88,17 @@ export function toAntigravityTools(tools, model = 'gemini') {
88
88
  ];
89
89
  }
90
90
  const SKIP_THOUGHT_SIGNATURE_VALIDATOR = 'skip_thought_signature_validator';
91
- /** Gemini 3 validates the first function call in every model tool-call step. */
91
+ /**
92
+ * Whether this model validates thought signatures on replayed function calls.
93
+ *
94
+ * Gemini 3 and 4 require a signature on the first function call of each step;
95
+ * foreign history uses the documented placeholder when no signature can be reused.
96
+ * https://ai.google.dev/gemini-api/docs/generate-content/thought-signatures
97
+ * Keep this scoped to these model families; future versions and unversioned aliases
98
+ * need verification before enabling the same fallback.
99
+ */
92
100
  function requiresThoughtSignatures(model) {
93
- return model !== undefined && /^gemini-3(?:[.-]|$)/i.test(model);
101
+ return model !== undefined && /^gemini-[34](?:[.-]|$)/i.test(model.trim());
94
102
  }
95
103
  /**
96
104
  * Convert resolved harness messages into Gemini contents. Function response
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-subscriptions",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Unified subscription providers and usage dashboard for DeepSeek Harness",
5
5
  "icon": "./icon.svg",
6
6
  "license": "MIT",
@@ -90,6 +90,7 @@
90
90
  },
91
91
  "devDependencies": {
92
92
  "@deepseek-ai/cordis": "4.0.4",
93
+ "@deepseek-ai/dsh-agent": "0.1.7-rc.2",
93
94
  "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
94
95
  "@deepseek-ai/dsh-attachment": "0.1.7-rc.2",
95
96
  "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2",