@wrongstack/webui-server 0.310.0 → 0.310.1
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 +163 -12
- package/dist/server/entry.js +146 -10
- package/dist/server/pref-helpers.d.ts +1 -1
- package/dist/server/prefs-handlers.d.ts +11 -1
- package/dist/server/proxy-runtime.d.ts +82 -0
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -97,7 +97,12 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
97
97
|
// `prefs.update` exactly so the panel does not error with
|
|
98
98
|
// "unknown preference key".
|
|
99
99
|
"readSymbols",
|
|
100
|
-
"showSageMemoryInject"
|
|
100
|
+
"showSageMemoryInject",
|
|
101
|
+
// WrongProxy / WrongTrace master switch. When on, the CLI rewrites every
|
|
102
|
+
// provider's base URL through the configured proxy URL (default
|
|
103
|
+
// http://localhost:8000 → http://localhost:8000/proxy/<host><path>).
|
|
104
|
+
// Excluded providers (openai-codex) flow through unchanged.
|
|
105
|
+
"wrongProxyEnabled"
|
|
101
106
|
]);
|
|
102
107
|
var STRING_ARRAY_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
103
108
|
"fallbackModels",
|
|
@@ -164,7 +169,11 @@ var STRING_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
164
169
|
"chimeraModel",
|
|
165
170
|
"autoReviewProvider",
|
|
166
171
|
"autoReviewModel",
|
|
167
|
-
"autoReviewFallbackProfile"
|
|
172
|
+
"autoReviewFallbackProfile",
|
|
173
|
+
// WrongProxy / WrongTrace URL. Empty = unset. Default lives in
|
|
174
|
+
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:8000'); users
|
|
175
|
+
// can override here for non-default daemon ports / paths.
|
|
176
|
+
"wrongProxyUrl"
|
|
168
177
|
]);
|
|
169
178
|
var ENUM_PREF_KEYS = {
|
|
170
179
|
autonomy: AUTONOMY_VALUES,
|
|
@@ -1054,7 +1063,7 @@ function routingPatch(payload) {
|
|
|
1054
1063
|
function handlePrefsGet(ctx, ws) {
|
|
1055
1064
|
ctx.send(ws, { type: "prefs.updated", payload: ctx.snapshot() });
|
|
1056
1065
|
}
|
|
1057
|
-
function handlePrefsUpdate(ctx, ws, input) {
|
|
1066
|
+
async function handlePrefsUpdate(ctx, ws, input) {
|
|
1058
1067
|
const parsed = validatePrefsUpdatePayload(input);
|
|
1059
1068
|
if (!parsed.ok) {
|
|
1060
1069
|
sendResult(ctx, ws, false, parsed.message);
|
|
@@ -1087,6 +1096,9 @@ function handlePrefsUpdate(ctx, ws, input) {
|
|
|
1087
1096
|
({ setDebugStreamEnabled }) => setDebugStreamEnabled(payload["debugStream"])
|
|
1088
1097
|
);
|
|
1089
1098
|
}
|
|
1099
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean" || typeof payload["wrongProxyUrl"] === "string") {
|
|
1100
|
+
await ctx.applyWrongProxyPrefs?.(payload);
|
|
1101
|
+
}
|
|
1090
1102
|
if (typeof payload["logLevel"] === "string" && ["debug", "info", "warn", "error"].includes(payload["logLevel"])) {
|
|
1091
1103
|
ctx.setLogLevel?.(payload["logLevel"]);
|
|
1092
1104
|
}
|
|
@@ -7290,6 +7302,8 @@ function seedContextMeta(config, context) {
|
|
|
7290
7302
|
meta["tgDelegate"] = tgExt?.["notifyOnDelegate"] !== false;
|
|
7291
7303
|
const tgMs = tgExt?.["longToolThresholdMs"];
|
|
7292
7304
|
meta["tgLongToolMs"] = typeof tgMs === "number" ? tgMs : 3e4;
|
|
7305
|
+
meta["wrongProxyEnabled"] = config.tools?.wrongProxy?.enabled === true;
|
|
7306
|
+
meta["wrongProxyUrl"] = config.tools?.wrongProxy?.url ?? "";
|
|
7293
7307
|
{
|
|
7294
7308
|
const pluginsEnabled = {};
|
|
7295
7309
|
const record = (name2) => {
|
|
@@ -7662,6 +7676,87 @@ import * as path13 from "node:path";
|
|
|
7662
7676
|
import { TOKENS } from "@wrongstack/core/kernel";
|
|
7663
7677
|
import { DefaultSessionStore as DefaultSessionStore2 } from "@wrongstack/core/storage";
|
|
7664
7678
|
import { toErrorMessage as toErrorMessage7, wstackGlobalRoot as wstackGlobalRoot2 } from "@wrongstack/core/utils";
|
|
7679
|
+
|
|
7680
|
+
// src/server/proxy-runtime.ts
|
|
7681
|
+
import {
|
|
7682
|
+
applyProxyConfig,
|
|
7683
|
+
getProxyConfig,
|
|
7684
|
+
rewriteBaseUrl,
|
|
7685
|
+
shouldRewriteFor
|
|
7686
|
+
} from "@wrongstack/core/wiring/proxy-rewrite";
|
|
7687
|
+
var HEALTH_PATH = "/api/health";
|
|
7688
|
+
var PROBE_TIMEOUT_MS = 2e3;
|
|
7689
|
+
function seedWrongProxyFromConfig(config) {
|
|
7690
|
+
const wp = config.tools?.wrongProxy;
|
|
7691
|
+
if (!wp) {
|
|
7692
|
+
return;
|
|
7693
|
+
}
|
|
7694
|
+
applyProxyConfig({
|
|
7695
|
+
enabled: wp.enabled === true,
|
|
7696
|
+
url: typeof wp.url === "string" ? wp.url : ""
|
|
7697
|
+
});
|
|
7698
|
+
}
|
|
7699
|
+
async function probeWrongProxyActive() {
|
|
7700
|
+
const cfg = getProxyConfig();
|
|
7701
|
+
if (!cfg.enabled || !cfg.url) {
|
|
7702
|
+
applyProxyConfig({ active: false });
|
|
7703
|
+
return false;
|
|
7704
|
+
}
|
|
7705
|
+
const abort = new AbortController();
|
|
7706
|
+
const timeout = setTimeout(() => abort.abort(), PROBE_TIMEOUT_MS);
|
|
7707
|
+
if (typeof timeout.unref === "function") {
|
|
7708
|
+
timeout.unref();
|
|
7709
|
+
}
|
|
7710
|
+
try {
|
|
7711
|
+
const healthUrl = `${cfg.url.replace(/\/+$/, "")}${HEALTH_PATH}`;
|
|
7712
|
+
const res = await fetch(healthUrl, {
|
|
7713
|
+
method: "GET",
|
|
7714
|
+
signal: abort.signal,
|
|
7715
|
+
headers: { accept: "application/json" }
|
|
7716
|
+
});
|
|
7717
|
+
const ok2 = res.ok && res.status >= 200 && res.status < 300;
|
|
7718
|
+
applyProxyConfig({ active: ok2 });
|
|
7719
|
+
return ok2;
|
|
7720
|
+
} catch {
|
|
7721
|
+
applyProxyConfig({ active: false });
|
|
7722
|
+
return false;
|
|
7723
|
+
} finally {
|
|
7724
|
+
clearTimeout(timeout);
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
async function applyWrongProxyPrefs(payload) {
|
|
7728
|
+
const patch = {};
|
|
7729
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean") {
|
|
7730
|
+
patch.enabled = payload["wrongProxyEnabled"];
|
|
7731
|
+
}
|
|
7732
|
+
if (typeof payload["wrongProxyUrl"] === "string") {
|
|
7733
|
+
patch.url = payload["wrongProxyUrl"];
|
|
7734
|
+
}
|
|
7735
|
+
if (Object.keys(patch).length === 0) return;
|
|
7736
|
+
applyProxyConfig(patch);
|
|
7737
|
+
await probeWrongProxyActive();
|
|
7738
|
+
}
|
|
7739
|
+
async function bootstrapWrongProxyFromConfig(config) {
|
|
7740
|
+
seedWrongProxyFromConfig(config);
|
|
7741
|
+
await probeWrongProxyActive();
|
|
7742
|
+
}
|
|
7743
|
+
function routeProviderCfgThroughProxy(cfg, fallbackBaseUrl, providerId) {
|
|
7744
|
+
const raw = cfg;
|
|
7745
|
+
const cfgType = typeof raw.type === "string" ? raw.type : void 0;
|
|
7746
|
+
const cfgBaseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl : void 0;
|
|
7747
|
+
const factoryType = cfgType ?? providerId;
|
|
7748
|
+
const rawBaseUrl = cfgBaseUrl ?? fallbackBaseUrl;
|
|
7749
|
+
if (!rawBaseUrl || !shouldRewriteFor(factoryType)) {
|
|
7750
|
+
return { ...cfg };
|
|
7751
|
+
}
|
|
7752
|
+
const baseUrl = rewriteBaseUrl(rawBaseUrl, getProxyConfig().url);
|
|
7753
|
+
return {
|
|
7754
|
+
...cfg,
|
|
7755
|
+
...baseUrl !== cfgBaseUrl ? { baseUrl } : {}
|
|
7756
|
+
};
|
|
7757
|
+
}
|
|
7758
|
+
|
|
7759
|
+
// src/server/embedded-host-adapters.ts
|
|
7665
7760
|
import { makeProviderFromConfig } from "@wrongstack/providers";
|
|
7666
7761
|
|
|
7667
7762
|
// src/server/project-handlers.ts
|
|
@@ -9884,7 +9979,12 @@ async function applyEmbeddedModelSwitch(ctx, providerId, modelId) {
|
|
|
9884
9979
|
await agentContext.runModelTransition(async () => {
|
|
9885
9980
|
const saved = await ctx.loadSavedProviders();
|
|
9886
9981
|
const providerConfig = saved[providerId] ?? { type: providerId };
|
|
9887
|
-
const
|
|
9982
|
+
const routedConfig = routeProviderCfgThroughProxy(
|
|
9983
|
+
providerConfig,
|
|
9984
|
+
ctx.getConfig?.()?.baseUrl,
|
|
9985
|
+
providerId
|
|
9986
|
+
);
|
|
9987
|
+
const nextProvider = makeProviderFromConfig(providerId, routedConfig);
|
|
9888
9988
|
await ctx.modelsRegistry?.refresh().catch((error2) => {
|
|
9889
9989
|
ctx.log(
|
|
9890
9990
|
JSON.stringify({
|
|
@@ -16267,7 +16367,15 @@ function createEmbeddedMessageRouter(deps2) {
|
|
|
16267
16367
|
getLiveProviderId: () => deps2.agentConfigCtx.agent.ctx.provider.id,
|
|
16268
16368
|
buildProvider: async (providerId) => {
|
|
16269
16369
|
const saved = await deps2.agentConfigCtx.loadSavedProviders();
|
|
16270
|
-
|
|
16370
|
+
const providerCfg = saved[providerId] ?? { type: providerId };
|
|
16371
|
+
return makeProviderFromConfig2(
|
|
16372
|
+
providerId,
|
|
16373
|
+
routeProviderCfgThroughProxy(
|
|
16374
|
+
providerCfg,
|
|
16375
|
+
deps2.agentConfigCtx.getConfig?.()?.baseUrl,
|
|
16376
|
+
providerId
|
|
16377
|
+
)
|
|
16378
|
+
);
|
|
16271
16379
|
},
|
|
16272
16380
|
applyModelSwitch: (providerId, modelId) => applyEmbeddedModelSwitch(deps2.agentConfigCtx, providerId, modelId),
|
|
16273
16381
|
isRunActive: () => deps2.conversationCtx.abortControllers.size > 0,
|
|
@@ -21101,7 +21209,13 @@ var PREF_KEYS = [
|
|
|
21101
21209
|
// Per-plugin enable/disable map (parity with the embedded server).
|
|
21102
21210
|
"pluginsEnabled",
|
|
21103
21211
|
// Fleet chat verbosity: off | full (migrated from streamFleet boolean).
|
|
21104
|
-
"fleetChatVerbosity"
|
|
21212
|
+
"fleetChatVerbosity",
|
|
21213
|
+
// WrongProxy / WrongTrace: master switch + configurable URL (default
|
|
21214
|
+
// http://localhost:8000). When `wrongProxyEnabled` is true and the daemon
|
|
21215
|
+
// is reachable, every provider's base URL flows through
|
|
21216
|
+
// `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is excluded by spec.
|
|
21217
|
+
"wrongProxyEnabled",
|
|
21218
|
+
"wrongProxyUrl"
|
|
21105
21219
|
];
|
|
21106
21220
|
function prefSnapshot(contextMeta) {
|
|
21107
21221
|
const snapshot = {};
|
|
@@ -21367,6 +21481,15 @@ async function persistPrefsToConfig(deps2, holder, payload) {
|
|
|
21367
21481
|
}
|
|
21368
21482
|
if (typeof payload["debugStream"] === "boolean")
|
|
21369
21483
|
decrypted.debugStream = payload["debugStream"];
|
|
21484
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean" || typeof payload["wrongProxyUrl"] === "string") {
|
|
21485
|
+
const toolsCfg = decrypted.tools ?? {};
|
|
21486
|
+
const wp = toolsCfg["wrongProxy"] ?? {};
|
|
21487
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean")
|
|
21488
|
+
wp["enabled"] = payload["wrongProxyEnabled"];
|
|
21489
|
+
if (typeof payload["wrongProxyUrl"] === "string") wp["url"] = payload["wrongProxyUrl"];
|
|
21490
|
+
toolsCfg["wrongProxy"] = wp;
|
|
21491
|
+
decrypted.tools = toolsCfg;
|
|
21492
|
+
}
|
|
21370
21493
|
if (typeof payload["pluginsEnabled"] === "object" && payload["pluginsEnabled"] !== null) {
|
|
21371
21494
|
const ext = decrypted.extensions ?? {};
|
|
21372
21495
|
const toggled = [];
|
|
@@ -26133,7 +26256,12 @@ function resolveSetupProvider(opts) {
|
|
|
26133
26256
|
baseUrl: config.baseUrl
|
|
26134
26257
|
};
|
|
26135
26258
|
try {
|
|
26136
|
-
const
|
|
26259
|
+
const routedConfig = routeProviderCfgThroughProxy(
|
|
26260
|
+
providerConfig,
|
|
26261
|
+
config.baseUrl,
|
|
26262
|
+
config.provider
|
|
26263
|
+
);
|
|
26264
|
+
const cfgWithType = { ...routedConfig, type: config.provider };
|
|
26137
26265
|
const provider2 = config.features.modelsRegistry && providerRegistry.has(config.provider) ? providerRegistry.create(cfgWithType) : makeProviderFromConfig3(config.provider, cfgWithType);
|
|
26138
26266
|
return { provider: provider2, needsSetup: false };
|
|
26139
26267
|
} catch (err) {
|
|
@@ -26146,8 +26274,13 @@ function resolveSetupProvider(opts) {
|
|
|
26146
26274
|
if (firstKey) {
|
|
26147
26275
|
const firstProvider = expectDefined3(savedProviders[firstKey]);
|
|
26148
26276
|
try {
|
|
26277
|
+
const routedConfig = routeProviderCfgThroughProxy(
|
|
26278
|
+
firstProvider,
|
|
26279
|
+
config.baseUrl,
|
|
26280
|
+
firstKey
|
|
26281
|
+
);
|
|
26149
26282
|
const provider2 = makeProviderFromConfig3(firstKey, {
|
|
26150
|
-
...
|
|
26283
|
+
...routedConfig,
|
|
26151
26284
|
type: firstKey,
|
|
26152
26285
|
family: firstProvider.family,
|
|
26153
26286
|
apiKey: firstProvider.apiKey
|
|
@@ -26793,9 +26926,14 @@ function buildRoutes(state, deps2, cb) {
|
|
|
26793
26926
|
const cur = state.getConfig();
|
|
26794
26927
|
const newCfg = patchConfig(cur, { provider: newProvider, model: newModel });
|
|
26795
26928
|
const providerCfg = newCfg.providers?.[newProvider] ?? { type: newProvider };
|
|
26796
|
-
const
|
|
26929
|
+
const routedCfg = routeProviderCfgThroughProxy(
|
|
26930
|
+
providerCfg,
|
|
26931
|
+
newCfg.baseUrl,
|
|
26932
|
+
newProvider
|
|
26933
|
+
);
|
|
26934
|
+
const built = deps2.providerRegistry.has(newProvider) ? deps2.providerRegistry.create({ ...routedCfg, type: newProvider }) : makeProviderFromConfig4(newProvider, routedCfg);
|
|
26797
26935
|
const newProv = deps2.modelsRegistry ? await withCatalogCapabilities(deps2.modelsRegistry, newProvider, built, {
|
|
26798
|
-
...
|
|
26936
|
+
...routedCfg,
|
|
26799
26937
|
type: newProvider,
|
|
26800
26938
|
model: newModel
|
|
26801
26939
|
}) : built;
|
|
@@ -26807,7 +26945,7 @@ function buildRoutes(state, deps2, cb) {
|
|
|
26807
26945
|
deps2.configStore.update({ provider: newProvider, model: newModel });
|
|
26808
26946
|
deps2.context.model = newModel;
|
|
26809
26947
|
deps2.context.provider = newProv;
|
|
26810
|
-
await cb.updateAutoCompactionMaxContext(newProv, newProvider,
|
|
26948
|
+
await cb.updateAutoCompactionMaxContext(newProv, newProvider, routedCfg).catch((error2) => {
|
|
26811
26949
|
deps2.logger.warn(`model.switch capability refresh failed: ${String(error2)}`);
|
|
26812
26950
|
});
|
|
26813
26951
|
broadcast(state.getClients(), {
|
|
@@ -26948,6 +27086,13 @@ function buildRoutes(state, deps2, cb) {
|
|
|
26948
27086
|
if (typeof payload["fallbackAuto"] === "boolean")
|
|
26949
27087
|
config.fallbackAuto = payload["fallbackAuto"];
|
|
26950
27088
|
},
|
|
27089
|
+
// WrongProxy / WrongTrace: reflect the standalone toggle/URL into the
|
|
27090
|
+
// shared `ProxyConfig` singleton immediately and await the re-probe so
|
|
27091
|
+
// `active` is fresh before a subsequent model.switch reads it. In the
|
|
27092
|
+
// CLI-hosted path this same key is the CLI's `applyWrongProxyPrefs`; when
|
|
27093
|
+
// running as its own process there is no CLI to inject it, so route it to
|
|
27094
|
+
// the server-local runtime module.
|
|
27095
|
+
applyWrongProxyPrefs: (payload) => applyWrongProxyPrefs(payload),
|
|
26951
27096
|
setAutoCompact: (enabled) => {
|
|
26952
27097
|
deps2.pipelines.contextWindow.remove("AutoCompaction", { optional: true });
|
|
26953
27098
|
if (enabled && deps2.autoCompactor) {
|
|
@@ -27432,7 +27577,12 @@ function setupWebuiCredentialWatcher(options) {
|
|
|
27432
27577
|
...snapshot.apiKey !== void 0 ? { apiKey: snapshot.apiKey } : {},
|
|
27433
27578
|
...snapshot.baseUrl !== void 0 ? { baseUrl: snapshot.baseUrl } : {}
|
|
27434
27579
|
};
|
|
27435
|
-
const
|
|
27580
|
+
const routedCfg = routeProviderCfgThroughProxy(
|
|
27581
|
+
providerCfg,
|
|
27582
|
+
state.getConfig().baseUrl,
|
|
27583
|
+
activeId
|
|
27584
|
+
);
|
|
27585
|
+
const newProv = deps2.providerRegistry.has(activeId) ? deps2.providerRegistry.create({ ...routedCfg, type: activeId }) : makeProviderFromConfig5(activeId, { ...routedCfg, type: activeId });
|
|
27436
27586
|
deps2.context.provider = newProv;
|
|
27437
27587
|
void updateAutoCompactionMaxContext(newProv).catch(() => void 0);
|
|
27438
27588
|
console.log(`[WebUI] Provider credentials reloaded from config.json (${activeId})`);
|
|
@@ -27634,6 +27784,7 @@ async function startWebUI(opts = {}) {
|
|
|
27634
27784
|
console.log("[WebUI] Starting backend services...");
|
|
27635
27785
|
const boot = await bootConfig();
|
|
27636
27786
|
const { config: baseConfig, globalConfigPath, wpaths, logger } = boot;
|
|
27787
|
+
await bootstrapWrongProxyFromConfig(baseConfig);
|
|
27637
27788
|
const vault = opts.services?.vault ?? boot.vault;
|
|
27638
27789
|
let config = baseConfig;
|
|
27639
27790
|
let projectRoot = boot.projectRoot;
|
package/dist/server/entry.js
CHANGED
|
@@ -98,7 +98,12 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
98
98
|
// `prefs.update` exactly so the panel does not error with
|
|
99
99
|
// "unknown preference key".
|
|
100
100
|
"readSymbols",
|
|
101
|
-
"showSageMemoryInject"
|
|
101
|
+
"showSageMemoryInject",
|
|
102
|
+
// WrongProxy / WrongTrace master switch. When on, the CLI rewrites every
|
|
103
|
+
// provider's base URL through the configured proxy URL (default
|
|
104
|
+
// http://localhost:8000 → http://localhost:8000/proxy/<host><path>).
|
|
105
|
+
// Excluded providers (openai-codex) flow through unchanged.
|
|
106
|
+
"wrongProxyEnabled"
|
|
102
107
|
]);
|
|
103
108
|
var STRING_ARRAY_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
104
109
|
"fallbackModels",
|
|
@@ -165,7 +170,11 @@ var STRING_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
165
170
|
"chimeraModel",
|
|
166
171
|
"autoReviewProvider",
|
|
167
172
|
"autoReviewModel",
|
|
168
|
-
"autoReviewFallbackProfile"
|
|
173
|
+
"autoReviewFallbackProfile",
|
|
174
|
+
// WrongProxy / WrongTrace URL. Empty = unset. Default lives in
|
|
175
|
+
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:8000'); users
|
|
176
|
+
// can override here for non-default daemon ports / paths.
|
|
177
|
+
"wrongProxyUrl"
|
|
169
178
|
]);
|
|
170
179
|
var ENUM_PREF_KEYS = {
|
|
171
180
|
autonomy: AUTONOMY_VALUES,
|
|
@@ -1031,7 +1040,7 @@ function routingPatch(payload) {
|
|
|
1031
1040
|
function handlePrefsGet(ctx, ws) {
|
|
1032
1041
|
ctx.send(ws, { type: "prefs.updated", payload: ctx.snapshot() });
|
|
1033
1042
|
}
|
|
1034
|
-
function handlePrefsUpdate(ctx, ws, input) {
|
|
1043
|
+
async function handlePrefsUpdate(ctx, ws, input) {
|
|
1035
1044
|
const parsed = validatePrefsUpdatePayload(input);
|
|
1036
1045
|
if (!parsed.ok) {
|
|
1037
1046
|
sendResult(ctx, ws, false, parsed.message);
|
|
@@ -1064,6 +1073,9 @@ function handlePrefsUpdate(ctx, ws, input) {
|
|
|
1064
1073
|
({ setDebugStreamEnabled }) => setDebugStreamEnabled(payload["debugStream"])
|
|
1065
1074
|
);
|
|
1066
1075
|
}
|
|
1076
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean" || typeof payload["wrongProxyUrl"] === "string") {
|
|
1077
|
+
await ctx.applyWrongProxyPrefs?.(payload);
|
|
1078
|
+
}
|
|
1067
1079
|
if (typeof payload["logLevel"] === "string" && ["debug", "info", "warn", "error"].includes(payload["logLevel"])) {
|
|
1068
1080
|
ctx.setLogLevel?.(payload["logLevel"]);
|
|
1069
1081
|
}
|
|
@@ -7105,6 +7117,8 @@ function seedContextMeta(config, context) {
|
|
|
7105
7117
|
meta["tgDelegate"] = tgExt?.["notifyOnDelegate"] !== false;
|
|
7106
7118
|
const tgMs = tgExt?.["longToolThresholdMs"];
|
|
7107
7119
|
meta["tgLongToolMs"] = typeof tgMs === "number" ? tgMs : 3e4;
|
|
7120
|
+
meta["wrongProxyEnabled"] = config.tools?.wrongProxy?.enabled === true;
|
|
7121
|
+
meta["wrongProxyUrl"] = config.tools?.wrongProxy?.url ?? "";
|
|
7108
7122
|
{
|
|
7109
7123
|
const pluginsEnabled = {};
|
|
7110
7124
|
const record = (name2) => {
|
|
@@ -7471,6 +7485,85 @@ function createCustomModeStore(wrongstackDir) {
|
|
|
7471
7485
|
return { modes, load: load2, save: save2, create, update, remove, list };
|
|
7472
7486
|
}
|
|
7473
7487
|
|
|
7488
|
+
// src/server/proxy-runtime.ts
|
|
7489
|
+
import {
|
|
7490
|
+
applyProxyConfig,
|
|
7491
|
+
getProxyConfig,
|
|
7492
|
+
rewriteBaseUrl,
|
|
7493
|
+
shouldRewriteFor
|
|
7494
|
+
} from "@wrongstack/core/wiring/proxy-rewrite";
|
|
7495
|
+
var HEALTH_PATH = "/api/health";
|
|
7496
|
+
var PROBE_TIMEOUT_MS = 2e3;
|
|
7497
|
+
function seedWrongProxyFromConfig(config) {
|
|
7498
|
+
const wp = config.tools?.wrongProxy;
|
|
7499
|
+
if (!wp) {
|
|
7500
|
+
return;
|
|
7501
|
+
}
|
|
7502
|
+
applyProxyConfig({
|
|
7503
|
+
enabled: wp.enabled === true,
|
|
7504
|
+
url: typeof wp.url === "string" ? wp.url : ""
|
|
7505
|
+
});
|
|
7506
|
+
}
|
|
7507
|
+
async function probeWrongProxyActive() {
|
|
7508
|
+
const cfg = getProxyConfig();
|
|
7509
|
+
if (!cfg.enabled || !cfg.url) {
|
|
7510
|
+
applyProxyConfig({ active: false });
|
|
7511
|
+
return false;
|
|
7512
|
+
}
|
|
7513
|
+
const abort = new AbortController();
|
|
7514
|
+
const timeout = setTimeout(() => abort.abort(), PROBE_TIMEOUT_MS);
|
|
7515
|
+
if (typeof timeout.unref === "function") {
|
|
7516
|
+
timeout.unref();
|
|
7517
|
+
}
|
|
7518
|
+
try {
|
|
7519
|
+
const healthUrl = `${cfg.url.replace(/\/+$/, "")}${HEALTH_PATH}`;
|
|
7520
|
+
const res = await fetch(healthUrl, {
|
|
7521
|
+
method: "GET",
|
|
7522
|
+
signal: abort.signal,
|
|
7523
|
+
headers: { accept: "application/json" }
|
|
7524
|
+
});
|
|
7525
|
+
const ok2 = res.ok && res.status >= 200 && res.status < 300;
|
|
7526
|
+
applyProxyConfig({ active: ok2 });
|
|
7527
|
+
return ok2;
|
|
7528
|
+
} catch {
|
|
7529
|
+
applyProxyConfig({ active: false });
|
|
7530
|
+
return false;
|
|
7531
|
+
} finally {
|
|
7532
|
+
clearTimeout(timeout);
|
|
7533
|
+
}
|
|
7534
|
+
}
|
|
7535
|
+
async function applyWrongProxyPrefs(payload) {
|
|
7536
|
+
const patch = {};
|
|
7537
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean") {
|
|
7538
|
+
patch.enabled = payload["wrongProxyEnabled"];
|
|
7539
|
+
}
|
|
7540
|
+
if (typeof payload["wrongProxyUrl"] === "string") {
|
|
7541
|
+
patch.url = payload["wrongProxyUrl"];
|
|
7542
|
+
}
|
|
7543
|
+
if (Object.keys(patch).length === 0) return;
|
|
7544
|
+
applyProxyConfig(patch);
|
|
7545
|
+
await probeWrongProxyActive();
|
|
7546
|
+
}
|
|
7547
|
+
async function bootstrapWrongProxyFromConfig(config) {
|
|
7548
|
+
seedWrongProxyFromConfig(config);
|
|
7549
|
+
await probeWrongProxyActive();
|
|
7550
|
+
}
|
|
7551
|
+
function routeProviderCfgThroughProxy(cfg, fallbackBaseUrl, providerId) {
|
|
7552
|
+
const raw = cfg;
|
|
7553
|
+
const cfgType = typeof raw.type === "string" ? raw.type : void 0;
|
|
7554
|
+
const cfgBaseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl : void 0;
|
|
7555
|
+
const factoryType = cfgType ?? providerId;
|
|
7556
|
+
const rawBaseUrl = cfgBaseUrl ?? fallbackBaseUrl;
|
|
7557
|
+
if (!rawBaseUrl || !shouldRewriteFor(factoryType)) {
|
|
7558
|
+
return { ...cfg };
|
|
7559
|
+
}
|
|
7560
|
+
const baseUrl = rewriteBaseUrl(rawBaseUrl, getProxyConfig().url);
|
|
7561
|
+
return {
|
|
7562
|
+
...cfg,
|
|
7563
|
+
...baseUrl !== cfgBaseUrl ? { baseUrl } : {}
|
|
7564
|
+
};
|
|
7565
|
+
}
|
|
7566
|
+
|
|
7474
7567
|
// src/server/project-handlers.ts
|
|
7475
7568
|
import * as fs10 from "node:fs/promises";
|
|
7476
7569
|
import * as path11 from "node:path";
|
|
@@ -19402,7 +19495,13 @@ var PREF_KEYS = [
|
|
|
19402
19495
|
// Per-plugin enable/disable map (parity with the embedded server).
|
|
19403
19496
|
"pluginsEnabled",
|
|
19404
19497
|
// Fleet chat verbosity: off | full (migrated from streamFleet boolean).
|
|
19405
|
-
"fleetChatVerbosity"
|
|
19498
|
+
"fleetChatVerbosity",
|
|
19499
|
+
// WrongProxy / WrongTrace: master switch + configurable URL (default
|
|
19500
|
+
// http://localhost:8000). When `wrongProxyEnabled` is true and the daemon
|
|
19501
|
+
// is reachable, every provider's base URL flows through
|
|
19502
|
+
// `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is excluded by spec.
|
|
19503
|
+
"wrongProxyEnabled",
|
|
19504
|
+
"wrongProxyUrl"
|
|
19406
19505
|
];
|
|
19407
19506
|
function prefSnapshot(contextMeta) {
|
|
19408
19507
|
const snapshot = {};
|
|
@@ -19668,6 +19767,15 @@ async function persistPrefsToConfig(deps2, holder, payload) {
|
|
|
19668
19767
|
}
|
|
19669
19768
|
if (typeof payload["debugStream"] === "boolean")
|
|
19670
19769
|
decrypted.debugStream = payload["debugStream"];
|
|
19770
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean" || typeof payload["wrongProxyUrl"] === "string") {
|
|
19771
|
+
const toolsCfg = decrypted.tools ?? {};
|
|
19772
|
+
const wp = toolsCfg["wrongProxy"] ?? {};
|
|
19773
|
+
if (typeof payload["wrongProxyEnabled"] === "boolean")
|
|
19774
|
+
wp["enabled"] = payload["wrongProxyEnabled"];
|
|
19775
|
+
if (typeof payload["wrongProxyUrl"] === "string") wp["url"] = payload["wrongProxyUrl"];
|
|
19776
|
+
toolsCfg["wrongProxy"] = wp;
|
|
19777
|
+
decrypted.tools = toolsCfg;
|
|
19778
|
+
}
|
|
19671
19779
|
if (typeof payload["pluginsEnabled"] === "object" && payload["pluginsEnabled"] !== null) {
|
|
19672
19780
|
const ext = decrypted.extensions ?? {};
|
|
19673
19781
|
const toggled = [];
|
|
@@ -24332,7 +24440,12 @@ function resolveSetupProvider(opts) {
|
|
|
24332
24440
|
baseUrl: config.baseUrl
|
|
24333
24441
|
};
|
|
24334
24442
|
try {
|
|
24335
|
-
const
|
|
24443
|
+
const routedConfig = routeProviderCfgThroughProxy(
|
|
24444
|
+
providerConfig,
|
|
24445
|
+
config.baseUrl,
|
|
24446
|
+
config.provider
|
|
24447
|
+
);
|
|
24448
|
+
const cfgWithType = { ...routedConfig, type: config.provider };
|
|
24336
24449
|
const provider2 = config.features.modelsRegistry && providerRegistry.has(config.provider) ? providerRegistry.create(cfgWithType) : makeProviderFromConfig(config.provider, cfgWithType);
|
|
24337
24450
|
return { provider: provider2, needsSetup: false };
|
|
24338
24451
|
} catch (err) {
|
|
@@ -24345,8 +24458,13 @@ function resolveSetupProvider(opts) {
|
|
|
24345
24458
|
if (firstKey) {
|
|
24346
24459
|
const firstProvider = expectDefined2(savedProviders[firstKey]);
|
|
24347
24460
|
try {
|
|
24461
|
+
const routedConfig = routeProviderCfgThroughProxy(
|
|
24462
|
+
firstProvider,
|
|
24463
|
+
config.baseUrl,
|
|
24464
|
+
firstKey
|
|
24465
|
+
);
|
|
24348
24466
|
const provider2 = makeProviderFromConfig(firstKey, {
|
|
24349
|
-
...
|
|
24467
|
+
...routedConfig,
|
|
24350
24468
|
type: firstKey,
|
|
24351
24469
|
family: firstProvider.family,
|
|
24352
24470
|
apiKey: firstProvider.apiKey
|
|
@@ -24992,9 +25110,14 @@ function buildRoutes(state, deps2, cb) {
|
|
|
24992
25110
|
const cur = state.getConfig();
|
|
24993
25111
|
const newCfg = patchConfig(cur, { provider: newProvider, model: newModel });
|
|
24994
25112
|
const providerCfg = newCfg.providers?.[newProvider] ?? { type: newProvider };
|
|
24995
|
-
const
|
|
25113
|
+
const routedCfg = routeProviderCfgThroughProxy(
|
|
25114
|
+
providerCfg,
|
|
25115
|
+
newCfg.baseUrl,
|
|
25116
|
+
newProvider
|
|
25117
|
+
);
|
|
25118
|
+
const built = deps2.providerRegistry.has(newProvider) ? deps2.providerRegistry.create({ ...routedCfg, type: newProvider }) : makeProviderFromConfig2(newProvider, routedCfg);
|
|
24996
25119
|
const newProv = deps2.modelsRegistry ? await withCatalogCapabilities(deps2.modelsRegistry, newProvider, built, {
|
|
24997
|
-
...
|
|
25120
|
+
...routedCfg,
|
|
24998
25121
|
type: newProvider,
|
|
24999
25122
|
model: newModel
|
|
25000
25123
|
}) : built;
|
|
@@ -25006,7 +25129,7 @@ function buildRoutes(state, deps2, cb) {
|
|
|
25006
25129
|
deps2.configStore.update({ provider: newProvider, model: newModel });
|
|
25007
25130
|
deps2.context.model = newModel;
|
|
25008
25131
|
deps2.context.provider = newProv;
|
|
25009
|
-
await cb.updateAutoCompactionMaxContext(newProv, newProvider,
|
|
25132
|
+
await cb.updateAutoCompactionMaxContext(newProv, newProvider, routedCfg).catch((error2) => {
|
|
25010
25133
|
deps2.logger.warn(`model.switch capability refresh failed: ${String(error2)}`);
|
|
25011
25134
|
});
|
|
25012
25135
|
broadcast(state.getClients(), {
|
|
@@ -25147,6 +25270,13 @@ function buildRoutes(state, deps2, cb) {
|
|
|
25147
25270
|
if (typeof payload["fallbackAuto"] === "boolean")
|
|
25148
25271
|
config.fallbackAuto = payload["fallbackAuto"];
|
|
25149
25272
|
},
|
|
25273
|
+
// WrongProxy / WrongTrace: reflect the standalone toggle/URL into the
|
|
25274
|
+
// shared `ProxyConfig` singleton immediately and await the re-probe so
|
|
25275
|
+
// `active` is fresh before a subsequent model.switch reads it. In the
|
|
25276
|
+
// CLI-hosted path this same key is the CLI's `applyWrongProxyPrefs`; when
|
|
25277
|
+
// running as its own process there is no CLI to inject it, so route it to
|
|
25278
|
+
// the server-local runtime module.
|
|
25279
|
+
applyWrongProxyPrefs: (payload) => applyWrongProxyPrefs(payload),
|
|
25150
25280
|
setAutoCompact: (enabled) => {
|
|
25151
25281
|
deps2.pipelines.contextWindow.remove("AutoCompaction", { optional: true });
|
|
25152
25282
|
if (enabled && deps2.autoCompactor) {
|
|
@@ -25631,7 +25761,12 @@ function setupWebuiCredentialWatcher(options) {
|
|
|
25631
25761
|
...snapshot.apiKey !== void 0 ? { apiKey: snapshot.apiKey } : {},
|
|
25632
25762
|
...snapshot.baseUrl !== void 0 ? { baseUrl: snapshot.baseUrl } : {}
|
|
25633
25763
|
};
|
|
25634
|
-
const
|
|
25764
|
+
const routedCfg = routeProviderCfgThroughProxy(
|
|
25765
|
+
providerCfg,
|
|
25766
|
+
state.getConfig().baseUrl,
|
|
25767
|
+
activeId
|
|
25768
|
+
);
|
|
25769
|
+
const newProv = deps2.providerRegistry.has(activeId) ? deps2.providerRegistry.create({ ...routedCfg, type: activeId }) : makeProviderFromConfig3(activeId, { ...routedCfg, type: activeId });
|
|
25635
25770
|
deps2.context.provider = newProv;
|
|
25636
25771
|
void updateAutoCompactionMaxContext(newProv).catch(() => void 0);
|
|
25637
25772
|
console.log(`[WebUI] Provider credentials reloaded from config.json (${activeId})`);
|
|
@@ -25833,6 +25968,7 @@ async function startWebUI(opts = {}) {
|
|
|
25833
25968
|
console.log("[WebUI] Starting backend services...");
|
|
25834
25969
|
const boot = await bootConfig();
|
|
25835
25970
|
const { config: baseConfig, globalConfigPath, wpaths, logger } = boot;
|
|
25971
|
+
await bootstrapWrongProxyFromConfig(baseConfig);
|
|
25836
25972
|
const vault = opts.services?.vault ?? boot.vault;
|
|
25837
25973
|
let config = baseConfig;
|
|
25838
25974
|
let projectRoot = boot.projectRoot;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { SecretVault } from '@wrongstack/core/types';
|
|
19
19
|
/** Pref keys exposed to the settings panel via prefs.get / prefs.updated. */
|
|
20
|
-
export declare const PREF_KEYS: readonly ['autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations', 'chime', 'confirmExit', 'nextPrediction', 'nextStepsTool', 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage', 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills', 'featureModelsRegistry', 'indexOnStart', 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier', 'maxConcurrent', 'titleAnimation', 'uiLocale', 'logLevel', 'auditLevel', 'hqEnabled', 'hqUrl', 'hqRawContent', 'tgConfigured', 'tgSessionEnd', 'tgDelegate', 'tgLongToolMs', 'reasoningMode', 'reasoningEffort', 'reasoningPreserve', 'cacheTtl', 'fallbackModels', 'fallbackProfiles', 'favoriteModels', 'favoriteModelsOnly', 'modelAvailabilitySchedule', 'modelMatrix', 'fallbackAuto', 'refinerProvider', 'refinerModel', 'refinerFallbackProfile', 'thinkingWord', 'statuslineMode', 'animationStyle', 'showModelReasoning', 'breakerEnabled', 'breakerAutoKillResetMs', 'fsAccess', 'debugStream', 'chimeraEnabled', 'chimeraProvider', 'chimeraModel', 'chimeraMaxFiles', 'chimeraAutoFix', 'autoReviewEnabled', 'autoReviewProvider', 'autoReviewModel', 'autoReviewFallbackProfile', 'autoReviewModelSelection', 'autoReviewFallbackModels', 'autoReviewDebounceMs', 'autoReviewMaxFilesPerBatch', 'autoReviewMaxConcurrentReviews', 'autoReviewCascadeOn', 'groupToolCalls', 'showThinkingLogs', 'autoCollapseInput', 'pluginsEnabled', 'fleetChatVerbosity'];
|
|
20
|
+
export declare const PREF_KEYS: readonly ['autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations', 'chime', 'confirmExit', 'nextPrediction', 'nextStepsTool', 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage', 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills', 'featureModelsRegistry', 'indexOnStart', 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier', 'maxConcurrent', 'titleAnimation', 'uiLocale', 'logLevel', 'auditLevel', 'hqEnabled', 'hqUrl', 'hqRawContent', 'tgConfigured', 'tgSessionEnd', 'tgDelegate', 'tgLongToolMs', 'reasoningMode', 'reasoningEffort', 'reasoningPreserve', 'cacheTtl', 'fallbackModels', 'fallbackProfiles', 'favoriteModels', 'favoriteModelsOnly', 'modelAvailabilitySchedule', 'modelMatrix', 'fallbackAuto', 'refinerProvider', 'refinerModel', 'refinerFallbackProfile', 'thinkingWord', 'statuslineMode', 'animationStyle', 'showModelReasoning', 'breakerEnabled', 'breakerAutoKillResetMs', 'fsAccess', 'debugStream', 'chimeraEnabled', 'chimeraProvider', 'chimeraModel', 'chimeraMaxFiles', 'chimeraAutoFix', 'autoReviewEnabled', 'autoReviewProvider', 'autoReviewModel', 'autoReviewFallbackProfile', 'autoReviewModelSelection', 'autoReviewFallbackModels', 'autoReviewDebounceMs', 'autoReviewMaxFilesPerBatch', 'autoReviewMaxConcurrentReviews', 'autoReviewCascadeOn', 'groupToolCalls', 'showThinkingLogs', 'autoCollapseInput', 'pluginsEnabled', 'fleetChatVerbosity', 'wrongProxyEnabled', 'wrongProxyUrl'];
|
|
21
21
|
export interface PrefHelperDeps {
|
|
22
22
|
/** Path to the active profile config; the sole settings mutation target. */
|
|
23
23
|
profileConfigPath: string;
|
|
@@ -13,10 +13,20 @@ export interface PrefsHandlerContext {
|
|
|
13
13
|
applyConfigPrefs?: ((payload: Record<string, unknown>) => void) | undefined;
|
|
14
14
|
setAutoCompact?: ((enabled: boolean) => void) | undefined;
|
|
15
15
|
setLogLevel?: ((level: 'debug' | 'info' | 'warn' | 'error') => void) | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* WrongProxy / WrongTrace: applies the toggle + URL to the runtime
|
|
18
|
+
* config and kicks the periodic probe. Injected by the CLI's
|
|
19
|
+
* `createPrefsSeeding` so the WS server stays package-agnostic — the
|
|
20
|
+
* server doesn't pull `@wrongstack/cli`'s import graph or its
|
|
21
|
+
* `setInterval`-owning probe module. May return a promise so the
|
|
22
|
+
* standalone server's re-probe can be awaited before the next
|
|
23
|
+
* prefs-dependent request (e.g. an immediate model.switch).
|
|
24
|
+
*/
|
|
25
|
+
applyWrongProxyPrefs?: ((payload: Record<string, unknown>) => void | Promise<void>) | undefined;
|
|
16
26
|
send: (ws: WebSocket, message: WSServerMessage) => void;
|
|
17
27
|
broadcast: (message: WSServerMessage) => void;
|
|
18
28
|
}
|
|
19
29
|
export declare function handlePrefsGet(ctx: PrefsHandlerContext, ws: WebSocket): void;
|
|
20
|
-
export declare function handlePrefsUpdate(ctx: PrefsHandlerContext, ws: WebSocket, input: Record<string, unknown>): void
|
|
30
|
+
export declare function handlePrefsUpdate(ctx: PrefsHandlerContext, ws: WebSocket, input: Record<string, unknown>): Promise<void>;
|
|
21
31
|
export declare function handleAutonomySwitch(ctx: PrefsHandlerContext, ws: WebSocket, mode: string): void;
|
|
22
32
|
//# sourceMappingURL=prefs-handlers.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WrongProxy / WrongTrace runtime seeding for the standalone WebUI server.
|
|
3
|
+
*
|
|
4
|
+
* The CLI hosts WebUI in-process via `dispatch-webui.ts`, which injects
|
|
5
|
+
* `applyWrongProxyPrefs` (from `@wrongstack/cli/wiring/proxy-wiring`) into
|
|
6
|
+
* the WS prefs handler and shares the CLI's proxy singleton. But when the
|
|
7
|
+
* WebUI server runs as its OWN process (`startWebUI`), no CLI is present to
|
|
8
|
+
* seed the `ProxyConfig` singleton in `@wrongstack/core/wiring/proxy-rewrite`
|
|
9
|
+
* — so all of the server's provider-build paths would construct providers
|
|
10
|
+
* with the raw base URL and never traverse the proxy.
|
|
11
|
+
*
|
|
12
|
+
* webui ⇏ cli, so this module cannot import `@wrongstack/cli`'s probe. It
|
|
13
|
+
* owns the same two concerns the CLI's `proxy-wiring` does, but dependency-
|
|
14
|
+
* light and self-contained:
|
|
15
|
+
*
|
|
16
|
+
* 1. Seeding the shared `ProxyConfig` singleton (`enabled` / `url`) from
|
|
17
|
+
* `config.tools.wrongProxy` at boot.
|
|
18
|
+
* 2. A one-shot `/api/health` reachability probe that flips `active` to
|
|
19
|
+
* true so `shouldRewriteFor()` returns true for subsequent provider
|
|
20
|
+
* builds. Unlike the CLI's periodic probe this runs once at seed time
|
|
21
|
+
* (the standalone server re-probes when the operator toggles the field
|
|
22
|
+
* via `applyWrongProxyPrefs`); a long-lived daemon is assumed stable.
|
|
23
|
+
*
|
|
24
|
+
* The rewrite itself (`shouldRewriteFor` / `rewriteBaseUrl`) is pure logic
|
|
25
|
+
* in `@wrongstack/core` and is applied at each provider-build site in this
|
|
26
|
+
* server (setup-screen, routes applyModelSwitchCore, embedded-message-router,
|
|
27
|
+
* embedded-host-adapters, start-webui-credential-watcher).
|
|
28
|
+
*/
|
|
29
|
+
import type { Config } from '@wrongstack/core/types';
|
|
30
|
+
/**
|
|
31
|
+
* Seed the shared `ProxyConfig` singleton from the persisted
|
|
32
|
+
* `config.tools.wrongProxy.{enabled,url}` block. Idempotent — safe to call
|
|
33
|
+
* at every boot. A provider that is eligible and reachable with a
|
|
34
|
+
* configured URL will then have its base URL rewritten through the proxy.
|
|
35
|
+
*/
|
|
36
|
+
export declare function seedWrongProxyFromConfig(config: Config): void;
|
|
37
|
+
/**
|
|
38
|
+
* Probe the configured proxy daemon once and flip `active` to true when it
|
|
39
|
+
* answers a 2xx on `/api/health`. Mirrors the CLI's probe contract but
|
|
40
|
+
* without owning a `setInterval` loop. Resolves with the new `active` value.
|
|
41
|
+
* A non-2xx / timeout / ECONNREFUSED leaves `active` false so the rewriter
|
|
42
|
+
* keeps base URLs unchanged.
|
|
43
|
+
*/
|
|
44
|
+
export declare function probeWrongProxyActive(): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Apply the `wrongProxyEnabled` + `wrongProxyUrl` portion of a WS prefs
|
|
47
|
+
* payload, then re-probe so the rewrite reflects the new state immediately
|
|
48
|
+
* (the next provider build reads the freshly-probed `active`). Skips when the
|
|
49
|
+
* payload carries neither key. Mirrors the CLI's `applyWrongProxyPrefs`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function applyWrongProxyPrefs(payload: Record<string, unknown>): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Seed the singleton from the persisted config and await the first probe so
|
|
54
|
+
* `active` is correct BEFORE the server's provider is constructed. Without
|
|
55
|
+
* the await, `setup-screen`'s `resolveSetupProvider` reads the singleton
|
|
56
|
+
* (synchronously) while `active` is still false and bakes the raw base URL
|
|
57
|
+
* into the initial provider. Mirrors the CLI's
|
|
58
|
+
* `bootstrapWrongProxy` + `awaitFirstWrongProxyProbe` pair.
|
|
59
|
+
*/
|
|
60
|
+
export declare function bootstrapWrongProxyFromConfig(config: Config): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Apply the WrongProxy / WrongTrace base-URL rewrite to ONE provider config
|
|
63
|
+
* before it is handed to a provider factory. This is the single shared seam
|
|
64
|
+
* for every WebUI-server provider-build path so the eligibility + compose
|
|
65
|
+
* rules cannot drift between call sites:
|
|
66
|
+
*
|
|
67
|
+
* - `routes.ts` `applyModelSwitchCore` (model.switch rebuild)
|
|
68
|
+
* - `setup-screen.ts` `resolveSetupProvider` (boot branches 1 + 2)
|
|
69
|
+
* - `embedded-message-router.ts` `buildProvider`
|
|
70
|
+
* - `embedded-host-adapters.ts` `applyEmbeddedModelSwitch`
|
|
71
|
+
* - `start-webui-credential-watcher.ts` (credential hot-reload)
|
|
72
|
+
*
|
|
73
|
+
* Returns a copy of `cfg` with `baseUrl` overridden to
|
|
74
|
+
* `${proxyUrl}/proxy/<host><path>` when the toggle is on, the daemon is
|
|
75
|
+
* reachable (`active`) and the provider is eligible (openai-codex excluded
|
|
76
|
+
* by the rewriter). `fallbackBaseUrl` is used when `cfg` carries no explicit
|
|
77
|
+
* baseUrl (the call site's top-level config baseUrl). When the proxy is off
|
|
78
|
+
* or unreachable, the cfg is returned unchanged so factory construction
|
|
79
|
+
* behaves exactly as before the proxy feature existed.
|
|
80
|
+
*/
|
|
81
|
+
export declare function routeProviderCfgThroughProxy<T extends object>(cfg: Readonly<T>, fallbackBaseUrl: string | undefined, providerId: string): T;
|
|
82
|
+
//# sourceMappingURL=proxy-runtime.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/webui-server",
|
|
3
|
-
"version": "0.310.
|
|
3
|
+
"version": "0.310.1",
|
|
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": [
|
|
@@ -36,18 +36,18 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"ws": "^8.21.3",
|
|
39
|
-
"@wrongstack/
|
|
40
|
-
"@wrongstack/
|
|
41
|
-
"@wrongstack/
|
|
42
|
-
"@wrongstack/
|
|
43
|
-
"@wrongstack/
|
|
44
|
-
"@wrongstack/
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/vector-memory": "0.310.
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/webui-protocol": "0.310.
|
|
39
|
+
"@wrongstack/core": "0.310.1",
|
|
40
|
+
"@wrongstack/kanban": "0.310.1",
|
|
41
|
+
"@wrongstack/mcp": "0.310.1",
|
|
42
|
+
"@wrongstack/sage": "0.310.1",
|
|
43
|
+
"@wrongstack/runtime": "0.310.1",
|
|
44
|
+
"@wrongstack/providers": "0.310.1",
|
|
45
|
+
"@wrongstack/sdd": "0.310.1",
|
|
46
|
+
"@wrongstack/tools": "0.310.1",
|
|
47
|
+
"@wrongstack/requirement-intake": "0.310.1",
|
|
48
|
+
"@wrongstack/vector-memory": "0.310.1",
|
|
49
|
+
"@wrongstack/techstack": "0.310.1",
|
|
50
|
+
"@wrongstack/webui-protocol": "0.310.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "^26.2.0",
|