dsh-neartoken 0.14.0 → 0.15.0

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/README.md CHANGED
@@ -99,13 +99,16 @@
99
99
 
100
100
  | 优先级 | 来源 | 维护方式 |
101
101
  |---|---|---|
102
- | 1 | `modelOverrides.*.contextWindow` | 改 profile 配置,重启 |
103
- | 2 | 站点 `/api/pricing` 的 `context_window` | 在 New API 管理后台维护 |
104
- | 3 | `defaultContextWindow` | 改 profile 配置 |
102
+ | 1 | 设置页「模型白名单 → 覆盖」填的上下文(`modelMeta`,volatile,保存即生效) | 设置页模型行点「覆盖」 |
103
+ | 2 | `modelOverrides.*.contextWindow` | 改 profile 配置,重启 |
104
+ | 3 | 站点 `/api/pricing` 的 `context_window` | 在 New API 管理后台维护 |
105
+ | 4 | `defaultContextWindow` | 改 profile 配置 |
106
+
107
+ 设置页的「覆盖」编辑器(模型白名单每行右侧按钮)可给单个模型改**上下文 / 最大输出 / 输入类型**三项:填了的字段逐项盖过 `modelOverrides` 与站点声明,留空的字段沿用下一级;输入类型(文本/图像)整体生效、至少留一项。数据存 `modelMeta`(volatile,与白名单同一次 profile 写入),保存后路由即重申、模型选择器立刻刷新,「清除覆盖」回到站点声明。编辑器里同时显示站点声明值作参照。
105
108
 
106
109
  最大输出(`max_tokens`)只在**站点或配置明确给出**时才写进请求。站点可能把同一个名字路由到上限更低的渠道,照抄厂商口径会把「回答被截断」换成「请求被拒」。不给出该字段时由上游默认值决定。
107
110
 
108
- 输入模态(`text` / `image`)优先级:`modelOverrides.*.input` > 站点 `input_modalities` > `['text']`。**站点没声明的模型一律当纯文本**,因为 harness 把「没有声明」当成「没有权限」:只有声明了 `image` 的模型才允许 `read_image` 和携带图片的请求,否则图片会在发出前被拦下。所以后台忘了勾 `image` 的模型,症状是「贴图被拦」而不是「报错」。
111
+ 输入模态(`text` / `image`)优先级:设置页「覆盖」的输入类型(`modelMeta.*.input`)> `modelOverrides.*.input` > 站点 `input_modalities` > `['text']`。**站点没声明的模型一律当纯文本**,因为 harness 把「没有声明」当成「没有权限」:只有声明了 `image` 的模型才允许 `read_image` 和携带图片的请求,否则图片会在发出前被拦下。所以后台忘了勾 `image` 的模型,症状是「贴图被拦」而不是「报错」。
109
112
 
110
113
  推理档位(`minimal` / `low` / `medium` / `high` / `xhigh` / `max`)优先级:`modelOverrides.*.reasoning` > 站点 `reasoning_levels` > 无档位。**站点没声明就没有档位选择器** —— 与其发一个上游不认的档位换来 400,不如不提供。
111
114
 
@@ -188,6 +191,7 @@ Gemini 系走原生 surface 而不是 openai 兼容层:同模型同提示词
188
191
  - 四套 wire(chat / anthropic / genai / responses)各自解析 SSE;**用户消息里的图片按各协议原样发送** —— chat 用 `image_url` part、anthropic 用 `source.base64`、genai 用 `inlineData`、responses 用 `input_image`。字节由 `attachments.readImage` 在请求前内联;没有 attachments 服务或读不出来会**让请求失败**,不再静默降级成纯文本(曾经就是这样:贴的截图模型根本收不到)。文件块(非图片附件)仍不发;`/model` 弹窗仍是内置平铺列表;箭头键盘导航未接。
189
192
  - 四套 wire 的 SSE 解析都有「帧样本 → 期望 chunk 序列」回归测试(`src/host/wire-parse.spec.ts`),帧样本取自生产网关的真实响应。网关在内容帧上发 `"usage": null`,只有末帧带真值:任何一处把 `usage` 当对象直接读都会让整条流中途崩掉(曾导致 claude 模型全不可用)。
190
193
  - **每个请求都带会话亲和键**:chat 与 responses 发 `prompt_cache_key`,anthropic 发 `metadata.user_id`,取值都是 DSH 的 `GenerateOptions.sessionId`。站点就是靠这个值挑上游渠道的(New API 的「codex cli trace」规则:`^gpt-.*$` + `/v1/responses`,键取自 body 的 `prompt_cache_key`,取不到就把整条规则跳过),而提示词缓存按**上游账号**存 —— 不带键时每个请求随机换账号,缓存永远不中。实测同一 6k 前缀:不带键连发 4 次 `cached_tokens` 全 0;带键后第 2 次起 5888/6011 ≈ 98%。`/v1/chat/completions` 上目前没有对应规则,chat 线即使带键也只是偶发命中,要彻底解决需要站点加一条匹配该路径的亲和规则;anthropic 线的 `metadata.user_id` 同理(规则只作用于 `/v1/messages`,这一条已经匹配)。
194
+ - **anthropic 线显式打缓存断点**:Anthropic 只在 `cache_control` 断点处写缓存,没有断点就整段 prompt 按新输入计价(亲和键只保证落在同一上游账号,不产生缓存)。每个请求打 4 个断点:`tools` 末项、`system` 末块、最后两条消息各自末块 —— harness 每轮全量重放历史,尾部双断点保证下一轮几乎全命中,每轮只写新增片段。实测(Claude Max 超惠分组,~6.3k token 前缀):无断点连发两次 `cache_read` 全 0;打点后第 2 次起 `in=4, cr=6316`,三轮增长历史 `cr` 累积到 10811、`in` 恒为个位数。断点也覆盖 `tool_result` 结尾的轮次(DSH 会话的常态形态)。
191
195
  - 推理等级按各协议自己的词汇发送:**anthropic 发 `thinking.type=adaptive` + `output_config.effort`**(不能再用 `thinking.type=enabled` + `budget_tokens`:Claude 5 代直接 400 `requires adaptive thinking`,而 adaptive 在老代际上同样可用,所以统一用它;`minimal` 收敛成 `low`);genai 发 `thinkingConfig` 且带 `includeThoughts`(不带你拿不到思维链);chat 与 responses 发 `reasoning_effort` / `reasoning.effort`。
