llm_mock 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 76c3be4ff38f519d54043d67a1a91112c832e99bd320e9b887881576bbc4391e
4
+ data.tar.gz: cc1cab796fc5149bdf27a7dfc188a09868b6ff7e26b361a16e4e5b2a4afcbbcc
5
+ SHA512:
6
+ metadata.gz: e33be7f603f386d41186f8f67a45c832194672164b5568b3648efefc9d40c0764b0ff5e84ca9dcf33f556c3a4b07b3dd94e01d559defbae990bca763fbb31645
7
+ data.tar.gz: de6b695425a8b983d188b9ec24f8d9c460d583f820fb94c22f5b1747abc07f04419aded7fcea0bdbd7d2311dcd31042812e2adb0b7bda59c5d78a9d844f3d746
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. This project adheres to
4
+ [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.1.0] - 2026-06-19
7
+
8
+ ### Added
9
+ - Initial release: the `LlmMock::Provider` contract that provider mock gems
10
+ (e.g. `llm_mock_anthropic`) implement.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nate Brustein
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # llm_mock
2
+
3
+ When you test code that calls an LLM API, one robust approach is to **stub the
4
+ client and hand back a canned response object** — no network, no flakiness, no
5
+ cost. But every provider's SDK returns differently-shaped objects (messages,
6
+ content blocks, tool calls, streams), and constructing those by hand is fiddly.
7
+ The `llm_mock` family solves that per provider: `llm_mock_anthropic`,
8
+ `llm_mock_gemini`, and so on, each giving you ergonomic builders for that SDK's
9
+ response objects.
10
+
11
+ **`llm_mock` itself is just the shared foundation.** You almost never depend on
12
+ it directly — you pick a provider gem. This gem exists so that:
13
+
14
+ - every provider mock implements the **same contract**, and
15
+ - tools that orchestrate testing (like [`deja`](https://github.com/nbrustein/deja),
16
+ which records and replays real LLM calls) can drive **any** provider through
17
+ one interface instead of special-casing each SDK.
18
+
19
+ ## Who depends on this
20
+
21
+ ```
22
+ your test ──► llm_mock_anthropic ──► llm_mock (the contract)
23
+ deja ─────────► llm_mock_anthropic ──► llm_mock
24
+ ```
25
+
26
+ You want **`llm_mock_anthropic`** (or another provider gem). It pulls in
27
+ `llm_mock` for you.
28
+
29
+ ## The contract
30
+
31
+ A provider gem subclasses `LlmMock::Provider` and implements the parts it
32
+ supports:
33
+
34
+ | Method | Purpose |
35
+ | --- | --- |
36
+ | `build_client(&responder)` | Return a stub client; each SDK method calls `responder.call(method, kwargs)`. |
37
+ | `call_real(client, method, kwargs)` | Invoke the real SDK method on a live client. |
38
+ | `serialize(method, response)` | SDK response object → plain Hash (for caching). |
39
+ | `deserialize(method, data)` | Plain Hash → an object shaped like the SDK response. |
40
+ | `prompt_for(kwargs)` | Optional readable prompt string for audit logs. |
41
+ | `default_real_client` | Optional `-> { ... }` that builds a live SDK client. |
42
+
43
+ That's the whole gem: a namespace and one abstract class. The interesting code
44
+ lives in the provider gems.
45
+
46
+ ## License
47
+
48
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LlmMock
4
+ # The contract every provider mock implements (llm_mock_anthropic, and more to
5
+ # come), so a consumer like the `deja` gem can drive any provider uniformly.
6
+ #
7
+ # A provider encapsulates one LLM SDK's *shape* for tests:
8
+ # - how to build a stub client whose methods route through a responder,
9
+ # - how to invoke the real SDK (when something isn't cached),
10
+ # - how to serialize/deserialize that SDK's response objects to/from the plain
11
+ # hashes a cache stores.
12
+ #
13
+ # Subclasses raise NotImplementedError for anything they don't provide.
14
+ class Provider
15
+ # Build a stub object shaped like the real SDK client. Every SDK method it
16
+ # exposes must call `responder.call(method_name, kwargs)` and return the
17
+ # result. The responder is supplied by the consumer (e.g. deja's cache layer),
18
+ # so the provider stays ignorant of caching.
19
+ def build_client(&responder)
20
+ raise NotImplementedError, "#{self.class} must implement #build_client"
21
+ end
22
+
23
+ # Invoke the real SDK method on a live client — used to make the actual call
24
+ # when there's no cached response. `method` is the symbol the stub captured.
25
+ def call_real(client, method, kwargs)
26
+ raise NotImplementedError, "#{self.class} must implement #call_real"
27
+ end
28
+
29
+ # Provider response object -> plain Hash (must round-trip through #deserialize).
30
+ def serialize(method, response)
31
+ raise NotImplementedError, "#{self.class} must implement #serialize"
32
+ end
33
+
34
+ # Plain Hash -> an object shaped like the SDK's response.
35
+ def deserialize(method, data)
36
+ raise NotImplementedError, "#{self.class} must implement #deserialize"
37
+ end
38
+
39
+ # A human-readable prompt string stored alongside cached calls for auditing.
40
+ # Optional — defaults to nil.
41
+ def prompt_for(_kwargs)
42
+ nil
43
+ end
44
+
45
+ # A callable (-> { ... }) that builds a live SDK client. Optional — consumers
46
+ # may supply their own instead.
47
+ def default_real_client
48
+ raise NotImplementedError, "#{self.class} must implement #default_real_client"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LlmMock
4
+ VERSION = "0.1.0"
5
+ end
data/lib/llm_mock.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "llm_mock/version"
4
+ require "llm_mock/provider"
5
+
6
+ # llm_mock is the shared foundation for a family of gems that fabricate LLM SDK
7
+ # response objects in tests — `llm_mock_anthropic`, and more providers to come.
8
+ #
9
+ # You don't usually depend on this gem directly; you pick a provider gem. This
10
+ # gem only defines the common contract (LlmMock::Provider) those providers
11
+ # implement, so tools like `deja` can drive any provider the same way.
12
+ module LlmMock
13
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: llm_mock
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nate Brustein
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rspec
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.0'
26
+ description: |
27
+ The shared foundation for a family of gems (llm_mock_anthropic, and more) that
28
+ build fake LLM SDK response objects for tests that stub the client directly.
29
+ This gem defines the common provider contract those gems implement so tools
30
+ like deja can drive any provider uniformly. You usually depend on a provider
31
+ gem, not this one.
32
+ email:
33
+ - nate@bidwrangler.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - CHANGELOG.md
39
+ - LICENSE
40
+ - README.md
41
+ - lib/llm_mock.rb
42
+ - lib/llm_mock/provider.rb
43
+ - lib/llm_mock/version.rb
44
+ homepage: https://github.com/nbrustein/llm_mock
45
+ licenses:
46
+ - MIT
47
+ metadata:
48
+ homepage_uri: https://github.com/nbrustein/llm_mock
49
+ source_code_uri: https://github.com/nbrustein/llm_mock
50
+ changelog_uri: https://github.com/nbrustein/llm_mock/blob/main/CHANGELOG.md
51
+ rubygems_mfa_required: 'true'
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '3.2'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubygems_version: 4.0.3
67
+ specification_version: 4
68
+ summary: Shared contract for gems that fabricate LLM SDK response objects in tests.
69
+ test_files: []