Skip to content
Closed
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
4 changes: 2 additions & 2 deletions crates/aish-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ pub mod model;

pub use loader::ConfigLoader;
pub use model::{
compile_remote_danger_patterns, ConfigModel, InlineCompletionConfig, MemoryConfig,
OutputOffloadConfig, RegistrySource, SkillsConfig, ToolArgPreviewConfig,
compile_remote_danger_patterns, ApiAccountConfig, ConfigModel, InlineCompletionConfig,
MemoryConfig, OutputOffloadConfig, RegistrySource, SkillsConfig, ToolArgPreviewConfig,
};
46 changes: 46 additions & 0 deletions crates/aish-config/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,23 @@ pub struct ConfigModel {
/// Skill marketplace: auto-search + registry sources.
#[serde(default)]
pub skills: SkillsConfig,
/// Additional API accounts for multi-key quota rotation under the same
/// provider. The top-level `api_key` is always the primary (account #0);
/// entries here are tried in order when the primary hits a rate/usage limit.
#[serde(default)]
pub api_accounts: Vec<ApiAccountConfig>,
/// Ordered fallback model names tried when the primary model fails
/// (rate-limit / usage-limit / exhausted 5xx). Each runs with the active account.
#[serde(default)]
pub fallback_models: Vec<String>,
/// Models the user has switched to via /model, most-recent-first. Surfaced
/// at the top of the picker so switching back is one keystroke.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub recent_models: Vec<String>,
/// Restore the primary model after its cooldown window expires following
/// a fallback. Default: true.
#[serde(default = "default_true")]
pub fallback_revert_on_cooldown: bool,
}

impl Default for ConfigModel {
Expand Down Expand Up @@ -553,10 +570,39 @@ impl Default for ConfigModel {
inline_completion: InlineCompletionConfig::default(),
pty_daemon_enabled: default_true(),
skills: SkillsConfig::default(),
api_accounts: vec![],
fallback_models: vec![],
recent_models: vec![],
fallback_revert_on_cooldown: default_true(),
}
}
}

/// One additional API credential for multi-key quota rotation.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ApiAccountConfig {
/// Human-readable label shown in the rotation UI.
pub name: String,
pub api_key: String,
/// Optional override of the provider base URL for this account.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub api_base: Option<String>,
/// Optional per-account model override. When set, this account uses its
/// own model regardless of the global `model` / fallback chain.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
/// Relative selection weight (advisory; higher = preferred).
#[serde(default = "default_one")]
pub weight: u32,
/// Skip this account entirely when true.
#[serde(default)]
pub disabled: bool,
}

fn default_one() -> u32 {
1
}

/// Compile the `remote_danger_patterns` into `Regex` objects, logging each
/// invalid pattern at warn level and skipping it. Patterns come from config
/// and don't change during a session, so callers should compile once and
Expand Down
230 changes: 230 additions & 0 deletions crates/aish-i18n/locales/de-DE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,195 @@ shell:
audit: "Audit-Protokoll abfragen (wer/wann/was/KI-Vorschlag/Bestaetigung)"
forget-approvals: "Gemerkte Befehlsgenehmigungen löschen (diese Sitzung)"
skill: "Skills suchen, installieren, prüfen; Registries verwalten"
accounts: "Multi-Key-Rotationskonten verwalten"
fallback: "Die Modell-Fallback-Kette verwalten"
fork: "Aktuelle Sitzung abzweigen"
sessions: "Sitzungsbaum anzeigen"
export: "Aktuelle Sitzung als Markdown exportieren"

