dsh-gpt-adapter 0.2.3 → 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.
- package/README.md +22 -3
- package/README.zh-CN.md +22 -3
- package/dist/src/context-window.d.ts +25 -0
- package/dist/src/host.d.ts +27 -0
- package/dist/src/settings-overlay.d.ts +16 -2
- package/lib/client.js +22 -7
- package/lib/core.js +28 -1
- package/lib/index.js +428 -62
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Install one plugin to reuse local Codex instructions, skills, enabled plugin res
|
|
|
12
12
|
|
|
13
13
|
- Discover upstream models with `GET /models` and retain stale entries until explicit cleanup.
|
|
14
14
|
- Provide the GPT reasoning preset `low / medium / high / xhigh / max / ultra` through the native Models page and conversation menu.
|
|
15
|
+
- Reuse the native per-model context field for manual capacities and automatic resolution, with support for K/M input.
|
|
15
16
|
- Offer independent Standard and Fast speed choices. Fast sends `service_tier: "priority"`; Ultrafast requires an explicit upstream declaration or override.
|
|
16
17
|
- Preserve optional function arguments on GPT Responses requests by setting missing `strict` values to `false`.
|
|
17
18
|
- Read Codex instruction files and refresh them at the next model step without repeating unchanged baselines.
|
|
@@ -22,14 +23,14 @@ Reasoning and speed presets are requests to the configured gateway, not guarante
|
|
|
22
23
|
|
|
23
24
|
## Compatibility and installation
|
|
24
25
|
|
|
25
|
-
The native integration targets DSH `0.2.2-rc.1`, Cordis `4.1.0`, and the pinned adapter source hash. The development dependency uses Pi AI `1.3.0`. Installed third-party package files are never edited. The
|
|
26
|
+
The native integration targets DSH `0.2.2-rc.1`, Cordis `4.1.0`, and the pinned adapter source hash. The development dependency uses Pi AI `1.3.0`. Installed third-party package files are never edited. The package version is `dsh-gpt-adapter@0.2.5`.
|
|
26
27
|
|
|
27
28
|
Requires Node.js `>=24.9.0` and DSH. Source builds also require pnpm.
|
|
28
29
|
|
|
29
30
|
Install the published package in the web profile:
|
|
30
31
|
|
|
31
32
|
```sh
|
|
32
|
-
dsh plugin --profile web add dsh-gpt-adapter@0.2.
|
|
33
|
+
dsh plugin --profile web add dsh-gpt-adapter@0.2.5
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
Restart the DSH host after installing or upgrading. Configure GPT connections under **Settings → Models**; Codex environment reuse is enabled by default. The plugin extends the existing native settings and conversation controls.
|
|
@@ -42,7 +43,7 @@ cd dsh-gpt-adapter
|
|
|
42
43
|
pnpm install --frozen-lockfile
|
|
43
44
|
mkdir -p artifacts
|
|
44
45
|
pnpm pack --pack-destination artifacts
|
|
45
|
-
dsh plugin --profile web add ./artifacts/dsh-gpt-adapter-0.2.
|
|
46
|
+
dsh plugin --profile web add ./artifacts/dsh-gpt-adapter-0.2.5.tgz
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
`pnpm pack` runs the production build.
|
|
@@ -125,6 +126,24 @@ An empty `mcpAllowlist` imports all enabled declared servers. A nonempty list fi
|
|
|
125
126
|
|
|
126
127
|
Capability precedence is user override, explicit upstream metadata, external catalog, then preset. Catalog requests never receive the provider API key. Model-list responses may omit capability metadata. Reasoning is sent as `reasoning.effort` for Responses and `reasoning_effort` for Chat Completions; the selected protocol is preserved.
|
|
127
128
|
|
|
129
|
+
### Context windows
|
|
130
|
+
|
|
131
|
+
Under **Settings → Models → Custom settings → Model catalog**, edit the native **Context window** field. The plugin reuses this field and adds no separate context editor. Enter a count, `516K` (`516000` tokens), or `1M` (`1000000` tokens); clear the field and save to restore automatic resolution.
|
|
132
|
+
|
|
133
|
+
Inherited model rows and provider defaults participate in edit detection and final budget validation. A failed legacy cleanup restores the previous native capacity while preserving unrelated edits.
|
|
134
|
+
|
|
135
|
+
An empty native field means automatic resolution. Automatic capacities stay in the effective model information; the editable draft contains manual values only, including existing legacy overrides. An explicit value equal to the current automatic capacity is still saved as a manual value.
|
|
136
|
+
|
|
137
|
+
Capacity suffixes use decimal units. Automatic resolution uses a distinguishable explicit provider default, upstream model metadata, the configured capability catalog, the shipped exact-model preset, then the native catalog/DSH fallback. Shipped presets are dated data, not a live fetch from OpenAI: `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-luna`, and `gpt-5.4` use `1050000`; `gpt-4.1` uses `1047576`; `gpt-4o` uses `128000`. Only documented snapshot aliases share these presets. References and verification dates are in [the preset table](src/context-window.ts).
|
|
138
|
+
|
|
139
|
+
Existing native per-model values, including catalog `modelOverrides`, and legacy JSON context overrides remain effective until deliberately edited. Editing the native context field clears only that model's legacy context override; clearing the field removes its manual context values while retaining provider defaults and other settings. Saving unrelated settings or discovering models does not turn automatic values into manual overrides. Identical model IDs on different providers are independent.
|
|
140
|
+
|
|
141
|
+
Providers using native catalog `modelOverrides` keep their catalog configuration during synchronization. Discovery and stale cleanup update the plugin snapshot without creating an incompatible explicit `models` list or deleting native overrides.
|
|
142
|
+
|
|
143
|
+
Native forms reject stale drafts when their automatic capacities change; refresh the form before retrying. Context, output-limit, and relevant provider-default edits are checked against the saved draft's output budget and native compaction headroom. An omitted output limit uses the native model catalog or provider/schema default. Invalid saves leave the previous values in place.
|
|
144
|
+
|
|
145
|
+
Changes apply to the next prepared call; calls already prepared retain their captured capacity. Model information, the inference model, overflow detection, and native compaction use the same effective window. Maximum output tokens and DSH's compaction policy remain independent. A larger local window does not increase the gateway's accepted limit.
|
|
146
|
+
|
|
128
147
|
Preset reasoning fields are projected into the native UI rather than persisted into native model configuration. Disabling GPT adaptation restores the native model values and schema. Speed selections are persisted per session. Synchronization failures retain the previous snapshot; absent models remain stale until explicit cleanup.
|
|
129
148
|
|
|
130
149
|
GPT model snapshots and speed selections are stored under `$DSH_HOME/storages/gpt-adapter`. Codex source files and imported MCP credentials are not copied there. The DSH host owns normal session transcripts and logs.
|
package/README.zh-CN.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
- 通过 `GET /models` 发现上游模型;失效模型保留到用户主动清理。
|
|
14
14
|
- 在原生模型设置页和对话菜单中提供 `low / medium / high / xhigh / max / ultra` 六档思考预设。
|
|
15
|
+
- 复用原生逐模型上下文字段,支持 K/M 输入、手动容量和自动解析。
|
|
15
16
|
- 提供独立的 Standard 和 Fast 速度选择。Fast 发送 `service_tier: "priority"`;Ultrafast 由上游明确声明或用户覆盖提供。
|
|
16
17
|
- 为 GPT Responses 函数工具补齐缺失的 `strict: false`,保留可选参数。
|
|
17
18
|
- 读取 Codex 指令,在下一模型步骤更新;内容不变时不重复注入。
|
|
@@ -22,14 +23,14 @@
|
|
|
22
23
|
|
|
23
24
|
## 兼容性与安装
|
|
24
25
|
|
|
25
|
-
原生集成面向 DSH `0.2.2-rc.1`、Cordis `4.1.0`,并校验适配器源码指纹。开发依赖固定 Pi AI `1.3.0
|
|
26
|
+
原生集成面向 DSH `0.2.2-rc.1`、Cordis `4.1.0`,并校验适配器源码指纹。开发依赖固定 Pi AI `1.3.0`。插件不会修改已安装的第三方包文件。插件版本为 `dsh-gpt-adapter@0.2.5`。
|
|
26
27
|
|
|
27
28
|
需要 Node.js `>=24.9.0` 和 DSH。源码构建另外需要 pnpm。
|
|
28
29
|
|
|
29
30
|
在 `web` 配置档(profile)中安装已发布的 npm 包:
|
|
30
31
|
|
|
31
32
|
```sh
|
|
32
|
-
dsh plugin --profile web add dsh-gpt-adapter@0.2.
|
|
33
|
+
dsh plugin --profile web add dsh-gpt-adapter@0.2.5
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
安装或升级后重启 DSH 宿主。在「设置 → 模型」中配置 GPT 连接;Codex 环境复用默认开启。插件扩展现有原生设置与对话控件。
|
|
@@ -42,7 +43,7 @@ cd dsh-gpt-adapter
|
|
|
42
43
|
pnpm install --frozen-lockfile
|
|
43
44
|
mkdir -p artifacts
|
|
44
45
|
pnpm pack --pack-destination artifacts
|
|
45
|
-
dsh plugin --profile web add ./artifacts/dsh-gpt-adapter-0.2.
|
|
46
|
+
dsh plugin --profile web add ./artifacts/dsh-gpt-adapter-0.2.5.tgz
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
`pnpm pack` 会自动执行生产构建。
|
|
@@ -125,6 +126,24 @@ codexCompatibility:
|
|
|
125
126
|
|
|
126
127
|
能力优先级为用户覆盖、上游明确元数据、外部能力目录、预设。能力目录请求不携带提供商 API 密钥;模型列表可以不包含能力元数据。Responses 使用 `reasoning.effort`,Chat Completions 使用 `reasoning_effort`,保留用户选定的协议。
|
|
127
128
|
|
|
129
|
+
### 上下文窗口
|
|
130
|
+
|
|
131
|
+
在「设置 → 模型 → 自定义设置 → 模型目录」中,直接编辑原生「上下文窗口」字段。插件复用这一字段,不再增加独立编辑入口。可输入完整词元数、`516K`(`516000`)或 `1M`(`1000000`);清空字段并保存可恢复自动解析。
|
|
132
|
+
|
|
133
|
+
编辑前后状态比较和最终预算校验会纳入继承模型及提供商默认值。旧覆盖清理失败时,恢复原生容量并保留无关修改。
|
|
134
|
+
|
|
135
|
+
原生字段留空表示自动解析。自动容量保留在模型有效信息中,编辑草稿只显示手动值(包括已有旧版覆盖);明确输入与当前自动容量相同的数值,也会保存为手动值。
|
|
136
|
+
|
|
137
|
+
容量后缀使用十进制单位。自动解析依次采用可辨识的显式提供商默认值、上游模型元数据、已配置的能力目录、插件内置的精确模型预设、原生目录或 DSH 后备值。内置预设是带核验日期的数据,不会实时抓取 OpenAI 页面:`gpt-6-astra`、`gpt-6.1-sol`、`gpt-6.1-terra`、`gpt-6-luna`、`gpt-5.4` 为 `1050000`,`gpt-4.1` 为 `1047576`,`gpt-4o` 为 `128000`;仅为有文档依据的快照别名复用预设。参考页面和核验日期见[预设表](src/context-window.ts)。
|
|
138
|
+
|
|
139
|
+
已有原生模型数值(包括目录模型的 `modelOverrides`)和旧版 JSON 上下文覆盖继续生效,直到用户主动编辑。编辑原生上下文字段时,仅清除该模型的旧版上下文覆盖;清空字段会删除该模型的手动上下文数值,保留提供商默认值和其他设置。保存无关设置或发现模型不会把自动值固化为手动覆盖。同名模型在不同提供商下独立设置。
|
|
140
|
+
|
|
141
|
+
使用原生目录 `modelOverrides` 的提供商在同步时保留目录配置。模型发现和失效清理只更新插件快照,不会生成不兼容的显式 `models` 列表,也不会删除原生覆盖。
|
|
142
|
+
|
|
143
|
+
原生表单的自动容量变化后,过期草稿会被拒绝,刷新表单再保存即可。修改上下文、最大输出或相关提供商默认值时,会校验同次保存的输出预算和原生压缩预留;未填写输出上限时采用原生模型目录或提供商、参数结构的默认值;无效数值不会覆盖已保存设置。
|
|
144
|
+
|
|
145
|
+
修改对下一次准备的调用生效,已准备的调用继续使用原有容量。模型信息、推理模型、溢出判断和原生上下文压缩采用同一有效窗口;最大输出词元设置与 DSH 原生压缩策略保持独立。扩大本地窗口不会提高网关实际接受的上限。
|
|
146
|
+
|
|
128
147
|
思考预设只投影到原生界面,不写入原生模型配置。关闭 GPT 自动适配后恢复原生值和参数结构。速度选择按会话持久化。同步失败保留旧快照,失效模型保留到主动清理。
|
|
129
148
|
|
|
130
149
|
GPT 模型快照与速度选择保存在 `$DSH_HOME/storages/gpt-adapter`。Codex 源文件和导入的 MCP 凭证不会复制到该位置。正常会话记录和日志由 DSH 宿主管理。
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type ContextWindowMode = 'default' | '516k' | '1m' | 'custom';
|
|
2
|
+
export type ContextWindowSource = 'legacy-override' | 'native-user' | 'provider-default' | 'upstream' | 'capability-catalog' | 'official-preset' | 'native-default';
|
|
3
|
+
export type ContextWindowResolution = {
|
|
4
|
+
mode: ContextWindowMode;
|
|
5
|
+
effectiveTokens: number;
|
|
6
|
+
defaultTokens: number;
|
|
7
|
+
source: ContextWindowSource;
|
|
8
|
+
};
|
|
9
|
+
export declare const OFFICIAL_CONTEXT_WINDOWS: Record<string, {
|
|
10
|
+
tokens: number;
|
|
11
|
+
url: string;
|
|
12
|
+
verifiedAt: string;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function validContextWindow(value: unknown): value is number;
|
|
15
|
+
export declare function contextWindowMode(tokens: number): ContextWindowMode;
|
|
16
|
+
export declare function contextWindowTokens(mode: ContextWindowMode, customTokens?: number): number | undefined;
|
|
17
|
+
export declare function resolveContextWindow(options: {
|
|
18
|
+
modelId: string;
|
|
19
|
+
legacy?: unknown;
|
|
20
|
+
native?: unknown;
|
|
21
|
+
providerDefault?: unknown;
|
|
22
|
+
upstream?: unknown;
|
|
23
|
+
catalog?: unknown;
|
|
24
|
+
nativeDefault?: unknown;
|
|
25
|
+
}): ContextWindowResolution;
|
package/dist/src/host.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { Service, type Context } from '@deepseek-ai/cordis';
|
|
|
2
2
|
import z from '@deepseek-ai/schemastery';
|
|
3
3
|
import { bindTypertRemote } from '@deepseek-ai/dsh-typert-protocol';
|
|
4
4
|
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client';
|
|
5
|
+
import { type ContextWindowMode, type ContextWindowResolution } from './context-window.js';
|
|
6
|
+
import { type ContextWindowEdit, type ContextWindowWriter } from './settings-overlay.js';
|
|
5
7
|
import { type CodexCompatibilityConfig, type CodexCompatibilityRuntime } from './codex.js';
|
|
6
8
|
import type { ModelCapabilities, ServiceTier } from './types.js';
|
|
7
9
|
type RouteOptions = {
|
|
@@ -51,6 +53,7 @@ export declare class GptModels extends Service {
|
|
|
51
53
|
private readonly options;
|
|
52
54
|
private readonly settingsNs;
|
|
53
55
|
codex?: CodexCompatibilityRuntime;
|
|
56
|
+
contextWriter: ContextWindowWriter | undefined;
|
|
54
57
|
readonly typertRemote: ReturnType<typeof bindTypertRemote>;
|
|
55
58
|
private readonly runners;
|
|
56
59
|
private readonly snapshots;
|
|
@@ -85,12 +88,36 @@ export declare class GptModels extends Service {
|
|
|
85
88
|
capabilities: {
|
|
86
89
|
[x: string]: ModelCapabilities;
|
|
87
90
|
};
|
|
91
|
+
contextWindows: {
|
|
92
|
+
[k: string]: ContextWindowResolution;
|
|
93
|
+
};
|
|
94
|
+
contextRevision: number;
|
|
88
95
|
options: RouteOptions;
|
|
89
96
|
};
|
|
90
97
|
configure(provider: string, enabled: boolean): Promise<void>;
|
|
91
98
|
updateOptions(provider: string, refreshIntervalMs: number, capabilityCatalogUrl: string, overridesJSON: string): Promise<void>;
|
|
92
99
|
refresh(provider: string): Promise<void>;
|
|
93
100
|
removeStale(provider: string): Promise<void>;
|
|
101
|
+
/** Internal model-list writes must use the same manual fields as native drafts. */
|
|
102
|
+
private editableModel;
|
|
103
|
+
editableContextWindow(provider: string, model: Record<string, any>): any;
|
|
104
|
+
/** Resolve raw metadata separately from merged capabilities and cached overrides. */
|
|
105
|
+
contextWindow(provider: string, modelId: string, nativeDefault?: number, profileOverride?: {
|
|
106
|
+
defaultContextWindow?: number;
|
|
107
|
+
models?: Array<{
|
|
108
|
+
id: string;
|
|
109
|
+
[key: string]: unknown;
|
|
110
|
+
}>;
|
|
111
|
+
modelOverrides?: Record<string, Record<string, unknown>>;
|
|
112
|
+
}): ContextWindowResolution;
|
|
113
|
+
/** Both native form saves and the compatibility RPC validate the same budget. */
|
|
114
|
+
validateContextWindow(provider: string, model: Record<string, any>, profile: Record<string, any>): void;
|
|
115
|
+
contextWriteRevision(): number | undefined;
|
|
116
|
+
/** Public form revisions also cover changes to projected model capacities. */
|
|
117
|
+
private modelsRevision;
|
|
118
|
+
/** Remove only legacy context fields after the matching native save commits. */
|
|
119
|
+
clearLegacyContext(edits: ContextWindowEdit[], expected?: number): Promise<void>;
|
|
120
|
+
setContextWindow(provider: string, modelId: string, mode: ContextWindowMode, customTokens?: number, expectedRevision?: number): Promise<void>;
|
|
94
121
|
setSpeed(sessionId: SessionId, provider: string, modelId: string, tier: ServiceTier): Promise<void>;
|
|
95
122
|
speed(sessionId: SessionId, provider: string, modelId: string): {
|
|
96
123
|
selected: ServiceTier;
|
|
@@ -5,9 +5,23 @@ type SettingsLike = {
|
|
|
5
5
|
write?: (ns: string, change: (current: any, base: any, schema: any) => any, expected?: number, paths?: string[][]) => Promise<void>;
|
|
6
6
|
};
|
|
7
7
|
export type CapabilityResolver = (provider: string, model: JsonObject, profile?: JsonObject) => ModelCapabilities | undefined;
|
|
8
|
-
export
|
|
8
|
+
export type ContextWindowEdit = {
|
|
9
|
+
provider: string;
|
|
10
|
+
modelId: string;
|
|
11
|
+
previousTokens: number | undefined;
|
|
12
|
+
};
|
|
13
|
+
type ContextWrites = {
|
|
14
|
+
editableContext?(provider: string, model: JsonObject): number | undefined;
|
|
15
|
+
validate?(provider: string, model: JsonObject, profile: JsonObject): void;
|
|
16
|
+
revision(): number | undefined;
|
|
17
|
+
saved(edits: ContextWindowEdit[], revision: number | undefined): Promise<void>;
|
|
18
|
+
};
|
|
19
|
+
export type ContextWindowWriter = (provider: string, modelId: string, tokens: number | undefined, expected?: number) => Promise<void>;
|
|
20
|
+
export declare function projectModel(provider: string, model: JsonObject, resolve: CapabilityResolver, profile?: JsonObject, includeContext?: boolean): JsonObject;
|
|
9
21
|
/** A view of native configuration; the original object and its stored fields stay intact. */
|
|
10
22
|
export declare function projectConfiguration(value: JsonObject | undefined, resolve: CapabilityResolver): JsonObject | undefined;
|
|
11
23
|
/** Dispose returns the native settings page to its original schema and values. */
|
|
12
|
-
export declare function installSettingsOverlay(settings: SettingsLike, resolve: CapabilityResolver): () => void
|
|
24
|
+
export declare function installSettingsOverlay(settings: SettingsLike, resolve: CapabilityResolver, contextWrites?: ContextWrites): (() => void) & {
|
|
25
|
+
setContextWindow: ContextWindowWriter;
|
|
26
|
+
};
|
|
13
27
|
export {};
|
package/lib/client.js
CHANGED
|
@@ -48,17 +48,21 @@ function apply(ctx) {
|
|
|
48
48
|
const [value, setValue] = (0, import_react.useState)();
|
|
49
49
|
const [error, setError] = (0, import_react.useState)("");
|
|
50
50
|
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
51
|
+
const requests = (0, import_react.useRef)({ sequence: 0, writing: false });
|
|
51
52
|
(0, import_react.useEffect)(() => {
|
|
52
53
|
let active = true;
|
|
54
|
+
requests.current.writing = false;
|
|
55
|
+
setBusy(false);
|
|
53
56
|
const refresh = () => {
|
|
54
|
-
if (!provider) return;
|
|
57
|
+
if (!provider || requests.current.writing) return;
|
|
58
|
+
const sequence = ++requests.current.sequence;
|
|
55
59
|
void call("status", { provider }).then((value2) => {
|
|
56
|
-
if (active) {
|
|
60
|
+
if (active && sequence === requests.current.sequence) {
|
|
57
61
|
setValue(value2);
|
|
58
62
|
setError("");
|
|
59
63
|
}
|
|
60
64
|
}).catch((error2) => {
|
|
61
|
-
if (active)
|
|
65
|
+
if (active && sequence === requests.current.sequence)
|
|
62
66
|
setError(
|
|
63
67
|
error2 instanceof Error ? error2.message : "\u65E0\u6CD5\u8BFB\u53D6 GPT \u8BBE\u7F6E"
|
|
64
68
|
);
|
|
@@ -68,22 +72,32 @@ function apply(ctx) {
|
|
|
68
72
|
const timer = setInterval(refresh, 3e3);
|
|
69
73
|
return () => {
|
|
70
74
|
active = false;
|
|
75
|
+
requests.current.sequence++;
|
|
71
76
|
clearInterval(timer);
|
|
72
77
|
};
|
|
73
78
|
}, [provider]);
|
|
74
79
|
async function act(method, args) {
|
|
75
|
-
if (
|
|
80
|
+
if (requests.current.writing) return;
|
|
81
|
+
requests.current.writing = true;
|
|
82
|
+
const sequence = ++requests.current.sequence;
|
|
76
83
|
setBusy(true);
|
|
77
84
|
try {
|
|
78
85
|
await call(method, args);
|
|
79
|
-
|
|
86
|
+
if (sequence !== requests.current.sequence) return false;
|
|
87
|
+
const next = await call("status", { provider });
|
|
88
|
+
if (sequence !== requests.current.sequence) return false;
|
|
89
|
+
setValue(next);
|
|
80
90
|
setError("");
|
|
81
91
|
return true;
|
|
82
92
|
} catch (error2) {
|
|
83
|
-
|
|
93
|
+
if (sequence === requests.current.sequence)
|
|
94
|
+
setError(error2 instanceof Error ? error2.message : "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
|
|
84
95
|
return false;
|
|
85
96
|
} finally {
|
|
86
|
-
|
|
97
|
+
if (sequence === requests.current.sequence) {
|
|
98
|
+
requests.current.writing = false;
|
|
99
|
+
setBusy(false);
|
|
100
|
+
}
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
return { value, error, busy, act };
|
|
@@ -220,6 +234,7 @@ function apply(ctx) {
|
|
|
220
234
|
]
|
|
221
235
|
}
|
|
222
236
|
) }),
|
|
237
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: native_settings_styles_default.advancedHint, children: "\u4E0A\u4E0B\u6587\u7A97\u53E3\u8BF7\u5728\u300C\u81EA\u5B9A\u4E49\u8BBE\u7F6E \u2192 \u6A21\u578B\u76EE\u5F55\u300D\u7684\u539F\u751F\u5B57\u6BB5\u4E2D\u4FEE\u6539\uFF0C\u652F\u6301 516K\u30011M \u6216\u81EA\u5B9A\u4E49\u6570\u503C\uFF1B\u6E05\u7A7A\u540E\u4FDD\u5B58\u53EF\u6062\u590D\u81EA\u52A8\u503C\u3002" }),
|
|
223
238
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
224
239
|
AdvancedSettings,
|
|
225
240
|
{
|
package/lib/core.js
CHANGED
|
@@ -121,6 +121,33 @@ function capabilityForSelection(capabilities, reasoningId, serviceTier2) {
|
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// src/context-window.ts
|
|
125
|
+
var officialModels = [
|
|
126
|
+
["gpt-6-astra", 105e4],
|
|
127
|
+
["gpt-6.1-sol", 105e4],
|
|
128
|
+
["gpt-6.1-terra", 105e4],
|
|
129
|
+
["gpt-6-luna", 105e4],
|
|
130
|
+
["gpt-5.4", 105e4],
|
|
131
|
+
["gpt-4.1", 1047576],
|
|
132
|
+
["gpt-4o", 128e3],
|
|
133
|
+
["gpt-5.4-2026-03-05", 105e4, "gpt-5.4"],
|
|
134
|
+
["gpt-4.1-2025-04-14", 1047576, "gpt-4.1"],
|
|
135
|
+
["gpt-4o-2024-08-06", 128e3, "gpt-4o"]
|
|
136
|
+
];
|
|
137
|
+
var OFFICIAL_CONTEXT_WINDOWS = Object.fromEntries(
|
|
138
|
+
officialModels.map(([id, tokens, page]) => [
|
|
139
|
+
id,
|
|
140
|
+
{
|
|
141
|
+
tokens,
|
|
142
|
+
url: `https://developers.openai.com/api/docs/models/${page ?? id}`,
|
|
143
|
+
verifiedAt: "2026-11-13"
|
|
144
|
+
}
|
|
145
|
+
])
|
|
146
|
+
);
|
|
147
|
+
function validContextWindow(value) {
|
|
148
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
124
151
|
// src/sync.ts
|
|
125
152
|
import { createHash } from "node:crypto";
|
|
126
153
|
var MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
@@ -298,7 +325,7 @@ function parseCapabilityHints(row, modelId) {
|
|
|
298
325
|
...typeof defaultReasoningValue === "string" ? { defaultReasoningId: defaultReasoningValue } : {},
|
|
299
326
|
...hasTierSignal ? { serviceTiers: tiers } : {},
|
|
300
327
|
...defaultTier ? { defaultServiceTier: defaultTier } : {},
|
|
301
|
-
...
|
|
328
|
+
...validContextWindow(contextWindow) ? { contextWindow } : {},
|
|
302
329
|
...typeof maxOutputTokens === "number" && maxOutputTokens > 0 ? { maxOutputTokens } : {}
|
|
303
330
|
};
|
|
304
331
|
return Object.keys(hints).length === 0 ? void 0 : hints;
|
package/lib/index.js
CHANGED
|
@@ -196,6 +196,84 @@ function createRequestBridge(provider) {
|
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
// src/context-window.ts
|
|
200
|
+
var officialModels = [
|
|
201
|
+
["gpt-6-astra", 105e4],
|
|
202
|
+
["gpt-6.1-sol", 105e4],
|
|
203
|
+
["gpt-6.1-terra", 105e4],
|
|
204
|
+
["gpt-6-luna", 105e4],
|
|
205
|
+
["gpt-5.4", 105e4],
|
|
206
|
+
["gpt-4.1", 1047576],
|
|
207
|
+
["gpt-4o", 128e3],
|
|
208
|
+
["gpt-5.4-2026-03-05", 105e4, "gpt-5.4"],
|
|
209
|
+
["gpt-4.1-2025-04-14", 1047576, "gpt-4.1"],
|
|
210
|
+
["gpt-4o-2024-08-06", 128e3, "gpt-4o"]
|
|
211
|
+
];
|
|
212
|
+
var OFFICIAL_CONTEXT_WINDOWS = Object.fromEntries(
|
|
213
|
+
officialModels.map(([id, tokens, page]) => [
|
|
214
|
+
id,
|
|
215
|
+
{
|
|
216
|
+
tokens,
|
|
217
|
+
url: `https://developers.openai.com/api/docs/models/${page ?? id}`,
|
|
218
|
+
verifiedAt: "2026-11-13"
|
|
219
|
+
}
|
|
220
|
+
])
|
|
221
|
+
);
|
|
222
|
+
function validContextWindow(value) {
|
|
223
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
224
|
+
}
|
|
225
|
+
function contextWindowMode(tokens) {
|
|
226
|
+
return tokens === 516e3 ? "516k" : tokens === 1e6 ? "1m" : "custom";
|
|
227
|
+
}
|
|
228
|
+
function contextWindowTokens(mode, customTokens) {
|
|
229
|
+
if (!["default", "516k", "1m", "custom"].includes(mode))
|
|
230
|
+
throw new Error("\u8BF7\u9009\u62E9\u6709\u6548\u7684\u4E0A\u4E0B\u6587\u9884\u8BBE");
|
|
231
|
+
if (mode !== "custom" && customTokens !== void 0)
|
|
232
|
+
throw new Error("\u53EA\u6709\u81EA\u5B9A\u4E49\u9884\u8BBE\u63A5\u53D7\u7A97\u53E3\u6570\u503C");
|
|
233
|
+
if (mode === "custom") {
|
|
234
|
+
if (!validContextWindow(customTokens))
|
|
235
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
236
|
+
return customTokens;
|
|
237
|
+
}
|
|
238
|
+
return mode === "516k" ? 516e3 : mode === "1m" ? 1e6 : void 0;
|
|
239
|
+
}
|
|
240
|
+
function resolveContextWindow(options) {
|
|
241
|
+
const fallback = [
|
|
242
|
+
[options.providerDefault, "provider-default"],
|
|
243
|
+
[options.upstream, "upstream"],
|
|
244
|
+
[options.catalog, "capability-catalog"],
|
|
245
|
+
[
|
|
246
|
+
Object.hasOwn(OFFICIAL_CONTEXT_WINDOWS, options.modelId) ? OFFICIAL_CONTEXT_WINDOWS[options.modelId]?.tokens : void 0,
|
|
247
|
+
"official-preset"
|
|
248
|
+
],
|
|
249
|
+
[options.nativeDefault, "native-default"],
|
|
250
|
+
[1e6, "native-default"]
|
|
251
|
+
];
|
|
252
|
+
const [defaultTokens, source] = fallback.find(
|
|
253
|
+
([tokens]) => validContextWindow(tokens)
|
|
254
|
+
);
|
|
255
|
+
for (const [tokens, manualSource] of [
|
|
256
|
+
[options.legacy, "legacy-override"],
|
|
257
|
+
[options.native, "native-user"]
|
|
258
|
+
]) {
|
|
259
|
+
if (tokens === void 0) continue;
|
|
260
|
+
if (!validContextWindow(tokens))
|
|
261
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
262
|
+
return {
|
|
263
|
+
mode: contextWindowMode(tokens),
|
|
264
|
+
effectiveTokens: tokens,
|
|
265
|
+
defaultTokens,
|
|
266
|
+
source: manualSource
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
mode: "default",
|
|
271
|
+
effectiveTokens: defaultTokens,
|
|
272
|
+
defaultTokens,
|
|
273
|
+
source
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
199
277
|
// src/sync.ts
|
|
200
278
|
import { createHash } from "node:crypto";
|
|
201
279
|
var MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
@@ -373,7 +451,7 @@ function parseCapabilityHints(row, modelId) {
|
|
|
373
451
|
...typeof defaultReasoningValue === "string" ? { defaultReasoningId: defaultReasoningValue } : {},
|
|
374
452
|
...hasTierSignal ? { serviceTiers: tiers } : {},
|
|
375
453
|
...defaultTier ? { defaultServiceTier: defaultTier } : {},
|
|
376
|
-
...
|
|
454
|
+
...validContextWindow(contextWindow) ? { contextWindow } : {},
|
|
377
455
|
...typeof maxOutputTokens === "number" && maxOutputTokens > 0 ? { maxOutputTokens } : {}
|
|
378
456
|
};
|
|
379
457
|
return Object.keys(hints).length === 0 ? void 0 : hints;
|
|
@@ -731,10 +809,11 @@ var JsonStorage = class {
|
|
|
731
809
|
};
|
|
732
810
|
|
|
733
811
|
// src/host.ts
|
|
734
|
-
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
812
|
+
import { Config as NativeConfig, PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
735
813
|
import { createRequire } from "node:module";
|
|
736
814
|
import { readFileSync } from "node:fs";
|
|
737
815
|
import { createHash as createHash6 } from "node:crypto";
|
|
816
|
+
import { getBuiltinModels } from "@earendil-works/pi-ai/providers/all";
|
|
738
817
|
|
|
739
818
|
// src/native-adapter.ts
|
|
740
819
|
function installNativeAdapterBridge(prototype, capture) {
|
|
@@ -759,6 +838,12 @@ function installNativeAdapterBridge(prototype, capture) {
|
|
|
759
838
|
});
|
|
760
839
|
const models = new Proxy(snapshot.models, {
|
|
761
840
|
get(target, key) {
|
|
841
|
+
if (key === "getModel" && typeof target.getModel === "function")
|
|
842
|
+
return (provider, modelId) => {
|
|
843
|
+
const model = target.getModel(provider, modelId);
|
|
844
|
+
const capacity = extension.model.context;
|
|
845
|
+
return model && provider === options.provider && modelId === options.model && capacity?.contextWindow ? { ...model, contextWindow: capacity.contextWindow } : model;
|
|
846
|
+
};
|
|
762
847
|
if (key === "streamSimple")
|
|
763
848
|
return (model, context, settings) => {
|
|
764
849
|
const call = extension.prepare(options);
|
|
@@ -853,11 +938,12 @@ function installNativeAdapterBridge(prototype, capture) {
|
|
|
853
938
|
// src/settings-overlay.ts
|
|
854
939
|
import z from "@deepseek-ai/schemastery";
|
|
855
940
|
import { symbols } from "@deepseek-ai/cordis";
|
|
856
|
-
function projectModel(provider, model, resolve4, profile) {
|
|
941
|
+
function projectModel(provider, model, resolve4, profile, includeContext = true) {
|
|
857
942
|
const capability = resolve4(provider, model, profile);
|
|
858
943
|
if (!capability) return model;
|
|
859
944
|
return {
|
|
860
945
|
...model,
|
|
946
|
+
...includeContext && validContextWindow(capability.contextWindow) ? { contextWindow: capability.contextWindow } : {},
|
|
861
947
|
reasoningEfforts: capability.reasoning.status === "unsupported" ? false : Object.fromEntries(
|
|
862
948
|
capability.reasoning.choices.map((choice) => [
|
|
863
949
|
choice.id,
|
|
@@ -903,52 +989,91 @@ function projectSchema(json, preserveNativeLevels) {
|
|
|
903
989
|
keys.list = offered.map((level) => z.const(level));
|
|
904
990
|
return schema.toJSON();
|
|
905
991
|
}
|
|
906
|
-
function nativeWrite(next, current, resolve4) {
|
|
992
|
+
function nativeWrite(next, current, base, resolve4, contextEdits, contextWrites) {
|
|
907
993
|
if (!next.providers) return next;
|
|
908
994
|
return {
|
|
909
995
|
...next,
|
|
910
996
|
providers: Object.fromEntries(
|
|
911
997
|
Object.entries(next.providers).map(([provider, raw]) => {
|
|
912
998
|
const profile = raw;
|
|
913
|
-
|
|
914
|
-
const
|
|
999
|
+
const inherited = base?.providers?.[provider] ?? {};
|
|
1000
|
+
const ownershipProfile = {
|
|
1001
|
+
...inherited,
|
|
1002
|
+
...current.providers?.[provider]
|
|
1003
|
+
};
|
|
1004
|
+
const effectiveProfile = { ...inherited, ...profile };
|
|
1005
|
+
const ownsModels = Array.isArray(profile?.models);
|
|
1006
|
+
const models = ownsModels ? profile.models : inherited.models?.map(
|
|
1007
|
+
(model) => projectModel(provider, model, resolve4, ownershipProfile)
|
|
1008
|
+
);
|
|
1009
|
+
if (!Array.isArray(models)) return [provider, profile];
|
|
1010
|
+
const previous = ownershipProfile.models ?? [];
|
|
1011
|
+
const savedModels = models.map((model) => {
|
|
1012
|
+
const original = previous.find((row) => row.id === model.id);
|
|
1013
|
+
const capability = resolve4(provider, model, ownershipProfile);
|
|
1014
|
+
if (!capability) return model;
|
|
1015
|
+
const managed = projectModel(
|
|
1016
|
+
provider,
|
|
1017
|
+
model,
|
|
1018
|
+
resolve4,
|
|
1019
|
+
ownershipProfile
|
|
1020
|
+
);
|
|
1021
|
+
if (original && JSON.stringify(model.reasoningEfforts) !== JSON.stringify(managed.reasoningEfforts))
|
|
1022
|
+
throw new Error(
|
|
1023
|
+
"GPT \u601D\u8003\u7B49\u7EA7\u7531\u63D2\u4EF6\u9884\u8BBE\u7BA1\u7406\uFF1B\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\uFF0C\u6216\u5728\u6A21\u578B\u80FD\u529B\u8986\u76D6\u4E2D\u4FEE\u6539\uFF0C\u505C\u7528\u81EA\u52A8\u9002\u914D\u53EF\u6062\u590D\u539F\u751F\u7F16\u8F91\u3002"
|
|
1024
|
+
);
|
|
1025
|
+
const restored = { ...model };
|
|
1026
|
+
const projectedContext = original ? projectModel(provider, original, resolve4, ownershipProfile).contextWindow : void 0;
|
|
1027
|
+
const editedContext = ownsModels && (original ? model.contextWindow !== projectedContext : Object.hasOwn(model, "contextWindow"));
|
|
1028
|
+
const budgetChanged = editedContext || !original || model.maxTokens !== original.maxTokens || model.maxTokens === void 0 && effectiveProfile.defaultMaxTokens !== ownershipProfile.defaultMaxTokens || model.contextWindow === void 0 && effectiveProfile.defaultContextWindow !== ownershipProfile.defaultContextWindow;
|
|
1029
|
+
if (!editedContext) {
|
|
1030
|
+
if (original && Object.hasOwn(original, "contextWindow"))
|
|
1031
|
+
restored.contextWindow = original.contextWindow;
|
|
1032
|
+
else delete restored.contextWindow;
|
|
1033
|
+
} else {
|
|
1034
|
+
if (model.contextWindow !== void 0 && !validContextWindow(model.contextWindow))
|
|
1035
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
1036
|
+
contextEdits.push({
|
|
1037
|
+
provider,
|
|
1038
|
+
modelId: model.id,
|
|
1039
|
+
previousTokens: original?.contextWindow
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
if (budgetChanged)
|
|
1043
|
+
contextWrites?.validate?.(
|
|
1044
|
+
provider,
|
|
1045
|
+
editedContext ? model : { ...model, contextWindow: capability.contextWindow },
|
|
1046
|
+
profile
|
|
1047
|
+
);
|
|
1048
|
+
if (original && Object.hasOwn(original, "reasoningEfforts"))
|
|
1049
|
+
restored.reasoningEfforts = structuredClone(
|
|
1050
|
+
original.reasoningEfforts
|
|
1051
|
+
);
|
|
1052
|
+
else delete restored.reasoningEfforts;
|
|
1053
|
+
return restored;
|
|
1054
|
+
});
|
|
915
1055
|
return [
|
|
916
1056
|
provider,
|
|
917
|
-
{
|
|
918
|
-
...profile,
|
|
919
|
-
models: profile.models.map((model) => {
|
|
920
|
-
const original = previous.find((row) => row.id === model.id);
|
|
921
|
-
const ownershipProfile = current.providers?.[provider] ?? profile;
|
|
922
|
-
const capability = resolve4(provider, model, ownershipProfile);
|
|
923
|
-
if (!capability) return model;
|
|
924
|
-
const managed = projectModel(
|
|
925
|
-
provider,
|
|
926
|
-
model,
|
|
927
|
-
resolve4,
|
|
928
|
-
ownershipProfile
|
|
929
|
-
);
|
|
930
|
-
if (original && JSON.stringify(model.reasoningEfforts) !== JSON.stringify(managed.reasoningEfforts))
|
|
931
|
-
throw new Error(
|
|
932
|
-
"GPT \u601D\u8003\u7B49\u7EA7\u7531\u63D2\u4EF6\u9884\u8BBE\u7BA1\u7406\uFF1B\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\uFF0C\u6216\u5728\u6A21\u578B\u80FD\u529B\u8986\u76D6\u4E2D\u4FEE\u6539\uFF0C\u505C\u7528\u81EA\u52A8\u9002\u914D\u53EF\u6062\u590D\u539F\u751F\u7F16\u8F91\u3002"
|
|
933
|
-
);
|
|
934
|
-
const restored = { ...model };
|
|
935
|
-
if (original && Object.hasOwn(original, "reasoningEfforts"))
|
|
936
|
-
restored.reasoningEfforts = structuredClone(
|
|
937
|
-
original.reasoningEfforts
|
|
938
|
-
);
|
|
939
|
-
else delete restored.reasoningEfforts;
|
|
940
|
-
return restored;
|
|
941
|
-
})
|
|
942
|
-
}
|
|
1057
|
+
ownsModels ? { ...profile, models: savedModels } : profile
|
|
943
1058
|
];
|
|
944
1059
|
})
|
|
945
1060
|
)
|
|
946
1061
|
};
|
|
947
1062
|
}
|
|
948
|
-
function installSettingsOverlay(settings, resolve4) {
|
|
1063
|
+
function installSettingsOverlay(settings, resolve4, contextWrites) {
|
|
949
1064
|
settings = settings[symbols.original] ?? settings;
|
|
950
1065
|
const originalDescribe = settings.describe;
|
|
951
1066
|
const originalWrite = settings.write;
|
|
1067
|
+
const editableResolve = (provider, model, profile) => {
|
|
1068
|
+
const capability = resolve4(provider, model, profile);
|
|
1069
|
+
if (!capability) return void 0;
|
|
1070
|
+
const manual = contextWrites?.editableContext ? contextWrites.editableContext(provider, model) : model.contextWindow;
|
|
1071
|
+
const projected = { ...capability };
|
|
1072
|
+
if (manual === void 0) delete projected.contextWindow;
|
|
1073
|
+
else projected.contextWindow = manual;
|
|
1074
|
+
return projected;
|
|
1075
|
+
};
|
|
1076
|
+
let viewRevision;
|
|
952
1077
|
function describe(options) {
|
|
953
1078
|
return originalDescribe.call(this, options).map((row) => {
|
|
954
1079
|
if (row.ns !== "llm-pi-ai") return row;
|
|
@@ -960,40 +1085,140 @@ function installSettingsOverlay(settings, resolve4) {
|
|
|
960
1085
|
for (const model of profile.models ?? [])
|
|
961
1086
|
if (resolve4(provider, model, profile)) managed = true;
|
|
962
1087
|
else other = true;
|
|
963
|
-
|
|
1088
|
+
const value = managed ? projectConfiguration(row.value, resolve4) : row.value;
|
|
1089
|
+
const contexts = JSON.stringify(
|
|
1090
|
+
Object.entries(value?.providers ?? {}).map(([provider, profile]) => [
|
|
1091
|
+
provider,
|
|
1092
|
+
profile.models?.map((model) => [
|
|
1093
|
+
model.id,
|
|
1094
|
+
model.contextWindow
|
|
1095
|
+
])
|
|
1096
|
+
])
|
|
1097
|
+
);
|
|
1098
|
+
if (typeof row.revision === "number") {
|
|
1099
|
+
if (!viewRevision)
|
|
1100
|
+
viewRevision = {
|
|
1101
|
+
native: row.revision,
|
|
1102
|
+
contexts,
|
|
1103
|
+
revision: row.revision
|
|
1104
|
+
};
|
|
1105
|
+
else if (viewRevision.native !== row.revision || viewRevision.contexts !== contexts)
|
|
1106
|
+
viewRevision = {
|
|
1107
|
+
native: row.revision,
|
|
1108
|
+
contexts,
|
|
1109
|
+
revision: Math.max(row.revision, viewRevision.revision + 1)
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
964
1112
|
return {
|
|
965
1113
|
...row,
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1114
|
+
...managed ? {
|
|
1115
|
+
schema: projectSchema(row.schema, other),
|
|
1116
|
+
value,
|
|
1117
|
+
base: projectConfiguration(row.base, editableResolve),
|
|
1118
|
+
user: projectConfiguration(row.user, editableResolve)
|
|
1119
|
+
} : {},
|
|
1120
|
+
...typeof row.revision === "number" ? { revision: viewRevision.revision } : {}
|
|
970
1121
|
};
|
|
971
1122
|
});
|
|
972
1123
|
}
|
|
973
1124
|
async function write(ns, change, expected, paths) {
|
|
974
|
-
|
|
1125
|
+
const edits = [];
|
|
1126
|
+
const legacyRevision = contextWrites?.revision();
|
|
1127
|
+
await originalWrite.call(
|
|
975
1128
|
this,
|
|
976
1129
|
ns,
|
|
977
1130
|
ns !== "llm-pi-ai" ? change : (current, base, schema) => nativeWrite(
|
|
978
1131
|
change(
|
|
979
|
-
projectConfiguration(current,
|
|
980
|
-
projectConfiguration(base,
|
|
1132
|
+
projectConfiguration(structuredClone(current), editableResolve),
|
|
1133
|
+
projectConfiguration(structuredClone(base), editableResolve),
|
|
981
1134
|
schema
|
|
982
1135
|
),
|
|
983
1136
|
current,
|
|
984
|
-
|
|
1137
|
+
base,
|
|
1138
|
+
editableResolve,
|
|
1139
|
+
edits,
|
|
1140
|
+
contextWrites
|
|
985
1141
|
),
|
|
986
1142
|
expected,
|
|
987
1143
|
paths
|
|
988
1144
|
);
|
|
1145
|
+
await finishContextWrite.call(this, ns, edits, legacyRevision, paths);
|
|
1146
|
+
}
|
|
1147
|
+
async function finishContextWrite(ns, edits, legacyRevision, paths) {
|
|
1148
|
+
if (ns !== "llm-pi-ai" || !edits.length || !contextWrites) return;
|
|
1149
|
+
const committedRevision = describe.call(this).find((row) => row.ns === ns)?.revision;
|
|
1150
|
+
try {
|
|
1151
|
+
await contextWrites.saved(edits, legacyRevision);
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
try {
|
|
1154
|
+
await originalWrite.call(
|
|
1155
|
+
this,
|
|
1156
|
+
ns,
|
|
1157
|
+
(current) => {
|
|
1158
|
+
const restored = structuredClone(current);
|
|
1159
|
+
for (const edit of edits) {
|
|
1160
|
+
const row = restored.providers?.[edit.provider]?.models?.find(
|
|
1161
|
+
(model) => model.id === edit.modelId
|
|
1162
|
+
);
|
|
1163
|
+
if (!row) continue;
|
|
1164
|
+
if (edit.previousTokens === void 0) delete row.contextWindow;
|
|
1165
|
+
else row.contextWindow = edit.previousTokens;
|
|
1166
|
+
}
|
|
1167
|
+
return restored;
|
|
1168
|
+
},
|
|
1169
|
+
committedRevision,
|
|
1170
|
+
paths
|
|
1171
|
+
);
|
|
1172
|
+
} catch (rollbackError) {
|
|
1173
|
+
throw new AggregateError(
|
|
1174
|
+
[error, rollbackError],
|
|
1175
|
+
"\u4E0A\u4E0B\u6587\u4FDD\u5B58\u672A\u5B8C\u6210\uFF0C\u6062\u590D\u5931\u8D25\uFF1B\u8BF7\u5237\u65B0\u67E5\u770B\u5F53\u524D\u8BBE\u7F6E"
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
throw error;
|
|
1179
|
+
}
|
|
989
1180
|
}
|
|
990
1181
|
settings.describe = describe;
|
|
991
1182
|
if (originalWrite) settings.write = write;
|
|
992
|
-
|
|
1183
|
+
const dispose = () => {
|
|
993
1184
|
if (settings.describe === describe) settings.describe = originalDescribe;
|
|
994
1185
|
if (originalWrite && settings.write === write)
|
|
995
1186
|
settings.write = originalWrite;
|
|
996
1187
|
};
|
|
1188
|
+
const setContextWindow = async (provider, modelId, tokens, expected) => {
|
|
1189
|
+
if (!originalWrite) throw new Error("\u4E0A\u4E0B\u6587\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
1190
|
+
if (tokens !== void 0 && !validContextWindow(tokens))
|
|
1191
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
1192
|
+
const edits = [];
|
|
1193
|
+
const legacyRevision = contextWrites?.revision();
|
|
1194
|
+
const paths = [["providers", provider, "models"]];
|
|
1195
|
+
await originalWrite.call(
|
|
1196
|
+
settings,
|
|
1197
|
+
"llm-pi-ai",
|
|
1198
|
+
(current) => {
|
|
1199
|
+
const next = structuredClone(current);
|
|
1200
|
+
const model = next.providers?.[provider]?.models?.find(
|
|
1201
|
+
(row) => row.id === modelId
|
|
1202
|
+
);
|
|
1203
|
+
if (!model) throw new Error("\u6A21\u578B\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5");
|
|
1204
|
+
edits.push({ provider, modelId, previousTokens: model.contextWindow });
|
|
1205
|
+
if (tokens === void 0) delete model.contextWindow;
|
|
1206
|
+
else model.contextWindow = tokens;
|
|
1207
|
+
contextWrites?.validate?.(provider, model, next.providers[provider]);
|
|
1208
|
+
return next;
|
|
1209
|
+
},
|
|
1210
|
+
expected,
|
|
1211
|
+
paths
|
|
1212
|
+
);
|
|
1213
|
+
await finishContextWrite.call(
|
|
1214
|
+
settings,
|
|
1215
|
+
"llm-pi-ai",
|
|
1216
|
+
edits,
|
|
1217
|
+
legacyRevision,
|
|
1218
|
+
paths
|
|
1219
|
+
);
|
|
1220
|
+
};
|
|
1221
|
+
return Object.assign(dispose, { setContextWindow });
|
|
997
1222
|
}
|
|
998
1223
|
|
|
999
1224
|
// src/codex.ts
|
|
@@ -2299,14 +2524,15 @@ var Config2 = z2.object({
|
|
|
2299
2524
|
mcpAllowlist: z2.array(String).default([])
|
|
2300
2525
|
}).default({})
|
|
2301
2526
|
});
|
|
2302
|
-
var _speed_dec, _setSpeed_dec, _removeStale_dec, _refresh_dec, _updateOptions_dec, _configure_dec, _status_dec, _refreshCodex_dec, _codexStatus_dec, _a, _init;
|
|
2303
|
-
var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refreshCodex_dec = [Remote], _status_dec = [Remote], _configure_dec = [Remote], _updateOptions_dec = [Remote], _refresh_dec = [Remote], _removeStale_dec = [Remote], _setSpeed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _speed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _a) {
|
|
2527
|
+
var _speed_dec, _setSpeed_dec, _setContextWindow_dec, _removeStale_dec, _refresh_dec, _updateOptions_dec, _configure_dec, _status_dec, _refreshCodex_dec, _codexStatus_dec, _a, _init;
|
|
2528
|
+
var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refreshCodex_dec = [Remote], _status_dec = [Remote], _configure_dec = [Remote], _updateOptions_dec = [Remote], _refresh_dec = [Remote], _removeStale_dec = [Remote], _setContextWindow_dec = [Remote], _setSpeed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _speed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _a) {
|
|
2304
2529
|
constructor(ctx, options, settingsNs) {
|
|
2305
2530
|
super(ctx, "gptModels");
|
|
2306
2531
|
this.options = options;
|
|
2307
2532
|
this.settingsNs = settingsNs;
|
|
2308
2533
|
__runInitializers(_init, 5, this);
|
|
2309
2534
|
__publicField(this, "codex");
|
|
2535
|
+
__publicField(this, "contextWriter");
|
|
2310
2536
|
__publicField(this, "typertRemote");
|
|
2311
2537
|
__publicField(this, "runners", /* @__PURE__ */ new Map());
|
|
2312
2538
|
__publicField(this, "snapshots", /* @__PURE__ */ new Map());
|
|
@@ -2434,11 +2660,11 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2434
2660
|
}
|
|
2435
2661
|
async publish(provider, snapshot) {
|
|
2436
2662
|
if (this.closed) return;
|
|
2437
|
-
const {
|
|
2663
|
+
const { profile } = this.profile(provider);
|
|
2438
2664
|
const existing = profile.models ?? [];
|
|
2439
2665
|
const ids = new Set(existing.map((model) => model.id));
|
|
2440
2666
|
const added = snapshot.models.filter((model) => !model.stale && !ids.has(model.id)).map((model) => ({ id: model.id, name: model.displayName ?? model.id }));
|
|
2441
|
-
if (added.length) {
|
|
2667
|
+
if (added.length && !Object.keys(profile.modelOverrides ?? {}).length) {
|
|
2442
2668
|
await this.ctx.settings.mutate(
|
|
2443
2669
|
"llm-pi-ai",
|
|
2444
2670
|
[
|
|
@@ -2446,15 +2672,11 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2446
2672
|
op: "set",
|
|
2447
2673
|
path: ["providers", provider, "models"],
|
|
2448
2674
|
value: [...existing, ...added].map(
|
|
2449
|
-
(model) =>
|
|
2450
|
-
provider,
|
|
2451
|
-
model,
|
|
2452
|
-
(route, row) => this.capability(route, row.id, row.name)
|
|
2453
|
-
)
|
|
2675
|
+
(model) => this.editableModel(provider, model, ids.has(model.id))
|
|
2454
2676
|
)
|
|
2455
2677
|
}
|
|
2456
2678
|
],
|
|
2457
|
-
|
|
2679
|
+
this.modelsRevision()
|
|
2458
2680
|
);
|
|
2459
2681
|
}
|
|
2460
2682
|
if (this.closed) return;
|
|
@@ -2490,6 +2712,15 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2490
2712
|
stale: model.stale ?? false
|
|
2491
2713
|
})) ?? [],
|
|
2492
2714
|
capabilities,
|
|
2715
|
+
contextWindows: Object.fromEntries(
|
|
2716
|
+
this.routeOptions(provider)?.enabled ? (this.profile(provider).profile.models ?? []).filter(
|
|
2717
|
+
(model) => this.capability(provider, model.id) !== void 0
|
|
2718
|
+
).map((model) => [
|
|
2719
|
+
model.id,
|
|
2720
|
+
this.contextWindow(provider, model.id)
|
|
2721
|
+
]) : []
|
|
2722
|
+
),
|
|
2723
|
+
contextRevision: this.modelsRevision(),
|
|
2493
2724
|
options: this.routeOptions(provider) ?? {
|
|
2494
2725
|
enabled: false,
|
|
2495
2726
|
refreshIntervalMs: 18e5,
|
|
@@ -2530,6 +2761,10 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2530
2761
|
const overrides = JSON.parse(overridesJSON);
|
|
2531
2762
|
if (!overrides || typeof overrides !== "object" || Array.isArray(overrides))
|
|
2532
2763
|
throw new Error("\u6A21\u578B\u8986\u76D6\u9700\u8981\u662F JSON \u5BF9\u8C61");
|
|
2764
|
+
for (const entry of Object.values(overrides)) {
|
|
2765
|
+
if (entry && typeof entry === "object" && "contextWindow" in entry && !validContextWindow(entry.contextWindow))
|
|
2766
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
2767
|
+
}
|
|
2533
2768
|
const descriptor = this.ctx.settings.describe().find((entry) => entry.ns === this.settingsNs);
|
|
2534
2769
|
if (!descriptor) throw new Error("GPT plugin settings unavailable");
|
|
2535
2770
|
await this.ctx.settings.mutate(
|
|
@@ -2559,7 +2794,7 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2559
2794
|
const runner = this.runners.get(provider);
|
|
2560
2795
|
if (!runner) throw new Error("Enable GPT adaptation first");
|
|
2561
2796
|
const staleIds = runner.current()?.models.filter((model) => model.stale).map((model) => model.id) ?? [];
|
|
2562
|
-
const {
|
|
2797
|
+
const { profile } = this.profile(provider);
|
|
2563
2798
|
const nextModels = profile.models?.filter(
|
|
2564
2799
|
(model) => !staleIds.includes(model.id)
|
|
2565
2800
|
);
|
|
@@ -2571,18 +2806,128 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2571
2806
|
op: "set",
|
|
2572
2807
|
path: ["providers", provider, "models"],
|
|
2573
2808
|
value: nextModels.map(
|
|
2574
|
-
(model) =>
|
|
2575
|
-
provider,
|
|
2576
|
-
model,
|
|
2577
|
-
(route, row) => this.capability(route, row.id, row.name)
|
|
2578
|
-
)
|
|
2809
|
+
(model) => this.editableModel(provider, model)
|
|
2579
2810
|
)
|
|
2580
2811
|
}
|
|
2581
2812
|
],
|
|
2582
|
-
|
|
2813
|
+
this.modelsRevision()
|
|
2583
2814
|
);
|
|
2584
2815
|
await runner.removeStale(staleIds);
|
|
2585
2816
|
}
|
|
2817
|
+
/** Internal model-list writes must use the same manual fields as native drafts. */
|
|
2818
|
+
editableModel(provider, model, existing = true) {
|
|
2819
|
+
const capability = this.capability(provider, model.id, model.name);
|
|
2820
|
+
if (!capability) return model;
|
|
2821
|
+
const tokens = existing ? this.editableContextWindow(provider, model) : model.contextWindow;
|
|
2822
|
+
return projectModel(
|
|
2823
|
+
provider,
|
|
2824
|
+
tokens === void 0 ? model : { ...model, contextWindow: tokens },
|
|
2825
|
+
() => capability,
|
|
2826
|
+
void 0,
|
|
2827
|
+
false
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
editableContextWindow(provider, model) {
|
|
2831
|
+
const context = this.contextWindow(provider, model.id);
|
|
2832
|
+
return context.source === "legacy-override" ? context.effectiveTokens : model.contextWindow;
|
|
2833
|
+
}
|
|
2834
|
+
/** Resolve raw metadata separately from merged capabilities and cached overrides. */
|
|
2835
|
+
contextWindow(provider, modelId, nativeDefault, profileOverride) {
|
|
2836
|
+
const { descriptor, profile: storedProfile } = this.profile(provider);
|
|
2837
|
+
const inherited = descriptor.base?.providers?.[provider];
|
|
2838
|
+
const profile = profileOverride ? { ...inherited, ...profileOverride } : storedProfile;
|
|
2839
|
+
const overrides = JSON.parse(
|
|
2840
|
+
this.routeOptions(provider, profile)?.overridesJSON ?? "{}"
|
|
2841
|
+
);
|
|
2842
|
+
const row = profile.models?.length ? profile.models.find((model) => model.id === modelId) : profile.modelOverrides?.[modelId];
|
|
2843
|
+
const snapshot = this.snapshots.get(provider);
|
|
2844
|
+
const raw = snapshot?.models.find((model) => model.id === modelId);
|
|
2845
|
+
const userProfile = profileOverride ?? descriptor.user?.providers?.[provider];
|
|
2846
|
+
const providerDefault = userProfile?.defaultContextWindow ?? (profile.defaultContextWindow !== 1e6 || descriptor.base === void 0 && descriptor.user === void 0 ? profile.defaultContextWindow : void 0);
|
|
2847
|
+
const catalogModel = getBuiltinModels(provider).find(
|
|
2848
|
+
(model) => model.id === modelId
|
|
2849
|
+
);
|
|
2850
|
+
return resolveContextWindow({
|
|
2851
|
+
modelId,
|
|
2852
|
+
legacy: overrides[modelId]?.contextWindow,
|
|
2853
|
+
native: row?.contextWindow,
|
|
2854
|
+
providerDefault,
|
|
2855
|
+
upstream: raw?.capabilities?.contextWindow,
|
|
2856
|
+
catalog: snapshot?.catalog?.models[modelId]?.contextWindow,
|
|
2857
|
+
nativeDefault: nativeDefault ?? catalogModel?.contextWindow ?? profile.defaultContextWindow
|
|
2858
|
+
});
|
|
2859
|
+
}
|
|
2860
|
+
/** Both native form saves and the compatibility RPC validate the same budget. */
|
|
2861
|
+
validateContextWindow(provider, model, profile) {
|
|
2862
|
+
const effective = model.contextWindow ?? this.contextWindow(provider, model.id, void 0, profile).defaultTokens;
|
|
2863
|
+
const compaction = this.nativeDescribe().find(
|
|
2864
|
+
(entry) => entry.ns === "compaction-basic"
|
|
2865
|
+
)?.value;
|
|
2866
|
+
const policy = compaction?.modelPolicies?.find(
|
|
2867
|
+
(entry) => entry.provider === provider && entry.model === model.id
|
|
2868
|
+
);
|
|
2869
|
+
const headroom = policy?.headroomTokens ?? compaction?.headroomTokens ?? 0;
|
|
2870
|
+
const inherited = this.nativeDescribe().find((entry) => entry.ns === "llm-pi-ai")?.base?.providers?.[provider];
|
|
2871
|
+
const defaults = NativeConfig({
|
|
2872
|
+
providers: {
|
|
2873
|
+
[provider]: {
|
|
2874
|
+
defaultMaxTokens: profile.defaultMaxTokens ?? inherited?.defaultMaxTokens
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}).providers.get()[provider];
|
|
2878
|
+
const output = model.maxTokens ?? getBuiltinModels(provider).find((entry) => entry.id === model.id)?.maxTokens ?? defaults.defaultMaxTokens;
|
|
2879
|
+
if (effective <= output + headroom)
|
|
2880
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u5927\u4E8E\u5F53\u524D\u6700\u5927\u8F93\u51FA\u548C\u538B\u7F29\u9884\u7559\u7684\u603B\u548C");
|
|
2881
|
+
}
|
|
2882
|
+
contextWriteRevision() {
|
|
2883
|
+
return this.nativeDescribe().find((row) => row.ns === this.settingsNs)?.revision;
|
|
2884
|
+
}
|
|
2885
|
+
/** Public form revisions also cover changes to projected model capacities. */
|
|
2886
|
+
modelsRevision() {
|
|
2887
|
+
const descriptor = this.ctx.settings.describe().find((row) => row.ns === "llm-pi-ai");
|
|
2888
|
+
if (!descriptor) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
2889
|
+
return descriptor.revision;
|
|
2890
|
+
}
|
|
2891
|
+
/** Remove only legacy context fields after the matching native save commits. */
|
|
2892
|
+
async clearLegacyContext(edits, expected) {
|
|
2893
|
+
const operations = [];
|
|
2894
|
+
for (const provider of new Set(edits.map((edit) => edit.provider))) {
|
|
2895
|
+
const text = this.options.routes[provider]?.overridesJSON;
|
|
2896
|
+
if (!text) continue;
|
|
2897
|
+
const overrides = JSON.parse(text);
|
|
2898
|
+
let changed = false;
|
|
2899
|
+
for (const edit of edits.filter((entry) => entry.provider === provider)) {
|
|
2900
|
+
if (overrides[edit.modelId] && Object.hasOwn(overrides[edit.modelId], "contextWindow")) {
|
|
2901
|
+
delete overrides[edit.modelId].contextWindow;
|
|
2902
|
+
changed = true;
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
if (changed)
|
|
2906
|
+
operations.push({
|
|
2907
|
+
op: "set",
|
|
2908
|
+
path: ["routes", provider, "overridesJSON"],
|
|
2909
|
+
value: JSON.stringify(overrides)
|
|
2910
|
+
});
|
|
2911
|
+
}
|
|
2912
|
+
if (operations.length)
|
|
2913
|
+
await this.ctx.settings.mutate(this.settingsNs, operations, expected);
|
|
2914
|
+
}
|
|
2915
|
+
async setContextWindow(provider, modelId, mode, customTokens, expectedRevision) {
|
|
2916
|
+
const tokens = contextWindowTokens(mode, customTokens);
|
|
2917
|
+
const { profile } = this.profile(provider);
|
|
2918
|
+
if (!this.capability(provider, modelId))
|
|
2919
|
+
throw new Error("\u8BF7\u5148\u542F\u7528\u8BE5 GPT \u6A21\u578B\u7684\u81EA\u52A8\u9002\u914D");
|
|
2920
|
+
const index = profile.models?.findIndex((model) => model.id === modelId) ?? -1;
|
|
2921
|
+
if (index < 0) throw new Error("\u6A21\u578B\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5");
|
|
2922
|
+
if (!this.contextWriter) throw new Error("\u4E0A\u4E0B\u6587\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
2923
|
+
await this.contextWriter(
|
|
2924
|
+
provider,
|
|
2925
|
+
modelId,
|
|
2926
|
+
tokens,
|
|
2927
|
+
expectedRevision ?? this.modelsRevision()
|
|
2928
|
+
);
|
|
2929
|
+
this.ctx.emit("llm/models-updated", provider);
|
|
2930
|
+
}
|
|
2586
2931
|
async setSpeed(sessionId, provider, modelId, tier) {
|
|
2587
2932
|
const capability = this.capability(provider, modelId);
|
|
2588
2933
|
if (!capability?.serviceTiers.some((choice) => choice.id === tier))
|
|
@@ -2619,11 +2964,15 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2619
2964
|
...overrides[modelId]
|
|
2620
2965
|
};
|
|
2621
2966
|
const current = this.snapshots.get(provider)?.capabilities[modelId];
|
|
2622
|
-
|
|
2967
|
+
const result = current ? mergeCapabilities(current, override, current.capabilityRevision) : resolveCapabilities(
|
|
2623
2968
|
{ id: modelId, ...displayName ? { displayName } : {} },
|
|
2624
2969
|
"gpt-preset",
|
|
2625
2970
|
override
|
|
2626
2971
|
);
|
|
2972
|
+
return {
|
|
2973
|
+
...result,
|
|
2974
|
+
contextWindow: this.contextWindow(provider, modelId).effectiveTokens
|
|
2975
|
+
};
|
|
2627
2976
|
}
|
|
2628
2977
|
/** Capture request controls for the version-checked native runtime extension. */
|
|
2629
2978
|
capture(provider, modelId, base) {
|
|
@@ -2636,6 +2985,14 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2636
2985
|
const protocol = profile.api ?? "openai-responses";
|
|
2637
2986
|
const model = {
|
|
2638
2987
|
...base,
|
|
2988
|
+
context: {
|
|
2989
|
+
...base.context ?? {},
|
|
2990
|
+
contextWindow: this.contextWindow(
|
|
2991
|
+
provider,
|
|
2992
|
+
modelId,
|
|
2993
|
+
base.context?.contextWindow
|
|
2994
|
+
).effectiveTokens
|
|
2995
|
+
},
|
|
2639
2996
|
name: capabilities.displayName === modelId ? base.name : capabilities.displayName
|
|
2640
2997
|
};
|
|
2641
2998
|
if (!preserveReasoning) delete model.reasoning;
|
|
@@ -2686,6 +3043,7 @@ __decorateElement(_init, 1, "configure", _configure_dec, GptModels);
|
|
|
2686
3043
|
__decorateElement(_init, 1, "updateOptions", _updateOptions_dec, GptModels);
|
|
2687
3044
|
__decorateElement(_init, 1, "refresh", _refresh_dec, GptModels);
|
|
2688
3045
|
__decorateElement(_init, 1, "removeStale", _removeStale_dec, GptModels);
|
|
3046
|
+
__decorateElement(_init, 1, "setContextWindow", _setContextWindow_dec, GptModels);
|
|
2689
3047
|
__decorateElement(_init, 1, "setSpeed", _setSpeed_dec, GptModels);
|
|
2690
3048
|
__decorateElement(_init, 1, "speed", _speed_dec, GptModels);
|
|
2691
3049
|
__decoratorMetadata(_init, GptModels);
|
|
@@ -2725,9 +3083,17 @@ async function apply2(ctx, config) {
|
|
|
2725
3083
|
const providers = service.enabledProviders();
|
|
2726
3084
|
const dispose = installSettingsOverlay(
|
|
2727
3085
|
ctx.settings,
|
|
2728
|
-
(provider, model, profile) => typeof model.id === "string" ? service.capability(provider, model.id, model.name, profile) : void 0
|
|
3086
|
+
(provider, model, profile) => typeof model.id === "string" ? service.capability(provider, model.id, model.name, profile) : void 0,
|
|
3087
|
+
{
|
|
3088
|
+
editableContext: (provider, model) => service.editableContextWindow(provider, model),
|
|
3089
|
+
validate: (provider, model, profile) => service.validateContextWindow(provider, model, profile),
|
|
3090
|
+
revision: () => service.contextWriteRevision(),
|
|
3091
|
+
saved: (edits, revision) => service.clearLegacyContext(edits, revision)
|
|
3092
|
+
}
|
|
2729
3093
|
);
|
|
3094
|
+
service.contextWriter = dispose.setContextWindow;
|
|
2730
3095
|
return () => {
|
|
3096
|
+
service.contextWriter = void 0;
|
|
2731
3097
|
dispose();
|
|
2732
3098
|
for (const provider of providers) ctx.emit("llm/models-updated", provider);
|
|
2733
3099
|
};
|