192
196
  - **Gemini 4 换成 `thinkingLevel`**:这一代不再接受 token 预算(发 budget 会 400 `Use thinking level instead`),按 `gemini-<主版本>` ≥ 4 自动切换字段,等级名用 `low` / `medium` / `high` / `max`。
193
197
  - 思考历史**不回传**:harness 的 reasoning 块没有 signature 槽位,anthropic 的 `signature_delta` 与 gemini 的 `thoughtSignature` 都被丢弃。当前网关的转换层本身也会丢弃 thinking 块,所以多轮不会因此报错;接真正的 Anthropic / Gemini 直连渠道时这一条会变成硬限制。
@@ -196,6 +200,7 @@ Gemini 系走原生 surface 而不是 openai 兼容层:同模型同提示词
196
200
  - `-c` 后缀是站点自己的约定(带该后缀的模型工具调用不可靠):站点声明了端点类型时插件按声明提供,声明里没有它就不会出现;没有声明时按名字隐藏它的无后缀孪生之外的变体。
197
201
  - 站点上新但还没在后台填能力的模型:只要声明了端点类型就会提供,容量走 `defaultContextWindow`,模态按纯文本、没有推理档位(除非在 `modelOverrides` 里写明)。这不是 bug,是「站点是唯一真源」的直接后果——补能力请去后台填,不必等插件发版。
198
202
  - pricing 加载失败时沿用上一次成功的结果,从未成功过则目录为空(失败不写缓存,下次调用会重试)。
203
+ - **上游错误映射到共享重试码表**(`src/host/wire-error.ts`):429→`RATE_LIMIT`、5xx/529/流中途失败→`SERVER`、网络层断连→`TRANSPORT`(fetch 抛错但非用户取消),这三类是 base 组合里 `dsh-llm-retry` 默认策略(5 次、指数退避、读 `retry-after`)会等过去重试的;401/403→`AUTH`、402/余额耗尽→`QUOTA`、400/413→`INVALID_REQUEST`、上下文超限→`CONTEXT_WINDOW_EXCEEDED`、其余→`HTTP_<status>` 保持不可重试。曾经全部抛 `PROVIDER_ERROR`——不在默认可重试集合里,网关一次瞬断就终止整轮(「一遇错误立即停止」的根因)。
199
204
  - 账号卡片的钱是**两次读**拼接的:授权那一刻 grant 里的 `user` 给出身份事实,余额/已用/代金券则来自站点 `/api/dsh/device/wallet`——Host 每 5 分钟读一次,页面在余额旁另有**立即刷新**按钮(`POST /neartoken/refresh`,读完后把同一份状态回给页面),所以不必重连也能看到新数字。落盘到 profile 下的 `neartoken-account.json` 只作重启回退。站点若没有该端点或读不到,卡片保留上一次的数字、不会清空。代金券为空时卡片给一句去「邀请计划」(站点 `/wallet` 页)领免费代金券的提示。
200
205
  - 白名单按裸模型名过滤:勾掉某模型会把它的所有分组一起隐藏;某个正在使用的模型被勾掉后,会话里已选中的 id 仍在,但选择器里不再列出它。
201
206
  - 白名单写入走 DSH 的 Settings:profile 里该行只保留 volatile 字段,所以别把 `baseURL` 等非 volatile 字段写进**同一个 profile 行**(会在此后第一次保存白名单时被 Settings 的 strip 规则清掉)。
