@goodandready/dsh-moa 0.2.21 → 0.2.22

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.
Files changed (3) hide show
  1. package/lib/index.js +79 -19
  2. package/lib/routes.js +25 -19
  3. package/package.json +6 -1
package/lib/index.js CHANGED
@@ -11,6 +11,18 @@ import { refreshCatalogInBackground } from './pricing.js'
11
11
  */
12
12
 
13
13
  import z from '@deepseek-ai/schemastery'
14
+
15
+ // Ensure .volatile() helper exists on Schemastery schema prototype
16
+ try {
17
+ const schemaProto = Object.getPrototypeOf(z.boolean())
18
+ if (schemaProto && typeof schemaProto.volatile !== 'function') {
19
+ schemaProto.volatile = function () {
20
+ return typeof this.extra === 'function' ? this.extra('volatile', true) : this
21
+ }
22
+ }
23
+ } catch {
24
+ // safe fallback
25
+ }
14
26
  import path from 'node:path'
15
27
  import os from 'node:os'
16
28
  import {
@@ -26,7 +38,7 @@ import { registerPluginUpdater, isSafeWriteRequest } from './updater.js'
26
38
 
27
39
  export const name = '@goodandready/dsh-moa'
28
40
  export { collectProjectContext, formatProjectContext } from './file-workspace.js'
29
- export const inject = ['webServer', 'llm', 'settings', 'sessions', 'tools']
41
+ export const inject = ['webServer', 'llm', 'sessions', 'tools']
30
42
 
31
43
  export const NS = 'dsh-moa'
32
44
 
@@ -65,9 +77,9 @@ export const PresetSchema = z.object({
65
77
  })
66
78
 
67
79
  export const Config = z.object({
68
- enabled: z.boolean().default(true),
69
- default_preset: z.string().default('default'),
70
- prices: z.dict(PriceRow).default({}),
80
+ enabled: z.boolean().default(true).volatile(),
81
+ default_preset: z.string().default('default').volatile(),
82
+ prices: z.dict(PriceRow).default({}).volatile(),
71
83
  presets: z.array(PresetSchema).default([
72
84
  {
73
85
  name: 'default',
@@ -110,31 +122,77 @@ export const Config = z.object({
110
122
  max_tokens: 8192,
111
123
  judge_criteria: '',
112
124
  },
113
- ]),
125
+ ]).volatile(),
114
126
  })
115
127
 
116
128
 
129
+ export function plainConfig(value) {
130
+ if (value && typeof value === 'object' && typeof value.get === 'function') {
131
+ return plainConfig(value.get())
132
+ }
133
+ if (Array.isArray(value)) {
134
+ return value.map(plainConfig)
135
+ }
136
+ if (value !== null && typeof value === 'object') {
137
+ return Object.fromEntries(
138
+ Object.entries(value).map(([key, child]) => [key, plainConfig(child)])
139
+ )
140
+ }
141
+ return value
142
+ }
143
+
117
144
  export function apply(ctx, config) {
118
145
  refreshCatalogInBackground()
119
146
 
120
- let settingsScope = null
121
- let getConfig = () => config
122
- const live = () => Config(structuredClone(getConfig() ?? {})) ?? config
147
+ let localConfig = plainConfig(config ?? {})
148
+ const getConfig = () => localConfig
149
+ const live = () => {
150
+ try {
151
+ const raw = getConfig() ?? {}
152
+ const validated = Config(plainConfig(raw))
153
+ return plainConfig(validated) ?? localConfig
154
+ } catch {
155
+ return localConfig
156
+ }
157
+ }
158
+
159
+ let settingsService = null
123
160
 
161
+ // Optional policy hook for DSH 0.1.7 settings forms:
162
+ // Suppress auto-generated settings form since dsh-moa provides its own
163
+ // custom settings surface in settings.plugin.item.
124
164
  ctx.inject(['settings'], (sctx) => {
125
- try {
126
- const scope = sctx.settings.register(NS, Config, { base: config })
127
- settingsScope = scope
128
- getConfig = () => scope.get() ?? config
129
- sctx.effect(() => () => {
130
- settingsScope = null
131
- getConfig = () => config
132
- }, 'dsh-moa: settings')
133
- } catch (e) {
134
- console.warn('[dsh-moa] Settings registration warning:', e)
165
+ settingsService = sctx.settings
166
+ if (sctx.settings && typeof sctx.settings.configure === 'function') {
167
+ try {
168
+ const dispose = sctx.settings.configure({ auto: false }, ctx.fiber)
169
+ if (typeof sctx.effect === 'function') {
170
+ sctx.effect(() => () => {
171
+ dispose()
172
+ settingsService = null
173
+ }, 'dsh-moa: settings policy')
174
+ }
175
+ } catch {
176
+ // Safe fallback if configure is already registered or throws
177
+ }
135
178
  }
136
179
  })
137
180
 
181
+ const saveConfig = async (newFields) => {
182
+ const plain = plainConfig(newFields)
183
+ localConfig = { ...localConfig, ...plain }
184
+ try {
185
+ if (settingsService && typeof settingsService.replace === 'function') {
186
+ await settingsService.replace(NS, plain)
187
+ } else if (settingsService && typeof settingsService.update === 'function') {
188
+ await settingsService.update(NS, plain)
189
+ }
190
+ } catch (err) {
191
+ console.warn('[dsh-moa] Settings persistence warning:', err?.message || err)
192
+ }
193
+ return localConfig
194
+ }
195
+
138
196
  /**
139
197
  * Unified LLM dispatch function using ctx.llm.prepareCall / stream
140
198
  */
@@ -226,7 +284,9 @@ export function apply(ctx, config) {
226
284
  live,
227
285
  callLlm,
228
286
  liveCanvas,
229
- getSettingsScope: () => settingsScope,
287
+ saveConfig,
288
+ Config,
289
+ plainConfig,
230
290
  })
231
291
 
232
292
  // Session turn interceptor: route turn to real aggregator model & stream MoA synthesis
package/lib/routes.js CHANGED
@@ -38,21 +38,24 @@ function readBody(req) {
38
38
  })
39
39
  }
