@wrongstack/webui-server 0.298.1 → 0.298.3
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/dist/index.js +91 -4
- package/dist/protocol/client-workspace.d.ts +1 -1
- package/dist/protocol/index.js +2 -0
- package/dist/protocol/registry.d.ts +1 -1
- package/dist/server/embedded-host-adapters.d.ts +2 -0
- package/dist/server/entry.js +91 -4
- package/dist/server/provider-handlers.d.ts +4 -0
- package/dist/server/provider-routes.d.ts +2 -0
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -15665,7 +15665,8 @@ function createProviderOperations(deps2) {
|
|
|
15665
15665
|
providerId,
|
|
15666
15666
|
config
|
|
15667
15667
|
);
|
|
15668
|
-
const
|
|
15668
|
+
const siblingCatalogKey = config?.family ?? providerId;
|
|
15669
|
+
const siblingId = SIBLING_CATALOG[siblingCatalogKey];
|
|
15669
15670
|
const sibling = siblingId && siblingId !== providerId ? await deps2.modelsRegistry.getProvider(siblingId).catch(() => void 0) : void 0;
|
|
15670
15671
|
let models = resolveProviderModelList(
|
|
15671
15672
|
config?.models,
|
|
@@ -15820,6 +15821,50 @@ function createProviderOperations(deps2) {
|
|
|
15820
15821
|
sendOperationResult(ws, false, errMessage(err));
|
|
15821
15822
|
}
|
|
15822
15823
|
}
|
|
15824
|
+
async function handleCustomModelSet(ws, providerId, modelId, definition) {
|
|
15825
|
+
try {
|
|
15826
|
+
const providers = await loadConfigProviders();
|
|
15827
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
15828
|
+
if (!cfg) {
|
|
15829
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
15830
|
+
return;
|
|
15831
|
+
}
|
|
15832
|
+
if (!cfg.customModels) cfg.customModels = {};
|
|
15833
|
+
cfg.customModels[modelId] = definition;
|
|
15834
|
+
if (!cfg.models) cfg.models = [];
|
|
15835
|
+
if (!cfg.models.includes(modelId)) cfg.models.push(modelId);
|
|
15836
|
+
await saveConfigProviders(providers);
|
|
15837
|
+
sendOperationResult(ws, true, `Saved model "${modelId}" for ${providerId}`);
|
|
15838
|
+
broadcastSaved(providers);
|
|
15839
|
+
} catch (err) {
|
|
15840
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
15841
|
+
}
|
|
15842
|
+
}
|
|
15843
|
+
async function handleCustomModelRemove(ws, providerId, modelId) {
|
|
15844
|
+
try {
|
|
15845
|
+
const providers = await loadConfigProviders();
|
|
15846
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
15847
|
+
if (!cfg) {
|
|
15848
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
15849
|
+
return;
|
|
15850
|
+
}
|
|
15851
|
+
if (cfg.customModels && Object.hasOwn(cfg.customModels, modelId)) {
|
|
15852
|
+
delete cfg.customModels[modelId];
|
|
15853
|
+
if (Object.keys(cfg.customModels).length === 0) delete cfg.customModels;
|
|
15854
|
+
if (cfg.models) {
|
|
15855
|
+
cfg.models = cfg.models.filter((m) => m !== modelId);
|
|
15856
|
+
if (cfg.models.length === 0) delete cfg.models;
|
|
15857
|
+
}
|
|
15858
|
+
await saveConfigProviders(providers);
|
|
15859
|
+
sendOperationResult(ws, true, `Removed model "${modelId}" from ${providerId}`);
|
|
15860
|
+
broadcastSaved(providers);
|
|
15861
|
+
} else {
|
|
15862
|
+
sendOperationResult(ws, false, `Model "${modelId}" not found in ${providerId}`);
|
|
15863
|
+
}
|
|
15864
|
+
} catch (err) {
|
|
15865
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15823
15868
|
async function handleProviderUndoClear(ws, providerId, previousModels) {
|
|
15824
15869
|
try {
|
|
15825
15870
|
const providers = await loadConfigProviders();
|
|
@@ -15895,7 +15940,7 @@ function createProviderOperations(deps2) {
|
|
|
15895
15940
|
const p = existing ? { ...existing } : { type: providerId };
|
|
15896
15941
|
p.family = outcome.family;
|
|
15897
15942
|
if (!p.baseUrl) p.baseUrl = outcome.baseUrl;
|
|
15898
|
-
p.models = [...outcome.models];
|
|
15943
|
+
if (outcome.models.length > 0) p.models = [...outcome.models];
|
|
15899
15944
|
const keys = normalizeKeys(p).filter((k) => k.label !== outcome.apiKey.label);
|
|
15900
15945
|
keys.push(outcome.apiKey);
|
|
15901
15946
|
writeKeysBack(p, keys);
|
|
@@ -16003,6 +16048,8 @@ function createProviderOperations(deps2) {
|
|
|
16003
16048
|
handleProviderAdd,
|
|
16004
16049
|
handleProviderRemove,
|
|
16005
16050
|
handleProviderClearModels,
|
|
16051
|
+
handleCustomModelSet,
|
|
16052
|
+
handleCustomModelRemove,
|
|
16006
16053
|
handleProviderUndoClear,
|
|
16007
16054
|
handleProviderUpdate,
|
|
16008
16055
|
handleProviderProbe,
|
|
@@ -16339,6 +16386,8 @@ var CLIENT_CONFIGURATION_MESSAGE_TYPES = [
|
|
|
16339
16386
|
"prefs.update",
|
|
16340
16387
|
"provider.add",
|
|
16341
16388
|
"provider.clear_models",
|
|
16389
|
+
"provider.custom_models.remove",
|
|
16390
|
+
"provider.custom_models.set",
|
|
16342
16391
|
"provider.models",
|
|
16343
16392
|
"provider.models.search",
|
|
16344
16393
|
"provider.probe",
|
|
@@ -18202,10 +18251,14 @@ async function handleProjectRoute(ws, msg, handlers) {
|
|
|
18202
18251
|
}
|
|
18203
18252
|
|
|
18204
18253
|
// src/server/provider-routes.ts
|
|
18254
|
+
import { modelsDevModelSchema } from "@wrongstack/core/models";
|
|
18205
18255
|
function asPayloadRecord(msg) {
|
|
18206
18256
|
const payload = msg.payload;
|
|
18207
18257
|
return typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : null;
|
|
18208
18258
|
}
|
|
18259
|
+
function isRecord4(value) {
|
|
18260
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18261
|
+
}
|
|
18209
18262
|
function requiredString(payload, key) {
|
|
18210
18263
|
const value = payload[key];
|
|
18211
18264
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
@@ -18228,7 +18281,7 @@ var CUSTOM_MODEL_BOOLEAN_CAPS = /* @__PURE__ */ new Set([
|
|
|
18228
18281
|
"streaming",
|
|
18229
18282
|
"jsonMode"
|
|
18230
18283
|
]);
|
|
18231
|
-
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider"]);
|
|
18284
|
+
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider", "modelsDev"]);
|
|
18232
18285
|
function optionalCustomModels(payload) {
|
|
18233
18286
|
const value = payload["customModels"];
|
|
18234
18287
|
if (value === void 0) return void 0;
|
|
@@ -18267,11 +18320,21 @@ function optionalCustomModels(payload) {
|
|
|
18267
18320
|
}
|
|
18268
18321
|
capabilities = built;
|
|
18269
18322
|
}
|
|
18323
|
+
const rawMd = definition["modelsDev"];
|
|
18324
|
+
let validatedModelsDev;
|
|
18325
|
+
if (rawMd !== void 0) {
|
|
18326
|
+
if (!isRecord4(rawMd)) return null;
|
|
18327
|
+
const parsed = modelsDevModelSchema.safeParse({ ...rawMd, id: modelId });
|
|
18328
|
+
if (!parsed.success) return null;
|
|
18329
|
+
const { id: _parsedId, ...validMd } = parsed.data;
|
|
18330
|
+
validatedModelsDev = validMd;
|
|
18331
|
+
}
|
|
18270
18332
|
out[modelId] = {
|
|
18271
18333
|
...typeof definition["name"] === "string" ? { name: definition["name"] } : {},
|
|
18272
18334
|
...typeof definition["provider"] === "string" ? { provider: definition["provider"] } : {},
|
|
18273
18335
|
...typeof definition["maxOutput"] === "number" ? { maxOutput: definition["maxOutput"] } : {},
|
|
18274
|
-
...capabilities ? { capabilities } : {}
|
|
18336
|
+
...capabilities ? { capabilities } : {},
|
|
18337
|
+
...validatedModelsDev ? { modelsDev: validatedModelsDev } : {}
|
|
18275
18338
|
};
|
|
18276
18339
|
}
|
|
18277
18340
|
return out;
|
|
@@ -18375,6 +18438,30 @@ async function handleProviderRoute(ws, msg, routes) {
|
|
|
18375
18438
|
await routes.providerHandlers.handleProviderClearModels(ws, providerId);
|
|
18376
18439
|
return true;
|
|
18377
18440
|
}
|
|
18441
|
+
case "provider.custom_models.set": {
|
|
18442
|
+
const payload = asPayloadRecord(msg);
|
|
18443
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
18444
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
18445
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
18446
|
+
return invalidPayload(ws, msg.type);
|
|
18447
|
+
}
|
|
18448
|
+
const customModelRaw = payload["customModel"];
|
|
18449
|
+
if (!isRecord4(customModelRaw)) return invalidPayload(ws, msg.type);
|
|
18450
|
+
const cm = optionalCustomModels({ customModels: { [modelId]: customModelRaw } });
|
|
18451
|
+
if (!cm || !cm[modelId]) return invalidPayload(ws, msg.type);
|
|
18452
|
+
await routes.providerHandlers.handleCustomModelSet(ws, providerId, modelId, cm[modelId]);
|
|
18453
|
+
return true;
|
|
18454
|
+
}
|
|
18455
|
+
case "provider.custom_models.remove": {
|
|
18456
|
+
const payload = asPayloadRecord(msg);
|
|
18457
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
18458
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
18459
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
18460
|
+
return invalidPayload(ws, msg.type);
|
|
18461
|
+
}
|
|
18462
|
+
await routes.providerHandlers.handleCustomModelRemove(ws, providerId, modelId);
|
|
18463
|
+
return true;
|
|
18464
|
+
}
|
|
18378
18465
|
case "provider.undo_clear": {
|
|
18379
18466
|
const payload = asPayloadRecord(msg);
|
|
18380
18467
|
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const CLIENT_WORKSPACE_MESSAGE_TYPES: readonly ['files.list', 'files.read', 'files.tree', 'files.write', 'git.changes', 'git.diff', 'git.info', 'projects.add', 'projects.list', 'projects.select', 'working_dir.set', 'worktree.cleanup', 'worktree.diff', 'worktree.merge', 'worktree.remove', 'worktree.scan', 'shell.open', 'process.kill', 'process.killAll', 'process.list', 'terminal.close', 'terminal.create', 'terminal.input', 'terminal.resize'];
|
|
2
|
-
export declare const CLIENT_CONFIGURATION_MESSAGE_TYPES: readonly ['codebase.index.server.shutdown', 'connections.health', 'connections.service_action', 'diag.get', 'key.add', 'key.delete', 'key.set_active', 'key.update', 'prefs.get', 'prefs.update', 'provider.add', 'provider.clear_models', 'provider.models', 'provider.models.search', 'provider.probe', 'provider.remove', 'provider.status.clear', 'provider.status.get', 'provider.status.retry', 'provider.undo_clear', 'provider.update', 'providers.list', 'providers.saved', 'tool.disable', 'tool.enable', 'tools.list', 'webui.shutdown'];
|
|
2
|
+
export declare const CLIENT_CONFIGURATION_MESSAGE_TYPES: readonly ['codebase.index.server.shutdown', 'connections.health', 'connections.service_action', 'diag.get', 'key.add', 'key.delete', 'key.set_active', 'key.update', 'prefs.get', 'prefs.update', 'provider.add', 'provider.clear_models', 'provider.custom_models.remove', 'provider.custom_models.set', 'provider.models', 'provider.models.search', 'provider.probe', 'provider.remove', 'provider.status.clear', 'provider.status.get', 'provider.status.retry', 'provider.undo_clear', 'provider.update', 'providers.list', 'providers.saved', 'tool.disable', 'tool.enable', 'tools.list', 'webui.shutdown'];
|
|
3
3
|
//# sourceMappingURL=client-workspace.d.ts.map
|
package/dist/protocol/index.js
CHANGED
|
@@ -289,6 +289,8 @@ var CLIENT_CONFIGURATION_MESSAGE_TYPES = [
|
|
|
289
289
|
"prefs.update",
|
|
290
290
|
"provider.add",
|
|
291
291
|
"provider.clear_models",
|
|
292
|
+
"provider.custom_models.remove",
|
|
293
|
+
"provider.custom_models.set",
|
|
292
294
|
"provider.models",
|
|
293
295
|
"provider.models.search",
|
|
294
296
|
"provider.probe",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const CLIENT_MESSAGE_TYPES: readonly ["abort", "ping", "user_message", "tool.confirm_result", "completion.request", "model.switch", "model.refine", "autonomy.switch", "context.clear", "context.compact", "context.debug", "context.editor.open", "context.editor.validate", "context.editor.apply", "context.mode.create", "context.mode.delete", "context.mode.switch", "context.mode.update", "context.modes.list", "context.repair", "mode.switch", "modes.list", "session.checkpoints", "session.delete", "session.new", "session.rename", "session.resume", "session.rewind", "session.save", "sessions.list", "side_effects.list", "stats.get", "todo.update", "todos.clear", "todos.get", "todos.remove", "collab.join", "collab.leave", "collab.annotate", "collab.resolve", "collab.request_pause", "collab.resume", "collab.grant_control", "collab.inject_tool", "mailbox.action", "mailbox.agents", "mailbox.clear", "mailbox.compact", "mailbox.messages", "mailbox.purge", "mailbox.send", "files.list", "files.read", "files.tree", "files.write", "git.changes", "git.diff", "git.info", "projects.add", "projects.list", "projects.select", "working_dir.set", "worktree.cleanup", "worktree.diff", "worktree.merge", "worktree.remove", "worktree.scan", "shell.open", "process.kill", "process.killAll", "process.list", "terminal.close", "terminal.create", "terminal.input", "terminal.resize", "codebase.index.server.shutdown", "connections.health", "connections.service_action", "diag.get", "key.add", "key.delete", "key.set_active", "key.update", "prefs.get", "prefs.update", "provider.add", "provider.clear_models", "provider.models", "provider.models.search", "provider.probe", "provider.remove", "provider.status.clear", "provider.status.get", "provider.status.retry", "provider.undo_clear", "provider.update", "providers.list", "providers.saved", "tool.disable", "tool.enable", "tools.list", "webui.shutdown", "goal-state.get", "goal.addTask", "goal.assess", "goal.assignTask", "goal.clear", "goal.get", "goal.list", "goal.load", "goal.moveTask", "goal.pause", "goal.resume", "goal.retryTask", "goal.revert", "goal.runTask", "goal.save", "goal.selectPhase", "goal.start", "goal.state", "goal.status", "goal.stop", "goal.taskStatus", "goal.toggleAutonomous", "plan.get", "plan.item.update", "plan.template_use", "task.update", "tasks.get", "sdd.board.cancel_task", "sdd.board.cleanup_worktrees", "sdd.board.delete_task", "sdd.board.destroy", "sdd.board.get", "sdd.board.list", "sdd.board.pause", "sdd.board.reassign", "sdd.board.resume", "sdd.board.retry", "sdd.board.retry_all_failed", "sdd.board.rollback", "sdd.board.set_task_fallbacks", "sdd.board.set_task_model", "sdd.board.set_task_verification", "sdd.board.split_task", "sdd.board.stop", "sdd.run.from_graph", "sdd.run.from_spec", "sdd.run.start", "sdd.spec.approve", "sdd.spec.discard", "sdd.spec.get", "sdd.spec.message", "sdd.spec.start", "specs.get", "specs.list", "specs.taskStatus", "brain.ask", "brain.config.get", "brain.config.set", "brain.risk", "brain.status", "chronicle.facet", "chronicle.facets", "chronicle.graph", "chronicle.metrics", "chronicle.query", "chronicle.status", "config.doctor", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "auth.oauth.cancel", "auth.oauth.code", "auth.oauth.start", "mcp.add", "mcp.disable", "mcp.discover", "mcp.enable", "mcp.list", "mcp.prompt.get", "mcp.prompts", "mcp.remove", "mcp.resource.read", "mcp.resources", "mcp.restart", "mcp.sleep", "mcp.update", "mcp.wake", "prompts.content", "prompts.create", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.create", "skills.edit", "skills.export", "skills.install", "skills.list", "skills.uninstall", "skills.update"];
|
|
1
|
+
export declare const CLIENT_MESSAGE_TYPES: readonly ["abort", "ping", "user_message", "tool.confirm_result", "completion.request", "model.switch", "model.refine", "autonomy.switch", "context.clear", "context.compact", "context.debug", "context.editor.open", "context.editor.validate", "context.editor.apply", "context.mode.create", "context.mode.delete", "context.mode.switch", "context.mode.update", "context.modes.list", "context.repair", "mode.switch", "modes.list", "session.checkpoints", "session.delete", "session.new", "session.rename", "session.resume", "session.rewind", "session.save", "sessions.list", "side_effects.list", "stats.get", "todo.update", "todos.clear", "todos.get", "todos.remove", "collab.join", "collab.leave", "collab.annotate", "collab.resolve", "collab.request_pause", "collab.resume", "collab.grant_control", "collab.inject_tool", "mailbox.action", "mailbox.agents", "mailbox.clear", "mailbox.compact", "mailbox.messages", "mailbox.purge", "mailbox.send", "files.list", "files.read", "files.tree", "files.write", "git.changes", "git.diff", "git.info", "projects.add", "projects.list", "projects.select", "working_dir.set", "worktree.cleanup", "worktree.diff", "worktree.merge", "worktree.remove", "worktree.scan", "shell.open", "process.kill", "process.killAll", "process.list", "terminal.close", "terminal.create", "terminal.input", "terminal.resize", "codebase.index.server.shutdown", "connections.health", "connections.service_action", "diag.get", "key.add", "key.delete", "key.set_active", "key.update", "prefs.get", "prefs.update", "provider.add", "provider.clear_models", "provider.custom_models.remove", "provider.custom_models.set", "provider.models", "provider.models.search", "provider.probe", "provider.remove", "provider.status.clear", "provider.status.get", "provider.status.retry", "provider.undo_clear", "provider.update", "providers.list", "providers.saved", "tool.disable", "tool.enable", "tools.list", "webui.shutdown", "goal-state.get", "goal.addTask", "goal.assess", "goal.assignTask", "goal.clear", "goal.get", "goal.list", "goal.load", "goal.moveTask", "goal.pause", "goal.resume", "goal.retryTask", "goal.revert", "goal.runTask", "goal.save", "goal.selectPhase", "goal.start", "goal.state", "goal.status", "goal.stop", "goal.taskStatus", "goal.toggleAutonomous", "plan.get", "plan.item.update", "plan.template_use", "task.update", "tasks.get", "sdd.board.cancel_task", "sdd.board.cleanup_worktrees", "sdd.board.delete_task", "sdd.board.destroy", "sdd.board.get", "sdd.board.list", "sdd.board.pause", "sdd.board.reassign", "sdd.board.resume", "sdd.board.retry", "sdd.board.retry_all_failed", "sdd.board.rollback", "sdd.board.set_task_fallbacks", "sdd.board.set_task_model", "sdd.board.set_task_verification", "sdd.board.split_task", "sdd.board.stop", "sdd.run.from_graph", "sdd.run.from_spec", "sdd.run.start", "sdd.spec.approve", "sdd.spec.discard", "sdd.spec.get", "sdd.spec.message", "sdd.spec.start", "specs.get", "specs.list", "specs.taskStatus", "brain.ask", "brain.config.get", "brain.config.set", "brain.risk", "brain.status", "chronicle.facet", "chronicle.facets", "chronicle.graph", "chronicle.metrics", "chronicle.query", "chronicle.status", "config.doctor", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "auth.oauth.cancel", "auth.oauth.code", "auth.oauth.start", "mcp.add", "mcp.disable", "mcp.discover", "mcp.enable", "mcp.list", "mcp.prompt.get", "mcp.prompts", "mcp.remove", "mcp.resource.read", "mcp.resources", "mcp.restart", "mcp.sleep", "mcp.update", "mcp.wake", "prompts.content", "prompts.create", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.create", "skills.edit", "skills.export", "skills.install", "skills.list", "skills.uninstall", "skills.update"];
|
|
2
2
|
export declare const SERVER_MESSAGE_TYPES: readonly ["error", "log", "pong", "side_effects", "agent.status_changed", "agent.timeline.message", "client.status_update", "chimera.report_available", "compaction.failed", "completion.result", "context.compacted", "context.debug", "context.editor.snapshot", "context.editor.validation", "context.editor.applied", "context.mode.changed", "context.modes.list", "context.repaired", "ctx.max_context", "ctx.pct", "delegate.completed", "delegate.started", "iteration.completed", "iteration.limit_reached", "iteration.started", "model.refine_result", "modes.list", "provider.active_blocked", "provider.error", "provider.fallback", "provider.response", "provider.retry", "provider.status_changed", "provider.stream_error", "provider.text_delta", "provider.thinking_delta", "run.result", "session.checkpoints", "session.damaged", "session.end", "session.rewound", "session.start", "session.stats", "sessions.list", "sessions.status_update", "stats.get", "token.cost_estimate_unavailable", "token.threshold", "tool.confirm_needed", "tool.disabled", "tool.enabled", "tool.executed", "tool.loop_detected", "tool.progress", "tool.started", "tools.list", "trust.persisted", "collab.annotation.added", "collab.annotation.resolved", "collab.event", "collab.injection.granted", "collab.participant.joined", "collab.participant.left", "collab.pause.granted", "collab.pause.released", "collab.state", "mailbox.action_result", "mailbox.agent_registered", "mailbox.agents", "mailbox.cleared", "mailbox.compacted", "mailbox.event", "mailbox.messages", "mailbox.sent", "mailbox.purged", "mailbox.received", "subagent.budget_extended", "subagent.event", "checkpoint.written", "codemap.file_event", "codemap.index_updated", "codemap.tool_executed", "codemap.tool_started", "file.saved", "files.list", "files.read", "files.tree", "files.written", "git.changes", "git.diff", "git.info", "process.list", "projects.added", "projects.list", "projects.selected", "terminal.exit", "terminal.output", "working_dir.changed", "worktree.cleanup_result", "worktree.diff_result", "worktree.event", "worktree.merge_result", "worktree.orphans", "worktree.state", "auth.oauth.status", "codebase.index.server.shutdown_result", "connections.health_error", "connections.health_result", "connections.service_action_result", "diag.get", "key.operation_result", "model.switch_result", "prefs.updated", "provider.catalog", "provider.models", "provider.models.search_result", "provider.probe", "provider.status.snapshot", "providers.saved", "budget.decision", "budget.threshold_reached", "coordinator.stats", "coordinator.status", "eternal.iteration", "fleet.concurrency_update", "goal-state.updated", "goal.assess.result", "goal.list", "goal.paused", "goal.resumed", "goal.saved", "goal.error", "goal.stopped", "goal.failed", "goal.completed", "goal.cleared", "goal.reverted", "goal.progress", "goal.state", "in_flight.ended", "in_flight.started", "plan.updated", "task.completed", "task.failed", "task.pending", "task.started", "tasks.updated", "todos.cleared", "todos.updated", "kanban.task.activity", "sdd.board.lifecycle_result", "sdd.board.list", "sdd.board.snapshot", "sdd.run.started", "sdd.spec.agent_text", "sdd.spec.error", "sdd.spec.snapshot", "specs.detail", "specs.list", "consensus.vote_cast", "consensus.vote_initiated", "consensus.vote_resolved", "cron.job_fired", "cron.snapshot", "techstack.job.cancelled", "techstack.job.failed", "techstack.job.progress", "techstack.job.started", "techstack.report.delivered", "techstack.report.ready", "techstack.snapshot.updated", "techstack.workspace.completed", "brain.answer", "brain.config", "brain.event", "brain.status", "chronicle.error", "chronicle.facet_result", "chronicle.facets_result", "chronicle.graph_result", "chronicle.metrics_result", "chronicle.query_result", "chronicle.status_result", "config.doctor.result", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.event", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "mcp.content.error", "mcp.content.selected", "mcp.list", "mcp.operation_result", "mcp.prompts", "mcp.resources", "mcp.server.added", "mcp.server.connected", "mcp.server.disconnected", "mcp.server.discovered", "mcp.server.error", "mcp.server.reconnected", "mcp.server.removed", "mcp.server.sleeping", "mcp.server.updated", "mcp.server.waking", "prompts.content", "prompts.created", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.created", "skills.edited", "skills.exported", "skills.installed", "skills.list", "skills.uninstalled", "skills.updated"];
|
|
3
3
|
export type ExactClientMessageType = (typeof CLIENT_MESSAGE_TYPES)[number];
|
|
4
4
|
export type ExactServerMessageType = (typeof SERVER_MESSAGE_TYPES)[number];
|
|
@@ -54,6 +54,8 @@ export declare function createEmbeddedProviderOperations(ctx: EmbeddedProviderCo
|
|
|
54
54
|
}) => Promise<void>;
|
|
55
55
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
56
56
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
57
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
58
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
57
59
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
58
60
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
59
61
|
id: string;
|
package/dist/server/entry.js
CHANGED
|
@@ -13762,7 +13762,8 @@ function createProviderOperations(deps2) {
|
|
|
13762
13762
|
providerId,
|
|
13763
13763
|
config
|
|
13764
13764
|
);
|
|
13765
|
-
const
|
|
13765
|
+
const siblingCatalogKey = config?.family ?? providerId;
|
|
13766
|
+
const siblingId = SIBLING_CATALOG[siblingCatalogKey];
|
|
13766
13767
|
const sibling = siblingId && siblingId !== providerId ? await deps2.modelsRegistry.getProvider(siblingId).catch(() => void 0) : void 0;
|
|
13767
13768
|
let models = resolveProviderModelList(
|
|
13768
13769
|
config?.models,
|
|
@@ -13917,6 +13918,50 @@ function createProviderOperations(deps2) {
|
|
|
13917
13918
|
sendOperationResult(ws, false, errMessage(err));
|
|
13918
13919
|
}
|
|
13919
13920
|
}
|
|
13921
|
+
async function handleCustomModelSet(ws, providerId, modelId, definition) {
|
|
13922
|
+
try {
|
|
13923
|
+
const providers = await loadConfigProviders();
|
|
13924
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
13925
|
+
if (!cfg) {
|
|
13926
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
13927
|
+
return;
|
|
13928
|
+
}
|
|
13929
|
+
if (!cfg.customModels) cfg.customModels = {};
|
|
13930
|
+
cfg.customModels[modelId] = definition;
|
|
13931
|
+
if (!cfg.models) cfg.models = [];
|
|
13932
|
+
if (!cfg.models.includes(modelId)) cfg.models.push(modelId);
|
|
13933
|
+
await saveConfigProviders(providers);
|
|
13934
|
+
sendOperationResult(ws, true, `Saved model "${modelId}" for ${providerId}`);
|
|
13935
|
+
broadcastSaved(providers);
|
|
13936
|
+
} catch (err) {
|
|
13937
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
13938
|
+
}
|
|
13939
|
+
}
|
|
13940
|
+
async function handleCustomModelRemove(ws, providerId, modelId) {
|
|
13941
|
+
try {
|
|
13942
|
+
const providers = await loadConfigProviders();
|
|
13943
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
13944
|
+
if (!cfg) {
|
|
13945
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
13946
|
+
return;
|
|
13947
|
+
}
|
|
13948
|
+
if (cfg.customModels && Object.hasOwn(cfg.customModels, modelId)) {
|
|
13949
|
+
delete cfg.customModels[modelId];
|
|
13950
|
+
if (Object.keys(cfg.customModels).length === 0) delete cfg.customModels;
|
|
13951
|
+
if (cfg.models) {
|
|
13952
|
+
cfg.models = cfg.models.filter((m) => m !== modelId);
|
|
13953
|
+
if (cfg.models.length === 0) delete cfg.models;
|
|
13954
|
+
}
|
|
13955
|
+
await saveConfigProviders(providers);
|
|
13956
|
+
sendOperationResult(ws, true, `Removed model "${modelId}" from ${providerId}`);
|
|
13957
|
+
broadcastSaved(providers);
|
|
13958
|
+
} else {
|
|
13959
|
+
sendOperationResult(ws, false, `Model "${modelId}" not found in ${providerId}`);
|
|
13960
|
+
}
|
|
13961
|
+
} catch (err) {
|
|
13962
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
13963
|
+
}
|
|
13964
|
+
}
|
|
13920
13965
|
async function handleProviderUndoClear(ws, providerId, previousModels) {
|
|
13921
13966
|
try {
|
|
13922
13967
|
const providers = await loadConfigProviders();
|
|
@@ -13992,7 +14037,7 @@ function createProviderOperations(deps2) {
|
|
|
13992
14037
|
const p = existing ? { ...existing } : { type: providerId };
|
|
13993
14038
|
p.family = outcome.family;
|
|
13994
14039
|
if (!p.baseUrl) p.baseUrl = outcome.baseUrl;
|
|
13995
|
-
p.models = [...outcome.models];
|
|
14040
|
+
if (outcome.models.length > 0) p.models = [...outcome.models];
|
|
13996
14041
|
const keys = normalizeKeys(p).filter((k) => k.label !== outcome.apiKey.label);
|
|
13997
14042
|
keys.push(outcome.apiKey);
|
|
13998
14043
|
writeKeysBack(p, keys);
|
|
@@ -14100,6 +14145,8 @@ function createProviderOperations(deps2) {
|
|
|
14100
14145
|
handleProviderAdd,
|
|
14101
14146
|
handleProviderRemove,
|
|
14102
14147
|
handleProviderClearModels,
|
|
14148
|
+
handleCustomModelSet,
|
|
14149
|
+
handleCustomModelRemove,
|
|
14103
14150
|
handleProviderUndoClear,
|
|
14104
14151
|
handleProviderUpdate,
|
|
14105
14152
|
handleProviderProbe,
|
|
@@ -14373,6 +14420,8 @@ var CLIENT_CONFIGURATION_MESSAGE_TYPES = [
|
|
|
14373
14420
|
"prefs.update",
|
|
14374
14421
|
"provider.add",
|
|
14375
14422
|
"provider.clear_models",
|
|
14423
|
+
"provider.custom_models.remove",
|
|
14424
|
+
"provider.custom_models.set",
|
|
14376
14425
|
"provider.models",
|
|
14377
14426
|
"provider.models.search",
|
|
14378
14427
|
"provider.probe",
|
|
@@ -15898,10 +15947,14 @@ async function handleProjectRoute(ws, msg, handlers) {
|
|
|
15898
15947
|
}
|
|
15899
15948
|
|
|
15900
15949
|
// src/server/provider-routes.ts
|
|
15950
|
+
import { modelsDevModelSchema } from "@wrongstack/core/models";
|
|
15901
15951
|
function asPayloadRecord(msg) {
|
|
15902
15952
|
const payload = msg.payload;
|
|
15903
15953
|
return typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : null;
|
|
15904
15954
|
}
|
|
15955
|
+
function isRecord4(value) {
|
|
15956
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15957
|
+
}
|
|
15905
15958
|
function requiredString(payload, key) {
|
|
15906
15959
|
const value = payload[key];
|
|
15907
15960
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
@@ -15924,7 +15977,7 @@ var CUSTOM_MODEL_BOOLEAN_CAPS = /* @__PURE__ */ new Set([
|
|
|
15924
15977
|
"streaming",
|
|
15925
15978
|
"jsonMode"
|
|
15926
15979
|
]);
|
|
15927
|
-
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider"]);
|
|
15980
|
+
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider", "modelsDev"]);
|
|
15928
15981
|
function optionalCustomModels(payload) {
|
|
15929
15982
|
const value = payload["customModels"];
|
|
15930
15983
|
if (value === void 0) return void 0;
|
|
@@ -15963,11 +16016,21 @@ function optionalCustomModels(payload) {
|
|
|
15963
16016
|
}
|
|
15964
16017
|
capabilities = built;
|
|
15965
16018
|
}
|
|
16019
|
+
const rawMd = definition["modelsDev"];
|
|
16020
|
+
let validatedModelsDev;
|
|
16021
|
+
if (rawMd !== void 0) {
|
|
16022
|
+
if (!isRecord4(rawMd)) return null;
|
|
16023
|
+
const parsed = modelsDevModelSchema.safeParse({ ...rawMd, id: modelId });
|
|
16024
|
+
if (!parsed.success) return null;
|
|
16025
|
+
const { id: _parsedId, ...validMd } = parsed.data;
|
|
16026
|
+
validatedModelsDev = validMd;
|
|
16027
|
+
}
|
|
15966
16028
|
out[modelId] = {
|
|
15967
16029
|
...typeof definition["name"] === "string" ? { name: definition["name"] } : {},
|
|
15968
16030
|
...typeof definition["provider"] === "string" ? { provider: definition["provider"] } : {},
|
|
15969
16031
|
...typeof definition["maxOutput"] === "number" ? { maxOutput: definition["maxOutput"] } : {},
|
|
15970
|
-
...capabilities ? { capabilities } : {}
|
|
16032
|
+
...capabilities ? { capabilities } : {},
|
|
16033
|
+
...validatedModelsDev ? { modelsDev: validatedModelsDev } : {}
|
|
15971
16034
|
};
|
|
15972
16035
|
}
|
|
15973
16036
|
return out;
|
|
@@ -16071,6 +16134,30 @@ async function handleProviderRoute(ws, msg, routes) {
|
|
|
16071
16134
|
await routes.providerHandlers.handleProviderClearModels(ws, providerId);
|
|
16072
16135
|
return true;
|
|
16073
16136
|
}
|
|
16137
|
+
case "provider.custom_models.set": {
|
|
16138
|
+
const payload = asPayloadRecord(msg);
|
|
16139
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
16140
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
16141
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
16142
|
+
return invalidPayload(ws, msg.type);
|
|
16143
|
+
}
|
|
16144
|
+
const customModelRaw = payload["customModel"];
|
|
16145
|
+
if (!isRecord4(customModelRaw)) return invalidPayload(ws, msg.type);
|
|
16146
|
+
const cm = optionalCustomModels({ customModels: { [modelId]: customModelRaw } });
|
|
16147
|
+
if (!cm || !cm[modelId]) return invalidPayload(ws, msg.type);
|
|
16148
|
+
await routes.providerHandlers.handleCustomModelSet(ws, providerId, modelId, cm[modelId]);
|
|
16149
|
+
return true;
|
|
16150
|
+
}
|
|
16151
|
+
case "provider.custom_models.remove": {
|
|
16152
|
+
const payload = asPayloadRecord(msg);
|
|
16153
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
16154
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
16155
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
16156
|
+
return invalidPayload(ws, msg.type);
|
|
16157
|
+
}
|
|
16158
|
+
await routes.providerHandlers.handleCustomModelRemove(ws, providerId, modelId);
|
|
16159
|
+
return true;
|
|
16160
|
+
}
|
|
16074
16161
|
case "provider.undo_clear": {
|
|
16075
16162
|
const payload = asPayloadRecord(msg);
|
|
16076
16163
|
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
@@ -98,6 +98,8 @@ export declare function createProviderOperations(deps: ProviderOperationsDeps):
|
|
|
98
98
|
}) => Promise<void>;
|
|
99
99
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
100
100
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
101
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
102
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
101
103
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
102
104
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
103
105
|
id: string;
|
|
@@ -138,6 +140,8 @@ export declare function createProviderHandlers(deps: ProviderHandlerDeps): {
|
|
|
138
140
|
}) => Promise<void>;
|
|
139
141
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
140
142
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
143
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
144
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
141
145
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
142
146
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
143
147
|
id: string;
|
|
@@ -17,6 +17,8 @@ export interface ProviderMutationHandlers {
|
|
|
17
17
|
}) => Promise<void>;
|
|
18
18
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
19
19
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
20
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
21
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
20
22
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
21
23
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
22
24
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/webui-server",
|
|
3
|
-
"version": "0.298.
|
|
3
|
+
"version": "0.298.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack WebUI HTTP/WebSocket server module — extracted from @wrongstack/webui in PR #243/244 to remove the CLI -> @wrongstack/webui/server cross-package edge (audit §3.1.1). Pure backend: HTTP routes, WebSocket handlers, MCP tool wrappers, HTML serving. The web frontend lives in @wrongstack/webui; this package is the standalone server it can run on.",
|
|
6
6
|
"keywords": [
|
|
@@ -40,15 +40,15 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"ws": "^8.21.1",
|
|
43
|
-
"@wrongstack/
|
|
44
|
-
"@wrongstack/
|
|
45
|
-
"@wrongstack/runtime": "0.298.
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
51
|
-
"@wrongstack/
|
|
43
|
+
"@wrongstack/core": "0.298.3",
|
|
44
|
+
"@wrongstack/providers": "0.298.3",
|
|
45
|
+
"@wrongstack/runtime": "0.298.3",
|
|
46
|
+
"@wrongstack/kanban": "0.298.3",
|
|
47
|
+
"@wrongstack/sdd": "0.298.3",
|
|
48
|
+
"@wrongstack/sage": "0.298.3",
|
|
49
|
+
"@wrongstack/techstack": "0.298.3",
|
|
50
|
+
"@wrongstack/tools": "0.298.3",
|
|
51
|
+
"@wrongstack/mcp": "0.298.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^26.1.2",
|