mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-29 04:10:00 +08:00
feat(hermes): add memory flush setting
This commit is contained in:
@@ -3554,6 +3554,7 @@ export function buildHermesMemoryConfigValues(config = {}) {
|
||||
memoryCharLimit: parseHermesInteger(memory.memory_char_limit, 'memory.memory_char_limit', 2200, 100, 200000, false),
|
||||
userCharLimit: parseHermesInteger(memory.user_char_limit, 'memory.user_char_limit', 1375, 100, 200000, false),
|
||||
nudgeInterval: parseHermesInteger(memory.nudge_interval, 'memory.nudge_interval', 10, 0, 1000, false),
|
||||
flushMinTurns: parseHermesInteger(memory.flush_min_turns, 'memory.flush_min_turns', 6, 0, 1000, false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3568,6 +3569,7 @@ export function mergeHermesMemoryConfig(config = {}, form = {}) {
|
||||
memory.memory_char_limit = parseHermesInteger(Object.hasOwn(form, 'memoryCharLimit') ? form.memoryCharLimit : currentValues.memoryCharLimit, 'memory.memory_char_limit', 2200, 100, 200000, true)
|
||||
memory.user_char_limit = parseHermesInteger(Object.hasOwn(form, 'userCharLimit') ? form.userCharLimit : currentValues.userCharLimit, 'memory.user_char_limit', 1375, 100, 200000, true)
|
||||
memory.nudge_interval = parseHermesInteger(Object.hasOwn(form, 'nudgeInterval') ? form.nudgeInterval : currentValues.nudgeInterval, 'memory.nudge_interval', 10, 0, 1000, true)
|
||||
memory.flush_min_turns = parseHermesInteger(Object.hasOwn(form, 'flushMinTurns') ? form.flushMinTurns : currentValues.flushMinTurns, 'memory.flush_min_turns', 6, 0, 1000, true)
|
||||
next.memory = memory
|
||||
return next
|
||||
}
|
||||
|
||||
@@ -3577,6 +3577,9 @@ fn build_hermes_memory_config_values(config: &serde_yaml::Value) -> Value {
|
||||
let nudge_interval = memory
|
||||
.map(|map| bounded_hermes_i64(yaml_i64_field(map, "nudge_interval"), 10, 0, 1000))
|
||||
.unwrap_or(10);
|
||||
let flush_min_turns = memory
|
||||
.map(|map| bounded_hermes_i64(yaml_i64_field(map, "flush_min_turns"), 6, 0, 1000))
|
||||
.unwrap_or(6);
|
||||
|
||||
serde_json::json!({
|
||||
"memoryEnabled": memory_enabled,
|
||||
@@ -3584,6 +3587,7 @@ fn build_hermes_memory_config_values(config: &serde_yaml::Value) -> Value {
|
||||
"memoryCharLimit": memory_char_limit,
|
||||
"userCharLimit": user_char_limit,
|
||||
"nudgeInterval": nudge_interval,
|
||||
"flushMinTurns": flush_min_turns,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3626,6 +3630,17 @@ fn merge_hermes_memory_config(config: &mut serde_yaml::Value, form: &Value) -> R
|
||||
0,
|
||||
1000,
|
||||
)?;
|
||||
let flush_min_turns = validate_hermes_i64(
|
||||
if form.get("flushMinTurns").is_some() {
|
||||
form_i64(form, "flushMinTurns")
|
||||
} else {
|
||||
Some(current["flushMinTurns"].as_i64().unwrap_or(6))
|
||||
},
|
||||
"memory.flush_min_turns",
|
||||
6,
|
||||
0,
|
||||
1000,
|
||||
)?;
|
||||
|
||||
let root = ensure_yaml_object(config)?;
|
||||
let memory = yaml_child_object(root, "memory")?;
|
||||
@@ -3649,6 +3664,10 @@ fn merge_hermes_memory_config(config: &mut serde_yaml::Value, form: &Value) -> R
|
||||
yaml_key("nudge_interval"),
|
||||
serde_yaml::Value::Number(nudge_interval.into()),
|
||||
);
|
||||
memory.insert(
|
||||
yaml_key("flush_min_turns"),
|
||||
serde_yaml::Value::Number(flush_min_turns.into()),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -10846,6 +10865,7 @@ mod hermes_memory_config_tests {
|
||||
assert_eq!(values["memoryCharLimit"], 2200);
|
||||
assert_eq!(values["userCharLimit"], 1375);
|
||||
assert_eq!(values["nudgeInterval"], 10);
|
||||
assert_eq!(values["flushMinTurns"], 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -10858,6 +10878,7 @@ memory:
|
||||
memory_enabled: true
|
||||
provider: honcho
|
||||
custom_flag: keep-me
|
||||
flush_min_turns: 9
|
||||
streaming:
|
||||
enabled: true
|
||||
"#,
|
||||
@@ -10872,6 +10893,7 @@ streaming:
|
||||
"memoryCharLimit": "2600",
|
||||
"userCharLimit": "1500",
|
||||
"nudgeInterval": "0",
|
||||
"flushMinTurns": "7",
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -10886,6 +10908,7 @@ streaming:
|
||||
assert_eq!(config["memory"]["memory_char_limit"].as_i64(), Some(2600));
|
||||
assert_eq!(config["memory"]["user_char_limit"].as_i64(), Some(1500));
|
||||
assert_eq!(config["memory"]["nudge_interval"].as_i64(), Some(0));
|
||||
assert_eq!(config["memory"]["flush_min_turns"].as_i64(), Some(7));
|
||||
assert_eq!(config["memory"]["provider"].as_str(), Some("honcho"));
|
||||
assert_eq!(config["memory"]["custom_flag"].as_str(), Some("keep-me"));
|
||||
}
|
||||
@@ -10905,6 +10928,12 @@ streaming:
|
||||
let err =
|
||||
merge_hermes_memory_config(&mut config, &json!({ "nudgeInterval": 1001 })).unwrap_err();
|
||||
assert!(err.contains("memory.nudge_interval"));
|
||||
let err =
|
||||
merge_hermes_memory_config(&mut config, &json!({ "flushMinTurns": -1 })).unwrap_err();
|
||||
assert!(err.contains("memory.flush_min_turns"));
|
||||
let err =
|
||||
merge_hermes_memory_config(&mut config, &json!({ "flushMinTurns": 1001 })).unwrap_err();
|
||||
assert!(err.contains("memory.flush_min_turns"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ const MEMORY_DEFAULTS = {
|
||||
memoryCharLimit: 2200,
|
||||
userCharLimit: 1375,
|
||||
nudgeInterval: 10,
|
||||
flushMinTurns: 6,
|
||||
}
|
||||
|
||||
const STREAMING_DEFAULTS = {
|
||||
@@ -343,6 +344,10 @@ export function render() {
|
||||
<span class="hm-field-label">${t('engine.hermesMemoryConfigNudgeInterval')}</span>
|
||||
<input id="hm-memory-nudge-interval" class="hm-input" type="number" inputmode="numeric" min="0" max="1000" step="1" value="${esc(memoryValues.nudgeInterval)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesMemoryConfigFlushMinTurns')}</span>
|
||||
<input id="hm-memory-flush-min-turns" class="hm-input" type="number" inputmode="numeric" min="0" max="1000" step="1" value="${esc(memoryValues.flushMinTurns)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-channel-footnote">${t('engine.hermesMemoryConfigFootnote')}</div>
|
||||
</div>
|
||||
@@ -864,6 +869,7 @@ export function render() {
|
||||
memoryCharLimit: el.querySelector('#hm-memory-char-limit')?.value || '2200',
|
||||
userCharLimit: el.querySelector('#hm-memory-user-char-limit')?.value || '1375',
|
||||
nudgeInterval: el.querySelector('#hm-memory-nudge-interval')?.value || '10',
|
||||
flushMinTurns: el.querySelector('#hm-memory-flush-min-turns')?.value || '6',
|
||||
}
|
||||
memorySaving = true
|
||||
memoryError = null
|
||||
|
||||
@@ -608,7 +608,8 @@ export default {
|
||||
hermesMemoryConfigMemoryCharLimit: _('记忆字符上限', 'Memory character limit', '記憶字元上限'),
|
||||
hermesMemoryConfigUserCharLimit: _('用户画像字符上限', 'User profile character limit', '使用者画像字元上限'),
|
||||
hermesMemoryConfigNudgeInterval: _('整理提醒间隔', 'Review nudge interval', '整理提醒間隔'),
|
||||
hermesMemoryConfigFootnote: _('提醒间隔按用户消息轮数计算,设为 0 可关闭提醒。外部记忆 provider 等高级字段会保留在 raw YAML 中。', 'The nudge interval is counted in user turns. Set it to 0 to disable nudges. Advanced fields such as external memory provider are preserved in raw YAML.', '提醒間隔依使用者訊息輪數計算,設為 0 可關閉提醒。外部記憶 provider 等進階欄位會保留在 raw YAML 中。'),
|
||||
hermesMemoryConfigFlushMinTurns: _('退出/重置前最少轮数', 'Minimum turns before flush', '退出/重置前最少輪數'),
|
||||
hermesMemoryConfigFootnote: _('提醒间隔按用户消息轮数计算,设为 0 可关闭提醒。flush 最小轮数会影响退出、重置和压缩前是否先写入记忆。外部记忆 provider 等高级字段会保留在 raw YAML 中。', 'The nudge interval is counted in user turns. Set it to 0 to disable nudges. flush minimum turns controls whether memory is written before exit, reset, or compression. Advanced fields such as external memory provider are preserved in raw YAML.', '提醒間隔依使用者訊息輪數計算,設為 0 可關閉提醒。flush 最小輪數會影響退出、重置和壓縮前是否先寫入記憶。外部記憶 provider 等進階欄位會保留在 raw YAML 中。'),
|
||||
// Batch 1 §E: 会话导出
|
||||
sessionsExport: _('导出', 'Export', '匯出'),
|
||||
sessionsExportSuccess: _('已导出', 'Exported', '已匯出'),
|
||||
|
||||
@@ -33,6 +33,7 @@ test('Hermes 配置页会暴露记忆结构化配置字段', () => {
|
||||
'hm-memory-char-limit',
|
||||
'hm-memory-user-char-limit',
|
||||
'hm-memory-nudge-interval',
|
||||
'hm-memory-flush-min-turns',
|
||||
]) {
|
||||
assert.match(source, new RegExp(`id="${id}"`), `缺少 ${id}`)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ test('Hermes 记忆配置读取会提供上游默认值', () => {
|
||||
memoryCharLimit: 2200,
|
||||
userCharLimit: 1375,
|
||||
nudgeInterval: 10,
|
||||
flushMinTurns: 6,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,6 +27,7 @@ test('Hermes 记忆配置读取会回显 YAML 中的记忆字段', () => {
|
||||
memory_char_limit: 3200,
|
||||
user_char_limit: 1800,
|
||||
nudge_interval: 12,
|
||||
flush_min_turns: 8,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -34,6 +36,7 @@ test('Hermes 记忆配置读取会回显 YAML 中的记忆字段', () => {
|
||||
assert.equal(values.memoryCharLimit, 3200)
|
||||
assert.equal(values.userCharLimit, 1800)
|
||||
assert.equal(values.nudgeInterval, 12)
|
||||
assert.equal(values.flushMinTurns, 8)
|
||||
})
|
||||
|
||||
test('Hermes 记忆配置保存会保留无关 YAML 并写入 snake_case 字段', () => {
|
||||
@@ -43,6 +46,7 @@ test('Hermes 记忆配置保存会保留无关 YAML 并写入 snake_case 字段'
|
||||
memory_enabled: true,
|
||||
provider: 'honcho',
|
||||
custom_flag: 'keep-me',
|
||||
flush_min_turns: 9,
|
||||
},
|
||||
streaming: { enabled: true },
|
||||
}, {
|
||||
@@ -51,6 +55,7 @@ test('Hermes 记忆配置保存会保留无关 YAML 并写入 snake_case 字段'
|
||||
memoryCharLimit: '2600',
|
||||
userCharLimit: '1500',
|
||||
nudgeInterval: '0',
|
||||
flushMinTurns: '7',
|
||||
})
|
||||
|
||||
assert.deepEqual(next.model, { provider: 'anthropic' })
|
||||
@@ -60,6 +65,7 @@ test('Hermes 记忆配置保存会保留无关 YAML 并写入 snake_case 字段'
|
||||
assert.equal(next.memory.memory_char_limit, 2600)
|
||||
assert.equal(next.memory.user_char_limit, 1500)
|
||||
assert.equal(next.memory.nudge_interval, 0)
|
||||
assert.equal(next.memory.flush_min_turns, 7)
|
||||
assert.equal(next.memory.provider, 'honcho')
|
||||
assert.equal(next.memory.custom_flag, 'keep-me')
|
||||
})
|
||||
@@ -81,4 +87,12 @@ test('Hermes 记忆配置保存会拒绝越界字符上限和提醒间隔', () =
|
||||
() => mergeHermesMemoryConfig({}, { nudgeInterval: '1001' }),
|
||||
/memory\.nudge_interval/,
|
||||
)
|
||||
assert.throws(
|
||||
() => mergeHermesMemoryConfig({}, { flushMinTurns: '-1' }),
|
||||
/memory\.flush_min_turns/,
|
||||
)
|
||||
assert.throws(
|
||||
() => mergeHermesMemoryConfig({}, { flushMinTurns: '1001' }),
|
||||
/memory\.flush_min_turns/,
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user