40
40
 
41
- export function registerMoaRoutes(ctx, { live, callLlm, liveCanvas, getSettingsScope }) {
42
- const getScope = () => (typeof getSettingsScope === 'function' ? getSettingsScope() : null)
41
+ export function registerMoaRoutes(ctx, { live, callLlm, liveCanvas, saveConfig, Config, plainConfig }) {
43
42
 
44
43
  ctx.effect(() => {
45
44
  return ctx.webServer.register({
46
45
  kind: 'exact',
47
46
  path: '/dsh-moa/status',
48
47
  handler: (_req, res) => {
49
- const cfg = live()
50
- writeJson(res, 200, {
51
- ok: true,
52
- enabled: cfg.enabled !== false,
53
- defaultPreset: cfg.default_preset || 'default',
54
- presetsCount: (cfg.presets || []).length,
55
- })
48
+ try {
49
+ const cfg = live()
50
+ writeJson(res, 200, {
51
+ ok: true,
52
+ enabled: cfg.enabled !== false,
53
+ defaultPreset: cfg.default_preset || 'default',
54
+ presetsCount: (cfg.presets || []).length,
55
+ })
56
+ } catch (err) {
57
+ writeJson(res, 500, { ok: false, error: err?.message || String(err) })
58
+ }
56
59
  },
57
60
  })
58
61
  }, 'dsh-moa: status route')
@@ -120,7 +123,12 @@ ctx.effect(() => {
120
123
 
121
124
  // Query settings for configured providers
122
125
  try {
123
- const s = ctx.get ? ctx.get('settings') : ctx.settings
126
+ let s = null
127
+ try {
128
+ s = ctx.get ? ctx.get('settings') : null
129
+ } catch {
130
+ s = null
131
+ }
124
132
  const getSetting = (k) => {
125
133
  try { return s?.get?.(k) } catch { return undefined }
126
134
  }
@@ -196,19 +204,17 @@ ctx.effect(() => {
196
204
  return
197
205
  }
198
206
 
199
- // Persist via Cordis Settings API
200
- if (settingsScope && typeof settingsScope.replace === 'function') {
201
- await settingsScope.replace(validated)
202
- } else {
203
- // In-memory fallback if settings service is unavailable
204
- getConfig = () => validated
207
+ // Persist via saveConfig (in-memory and DSH profile settings)
208
+ if (typeof saveConfig === 'function') {
209
+ await saveConfig(validated)
205
210
  }
206
211
 
212
+ const unwrapped = typeof plainConfig === 'function' ? plainConfig(validated) : validated
207
213
  writeJson(res, 200, {
208
214
  ok: true,
209
- enabled: validated.enabled !== false,
210
- defaultPreset: validated.default_preset,
211
- presets: validated.presets,
215
+ enabled: unwrapped.enabled !== false,
216
+ defaultPreset: unwrapped.default_preset,
217
+ presets: unwrapped.presets,
212
218
  })
213
219
  } catch (err) {
214
220
  writeJson(res, 400, { ok: false, error: err?.message || String(err) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-moa",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Mixture of Agents (MoA) plugin for DeepSeek Harness with /moa slash command",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -59,5 +59,10 @@
59
59
  "@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
60
60
  "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
61
61
  "@deepseek-ai/schemastery": "^3.18.1"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "@deepseek-ai/dsh-settings": {
65
+ "optional": true
66
+ }
62
67
  }
63
68
  }