package/lib/client.js CHANGED
@@ -100,11 +100,14 @@ window.__ModuleLoader__.load({
100
100
  async models() {
101
101
  return await jsonOf(await fetcher(MODELS_PATH, { headers: { accept: "application/json" } }));
102
102
  },
103
- async saveModels(enabled) {
103
+ async saveModels(enabled, meta) {
104
104
  await jsonOf(await fetcher(MODELS_PATH, {
105
105
  method: "POST",
106
106
  headers: { "content-type": "application/json" },
107
- body: JSON.stringify({ enabled })
107
+ body: JSON.stringify({
108
+ enabled,
109
+ ...meta === void 0 ? {} : { meta }
110
+ })
108
111
  }));
109
112
  },
110
113
  async images() {
@@ -343,22 +346,22 @@ window.__ModuleLoader__.load({
343
346
  }
344
347
  var group_tags_module_css_default = {
345
348
  "toneCyan": "FotuUq_toneCyan",
349
+ "toneIndigo": "FotuUq_toneIndigo",
350
+ "toneSky": "FotuUq_toneSky",
351
+ "toneEmerald": "FotuUq_toneEmerald",
352
+ "toneOrange": "FotuUq_toneOrange",
353
+ "tag": "FotuUq_tag",
354
+ "toneFuchsia": "FotuUq_toneFuchsia",
346
355
  "toneRose": "FotuUq_toneRose",
347
- "tonePink": "FotuUq_tonePink",
348
- "ratioChip": "FotuUq_ratioChip",
356
+ "toneTeal": "FotuUq_toneTeal",
349
357
  "toneLime": "FotuUq_toneLime",
358
+ "toneAmber": "FotuUq_toneAmber",
350
359
  "ratioCheap": "FotuUq_ratioCheap",
351
- "toneOrange": "FotuUq_toneOrange",
352
- "toneEmerald": "FotuUq_toneEmerald",
353
360
  "ratioBase": "FotuUq_ratioBase",
354
- "toneAmber": "FotuUq_toneAmber",
355
- "toneTeal": "FotuUq_toneTeal",
356
- "tag": "FotuUq_tag",
357
- "toneSky": "FotuUq_toneSky",
358
- "toneIndigo": "FotuUq_toneIndigo",
359
- "ratioPricey": "FotuUq_ratioPricey",
361
+ "ratioChip": "FotuUq_ratioChip",
360
362
  "toneViolet": "FotuUq_toneViolet",
361
- "toneFuchsia": "FotuUq_toneFuchsia"
363
+ "tonePink": "FotuUq_tonePink",
364
+ "ratioPricey": "FotuUq_ratioPricey"
362
365
  };
363
366
  //#endregion
364
367
  //#region src/client/group-tags.tsx
@@ -413,39 +416,39 @@ window.__ModuleLoader__.load({
413
416
  document.head.appendChild(tag);
414
417
  }
415
418
  var ModelGroupSelect_module_css_default = {
416
- "option": "_2pt-bW_option",
417
- "selected": "_2pt-bW_selected",
418
- "trigger": "_2pt-bW_trigger",
419
- "searchClear": "_2pt-bW_searchClear",
420
- "warning": "_2pt-bW_warning",
421
- "optionCopy": "_2pt-bW_optionCopy",
422
- "menu": "_2pt-bW_menu",
423
- "optionActive": "_2pt-bW_optionActive",
424
- "cellLabel": "_2pt-bW_cellLabel",
425
- "error": "_2pt-bW_error",
426
419
  "optionTrailing": "_2pt-bW_optionTrailing",
427
- "cellValue": "_2pt-bW_cellValue",
428
- "groups": "_2pt-bW_groups",
429
420
  "root": "_2pt-bW_root",
430
- "triggerIcon": "_2pt-bW_triggerIcon",
431
421
  "groupOptionLabel": "_2pt-bW_groupOptionLabel",
422
+ "status": "_2pt-bW_status",
423
+ "groups": "_2pt-bW_groups",
432
424
  "triggerLabel": "_2pt-bW_triggerLabel",
433
- "triggerEffort": "_2pt-bW_triggerEffort",
434
- "groupInline": "_2pt-bW_groupInline",
435
- "empty": "_2pt-bW_empty",
436
- "searchRow": "_2pt-bW_searchRow",
437
- "groupName": "_2pt-bW_groupName",
425
+ "optionCopy": "_2pt-bW_optionCopy",
426
+ "variantCount": "_2pt-bW_variantCount",
427
+ "option": "_2pt-bW_option",
438
428
  "modelOption": "_2pt-bW_modelOption",
439
- "chevron": "_2pt-bW_chevron",
440
- "status": "_2pt-bW_status",
441
- "retry": "_2pt-bW_retry",
442
- "search": "_2pt-bW_search",
429
+ "warning": "_2pt-bW_warning",
443
430
  "modelName": "_2pt-bW_modelName",
444
- "variantCount": "_2pt-bW_variantCount",
445
431
  "check": "_2pt-bW_check",
432
+ "toast": "_2pt-bW_toast",
433
+ "triggerIcon": "_2pt-bW_triggerIcon",
434
+ "empty": "_2pt-bW_empty",
435
+ "retry": "_2pt-bW_retry",
436
+ "error": "_2pt-bW_error",
437
+ "cellLabel": "_2pt-bW_cellLabel",
438
+ "menu": "_2pt-bW_menu",
439
+ "searchRow": "_2pt-bW_searchRow",
440
+ "searchClear": "_2pt-bW_searchClear",
446
441
  "cell": "_2pt-bW_cell",
442
+ "triggerEffort": "_2pt-bW_triggerEffort",
443
+ "selected": "_2pt-bW_selected",
444
+ "cellValue": "_2pt-bW_cellValue",
447
445
  "cellChevron": "_2pt-bW_cellChevron",
448
- "toast": "_2pt-bW_toast"
446
+ "groupName": "_2pt-bW_groupName",
447
+ "search": "_2pt-bW_search",
448
+ "optionActive": "_2pt-bW_optionActive",
449
+ "chevron": "_2pt-bW_chevron",
450
+ "groupInline": "_2pt-bW_groupInline",
451
+ "trigger": "_2pt-bW_trigger"
449
452
  };
450
453
  //#endregion
451
454
  //#region src/client/ModelGroupSelect.tsx
@@ -1001,7 +1004,7 @@ window.__ModuleLoader__.load({
1001
1004
  }
1002
1005
  //#endregion
1003
1006
  //#region \0dsh-css:D:\Projects\deepseek-harness\dsh-neartoken\src\client\NearTokenSection.module.css.mjs
1004
- const css = "._02HI2q_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}._02HI2q_title{margin:0;font-size:16px;font-weight:500;line-height:24px}._02HI2q_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}._02HI2q_card{border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-settings-card-fill);border-radius:var(--dsw-radius-xl);flex-direction:column;gap:12px;padding:14px 16px;display:flex}._02HI2q_cardHead{align-items:baseline;gap:10px;display:flex}._02HI2q_name{font-size:15px;font-weight:500;line-height:22px}._02HI2q_handle{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._02HI2q_badge{background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-secondary);border-radius:999px;margin-left:auto;padding:2px 8px;font-size:12px;line-height:18px}._02HI2q_badgeOn{color:var(--dsw-alias-state-success-primary)}._02HI2q_facts{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-interactive-bg-hover);grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:14px 18px;margin:0;padding:12px 14px;display:grid}._02HI2q_fact{flex-direction:column;gap:2px;display:flex}._02HI2q_factLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._02HI2q_factValue{font-variant-numeric:tabular-nums;letter-spacing:-.01em;color:var(--dsw-alias-label-primary);font-size:15px;font-weight:500;line-height:22px}._02HI2q_valueRow{align-items:center;gap:6px;display:flex}._02HI2q_refresh{border-radius:var(--dsw-radius-sm);width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;display:inline-flex}._02HI2q_refresh:hover:not(:disabled){background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary)}._02HI2q_refresh:disabled{opacity:.55;cursor:default}._02HI2q_voucherFact{grid-column:1/-1}._02HI2q_voucherList{flex-direction:column;gap:2px;margin:0;display:flex}._02HI2q_voucherRow{justify-content:space-between;align-items:baseline;gap:10px;font-size:13px;line-height:20px;display:flex}._02HI2q_voucherGroup{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._02HI2q_voucherAmount{color:var(--dsw-alias-state-success-primary);font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:500}._02HI2q_voucherEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:20px}._02HI2q_invite{color:var(--dsw-alias-label-primary);text-underline-offset:2px;text-decoration:underline}._02HI2q_form{flex-direction:column;gap:10px;display:flex}._02HI2q_label{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}._02HI2q_codeRow{align-items:center;gap:10px;display:flex}._02HI2q_code{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);letter-spacing:.08em;border-radius:var(--dsw-radius-md);background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary);user-select:all;padding:4px 12px;font-size:18px;line-height:26px}._02HI2q_linkRow{flex-direction:column;gap:4px;display:flex}._02HI2q_linkLine{align-items:flex-start;gap:8px;display:flex}._02HI2q_link{min-width:0;font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);word-break:break-all;color:var(--dsw-alias-label-secondary);user-select:all;flex:auto;font-size:12px;line-height:18px}._02HI2q_actions{align-items:center;gap:10px;display:flex}._02HI2q_button{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-button-elevated-fill);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;padding:0 14px;font-size:14px}._02HI2q_buttonPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:#0000}._02HI2q_button:disabled{opacity:.55;cursor:default}._02HI2q_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}._02HI2q_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}._02HI2q_search{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-button-elevated-fill);height:32px;color:var(--dsw-alias-label-primary);padding:0 10px;font-size:14px}._02HI2q_search::placeholder{color:var(--dsw-alias-label-dimmed)}._02HI2q_toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._02HI2q_autosave{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:12px;line-height:18px}._02HI2q_list{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-md);flex-direction:column;max-height:320px;padding:4px;display:flex;overflow-y:auto}._02HI2q_row{border-radius:var(--dsw-radius-sm);cursor:pointer;align-items:baseline;gap:8px;padding:4px 6px;font-size:13px;line-height:20px;display:flex}._02HI2q_row:hover{background:var(--dsw-alias-interactive-bg-hover)}._02HI2q_row input{accent-color:var(--dsw-alias-button-primary-fill);align-self:center}._02HI2q_rowName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:auto;overflow:hidden}._02HI2q_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;align-items:baseline;gap:8px;font-size:12px;display:flex}._02HI2q_rowRatio{color:var(--dsw-alias-label-secondary)}._02HI2q_tip{z-index:40;border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-settings-card-fill);pointer-events:none;flex-direction:column;gap:2px;width:280px;max-height:240px;padding:8px 10px;font-size:12px;line-height:18px;display:flex;position:fixed;overflow-y:auto;box-shadow:0 8px 24px #00000024}._02HI2q_tipTitle{color:var(--dsw-alias-label-tertiary)}._02HI2q_tipRow{justify-content:space-between;align-items:baseline;gap:10px;display:flex}._02HI2q_tipGroup{min-width:0;color:var(--dsw-alias-label-primary);align-items:center;gap:4px;display:flex;overflow:hidden}._02HI2q_tipGroupName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._02HI2q_select{border:1px solid var(--dsw-color-border-subtle,#0000001f);max-width:60%;color:inherit;font:inherit;background:0 0;border-radius:6px;margin-left:auto;padding:2px 6px;font-size:12px}._02HI2q_select:disabled{opacity:.5}._02HI2q_cardToggle{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:0;display:flex}._02HI2q_cardToggle:hover ._02HI2q_name{color:var(--dsw-alias-label-primary)}._02HI2q_count{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;margin-left:auto;font-size:12px;line-height:18px;display:inline-flex}._02HI2q_countDot{background:var(--dsw-alias-label-dimmed);border-radius:50%;width:3px;height:3px}._02HI2q_countPicked{color:var(--dsw-alias-label-secondary)}._02HI2q_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s}._02HI2q_chevronOpen{transform:rotate(180deg)}";
1007
+ const css = "._02HI2q_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}._02HI2q_title{margin:0;font-size:16px;font-weight:500;line-height:24px}._02HI2q_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}._02HI2q_card{border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-settings-card-fill);border-radius:var(--dsw-radius-xl);flex-direction:column;gap:12px;padding:14px 16px;display:flex}._02HI2q_cardHead{align-items:baseline;gap:10px;display:flex}._02HI2q_name{font-size:15px;font-weight:500;line-height:22px}._02HI2q_handle{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._02HI2q_badge{background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-secondary);border-radius:999px;margin-left:auto;padding:2px 8px;font-size:12px;line-height:18px}._02HI2q_badgeOn{color:var(--dsw-alias-state-success-primary)}._02HI2q_facts{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-interactive-bg-hover);grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:14px 18px;margin:0;padding:12px 14px;display:grid}._02HI2q_fact{flex-direction:column;gap:2px;display:flex}._02HI2q_factLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}._02HI2q_factValue{font-variant-numeric:tabular-nums;letter-spacing:-.01em;color:var(--dsw-alias-label-primary);font-size:15px;font-weight:500;line-height:22px}._02HI2q_valueRow{align-items:center;gap:6px;display:flex}._02HI2q_refresh{border-radius:var(--dsw-radius-sm);width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;display:inline-flex}._02HI2q_refresh:hover:not(:disabled){background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary)}._02HI2q_refresh:disabled{opacity:.55;cursor:default}._02HI2q_voucherFact{grid-column:1/-1}._02HI2q_voucherList{flex-direction:column;gap:2px;margin:0;display:flex}._02HI2q_voucherRow{justify-content:space-between;align-items:baseline;gap:10px;font-size:13px;line-height:20px;display:flex}._02HI2q_voucherGroup{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._02HI2q_voucherAmount{color:var(--dsw-alias-state-success-primary);font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:500}._02HI2q_voucherEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:20px}._02HI2q_invite{color:var(--dsw-alias-label-primary);text-underline-offset:2px;text-decoration:underline}._02HI2q_form{flex-direction:column;gap:10px;display:flex}._02HI2q_label{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}._02HI2q_codeRow{align-items:center;gap:10px;display:flex}._02HI2q_code{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);letter-spacing:.08em;border-radius:var(--dsw-radius-md);background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary);user-select:all;padding:4px 12px;font-size:18px;line-height:26px}._02HI2q_linkRow{flex-direction:column;gap:4px;display:flex}._02HI2q_linkLine{align-items:flex-start;gap:8px;display:flex}._02HI2q_link{min-width:0;font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);word-break:break-all;color:var(--dsw-alias-label-secondary);user-select:all;flex:auto;font-size:12px;line-height:18px}._02HI2q_actions{align-items:center;gap:10px;display:flex}._02HI2q_metaBtn{border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:9px;margin-left:auto;padding:1px 8px;font-size:11px;line-height:18px}._02HI2q_metaBtn:hover{color:var(--dsw-alias-label-primary)}._02HI2q_metaBtnOn{border-color:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-button-primary-fill)}._02HI2q_metaEditor{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-md);flex-direction:column;gap:8px;margin:2px 0 6px 26px;padding:10px 12px;display:flex}._02HI2q_metaTitle{font-weight:600}._02HI2q_metaIntro{color:var(--dsw-alias-label-tertiary);margin:0}._02HI2q_metaField{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._02HI2q_metaLabel{min-width:120px;color:var(--dsw-alias-label-secondary)}._02HI2q_metaInput{width:140px;padding:2px 6px}._02HI2q_metaHint{color:var(--dsw-alias-label-tertiary);font-size:11px}._02HI2q_metaCheck{align-items:center;gap:4px;display:inline-flex}._02HI2q_metaActions{align-items:center;gap:8px;display:flex}._02HI2q_button{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-button-elevated-fill);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;padding:0 14px;font-size:14px}._02HI2q_buttonPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:#0000}._02HI2q_button:disabled{opacity:.55;cursor:default}._02HI2q_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}._02HI2q_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}._02HI2q_search{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-button-elevated-fill);height:32px;color:var(--dsw-alias-label-primary);padding:0 10px;font-size:14px}._02HI2q_search::placeholder{color:var(--dsw-alias-label-dimmed)}._02HI2q_toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._02HI2q_autosave{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:12px;line-height:18px}._02HI2q_list{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-md);flex-direction:column;max-height:320px;padding:4px;display:flex;overflow-y:auto}._02HI2q_row{border-radius:var(--dsw-radius-sm);cursor:pointer;align-items:baseline;gap:8px;padding:4px 6px;font-size:13px;line-height:20px;display:flex}._02HI2q_row:hover{background:var(--dsw-alias-interactive-bg-hover)}._02HI2q_row input{accent-color:var(--dsw-alias-button-primary-fill);align-self:center}._02HI2q_rowName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:auto;overflow:hidden}._02HI2q_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;align-items:baseline;gap:8px;font-size:12px;display:flex}._02HI2q_rowRatio{color:var(--dsw-alias-label-secondary)}._02HI2q_tip{z-index:40;border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-settings-card-fill);pointer-events:none;flex-direction:column;gap:2px;width:280px;max-height:240px;padding:8px 10px;font-size:12px;line-height:18px;display:flex;position:fixed;overflow-y:auto;box-shadow:0 8px 24px #00000024}._02HI2q_tipTitle{color:var(--dsw-alias-label-tertiary)}._02HI2q_tipRow{justify-content:space-between;align-items:baseline;gap:10px;display:flex}._02HI2q_tipGroup{min-width:0;color:var(--dsw-alias-label-primary);align-items:center;gap:4px;display:flex;overflow:hidden}._02HI2q_tipGroupName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._02HI2q_select{border:1px solid var(--dsw-color-border-subtle,#0000001f);max-width:60%;color:inherit;font:inherit;background:0 0;border-radius:6px;margin-left:auto;padding:2px 6px;font-size:12px}._02HI2q_select:disabled{opacity:.5}._02HI2q_cardToggle{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:0;display:flex}._02HI2q_cardToggle:hover ._02HI2q_name{color:var(--dsw-alias-label-primary)}._02HI2q_count{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;margin-left:auto;font-size:12px;line-height:18px;display:inline-flex}._02HI2q_countDot{background:var(--dsw-alias-label-dimmed);border-radius:50%;width:3px;height:3px}._02HI2q_countPicked{color:var(--dsw-alias-label-secondary)}._02HI2q_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .12s}._02HI2q_chevronOpen{transform:rotate(180deg)}";
1005
1008
  const tagId = "dsh-neartoken/NearTokenSection.module.css";
1006
1009
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
1007
1010
  const tag = document.createElement("style");
@@ -1011,60 +1014,71 @@ window.__ModuleLoader__.load({
1011
1014
  document.head.appendChild(tag);
1012
1015
  }
1013
1016
  var NearTokenSection_module_css_default = {
1014
- "tip": "_02HI2q_tip",
1017
+ "factValue": "_02HI2q_factValue",
1018
+ "countPicked": "_02HI2q_countPicked",
1019
+ "metaCheck": "_02HI2q_metaCheck",
1020
+ "tipGroup": "_02HI2q_tipGroup",
1021
+ "toolbar": "_02HI2q_toolbar",
1022
+ "metaHint": "_02HI2q_metaHint",
1023
+ "codeRow": "_02HI2q_codeRow",
1024
+ "tipRow": "_02HI2q_tipRow",
1025
+ "metaLabel": "_02HI2q_metaLabel",
1026
+ "row": "_02HI2q_row",
1027
+ "metaActions": "_02HI2q_metaActions",
1028
+ "rowName": "_02HI2q_rowName",
1015
1029
  "search": "_02HI2q_search",
1016
- "linkLine": "_02HI2q_linkLine",
1017
- "buttonPrimary": "_02HI2q_buttonPrimary",
1030
+ "voucherAmount": "_02HI2q_voucherAmount",
1031
+ "badge": "_02HI2q_badge",
1032
+ "tip": "_02HI2q_tip",
1033
+ "intro": "_02HI2q_intro",
1034
+ "card": "_02HI2q_card",
1035
+ "factLabel": "_02HI2q_factLabel",
1036
+ "metaEditor": "_02HI2q_metaEditor",
1037
+ "metaTitle": "_02HI2q_metaTitle",
1038
+ "metaField": "_02HI2q_metaField",
1039
+ "rowMeta": "_02HI2q_rowMeta",
1040
+ "rowRatio": "_02HI2q_rowRatio",
1041
+ "form": "_02HI2q_form",
1018
1042
  "select": "_02HI2q_select",
1019
- "voucherFact": "_02HI2q_voucherFact",
1020
- "linkRow": "_02HI2q_linkRow",
1043
+ "refresh": "_02HI2q_refresh",
1044
+ "notice": "_02HI2q_notice",
1045
+ "chevronOpen": "_02HI2q_chevronOpen",
1021
1046
  "cardHead": "_02HI2q_cardHead",
1047
+ "linkRow": "_02HI2q_linkRow",
1048
+ "metaIntro": "_02HI2q_metaIntro",
1049
+ "badgeOn": "_02HI2q_badgeOn",
1050
+ "button": "_02HI2q_button",
1051
+ "voucherEmpty": "_02HI2q_voucherEmpty",
1052
+ "metaBtnOn": "_02HI2q_metaBtnOn",
1053
+ "buttonPrimary": "_02HI2q_buttonPrimary",
1054
+ "list": "_02HI2q_list",
1022
1055
  "voucherList": "_02HI2q_voucherList",
1023
- "section": "_02HI2q_section",
1024
- "valueRow": "_02HI2q_valueRow",
1025
- "badge": "_02HI2q_badge",
1026
- "tipTitle": "_02HI2q_tipTitle",
1027
- "voucherRow": "_02HI2q_voucherRow",
1056
+ "title": "_02HI2q_title",
1028
1057
  "name": "_02HI2q_name",
1029
- "handle": "_02HI2q_handle",
1030
- "factLabel": "_02HI2q_factLabel",
1031
- "voucherAmount": "_02HI2q_voucherAmount",
1032
- "notice": "_02HI2q_notice",
1033
- "countPicked": "_02HI2q_countPicked",
1034
- "chevron": "_02HI2q_chevron",
1035
- "hint": "_02HI2q_hint",
1036
- "tipRow": "_02HI2q_tipRow",
1058
+ "metaInput": "_02HI2q_metaInput",
1059
+ "actions": "_02HI2q_actions",
1037
1060
  "label": "_02HI2q_label",
1038
- "invite": "_02HI2q_invite",
1039
1061
  "link": "_02HI2q_link",
1040
- "actions": "_02HI2q_actions",
1041
- "cardToggle": "_02HI2q_cardToggle",
1042
- "chevronOpen": "_02HI2q_chevronOpen",
1043
- "refresh": "_02HI2q_refresh",
1044
- "code": "_02HI2q_code",
1045
- "intro": "_02HI2q_intro",
1046
- "fact": "_02HI2q_fact",
1047
- "factValue": "_02HI2q_factValue",
1062
+ "hint": "_02HI2q_hint",
1063
+ "section": "_02HI2q_section",
1064
+ "voucherRow": "_02HI2q_voucherRow",
1065
+ "count": "_02HI2q_count",
1066
+ "voucherFact": "_02HI2q_voucherFact",
1067
+ "countDot": "_02HI2q_countDot",
1048
1068
  "voucherGroup": "_02HI2q_voucherGroup",
1049
- "voucherEmpty": "_02HI2q_voucherEmpty",
1050
- "button": "_02HI2q_button",
1051
- "toolbar": "_02HI2q_toolbar",
1052
- "autosave": "_02HI2q_autosave",
1053
- "rowName": "_02HI2q_rowName",
1054
- "rowRatio": "_02HI2q_rowRatio",
1055
- "card": "_02HI2q_card",
1056
- "row": "_02HI2q_row",
1057
- "tipGroup": "_02HI2q_tipGroup",
1058
- "badgeOn": "_02HI2q_badgeOn",
1059
- "codeRow": "_02HI2q_codeRow",
1060
- "title": "_02HI2q_title",
1069
+ "code": "_02HI2q_code",
1070
+ "metaBtn": "_02HI2q_metaBtn",
1061
1071
  "facts": "_02HI2q_facts",
1062
- "count": "_02HI2q_count",
1063
- "list": "_02HI2q_list",
1072
+ "valueRow": "_02HI2q_valueRow",
1073
+ "tipTitle": "_02HI2q_tipTitle",
1064
1074
  "tipGroupName": "_02HI2q_tipGroupName",
1065
- "countDot": "_02HI2q_countDot",
1066
- "form": "_02HI2q_form",
1067
- "rowMeta": "_02HI2q_rowMeta"
1075
+ "chevron": "_02HI2q_chevron",
1076
+ "cardToggle": "_02HI2q_cardToggle",
1077
+ "invite": "_02HI2q_invite",
1078
+ "handle": "_02HI2q_handle",
1079
+ "linkLine": "_02HI2q_linkLine",
1080
+ "autosave": "_02HI2q_autosave",
1081
+ "fact": "_02HI2q_fact"
1068
1082
  };
1069
1083
  //#endregion
1070
1084
  //#region src/client/NearTokenSection.tsx
@@ -1501,11 +1515,23 @@ window.__ModuleLoader__.load({
1501
1515
  const [open, setOpen] = (0, react.useState)(false);
1502
1516
  /** The queued save, while a burst of clicks is still settling. */
1503
1517
  const pending = (0, react.useRef)(void 0);
1518
+ /** The stored per-model meta overrides, mirrored from the host answer. */
1519
+ const [meta, setMeta] = (0, react.useState)({});
1520
+ /** The model whose meta editor is open; one editor at a time. */
1521
+ const [editing, setEditing] = (0, react.useState)(void 0);
1522
+ /** The editor's draft: strings for the numeric fields, boxes for the modalities. */
1523
+ const [draft, setDraft] = (0, react.useState)({
1524
+ contextWindow: "",
1525
+ maxTokens: "",
1526
+ text: true,
1527
+ image: false
1528
+ });
1504
1529
  const [tip, setTip] = (0, react.useState)(void 0);
1505
1530
  /** Publish one host answer: the boxes show the stored list, or all when none is stored. */
1506
1531
  const adopt = (0, react.useCallback)((next) => {
1507
1532
  setState(next);
1508
1533
  setSelected(new Set(next.enabled.length === 0 ? next.models.map((entry) => entry.model) : next.enabled));
1534
+ setMeta(next.meta);
1509
1535
  }, []);
1510
1536
  const load = (0, react.useCallback)(async () => {
1511
1537
  try {
@@ -1615,6 +1641,71 @@ window.__ModuleLoader__.load({
1615
1641
  setSelected(new Set(models.map((entry) => entry.model)));
1616
1642
  persist([]);
1617
1643
  };
1644
+ /**
1645
+ * Open one model's meta editor, seeded from its stored override.
1646
+ * @param entry - the model row the editor belongs to.
1647
+ */
1648
+ const openEditor = (entry) => {
1649
+ const stored = meta[entry.model];
1650
+ setEditing(entry.model);
1651
+ setNotice(void 0);
1652
+ setDraft({
1653
+ contextWindow: stored?.contextWindow === void 0 ? "" : String(stored.contextWindow),
1654
+ maxTokens: stored?.maxTokens === void 0 ? "" : String(stored.maxTokens),
1655
+ text: stored?.input === void 0 ? true : stored.input.includes("text"),
1656
+ image: stored?.input === void 0 ? false : stored.input.includes("image")
1657
+ });
1658
+ };
1659
+ /**
1660
+ * Write one model's override away, or remove it.
1661
+ *
1662
+ * The numeric fields stay unoverridden when left blank; the modality boxes
1663
+ * always state their whole set, because a box cannot tell "left alone" from
1664
+ * "chosen".
1665
+ * @param model - the bare model name.
1666
+ * @param facts - the override to store, or undefined to remove the entry.
1667
+ */
1668
+ const persistMeta = (model, facts) => {
1669
+ const next = { ...meta };
1670
+ if (facts === void 0) delete next[model];
1671
+ else next[model] = facts;
1672
+ const enabled = models.filter((entry) => selected.has(entry.model)).map((entry) => entry.model);
1673
+ setSaving(true);
1674
+ setError(void 0);
1675
+ (async () => {
1676
+ try {
1677
+ await api.saveModels(enabled, next);
1678
+ setMeta(next);
1679
+ setEditing(void 0);
1680
+ setSaved(true);
1681
+ } catch (failure) {
1682
+ setError(t("whitelist.failed", { message: messageOf(failure) }));
1683
+ } finally {
1684
+ setSaving(false);
1685
+ }
1686
+ })();
1687
+ };
1688
+ /** Validate the draft and write it; a refusal explains itself inline. */
1689
+ const saveEditor = (entry) => {
1690
+ const contextWindow = draft.contextWindow.trim();
1691
+ const maxTokens = draft.maxTokens.trim();
1692
+ const context = contextWindow === "" ? void 0 : Number(contextWindow);
1693
+ const output = maxTokens === "" ? void 0 : Number(maxTokens);
1694
+ if (context !== void 0 && (!Number.isSafeInteger(context) || context <= 0) || output !== void 0 && (!Number.isSafeInteger(output) || output <= 0)) {
1695
+ setNotice(t("meta.badNumber"));
1696
+ return;
1697
+ }
1698
+ if (!draft.text && !draft.image) {
1699
+ setNotice(t("meta.needModality"));
1700
+ return;
1701
+ }
1702
+ const input = [...draft.text ? ["text"] : [], ...draft.image ? ["image"] : []];
1703
+ persistMeta(entry.model, {
1704
+ ...context === void 0 ? {} : { contextWindow: context },
1705
+ ...output === void 0 ? {} : { maxTokens: output },
1706
+ input
1707
+ });
1708
+ };
1618
1709
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1619
1710
  className: NearTokenSection_module_css_default.card,
1620
1711
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -1715,7 +1806,7 @@ window.__ModuleLoader__.load({
1715
1806
  children: [visible.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1716
1807
  className: NearTokenSection_module_css_default.hint,
1717
1808
  children: t("whitelist.noMatch")
1718
- }) : visible.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1809
+ }) : visible.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1719
1810
  className: NearTokenSection_module_css_default.row,
1720
1811
  onMouseEnter: (event) => {
1721
1812
  showTip(entry, event.currentTarget);
@@ -1741,9 +1832,155 @@ window.__ModuleLoader__.load({
1741
1832
  className: NearTokenSection_module_css_default.rowRatio,
1742
1833
  children: t("whitelist.minRatio")
1743
1834
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RatioChip, { ratio: String(entry.minRatio) + "x" })] })]
1835
+ }),
1836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1837
+ type: "button",
1838
+ className: meta[entry.model] === void 0 ? NearTokenSection_module_css_default.metaBtn : NearTokenSection_module_css_default.metaBtn + " " + NearTokenSection_module_css_default.metaBtnOn,
1839
+ onClick: () => {
1840
+ if (editing === entry.model) setEditing(void 0);
1841
+ else openEditor(entry);
1842
+ },
1843
+ children: meta[entry.model] === void 0 ? t("meta.edit") : t("meta.overridden")
1844
+ })
1845
+ ]
1846
+ }), editing !== entry.model ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1847
+ className: NearTokenSection_module_css_default.metaEditor,
1848
+ children: [
1849
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1850
+ className: NearTokenSection_module_css_default.metaTitle,
1851
+ children: t("meta.editorTitle")
1852
+ }),
1853
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1854
+ className: NearTokenSection_module_css_default.metaIntro,
1855
+ children: t("meta.editorIntro")
1856
+ }),
1857
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1858
+ className: NearTokenSection_module_css_default.metaField,
1859
+ children: [
1860
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1861
+ className: NearTokenSection_module_css_default.metaLabel,
1862
+ children: t("meta.contextWindow")
1863
+ }),
1864
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1865
+ className: NearTokenSection_module_css_default.metaInput,
1866
+ type: "number",
1867
+ min: 1,
1868
+ step: 1,
1869
+ value: draft.contextWindow,
1870
+ placeholder: entry.contextWindow === void 0 ? t("meta.undeclared") : String(entry.contextWindow),
1871
+ onChange: (event) => {
1872
+ setDraft((current) => ({
1873
+ ...current,
1874
+ contextWindow: event.target.value
1875
+ }));
1876
+ }
1877
+ }),
1878
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1879
+ className: NearTokenSection_module_css_default.metaHint,
1880
+ children: entry.contextWindow === void 0 ? t("meta.undeclared") : t("meta.declaredContext", { value: String(entry.contextWindow) })
1881
+ })
1882
+ ]
1883
+ }),
1884
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1885
+ className: NearTokenSection_module_css_default.metaField,
1886
+ children: [
1887
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1888
+ className: NearTokenSection_module_css_default.metaLabel,
1889
+ children: t("meta.maxTokens")
1890
+ }),
1891
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1892
+ className: NearTokenSection_module_css_default.metaInput,
1893
+ type: "number",
1894
+ min: 1,
1895
+ step: 1,
1896
+ value: draft.maxTokens,
1897
+ placeholder: entry.maxTokens === void 0 ? t("meta.undeclared") : String(entry.maxTokens),
1898
+ onChange: (event) => {
1899
+ setDraft((current) => ({
1900
+ ...current,
1901
+ maxTokens: event.target.value
1902
+ }));
1903
+ }
1904
+ }),
1905
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1906
+ className: NearTokenSection_module_css_default.metaHint,
1907
+ children: entry.maxTokens === void 0 ? t("meta.undeclared") : t("meta.declaredMaxTokens", { value: String(entry.maxTokens) })
1908
+ })
1909
+ ]
1910
+ }),
1911
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1912
+ className: NearTokenSection_module_css_default.metaField,
1913
+ children: [
1914
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1915
+ className: NearTokenSection_module_css_default.metaLabel,
1916
+ children: t("meta.input")
1917
+ }),
1918
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1919
+ className: NearTokenSection_module_css_default.metaCheck,
1920
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1921
+ type: "checkbox",
1922
+ checked: draft.text,
1923
+ onChange: (event) => {
1924
+ setDraft((current) => ({
1925
+ ...current,
1926
+ text: event.target.checked
1927
+ }));
1928
+ }
1929
+ }), t("meta.inputText")]
1930
+ }),
1931
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1932
+ className: NearTokenSection_module_css_default.metaCheck,
1933
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1934
+ type: "checkbox",
1935
+ checked: draft.image,
1936
+ onChange: (event) => {
1937
+ setDraft((current) => ({
1938
+ ...current,
1939
+ image: event.target.checked
1940
+ }));
1941
+ }
1942
+ }), t("meta.inputImage")]
1943
+ }),
1944
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1945
+ className: NearTokenSection_module_css_default.metaHint,
1946
+ children: entry.input === void 0 || entry.input.length === 0 ? t("meta.undeclared") : t("meta.declaredInput", { value: entry.input.join(" + ") })
1947
+ })
1948
+ ]
1949
+ }),
1950
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1951
+ className: NearTokenSection_module_css_default.metaActions,
1952
+ children: [
1953
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1954
+ type: "button",
1955
+ className: NearTokenSection_module_css_default.buttonPrimary,
1956
+ disabled: saving,
1957
+ onClick: () => {
1958
+ saveEditor(entry);
1959
+ },
1960
+ children: saving ? t("meta.saving") : t("meta.save")
1961
+ }),
1962
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1963
+ type: "button",
1964
+ className: NearTokenSection_module_css_default.button,
1965
+ disabled: saving || meta[entry.model] === void 0,
1966
+ onClick: () => {
1967
+ persistMeta(entry.model, void 0);
1968
+ },
1969
+ children: t("meta.clear")
1970
+ }),
1971
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1972
+ type: "button",
1973
+ className: NearTokenSection_module_css_default.button,
1974
+ disabled: saving,
1975
+ onClick: () => {
1976
+ setEditing(void 0);
1977
+ },
1978
+ children: t("meta.cancel")
1979
+ })
1980
+ ]
1744
1981
  })