menu:
accounts:
title: "Rotationskonten"
list: "Konten auflisten"
list_desc: "alle Rotationskonten + Status anzeigen"
add: "Konto hinzufügen"
add_desc: "einen neuen API-Schlüssel registrieren"
remove: "Konto entfernen"
remove_desc: "ein Konto löschen"
toggle: "Aktivieren / Deaktivieren"
toggle_desc: "ein Konto pausieren oder fortsetzen"
use: "Konto wechseln"
use_desc: "Aktives Konto wechseln"
remove_title: "Konto entfernen"
toggle_title: "Konto aktivieren / deaktivieren"
fallback:
title: "Modell-Fallback-Kette"
list: "Kette auflisten"
list_desc: "primäres + Fallback-Modelle und Richtlinie anzeigen"
add: "Modell hinzufügen"
add_desc: "ein Fallback-Modell anhängen"
remove: "Modell entfernen"
remove_desc: "ein Modell aus der Kette entfernen"
clear: "Kette leeren"
clear_desc: "die Fallback-Kette leeren"
revert: "Revert umschalten"
revert_desc: "Auto-Revert auf primär ein/aus"
remove_title: "Fallback-Modell entfernen"
revert_title: "Revert-Richtlinie"
on: "Auto-Revert"
on_desc: "nach Abklingzeit zum primären Modell zurückkehren (empfohlen)"
off: "Bei Fallback bleiben"
off_desc: "Fallback bis manuellem Wechsel beibehalten"
audit:
title: "Audit-Protokoll"
recent: "Letzte Ereignisse"
recent_desc: "die letzten 20 über alle hinweg"
user: "Nach Benutzer filtern"
user_desc: "Ereignisse für einen Benutzer anzeigen"
host: "Nach Host filtern"
host_desc: "Ereignisse auf einem Host anzeigen"
type: "Nach Ereignistyp filtern"
type_desc: "einen Ereignistyp anzeigen"
user_label: "Benutzername"
host_label: "Host"
type_label: "Ereignistyp"
doctor:
title: "Systemdiagnose"
run: "Diagnose ausführen"
run_desc: "Systemzustand prüfen"
fix: "Mit Auto-Fix ausführen"
fix_desc: "automatische Reparaturen versuchen"
record:
title: "Terminalaufzeichnung"
start: "Aufzeichnung starten"
start_desc: "eine neue Terminalaufzeichnung beginnen"
stop: "Aufzeichnung stoppen"
stop_desc: "die Terminalaufzeichnung beenden und speichern"
plan:
title: "Planmodus"
start: "Planung starten"
start_desc: "in den schreibgeschützten Planmodus wechseln"
status: "Status anzeigen"
status_desc: "aktueller Plan-Status"
exit: "Planmodus verlassen"
exit_desc: "Planung verlassen"
not_in_plan: "Nicht im Planmodus. Verwende `/plan start` (oder `; <Anfrage>`), um mit der Planung zu beginnen."
kill:
title: "Aktive Sitzungen beenden"
all: "Alle anderen beenden"
all_desc: "jede Sitzung außer der aktuellen"

