feat: profile-aware routes, provider sync, channel settings improvements
- Add hermes-profile.ts for dynamic profile path resolution (all backend routes now read from active profile directory instead of hardcoded ~/.hermes/) - Add profile switcher dropdown in sidebar, reload page on switch - Sync PROVIDER_PRESETS with Hermes CLI (fix keys: kimi-coding→kimi-for-coding, kilocode→kilo, ai-gateway→vercel, opencode-zen→opencode; remove moonshot) - Sync PROVIDER_ENV_MAP with Hermes models.dev + overlays (correct env var names) - Add gateway restart after adding model provider - Don't write GLM_BASE_URL/KIMI_BASE_URL for zai/kimi (let Hermes auto-detect) - Write API keys to .env and credential_pool for all providers - Built-in providers skip custom_providers in config.yaml - Add debounce + per-field loading state for channel settings inputs - Run hermes setup --reset for profiles without config.yaml - Create empty .env for new profiles (not copied from default) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
const loading = ref(false)
|
||||
const data = ref<MemoryData | null>(null)
|
||||
const editingSection = ref<'memory' | 'user' | null>(null)
|
||||
const editingSection = ref<'memory' | 'user' | 'soul' | null>(null)
|
||||
const editContent = ref('')
|
||||
const saving = ref(false)
|
||||
|
||||
@@ -27,7 +27,7 @@ async function loadMemory() {
|
||||
}
|
||||
}
|
||||
|
||||
function startEdit(section: 'memory' | 'user') {
|
||||
function startEdit(section: 'memory' | 'user' | 'soul') {
|
||||
editingSection.value = section
|
||||
editContent.value = data.value?.[section] || ''
|
||||
}
|
||||
@@ -65,9 +65,11 @@ function formatTime(ts: number | null): string {
|
||||
|
||||
const memoryEmpty = computed(() => !data.value?.memory?.trim())
|
||||
const userEmpty = computed(() => !data.value?.user?.trim())
|
||||
const soulEmpty = computed(() => !data.value?.soul?.trim())
|
||||
|
||||
const displayMemory = computed(() => (data.value?.memory || '').replace(/§/g, '\n\n'))
|
||||
const displayUser = computed(() => (data.value?.user || '').replace(/§/g, '\n\n'))
|
||||
const displaySoul = computed(() => (data.value?.soul || '').replace(/§/g, '\n\n'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -179,6 +181,53 @@ const displayUser = computed(() => (data.value?.user || '').replace(/§/g, '\n\n
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Soul -->
|
||||
<div class="memory-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title-row">
|
||||
<span class="section-icon">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
|
||||
<path d="M8 14s1.5 2 4 2 4-2 4-2" />
|
||||
<line x1="9" y1="9" x2="9.01" y2="9" />
|
||||
<line x1="15" y1="9" x2="15.01" y2="9" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="section-title">{{ t('memory.soul') }}</span>
|
||||
<span v-if="data?.soul_mtime" class="section-mtime">{{ formatTime(data.soul_mtime) }}</span>
|
||||
</div>
|
||||
<NButton v-if="editingSection !== 'soul'" size="tiny" quaternary @click="startEdit('soul')">
|
||||
<template #icon>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
||||
</svg>
|
||||
</template>
|
||||
{{ t('common.edit') }}
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
<!-- View mode -->
|
||||
<div v-if="editingSection !== 'soul'" class="section-body">
|
||||
<MarkdownRenderer v-if="!soulEmpty" :content="displaySoul" />
|
||||
<p v-else class="empty-text">{{ t('memory.noSoul') }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Edit mode -->
|
||||
<div v-else class="section-edit">
|
||||
<textarea
|
||||
v-model="editContent"
|
||||
class="edit-textarea"
|
||||
:placeholder="t('memory.soulPlaceholder')"
|
||||
spellcheck="false"
|
||||
></textarea>
|
||||
<div class="edit-actions">
|
||||
<NButton size="small" @click="cancelEdit">{{ t('common.cancel') }}</NButton>
|
||||
<NButton size="small" type="primary" :loading="saving" @click="handleSave">{{ t('common.save') }}</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user