@awiki/dsh-plugin 0.2.4 → 0.2.5

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 (115) hide show
  1. package/README.md +80 -11
  2. package/README.zh.md +67 -12
  3. package/THIRD_PARTY_NOTICES.md +8 -1
  4. package/cordis.patch.yml +13 -0
  5. package/lib/client.js +8223 -1939
  6. package/lib/client.js.map +1 -1
  7. package/lib/index.js +1486 -59
  8. package/lib/model-proxy-contract.js +89 -0
  9. package/lib/model-proxy.js +383 -0
  10. package/lib/provider.js +2 -1
  11. package/lib/sdk-adapter-DKgkyApB.mjs +669 -0
  12. package/lib/typert.host.js +470 -482
  13. package/lib/typert.remote-client.d.ts +15 -1
  14. package/lib/typert.remote-client.d.ts.map +1 -1
  15. package/lib/typert.remote-client.js +469 -103
  16. package/lib/types/attachment-cache.d.ts +28 -0
  17. package/lib/types/attachment-cache.d.ts.map +1 -0
  18. package/lib/types/attachment-cache.js +194 -0
  19. package/lib/types/attachment-cache.js.map +1 -0
  20. package/lib/types/client/AwikiMail.d.ts +14 -0
  21. package/lib/types/client/AwikiMail.d.ts.map +1 -0
  22. package/lib/types/client/AwikiMail.js +260 -0
  23. package/lib/types/client/AwikiMail.js.map +1 -0
  24. package/lib/types/client/AwikiOnboarding.d.ts +22 -0
  25. package/lib/types/client/AwikiOnboarding.d.ts.map +1 -0
  26. package/lib/types/client/AwikiOnboarding.js +87 -0
  27. package/lib/types/client/AwikiOnboarding.js.map +1 -0
  28. package/lib/types/client/AwikiOverlay.d.ts +15 -0
  29. package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
  30. package/lib/types/client/AwikiOverlay.js +251 -20
  31. package/lib/types/client/AwikiOverlay.js.map +1 -1
  32. package/lib/types/client/AwikiSettingsSection.d.ts +20 -4
  33. package/lib/types/client/AwikiSettingsSection.d.ts.map +1 -1
  34. package/lib/types/client/AwikiSettingsSection.js +279 -23
  35. package/lib/types/client/AwikiSettingsSection.js.map +1 -1
  36. package/lib/types/client/RechargeComingSoonDialog.d.ts +11 -0
  37. package/lib/types/client/RechargeComingSoonDialog.d.ts.map +1 -0
  38. package/lib/types/client/RechargeComingSoonDialog.js +8 -0
  39. package/lib/types/client/RechargeComingSoonDialog.js.map +1 -0
  40. package/lib/types/client/controller.d.ts +82 -4
  41. package/lib/types/client/controller.d.ts.map +1 -1
  42. package/lib/types/client/controller.js +517 -74
  43. package/lib/types/client/controller.js.map +1 -1
  44. package/lib/types/client/image-cache.d.ts +20 -0
  45. package/lib/types/client/image-cache.d.ts.map +1 -0
  46. package/lib/types/client/image-cache.js +177 -0
  47. package/lib/types/client/image-cache.js.map +1 -0
  48. package/lib/types/client/index.d.ts +2 -0
  49. package/lib/types/client/index.d.ts.map +1 -1
  50. package/lib/types/client/index.js +84 -41
  51. package/lib/types/client/index.js.map +1 -1
  52. package/lib/types/client/model-account-settings-availability.d.ts +4 -0
  53. package/lib/types/client/model-account-settings-availability.d.ts.map +1 -0
  54. package/lib/types/client/model-account-settings-availability.js +4 -0
  55. package/lib/types/client/model-account-settings-availability.js.map +1 -0
  56. package/lib/types/client/model-availability-controller.d.ts +27 -0
  57. package/lib/types/client/model-availability-controller.d.ts.map +1 -0
  58. package/lib/types/client/model-availability-controller.js +111 -0
  59. package/lib/types/client/model-availability-controller.js.map +1 -0
  60. package/lib/types/client/model-proxy-controller.d.ts +41 -0
  61. package/lib/types/client/model-proxy-controller.d.ts.map +1 -0
  62. package/lib/types/client/model-proxy-controller.js +241 -0
  63. package/lib/types/client/model-proxy-controller.js.map +1 -0
  64. package/lib/types/client/recharge-availability.d.ts +6 -0
  65. package/lib/types/client/recharge-availability.d.ts.map +1 -0
  66. package/lib/types/client/recharge-availability.js +6 -0
  67. package/lib/types/client/recharge-availability.js.map +1 -0
  68. package/lib/types/client/settings-locales.d.ts +1 -1
  69. package/lib/types/client/settings-locales.d.ts.map +1 -1
  70. package/lib/types/client/settings-locales.js +180 -2
  71. package/lib/types/client/settings-locales.js.map +1 -1
  72. package/lib/types/client/slots.d.ts +15 -2
  73. package/lib/types/client/slots.d.ts.map +1 -1
  74. package/lib/types/index.d.ts +56 -2
  75. package/lib/types/index.d.ts.map +1 -1
  76. package/lib/types/index.js +462 -31
  77. package/lib/types/index.js.map +1 -1
  78. package/lib/types/listener-state.d.ts +23 -0
  79. package/lib/types/listener-state.d.ts.map +1 -0
  80. package/lib/types/listener-state.js +124 -0
  81. package/lib/types/listener-state.js.map +1 -0
  82. package/lib/types/listener.d.ts +96 -0
  83. package/lib/types/listener.d.ts.map +1 -0
  84. package/lib/types/listener.js +575 -0
  85. package/lib/types/listener.js.map +1 -0
  86. package/lib/types/mail.d.ts +8 -0
  87. package/lib/types/mail.d.ts.map +1 -0
  88. package/lib/types/mail.js +75 -0
  89. package/lib/types/mail.js.map +1 -0
  90. package/lib/types/model-proxy-contract.d.ts +61 -0
  91. package/lib/types/model-proxy-contract.d.ts.map +1 -0
  92. package/lib/types/model-proxy-contract.js +129 -0
  93. package/lib/types/model-proxy-contract.js.map +1 -0
  94. package/lib/types/model-proxy.d.ts +14 -0
  95. package/lib/types/model-proxy.d.ts.map +1 -0
  96. package/lib/types/model-proxy.js +371 -0
  97. package/lib/types/model-proxy.js.map +1 -0
  98. package/lib/types/provider-api.d.ts +78 -2
  99. package/lib/types/provider-api.d.ts.map +1 -1
  100. package/lib/types/provider.d.ts.map +1 -1
  101. package/lib/types/provider.js +1 -0
  102. package/lib/types/provider.js.map +1 -1
  103. package/lib/types/sdk-adapter.d.ts +26 -2
  104. package/lib/types/sdk-adapter.d.ts.map +1 -1
  105. package/lib/types/sdk-adapter.js +380 -24
  106. package/lib/types/sdk-adapter.js.map +1 -1
  107. package/lib/types/tools.d.ts +10 -0
  108. package/lib/types/tools.d.ts.map +1 -1
  109. package/lib/types/tools.js +98 -0
  110. package/lib/types/tools.js.map +1 -1
  111. package/lib/types/types.d.ts +103 -1
  112. package/lib/types/types.d.ts.map +1 -1
  113. package/lib/types/types.js.map +1 -1
  114. package/package.json +30 -5
  115. package/lib/sdk-adapter-DK6RqV-c.mjs +0 -355
