ruby_llm-providers-lms 0.1.1 → 0.2.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -0
  3. data/README.md +467 -104
  4. data/lib/ruby_llm/providers/lms/anthropic_messages.rb +28 -0
  5. data/lib/ruby_llm/providers/lms/endpoints.rb +18 -0
  6. data/lib/ruby_llm/providers/lms/model_management.rb +59 -0
  7. data/lib/ruby_llm/providers/lms/models.rb +44 -12
  8. data/lib/ruby_llm/providers/lms/native_chat/conversation.rb +93 -0
  9. data/lib/ruby_llm/providers/lms/native_chat/streaming.rb +67 -0
  10. data/lib/ruby_llm/providers/lms/native_chat.rb +134 -0
  11. data/lib/ruby_llm/providers/lms/native_v1.rb +97 -0
  12. data/lib/ruby_llm/providers/lms/responses.rb +47 -0
  13. data/lib/ruby_llm/providers/lms/version.rb +15 -0
  14. data/lib/ruby_llm/providers/lms.rb +51 -1
  15. data/models.json +69 -454
  16. metadata +12 -37
  17. data/.flayignore +0 -1
  18. data/.github/workflows/ci.yml +0 -29
  19. data/.github/workflows/gitleaks.yml +0 -22
  20. data/.github/workflows/release.yml +0 -36
  21. data/.overcommit.yml +0 -31
  22. data/.rspec +0 -2
  23. data/.rubocop.yml +0 -29
  24. data/Archspec.rb +0 -14
  25. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_openai_gpt_oss_20b_can_handle_a_multi_turn_conversation.yml +0 -92
  26. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_openai_gpt_oss_20b_can_have_a_basic_conversation.yml +0 -45
  27. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_openai_gpt_oss_20b_can_use_tools.yml +0 -129
  28. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_openai_gpt_oss_20b_returns_the_raw_response.yml +0 -73
  29. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_openai_gpt_oss_20b_supports_streaming_responses.yml +0 -81
  30. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_qwen3_0_6b_bible_assistant_can_have_a_basic_conversation.yml +0 -73
  31. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_qwen3_0_6b_bible_assistant_returns_structured_output.yml +0 -73
  32. data/spec/fixtures/vcr_cassettes/rubyllm_chat_lms_qwen3_0_6b_bible_assistant_returns_the_raw_response.yml +0 -73
  33. data/spec/fixtures/vcr_cassettes/rubyllm_embedding_lms_text_embedding_nomic_embed_text_v1_5_embeds_one_text.yml +0 -828
  34. data/spec/fixtures/vcr_cassettes/rubyllm_embedding_lms_text_embedding_nomic_embed_text_v1_5_embeds_several_texts.yml +0 -2375
  35. data/spec/ruby_llm/chat_schema_spec.rb +0 -30
  36. data/spec/ruby_llm/chat_spec.rb +0 -35
  37. data/spec/ruby_llm/chat_streaming_spec.rb +0 -22
  38. data/spec/ruby_llm/chat_tools_spec.rb +0 -30
  39. data/spec/ruby_llm/embedding_spec.rb +0 -49
  40. data/spec/ruby_llm/image_spec.rb +0 -23
  41. data/spec/ruby_llm/models_spec.rb +0 -11
  42. data/spec/ruby_llm/moderation_spec.rb +0 -22
  43. data/spec/ruby_llm/providers/lms/connection_guard_spec.rb +0 -47
  44. data/spec/ruby_llm/providers/lms_spec.rb +0 -153
  45. data/spec/ruby_llm/rerank_spec.rb +0 -23
  46. data/spec/ruby_llm/speech_spec.rb +0 -25
  47. data/spec/ruby_llm/video_spec.rb +0 -27
  48. data/spec/spec_helper.rb +0 -26
  49. data/spec/support/models.rb +0 -29
  50. data/spec/support/rubyllm_configuration.rb +0 -14
  51. data/spec/support/vcr_configuration.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdaf33f5245f3b78bcfd33a13c7f2a0838149de0998b09c7f8e4256e447cda69
