Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 77 additions & 3 deletions app/L0/_all/mod/_core/admin/views/agent/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,80 @@ export const ADMIN_CHAT_HISTORY_PATH = "~/hist/admin-chat.json";
export const DEFAULT_ADMIN_CHAT_MAX_TOKENS = 120_000;
export const ADMIN_CHAT_LLM_PROVIDER = {
API: "api",
BEDROCK: "bedrock",
LOCAL: "local"
};

export const ADMIN_CHAT_BEDROCK_CRED_MODE = {
SERVER: "server",
CLIENT_KEY: "client-key"
};

export const ADMIN_CHAT_BEDROCK_ROUTE = {
CONVERSE: "converse",
OPENAI: "openai"
};

export const BEDROCK_MODEL_PRESETS = [
{
id: "us.anthropic.claude-sonnet-4-6",
label: "Claude Sonnet 4.6 (fast, recommended)",
route: "converse"
},
{
id: "us.anthropic.claude-opus-4-7",
label: "Claude Opus 4.7 (smartest)",
route: "converse"
},
{
id: "us.anthropic.claude-opus-4-6-v1",
label: "Claude Opus 4.6",
route: "converse"
},
{
id: "us.anthropic.claude-haiku-4-5-20251001-v1:0",
label: "Claude Haiku 4.5 (cheap)",
route: "converse"
},
{
id: "openai.gpt-oss-20b-1:0",
label: "OpenAI gpt-oss 20B",
route: "openai"
},
{
id: "openai.gpt-oss-120b-1:0",
label: "OpenAI gpt-oss 120B",
route: "openai"
}
];

export function bedrockRouteForModel(modelId = "") {
const normalized = String(modelId || "").trim().toLowerCase();
if (!normalized) {
return ADMIN_CHAT_BEDROCK_ROUTE.CONVERSE;
}
if (normalized.startsWith("openai.")) {
return ADMIN_CHAT_BEDROCK_ROUTE.OPENAI;
}
return ADMIN_CHAT_BEDROCK_ROUTE.CONVERSE;
}

export function bedrockApiEndpointForRoute(route = ADMIN_CHAT_BEDROCK_ROUTE.CONVERSE) {
return route === ADMIN_CHAT_BEDROCK_ROUTE.OPENAI
? "/api/bedrock/openai/v1/chat/completions"
: "/api/bedrock/converse/v1/chat/completions";
}

export const ADMIN_CHAT_LOCAL_PROVIDER = {
HUGGINGFACE: "huggingface"
};