@@ -0,0 +1,89 @@
1
+ //#region lib/types/model-proxy-contract.js
2
+ /** Browser-safe contracts for the loopback AWiki-hosted DeepSeek proxy channel. */
3
+ const AWIKI_MODEL_PROXY_RPC_CHANNEL = "/awiki-model-proxy";
4
+ const AWIKI_MODEL_PROXY_RPC_ENDPOINTS = {
5
+ status: "status",
6
+ usage: "usage",
7
+ setEnabled: "set-enabled",
8
+ createRecharge: "create-recharge",
9
+ rechargeStatus: "recharge-status",
10
+ closeRecharge: "close-recharge"
11
+ };
12
+ function decodeModelProxyStatus(value) {
13
+ if (!isRecord(value) || typeof value.enabled !== "boolean") return void 0;
14
+ const account = decodeAccount(value.account);
15
+ if (account === void 0) return void 0;
16
+ const pendingRechargeOrder = value.pending_recharge_order === null ? null : decodeRechargeOrder(value.pending_recharge_order);
17
+ if (pendingRechargeOrder === void 0 || pendingRechargeOrder !== null && pendingRechargeOrder.status !== "pending") return void 0;
18
+ if (value.recommended_model !== "deepseek-v4-flash" || !Array.isArray(value.models) || value.models.length !== 2 || value.models[0] !== "deepseek-v4-flash" || value.models[1] !== "deepseek-v4-pro") return void 0;
19
+ return {
20
+ enabled: value.enabled,
21
+ account,
22
+ pending_recharge_order: pendingRechargeOrder,
23
+ recommended_model: "deepseek-v4-flash",
24
+ models: ["deepseek-v4-flash", "deepseek-v4-pro"]
25
+ };
26
+ }
27
+ function decodeModelProxyUsage(value) {
28
+ if (!Array.isArray(value)) return void 0;
29
+ const usage = value.map(decodeUsage);
30
+ return usage.every((item) => item !== void 0) ? usage : void 0;
31
+ }
32
+ function decodeRechargeOrder(value) {
33
+ if (!isRecord(value) || typeof value.out_trade_no !== "string" || !Number.isSafeInteger(value.amount_cents) || ![
34
+ "pending",
35
+ "paid",
36
+ "closed"
37
+ ].includes(String(value.status)) || typeof value.provider !== "string" || typeof value.payment_method !== "string" || typeof value.created_at !== "string") return void 0;
38
+ if (value.payment_action !== void 0 && (!isRecord(value.payment_action) || !["redirect_url", "qr_code"].includes(String(value.payment_action.type)) || typeof value.payment_action.data !== "string")) return void 0;
39
+ const action = value.payment_action;
40
+ return {
41
+ out_trade_no: value.out_trade_no,
42
+ amount_cents: value.amount_cents,
43
+ status: value.status,
44
+ provider: value.provider,
45
+ payment_method: value.payment_method,
46
+ created_at: value.created_at,
47
+ ...action === void 0 ? {} : { payment_action: {
48
+ type: action.type,
49
+ data: action.data
50
+ } }
51
+ };
52
+ }
53
+ function decodeCloseRechargeResult(value) {
54
+ return isRecord(value) && value.closed === true ? { closed: true } : void 0;
55
+ }
56
+ function decodeAccount(value) {
57
+ if (!(isRecord(value) && typeof value.did === "string" && Number.isSafeInteger(value.balance_cents) && typeof value.balance === "string" && value.currency === "CNY" && typeof value.model_access_available === "boolean" && (value.model_access_reason === null || typeof value.model_access_reason === "string") && ["strict", "development_bypass"].includes(String(value.billing_mode)) && typeof value.payments_available === "boolean")) return void 0;
58
+ return {
59
+ did: value.did,
60
+ balance_cents: value.balance_cents,
61
+ balance: value.balance,
62
+ currency: "CNY",
63
+ model_access_available: value.model_access_available,
64
+ model_access_reason: value.model_access_reason,
65
+ billing_mode: value.billing_mode,
66
+ payments_available: value.payments_available
67
+ };
68
+ }
69
+ function decodeUsage(value) {
70
+ if (!(isRecord(value) && Number.isSafeInteger(value.id) && typeof value.endpoint === "string" && typeof value.model === "string" && Number.isSafeInteger(value.cache_hit_tokens) && Number.isSafeInteger(value.cache_miss_tokens) && Number.isSafeInteger(value.completion_tokens) && ["strict", "development_bypass"].includes(String(value.billing_mode)) && (value.calculated_cost_micros === null || Number.isSafeInteger(value.calculated_cost_micros)) && Number.isSafeInteger(value.charged_micros) && typeof value.estimated === "boolean" && typeof value.created_at === "string")) return void 0;
71
+ return {
72
+ id: value.id,
73
+ endpoint: value.endpoint,
74
+ model: value.model,
75
+ cache_hit_tokens: value.cache_hit_tokens,
76
+ cache_miss_tokens: value.cache_miss_tokens,
77
+ completion_tokens: value.completion_tokens,
78
+ billing_mode: value.billing_mode,
79
+ calculated_cost_micros: value.calculated_cost_micros,
80
+ charged_micros: value.charged_micros,
81
+ estimated: value.estimated,
82
+ created_at: value.created_at
83
+ };
84
+ }
85
+ function isRecord(value) {
86
+ return typeof value === "object" && value !== null && !Array.isArray(value);
87
+ }
88
+ //#endregion
89
+ export { AWIKI_MODEL_PROXY_RPC_CHANNEL, AWIKI_MODEL_PROXY_RPC_ENDPOINTS, decodeCloseRechargeResult, decodeModelProxyStatus, decodeModelProxyUsage, decodeRechargeOrder };
@@ -0,0 +1,383 @@
1
+ import { AWIKI_MODEL_PROXY_RPC_CHANNEL, AWIKI_MODEL_PROXY_RPC_ENDPOINTS, decodeModelProxyStatus, decodeModelProxyUsage, decodeRechargeOrder } from "./model-proxy-contract.js";
2
+ import z from "@deepseek-ai/schemastery";
3
+ import { settingsNamespace } from "@deepseek-ai/dsh-settings";
4
+ import { LlmError, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
5
+ import { getOrCreateAnonymousUserId } from "@deepseek-ai/dsh-anonymous-user-id";
6
+ import { credentialRef } from "@deepseek-ai/dsh-credentials";
7
+ import { DeepSeekAdapter } from "@deepseek-ai/dsh-llm-deepseek";
8
+ //#region lib/types/model-proxy.js
9
+ /** Host-only AWiki-authenticated model-proxy provider and loopback account API. */
10
+ const name = "awiki-model-proxy";
11
+ const inject = [
12
+ "awiki",
13
+ "llm",
14
+ "settings",
15
+ "agentDefaultModel",
16
+ "connection"
17
+ ];
18
+ const SETTINGS = settingsNamespace("awiki-model-proxy");
19
+ const PROVIDER = "awiki-deepseek";
20
+ const FLASH = "deepseek-v4-flash";
21
+ const PRO = "deepseek-v4-pro";
22
+ const MODELS = [FLASH, PRO];
23
+ const PROVIDER_NAME = "AWiki-hosted DeepSeek";
24
+ const SettingsSchema = z.object({
25
+ enabled: z.boolean().default(false),
26
+ previousProvider: z.string(),
27
+ previousModel: z.string(),
28
+ previousReasoningEffort: z.string()
29
+ });
30
+ const Config = z.object({
31
+ baseURL: z.string().default("https://model.awiki.info"),
32
+ contextWindow: z.number().step(1).min(1).default(1e6),
33
+ maxTokens: z.number().step(1).min(1).default(8192),
34
+ tokenRefreshSkewSeconds: z.number().step(1).min(0).default(60)
35
+ });
36
+ function apply(ctx, input = {}) {
37
+ const config = resolveConfig(input);
38
+ const settings = ctx.settings.register(SETTINGS, SettingsSchema, {
39
+ base: { enabled: false },
40
+ applies: "live"
41
+ });
42
+ const token = new ModelProxyToken(ctx, config);
43
+ const adapter = new AwikiHostedDeepSeekAdapter({
44
+ options: () => ({
45
+ baseURL: new URL("/v1", config.baseURL).toString().replace(/\/$/, ""),
46
+ apiKeyEnv: credentialRef("AWIKI_MODEL_PROXY_TOKEN"),
47
+ defaults: {},
48
+ maxTokens: config.maxTokens,
49
+ defaultContextWindow: config.contextWindow,
50
+ models: [{
51
+ id: FLASH,
52
+ name: "DeepSeek V4 Flash",
53
+ contextWindow: config.contextWindow,
54
+ maxTokens: config.maxTokens
55
+ }, {
56
+ id: PRO,
57
+ name: "DeepSeek V4 Pro",
58
+ contextWindow: config.contextWindow,
59
+ maxTokens: config.maxTokens
60
+ }],
61
+ streamIdleTimeoutMs: 3e5,
62
+ retryPolicy: resolveRetryPolicy(void 0, "awiki-model-proxy: retryPolicy")
63
+ }),
64
+ resolveApiKey: () => token.get(),
65
+ resolveUserId: () => getOrCreateAnonymousUserId()
66
+ });
67
+ let route;
68
+ let directory;
69
+ let sessionStatus;
70
+ let sessionRefresh;
71
+ const sync = () => {
72
+ const enabled = settings.get().enabled;
73
+ if (enabled && sessionStatus === "active" && route === void 0) {
74
+ directory = ctx.llm.registerConfigurableProviders([{
75
+ provider: PROVIDER,
76
+ displayName: PROVIDER_NAME,
77
+ settingsNs: SETTINGS,
78
+ settingsPath: []
79
+ }]);
80
+ route = ctx.llm.registerAdapter([PROVIDER], adapter);
81
+ } else if ((!enabled || sessionStatus !== "active") && route !== void 0) {
82
+ route();
83
+ directory?.();
84
+ route = void 0;
85
+ directory = void 0;
86
+ token.clear();
87
+ }
88
+ };
89
+ const publishSession = (session) => {
90
+ sessionStatus = session.status;
91
+ token.clear();
92
+ sync();
93
+ };
94
+ const refreshSession = () => {
95
+ if (sessionStatus !== void 0) return Promise.resolve(sessionStatus);
96
+ return sessionRefresh ??= ctx.awiki.getSession().then((result) => {
97
+ if (!result.ok) return void 0;
98
+ publishSession(result.value);
99
+ return result.value.status;
100
+ }).finally(() => {
101
+ sessionRefresh = void 0;
102
+ });
103
+ };
104
+ sync();
105
+ refreshSession();
106
+ ctx.on("awiki/session", (session) => {
107
+ publishSession(session);
108
+ });
109
+ ctx.on("settings/updated", (namespace) => {
110
+ if (namespace === SETTINGS) sync();
111
+ });
112
+ ctx.effect(() => () => {
113
+ route?.();
114
+ directory?.();
115
+ token.clear();
116
+ }, "awiki-model-proxy: release adapter and token");
117
+ const handler = createRpcHandler(ctx, config, token, () => settings.get(), sync, async () => await refreshSession() === "active");
118
+ ctx.connection.rpc.handle(AWIKI_MODEL_PROXY_RPC_CHANNEL, handler, { authority: "loopback" });
119
+ }
120
+ var ModelProxyToken = class {
121
+ ctx;
122
+ config;
123
+ value;
124
+ expiresAt = 0;
125
+ pending;
126
+ generation = 0;
127
+ constructor(ctx, config) {
128
+ this.ctx = ctx;
129
+ this.config = config;
130
+ }
131
+ get() {
132
+ if (this.value !== void 0 && Date.now() < this.expiresAt - this.config.tokenRefreshSkewMs) return Promise.resolve(this.value);
133
+ if (this.pending !== void 0) return this.pending;
134
+ const generation = this.generation;
135
+ const pending = this.refresh(generation).finally(() => {
136
+ if (this.pending === pending) this.pending = void 0;
137
+ });
138
+ this.pending = pending;
139
+ return pending;
140
+ }
141
+ clear() {
142
+ this.generation += 1;
143
+ this.value = void 0;
144
+ this.expiresAt = 0;
145
+ this.pending = void 0;
146
+ }
147
+ invalidate(value) {
148
+ if (this.value === value) this.clear();
149
+ }
150
+ async refresh(generation) {
151
+ const response = await this.ctx.awiki.externalHttpAuth.dispatch(new Request(new URL("/api/token", this.config.baseURL), { method: "POST" }), (request) => fetch(request));
152
+ if (!response.ok) throw await modelProxyError(response, "AWiki-hosted DeepSeek authentication failed");
153
+ const value = await response.json();
154
+ if (!isRecord(value) || typeof value.access_token !== "string" || value.access_token.length === 0 || !Number.isSafeInteger(value.expires_in) || value.expires_in <= 0) throw new LlmError("AWiki-hosted DeepSeek authentication returned an invalid response", "AUTH");
155
+ const token = value;
156
+ if (generation !== this.generation) throw new LlmError("AWiki-hosted DeepSeek authentication state changed", "AUTH");
157
+ this.value = token.access_token;
158
+ this.expiresAt = Date.now() + token.expires_in * 1e3;
159
+ return token.access_token;
160
+ }
161
+ };
162
+ var AwikiHostedDeepSeekAdapter = class extends DeepSeekAdapter {
163
+ providerInfo(provider) {
164
+ return {
165
+ id: provider,
166
+ name: PROVIDER_NAME
167
+ };
168
+ }
169
+ };
170
+ function createRpcHandler(ctx, config, token, currentSettings, sync, sessionActive) {
171
+ return async (endpoint, payload, signal) => {
172
+ try {
173
+ if (signal.aborted) throw new Error("request cancelled");
174
+ if (!await sessionActive()) throw new LlmError("Sign in to AWiki before using AWiki-hosted DeepSeek.", "AUTH");
175
+ if (endpoint === AWIKI_MODEL_PROXY_RPC_ENDPOINTS.status) return {
176
+ ok: true,
177
+ value: await status(config, token, currentSettings().enabled, signal)
178
+ };
179
+ if (endpoint === AWIKI_MODEL_PROXY_RPC_ENDPOINTS.usage) {
180
+ const value = await authenticatedJson(config, token, "/api/usage", { signal });
181
+ const usage = decodeModelProxyUsage(value);
182
+ if (usage === void 0) throw new Error("invalid usage response");
183
+ return {
184
+ ok: true,
185
+ value: usage
186
+ };
187
+ }
188
+ if (endpoint === AWIKI_MODEL_PROXY_RPC_ENDPOINTS.createRecharge) {
189
+ if (!isRecord(payload) || !Number.isSafeInteger(payload.amount_cents)) return badRequest();
190
+ const value = await authenticatedJson(config, token, "/api/recharge/orders", {
191
+ method: "POST",
192
+ headers: {
193
+ "content-type": "application/json",
194
+ "idempotency-key": globalThis.crypto.randomUUID()
195
+ },
196
+ body: JSON.stringify({ amount_cents: payload.amount_cents }),
197
+ signal
198
+ });
199
+ const order = decodeRechargeOrder(value);
200
+ if (order === void 0 || order.payment_action === void 0) throw new Error("invalid recharge response");
201
+ return {
202
+ ok: true,
203
+ value: order
204
+ };
205
+ }
206
+ if (endpoint === AWIKI_MODEL_PROXY_RPC_ENDPOINTS.rechargeStatus) {
207
+ if (!isRecord(payload) || typeof payload.out_trade_no !== "string") return badRequest();
208
+ const value = await authenticatedJson(config, token, `/api/recharge/orders/${encodeURIComponent(payload.out_trade_no)}`, { signal });
209
+ const order = decodeRechargeOrder(value);
210
+ if (order === void 0) throw new Error("invalid recharge status response");
211
+ return {
212
+ ok: true,
213
+ value: order
214
+ };
215
+ }
216
+ if (endpoint === AWIKI_MODEL_PROXY_RPC_ENDPOINTS.closeRecharge) {
217
+ if (!isRecord(payload) || typeof payload.out_trade_no !== "string") return badRequest();
218
+ if ((await authenticatedResponse(config, token, `/api/recharge/orders/${encodeURIComponent(payload.out_trade_no)}/close`, {
219
+ method: "POST",
220
+ signal
221
+ })).status !== 204) throw new Error("invalid recharge close response");
222
+ return {
223
+ ok: true,
224
+ value: { closed: true }
225
+ };
226
+ }
227
+ if (endpoint === AWIKI_MODEL_PROXY_RPC_ENDPOINTS.setEnabled) {
228
+ if (!isRecord(payload) || typeof payload.enabled !== "boolean") return badRequest();
229
+ if (payload.enabled) {
230
+ if (!(await status(config, token, false, signal)).account.model_access_available) return modelUnavailable("Account balance is required before enabling AWiki-hosted DeepSeek.");
231
+ const previous = ctx.agentDefaultModel.currentSelection();
232
+ await ctx.settings.update(SETTINGS, {
233
+ enabled: true,
234
+ previousProvider: previous.provider,
235
+ previousModel: previous.model,
236
+ ...previous.reasoningEffort === void 0 ? {} : { previousReasoningEffort: String(previous.reasoningEffort) }
237
+ });
238
+ sync();
239
+ await ctx.agentDefaultModel.saveSelection({
240
+ provider: PROVIDER,
241
+ model: FLASH
242
+ });
243
+ } else {
244
+ const stored = currentSettings();
245
+ await ctx.settings.update(SETTINGS, { enabled: false });
246
+ sync();
247
+ if (ctx.agentDefaultModel.currentSelection().provider === PROVIDER) await ctx.agentDefaultModel.saveSelection({
248
+ provider: stored.previousProvider ?? "deepseek-official",
249
+ model: stored.previousModel ?? FLASH,
250
+ ...stored.previousReasoningEffort === void 0 ? {} : { reasoningEffort: stored.previousReasoningEffort }
251
+ });
252
+ }
253
+ return {
254
+ ok: true,
255
+ value: await status(config, token, payload.enabled, signal)
256
+ };
257
+ }
258
+ return badRequest();
259
+ } catch (error) {
260
+ ctx.logger.warn("awiki-model-proxy: loopback request failed");
261
+ ctx.logger.warn(error);
262
+ return internal(displayMessage(error));
263
+ }
264
+ };
265
+ }
266
+ async function status(config, token, enabled, signal) {
267
+ const [account, pendingRechargeOrder] = await Promise.all([authenticatedJson(config, token, "/api/account", { signal }), authenticatedJson(config, token, "/api/recharge/orders/pending", { signal })]);
268
+ const decoded = decodeModelProxyStatus({
269
+ enabled,
270
+ account,
271
+ pending_recharge_order: pendingRechargeOrder,
272
+ recommended_model: FLASH,
273
+ models: MODELS
274
+ });
275
+ if (decoded === void 0) throw new Error("invalid account response");
276
+ return decoded;
277
+ }
278
+ async function authenticatedJson(config, token, path, init) {
279
+ return (await authenticatedResponse(config, token, path, init)).json();
280
+ }
281
+ async function authenticatedResponse(config, token, path, init) {
282
+ const send = async () => {
283
+ const accessToken = await token.get();
284
+ return {
285
+ response: await fetch(new URL(path, config.baseURL), {
286
+ ...init,
287
+ headers: {
288
+ ...headersRecord(init.headers),
289
+ authorization: `Bearer ${accessToken}`
290
+ }
291
+ }),
292
+ accessToken
293
+ };
294
+ };
295
+ let result = await send();
296
+ if (result.response.status === 401) {
297
+ token.invalidate(result.accessToken);
298
+ result = await send();
299
+ }
300
+ const { response } = result;
301
+ if (!response.ok) throw await modelProxyError(response, `AWiki-hosted DeepSeek service returned HTTP ${response.status}`);
302
+ return response;
303
+ }
304
+ async function modelProxyError(response, fallback) {
305
+ let message = fallback;
306
+ try {
307
+ const body = await response.text();
308
+ if (body !== "") try {
309
+ const value = JSON.parse(body);
310
+ if (isRecord(value) && isRecord(value.error) && typeof value.error.message === "string") message = value.error.message;
311
+ } catch {
312
+ message = body;
313
+ }
314
+ } catch {}
315
+ return new LlmError(message, response.status === 401 || response.status === 403 ? "AUTH" : `HTTP_${response.status}`, { status: response.status });
316
+ }
317
+ function resolveConfig(input) {
318
+ const baseURL = new URL(input.baseURL ?? "https://model.awiki.info");
319
+ if (baseURL.username !== "" || baseURL.password !== "" || baseURL.search !== "" || baseURL.hash !== "") throw new Error("awiki-model-proxy: baseURL must not contain credentials, query, or fragment");
320
+ if (baseURL.protocol !== "https:" && !(baseURL.protocol === "http:" && [
321
+ "127.0.0.1",
322
+ "localhost",
323
+ "::1"
324
+ ].includes(baseURL.hostname))) throw new Error("awiki-model-proxy: baseURL must use HTTPS or loopback HTTP");
325
+ const contextWindow = positiveInteger(input.contextWindow ?? 1e6, "contextWindow");
326
+ const maxTokens = positiveInteger(input.maxTokens ?? 8192, "maxTokens");
327
+ const skew = input.tokenRefreshSkewSeconds ?? 60;
328
+ if (!Number.isSafeInteger(skew) || skew < 0) throw new Error("awiki-model-proxy: tokenRefreshSkewSeconds must be a non-negative integer");
329
+ return {
330
+ baseURL,
331
+ contextWindow,
332
+ maxTokens,
333
+ tokenRefreshSkewMs: skew * 1e3
334
+ };
335
+ }
336
+ function positiveInteger(value, name) {
337
+ if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`awiki-model-proxy: ${name} must be a positive integer`);
338
+ return value;
339
+ }
340
+ function headersRecord(headers) {
341
+ return Object.fromEntries(new Headers(headers));
342
+ }
343
+ function isRecord(value) {
344
+ return typeof value === "object" && value !== null && !Array.isArray(value);
345
+ }
346
+ function displayMessage(error) {
347
+ return error instanceof Error && error.message !== "" ? error.message : "AWiki-hosted DeepSeek service is unavailable.";
348
+ }
349
+ function badRequest() {
350
+ return {
351
+ ok: false,
352
+ error: {
353
+ code: "bad-request",
354
+ message: "The AWiki-hosted DeepSeek request is invalid.",
355
+ details: { issues: [] }
356
+ }
357
+ };
358
+ }
359
+ function modelUnavailable(message) {
360
+ return {
361
+ ok: false,
362
+ error: {
363
+ code: "model-unavailable",
364
+ message,
365
+ details: {
366
+ provider: PROVIDER,
367
+ model: FLASH
368
+ }
369
+ }
370
+ };
371
+ }
372
+ function internal(message) {
373
+ return {
374
+ ok: false,
375
+ error: {
376
+ code: "internal",
377
+ message,
378
+ details: {}
379
+ }
380
+ };
381
+ }
382
+ //#endregion
383
+ export { Config, apply, inject, name };
package/lib/provider.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as RustSdkAdapter } from "./sdk-adapter-DK6RqV-c.mjs";
1
+ import { t as RustSdkAdapter } from "./sdk-adapter-DKgkyApB.mjs";
2
2
  import { openImCoreNodeClient } from "@awiki/im-core-node";
3
3
  //#region lib/types/provider.js
4
4
  /** Production AWiki provider backed by the versioned Rust IM Core Node bridge. */
@@ -14,6 +14,7 @@ function apply(ctx) {
14
14
  didDomain: options.userServiceDomain,
15
15
  userServiceEndpoint: options.userServiceUrl,
16
16
  messageServiceEndpoint: options.messageServiceUrl,
17
+ mailServiceEndpoint: options.mailServiceUrl,
17
18
  anpServiceEndpoint: options.messageServiceUrl,
18
19
  anpServiceDid: options.messageServiceDid,
19
20
  externalHttpAllowInsecureLoopbackForTesting: options.allowInsecureLoopbackForTesting