dsh-codearts 1.1.3 → 1.1.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/lib/index.mjs CHANGED
@@ -1,9 +1,8 @@
1
- import { A as filterEnabledModels, C as rateLimitFrame, D as FALLBACK_CODEARTS_MODELS, E as CodeArtsCatalog, F as MANUAL_ACCOUNT_ID, I as codeartsAccountsPath, L as codeartsAuthPath, M as isBenefitModel, N as CodeArtsAccountStore, O as clearBenefitBlocked, P as CodeArtsCredentialStore, R as startLogin, S as prepareChatBody, T as upstreamErrorMessage, _ as isQueueableRate, a as SNAP_HOST, b as maxTokensCeilingFor, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isParamInvalidFrame, h as isConcurrencyCap, i as refreshCatalog, j as isBenefitBlocked, k as creditRatioLabel, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isTpmLimit, w as signedGet, x as pickDailyWelfareCampaign, y as isWelfareClaimedStatus } from "./usage-5YK7bW-e.mjs";
1
+ import { A as filterEnabledModels, C as rateLimitFrame, D as FALLBACK_CODEARTS_MODELS, E as CodeArtsCatalog, F as MANUAL_ACCOUNT_ID, I as codeartsAccountsPath, L as codeartsAuthPath, M as isBenefitModel, N as CodeArtsAccountStore, O as clearBenefitBlocked, P as CodeArtsCredentialStore, R as startLogin, S as prepareChatBody, T as upstreamErrorMessage, _ as isQueueableRate, a as SNAP_HOST, b as maxTokensCeilingFor, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isParamInvalidFrame, h as isConcurrencyCap, i as refreshCatalog, j as isBenefitBlocked, k as creditRatioLabel, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isTpmLimit, w as signedGet, x as pickDailyWelfareCampaign, y as isWelfareClaimedStatus } from "./usage-B0NfG8vZ.mjs";
2
+ import { i as lazyApi, r as createProvider } from "./models-CgKCibpk.mjs";
2
3
  import z from "@deepseek-ai/schemastery";
3
4
  import { randomBytes, timingSafeEqual } from "node:crypto";
4
5
  import { createServer } from "node:http";
5
- import { createProvider } from "@earendil-works/pi-ai";
6
- import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
7
6
  import { resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
8
7
  import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
9
8
  import * as settingsModule from "@deepseek-ai/dsh-settings";
@@ -545,6 +544,9 @@ var CodeArtsCreditCache = class {
545
544
  }
546
545
  };
547
546
  //#endregion
547
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.lazy.js
548
+ const openAICompletionsApi = () => lazyApi(() => import("./openai-completions-Cn5ZQvOO.mjs"));
549
+ //#endregion
548
550
  //#region src/adapter.ts
