Class: Spurline::Tools::Idempotency::KeyComputer
- Inherits:
-
Object
- Object
- Spurline::Tools::Idempotency::KeyComputer
- Defined in:
- lib/spurline/tools/idempotency.rb
Overview
Computes idempotency keys from tool name and arguments.
Class Method Summary collapse
-
.canonical_hash(args) ⇒ Object
Produces a deterministic hash of arguments.
-
.canonicalize(obj) ⇒ Object
Recursively sorts hash keys for deterministic serialization.
-
.compute(tool_name:, args:, key_params: nil, key_fn: nil) ⇒ String
Computes a deterministic key for a tool call.
Class Method Details
.canonical_hash(args) ⇒ Object
Produces a deterministic hash of arguments. Sorts keys recursively for canonical representation.
39 40 41 42 |
# File 'lib/spurline/tools/idempotency.rb', line 39 def self.canonical_hash(args) json = JSON.generate(canonicalize(args)) Digest::SHA256.hexdigest(json) end |
.canonicalize(obj) ⇒ Object
Recursively sorts hash keys for deterministic serialization.
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/spurline/tools/idempotency.rb', line 45 def self.canonicalize(obj) case obj when Hash obj.sort_by { |k, _| k.to_s }.map { |k, v| [k.to_s, canonicalize(v)] }.to_h when Array obj.map { |v| canonicalize(v) } else obj end end |
.compute(tool_name:, args:, key_params: nil, key_fn: nil) ⇒ String
Computes a deterministic key for a tool call.
Key computation:
1. If key_fn provided: "#{tool_name}:#{key_fn.call(args)}"
2. If key_params provided: SHA256 of only those params
3. Default: SHA256 of all args (canonical JSON with sorted keys)
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/spurline/tools/idempotency.rb', line 23 def self.compute(tool_name:, args:, key_params: nil, key_fn: nil) prefix = tool_name.to_s hash = if key_fn key_fn.call(args).to_s elsif key_params canonical_hash(args.slice(*key_params)) else canonical_hash(args) end "#{prefix}:#{hash}" end |