@tritard/waterbrother 0.16.7 → 0.16.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/cli.js +99 -21
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ It is Vercel-ready via `vercel.json` (clean URLs, no build step required).
|
|
|
29
29
|
- First-run onboarding wizard in terminal
|
|
30
30
|
- asks for provider first
|
|
31
31
|
- asks for API key when the selected provider requires one
|
|
32
|
+
- tries a live provider model list after credentials, shows when that live list is in use, then falls back to the built-in catalog
|
|
32
33
|
- prompts for default model and agent profile
|
|
33
34
|
- Multi-provider chat integration through provider adapters and model registry
|
|
34
35
|
- Vision command for local images: `waterbrother vision <image-path> <prompt>`
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -2830,34 +2830,103 @@ async function chooseProviderInteractive(defaultProvider = 'xai') {
|
|
|
2830
2830
|
return selected?.value || defaultProvider;
|
|
2831
2831
|
}
|
|
2832
2832
|
|
|
2833
|
-
async function
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2833
|
+
async function buildModelPickerOptions(defaultModel, provider = '', { apiKey = '', baseUrl = '', allowRemote = true } = {}) {
|
|
2834
|
+
const normalizedProvider = normalizeProvider(provider);
|
|
2835
|
+
let remoteModels = [];
|
|
2836
|
+
if (allowRemote && normalizedProvider) {
|
|
2837
|
+
try {
|
|
2838
|
+
remoteModels = await listModels({
|
|
2839
|
+
provider: normalizedProvider,
|
|
2840
|
+
apiKey,
|
|
2841
|
+
baseUrl
|
|
2842
|
+
});
|
|
2843
|
+
} catch {
|
|
2844
|
+
remoteModels = [];
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
const seen = new Set();
|
|
2849
|
+
const options = [];
|
|
2850
|
+
|
|
2851
|
+
for (const model of remoteModels) {
|
|
2852
|
+
const value = String(model?.id || "").trim();
|
|
2853
|
+
if (!value || seen.has(value)) continue;
|
|
2854
|
+
seen.add(value);
|
|
2855
|
+
options.push({
|
|
2856
|
+
value,
|
|
2857
|
+
label: model?.notes ? `${value} - ${model.notes}` : value
|
|
2858
|
+
});
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
for (const model of MODEL_CATALOG) {
|
|
2862
|
+
if (normalizedProvider && model.provider !== normalizedProvider) continue;
|
|
2863
|
+
const value = String(model?.id || "").trim();
|
|
2864
|
+
if (!value || seen.has(value)) continue;
|
|
2865
|
+
seen.add(value);
|
|
2866
|
+
options.push({
|
|
2867
|
+
value,
|
|
2868
|
+
label: model?.notes ? `${value} - ${model.notes}` : value
|
|
2869
|
+
});
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2872
|
+
if (!options.length) {
|
|
2873
|
+
options.push({
|
|
2874
|
+
value: defaultModel,
|
|
2875
|
+
label: `${defaultModel} (default)`
|
|
2876
|
+
});
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
const defaultIndex = Math.max(0, options.findIndex((model) => model.value === defaultModel));
|
|
2880
|
+
const titledOptions = options.map((model, index) => ({
|
|
2881
|
+
value: model.value,
|
|
2882
|
+
label: `${model.label}${index === defaultIndex ? " (default)" : ""}`
|
|
2839
2883
|
}));
|
|
2884
|
+
|
|
2885
|
+
return {
|
|
2886
|
+
normalizedProvider,
|
|
2887
|
+
options: titledOptions,
|
|
2888
|
+
defaultIndex,
|
|
2889
|
+
usedRemote: remoteModels.length > 0
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
async function chooseModelInteractive(defaultModel, provider = '', { apiKey = '', baseUrl = '', allowRemote = true } = {}) {
|
|
2894
|
+
const picker = await buildModelPickerOptions(defaultModel, provider, { apiKey, baseUrl, allowRemote });
|
|
2895
|
+
if (picker.usedRemote) {
|
|
2896
|
+
console.log(dim(`Using live ${picker.normalizedProvider} model list.`));
|
|
2897
|
+
} else if (picker.normalizedProvider) {
|
|
2898
|
+
console.log(dim(`Live ${picker.normalizedProvider} model list unavailable. Falling back to the built-in catalog.`));
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2840
2901
|
const selected = await chooseFromInteractiveMenu({
|
|
2841
|
-
title:
|
|
2842
|
-
|
|
2843
|
-
|
|
2902
|
+
title: picker.usedRemote
|
|
2903
|
+
? `Select default model for ${picker.normalizedProvider} (live list):`
|
|
2904
|
+
: picker.normalizedProvider
|
|
2905
|
+
? `Select default model for ${picker.normalizedProvider}:`
|
|
2906
|
+
: "Select default model:",
|
|
2907
|
+
options: picker.options,
|
|
2908
|
+
defaultIndex: picker.defaultIndex
|
|
2844
2909
|
});
|
|
2845
2910
|
return selected?.value || defaultModel;
|
|
2846
2911
|
}
|
|
2847
2912
|
|
|
2848
|
-
async function chooseRuntimeModelInteractive(currentModel, provider = '') {
|
|
2849
|
-
const
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2913
|
+
async function chooseRuntimeModelInteractive(currentModel, provider = '', { apiKey = '', baseUrl = '', allowRemote = true } = {}) {
|
|
2914
|
+
const picker = await buildModelPickerOptions(currentModel, provider, { apiKey, baseUrl, allowRemote });
|
|
2915
|
+
if (!picker.options.length) return currentModel;
|
|
2916
|
+
const options = picker.options.map((model, index) => ({
|
|
2917
|
+
value: model.value,
|
|
2918
|
+
label: model.value === currentModel || index === picker.defaultIndex
|
|
2919
|
+
? model.label.replace(/ \(default\)$/, "") + " (current)"
|
|
2920
|
+
: model.label.replace(/ \(default\)$/, "")
|
|
2856
2921
|
}));
|
|
2857
2922
|
const selected = await chooseFromInteractiveMenu({
|
|
2858
|
-
title:
|
|
2923
|
+
title: picker.usedRemote
|
|
2924
|
+
? `Select ${picker.normalizedProvider} model (live list):`
|
|
2925
|
+
: picker.normalizedProvider
|
|
2926
|
+
? `Select ${picker.normalizedProvider} model:`
|
|
2927
|
+
: 'Select model:',
|
|
2859
2928
|
options,
|
|
2860
|
-
defaultIndex
|
|
2929
|
+
defaultIndex: picker.defaultIndex
|
|
2861
2930
|
});
|
|
2862
2931
|
return selected?.value || currentModel;
|
|
2863
2932
|
}
|
|
@@ -2927,7 +2996,11 @@ async function runOnboardingWizard(config, { cwd }) {
|
|
|
2927
2996
|
}
|
|
2928
2997
|
|
|
2929
2998
|
next.baseUrl = providerSpec?.defaultBaseUrl || next.baseUrl || '';
|
|
2930
|
-
next.model = await chooseModelInteractive(next.model || getDefaultModelForProvider(next.provider), next.provider
|
|
2999
|
+
next.model = await chooseModelInteractive(next.model || getDefaultModelForProvider(next.provider), next.provider, {
|
|
3000
|
+
apiKey: next.apiKey,
|
|
3001
|
+
baseUrl: next.baseUrl,
|
|
3002
|
+
allowRemote: providerSpec?.supportsRemoteModelList !== false
|
|
3003
|
+
});
|
|
2931
3004
|
next.agentProfile = await chooseAgentProfileInteractive(next.agentProfile || 'coder');
|
|
2932
3005
|
if (!next.approvalMode) next.approvalMode = 'on-request';
|
|
2933
3006
|
if (!next.designModel) next.designModel = getDefaultDesignModelForProvider(next.provider);
|
|
@@ -8243,7 +8316,12 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
|
|
|
8243
8316
|
|
|
8244
8317
|
if (line === "/models") {
|
|
8245
8318
|
try {
|
|
8246
|
-
const
|
|
8319
|
+
const providerSpec = getProviderSpec(context.runtime.provider);
|
|
8320
|
+
const selectedModel = await chooseRuntimeModelInteractive(agent.getModel(), context.runtime.provider, {
|
|
8321
|
+
apiKey: context.runtime.apiKey,
|
|
8322
|
+
baseUrl: context.runtime.baseUrl,
|
|
8323
|
+
allowRemote: providerSpec?.supportsRemoteModelList !== false
|
|
8324
|
+
});
|
|
8247
8325
|
const { config } = await loadConfigLayers(context.cwd);
|
|
8248
8326
|
const nextRuntime = await applyRuntimeSelection({
|
|
8249
8327
|
config,
|