dsh-opencode-go 0.1.6 → 0.1.7
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.en.md +152 -0
- package/README.md +62 -41
- package/docs/verification.md +35 -0
- package/lib/client.js +348 -20
- package/lib/index.js +81 -15
- package/lib/types/adapter.d.ts +2 -3
- package/lib/types/client/locales.d.ts +15 -0
- package/lib/types/client/section-controller.d.ts +28 -2
- package/lib/types/client/settings.d.ts +18 -0
- package/lib/types/client/staged-form.d.ts +11 -1
- package/lib/types/config.d.ts +29 -5
- package/lib/types/index.d.ts +10 -6
- package/package.json +27 -23
package/lib/index.js
CHANGED
|
@@ -308,9 +308,13 @@ function flattenText(message) {
|
|
|
308
308
|
function toolResultText(blocks) {
|
|
309
309
|
return blocks.map((block) => block.type === "text" ? block.text : block.type === "tool-result" ? toolResultText(block.content) : "").join("");
|
|
310
310
|
}
|
|
311
|
+
function toolMessage(message) {
|
|
312
|
+
if (message.role !== "tool") return void 0;
|
|
313
|
+
return message;
|
|
314
|
+
}
|
|
311
315
|
function assertSupportedImageRoles(messages) {
|
|
312
316
|
for (const message of messages) {
|
|
313
|
-
if (message.role !== "user" && contentHasImage(message.content)) {
|
|
317
|
+
if (message.role !== "user" && !toolMessage(message) && contentHasImage(message.content)) {
|
|
314
318
|
throw new LlmError3(
|
|
315
319
|
`pi-ai cannot represent an image in an in-history ${message.role} message`,
|
|
316
320
|
"UNSUPPORTED_CONTENT"
|
|
@@ -417,6 +421,18 @@ function textOnlyContext(options, onReplayDegrade) {
|
|
|
417
421
|
if (contentHasImage(message.content)) {
|
|
418
422
|
throw new LlmError3("pi-ai image conversion requires the durable attachment service", "UNSUPPORTED_CONTENT");
|
|
419
423
|
}
|
|
424
|
+
const tool = toolMessage(message);
|
|
425
|
+
if (tool) {
|
|
426
|
+
messages.push({
|
|
427
|
+
role: "toolResult",
|
|
428
|
+
toolCallId: tool.toolCallId,
|
|
429
|
+
toolName: toolNames.get(tool.toolCallId) ?? "unknown",
|
|
430
|
+
content: [{ type: "text", text: toolResultText(tool.content) || "(no output)" }],
|
|
431
|
+
isError: tool.isError ?? false,
|
|
432
|
+
timestamp: 0
|
|
433
|
+
});
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
420
436
|
if (message.role === "system") {
|
|
421
437
|
messages.push({ role: "user", content: flattenText(message), timestamp: 0 });
|
|
422
438
|
continue;
|
|
@@ -480,6 +496,19 @@ async function toPiContextWithImages(options, images, onReplayDegrade) {
|
|
|
480
496
|
const toolNames = /* @__PURE__ */ new Map();
|
|
481
497
|
const messages = [];
|
|
482
498
|
for (const message of exactMessages) {
|
|
499
|
+
const tool = toolMessage(message);
|
|
500
|
+
if (tool) {
|
|
501
|
+
const content2 = await userContent(tool.content, requestImages, resolveImageAccess);
|
|
502
|
+
messages.push({
|
|
503
|
+
role: "toolResult",
|
|
504
|
+
toolCallId: tool.toolCallId,
|
|
505
|
+
toolName: toolNames.get(tool.toolCallId) ?? "unknown",
|
|
506
|
+
content: typeof content2 === "string" ? [{ type: "text", text: content2 || "(no output)" }] : content2,
|
|
507
|
+
isError: tool.isError ?? false,
|
|
508
|
+
timestamp: 0
|
|
509
|
+
});
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
483
512
|
if (message.role === "system") {
|
|
484
513
|
messages.push({ role: "user", content: flattenText(message), timestamp: 0 });
|
|
485
514
|
continue;
|
|
@@ -953,7 +982,7 @@ import z from "@deepseek-ai/schemastery";
|
|
|
953
982
|
var DEFAULT_API_KEY_ENV = "OPENCODE_API_KEY";
|
|
954
983
|
var DEFAULT_REFRESH_MINUTES = 60;
|
|
955
984
|
var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
|
|
956
|
-
var
|
|
985
|
+
var fields = {
|
|
957
986
|
enabled: z.boolean().default(true),
|
|
958
987
|
apiKeyEnv: z.string().role("credential-ref").default(DEFAULT_API_KEY_ENV),
|
|
959
988
|
baseURL: z.string().default(DEFAULT_BASE_URL),
|
|
@@ -963,8 +992,20 @@ var Config = z.object({
|
|
|
963
992
|
// request image fits the budget, and fifteen of them fit the payload cap.
|
|
964
993
|
maxRequestImageBytes: z.number().step(1).min(1).default(DEFAULT_MAX_REQUEST_IMAGE_BYTES),
|
|
965
994
|
requestImagePixelBudget: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
|
|
966
|
-
requestImageMaxBytes: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_MAX_BYTES)
|
|
967
|
-
|
|
995
|
+
requestImageMaxBytes: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_MAX_BYTES),
|
|
996
|
+
// null explicitly selects catalog values, overriding even inherited profile limits.
|
|
997
|
+
modelLimits: z.dict(z.union([z.const(null), z.object({
|
|
998
|
+
contextWindow: z.union([z.const(null), z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER)]),
|
|
999
|
+
maxTokens: z.union([z.const(null), z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER)])
|
|
1000
|
+
})])).default({})
|
|
1001
|
+
};
|
|
1002
|
+
var PlainConfig = z.object(fields);
|
|
1003
|
+
var Config = z.object(Object.fromEntries(
|
|
1004
|
+
Object.entries(fields).map(([key, schema]) => [key, schema.volatile()])
|
|
1005
|
+
));
|
|
1006
|
+
function readConfig(config) {
|
|
1007
|
+
return Object.fromEntries(Object.entries(config).map(([key, value]) => [key, value.get()]));
|
|
1008
|
+
}
|
|
968
1009
|
function assertBaseURL(raw) {
|
|
969
1010
|
let url;
|
|
970
1011
|
try {
|
|
@@ -982,6 +1023,15 @@ function assertBaseURL(raw) {
|
|
|
982
1023
|
}
|
|
983
1024
|
|
|
984
1025
|
// src/adapter.ts
|
|
1026
|
+
function withModelLimit(model, limits) {
|
|
1027
|
+
const limit = limits[model.id];
|
|
1028
|
+
if (limit == null) return model;
|
|
1029
|
+
return {
|
|
1030
|
+
...model,
|
|
1031
|
+
contextWindow: limit.contextWindow ?? model.contextWindow,
|
|
1032
|
+
maxTokens: limit.maxTokens ?? model.maxTokens
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
985
1035
|
function opencodeSessionValue(sessionId) {
|
|
986
1036
|
return sessionId !== void 0 && sessionId.length > 0 ? sessionId : randomUUID();
|
|
987
1037
|
}
|
|
@@ -1001,9 +1051,8 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1001
1051
|
* The catalog resolver for one configuration, rebuilding on the facts it
|
|
1002
1052
|
* owns. Public for the plugin's discovery registration, which resolves the
|
|
1003
1053
|
* current configuration the same way the adapter does.
|
|
1004
|
-
* @param config - the
|
|
1005
|
-
*
|
|
1006
|
-
* @returns the resolver caching one snapshot per endpoint/refresh pair.
|
|
1054
|
+
* @param config - the endpoint and refresh interval for the raw catalog.
|
|
1055
|
+
* @returns the resolver caching catalog values, independent of deployment limits.
|
|
1007
1056
|
*/
|
|
1008
1057
|
catalogOf(config) {
|
|
1009
1058
|
const key = `${config.baseURL}|${String(config.refreshMinutes)}`;
|
|
@@ -1037,12 +1086,13 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1037
1086
|
}));
|
|
1038
1087
|
}
|
|
1039
1088
|
async resolveModel(_provider, model, _signal) {
|
|
1040
|
-
const
|
|
1089
|
+
const config = this.options.config();
|
|
1090
|
+
const snapshot = await this.catalogOf(config).forModel(model);
|
|
1041
1091
|
const resolved = snapshot.models.get(model);
|
|
1042
1092
|
if (resolved === void 0) {
|
|
1043
1093
|
throw new LlmError6(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
|
|
1044
1094
|
}
|
|
1045
|
-
return this.modelInfo(resolved);
|
|
1095
|
+
return this.modelInfo(withModelLimit(resolved, config.modelLimits));
|
|
1046
1096
|
}
|
|
1047
1097
|
/** Describe one model: capacities plus the reasoning levels it actually offers. */
|
|
1048
1098
|
modelInfo(model) {
|
|
@@ -1083,10 +1133,13 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1083
1133
|
}
|
|
1084
1134
|
const config = this.options.config();
|
|
1085
1135
|
const snapshot = await this.catalogOf(config).forModel(options.model);
|
|
1086
|
-
const
|
|
1087
|
-
if (
|
|
1136
|
+
const advertised = snapshot.models.get(options.model);
|
|
1137
|
+
if (advertised === void 0) {
|
|
1088
1138
|
throw new LlmError6(`opencode-go has no model "${options.model}"`, "UNKNOWN_MODEL");
|
|
1089
1139
|
}
|
|
1140
|
+
const model = withModelLimit(advertised, config.modelLimits);
|
|
1141
|
+
const outputLimit = config.modelLimits[model.id]?.maxTokens;
|
|
1142
|
+
const maxTokens = outputLimit == null ? options.maxTokens : Math.min(options.maxTokens ?? outputLimit, outputLimit);
|
|
1090
1143
|
const apiKey = await this.options.resolveApiKey();
|
|
1091
1144
|
if (apiKey === void 0 || apiKey.length === 0) {
|
|
1092
1145
|
throw new LlmError6("llm-opencode-go: no credential resolved for the route", "MISSING_CREDENTIAL");
|
|
@@ -1122,7 +1175,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1122
1175
|
apiKey,
|
|
1123
1176
|
...reasoning === void 0 || reasoning === "off" ? {} : { reasoning },
|
|
1124
1177
|
...options.temperature === void 0 ? {} : { temperature: options.temperature },
|
|
1125
|
-
...
|
|
1178
|
+
...maxTokens === void 0 ? {} : { maxTokens },
|
|
1126
1179
|
...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
|
|
1127
1180
|
signal: watchdog.signal,
|
|
1128
1181
|
// Harness-owned request identity: the gateway refuses requests without
|
|
@@ -1248,9 +1301,10 @@ var name = "llm-opencode-go";
|
|
|
1248
1301
|
var inject = ["llm"];
|
|
1249
1302
|
var NS = "llm-opencode-go";
|
|
1250
1303
|
function apply(ctx, raw) {
|
|
1251
|
-
const
|
|
1304
|
+
const config = raw && typeof raw.enabled === "object" ? raw : Config(raw);
|
|
1305
|
+
const entry = readConfig(config);
|
|
1252
1306
|
assertBaseURL(entry.baseURL);
|
|
1253
|
-
let current = () =>
|
|
1307
|
+
let current = () => readConfig(config);
|
|
1254
1308
|
const resolveApiKey = async () => {
|
|
1255
1309
|
const ref = current().apiKeyEnv;
|
|
1256
1310
|
const credentials = ctx.get("credentials");
|
|
@@ -1330,7 +1384,12 @@ function apply(ctx, raw) {
|
|
|
1330
1384
|
undiscover();
|
|
1331
1385
|
});
|
|
1332
1386
|
ctx.inject(["settings"], (settingsCtx) => {
|
|
1333
|
-
settingsCtx.settings
|
|
1387
|
+
if ("configure" in settingsCtx.settings) {
|
|
1388
|
+
const settings = settingsCtx.settings;
|
|
1389
|
+
settingsCtx.effect(() => settings.configure({ auto: false }, ctx.fiber));
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
settingsCtx.settings.installSection(ctx, NS, PlainConfig, entry, {
|
|
1334
1393
|
validate: (value) => {
|
|
1335
1394
|
assertBaseURL(value.baseURL);
|
|
1336
1395
|
},
|
|
@@ -1342,6 +1401,12 @@ function apply(ctx, raw) {
|
|
|
1342
1401
|
}
|
|
1343
1402
|
});
|
|
1344
1403
|
});
|
|
1404
|
+
ctx.on("internal/config", function(_raw, next) {
|
|
1405
|
+
const value = next();
|
|
1406
|
+
if (this === ctx.fiber) assertBaseURL(PlainConfig(value).baseURL);
|
|
1407
|
+
return value;
|
|
1408
|
+
});
|
|
1409
|
+
ctx.on("loader/volatile-update", syncRoute);
|
|
1345
1410
|
ctx.inject(["credentials"], (credentialsCtx) => {
|
|
1346
1411
|
credentialsCtx.on("credentials/reference-updated", (ref) => {
|
|
1347
1412
|
if (ref === current().apiKeyEnv) syncRoute();
|
|
@@ -1358,6 +1423,7 @@ export {
|
|
|
1358
1423
|
OpencodeGoAdapter,
|
|
1359
1424
|
OpencodeGoCatalog,
|
|
1360
1425
|
PROVIDER_ID,
|
|
1426
|
+
PlainConfig,
|
|
1361
1427
|
apply,
|
|
1362
1428
|
assertBaseURL,
|
|
1363
1429
|
discoverCatalogModels,
|
package/lib/types/adapter.d.ts
CHANGED
|
@@ -82,9 +82,8 @@ export declare class OpencodeGoAdapter extends LlmAdapter {
|
|
|
82
82
|
* The catalog resolver for one configuration, rebuilding on the facts it
|
|
83
83
|
* owns. Public for the plugin's discovery registration, which resolves the
|
|
84
84
|
* current configuration the same way the adapter does.
|
|
85
|
-
* @param config - the
|
|
86
|
-
*
|
|
87
|
-
* @returns the resolver caching one snapshot per endpoint/refresh pair.
|
|
85
|
+
* @param config - the endpoint and refresh interval for the raw catalog.
|
|
86
|
+
* @returns the resolver caching catalog values, independent of deployment limits.
|
|
88
87
|
*/
|
|
89
88
|
catalogOf(config: OpencodeGoConfig): OpencodeGoCatalog;
|
|
90
89
|
providerInfo(provider: string): {
|
|
@@ -28,6 +28,21 @@ export declare const en: {
|
|
|
28
28
|
modelsFailed: string;
|
|
29
29
|
modelsEmpty: string;
|
|
30
30
|
modelsCount: string;
|
|
31
|
+
limitsLabel: string;
|
|
32
|
+
limitsHint: string;
|
|
33
|
+
limitsFilterLabel: string;
|
|
34
|
+
limitsFilterPlaceholder: string;
|
|
35
|
+
limitsSummary: string;
|
|
36
|
+
limitsModel: string;
|
|
37
|
+
limitsContext: string;
|
|
38
|
+
limitsOutput: string;
|
|
39
|
+
limitsAdvertised: string;
|
|
40
|
+
limitsResetModel: string;
|
|
41
|
+
limitsResetAll: string;
|
|
42
|
+
limitsNoMatches: string;
|
|
43
|
+
limitsEmpty: string;
|
|
44
|
+
limitsContextLabel: string;
|
|
45
|
+
limitsOutputLabel: string;
|
|
31
46
|
advancedLabel: string;
|
|
32
47
|
advancedHint: string;
|
|
33
48
|
apiKeyEnvLabel: string;
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* covers everything the page shows.
|
|
10
10
|
*/
|
|
11
11
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
12
|
+
import type { LlmDiscoveredModel } from '@deepseek-ai/dsh-api-remotes/client';
|
|
12
13
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
13
|
-
import type { SettingsScope } from '
|
|
14
|
+
import type { SettingsScope } from './settings.ts';
|
|
14
15
|
import { type FieldState, type FormActions, type FormShell } from './staged-form.ts';
|
|
15
16
|
/** Namespace of the OpenCode Go adapter. Spelled here rather than imported: a client package must not depend on a Host package. */
|
|
16
17
|
export declare const OPENCODE_GO_NS = "llm-opencode-go";
|
|
@@ -32,7 +33,15 @@ export interface OpencodeGoSettings {
|
|
|
32
33
|
requestImagePixelBudget?: number;
|
|
33
34
|
/** Raw encoded-byte target for one request image. */
|
|
34
35
|
requestImageMaxBytes?: number;
|
|
36
|
+
/** Per-model capacity overrides, keyed by the gateway model id. */
|
|
37
|
+
modelLimits?: OpencodeGoModelLimits;
|
|
35
38
|
}
|
|
39
|
+
/** The two capacity values the settings table can override. */
|
|
40
|
+
export interface OpencodeGoModelLimit {
|
|
41
|
+
contextWindow?: number | null;
|
|
42
|
+
maxTokens?: number | null;
|
|
43
|
+
}
|
|
44
|
+
export type OpencodeGoModelLimits = Record<string, OpencodeGoModelLimit | null>;
|
|
36
45
|
/** The gateway's model listing as the page reports it. */
|
|
37
46
|
export type OpencodeGoModels =
|
|
38
47
|
/** Not asked for yet; the page asks once it mounts. */
|
|
@@ -43,11 +52,15 @@ export type OpencodeGoModels =
|
|
|
43
52
|
| {
|
|
44
53
|
readonly status: 'loading';
|
|
45
54
|
}
|
|
46
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* The gateway answered: a count/preview for the compact summary plus every
|
|
57
|
+
* discovered entry used by the capacity editor.
|
|
58
|
+
*/
|
|
47
59
|
| {
|
|
48
60
|
readonly status: 'ready';
|
|
49
61
|
readonly count: number;
|
|
50
62
|
readonly preview: readonly string[];
|
|
63
|
+
readonly entries: readonly LlmDiscoveredModel[];
|
|
51
64
|
}
|
|
52
65
|
/** The listing could not be read; `message` is the Host's own diagnostic. */
|
|
53
66
|
| {
|
|
@@ -84,6 +97,10 @@ export interface OpencodeGoSectionState extends FormShell {
|
|
|
84
97
|
apiKeyWritable: boolean;
|
|
85
98
|
/** The gateway's current model listing. */
|
|
86
99
|
models: OpencodeGoModels;
|
|
100
|
+
/** The staged JSON field backing the capacity table. */
|
|
101
|
+
modelLimits: FieldState;
|
|
102
|
+
/** The parsed overrides currently shown by the capacity table. */
|
|
103
|
+
modelLimitDraft: OpencodeGoModelLimits;
|
|
87
104
|
}
|
|
88
105
|
/** The registration-side face the page's slot entry injects. */
|
|
89
106
|
export interface OpencodeGoSectionFace extends FormActions {
|
|
@@ -109,13 +126,22 @@ export declare class OpencodeGoSectionController {
|
|
|
109
126
|
private models;
|
|
110
127
|
private modelsRequest;
|
|
111
128
|
private face;
|
|
129
|
+
private readonly unsubscribe;
|
|
112
130
|
/**
|
|
113
131
|
* @param scope - the bound settings scope for the `llm-opencode-go` namespace.
|
|
114
132
|
* @param ctx - the page plugin's context, whose `remote.credentials` namespace
|
|
115
133
|
* answers for the credential the section references.
|
|
116
134
|
*/
|
|
117
135
|
constructor(scope: SettingsScope<OpencodeGoSettings>, ctx: ClientContext);
|
|
136
|
+
/** Release subscriptions without disposing the host's shared form. */
|
|
137
|
+
dispose(): void;
|
|
118
138
|
private projection;
|
|
139
|
+
/**
|
|
140
|
+
* Read the overrides as the page currently shows them. A staged JSON draft
|
|
141
|
+
* wins while it is valid; malformed text falls back to the last accepted
|
|
142
|
+
* settings value so the table never renders phantom rows.
|
|
143
|
+
*/
|
|
144
|
+
private limitDraft;
|
|
119
145
|
/**
|
|
120
146
|
* The adapter's effective switch state: the resolved section's value, over
|
|
121
147
|
* the Host's own default when the section carries none.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
|
|
2
|
+
/** Common read/write contract of legacy SettingsScope and 0.1.7 ConfigForm. */
|
|
3
|
+
export interface SettingsScopeSnapshot<T> {
|
|
4
|
+
status: 'loading' | 'ready' | 'unavailable';
|
|
5
|
+
value: T | undefined;
|
|
6
|
+
base: unknown;
|
|
7
|
+
user: unknown;
|
|
8
|
+
revision: number | undefined;
|
|
9
|
+
writable: boolean;
|
|
10
|
+
mode: 'host' | 'memory';
|
|
11
|
+
}
|
|
12
|
+
export interface SettingsScope<T> {
|
|
13
|
+
getSnapshot(): SettingsScopeSnapshot<T>;
|
|
14
|
+
subscribe(listener: () => void): () => void;
|
|
15
|
+
mutate(ops: readonly SettingsPathOpView[], expectedRevision?: number): Promise<void | boolean>;
|
|
16
|
+
set(field: string, value: unknown): Promise<void | boolean>;
|
|
17
|
+
unset(field: string): Promise<void | boolean>;
|
|
18
|
+
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* forms evolve independently anyway.
|
|
18
18
|
*/
|
|
19
19
|
import { type SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
20
|
-
import type { SettingsScope } from '
|
|
20
|
+
import type { SettingsScope } from './settings.ts';
|
|
21
21
|
/** The write one field's staged text performs when the page is saved. */
|
|
22
22
|
export type FieldWrite = {
|
|
23
23
|
kind: 'set';
|
|
@@ -111,6 +111,13 @@ export declare function booleanField(field: string): FieldSpec;
|
|
|
111
111
|
* @returns the field's conversion spec.
|
|
112
112
|
*/
|
|
113
113
|
export declare function textField(field: string): FieldSpec;
|
|
114
|
+
/**
|
|
115
|
+
* A structured field edited as JSON text. Empty text clears the field and
|
|
116
|
+
* malformed JSON blocks the save instead of reaching the Host as a string.
|
|
117
|
+
* @param field - field name inside the namespace section.
|
|
118
|
+
* @returns the field's conversion spec.
|
|
119
|
+
*/
|
|
120
|
+
export declare function jsonField(field: string): FieldSpec;
|
|
114
121
|
/**
|
|
115
122
|
* Stages the page's edits over the `llm-opencode-go` namespace and writes them
|
|
116
123
|
* on save.
|
|
@@ -125,6 +132,7 @@ export declare class StagedForm {
|
|
|
125
132
|
private readonly secretSpecs;
|
|
126
133
|
private readonly staged;
|
|
127
134
|
private readonly listeners;
|
|
135
|
+
private readonly unsubscribe;
|
|
128
136
|
private saving;
|
|
129
137
|
private failed;
|
|
130
138
|
/**
|
|
@@ -133,6 +141,8 @@ export declare class StagedForm {
|
|
|
133
141
|
* @param secrets - the page's write-only controls, written outside the section.
|
|
134
142
|
*/
|
|
135
143
|
constructor(scope: SettingsScope<Record<string, unknown>>, specs: FieldSpec[], secrets?: SecretSpec[]);
|
|
144
|
+
/** Shared 0.1.7 forms outlive individual settings pages. */
|
|
145
|
+
dispose(): void;
|
|
136
146
|
/**
|
|
137
147
|
* Publish a projection of this form, rebuilt whenever the scope or a draft changes.
|
|
138
148
|
* @param project - build the page state from the form's current reads.
|
package/lib/types/config.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration schema for the OpenCode Go adapter plugin. The section is
|
|
3
|
-
* installed under the `llm-opencode-go` settings namespace
|
|
4
|
-
*
|
|
5
|
-
* field by field
|
|
3
|
+
* installed under the `llm-opencode-go` settings namespace on DSH 0.1.5/0.1.6.
|
|
4
|
+
* DSH 0.1.7 edits the `opencode-go` profile entry through live references.
|
|
5
|
+
* Both paths update field by field without a restart. Self-contained constraints
|
|
6
6
|
* (URL shape, numeric bounds) fail at load for the composition layer and
|
|
7
7
|
* refuse the write for the settings layer.
|
|
8
8
|
*
|
|
@@ -15,6 +15,19 @@ export declare const DEFAULT_API_KEY_ENV = "OPENCODE_API_KEY";
|
|
|
15
15
|
export declare const DEFAULT_REFRESH_MINUTES = 60;
|
|
16
16
|
/** Default maximum idle interval while a stream read is outstanding. */
|
|
17
17
|
export declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300000;
|
|
18
|
+
/**
|
|
19
|
+
* One model's configured capacities. Every field is optional so a deployment
|
|
20
|
+
* can override only the value it needs. Null explicitly selects the catalog
|
|
21
|
+
* value even when a lower profile/settings layer supplies an override.
|
|
22
|
+
*/
|
|
23
|
+
export interface OpencodeGoModelLimit {
|
|
24
|
+
/** Context window in tokens, overriding what the catalog advertised. */
|
|
25
|
+
contextWindow?: number | null;
|
|
26
|
+
/** Output cap per request, overriding what the catalog advertised. */
|
|
27
|
+
maxTokens?: number | null;
|
|
28
|
+
}
|
|
29
|
+
/** Per-model capacities; a null entry selects both original catalog values. */
|
|
30
|
+
export type OpencodeGoModelLimits = Record<string, OpencodeGoModelLimit | null>;
|
|
18
31
|
/** Runtime configuration for one plugin mount. */
|
|
19
32
|
export interface OpencodeGoConfig {
|
|
20
33
|
/**
|
|
@@ -39,9 +52,20 @@ export interface OpencodeGoConfig {
|
|
|
39
52
|
requestImagePixelBudget: number;
|
|
40
53
|
/** Raw encoded-byte target for one request image before base64 expansion. */
|
|
41
54
|
requestImageMaxBytes: number;
|
|
55
|
+
/** Per-model capacity overrides; an absent field inherits the catalog value. */
|
|
56
|
+
modelLimits: OpencodeGoModelLimits;
|
|
42
57
|
}
|
|
43
|
-
/**
|
|
44
|
-
export declare const
|
|
58
|
+
/** Plain values used by the adapter and by pre-0.1.7 settings documents. */
|
|
59
|
+
export declare const PlainConfig: z<OpencodeGoConfig>;
|
|
60
|
+
/** 0.1.7's Loader retains these references when profile fields change. */
|
|
61
|
+
export type LiveConfig = {
|
|
62
|
+
[K in keyof OpencodeGoConfig]: {
|
|
63
|
+
get(): OpencodeGoConfig[K];
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
export declare const Config: z<Partial<OpencodeGoConfig>, LiveConfig>;
|
|
67
|
+
/** Keep the Loader's references: reparsing them would detach live updates. */
|
|
68
|
+
export declare function readConfig(config: LiveConfig): OpencodeGoConfig;
|
|
45
69
|
/**
|
|
46
70
|
* Accept only an http(s) base without a query or fragment. Runs at load for
|
|
47
71
|
* the composition layer and as the settings section's write validator, so a
|
package/lib/types/index.d.ts
CHANGED
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* cannot express: a mandatory per-conversation `x-opencode-session` routing
|
|
9
9
|
* header and a model list that rotates faster than any shipped catalog.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* field by field.
|
|
11
|
+
* DSH 0.1.5/0.1.6 layer the settings document over the composition entry;
|
|
12
|
+
* 0.1.7 edits live configuration fields on the profile entry directly.
|
|
14
13
|
*
|
|
15
14
|
* ```yaml
|
|
16
15
|
* - id: llm-opencode-go
|
|
@@ -32,11 +31,16 @@
|
|
|
32
31
|
* @module dsh-opencode-go
|
|
33
32
|
*/
|
|
34
33
|
import type { Context } from '@deepseek-ai/cordis';
|
|
35
|
-
import type { OpencodeGoConfig } from './config.ts';
|
|
34
|
+
import type { LiveConfig, OpencodeGoConfig } from './config.ts';
|
|
35
|
+
declare module '@deepseek-ai/cordis' {
|
|
36
|
+
interface Events {
|
|
37
|
+
'loader/volatile-update'(paths: readonly (readonly string[])[]): void;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
36
40
|
export { OpencodeGoAdapter } from './adapter.ts';
|
|
37
41
|
export type { OpencodeGoAdapterOptions, OpencodeGoImageAccess } from './adapter.ts';
|
|
38
42
|
export { DEFAULT_BASE_URL, DISPLAY_NAME, PROVIDER_ID, OpencodeGoCatalog, discoverCatalogModels, readLiveModelIds, } from './catalog.ts';
|
|
39
|
-
export { Config, assertBaseURL } from './config.ts';
|
|
43
|
+
export { Config, PlainConfig, assertBaseURL } from './config.ts';
|
|
40
44
|
export type { OpencodeGoConfig } from './config.ts';
|
|
41
45
|
export declare const name = "llm-opencode-go";
|
|
42
46
|
export declare const inject: string[];
|
|
@@ -48,4 +52,4 @@ export declare const NS = "llm-opencode-go";
|
|
|
48
52
|
* replaced by the settings section's resolved value once the settings
|
|
49
53
|
* provider attaches; the adapter re-reads it at every operation.
|
|
50
54
|
*/
|
|
51
|
-
export declare function apply(ctx: Context, raw?: OpencodeGoConfig): void;
|
|
55
|
+
export declare function apply(ctx: Context, raw?: OpencodeGoConfig | LiveConfig): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-opencode-go",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "OpenCode Go model provider and settings UI for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": "^22.19.0 || >=24.0.0",
|
|
17
|
-
"dsh": ">=0.1.5-rc.1 <0.1.6-0 || 0.1.6-alpha.1 || 0.1.6-alpha.2"
|
|
17
|
+
"dsh": ">=0.1.5-rc.1 <0.1.6-0 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1"
|
|
18
18
|
},
|
|
19
19
|
"main": "./lib/index.js",
|
|
20
20
|
"types": "./lib/types/index.d.ts",
|
|
@@ -60,30 +60,30 @@
|
|
|
60
60
|
"verify:headless": "node scripts/headless-smoke.mjs"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@deepseek-ai/cordis": "4.0.2",
|
|
64
|
-
"@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
65
|
-
"@deepseek-ai/dsh-api-remotes": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
66
|
-
"@deepseek-ai/dsh-api-settings-controller": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
67
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
68
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
69
|
-
"@deepseek-ai/dsh-client-store": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
70
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
71
|
-
"@deepseek-ai/dsh-client-ui-model-selection": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
72
|
-
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
73
|
-
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
75
|
-
"@deepseek-ai/dsh-credentials": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
76
|
-
"@deepseek-ai/dsh-fs": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
77
|
-
"@deepseek-ai/dsh-launch-environment": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
78
|
-
"@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
79
|
-
"@deepseek-ai/dsh-settings": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
80
|
-
"@deepseek-ai/dsh-timeout": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
81
|
-
"@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
|
|
82
|
-
"@deepseek-ai/dsh-typert-registry": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2"
|
|
63
|
+
"@deepseek-ai/cordis": "4.0.2 || 4.0.3",
|
|
64
|
+
"@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
65
|
+
"@deepseek-ai/dsh-api-remotes": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
66
|
+
"@deepseek-ai/dsh-api-settings-controller": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
67
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-client-store": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-model-selection": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
75
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
76
|
+
"@deepseek-ai/dsh-fs": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
77
|
+
"@deepseek-ai/dsh-launch-environment": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
78
|
+
"@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
79
|
+
"@deepseek-ai/dsh-settings": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
80
|
+
"@deepseek-ai/dsh-timeout": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
81
|
+
"@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1",
|
|
82
|
+
"@deepseek-ai/dsh-typert-registry": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"@deepseek-ai/dsh-brand": "0.1.6-alpha.1",
|
|
86
|
-
"@deepseek-ai/schemastery": "3.18.
|
|
86
|
+
"@deepseek-ai/schemastery": "3.18.3",
|
|
87
87
|
"@earendil-works/pi-ai": "0.85.1"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
@@ -116,6 +116,7 @@
|
|
|
116
116
|
"@deepseek-ai/dsh-typert-protocol": "0.1.6-alpha.1",
|
|
117
117
|
"@deepseek-ai/dsh-typert-registry": "0.1.6-alpha.1",
|
|
118
118
|
"@shikijs/langs": "^4.3.1",
|
|
119
|
+
"@testing-library/dom": "^10.4.2",
|
|
119
120
|
"@testing-library/react": "^16.3.2",
|
|
120
121
|
"@types/mdast": "^4.0.4",
|
|
121
122
|
"@types/node": "^22.20.0",
|
|
@@ -204,5 +205,8 @@
|
|
|
204
205
|
"opencode-go",
|
|
205
206
|
"llm",
|
|
206
207
|
"cordis"
|
|
208
|
+
],
|
|
209
|
+
"workspaces": [
|
|
210
|
+
"tests/hosts/*"
|
|
207
211
|
]
|
|
208
212
|
}
|