llm.rb 11.3.1 → 12.0.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +242 -1
  3. data/LICENSE +92 -17
  4. data/README.md +204 -623
  5. data/data/anthropic.json +433 -249
  6. data/data/bedrock.json +2097 -1055
  7. data/data/deepinfra.json +993 -0
  8. data/data/deepseek.json +53 -28
  9. data/data/google.json +389 -771
  10. data/data/openai.json +1053 -771
  11. data/data/xai.json +133 -292
  12. data/data/zai.json +249 -141
  13. data/lib/llm/active_record/acts_as_agent.rb +3 -41
  14. data/lib/llm/active_record/acts_as_llm.rb +18 -0
  15. data/lib/llm/active_record.rb +3 -3
  16. data/lib/llm/context.rb +9 -5
  17. data/lib/llm/contract/completion.rb +2 -2
  18. data/lib/llm/provider.rb +2 -2
  19. data/lib/llm/providers/deepinfra/audio.rb +66 -0
  20. data/lib/llm/providers/deepinfra/images.rb +90 -0
  21. data/lib/llm/providers/deepinfra/response_adapter.rb +36 -0
  22. data/lib/llm/providers/deepinfra.rb +100 -0
  23. data/lib/llm/providers/deepseek/images.rb +109 -0
  24. data/lib/llm/providers/deepseek/request_adapter.rb +32 -0
  25. data/lib/llm/providers/deepseek/response_adapter/image.rb +9 -0
  26. data/lib/llm/providers/deepseek/response_adapter.rb +29 -0
  27. data/lib/llm/providers/deepseek.rb +4 -2
  28. data/lib/llm/providers/google/request_adapter.rb +22 -5
  29. data/lib/llm/providers/google.rb +4 -4
  30. data/lib/llm/providers/openai/audio.rb +6 -2
  31. data/lib/llm/providers/openai/images.rb +9 -50
  32. data/lib/llm/providers/openai/request_adapter/respond.rb +38 -4
  33. data/lib/llm/providers/openai/response_adapter/audio.rb +5 -1
  34. data/lib/llm/providers/openai/response_adapter/completion.rb +1 -1
  35. data/lib/llm/providers/openai/response_adapter/image.rb +0 -4
  36. data/lib/llm/providers/openai/responses.rb +1 -0
  37. data/lib/llm/providers/openai/stream_parser.rb +5 -6
  38. data/lib/llm/providers/openai.rb +2 -2
  39. data/lib/llm/providers/xai/images.rb +49 -26
  40. data/lib/llm/providers/xai.rb +2 -2
  41. data/lib/llm/response.rb +10 -0
  42. data/lib/llm/schema/leaf.rb +7 -1
  43. data/lib/llm/schema/renderer.rb +121 -0
  44. data/lib/llm/schema.rb +30 -0
  45. data/lib/llm/sequel/agent.rb +2 -43
  46. data/lib/llm/sequel/plugin.rb +25 -7
  47. data/lib/llm/tracer/telemetry.rb +4 -6
  48. data/lib/llm/tracer.rb +9 -21
  49. data/lib/llm/transport/execution.rb +16 -1
  50. data/lib/llm/transport/net_http_adapter.rb +1 -1
  51. data/lib/llm/uridata.rb +16 -0
  52. data/lib/llm/version.rb +1 -1
  53. data/lib/llm.rb +9 -0
  54. data/llm.gemspec +5 -18
  55. data/resources/deepdive.md +798 -264
  56. metadata +15 -18
  57. data/lib/llm/tracer/langsmith.rb +0 -144
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 11.3.1
4
+ version: 12.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - Robert (0x1eef)
7
+ - bsdrobert
8
8
  - Antar Azri
9
9
  - Rodrigo Serrano
10
10
  bindir: bin
@@ -277,20 +277,8 @@ dependencies:
277
277
  - - "~>"
278
278
  - !ruby/object:Gem::Version
279
279
  version: '1.18'
