dsh-opencode-go 0.1.5 → 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/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;
@@ -445,7 +461,11 @@ function textOnlyContext(options, onReplayDegrade) {
445
461
  return piContext(split.systemPrompt, options, messages);
446
462
  }
447
463
  function requestImageTarget(ref, budget) {
448
- return { ...requestImageDimensions(ref.width, ref.height, budget.maxPixels), maxBytes: budget.maxBytes };
464
+ return {
465
+ ...requestImageDimensions(ref.width, ref.height, budget.maxPixels),
466
+ maxPixels: budget.maxPixels,
467
+ maxBytes: budget.maxBytes
468
+ };
449
469
  }
450
470
  function toPiContext(options, images, onReplayDegrade) {
451
471
  return images === void 0 ? textOnlyContext(options, onReplayDegrade) : toPiContextWithImages(options, images, onReplayDegrade);
@@ -476,6 +496,19 @@ async function toPiContextWithImages(options, images, onReplayDegrade) {
476
496
  const toolNames = /* @__PURE__ */ new Map();
477
497
  const messages = [];
478
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
+ }
479
512
  if (message.role === "system") {
480
513
  messages.push({ role: "user", content: flattenText(message), timestamp: 0 });
481
514
  continue;
@@ -949,7 +982,7 @@ import z from "@deepseek-ai/schemastery";
949
982
  var DEFAULT_API_KEY_ENV = "OPENCODE_API_KEY";
950
983
  var DEFAULT_REFRESH_MINUTES = 60;
951
984
  var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
952
- var Config = z.object({
985
+ var fields = {
953
986
  enabled: z.boolean().default(true),
954
987
  apiKeyEnv: z.string().role("credential-ref").default(DEFAULT_API_KEY_ENV),
955
988
  baseURL: z.string().default(DEFAULT_BASE_URL),
@@ -959,8 +992,20 @@ var Config = z.object({
959
992
  // request image fits the budget, and fifteen of them fit the payload cap.
960
993
  maxRequestImageBytes: z.number().step(1).min(1).default(DEFAULT_MAX_REQUEST_IMAGE_BYTES),
961
994
  requestImagePixelBudget: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
962
- requestImageMaxBytes: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_MAX_BYTES)
963
- });
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
+ }
964
1009
  function assertBaseURL(raw) {
965
1010
  let url;
966
1011
  try {
@@ -978,6 +1023,15 @@ function assertBaseURL(raw) {
978
1023
  }
979
1024
 
980
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
+ }
981
1035
  function opencodeSessionValue(sessionId) {
982
1036
  return sessionId !== void 0 && sessionId.length > 0 ? sessionId : randomUUID();
983
1037
  }
@@ -997,9 +1051,8 @@ var OpencodeGoAdapter = class extends LlmAdapter {
997
1051
  * The catalog resolver for one configuration, rebuilding on the facts it
998
1052
  * owns. Public for the plugin's discovery registration, which resolves the
999
1053
  * current configuration the same way the adapter does.
1000
- * @param config - the configuration whose endpoint and refresh interval the
1001
- * resolver serves; a change to either yields a fresh resolver.
1002
- * @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.
1003
1056
  */
1004
1057
  catalogOf(config) {
1005
1058
  const key = `${config.baseURL}|${String(config.refreshMinutes)}`;
@@ -1033,12 +1086,13 @@ var OpencodeGoAdapter = class extends LlmAdapter {
1033
1086
  }));
1034
1087
  }
1035
1088
  async resolveModel(_provider, model, _signal) {
1036
- const snapshot = await this.catalogOf(this.options.config()).forModel(model);
1089
+ const config = this.options.config();
1090
+ const snapshot = await this.catalogOf(config).forModel(model);
1037
1091
  const resolved = snapshot.models.get(model);
1038
1092
  if (resolved === void 0) {
1039
1093
  throw new LlmError6(`opencode-go has no model "${model}"`, "UNKNOWN_MODEL");
1040
1094
  }
1041
- return this.modelInfo(resolved);
1095
+ return this.modelInfo(withModelLimit(resolved, config.modelLimits));
1042
1096
  }
1043
1097
  /** Describe one model: capacities plus the reasoning levels it actually offers. */
1044
1098
  modelInfo(model) {
@@ -1079,10 +1133,13 @@ var OpencodeGoAdapter = class extends LlmAdapter {
1079
1133
  }
1080
1134
  const config = this.options.config();
1081
1135
  const snapshot = await this.catalogOf(config).forModel(options.model);
1082
- const model = snapshot.models.get(options.model);
1083
- if (model === void 0) {
1136
+ const advertised = snapshot.models.get(options.model);
1137
+ if (advertised === void 0) {
1084
1138
  throw new LlmError6(`opencode-go has no model "${options.model}"`, "UNKNOWN_MODEL");
1085
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);
1086
1143
  const apiKey = await this.options.resolveApiKey();
1087
1144
  if (apiKey === void 0 || apiKey.length === 0) {
1088
1145
  throw new LlmError6("llm-opencode-go: no credential resolved for the route", "MISSING_CREDENTIAL");
@@ -1118,7 +1175,7 @@ var OpencodeGoAdapter = class extends LlmAdapter {
1118
1175
  apiKey,
1119
1176
  ...reasoning === void 0 || reasoning === "off" ? {} : { reasoning },
1120
1177
  ...options.temperature === void 0 ? {} : { temperature: options.temperature },
1121
- ...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
1178
+ ...maxTokens === void 0 ? {} : { maxTokens },
1122
1179
  ...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
1123
1180
  signal: watchdog.signal,
1124
1181
  // Harness-owned request identity: the gateway refuses requests without
@@ -1244,9 +1301,10 @@ var name = "llm-opencode-go";
1244
1301
  var inject = ["llm"];
1245
1302
  var NS = "llm-opencode-go";
1246
1303
  function apply(ctx, raw) {
1247
- const entry = Config(raw);
1304
+ const config = raw && typeof raw.enabled === "object" ? raw : Config(raw);
1305
+ const entry = readConfig(config);
1248
1306
  assertBaseURL(entry.baseURL);
1249
- let current = () => entry;
1307
+ let current = () => readConfig(config);
1250
1308
  const resolveApiKey = async () => {
1251
1309
  const ref = current().apiKeyEnv;
1252
1310
  const credentials = ctx.get("credentials");
@@ -1326,7 +1384,12 @@ function apply(ctx, raw) {
1326
1384
  undiscover();
1327
1385
  });
1328
1386
  ctx.inject(["settings"], (settingsCtx) => {
1329
- settingsCtx.settings.installSection(ctx, NS, Config, entry, {
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, {
1330
1393
  validate: (value) => {
1331
1394
  assertBaseURL(value.baseURL);
1332
1395
  },
@@ -1338,6 +1401,12 @@ function apply(ctx, raw) {
1338
1401
  }
1339
1402
  });
1340
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);
1341
1410
  ctx.inject(["credentials"], (credentialsCtx) => {
1342
1411
  credentialsCtx.on("credentials/reference-updated", (ref) => {
1343
1412
  if (ref === current().apiKeyEnv) syncRoute();
@@ -1354,6 +1423,7 @@ export {
1354
1423
  OpencodeGoAdapter,
1355
1424
  OpencodeGoCatalog,
1356
1425
  PROVIDER_ID,
1426
+ PlainConfig,
1357
1427
  apply,
1358
1428
  assertBaseURL,
1359
1429
  discoverCatalogModels,
@@ -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 configuration whose endpoint and refresh interval the
86
- * resolver serves; a change to either yields a fresh resolver.
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 '@deepseek-ai/dsh-client-ui-settings/client';
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
- /** The gateway answered: how many models it serves, and a preview of their names. */
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 '@deepseek-ai/dsh-client-ui-settings/client';
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.
@@ -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: a cordis.yml
4
- * entry supplies the composition base and the settings document overrides it
5
- * field by field, hot-reloaded without a restart. Self-contained constraints
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
- /** Runtime schema for {@link OpencodeGoConfig}. */
44
- export declare const Config: z<OpencodeGoConfig>;
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
@@ -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
- * Configuration layers like every settings-backed plugin: a `cordis.yml`
12
- * entry supplies the composition base and the settings document overrides it
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.5",
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"
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",
65
- "@deepseek-ai/dsh-api-remotes": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
66
- "@deepseek-ai/dsh-api-settings-controller": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
67
- "@deepseek-ai/dsh-attachment": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
68
- "@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
69
- "@deepseek-ai/dsh-client-store": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
70
- "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
71
- "@deepseek-ai/dsh-client-ui-model-selection": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
72
- "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
73
- "@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
74
- "@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
75
- "@deepseek-ai/dsh-credentials": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
76
- "@deepseek-ai/dsh-fs": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
77
- "@deepseek-ai/dsh-launch-environment": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
78
- "@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
79
- "@deepseek-ai/dsh-settings": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
80
- "@deepseek-ai/dsh-timeout": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
81
- "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1",
82
- "@deepseek-ai/dsh-typert-registry": ">=0.1.5-rc.1 <0.1.6 || 0.1.6-alpha.1"
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.2",
86
+ "@deepseek-ai/schemastery": "3.18.3",
87
87
  "@earendil-works/pi-ai": "0.85.1"
88
88
  },
89
89
  "devDependencies": {
@@ -94,6 +94,7 @@
94
94
  "@deepseek-ai/dsh-api-remotes": "0.1.6-alpha.1",
95
95
  "@deepseek-ai/dsh-api-settings-controller": "0.1.6-alpha.1",
96
96
  "@deepseek-ai/dsh-attachment": "0.1.6-alpha.1",
97
+ "@deepseek-ai/dsh-attachment-local": "0.1.6-alpha.1",
97
98
  "@deepseek-ai/dsh-brand": "0.1.6-alpha.1",
98
99
  "@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
99
100
  "@deepseek-ai/dsh-client-store": "0.1.6-alpha.1",
@@ -106,6 +107,7 @@
106
107
  "@deepseek-ai/dsh-credentials": "0.1.6-alpha.1",
107
108
  "@deepseek-ai/dsh-credentials-local": "0.1.6-alpha.1",
108
109
  "@deepseek-ai/dsh-fs": "0.1.6-alpha.1",
110
+ "@deepseek-ai/dsh-home-paths": "0.1.6-alpha.1",
109
111
  "@deepseek-ai/dsh-launch-environment": "0.1.6-alpha.1",
110
112
  "@deepseek-ai/dsh-llm": "0.1.6-alpha.1",
111
113
  "@deepseek-ai/dsh-settings": "0.1.6-alpha.1",
@@ -114,6 +116,7 @@
114
116
  "@deepseek-ai/dsh-typert-protocol": "0.1.6-alpha.1",
115
117
  "@deepseek-ai/dsh-typert-registry": "0.1.6-alpha.1",
116
118
  "@shikijs/langs": "^4.3.1",
119
+ "@testing-library/dom": "^10.4.2",
117
120
  "@testing-library/react": "^16.3.2",
118
121
  "@types/mdast": "^4.0.4",
119
122
  "@types/node": "^22.20.0",
@@ -122,8 +125,15 @@
122
125
  "anser": "^2.3.5",
123
126
  "clsx": "^2.0.0",
124
127
  "diff": "^9.0.0",
128
+ "dsh-attachment-local-v015-rc1": "npm:@deepseek-ai/dsh-attachment-local@0.1.5-rc.1",
129
+ "dsh-attachment-local-v015-rc2": "npm:@deepseek-ai/dsh-attachment-local@0.1.5-rc.2",
130
+ "dsh-attachment-local-v016-alpha2": "npm:@deepseek-ai/dsh-attachment-local@0.1.6-alpha.2",
131
+ "dsh-attachment-v015-rc1": "npm:@deepseek-ai/dsh-attachment@0.1.5-rc.1",
132
+ "dsh-attachment-v015-rc2": "npm:@deepseek-ai/dsh-attachment@0.1.5-rc.2",
133
+ "dsh-attachment-v016-alpha2": "npm:@deepseek-ai/dsh-attachment@0.1.6-alpha.2",
125
134
  "dsh-llm-v015-rc1": "npm:@deepseek-ai/dsh-llm@0.1.5-rc.1",
126
135
  "dsh-llm-v015-rc2": "npm:@deepseek-ai/dsh-llm@0.1.5-rc.2",
136
+ "dsh-llm-v016-alpha2": "npm:@deepseek-ai/dsh-llm@0.1.6-alpha.2",
127
137
  "esbuild": "^0.25.0",
128
138
  "immer": "^10.1.1",
129
139
  "jsdom": "29.1.1",
@@ -195,5 +205,8 @@
195
205
  "opencode-go",
196
206
  "llm",
197
207
  "cordis"
208
+ ],
209
+ "workspaces": [
210
+ "tests/hosts/*"
198
211
  ]
199
212
  }