llm.rb 15.2.2 → 15.4.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 +4 -4
- data/CHANGELOG.md +197 -3
- data/README.md +180 -64
- data/bin/llm.rb +9 -2
- data/data/alibaba.json +45 -0
- data/data/anthropic.json +67 -0
- data/data/bedrock.json +1466 -397
- data/data/deepinfra.json +148 -16
- data/data/deepseek.json +3 -0
- data/data/mistral.json +42 -0
- data/data/openai.json +186 -0
- data/data/openrouter.json +1538 -378
- data/data/xai.json +53 -20
- data/data/zai.json +90 -4
- data/docs/deepdive/advanced/compaction.md +1 -2
- data/docs/deepdive/advanced/context.md +214 -1
- data/docs/deepdive/advanced/guard.md +9 -57
- data/docs/deepdive/features/builtin_tools.md +14 -16
- data/docs/deepdive/features/console.md +5 -0
- data/docs/deepdive/features/database.md +85 -10
- data/docs/deepdive/fundamentals/agents.md +7 -8
- data/docs/deepdive/fundamentals/providers.md +45 -5
- data/docs/deepdive/fundamentals/schema.md +73 -0
- data/docs/deepdive/fundamentals/tools.md +80 -27
- data/docs/deepdive/media/audio.md +8 -19
- data/docs/deepdive/media/images.md +8 -10
- data/docs/deepdive/media/ocr.md +1 -3
- data/docs/deepdive/reference/cost.md +48 -0
- data/docs/deepdive/reference/tracer.md +76 -0
- data/docs/deepdive.md +1 -1
- data/lib/llm/active_record/message.rb +113 -0
- data/lib/llm/active_record.rb +1 -0
- data/lib/llm/agent.rb +44 -19
- data/lib/llm/console/buffer.rb +9 -1
- data/lib/llm/console.rb +6 -1
- data/lib/llm/context/deserializer.rb +10 -3
- data/lib/llm/context.rb +62 -26
- data/lib/llm/guard.rb +2 -8
- data/lib/llm/message.rb +18 -7
- data/lib/llm/provider.rb +74 -16
- data/lib/llm/providers/alibaba.rb +15 -0
- data/lib/llm/providers/anthropic/error_handler.rb +5 -2
- data/lib/llm/providers/anthropic/files.rb +12 -12
- data/lib/llm/providers/anthropic/models.rb +2 -2
- data/lib/llm/providers/anthropic.rb +5 -3
- data/lib/llm/providers/bedrock/error_handler.rb +3 -2
- data/lib/llm/providers/bedrock/models.rb +5 -3
- data/lib/llm/providers/bedrock.rb +5 -3
- data/lib/llm/providers/deepinfra/audio.rb +4 -4
- data/lib/llm/providers/deepinfra/images.rb +4 -4
- data/lib/llm/providers/google/error_handler.rb +5 -2
- data/lib/llm/providers/google/files.rb +10 -10
- data/lib/llm/providers/google/images.rb +2 -2
- data/lib/llm/providers/google/models.rb +2 -2
- data/lib/llm/providers/google.rb +7 -7
- data/lib/llm/providers/mistral.rb +3 -1
- data/lib/llm/providers/ollama/error_handler.rb +5 -2
- data/lib/llm/providers/ollama/models.rb +2 -2
- data/lib/llm/providers/ollama.rb +7 -5
- data/lib/llm/providers/openai/audio.rb +6 -6
- data/lib/llm/providers/openai/error_handler.rb +5 -2
- data/lib/llm/providers/openai/files.rb +10 -10
- data/lib/llm/providers/openai/images.rb +4 -4
- data/lib/llm/providers/openai/models.rb +2 -2
- data/lib/llm/providers/openai/moderations.rb +2 -2
- data/lib/llm/providers/openai/request_adapter.rb +1 -1
- data/lib/llm/providers/openai/responses.rb +8 -8
- data/lib/llm/providers/openai/vector_stores.rb +22 -22
- data/lib/llm/providers/openai.rb +10 -8
- data/lib/llm/providers/xai/images.rb +4 -4
- data/lib/llm/schema.rb +24 -0
- data/lib/llm/tracer/telemetry.rb +4 -4
- data/lib/llm/tracer.rb +11 -3
- data/lib/llm/transport/execution.rb +8 -4
- data/lib/llm/utils.rb +13 -0
- data/lib/llm/version.rb +1 -1
- data/llm.gemspec +2 -2
- metadata +5 -5
- data/lib/llm/guard/loop.rb +0 -89
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: llm.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 15.
|
|
4
|
+
version: 15.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Gleeson
|
|
@@ -429,6 +429,7 @@ files:
|
|
|
429
429
|
- lib/llm/active_record.rb
|
|
430
430
|
- lib/llm/active_record/acts_as_agent.rb
|
|
431
431
|
- lib/llm/active_record/acts_as_llm.rb
|
|
432
|
+
- lib/llm/active_record/message.rb
|
|
432
433
|
- lib/llm/agent.rb
|
|
433
434
|
- lib/llm/buffer.rb
|
|
434
435
|
- lib/llm/compactor.rb
|
|
@@ -492,7 +493,6 @@ files:
|
|
|
492
493
|
- lib/llm/function/thread/task.rb
|
|
493
494
|
- lib/llm/function/tracing.rb
|
|
494
495
|
- lib/llm/guard.rb
|
|
495
|
-
- lib/llm/guard/loop.rb
|
|
496
496
|
- lib/llm/guard/null.rb
|
|
497
497
|
- lib/llm/json_adapter.rb
|
|
498
498
|
- lib/llm/mcp.rb
|
|
@@ -695,8 +695,8 @@ metadata:
|
|
|
695
695
|
source_code_uri: https://github.com/r-uby-dev/llm
|
|
696
696
|
documentation_uri: https://r.uby.dev
|
|
697
697
|
changelog_uri: https://github.com/r-uby-dev/llm/blob/main/CHANGELOG.md
|
|
698
|
-
post_install_message: "\
|
|
699
|
-
|
|
698
|
+
post_install_message: "\nWant to see what I'm building with llm.rb? \nCheckout the
|
|
699
|
+
https://r.uby.dev website.\n\n"
|
|
700
700
|
rdoc_options: []
|
|
701
701
|
require_paths:
|
|
702
702
|
- lib
|
|
@@ -711,7 +711,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
711
711
|
- !ruby/object:Gem::Version
|
|
712
712
|
version: '0'
|
|
713
713
|
requirements: []
|
|
714
|
-
rubygems_version: 4.0.
|
|
714
|
+
rubygems_version: 4.0.16
|
|
715
715
|
specification_version: 4
|
|
716
716
|
summary: Ruby's capable AI runtime
|
|
717
717
|
test_files: []
|
data/lib/llm/guard/loop.rb
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class LLM::Guard
|
|
4
|
-
##
|
|
5
|
-
# {LLM::Guard::Loop LLM::Guard::Loop} is the built-in loop-detection
|
|
6
|
-
# guard. It detects when a context is repeating the same tool-call
|
|
7
|
-
# pattern instead of making progress, and returns an in-band
|
|
8
|
-
# {LLM::Function::Return LLM::Function::Return} so {LLM::Context
|
|
9
|
-
# LLM::Context} can block the pending tool work.
|
|
10
|
-
class Loop < self
|
|
11
|
-
##
|
|
12
|
-
# The default number of repeated tool-call patterns required before
|
|
13
|
-
# the guard intervenes.
|
|
14
|
-
# @return [Integer]
|
|
15
|
-
DEFAULT_THRESHOLD = 3
|
|
16
|
-
|
|
17
|
-
##
|
|
18
|
-
# Checks the current context for repeated tool-call patterns.
|
|
19
|
-
#
|
|
20
|
-
# This method inspects assistant tool calls only. It reduces each call
|
|
21
|
-
# to a `[tool_name, arguments]` signature and checks whether the tail
|
|
22
|
-
# of the sequence is repeating.
|
|
23
|
-
#
|
|
24
|
-
# @param [LLM::Function] function
|
|
25
|
-
# The pending function being decided about. Only its id and name are
|
|
26
|
-
# used to build the return.
|
|
27
|
-
# @param [Integer] threshold
|
|
28
|
-
# How many repeated tool-call patterns must appear at the tail of the
|
|
29
|
-
# sequence before the guard returns a warning.
|
|
30
|
-
# @param [Hash] opts
|
|
31
|
-
# Additional per-call options (ignored).
|
|
32
|
-
# @return [LLM::Function::Return, nil]
|
|
33
|
-
# Returns a tool return that blocks this function's pending call, or
|
|
34
|
-
# nil when execution should continue.
|
|
35
|
-
def call(function:, threshold: DEFAULT_THRESHOLD, **opts)
|
|
36
|
-
repetitions = detect(messages.to_a, threshold)
|
|
37
|
-
return unless repetitions
|
|
38
|
-
function.return(error: true, type: "guard_error", message: warning(repetitions))
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def detect(messages, threshold)
|
|
44
|
-
signatures = extract_signatures(messages)
|
|
45
|
-
return if signatures.size < threshold
|
|
46
|
-
check_repeating_pattern(signatures, threshold)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def warning(repetitions)
|
|
50
|
-
<<~MSG
|
|
51
|
-
SYSTEM NOTICE: Repeated tool-call pattern detected - the same pattern has repeated #{repetitions} times.
|
|
52
|
-
You are stuck in a loop and not making progress. Stop and try a fundamentally different approach:
|
|
53
|
-
- Re-read the relevant context before retrying
|
|
54
|
-
- Try a different tool or strategy
|
|
55
|
-
- Break the problem into smaller steps
|
|
56
|
-
- If a tool keeps failing, investigate why before retrying
|
|
57
|
-
MSG
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def extract_signatures(messages)
|
|
61
|
-
messages
|
|
62
|
-
.select(&:assistant?)
|
|
63
|
-
.flat_map { |message| message.functions.map { [_1.name.to_s, _1.arguments.to_h] } }
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def check_repeating_pattern(sequence, threshold)
|
|
67
|
-
max_pattern_len = sequence.size / threshold
|
|
68
|
-
(1..max_pattern_len).each do |pattern_len|
|
|
69
|
-
count = count_tail_repetitions(sequence, pattern_len)
|
|
70
|
-
return count if count >= threshold
|
|
71
|
-
end
|
|
72
|
-
nil
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def count_tail_repetitions(sequence, length)
|
|
76
|
-
return 0 if sequence.size < length
|
|
77
|
-
pattern = sequence.last(length)
|
|
78
|
-
count = 1
|
|
79
|
-
pos = sequence.size - length
|
|
80
|
-
while pos >= length
|
|
81
|
-
candidate = sequence[(pos - length)...pos]
|
|
82
|
-
break unless candidate == pattern
|
|
83
|
-
count += 1
|
|
84
|
-
pos -= length
|
|
85
|
-
end
|
|
86
|
-
count
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|