280
- description: |
281
- llm.rb is Ruby's capable AI runtime.
282
-
283
- It runs on Ruby's standard library by default. loads optional pieces
284
- only when needed, and offers a single runtime for providers, agents,
285
- tools, skills, MCP, A2A (Agent2Agent), RAG (vector stores & embeddings),
286
- streaming, files, and persisted state. As a bonus, llm.rb is also available
287
- for mruby.
288
-
289
- It supports OpenAI, OpenAI-compatible endpoints, Anthropic, Google
290
- Gemini, DeepSeek, xAI, Z.ai, AWS Bedrock, Ollama, and llama.cpp. It
291
- also includes built-in ActiveRecord and Sequel support, plus concurrent
292
- tool execution through threads, tasks (via async gem), fibers, ractors,
293
- and fork (via xchan.rb gem).
280
+ description: llm.rb is not a library, framework or toolkit but an advanced runtime
281
+ for building highly capable AI applications on CRuby.
294
282
  email:
295
283
  - robert@r.uby.dev
296
284
  executables: []
@@ -302,6 +290,7 @@ files:
302
290
  - README.md
303
291
  - data/anthropic.json
304
292
  - data/bedrock.json
293
+ - data/deepinfra.json
305
294
  - data/deepseek.json
306
295
  - data/google.json
307
296
  - data/openai.json
@@ -401,9 +390,16 @@ files:
401
390
  - lib/llm/providers/bedrock/signature.rb
402
391
  - lib/llm/providers/bedrock/stream_decoder.rb
403
392
  - lib/llm/providers/bedrock/stream_parser.rb
393
+ - lib/llm/providers/deepinfra.rb
394
+ - lib/llm/providers/deepinfra/audio.rb
395
+ - lib/llm/providers/deepinfra/images.rb
396
+ - lib/llm/providers/deepinfra/response_adapter.rb
404
397
  - lib/llm/providers/deepseek.rb
398
+ - lib/llm/providers/deepseek/images.rb
405
399
  - lib/llm/providers/deepseek/request_adapter.rb
406
400
  - lib/llm/providers/deepseek/request_adapter/completion.rb
401
+ - lib/llm/providers/deepseek/response_adapter.rb
402
+ - lib/llm/providers/deepseek/response_adapter/image.rb
407
403
  - lib/llm/providers/google.rb
408
404
  - lib/llm/providers/google/audio.rb
409
405
  - lib/llm/providers/google/error_handler.rb
@@ -477,6 +473,7 @@ files:
477
473
  - lib/llm/schema/object.rb
478
474
  - lib/llm/schema/one_of.rb
479
475
  - lib/llm/schema/parser.rb
476
+ - lib/llm/schema/renderer.rb
480
477
  - lib/llm/schema/string.rb
481
478
  - lib/llm/schema/version.rb
482
479
  - lib/llm/sequel/agent.rb
@@ -489,7 +486,6 @@ files:
489
486
  - lib/llm/tool.rb
490
487
  - lib/llm/tool/param.rb
491
488
  - lib/llm/tracer.rb
492
- - lib/llm/tracer/langsmith.rb
493
489
  - lib/llm/tracer/logger.rb
494
490
  - lib/llm/tracer/null.rb
495
491
  - lib/llm/tracer/telemetry.rb
@@ -505,6 +501,7 @@ files:
505
501
  - lib/llm/transport/response/http.rb
506
502
  - lib/llm/transport/stream_decoder.rb
507
503
  - lib/llm/transport/utils.rb
504
+ - lib/llm/uridata.rb
508
505
  - lib/llm/usage.rb
509
506
  - lib/llm/utils.rb
510
507
  - lib/llm/version.rb
@@ -514,7 +511,7 @@ files:
514
511
  - resources/deepdive.md
515
512
  homepage: https://r.uby.dev/llm/
516
513
  licenses:
517
- - 0BSD
514
+ - BUSL-1.1
518
515
  metadata:
519
516
  homepage_uri: https://r.uby.dev/llm/
520
517
  source_code_uri: https://github.com/r-uby-dev/llm.rb