1745
1982
  ]
1746
- }, entry.model)), tip === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1983
+ })] }, entry.model)), tip === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1747
1984
  className: NearTokenSection_module_css_default.tip,
1748
1985
  style: {
1749
1986
  top: tip.top,
@@ -2093,6 +2330,26 @@ window.__ModuleLoader__.load({
2093
2330
  "whitelist.hint": "勾选即自动保存;没勾选的不会出现在模型选择器里。「全部显示」会清空白名单。",
2094
2331
  "whitelist.keepOne": "至少要保留一个模型;想放开全部请点「全部显示」。",
2095
2332
  "whitelist.cleared": "已清空勾选;勾选要显示的模型后会立即保存。",
2333
+ "meta.edit": "覆盖",
2334
+ "meta.overridden": "已覆盖",
2335
+ "meta.editorTitle": "元信息覆盖",
2336
+ "meta.editorIntro": "填了的字段会盖过站点声明;留空的字段沿用站点声明或默认值。",
2337
+ "meta.contextWindow": "上下文(tokens)",
2338
+ "meta.maxTokens": "最大输出(tokens)",
2339
+ "meta.input": "输入类型",
2340
+ "meta.inputText": "文本",
2341
+ "meta.inputImage": "图像",
2342
+ "meta.declaredContext": "站点声明 {value}",
2343
+ "meta.declaredMaxTokens": "站点声明 {value}",
2344
+ "meta.declaredInput": "站点声明 {value}",
2345
+ "meta.undeclared": "站点未声明",
2346
+ "meta.save": "保存",
2347
+ "meta.clear": "清除覆盖",
2348
+ "meta.cancel": "取消",
2349
+ "meta.saving": "正在保存…",
2350
+ "meta.saved": "已保存,模型选择器已刷新",
2351
+ "meta.badNumber": "上下文与最大输出必须是正整数。",
2352
+ "meta.needModality": "输入类型至少勾选一项。",
2096
2353
  "images.title": "图像生成",
2097
2354
  "images.intro": "开启后模型可以调用 generate_image 工具生图。勾选要用的生图模型,并为每个模型指定走哪个分组(决定计费与可用性)。",
2098
2355
  "images.enable": "启用 generate_image 工具",
@@ -2188,6 +2445,26 @@ window.__ModuleLoader__.load({
2188
2445
  "whitelist.hint": "Every change saves itself; unchecked models stay out of the picker. \"Show all\" clears the whitelist.",
2189
2446
  "whitelist.keepOne": "Keep at least one model; use \"Show all\" to offer everything again.",
2190
2447
  "whitelist.cleared": "Boxes cleared; checking a model saves the list you want.",
2448
+ "meta.edit": "Override",
2449
+ "meta.overridden": "Overridden",
2450
+ "meta.editorTitle": "Meta overrides",
2451
+ "meta.editorIntro": "A filled field overrides the site's declaration; an empty one falls back to the site or the default.",
2452
+ "meta.contextWindow": "Context (tokens)",
2453
+ "meta.maxTokens": "Max output (tokens)",
2454
+ "meta.input": "Input types",
2455
+ "meta.inputText": "Text",
2456
+ "meta.inputImage": "Image",
2457
+ "meta.declaredContext": "site declares {value}",
2458
+ "meta.declaredMaxTokens": "site declares {value}",
2459
+ "meta.declaredInput": "site declares {value}",
2460
+ "meta.undeclared": "not declared by the site",
2461
+ "meta.save": "Save",
2462
+ "meta.clear": "Clear override",
2463
+ "meta.cancel": "Cancel",
2464
+ "meta.saving": "Saving…",
2465
+ "meta.saved": "Saved; the model picker has been refreshed",
2466
+ "meta.badNumber": "Context and max output must be positive integers.",
2467
+ "meta.needModality": "Keep at least one input type checked.",
2191
2468
  "images.title": "Image generation",
2192
2469
  "images.intro": "Once on, the model can call the generate_image tool. Check the picture models you want and pick the group each one bills to.",
2193
2470
  "images.enable": "Enable the generate_image tool",