From 2423241a40de74a252e233bf12ebd1df1e4fc7f3 Mon Sep 17 00:00:00 2001 From: vegu-ai-tools <152010387+vegu-ai-tools@users.noreply.github.com> Date: Sat, 6 Jun 2026 17:54:48 +0300 Subject: [PATCH] feat: add adaptive response length enforcement option and update documentation --- CHANGELOG.yaml | 1 + src/talemate/client/base.py | 33 ++++++++++++++++++++++++++++++--- src/talemate/config/schema.py | 12 ++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index 6a1d9e70..554b93c5 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -35,6 +35,7 @@ - "Inference Presets: Added an 'Apply to all' action to the inference parameter editor that copies the current preset's values to every other preset in the group. The Reset action now asks for confirmation as well." - "Inference Presets: Widened the adjustable range and refined the step increments on several inference parameter sliders so presets can be tuned more precisely." - "More Autocomplete Fields: The character actor's Add Dialogue Example field and the world editor's World information field now support autocomplete (Ctrl+Enter), with the same hint and Redo/Undo affordances as other generated fields." + - "Response Length Enforcement: Added an Adaptive option to the client's response-length setting, now the default. When reasoning is enabled it relies on length instructions alone, which reasoning models follow well, and drops the token cap that could otherwise cut a response off while the model is still thinking. With reasoning off it falls back to capping tokens and sending instructions." changes: - "World State Snapshot Cadence: The snapshot now refreshes per individual character turn rather than per full scene round. The default interval was raised from 5 to 10 to keep the effective cadence comparable." fixes: diff --git a/src/talemate/client/base.py b/src/talemate/client/base.py index f61de5c9..babde18f 100644 --- a/src/talemate/client/base.py +++ b/src/talemate/client/base.py @@ -434,13 +434,40 @@ class ClientBase: return self.client_config.dedupe_enabled @property - def enforce_response_length(self) -> str: + def enforce_response_length( + self, + ) -> Literal[ + "uncapped", + "cap_tokens_and_instructions", + "cap_tokens", + "instructions", + "adaptive", + ]: return self.client_config.enforce_response_length + @property + def enforce_response_length_resolved( + self, + ) -> Literal[ + "uncapped", + "cap_tokens_and_instructions", + "cap_tokens", + "instructions", + ]: + """The effective mode, resolving "adaptive" based on runtime reasoning state. + + "adaptive" sends instructions only when reasoning is enabled, otherwise + caps tokens and sends instructions. + """ + mode = self.enforce_response_length + if mode == "adaptive": + return "instructions" if self.reason_enabled else "cap_tokens_and_instructions" + return mode + @property def enforce_response_length_cap_tokens(self) -> bool: """Whether the current mode should cap tokens (send max_tokens to the API).""" - return self.enforce_response_length in ( + return self.enforce_response_length_resolved in ( "cap_tokens_and_instructions", "cap_tokens", ) @@ -448,7 +475,7 @@ class ClientBase: @property def enforce_response_length_instructions(self) -> bool: """Whether the current mode should append human-readable length instructions.""" - return self.enforce_response_length in ( + return self.enforce_response_length_resolved in ( "cap_tokens_and_instructions", "instructions", ) diff --git a/src/talemate/config/schema.py b/src/talemate/config/schema.py index 974253b2..afe05611 100644 --- a/src/talemate/config/schema.py +++ b/src/talemate/config/schema.py @@ -99,15 +99,18 @@ class Client(pydantic.BaseModel): # Controls whether token caps and/or response length instructions are # sent with prompts. Options: # "uncapped" - no token cap, no instructions - # "cap_tokens_and_instructions" - cap tokens + append instructions (default) + # "cap_tokens_and_instructions" - cap tokens + append instructions # "cap_tokens" - cap tokens only, no instructions # "instructions" - append instructions only, no token cap + # "adaptive" - "instructions" when reasoning is enabled, otherwise + # "cap_tokens_and_instructions" (default) enforce_response_length: Literal[ "uncapped", "cap_tokens_and_instructions", "cap_tokens", "instructions", - ] = "cap_tokens_and_instructions" + "adaptive", + ] = "adaptive" @pydantic.field_validator("lock_template", mode="before") @classmethod @@ -140,6 +143,11 @@ class Client(pydantic.BaseModel): "value": "instructions", "help": "Appends length instructions without limiting tokens", }, + { + "label": "Adaptive", + "value": "adaptive", + "help": "Sends instructions only when reasoning is enabled, otherwise limits tokens and sends instructions", + }, ], }