@@ -1,144 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LLM
4
- ##
5
- # LangSmith-specific tracer built on top of Telemetry. Supports extra
6
- # inputs/outputs and metadata on traces and spans via {#merge_extra} and
7
- # {#start_trace}(metadata:).
8
- #
9
- # @example Constructor metadata and tags
10
- # llm.tracer = LLM::Tracer::Langsmith.new(
11
- # llm,
12
- # session_id: "123e4567-e89b-12d3-a456-426614174000",
13
- # metadata: {env: "dev"},
14
- # tags: ["changelog"]
15
- # )
16
- #
17
- # @example Per-request extra metadata and inputs (e.g. from chatbot)
18
- # tracer.merge_extra(
19
- # metadata: { turn_id: turn.id, component: "chatbot_message_stream" },
20
- # inputs: { "gen_ai.input.messages" => messages_json }
21
- # )
22
- # bot.chat(prompt)
23
- #
24
- # @example Trace-level metadata via start_trace
25
- # tracer.start_trace(trace_group_id: turn.id, name: "chatbot.turn", metadata: { turn_id: turn.id })
26
- class Tracer::Langsmith < Tracer::Telemetry
27
- THREAD_EXTRA_KEY = :llm_langsmith_extra
28
-
29
- UUID = /\A
30
- [0-9a-f]{8}-
31
- [0-9a-f]{4}-
32
- [1-5][0-9a-f]{3}-
33
- [89ab][0-9a-f]{3}-
34
- [0-9a-f]{12}
35
- \z/ix
36
-
37
- def initialize(provider, options = {})
38
- super
39
- setup_langsmith!(options)
40
- end
41
-
42
- def start_trace(trace_group_id: nil, name: "llm", attributes: {}, metadata: nil)
43
- merge_extra(metadata: metadata) if metadata && !metadata.empty?
44
- super
45
- end
46
-
47
- def stop_trace
48
- clear_thread_extra!
49
- super
50
- end
51
-
52
- def merge_extra(metadata: nil, inputs: nil, outputs: nil)
53
- store = thread_extra
54
- store[:metadata].merge!(metadata) if metadata && !metadata.empty?
55
- store[:inputs].merge!(inputs) if inputs && !inputs.empty?
56
- store[:outputs].merge!(outputs) if outputs && !outputs.empty?
57
- self
58
- end
59
-
60
- def current_extra
61
- store = thread_extra
62
- {
63
- metadata: store[:metadata].dup,
64
- inputs: store[:inputs].dup,
65
- outputs: store[:outputs].dup
66
- }
67
- end
68
-
69
- def consume_extra_inputs
70
- thread_extra[:inputs].tap { thread_extra[:inputs] = {} }
71
- end
72
-
73
- def consume_extra_outputs
74
- thread_extra[:outputs].tap { thread_extra[:outputs] = {} }
75
- end
76
-
77
- private
78
-
79
- def trace_attributes(span_kind:)
80
- attributes = {}
81
- unless @langsmith_session_id.to_s.empty?
82
- attributes["langsmith.trace.session_id"] = @langsmith_session_id
83
- end
84
- merged_metadata = @langsmith_metadata.merge(thread_extra[:metadata])
85
- merged_metadata.each do |key, value|
86
- next if value.nil?
87
-
88
- attr_key = key.to_s.start_with?("langsmith.metadata.") ? key.to_s : "langsmith.metadata.#{key}"
89
- attributes[attr_key] = serialize_langsmith_value(value)
90
- end
91
- unless @langsmith_tags.empty?
92
- attributes["langsmith.span.tags"] = @langsmith_tags.map(&:to_s).join(",")
93
- end
94
- attributes["langsmith.span.kind"] = span_kind
95
- attributes
96
- end
97
-
98
- def thread_extra
99
- Thread.current[THREAD_EXTRA_KEY] ||= {
100
- metadata: {},
101
- inputs: {},
102
- outputs: {}
103
- }
104
- end
105
-
106
- def clear_thread_extra!
107
- Thread.current[THREAD_EXTRA_KEY] = nil
108
- end
109
-
110
- def setup_langsmith!(options)
111
- options ||= {}
112
- @langsmith_metadata = options[:metadata] || {}
113
- @langsmith_session_id = normalize_langsmith_session_id(
114
- options[:session_id],
115
- metadata: @langsmith_metadata
116
- )
117
- @langsmith_tags = options[:tags] || []
118
- end
119
-
120
- def serialize_langsmith_value(value)
121
- case value
122
- when String, Numeric, TrueClass, FalseClass
123
- value
124
- else
125
- LLM.json.dump(value)
126
- end
127
- end
128
-
129
- def normalize_langsmith_session_id(session_id, metadata:)
130
- raw = session_id&.to_s
131
- return nil if raw.to_s.empty?
132
- return raw if uuid?(raw)
133
-
134
- # Keep arbitrary identifiers in metadata instead of forcing
135
- # them into langsmith.trace.session_id, which expects a UUID.
136
- metadata[:session_id] ||= raw
137
- nil
138
- end
139
-
140
- def uuid?(value)
141
- value.match?(UUID)
142
- end
143
- end
144
- end