export const DEFAULT_ADMIN_CHAT_SETTINGS = {
apiEndpoint: "https://openrouter.ai/api/v1/chat/completions",
apiKey: "",
bedrockApiKey: "",
bedrockCredMode: ADMIN_CHAT_BEDROCK_CRED_MODE.SERVER,
bedrockModel: BEDROCK_MODEL_PRESETS[0].id,
huggingfaceDtype: "q4",
huggingfaceModel: "",
localProvider: ADMIN_CHAT_LOCAL_PROVIDER.HUGGINGFACE,
Expand All @@ -26,9 +90,19 @@ export const DEFAULT_ADMIN_CHAT_SETTINGS = {
};

export function normalizeAdminChatLlmProvider(value) {
return value === ADMIN_CHAT_LLM_PROVIDER.LOCAL
? ADMIN_CHAT_LLM_PROVIDER.LOCAL
: ADMIN_CHAT_LLM_PROVIDER.API;
if (value === ADMIN_CHAT_LLM_PROVIDER.LOCAL) {
return ADMIN_CHAT_LLM_PROVIDER.LOCAL;
}
if (value === ADMIN_CHAT_LLM_PROVIDER.BEDROCK) {
return ADMIN_CHAT_LLM_PROVIDER.BEDROCK;
}
return ADMIN_CHAT_LLM_PROVIDER.API;
}

export function normalizeAdminChatBedrockCredMode(value) {
return value === ADMIN_CHAT_BEDROCK_CRED_MODE.CLIENT_KEY
? ADMIN_CHAT_BEDROCK_CRED_MODE.CLIENT_KEY
: ADMIN_CHAT_BEDROCK_CRED_MODE.SERVER;
}

export function normalizeAdminChatLocalProvider(value) {
Expand Down
38 changes: 1 addition & 37 deletions app/L0/_all/mod/_core/admin/views/agent/panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,43 +179,7 @@ <h2>Custom system instructions</h2>
<h2>Provider and model configuration</h2>
</div>
</header>
<div class="dialog-segmented-control admin-agent-provider-switch" role="tablist" aria-label="LLM provider">
<button
type="button"
class="secondary-button dialog-segmented-button"
:class="{ 'is-active': $store.adminAgent.isSettingsDraftUsingApiProvider }"
@click="$store.adminAgent.setSettingsProvider('api')"
>
<span>API</span>
</button>
<button
type="button"
class="secondary-button dialog-segmented-button"
:class="{ 'is-active': $store.adminAgent.isSettingsDraftUsingLocalProvider }"
@click="$store.adminAgent.setSettingsProvider('local')"
>
<span>Local</span>
</button>
</div>
<div x-show="$store.adminAgent.isSettingsDraftUsingApiProvider" x-cloak>
<label class="field">
<span>Provider API Endpoint URL</span>
<input type="url" x-model="$store.adminAgent.settingsDraft.apiEndpoint" />
</label>
<label class="field">
<span>Model Name</span>
<input type="text" x-model="$store.adminAgent.settingsDraft.model" />
</label>
<label class="field">
<span>API Key</span>
<input type="password" x-model="$store.adminAgent.settingsDraft.apiKey" />
</label>
</div>
<div x-show="$store.adminAgent.isSettingsDraftUsingLocalProvider" x-cloak class="admin-agent-local-settings">
<div class="admin-agent-local-provider-panel">
<x-component path="/mod/_core/huggingface/config-sidebar.html" mode="admin"></x-component>
</div>
</div>
<x-component path="/mod/_core/llm_settings/panel.html" mode="admin"></x-component>
<label class="field">
<span>Max Tokens</span>
<input type="number" min="1" step="1" inputmode="numeric" x-model="$store.adminAgent.settingsDraft.maxTokens" />
Expand Down
16 changes: 14 additions & 2 deletions app/L0/_all/mod/_core/admin/views/agent/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,13 @@ export async function loadAdminChatConfig() {
const runtime = getRuntime();

try {
const result = await runtime.api.fileRead(config.ADMIN_CHAT_CONFIG_PATH);
const result = await runtime.api.fileRead({
path: config.ADMIN_CHAT_CONFIG_PATH,
allowMissing: true
});
if (result && result.exists === false) {
return createDefaultConfig();
}
return normalizeStoredConfig(runtime, runtime.utils.yaml.parse(String(result?.content || "")));
} catch (error) {
if (isMissingFileError(error)) {
Expand Down Expand Up @@ -230,7 +236,13 @@ export async function loadAdminChatHistory() {
const runtime = getRuntime();

try {
const result = await runtime.api.fileRead(config.ADMIN_CHAT_HISTORY_PATH);
const result = await runtime.api.fileRead({
path: config.ADMIN_CHAT_HISTORY_PATH,
allowMissing: true
});
if (result && result.exists === false) {
return [];
}
const parsed = JSON.parse(String(result?.content || "[]"));
return Array.isArray(parsed) ? parsed : [];
} catch (error) {
Expand Down
98 changes: 95 additions & 3 deletions app/L0/_all/mod/_core/admin/views/agent/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,22 @@ const model = {
return config.normalizeAdminChatLlmProvider(this.settingsDraft.provider) === config.ADMIN_CHAT_LLM_PROVIDER.API;
},

get isSettingsDraftUsingBedrockProvider() {
return config.normalizeAdminChatLlmProvider(this.settingsDraft.provider) === config.ADMIN_CHAT_LLM_PROVIDER.BEDROCK;
},

get isSettingsDraftUsingBedrockClientKey() {
return config.normalizeAdminChatBedrockCredMode(this.settingsDraft.bedrockCredMode) === config.ADMIN_CHAT_BEDROCK_CRED_MODE.CLIENT_KEY;
},

get bedrockModelPresets() {
return config.BEDROCK_MODEL_PRESETS;
},

get bedrockServerConfig() {
return this.bedrockServerConfigState || null;
},

get isSettingsDraftUsingLocalProvider() {
return config.normalizeAdminChatLlmProvider(this.settingsDraft.provider) === config.ADMIN_CHAT_LLM_PROVIDER.LOCAL;
},
Expand Down Expand Up @@ -1635,6 +1651,11 @@ const model = {
openSettingsDialog() {
this.settingsDraft = {
...this.settings,
bedrockApiKey: this.settings.bedrockApiKey || "",
bedrockCredMode:
this.settings.bedrockCredMode || config.DEFAULT_ADMIN_CHAT_SETTINGS.bedrockCredMode,
bedrockModel:
this.settings.bedrockModel || config.DEFAULT_ADMIN_CHAT_SETTINGS.bedrockModel,
promptBudgetRatios: clonePromptBudgetRatios(this.settings.promptBudgetRatios)
};
this.syncHuggingFaceFromManager();
Expand All @@ -1648,9 +1669,52 @@ const model = {
.catch((error) => {
this.reportError("warming the local-provider settings draft", error);
});

void this.loadBedrockServerConfig().catch((error) => {
this.reportError("loading Bedrock server config", error);
});

openDialog(this.refs.settingsDialog);
},

async loadBedrockServerConfig() {
try {
const response = await fetch("/api/bedrock/config", {
credentials: "same-origin"
});
if (!response.ok) {
this.bedrockServerConfigState = { error: `HTTP ${response.status}` };
return;
}
const body = await response.json();
this.bedrockServerConfigState = {
error: null,
hasApiKey: Boolean(body.hasApiKey),
mode: body.mode || "unknown",
profile: body.profile || "",
region: body.region || ""
};
} catch (error) {
this.bedrockServerConfigState = {
error: error instanceof Error ? error.message : String(error)
};
}
},

setSettingsBedrockCredMode(mode) {
this.settingsDraft = {
...this.settingsDraft,
bedrockCredMode: config.normalizeAdminChatBedrockCredMode(mode)
};
},

setSettingsBedrockModel(modelId) {
this.settingsDraft = {
...this.settingsDraft,
bedrockModel: String(modelId || "").trim()
};
},

closeSettingsDialog() {
closeDialog(this.refs.settingsDialog);
},
Expand Down Expand Up @@ -1856,6 +1920,12 @@ const model = {
const localProvider = config.normalizeAdminChatLocalProvider(this.settingsDraft.localProvider);
const paramsText = typeof this.settingsDraft.paramsText === "string" ? this.settingsDraft.paramsText.trim() : "";
let maxTokens = config.DEFAULT_ADMIN_CHAT_SETTINGS.maxTokens;
let effectiveApiEndpoint = (this.settingsDraft.apiEndpoint || "").trim();
let effectiveApiKey = (this.settingsDraft.apiKey || "").trim();
let effectiveModel = (this.settingsDraft.model || "").trim();
const effectiveBedrockCredMode = config.normalizeAdminChatBedrockCredMode(this.settingsDraft.bedrockCredMode);
const effectiveBedrockApiKey = (this.settingsDraft.bedrockApiKey || "").trim();
const effectiveBedrockModel = (this.settingsDraft.bedrockModel || config.DEFAULT_ADMIN_CHAT_SETTINGS.bedrockModel || "").trim();

try {
maxTokens = config.parseAdminChatMaxTokens(this.settingsDraft.maxTokens);
Expand All @@ -1869,19 +1939,41 @@ const model = {
throw new Error("Choose a Hugging Face model and dtype before saving.");
}
}

if (provider === config.ADMIN_CHAT_LLM_PROVIDER.BEDROCK) {
if (!effectiveBedrockModel) {
throw new Error("Pick a Bedrock model before saving.");
}
if (
effectiveBedrockCredMode === config.ADMIN_CHAT_BEDROCK_CRED_MODE.CLIENT_KEY &&
!effectiveBedrockApiKey
) {
throw new Error("Paste a Bedrock API key, or switch to the server-side credential mode.");
}
const route = config.bedrockRouteForModel(effectiveBedrockModel);
effectiveApiEndpoint = config.bedrockApiEndpointForRoute(route);
effectiveApiKey =
effectiveBedrockCredMode === config.ADMIN_CHAT_BEDROCK_CRED_MODE.CLIENT_KEY
? effectiveBedrockApiKey
: "local";
effectiveModel = effectiveBedrockModel;
}
} catch (error) {
this.reportError("validating admin chat settings", error);
return;
}

this.settings = {
apiEndpoint: (this.settingsDraft.apiEndpoint || "").trim(),
apiKey: (this.settingsDraft.apiKey || "").trim(),
apiEndpoint: effectiveApiEndpoint,
apiKey: effectiveApiKey,
bedrockApiKey: effectiveBedrockApiKey,
bedrockCredMode: effectiveBedrockCredMode,
bedrockModel: effectiveBedrockModel,
huggingfaceDtype: (this.settingsDraft.huggingfaceDtype || "").trim(),
huggingfaceModel: normalizeHuggingFaceModelInput(this.settingsDraft.huggingfaceModel || ""),
localProvider,
maxTokens,
model: (this.settingsDraft.model || "").trim(),
model: effectiveModel,
paramsText,
promptBudgetRatios: clonePromptBudgetRatios(this.settingsDraft.promptBudgetRatios),
provider,
Expand Down
5 changes: 4 additions & 1 deletion app/L0/_all/mod/_core/dashboard_welcome/dashboard-prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ export async function loadDashboardPrefs() {
const runtime = getRuntime();

try {
const result = await runtime.api.fileRead(DASHBOARD_CONFIG_PATH);
const result = await runtime.api.fileRead({ path: DASHBOARD_CONFIG_PATH, allowMissing: true });
if (result && result.exists === false) {
return normalizeDashboardPrefs({});
}
return normalizeDashboardPrefs(runtime.utils.yaml.parse(String(result?.content || "")));
} catch (error) {
if (isMissingFileError(error)) {
Expand Down
Loading