openclacky 0.9.3 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d842684d3cae23106509a9e47be986d51e518f8b953e66011783b32e1a121a6e
4
- data.tar.gz: 34a8ef45f736724fd7e8356e032a4cd1102bd1a28b47f412419895bd8575caf7
3
+ metadata.gz: a9c12ba4b5e244e6dbbec7d723dc6d0f9c7e4e4523a82bafbb96f668e7b1a0f4
4
+ data.tar.gz: 5d6e7d71829aa2bafbe68dc825b6ec0e7bd4c1ad004804d43ef9121a46fa6671
5
5
  SHA512:
6
- metadata.gz: cc9f6ee3d0b8ebf01346261dfd9dbcf6a77654bc40632b5730432fbe5ce23c604f30135739507c1802e837a4baf6097609ba26397c9eea2ec4555b115cd73dc9
7
- data.tar.gz: 20ad77eb3191fadd1d4340ce7a92b16489be68e83dc4d33fa1d2e802a821074d1964f9a1e7afadcd7cbf9846b81dabebd5cbd918441bb3b3528bfd6212fb5f56
6
+ metadata.gz: 1dd7ede95260c506b7dfb89cd5596ea4ba9ac4e6949e17067b84ec6a9a2686892a27fafd1e25bf80a6c0ade211f398c3f6b8ab87d3e7167ea808fe88398f46be
7
+ data.tar.gz: 38771322fb7651494b4595d82e315a3a6ddf902ae3bf4141d4ea01a63a65ffd1c9adb1dcf91da43d29ead77f673025e1559d0ad688fafbfa7673738dcf393052
data/CHANGELOG.md CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.4] - 2026-03-16
11
+
12
+ ### Fixed
13
+ - **Prompt cache strategy reverted to simple last-message anchoring**: the experimental assistant-message-anchored cache strategy introduced in v0.9.3 was causing regressions; caching is now restored to a simpler, proven approach where the last message is used as the cache breakpoint
14
+
10
15
  ## [0.9.3] - 2026-03-16
11
16
 
12
17
  ### Added
data/lib/clacky/client.rb CHANGED
@@ -143,38 +143,16 @@ module Clacky
143
143
  # ── Prompt caching helpers ────────────────────────────────────────────────
144
144
 
145
145
  # Add cache_control marker to the appropriate message in the array.
146
- #
147
- # Strategy: mark the SECOND-TO-LAST non-injected assistant message.
148
- #
149
- # Rationale: Anthropic prompt caching is prefix-based. If we mark the last
150
- # message (typically the latest user turn or tool_result), the cached prefix
151
- # changes every request because tool results and user inputs vary each turn.
152
- # This causes alternating miss/hit patterns observed in production.
153
- #
154
- # By placing the breakpoint on the most recent ASSISTANT message that precedes
155
- # the current user turn, we cache everything up to (and including) the last LLM
156
- # reply — a stable prefix. The new user turn + any tool results live AFTER the
157
- # breakpoint and are not cached (they change every request anyway).
158
- #
159
- # Special cases:
160
- # - Compression instruction as last message: skip it, find the assistant before it.
161
- # - Fewer than 2 messages: fall back to marking the last message.
146
+ # Strategy: mark the last message, unless that message is a compression
147
+ # instruction (system_injected: true) — in that case mark the one before it.
162
148
  def apply_message_caching(messages)
163
149
  return messages if messages.empty?
164
150
 
165
- # Walk backwards to find the last assistant message that is not system_injected.
166
- # That is the stable "end of history" to anchor the cache breakpoint on.
167
- cache_index = nil
168
- messages.each_with_index.reverse_each do |msg, idx|
169
- next if msg[:system_injected]
170
- if msg[:role] == "assistant"
171
- cache_index = idx
172
- break
173
- end
174
- end
175
-
176
- # Fallback: if no assistant message found, mark the last message
177
- cache_index ||= messages.length - 1
151
+ cache_index = if is_compression_instruction?(messages.last)
152
+ [messages.length - 2, 0].max
153
+ else
154
+ messages.length - 1
155
+ end
178
156
 
179
157
  messages.map.with_index do |msg, idx|
180
158
  idx == cache_index ? add_cache_control_to_message(msg) : msg
@@ -199,18 +177,8 @@ module Clacky
199
177
  msg.merge(content: content_array)
200
178
  end
201
179
 
202
- # Only true for the compression-instruction user message inserted by MessageCompressor.
203
- # Skill shim messages (also system_injected: true) must NOT be treated as compression
204
- # instructions — doing so shifts the cache breakpoint into the volatile skill content
205
- # block, causing a full cache miss on every slash command turn.
206
180
  def is_compression_instruction?(message)
207
- return false unless message.is_a?(Hash)
208
- return false unless message[:system_injected] == true
209
- return false unless message[:role] == "user"
210
-
211
- content = message[:content].to_s
212
- content.include?("CRITICAL: TASK CHANGE - MEMORY COMPRESSION MODE") ||
213
- content.include?("MEMORY COMPRESSION MODE")
181
+ message.is_a?(Hash) && message[:system_injected] == true
214
182
  end
215
183
 
216
184
  # ── HTTP connections ──────────────────────────────────────────────────────
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clacky
4
- VERSION = "0.9.3"
4
+ VERSION = "0.9.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openclacky
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - windy