accounts:
list_title: "Rotationskonten"
primary: " [0] primär key={key}... {state}"
key_preview: "key={key}..."
unset: "(nicht gesetzt)"
enabled: "aktiviert"
disabled: "deaktiviert"
added: "Konto '{name}' hinzugefügt ({count} zusätzliche Konten)"
removed: "Konto '{name}' entfernt"
already_exists: "Konto '{name}' existiert bereits"
toggled: "{action} Konto '{name}'"
no_extra_remove: "keine zusätzlichen Konten zu entfernen"
no_extra_toggle: "keine zusätzlichen Konten umzuschalten"
no_account_named: "kein Konto namens '{name}'"
no_extra_hint: " (keine zusätzlichen Konten; füge eins hinzu mit /accounts add <name> <key>)"
usage_add: "Verwendung: /accounts add <name> <api_key> [api_base]"
usage_remove: "Verwendung: /accounts remove <name>"
usage_enable: "Verwendung: /accounts enable|disable <name>"
unknown_sub: "unbekannter Unterbefehl '{sub}'. Versuche /accounts help"
help_1: "/accounts Rotationskonten auflisten"
help_2: "/accounts add <name> <key> [base]"
help_3: "/accounts remove <name>"
help_4: "/accounts enable|disable <name>"
help_5: "(ohne Argumente wird ein interaktives Menü geöffnet)"
name_label: "Kontoname"
name_desc: "kurze Bezeichnung, z.B. 'team-b'"
key_label: "API-Schlüssel"
key_desc: "der Schlüssel für dieses Konto"
base_label: "API-Base (optional)"
base_desc: "Endpunkt überschreiben; leer = wie primär"
custom_model: "Benutzerdefiniert (manuell eingeben)"
model_label: "Modell"
model_desc: "Von diesem Endpunkt verwendeter Modellname"
select_model: "Modell zur Überprüfung wählen"
no_models: "Keine Modelle aufgelistet; verwende primäres Modell '{model}'"
fetch_failed: "Modelle konnten nicht abgerufen werden: {error}"
verifying: "Verbindung wird überprüft..."
connected: "Verbunden ({latency}ms) - Modell: {model}"
tool_yes: "Tool-Aufrufe: unterstützt"
tool_no: "Tool-Aufrufe: nicht unterstützt"
verify_failed: "Verbindungsprüfung fehlgeschlagen: {error}"
verify_failed_title: "Überprüfung fehlgeschlagen"
save_anyway: "Trotzdem speichern"
cancel_add: "Abbrechen"
usage_use: "Verwendung: /accounts use <Name>"
switched: "Zu '{name}' gewechselt (Modell: {model})"
no_extra_use: "Keine zusätzlichen Konten zum Wechseln. Mit /accounts add hinzufügen."
primary_choice: "Primär ({model})"
select_use: "Konto zur Verwendung auswählen"

fallback:
chain_title: "Fallback-Modell-Kette"
primary: " primär : {model}"
none: " fallback: (nicht konfiguriert)"
policy_auto: " Richtlinie : nach Abkühlung zum primären Modell zurückkehren"
policy_stay: " Richtlinie : bei Fallback bleiben bis manueller Wechsel"
added: "Fallback '{model}' hinzugefügt"
removed: "Fallback '{model}' entfernt"
cleared: "Fallback-Kette geleert"
already_in_chain: "'{model}' ist bereits in der Fallback-Kette"
not_in_chain: "'{model}' nicht in der Fallback-Kette"
empty: "Fallback-Kette ist leer"
usage_add: "Verwendung: /fallback add <modell>"
usage_remove: "Verwendung: /fallback remove <modell>"
usage_revert: "Verwendung: /fallback revert on|off"
unknown_sub: "unbekannter Unterbefehl '{sub}'. Versuche /fallback help"
help_1: "/fallback Fallback-Modell-Kette auflisten"
help_2: "/fallback add <modell> ein Fallback-Modell anhängen"
help_3: "/fallback remove <modell> ein Fallback-Modell entfernen"
help_4: "/fallback clear Kette leeren"
help_5: "/fallback revert on|off nach Abkühlung zum primären Modell zurückkehren"
help_6: "(ohne Argumente wird ein interaktives Menü geöffnet)"
model_label: "Fallback-Modell"
model_desc: "Modellname, der probiert wird, wenn das primäre scheitert (z.B. gpt-4o-mini)"
revert_already: "Rückkehr-Richtlinie bereits '{policy}'"
revert_set_on: "Rückkehr-Richtlinie: on (automatisch)"
revert_set_off: "Rückkehr-Richtlinie: off (bleiben)"

fork:
forked: "Sitzung verzweigt {short} (von {parent})"
switch_failed: "Verzweigung erstellt, aber Wechsel fehlgeschlagen: {error}"
switch_manual: "verwende `/resume {short}` zum manuellen Wechseln"
failed: "Verzweigung fehlgeschlagen: {error}"
store_unavailable: "Sitzungsspeicher nicht verfügbar; Verzweigung nicht möglich"

sessions:
none: "(keine gespeicherten Sitzungen)"
switch_failed: "Sitzungswechsel fehlgeschlagen: {error}"
list_failed: "Sitzungen auflisten fehlgeschlagen: {error}"

