diff --git a/src/loop.metta b/src/loop.metta index 783b2daa..c0549482 100644 --- a/src/loop.metta +++ b/src/loop.metta @@ -7,11 +7,13 @@ (= (wakeupInterval) (empty)) (= (memoryDirectory) (empty)) (= (spamShield) (empty)) ; TODO: this parameter is considered deprecated +(= (stableContextOrder) (empty)) ; order prompt sections stable->volatile so providers can reuse the cached prefix (= (initLoop) (progn (configure maxNewInputLoops 50) ;20 (configure maxWakeLoops 1) (configure spamShield False) + (configure stableContextOrder False) (configure sleepInterval 1) ;10 (configure provider Anthropic) (configure maxOutputToken 6000) @@ -40,10 +42,29 @@ " toolName4 arg4" (newline) " toolName5 arg5" (newline) " SAVE_PERMANENT_FILES_DIR: " (memoryDirectory) - " LAST_SKILL_USE_RESULTS: " (last_chars (get-state &lastresults) (maxFeedback)) - " HISTORY: " (getHistory) + (contextVolatileTail) " TIME: " (get_time_as_string))))) +; LAST_SKILL_USE_RESULTS changes every cycle and is one of the largest sections, +; so keeping it before HISTORY ends the provider's reusable cache prefix right after +; the static head. With stableContextOrder on, HISTORY (which shifts far less between +; consecutive calls) comes first and the volatile results section goes last, so more of +; the prefix stays byte-identical and can be served from cache. Default is off, in which +; case the tail is byte-for-byte identical to the original layout. +(= (contextVolatileTail) + (py-str (orderedContextSections (stableContextOrder) + (last_chars (get-state &lastresults) (maxFeedback)) + (getHistory)))) + +; Section ordering, kept separate from the state reads and the py-str call so it +; can be checked on its own. Returns the sections as a plain tuple. Flag off keeps +; the results section ahead of HISTORY (the original layout); flag on puts HISTORY +; first so the stable part sits in the reusable cache prefix. +(= (orderedContextSections $stable $results $history) + (if $stable + (" HISTORY: " $history " LAST_SKILL_USE_RESULTS: " $results) + (" LAST_SKILL_USE_RESULTS: " $results " HISTORY: " $history))) + (= (addTelegramPromptExtension) (if (== (commchannel) telegram) (let $path (joinPath ((memoryDirectory) "tg_prompt.txt")) diff --git a/tests/src_loop.metta b/tests/src_loop.metta new file mode 100644 index 00000000..36e9657a --- /dev/null +++ b/tests/src_loop.metta @@ -0,0 +1,17 @@ +!(import! &self ./tests/lib/utils) +!(import! &self ../src/helper.py) +!(import! &self ./src/utils) +!(import! &self ./src/loop) + +; orderedContextSections is a pure function of the two section strings and returns +; the sections as a plain tuple, so the ordering can be checked directly without +; loop state, the global flag, or building the final string. + +; Flag off (default): the volatile results section stays ahead of HISTORY, which +; keeps the assembled prompt byte-for-byte identical to the original layout. +!(test (orderedContextSections False "RESULT" "HIST") + (" LAST_SKILL_USE_RESULTS: " "RESULT" " HISTORY: " "HIST")) + +; Flag on: HISTORY moves ahead of the volatile results section. +!(test (orderedContextSections True "RESULT" "HIST") + (" HISTORY: " "HIST" " LAST_SKILL_USE_RESULTS: " "RESULT"))