dsh-opencode-go 0.1.7 → 0.1.9
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 +30 -52
- package/README.md +30 -72
- package/docs/assets/install-via-dsh.gif +0 -0
- package/docs/verification.md +32 -0
- package/lib/client.js +486 -358
- package/lib/index.js +108 -13
- package/lib/types/catalog.d.ts +5 -0
- package/lib/types/client/ModelEditor.d.ts +13 -0
- package/lib/types/client/locales.d.ts +16 -1
- package/lib/types/client/section-controller.d.ts +15 -3
- package/lib/types/config.d.ts +2 -0
- package/lib/types/index.d.ts +2 -2
- package/lib/types/model-metadata.d.ts +2 -0
- package/lib/types/models-contract.d.ts +23 -0
- package/lib/types/models.d.ts +12 -0
- package/lib/types/remote-contract.d.ts +3 -0
- package/lib/types/remotes.d.ts +3 -0
- package/package.json +24 -22
package/lib/index.js
CHANGED
|
@@ -705,6 +705,54 @@ import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completio
|
|
|
705
705
|
import { openAIResponsesApi } from "@earendil-works/pi-ai/api/openai-responses.lazy";
|
|
706
706
|
import { attributionHeaders, LlmError as LlmError5 } from "@deepseek-ai/dsh-llm";
|
|
707
707
|
|
|
708
|
+
// src/models-contract.ts
|
|
709
|
+
function validReleaseDate(value) {
|
|
710
|
+
return typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(value)) && new Date(value).toISOString().slice(0, 10) === value;
|
|
711
|
+
}
|
|
712
|
+
function isNewModel(model, now = Date.now()) {
|
|
713
|
+
if (model.deprecated || !validReleaseDate(model.releaseDate)) return false;
|
|
714
|
+
const days = Math.floor(now / 864e5) - Date.parse(model.releaseDate) / 864e5;
|
|
715
|
+
return days >= 0 && days < 7;
|
|
716
|
+
}
|
|
717
|
+
function sortModels(models, now = Date.now()) {
|
|
718
|
+
const rank = (model) => model.deprecated ? 2 : isNewModel(model, now) ? 0 : 1;
|
|
719
|
+
return [...models].sort((a, b) => rank(a) - rank(b) || (isNewModel(a, now) && isNewModel(b, now) ? b.releaseDate.localeCompare(a.releaseDate) : 0));
|
|
720
|
+
}
|
|
721
|
+
function parseGoModels(value) {
|
|
722
|
+
if (!Array.isArray(value)) throw new Error("Invalid OpenCode Go model list");
|
|
723
|
+
return value.map((entry) => {
|
|
724
|
+
if (!entry || typeof entry !== "object") throw new Error("Invalid OpenCode Go model");
|
|
725
|
+
const row = entry;
|
|
726
|
+
if (typeof row.id !== "string" || !row.id) throw new Error("Missing OpenCode Go model id");
|
|
727
|
+
const model = { id: row.id };
|
|
728
|
+
if (typeof row.name === "string") model.name = row.name;
|
|
729
|
+
for (const key of ["contextWindow", "maxTokens"]) {
|
|
730
|
+
if (typeof row[key] === "number" && Number.isSafeInteger(row[key]) && row[key] > 0) model[key] = row[key];
|
|
731
|
+
}
|
|
732
|
+
if (typeof row.deprecated === "boolean") model.deprecated = row.deprecated;
|
|
733
|
+
if (validReleaseDate(row.releaseDate)) model.releaseDate = row.releaseDate;
|
|
734
|
+
return model;
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
var codec = {
|
|
738
|
+
mode: "strict",
|
|
739
|
+
typeSymbol: "dsh-opencode-go#GoModels",
|
|
740
|
+
schema: { parse: parseGoModels },
|
|
741
|
+
create: () => ({ parse: parseGoModels })
|
|
742
|
+
};
|
|
743
|
+
var modelsRemote = {
|
|
744
|
+
package: "dsh-opencode-go",
|
|
745
|
+
descriptors: [{
|
|
746
|
+
id: "dsh-opencode-go#opencodeGoModels/read",
|
|
747
|
+
service: "opencodeGoModels",
|
|
748
|
+
namespace: "opencodeGoModels",
|
|
749
|
+
method: "read",
|
|
750
|
+
invocation: { kind: "direct" },
|
|
751
|
+
parameters: [],
|
|
752
|
+
result: codec
|
|
753
|
+
}]
|
|
754
|
+
};
|
|
755
|
+
|
|
708
756
|
// src/model-metadata.ts
|
|
709
757
|
var MODEL_METADATA_URL = "https://models.dev/api.json";
|
|
710
758
|
function record(value) {
|
|
@@ -755,7 +803,13 @@ function readModelMetadata(body, baseURL, builtin) {
|
|
|
755
803
|
const entries = record(provider.models);
|
|
756
804
|
const models = /* @__PURE__ */ new Map();
|
|
757
805
|
const errors = /* @__PURE__ */ new Map();
|
|
806
|
+
const details = /* @__PURE__ */ new Map();
|
|
758
807
|
for (const [id, value] of Object.entries(entries)) {
|
|
808
|
+
const data = record(value);
|
|
809
|
+
details.set(id, {
|
|
810
|
+
deprecated: data.status === "deprecated",
|
|
811
|
+
...validReleaseDate(data.release_date) ? { releaseDate: data.release_date } : {}
|
|
812
|
+
});
|
|
759
813
|
try {
|
|
760
814
|
const metadata = record(value);
|
|
761
815
|
const npm = record(metadata.provider).npm ?? provider.npm;
|
|
@@ -801,7 +855,7 @@ function readModelMetadata(body, baseURL, builtin) {
|
|
|
801
855
|
errors.set(id, error instanceof Error ? error.message : String(error));
|
|
802
856
|
}
|
|
803
857
|
}
|
|
804
|
-
return { models, errors };
|
|
858
|
+
return { models, errors, details };
|
|
805
859
|
}
|
|
806
860
|
|
|
807
861
|
// src/catalog.ts
|
|
@@ -916,9 +970,10 @@ var OpencodeGoCatalog = class {
|
|
|
916
970
|
this.onFallback({ url: MODEL_METADATA_URL, error: metadataResult.reason, kept: known.size });
|
|
917
971
|
}
|
|
918
972
|
if (listing.status === "rejected") {
|
|
919
|
-
const models2 = this.served?.models ??
|
|
973
|
+
const models2 = this.served?.models ?? /* @__PURE__ */ new Map();
|
|
920
974
|
this.onFallback({ url: `${this.baseURL.replace(/\/+$/, "")}/models`, error: listing.reason, kept: models2.size });
|
|
921
975
|
return {
|
|
976
|
+
details: this.served?.details ?? /* @__PURE__ */ new Map(),
|
|
922
977
|
models: models2,
|
|
923
978
|
unavailable: this.served?.unavailable ?? /* @__PURE__ */ new Map(),
|
|
924
979
|
provider: buildProvider(this.baseURL, [...models2.values()]),
|
|
@@ -939,6 +994,7 @@ var OpencodeGoCatalog = class {
|
|
|
939
994
|
}
|
|
940
995
|
if (unavailable.size > 0) this.onOmitted([...unavailable.keys()]);
|
|
941
996
|
return {
|
|
997
|
+
details: new Map(listing.value.map((id) => [id, metadata?.details.get(id) ?? {}])),
|
|
942
998
|
models,
|
|
943
999
|
unavailable,
|
|
944
1000
|
provider: buildProvider(this.baseURL, [...models.values()]),
|
|
@@ -965,6 +1021,9 @@ async function discoverCatalogModels(catalog) {
|
|
|
965
1021
|
if (!snapshot.live) {
|
|
966
1022
|
throw new LlmError5("llm-opencode-go: the live model listing is unreachable; try again later", "DISCOVERY_FAILED");
|
|
967
1023
|
}
|
|
1024
|
+
return describeCatalog(snapshot);
|
|
1025
|
+
}
|
|
1026
|
+
function describeCatalog(snapshot) {
|
|
968
1027
|
return [
|
|
969
1028
|
...[...snapshot.models.values()].map((model) => ({
|
|
970
1029
|
id: model.id,
|
|
@@ -975,6 +1034,11 @@ async function discoverCatalogModels(catalog) {
|
|
|
975
1034
|
...[...snapshot.unavailable].map(([id, reason]) => ({ id, name: `${id} (metadata unavailable: ${reason})` }))
|
|
976
1035
|
];
|
|
977
1036
|
}
|
|
1037
|
+
async function discoverSettingsModels(catalog) {
|
|
1038
|
+
const snapshot = await catalog.snapshot(true);
|
|
1039
|
+
if (!snapshot.live) throw new LlmError5("llm-opencode-go: the live model listing is unreachable; try again later", "DISCOVERY_FAILED");
|
|
1040
|
+
return sortModels(describeCatalog(snapshot).map((model) => ({ ...model, ...snapshot.details.get(model.id) })));
|
|
1041
|
+
}
|
|
978
1042
|
|
|
979
1043
|
// src/config.ts
|
|
980
1044
|
import { MAX_TIMER_DELAY_MS } from "@deepseek-ai/dsh-timeout";
|
|
@@ -984,6 +1048,7 @@ var DEFAULT_REFRESH_MINUTES = 60;
|
|
|
984
1048
|
var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
|
|
985
1049
|
var fields = {
|
|
986
1050
|
enabled: z.boolean().default(true),
|
|
1051
|
+
showDeprecatedModels: z.boolean().default(false),
|
|
987
1052
|
apiKeyEnv: z.string().role("credential-ref").default(DEFAULT_API_KEY_ENV),
|
|
988
1053
|
baseURL: z.string().default(DEFAULT_BASE_URL),
|
|
989
1054
|
refreshMinutes: z.number().step(1).min(1).max(7 * 24 * 60).default(DEFAULT_REFRESH_MINUTES),
|
|
@@ -1077,8 +1142,9 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1077
1142
|
return { id: provider, name: DISPLAY_NAME };
|
|
1078
1143
|
}
|
|
1079
1144
|
async listModels(_provider) {
|
|
1080
|
-
const
|
|
1081
|
-
|
|
1145
|
+
const config = this.options.config();
|
|
1146
|
+
const snapshot = await this.catalogOf(config).snapshot(true);
|
|
1147
|
+
return [...snapshot.models.values()].filter((model) => config.showDeprecatedModels || !snapshot.details.get(model.id)?.deprecated).map((model) => ({
|
|
1082
1148
|
provider: PROVIDER_ID,
|
|
1083
1149
|
id: model.id,
|
|
1084
1150
|
name: model.name,
|
|
@@ -1271,15 +1337,6 @@ var GoUsageService = class extends TypertRemoteService {
|
|
|
1271
1337
|
constructor(ctx, options) {
|
|
1272
1338
|
super(ctx, "opencodeGoUsage");
|
|
1273
1339
|
this.options = options;
|
|
1274
|
-
ctx.inject(["typert"], (scope) => {
|
|
1275
|
-
scope.effect(() => scope.typert.register({
|
|
1276
|
-
package: usageRemote.package,
|
|
1277
|
-
face: "host",
|
|
1278
|
-
schemas: [],
|
|
1279
|
-
model: { services: [], events: [], objects: [] },
|
|
1280
|
-
invocations: usageRemote.descriptors
|
|
1281
|
-
}));
|
|
1282
|
-
});
|
|
1283
1340
|
}
|
|
1284
1341
|
async read() {
|
|
1285
1342
|
const baseURL = assertBaseURL(this.options.baseURL()).replace(/\/$/, "");
|
|
@@ -1296,6 +1353,37 @@ var GoUsageService = class extends TypertRemoteService {
|
|
|
1296
1353
|
}
|
|
1297
1354
|
};
|
|
1298
1355
|
|
|
1356
|
+
// src/models.ts
|
|
1357
|
+
import { TypertRemoteService as TypertRemoteService2 } from "@deepseek-ai/dsh-typert-protocol";
|
|
1358
|
+
var GoModelsService = class extends TypertRemoteService2 {
|
|
1359
|
+
constructor(ctx, options) {
|
|
1360
|
+
super(ctx, "opencodeGoModels");
|
|
1361
|
+
this.options = options;
|
|
1362
|
+
}
|
|
1363
|
+
read() {
|
|
1364
|
+
return discoverSettingsModels(this.options.catalog());
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
// src/remote-contract.ts
|
|
1369
|
+
var goRemote = {
|
|
1370
|
+
package: "dsh-opencode-go",
|
|
1371
|
+
descriptors: [...usageRemote.descriptors, ...modelsRemote.descriptors]
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
// src/remotes.ts
|
|
1375
|
+
function registerGoRemotes(ctx) {
|
|
1376
|
+
ctx.inject(["typert"], (scope) => {
|
|
1377
|
+
scope.effect(() => scope.typert.register({
|
|
1378
|
+
package: goRemote.package,
|
|
1379
|
+
face: "host",
|
|
1380
|
+
schemas: [],
|
|
1381
|
+
model: { services: [], events: [], objects: [] },
|
|
1382
|
+
invocations: goRemote.descriptors
|
|
1383
|
+
}));
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1299
1387
|
// src/index.ts
|
|
1300
1388
|
var name = "llm-opencode-go";
|
|
1301
1389
|
var inject = ["llm"];
|
|
@@ -1315,6 +1403,7 @@ function apply(ctx, raw) {
|
|
|
1315
1403
|
"MISSING_CREDENTIAL"
|
|
1316
1404
|
);
|
|
1317
1405
|
};
|
|
1406
|
+
registerGoRemotes(ctx);
|
|
1318
1407
|
ctx.plugin(GoUsageService, { baseURL: () => current().baseURL, resolveApiKey });
|
|
1319
1408
|
const logger = {
|
|
1320
1409
|
fallback: ({ url, error }) => {
|
|
@@ -1341,6 +1430,8 @@ function apply(ctx, raw) {
|
|
|
1341
1430
|
ctx.logger.warn(`llm-opencode-go: unusable replay state on assistant history; sending provider-neutral content (${reason})`);
|
|
1342
1431
|
}
|
|
1343
1432
|
});
|
|
1433
|
+
ctx.plugin(GoModelsService, { catalog: () => adapter.catalogOf(current()) });
|
|
1434
|
+
let pickerVisibility = current().showDeprecatedModels;
|
|
1344
1435
|
let registration;
|
|
1345
1436
|
const applyRoute = (configured) => {
|
|
1346
1437
|
if (configured && current().enabled && registration === void 0) {
|
|
@@ -1358,6 +1449,10 @@ function apply(ctx, raw) {
|
|
|
1358
1449
|
}
|
|
1359
1450
|
};
|
|
1360
1451
|
const syncRoute = () => {
|
|
1452
|
+
if (pickerVisibility !== current().showDeprecatedModels) {
|
|
1453
|
+
pickerVisibility = current().showDeprecatedModels;
|
|
1454
|
+
registration?.replace([PROVIDER_ID]);
|
|
1455
|
+
}
|
|
1361
1456
|
const credentials = ctx.get("credentials");
|
|
1362
1457
|
if (credentials === void 0) {
|
|
1363
1458
|
applyRoute(launchEnvironmentOf(ctx).get(current().apiKeyEnv)?.value !== void 0);
|
package/lib/types/catalog.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Api, Model, Provider } from '@earendil-works/pi-ai';
|
|
2
2
|
import type { LlmDiscoveredModel } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import { type GoModel } from './models-contract.ts';
|
|
4
|
+
import type { ModelMetadata } from './model-metadata.ts';
|
|
3
5
|
export declare const PROVIDER_ID = "opencode-go";
|
|
4
6
|
export declare const DISPLAY_NAME = "OpenCode Go";
|
|
5
7
|
export declare const DEFAULT_BASE_URL = "https://opencode.ai/zen/go/v1";
|
|
6
8
|
export interface CatalogSnapshot {
|
|
9
|
+
readonly details: ModelMetadata['details'];
|
|
7
10
|
readonly models: ReadonlyMap<string, Model<Api>>;
|
|
8
11
|
/** Advertised ids with missing/unsupported metadata stay visible with a diagnostic. */
|
|
9
12
|
readonly unavailable: ReadonlyMap<string, string>;
|
|
@@ -41,3 +44,5 @@ export declare class OpencodeGoCatalog {
|
|
|
41
44
|
}
|
|
42
45
|
/** Explicit discovery always revalidates both sources, including during the runtime TTL. */
|
|
43
46
|
export declare function discoverCatalogModels(catalog: OpencodeGoCatalog): Promise<readonly LlmDiscoveredModel[]>;
|
|
47
|
+
/** Settings retain deprecated gateway entries regardless of picker visibility. */
|
|
48
|
+
export declare function discoverSettingsModels(catalog: OpencodeGoCatalog): Promise<readonly GoModel[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { OpencodeGoModelLimit, OpencodeGoModelLimits, OpencodeGoModels } from './section-controller.ts';
|
|
2
|
+
import type { en } from './locales.ts';
|
|
3
|
+
type Translate = (key: keyof typeof en, params?: Record<string, unknown>) => string;
|
|
4
|
+
export declare function hasCapacityOverride(limit: OpencodeGoModelLimit | null | undefined): boolean;
|
|
5
|
+
/** One gateway-backed list and its selected model's staged capacity settings. */
|
|
6
|
+
export declare function ModelEditor({ models, draft, t, disabled, onEdit }: {
|
|
7
|
+
models: OpencodeGoModels;
|
|
8
|
+
draft: OpencodeGoModelLimits;
|
|
9
|
+
t: Translate;
|
|
10
|
+
disabled: boolean;
|
|
11
|
+
onEdit: (next: OpencodeGoModelLimits) => void;
|
|
12
|
+
}): import("react").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -36,7 +36,22 @@ export declare const en: {
|
|
|
36
36
|
limitsModel: string;
|
|
37
37
|
limitsContext: string;
|
|
38
38
|
limitsOutput: string;
|
|
39
|
-
|
|
39
|
+
capacityDefault: string;
|
|
40
|
+
capacityMissing: string;
|
|
41
|
+
showDeprecatedLabel: string;
|
|
42
|
+
showDeprecatedHint: string;
|
|
43
|
+
pickerFailed: string;
|
|
44
|
+
deprecatedBadge: string;
|
|
45
|
+
deprecatedHint: string;
|
|
46
|
+
newHint: string;
|
|
47
|
+
releasedOn: string;
|
|
48
|
+
releaseSource: string;
|
|
49
|
+
modelDetails: string;
|
|
50
|
+
filterLabel: string;
|
|
51
|
+
filterAll: string;
|
|
52
|
+
filterNew: string;
|
|
53
|
+
filterCustom: string;
|
|
54
|
+
filterDeprecated: string;
|
|
40
55
|
limitsResetModel: string;
|
|
41
56
|
limitsResetAll: string;
|
|
42
57
|
limitsNoMatches: string;
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* covers everything the page shows.
|
|
10
10
|
*/
|
|
11
11
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
12
|
-
import type {
|
|
12
|
+
import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
|
|
13
|
+
import type { GoModel } from '../models-contract.ts';
|
|
13
14
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
14
15
|
import type { SettingsScope } from './settings.ts';
|
|
15
16
|
import { type FieldState, type FormActions, type FormShell } from './staged-form.ts';
|
|
@@ -19,6 +20,8 @@ export declare const OPENCODE_GO_NS = "llm-opencode-go";
|
|
|
19
20
|
export interface OpencodeGoSettings {
|
|
20
21
|
/** Whether the adapter serves its route; false withdraws it from every picker. */
|
|
21
22
|
enabled?: boolean;
|
|
23
|
+
/** Include gateway-served deprecated models in conversation pickers. */
|
|
24
|
+
showDeprecatedModels?: boolean;
|
|
22
25
|
/** Credential reference naming the environment key. */
|
|
23
26
|
apiKeyEnv?: string;
|
|
24
27
|
/** The gateway endpoint; also the live listing base. */
|
|
@@ -60,7 +63,7 @@ export type OpencodeGoModels =
|
|
|
60
63
|
readonly status: 'ready';
|
|
61
64
|
readonly count: number;
|
|
62
65
|
readonly preview: readonly string[];
|
|
63
|
-
readonly entries: readonly
|
|
66
|
+
readonly entries: readonly GoModel[];
|
|
64
67
|
}
|
|
65
68
|
/** The listing could not be read; `message` is the Host's own diagnostic. */
|
|
66
69
|
| {
|
|
@@ -75,6 +78,9 @@ export interface OpencodeGoSectionState extends FormShell {
|
|
|
75
78
|
* a withdrawn route is what the user is trying to observe.
|
|
76
79
|
*/
|
|
77
80
|
enabled: boolean;
|
|
81
|
+
showDeprecatedModels: boolean;
|
|
82
|
+
pickerSaving: boolean;
|
|
83
|
+
pickerFailed: boolean;
|
|
78
84
|
/** Credential reference naming the environment key. */
|
|
79
85
|
apiKeyEnv: FieldState;
|
|
80
86
|
/** The gateway endpoint. */
|
|
@@ -115,16 +121,20 @@ export interface OpencodeGoSectionFace extends FormActions {
|
|
|
115
121
|
* @param next - the state the switch asks for.
|
|
116
122
|
*/
|
|
117
123
|
setEnabled: (next: boolean) => void;
|
|
124
|
+
setShowDeprecatedModels: (next: boolean) => void;
|
|
118
125
|
}
|
|
119
126
|
/** Bridges the `llm-opencode-go` scope and the credentials domain onto the page. */
|
|
120
127
|
export declare class OpencodeGoSectionController {
|
|
121
128
|
private readonly scope;
|
|
122
129
|
private readonly ctx;
|
|
130
|
+
private readonly readModels;
|
|
123
131
|
private readonly form;
|
|
124
132
|
private readonly store;
|
|
125
133
|
private credential;
|
|
126
134
|
private models;
|
|
127
135
|
private modelsRequest;
|
|
136
|
+
private pickerSaving;
|
|
137
|
+
private pickerFailed;
|
|
128
138
|
private face;
|
|
129
139
|
private readonly unsubscribe;
|
|
130
140
|
/**
|
|
@@ -132,7 +142,7 @@ export declare class OpencodeGoSectionController {
|
|
|
132
142
|
* @param ctx - the page plugin's context, whose `remote.credentials` namespace
|
|
133
143
|
* answers for the credential the section references.
|
|
134
144
|
*/
|
|
135
|
-
constructor(scope: SettingsScope<OpencodeGoSettings>, ctx: ClientContext);
|
|
145
|
+
constructor(scope: SettingsScope<OpencodeGoSettings>, ctx: ClientContext, readModels?: () => Promise<RemoteResult<readonly GoModel[]>>);
|
|
136
146
|
/** Release subscriptions without disposing the host's shared form. */
|
|
137
147
|
dispose(): void;
|
|
138
148
|
private projection;
|
|
@@ -160,6 +170,8 @@ export declare class OpencodeGoSectionController {
|
|
|
160
170
|
* @param next - the state the switch asks for.
|
|
161
171
|
*/
|
|
162
172
|
setEnabled(next: boolean): void;
|
|
173
|
+
/** Visibility is immediate; failed writes leave the committed switch state visible. */
|
|
174
|
+
setShowDeprecatedModels(next: boolean): Promise<void>;
|
|
163
175
|
/**
|
|
164
176
|
* Read the gateway's model listing through the Host's discovery for this
|
|
165
177
|
* adapter. Called when the page mounts and again from its refresh control.
|
package/lib/types/config.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface OpencodeGoConfig {
|
|
|
38
38
|
* false registers nothing.
|
|
39
39
|
*/
|
|
40
40
|
enabled: boolean;
|
|
41
|
+
/** Include models marked deprecated by models.dev in conversation pickers. */
|
|
42
|
+
showDeprecatedModels: boolean;
|
|
41
43
|
/** Credential reference: the environment variable the key resolves from. */
|
|
42
44
|
apiKeyEnv: string;
|
|
43
45
|
/** The gateway endpoint; also the base of the live model listing. */
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dedicated OpenCode Go adapter plugin. Registers one `opencode-go` route
|
|
3
|
-
* whose catalog
|
|
4
|
-
*
|
|
3
|
+
* whose catalog follows the gateway's live model listing and models.dev
|
|
4
|
+
* metadata, and installs the `llm-opencode-go` settings section: the Web UI
|
|
5
5
|
* renders it as its own settings page where the API key and every knob are
|
|
6
6
|
* edited, and a change reaches the next request without a restart. The plugin
|
|
7
7
|
* exists because the gateway has wire requirements a generic pi-ai route
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/** Convert OpenCode's online models.dev metadata into the SDK's three wire protocols. */
|
|
2
2
|
import type { Api, Model } from '@earendil-works/pi-ai';
|
|
3
|
+
import { type GoModel } from './models-contract.ts';
|
|
3
4
|
export declare const MODEL_METADATA_URL = "https://models.dev/api.json";
|
|
4
5
|
export interface ModelMetadata {
|
|
5
6
|
readonly models: ReadonlyMap<string, Model<Api>>;
|
|
7
|
+
readonly details: ReadonlyMap<string, Pick<GoModel, 'deprecated' | 'releaseDate'>>;
|
|
6
8
|
readonly errors: ReadonlyMap<string, string>;
|
|
7
9
|
}
|
|
8
10
|
/** Anthropic's SDK appends /v1/messages; the OpenAI SDKs append paths below /v1. */
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Settings discovery includes lifecycle data that the host's generic model DTO omits. */
|
|
2
|
+
import type { RemoteResult, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol';
|
|
3
|
+
export interface GoModel {
|
|
4
|
+
id: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
contextWindow?: number;
|
|
7
|
+
maxTokens?: number;
|
|
8
|
+
deprecated?: boolean;
|
|
9
|
+
releaseDate?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function validReleaseDate(value: unknown): value is string;
|
|
12
|
+
/** Calendar dates are supplied without a timezone; compare UTC dates consistently. */
|
|
13
|
+
export declare function isNewModel(model: GoModel, now?: number): boolean;
|
|
14
|
+
export declare function sortModels(models: readonly GoModel[], now?: number): GoModel[];
|
|
15
|
+
export declare function parseGoModels(value: unknown): GoModel[];
|
|
16
|
+
declare module '@deepseek-ai/dsh-typert-protocol' {
|
|
17
|
+
interface TypertRemoteNamespaceMap {
|
|
18
|
+
opencodeGoModels: {
|
|
19
|
+
read(): Promise<RemoteResult<readonly GoModel[]>>;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export declare const modelsRemote: TypertRemoteContribution;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
3
|
+
import { type OpencodeGoCatalog } from './catalog.ts';
|
|
4
|
+
import type { GoModel } from './models-contract.ts';
|
|
5
|
+
/** Uses the same gateway snapshot as the adapter, including models hidden from pickers. */
|
|
6
|
+
export declare class GoModelsService extends TypertRemoteService {
|
|
7
|
+
private readonly options;
|
|
8
|
+
constructor(ctx: Context, options: {
|
|
9
|
+
catalog: () => OpencodeGoCatalog;
|
|
10
|
+
});
|
|
11
|
+
read(): Promise<readonly GoModel[]>;
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-opencode-go",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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 || 0.1.7-alpha.1"
|
|
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 || 0.1.7-alpha.2"
|
|
18
18
|
},
|
|
19
19
|
"main": "./lib/index.js",
|
|
20
20
|
"types": "./lib/types/index.d.ts",
|
|
@@ -60,26 +60,26 @@
|
|
|
60
60
|
"verify:headless": "node scripts/headless-smoke.mjs"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
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"
|
|
63
|
+
"@deepseek-ai/cordis": "4.0.2 || 4.0.3 || 4.0.4",
|
|
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 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-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 || 0.1.7-alpha.1 || 0.1.7-alpha.2"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"@deepseek-ai/dsh-brand": "0.1.6-alpha.1",
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"@types/node": "^22.20.0",
|
|
123
123
|
"@types/react": "~18.3.1",
|
|
124
124
|
"@types/react-dom": "~18.3.0",
|
|
125
|
+
"@types/semver": "7.8.0",
|
|
125
126
|
"anser": "^2.3.5",
|
|
126
127
|
"clsx": "^2.0.0",
|
|
127
128
|
"diff": "^9.0.0",
|
|
@@ -153,6 +154,7 @@
|
|
|
153
154
|
"micromark-util-types": "^2.0.2",
|
|
154
155
|
"react": "^18.2.0",
|
|
155
156
|
"react-dom": "^18.2.0",
|
|
157
|
+
"semver": "7.8.5",
|
|
156
158
|
"shiki": "^4.3.1",
|
|
157
159
|
"typescript": "6.0.3",
|
|
158
160
|
"vitest": "^4.1.8",
|