export:
md_header: "# aish Sitzungsexport"
session_label: "- **Sitzung**: `{uuid}`"
model_label: "- **Modell**: {model}"
api_base_label: "- **api_base**: {base}"
forked_label: "- **verzweigt von**: `{parent}`"
created_label: "- **erstellt**: {created}"
working_dir: "**Arbeitsverzeichnis**: `{cwd}`"
conversation_header: "## Unterhaltung"
history_header: "## Befehlsverlauf"
exported: "exportiert {file} ({msgs} Nachrichten, {cmds} Befehle)"
write_failed: "Schreiben von {file} fehlgeschlagen: {error}"
usage: "Verwendung: /export [md] (nur markdown wird unterstützt)"
store_unavailable: "Sitzungsspeicher nicht verfügbar; Export nicht möglich"
not_found: "aktuelle Sitzung im Speicher nicht gefunden"
load_failed: "Laden der Sitzung fehlgeschlagen: {error}"

common:
cancelled: "abgebrochen"
session_store_unavailable: "Sitzungsspeicher nicht verfügbar"
config_save_warning: "Warnung: Konfiguration konnte nicht gespeichert werden: {error}"

feedback:
select_type: "Feedback-Typ auswählen"
Expand Down Expand Up @@ -312,12 +501,53 @@ shell:
switch_same: "Modell unverändert: {model}"
switch_success: "Zu Modell gewechselt: {model}"
verify_failed: "Modellvalidierung fehlgeschlagen: {reason}"
picker_title: "Modell / Konto wechseln"
picker_subtitle: "↑↓ Auswaehlen, Enter wechseln"
fetch_failed_subtitle: "Modellliste konnte nicht abgerufen werden (Endpoint unerreichbar) — nur aktuell + Verlauf"
picker_search: "Modelle oder URLs suchen..."
picker_footer: "a Konto hinzufuegen m verwalten Esc Abbrechen"
action_add: "neu"
action_del: "loeschen"
action_toggle: "an/aus"
action_edit: "bearbeiten"
edit_label: "Modellname"
edit_desc: "Modell dieses Kontos"
edited: "'{name}' Modell auf {model} aktualisiert"
cannot_remove_primary: "Das primaere Modell kann nicht entfernt werden"
switched_account: "Zu '{name}' gewechselt (Modell: {model})"
fallback_badge: "Fallback"
primary_badge: "Primär"
recent_badge: "kuerzlich"
action_fallback: "Fallback"
fallback_not_switchable: "Fallback-Modell '{model}' ist nicht direkt umschaltbar; wird nur versucht, wenn das primaere versagt"
fallback_add_label: "Fallback-Modellname"
fallback_add_desc: "Modell, das versucht wird, wenn das primaere versagt"
fallback_added: "Fallback '{model}' hinzugefuegt"
fallback_removed: "Fallback '{model}' entfernt"
fallback_exists: "Fallback '{model}' existiert bereits"
action_manage: "verwalten"
manage_title: "Konten & Fallback"
manage_search: "Suchen..."
manage_subtitle: "d markierten Eintrag loeschen"
manage_footer: "d loeschen f Fallback hinzufuegen Esc zurueck"
manage_empty: "Keine Konten oder Fallbacks zu verwalten"
token:
title: "Token-Nutzung (letzte 7 Tage)"
input_tokens: "Eingabe-Tokens"
output_tokens: "Ausgabe-Tokens"
total: "Gesamt"
api_calls: "API-Aufrufe"
today: "Heute"
session: "Diese Sitzung"
rotation: "Kontorotation"
rotation_avail: "{available}/{total} verfügbar"
rotation_count: "{count} Rotationen in dieser Sitzung"
state_active: "aktiv"
state_cooling: "Abkühlphase"
state_ready: "bereit"
active_model: "Aktives Modell: {model}"
fallback_active: "Fallback aktiv"
fallback_chain: "Fallback-Kette: {chain}"
setup:
no_config_manager: "Neukonfiguration nicht möglich: Konfigurationsmanager nicht verfügbar"
cancelled: "Einrichtung abgebrochen; aktuelle Einstellungen werden beibehalten"
Expand Down
Loading
Loading