549
551
  /**
550
552
  * The `codearts` pi-ai provider.
@@ -734,8 +736,8 @@ var CodeArtsPiAiAdapter = class extends PiAiAdapter {
734
736
  * 用户只看得到一句「本轮运行失败」。
735
737
  *
736
738
  * 什么时候会拿到旧的那份:profile 顶层被别的插件 hoist 了一个低版本,而本插件的依赖
737
- * 没落地到自己的 `node_modules`。1.1.3 起 `@earendil-works/pi-ai` 已从 peerDependencies
738
- * 移进 dependencies,区间真正生效;这里再探测一次,把「版本不兼容」明说,而不是让
739
+ * 没落地到自己的 `node_modules`。1.1.4 起 pi-ai 直接打包进 `lib/`(不再经 npm 解析),
740
+ * 版本漂移在结构上不可能了;这里仍探测一次,把「产物损坏/不兼容」明说,而不是让
739
741
  * 每条消息各自崩在一个看不懂的 TypeError 上。
740
742
  *
741
743
  * 探测用能力而不是版本号:不依赖 package.json 能不能读到,也对未来的版本漂移免疫。
@@ -751,10 +753,10 @@ function probePiAiCompat() {
751
753
  return probe;
752
754
  }
753
755
  async function runProbe() {
754
- const hint = `需要 @earendil-works/pi-ai >= ${MIN_PI_AI_VERSION},请重装 dsh-codearts(1.1.3 起它自带这份依赖),或把 profile 顶层那份升级到同一区间`;
756
+ const hint = `需要 @earendil-works/pi-ai >= ${MIN_PI_AI_VERSION} 的行为;1.1.4 起它已打进插件产物,探测失败说明产物损坏或被改动,请重装 dsh-codearts`;
755
757
  let estimate;
756
758
  try {
757
- ({estimateMessageTokens: estimate} = await import("@earendil-works/pi-ai/utils/estimate"));
759
+ ({estimateMessageTokens: estimate} = await import("./estimate-BePoD-Np.mjs").then((n) => n.n));
758
760
  } catch (error) {
759
761
  return `pi-ai 不兼容:读不到 @earendil-works/pi-ai/utils/estimate(${messageOf(error)})。${hint}`;
760
762
  }
@@ -0,0 +1,377 @@
1
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js
2
+ var FifoQueue = class {
3
+ incoming = [];
4
+ outgoing = [];
5
+ get length() {
6
+ return this.incoming.length + this.outgoing.length;
7
+ }
8
+ enqueue(value) {
9
+ this.incoming.push(value);
10
+ }
11
+ dequeue() {
12
+ if (this.outgoing.length === 0) while (this.incoming.length > 0) this.outgoing.push(this.incoming.pop());
13
+ return this.outgoing.pop();
14
+ }
15
+ };
16
+ var EventStream = class {
17
+ queue = new FifoQueue();
18
+ waiting = new FifoQueue();
19
+ done = false;
20
+ finalResultPromise;
21
+ resolveFinalResult;
22
+ isComplete;
23
+ extractResult;
24
+ constructor(isComplete, extractResult) {
25
+ this.isComplete = isComplete;
26
+ this.extractResult = extractResult;
27
+ this.finalResultPromise = new Promise((resolve) => {
28
+ this.resolveFinalResult = resolve;
29
+ });
30
+ }
31
+ push(event) {
32
+ if (this.done) return;
33
+ if (this.isComplete(event)) {
34
+ this.done = true;
35
+ this.resolveFinalResult(this.extractResult(event));
36
+ }
37
+ const waiter = this.waiting.dequeue();
38
+ if (waiter) waiter({
39
+ value: event,
40
+ done: false
41
+ });
42
+ else this.queue.enqueue(event);
43
+ }
44
+ end(result) {
45
+ this.done = true;
46
+ if (result !== void 0) this.resolveFinalResult(result);
47
+ while (this.waiting.length > 0) this.waiting.dequeue()({
48
+ value: void 0,
49
+ done: true
50
+ });
51
+ }
52
+ async *[Symbol.asyncIterator]() {
53
+ while (true) if (this.queue.length > 0) yield this.queue.dequeue();
54
+ else if (this.done) return;
55
+ else {
56
+ const result = await new Promise((resolve) => this.waiting.enqueue(resolve));
57
+ if (result.done) return;
58
+ yield result.value;
59
+ }
60
+ }
61
+ result() {
62
+ return this.finalResultPromise;
63
+ }
64
+ };
65
+ /**
66
+ * Event stream of one assistant response. It also times the response: the final message (`done` or `error` event, or
67
+ * the result passed to `end()`) gets `durationMs`, measured with a monotonic clock from the stream's creation, unless
68
+ * the message already has one or its `timestamp` predates the stream. A stream that forwards a response which started
69
+ * elsewhere, such as a deferred result fetched later, therefore leaves it untimed.
70
+ */
71
+ var AssistantMessageEventStream = class extends EventStream {
72
+ #startedAt = Date.now();
73
+ #startedAtMonotonic = performance.now();
74
+ constructor() {
75
+ super((event) => event.type === "done" || event.type === "error", (event) => {
76
+ if (event.type === "done") return event.message;
77
+ else if (event.type === "error") return event.error;
78
+ throw new Error("Unexpected event type for final result");
79
+ });
80
+ }
81
+ push(event) {
82
+ if (event.type === "done") this.#time(event.message);
83
+ else if (event.type === "error") this.#time(event.error);
84
+ super.push(event);
85
+ }
86
+ end(result) {
87
+ if (result !== void 0) this.#time(result);
88
+ super.end(result);
89
+ }
90
+ #time(message) {
91
+ if (this.done || message.durationMs !== void 0 || message.timestamp < this.#startedAt) return;
92
+ message.durationMs = Math.max(0, Math.round(performance.now() - this.#startedAtMonotonic));
93
+ }
94
+ };
95
+ //#endregion
96
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/api/lazy.js
97
+ function createSetupErrorMessage(model, error, timestamp) {
98
+ return {
99
+ role: "assistant",
100
+ content: [],
101
+ api: model.api,
102
+ provider: model.provider,
103
+ model: model.id,
104
+ usage: {
105
+ input: 0,
106
+ output: 0,
107
+ cacheRead: 0,
108
+ cacheWrite: 0,
109
+ totalTokens: 0,
110
+ cost: {
111
+ input: 0,
112
+ output: 0,
113
+ cacheRead: 0,
114
+ cacheWrite: 0,
115
+ total: 0
116
+ }
117
+ },
118
+ stopReason: "error",
119
+ errorMessage: error instanceof Error ? error.message : String(error),
120
+ timestamp
121
+ };
122
+ }
123
+ function hasResult(source) {
124
+ return typeof source.result === "function";
125
+ }
126
+ async function forwardStream(target, source) {
127
+ for await (const event of source) target.push(event);
128
+ target.end(hasResult(source) ? await source.result() : void 0);
129
+ }
130
+ /**
131
+ * Returns a stream synchronously while running async setup (auth resolution,
132
+ * lazy module loading) behind it. Setup failures terminate the stream with an
133
+ * error event.
134
+ */
135
+ function lazyStream(model, setup) {
136
+ const startedAt = Date.now();
137
+ const outer = new AssistantMessageEventStream();
138
+ setup().then((inner) => forwardStream(outer, inner)).catch((error) => {
139
+ const message = createSetupErrorMessage(model, error, startedAt);
140
+ outer.push({
141
+ type: "error",
142
+ reason: "error",
143
+ error: message
144
+ });
145
+ outer.end(message);
146
+ });
147
+ return outer;
148
+ }
149
+ function lazyApi(load, capabilities) {
150
+ const api = {
151
+ stream: (model, context, options) => lazyStream(model, async () => (await load()).stream(model, context, options)),
152
+ streamSimple: (model, context, options) => lazyStream(model, async () => (await load()).streamSimple(model, context, options))
153
+ };
154
+ if (capabilities?.fetchDeferred) api.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {
155
+ const implementation = await load();
156
+ if (!implementation.fetchDeferred) throw new Error("API does not support deferred responses");
157
+ return implementation.fetchDeferred(model, handle, options);
158
+ });
159
+ if (capabilities?.cancelDeferred) api.cancelDeferred = async (model, handle, options) => {
160
+ const implementation = await load();
161
+ if (!implementation.cancelDeferred) throw new Error("API cannot cancel deferred responses");
162
+ await implementation.cancelDeferred(model, handle, options);
163
+ };
164
+ return api;
165
+ }
166
+ //#endregion
167
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js
168
+ function formatThrownValue(value) {
169
+ if (value instanceof Error) return value.message || value.name;
170
+ if (typeof value === "string") return value;
171
+ return String(value);
172
+ }
173
+ //#endregion
174
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/utils/models-error.js
175
+ var ModelsError = class extends Error {
176
+ code;
177
+ constructor(code, message, options) {
178
+ super(withCauseDetail(message, options?.cause), options);
179
+ this.name = "ModelsError";
180
+ this.code = code;
181
+ }
182
+ };
183
+ /** Callers surface `error.message` only, so keep the underlying reason in it. */
184
+ function withCauseDetail(message, cause) {
185
+ if (cause === void 0 || cause === null) return message;
186
+ const detail = formatThrownValue(cause).trim();
187
+ if (!detail || message.includes(detail)) return message;
188
+ return `${message}: ${detail}`;
189
+ }
190
+ //#endregion
191
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/utils/model-operations.js
192
+ /** The type of a model. Models without `type` are chat models. */
193
+ function getModelType(model) {
194
+ return model.type ?? "chat";
195
+ }
196
+ /** Runtime-checked model type narrowing, including legacy chat models without `type`. */
197
+ function isModelType(model, type) {
198
+ return getModelType(model) === type;
199
+ }
200
+ function imageErrorResult(model, error, aborted = false) {
201
+ return {
202
+ api: model.api,
203
+ provider: model.provider,
204
+ model: model.id,
205
+ output: [],
206
+ stopReason: aborted ? "aborted" : "error",
207
+ errorMessage: error instanceof Error ? error.message : String(error),
208
+ timestamp: Date.now()
209
+ };
210
+ }
211
+ function classifierErrorResult(model, error, aborted = false) {
212
+ return {
213
+ api: model.api,
214
+ provider: model.provider,
215
+ model: model.id,
216
+ answers: {},
217
+ stopReason: aborted ? "aborted" : "error",
218
+ errorMessage: error instanceof Error ? error.message : String(error),
219
+ timestamp: Date.now()
220
+ };
221
+ }
222
+ //#endregion
223
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@1.3.0_@aws-sdk+credential-provider-node@3.972.84_@smithy+signature-v4@5.7.4_ws@8.22.0_zod@4.6.5/node_modules/@earendil-works/pi-ai/dist/models.js
224
+ const KNOWN_MODEL_TYPES = {
225
+ chat: true,
226
+ image: true,
227
+ classifier: true
228
+ };
229
+ /** Models from stores and remote sources may have types that only newer versions know. */
230
+ function hasKnownModelType(model) {
231
+ return Object.hasOwn(KNOWN_MODEL_TYPES, getModelType(model));
232
+ }
233
+ /**
234
+ * Builds a provider from parts. Built-in provider factories and models.json
235
+ * custom providers both go through this. A single `api` streams all chat
236
+ * models; an `api` map dispatches on `model.api`, and a model whose api has
237
+ * no entry produces a stream error. One-shot operation maps dispatch on
238
+ * `model.api` the same way. At least one concrete implementation across
239
+ * `api`/`images`/`classifiers` is required; empty maps are rejected.
240
+ */
241
+ function createProvider(input) {
242
+ const single = input.api && typeof input.api.stream === "function" ? input.api : void 0;
243
+ const byApi = single || !input.api ? void 0 : input.api;
244
+ const images = input.images;
245
+ const classifiers = input.classifiers;
246
+ const streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== void 0);
247
+ const imageImplementations = Object.values(images ?? {}).filter((entry) => entry !== void 0);
248
+ const classifierImplementations = Object.values(classifiers ?? {}).filter((entry) => entry !== void 0);
249
+ if (streams.length === 0 && imageImplementations.length === 0 && classifierImplementations.length === 0) throw new Error(`Provider ${input.id}: at least one of "api", "images", or "classifiers" is required.`);
250
+ const baselineModels = input.models;
251
+ let dynamicModels = [];
252
+ const fetchModels = input.fetchModels;
253
+ const currentModels = () => {
254
+ const merged = [...baselineModels];
255
+ for (const model of dynamicModels) {
256
+ const index = merged.findIndex((entry) => getModelType(entry) === getModelType(model) && entry.id === model.id);
257
+ if (index >= 0) merged[index] = model;
258
+ else merged.push(model);
259
+ }
260
+ return merged;
261
+ };
262
+ const apiFor = (model) => single ?? byApi?.[model.api];
263
+ const dispatch = (model, run) => {
264
+ const streams = apiFor(model);
265
+ if (!streams) return lazyStream(model, async () => {
266
+ throw new ModelsError("stream", `Provider ${input.id} has no API implementation for "${model.api}"`);
267
+ });
268
+ return run(streams);
269
+ };
270
+ const provider = {
271
+ id: input.id,
272
+ name: input.name ?? input.id,
273
+ baseUrl: input.baseUrl,
274
+ headers: input.headers,
275
+ auth: input.auth,
276
+ getModels: () => currentModels().filter((model) => isModelType(model, "chat")),
277
+ getAllModels: currentModels,
278
+ refreshModels: fetchModels ? async (context) => {
279
+ if (context.stored) {
280
+ const restored = context.stored.models.filter((model) => model.provider === input.id).map((model) => model);
281
+ if (!await context.publish({ update: () => {
282
+ dynamicModels = restored;
283
+ } })) return;
284
+ }
285
+ if (!context.allowNetwork || context.signal.aborted) return;
286
+ const fetched = await fetchModels(context);
287
+ if (context.signal.aborted) return;
288
+ const refreshed = fetched.filter(hasKnownModelType);
289
+ await context.publish({
290
+ persist: {
291
+ models: refreshed,
292
+ checkedAt: Date.now()
293
+ },
294
+ update: () => {
295
+ dynamicModels = refreshed;
296
+ }
297
+ });
298
+ } : void 0,
299
+ filterModels: input.filterModels,
300
+ filterAllModels: input.filterAllModels,
301
+ stream: (model, context, options) => dispatch(model, (streams) => streams.stream(model, context, options)),
302
+ streamSimple: (model, context, options) => dispatch(model, (streams) => streams.streamSimple(model, context, options))
303
+ };
304
+ if (streams.some((entry) => entry.fetchDeferred !== void 0)) provider.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {
305
+ const implementation = apiFor(model);
306
+ if (!implementation?.fetchDeferred) throw new ModelsError("provider", `Provider ${input.id} does not support deferred responses for "${model.api}"`);
307
+ return implementation.fetchDeferred(model, handle, options);
308
+ });
309
+ if (streams.some((entry) => entry.cancelDeferred !== void 0)) provider.cancelDeferred = async (model, handle, options) => {
310
+ const implementation = apiFor(model);
311
+ if (!implementation?.cancelDeferred) throw new ModelsError("provider", `Provider ${input.id} cannot cancel deferred responses for "${model.api}"`);
312
+ await implementation.cancelDeferred(model, handle, options);
313
+ };
314
+ if (images && imageImplementations.length > 0) provider.generateImages = async (model, context, options) => {
315
+ const implementation = images[model.api];
316
+ if (!implementation) return imageErrorResult(model, new ModelsError("provider", `Provider ${input.id} has no image generation implementation for "${model.api}"`));
317
+ return implementation.generateImages(model, context, options);
318
+ };
319
+ if (classifiers && classifierImplementations.length > 0) provider.classify = async (model, context, options) => {
320
+ const implementation = classifiers[model.api];
321
+ if (!implementation) return classifierErrorResult(model, new ModelsError("provider", `Provider ${input.id} has no classifier implementation for "${model.api}"`));
322
+ return implementation.classify(model, context, options);
323
+ };
324
+ return provider;
325
+ }
326
+ function calculateCost(model, usage) {
327
+ const inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;
328
+ let rates = model.cost;
329
+ let matchedThreshold = -1;
330
+ for (const tier of model.cost.tiers ?? []) if (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {
331
+ rates = tier;
332
+ matchedThreshold = tier.inputTokensAbove;
333
+ }
334
+ const longWrite = usage.cacheWrite1h ?? 0;
335
+ const shortWrite = usage.cacheWrite - longWrite;
336
+ usage.cost.input = rates.input / 1e6 * usage.input;
337
+ usage.cost.output = rates.output / 1e6 * usage.output;
338
+ usage.cost.cacheRead = rates.cacheRead / 1e6 * usage.cacheRead;
339
+ usage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1e6;
340
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
341
+ return usage.cost;
342
+ }
343
+ const EXTENDED_THINKING_LEVELS = [
344
+ "off",
345
+ "minimal",
346
+ "low",
347
+ "medium",
348
+ "high",
349
+ "xhigh",
350
+ "max"
351
+ ];
352
+ function getSupportedThinkingLevels(model) {
353
+ if (!model.reasoning) return ["off"];
354
+ return EXTENDED_THINKING_LEVELS.filter((level) => {
355
+ const mapped = model.thinkingLevelMap?.[level];
356
+ if (mapped === null) return false;
357
+ if (level === "xhigh" || level === "max") return mapped !== void 0;
358
+ return true;
359
+ });
360
+ }
361
+ function clampThinkingLevel(model, level) {
362
+ const availableLevels = getSupportedThinkingLevels(model);
363
+ if (availableLevels.includes(level)) return level;
364
+ const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
365
+ if (requestedIndex === -1) return availableLevels[0] ?? "off";
366
+ for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {
367
+ const candidate = EXTENDED_THINKING_LEVELS[i];
368
+ if (availableLevels.includes(candidate)) return candidate;
369
+ }
370
+ for (let i = requestedIndex - 1; i >= 0; i--) {
371
+ const candidate = EXTENDED_THINKING_LEVELS[i];
372
+ if (availableLevels.includes(candidate)) return candidate;
373
+ }
374
+ return availableLevels[0] ?? "off";
375
+ }
376
+ //#endregion
377
+ export { AssistantMessageEventStream as a, lazyApi as i, clampThinkingLevel as n, createProvider as r, calculateCost as t };