4
- data.tar.gz: 285c1c5ddff4227b90b435755b8cc29b1a28bb695fa33c7f1c6510ce3a5853cb
3
+ metadata.gz: 3644c34d63679aa27bdbb8efc413a9ddc0a6d60dfcd7a93504b14d10dae910c7
4
+ data.tar.gz: 13d0cc4ac01da254166c9169fb3dc5b8daf7fffd4d4b869b58848b26dfc33a1b
5
5
  SHA512:
6
- metadata.gz: 548a88a50a88795f9b5b7cd11c64ee1c43e76406c7730c34c42cf90bf2e748eded77029f38f9994f5ab8820a05d7e0479118e8a43f3dbb165a3bc11e0297a892
7
- data.tar.gz: d01419d61951513cc00dcd72e546f7a56e2023fa59ff1bcadc99e0b117f1bdfab6b06c541078b0a984dede41f025e9668fd00921086b3163c5590654d1d99bc2
6
+ metadata.gz: 4cdd3109e72648dfd1294ea842a5d480b07974780ee2eee791f7a4e40b2a981a914cad85106ac6fba7290836a8bce32018307fd66998f8d413f21538b948a36a
7
+ data.tar.gz: c43720ead841a2a2bc7e7557a6209c83d2f485f65e5e3197c4794e0e894de5c76a636a3316879b5182dc9cd175025a771b3eb9a43b274c16e25d3fb05c86de70
data/CHANGELOG.md ADDED
@@ -0,0 +1,121 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0] - 2026-09-14
9
+
10
+ ### Added
11
+
12
+ - `:native_chat` protocol for LM Studio's native chat API (`POST /api/v1/chat`).
13
+ The endpoint is stateful — LM Studio stores each response and continues from a
14
+ `response_id` — so the protocol sends only the messages newer than the last
15
+ assistant response and points `previous_response_id` at it, which makes ordinary
16
+ multi-turn `RubyLLM::Chat` work on top of it. The id rides on
17
+ `Message#raw_content`, which RubyLLM persists, so a chat reloaded from the
18
+ database continues rather than refusing to replay. Streaming included.
19
+ Native-only options reach the request through `with_provider_options`:
20
+ `integrations:` (MCP plugins or ephemeral MCP servers the server runs itself),
21
+ `context_length:`, `store: false`, and the sampling settings the native schema
22
+ accepts (`top_p`, `top_k`, `min_p`, `repeat_penalty`). The endpoint reports no
23
+ stop reason of its own, so a generation that runs into `max_output_tokens` is
24
+ reported as `finish_reason: :length` from the token counts.
25
+ - `:native_v0` protocol — LM Studio's `POST /api/v0/chat/completions`. Same wire
26
+ shape as the OpenAI-compatible endpoint, but the response carries the `stats`
27
+ block that `/v1/chat/completions` leaves empty (tokens per second, time to first
28
+ token, generation time, stop reason) plus `model_info` and `runtime`, reachable
29
+ through `Message#raw`.
30
+ - `:anthropic` protocol — LM Studio also serves Anthropic's Messages API, driven
31
+ by RubyLLM's stock Anthropic protocol with only the request path adjusted.
32
+ - Model management on the provider, backed by LM Studio's native REST API:
33
+ `native_models`, `loaded_models`, `load_model` (with an optional
34
+ `context_length:` override), `unload_model`, and `download_model`. All three
35
+ writes are sent non-idempotent: RubyLLM retries a POST that times out, and
36
+ LM Studio answers a second load of a resident model by starting a second
37
+ instance, so a replayed load would hold the weights in memory twice.
38
+ - Reasoning control across every protocol that supports it. LM Studio reports
39
+ each model's reasoning vocabulary in its own spelling (`off`, `low`, `medium`,
40
+ `high`, `xhigh`, `on`); the provider translates it into the vocabulary
41
+ RubyLLM's registry reads — `off` becomes the `none` effort, `on` becomes a
42
+ `:toggle` option — so `with_thinking`, `with_thinking(false)` and
43
+ `with_thinking(effort:)` all resolve against what the model actually supports.
44
+ The native endpoint takes a different spelling from the OpenAI ones, so
45
+ `:native_chat` translates `none` back to `off` on the way out.
46
+ - `reasoning` and `tool_choice` capabilities on listed models, alongside the
47
+ `function_calling` and `vision` already derived from the native listing.
48
+ - Model listings read LM Studio's native v1 listing (`/api/v1/models`) when the
49
+ server has one and fall back to the v0 listing otherwise, adding display name,
50
+ description, parameter count, size on disk, quantization bit width, downloaded
51
+ variants and the selected one, reasoning options, and the loaded instance's
52
+ context length and remaining idle TTL to each model's metadata.
53
+ - Embeddings always go to `POST /v1/embeddings`, whichever chat dialect
54
+ `lms_protocol` selects — LM Studio serves them nowhere else, and resolving
55
+ them through the configured chat protocol meant `:anthropic` refused them
56
+ outright.
57
+ - `RubyLLM::Providers::LMS::VERSION` and `RubyLLM::Providers::LMS.version`.
58
+ - Examples 11-15: native inference stats, the Anthropic protocol, the native chat
59
+ protocol, model management, and a protocol capability matrix.
60
+
61
+ ### Fixed
62
+
63
+ - The `:responses` protocol dropped reasoning text. OpenAI never returns raw
64
+ reasoning, only an optional summary, so RubyLLM's stock protocol reads a
65
+ reasoning item's `summary` and the matching
66
+ `response.reasoning_summary_text.delta` event. LM Studio returns the reasoning
67
+ itself in `content` as `reasoning_text`, streamed as
68
+ `response.reasoning_text.delta`, leaving `summary` empty — so the response
69
+ spent reasoning tokens and `message.thinking` came back nil. A
70
+ `LMS::Responses` subclass now reads both shapes, on the sync and streaming
71
+ paths alike.
72
+ - The published gem no longer ships `spec/` and its VCR cassettes, which are
73
+ recorded conversations with the author's own models.
74
+
75
+ ### Changed
76
+
77
+ - Models are named by their LM Studio display name when the server reports one,
78
+ falling back to the model id.
79
+ - The `:responses` protocol is now `RubyLLM::Providers::LMS::Responses` rather
80
+ than RubyLLM's stock `Protocols::Responses`. Behaviour is unchanged apart from
81
+ the reasoning fix above; code that referenced the stock class by name should
82
+ follow.
83
+ - The gemspec reads the version from `lib/ruby_llm/providers/lms/version.rb`
84
+ instead of carrying its own literal.
85
+ - A failing `:live` spec no longer deletes its cassette, which let a real
86
+ regression pass on the next run by re-recording itself green. Pass
87
+ `RERECORD=1` to re-record deliberately.
88
+
89
+ ## [0.1.1] - 2026-09-11
90
+
91
+ ### Added
92
+
93
+ - A friendly `RubyLLM::Error` when the LM Studio server is not running.
94
+ Connection refusals bypass RubyLLM's error middleware, which only maps HTTP
95
+ status codes, so the raw `Faraday::ConnectionFailed` used to surface instead.
96
+ - Examples 01-10, covering basic usage, streaming, tools, structured output,
97
+ embeddings, the model catalog, the `:responses` protocol, the connection guard,
98
+ provider options, and provider introspection.
99
+
100
+ ### Fixed
101
+
102
+ - VCR cassettes replay without `LMS_API_BASE` set, so CI can run them.
103
+
104
+ ### Changed
105
+
106
+ - CI tests only non-EOL Rubies (3.3, 3.4, 4.0).
107
+
108
+ ## [0.1.0] - 2026-09-11
109
+
110
+ ### Added
111
+
112
+ - Initial release: a `:lms` provider for RubyLLM that talks to LM Studio's local
113
+ OpenAI-compatible server (`lms server start`, default
114
+ `http://localhost:1234/v1`) with no API key or configuration required.
115
+ - `:chat_completions` and `:responses` protocols.
116
+ - Model listings enriched from LM Studio's native REST API, plus a packaged
117
+ `models.json` fallback catalog.
118
+
119
+ [0.2.0]: https://github.com/madbomber/ruby_llm-providers-lms/compare/v0.1.1...v0.2.0
120
+ [0.1.1]: https://github.com/madbomber/ruby_llm-providers-lms/compare/v0.1.0...v0.1.1
121
+ [0.1.0]: https://github.com/madbomber/ruby_llm-providers-lms/releases/tag/v0.1.0