llm.rb 13.0.0 → 14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +505 -14
- data/README.md +484 -50
- data/bin/llm.rb +148 -0
- data/data/anthropic.json +206 -263
- data/data/bedrock.json +2138 -1860
- data/data/deepinfra.json +1003 -624
- data/data/deepseek.json +38 -34
- data/data/google.json +1079 -371
- data/data/mistral.json +448 -368
- data/data/moonshot.json +384 -0
- data/data/openai.json +974 -1343
- data/data/xai.json +154 -126
- data/data/zai.json +191 -191
- data/lib/llm/agent.rb +123 -20
- data/lib/llm/context.rb +71 -88
- data/lib/llm/cost.rb +23 -17
- data/lib/llm/error.rb +0 -8
- data/lib/llm/function/array.rb +3 -3
- data/lib/llm/function/async/task.rb +2 -0
- data/lib/llm/function/fiber/task.rb +2 -0
- data/lib/llm/function/fork/task.rb +2 -0
- data/lib/llm/function/ractor/task.rb +2 -0
- data/lib/llm/function/sequential/group.rb +4 -1
- data/lib/llm/function/sequential/task.rb +1 -1
- data/lib/llm/function/task.rb +4 -0
- data/lib/llm/function/thread/task.rb +2 -0
- data/lib/llm/function.rb +33 -6
- data/lib/llm/guard/loop.rb +89 -0
- data/lib/llm/guard/null.rb +19 -0
- data/lib/llm/guard.rb +61 -0
- data/lib/llm/provider.rb +36 -0
- data/lib/llm/providers/anthropic/stream_parser.rb +1 -0
- data/lib/llm/providers/anthropic.rb +2 -9
- data/lib/llm/providers/bedrock/request_adapter.rb +1 -1
- data/lib/llm/providers/bedrock/stream_parser.rb +1 -0
- data/lib/llm/providers/bedrock.rb +1 -8
- data/lib/llm/providers/google/stream_parser.rb +1 -0
- data/lib/llm/providers/google.rb +1 -8
- data/lib/llm/providers/mistral.rb +1 -1
- data/lib/llm/providers/moonshot.rb +76 -0
- data/lib/llm/providers/ollama.rb +2 -9
- data/lib/llm/providers/openai/responses/stream_parser.rb +1 -0
- data/lib/llm/providers/openai/responses.rb +7 -9
- data/lib/llm/providers/openai/stream_parser.rb +1 -0
- data/lib/llm/providers/openai.rb +4 -11
- data/lib/llm/repl/bar.rb +4 -3
- data/lib/llm/repl/{transcript.rb → buffer.rb} +69 -29
- data/lib/llm/repl/color.rb +78 -0
- data/lib/llm/repl/command.rb +12 -5
- data/lib/llm/repl/commands/compact.rb +2 -2
- data/lib/llm/repl/commands/help.rb +3 -5
- data/lib/llm/repl/input/char.rb +46 -0
- data/lib/llm/repl/input/row.rb +39 -0
- data/lib/llm/repl/input.rb +251 -66
- data/lib/llm/repl/markdown/table.rb +11 -3
- data/lib/llm/repl/markdown.rb +34 -8
- data/lib/llm/repl/node.rb +37 -0
- data/lib/llm/repl/status.rb +42 -7
- data/lib/llm/repl/stream.rb +18 -6
- data/lib/llm/repl/walker.rb +3 -2
- data/lib/llm/repl/window.rb +54 -35
- data/lib/llm/repl.rb +74 -32
- data/lib/llm/skill.rb +20 -4
- data/lib/llm/stream.rb +8 -7
- data/lib/llm/tool.rb +29 -0
- data/lib/llm/tools/{swap_text.rb → edit-file.rb} +3 -3
- data/lib/llm/tools/git.rb +3 -0
- data/lib/llm/tools/mkdir.rb +3 -0
- data/lib/llm/tools/rg.rb +3 -0
- data/lib/llm/tools/ruby.rb +46 -0
- data/lib/llm/tools/shell.rb +3 -0
- data/lib/llm/tracer/pretty_logger.rb +127 -0
- data/lib/llm/tracer.rb +1 -0
- data/lib/llm/transformer/null.rb +21 -0
- data/lib/llm/transformer.rb +55 -0
- data/lib/llm/version.rb +1 -1
- data/lib/llm.rb +12 -2
- data/llm.gemspec +9 -2
- data/resources/deepdive/advanced/cancellation.md +74 -0
- data/resources/deepdive/advanced/compaction.md +83 -0
- data/resources/deepdive/advanced/context.md +267 -0
- data/resources/deepdive/advanced/guard.md +371 -0
- data/resources/deepdive/advanced/tracer.md +180 -0
- data/resources/deepdive/advanced/transformer.md +67 -0
- data/resources/deepdive/advanced/transports.md +45 -0
- data/resources/deepdive/everything_else/audio.md +122 -0
- data/resources/deepdive/everything_else/cost.md +99 -0
- data/resources/deepdive/everything_else/images.md +89 -0
- data/resources/deepdive/everything_else/object.md +108 -0
- data/resources/deepdive/everything_else/ocr.md +48 -0
- data/resources/deepdive/fundamentals/agents.md +202 -0
- data/resources/deepdive/fundamentals/builtin_tools.md +191 -0
- data/resources/deepdive/fundamentals/concurrency.md +104 -0
- data/resources/deepdive/fundamentals/database.md +449 -0
- data/resources/deepdive/fundamentals/embeddings.md +157 -0
- data/resources/deepdive/fundamentals/repl.md +87 -0
- data/resources/deepdive/fundamentals/schema.md +61 -0
- data/resources/deepdive/fundamentals/skills.md +106 -0
- data/resources/deepdive/fundamentals/stream.md +110 -0
- data/resources/deepdive/fundamentals/tools.md +265 -0
- data/resources/deepdive/protocols/a2a.md +106 -0
- data/resources/deepdive/protocols/mcp.md +111 -0
- data/resources/deepdive.md +58 -1792
- metadata +51 -7
- data/lib/llm/loop_guard.rb +0 -107
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:
|
|
4
|
+
version: 14.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- robert
|
|
@@ -280,23 +280,26 @@ dependencies:
|
|
|
280
280
|
description: |
|
|
281
281
|
llm.rb is an advanced runtime for building capable AI applications
|
|
282
282
|
on CRuby. By default it has zero runtime dependencies although certain
|
|
283
|
-
functionality
|
|
283
|
+
functionality (such as ActiveRecord support) require
|
|
284
284
|
optional dependencies that are opt-in.
|
|
285
285
|
email:
|
|
286
286
|
- robert@r.uby.dev
|
|
287
|
-
executables:
|
|
287
|
+
executables:
|
|
288
|
+
- llm.rb
|
|
288
289
|
extensions: []
|
|
289
290
|
extra_rdoc_files: []
|
|
290
291
|
files:
|
|
291
292
|
- CHANGELOG.md
|
|
292
293
|
- LICENSE
|
|
293
294
|
- README.md
|
|
295
|
+
- bin/llm.rb
|
|
294
296
|
- data/anthropic.json
|
|
295
297
|
- data/bedrock.json
|
|
296
298
|
- data/deepinfra.json
|
|
297
299
|
- data/deepseek.json
|
|
298
300
|
- data/google.json
|
|
299
301
|
- data/mistral.json
|
|
302
|
+
- data/moonshot.json
|
|
300
303
|
- data/openai.json
|
|
301
304
|
- data/xai.json
|
|
302
305
|
- data/zai.json
|
|
@@ -355,8 +358,10 @@ files:
|
|
|
355
358
|
- lib/llm/function/thread/group.rb
|
|
356
359
|
- lib/llm/function/thread/task.rb
|
|
357
360
|
- lib/llm/function/tracing.rb
|
|
361
|
+
- lib/llm/guard.rb
|
|
362
|
+
- lib/llm/guard/loop.rb
|
|
363
|
+
- lib/llm/guard/null.rb
|
|
358
364
|
- lib/llm/json_adapter.rb
|
|
359
|
-
- lib/llm/loop_guard.rb
|
|
360
365
|
- lib/llm/mcp.rb
|
|
361
366
|
- lib/llm/mcp/command.rb
|
|
362
367
|
- lib/llm/mcp/error.rb
|
|
@@ -433,6 +438,7 @@ files:
|
|
|
433
438
|
- lib/llm/providers/mistral.rb
|
|
434
439
|
- lib/llm/providers/mistral/request_adapter.rb
|
|
435
440
|
- lib/llm/providers/mistral/request_adapter/completion.rb
|
|
441
|
+
- lib/llm/providers/moonshot.rb
|
|
436
442
|
- lib/llm/providers/ollama.rb
|
|
437
443
|
- lib/llm/providers/ollama/error_handler.rb
|
|
438
444
|
- lib/llm/providers/ollama/models.rb
|
|
@@ -475,16 +481,20 @@ files:
|
|
|
475
481
|
- lib/llm/registry.rb
|
|
476
482
|
- lib/llm/repl.rb
|
|
477
483
|
- lib/llm/repl/bar.rb
|
|
484
|
+
- lib/llm/repl/buffer.rb
|
|
485
|
+
- lib/llm/repl/color.rb
|
|
478
486
|
- lib/llm/repl/command.rb
|
|
479
487
|
- lib/llm/repl/commands/compact.rb
|
|
480
488
|
- lib/llm/repl/commands/exit.rb
|
|
481
489
|
- lib/llm/repl/commands/help.rb
|
|
482
490
|
- lib/llm/repl/input.rb
|
|
491
|
+
- lib/llm/repl/input/char.rb
|
|
492
|
+
- lib/llm/repl/input/row.rb
|
|
483
493
|
- lib/llm/repl/markdown.rb
|
|
484
494
|
- lib/llm/repl/markdown/table.rb
|
|
495
|
+
- lib/llm/repl/node.rb
|
|
485
496
|
- lib/llm/repl/status.rb
|
|
486
497
|
- lib/llm/repl/stream.rb
|
|
487
|
-
- lib/llm/repl/transcript.rb
|
|
488
498
|
- lib/llm/repl/walker.rb
|
|
489
499
|
- lib/llm/repl/window.rb
|
|
490
500
|
- lib/llm/response.rb
|
|
@@ -517,21 +527,25 @@ files:
|
|
|
517
527
|
- lib/llm/tool/param.rb
|
|
518
528
|
- lib/llm/tools.rb
|
|
519
529
|
- lib/llm/tools/chdir.rb
|
|
530
|
+
- lib/llm/tools/edit-file.rb
|
|
520
531
|
- lib/llm/tools/git.rb
|
|
521
532
|
- lib/llm/tools/ls.rb
|
|
522
533
|
- lib/llm/tools/mkdir.rb
|
|
523
534
|
- lib/llm/tools/pwd.rb
|
|
524
535
|
- lib/llm/tools/read_file.rb
|
|
525
536
|
- lib/llm/tools/rg.rb
|
|
537
|
+
- lib/llm/tools/ruby.rb
|
|
526
538
|
- lib/llm/tools/shell.rb
|
|
527
|
-
- lib/llm/tools/swap_text.rb
|
|
528
539
|
- lib/llm/tools/utils.rb
|
|
529
540
|
- lib/llm/tools/which.rb
|
|
530
541
|
- lib/llm/tools/write_file.rb
|
|
531
542
|
- lib/llm/tracer.rb
|
|
532
543
|
- lib/llm/tracer/logger.rb
|
|
533
544
|
- lib/llm/tracer/null.rb
|
|
545
|
+
- lib/llm/tracer/pretty_logger.rb
|
|
534
546
|
- lib/llm/tracer/telemetry.rb
|
|
547
|
+
- lib/llm/transformer.rb
|
|
548
|
+
- lib/llm/transformer/null.rb
|
|
535
549
|
- lib/llm/transport.rb
|
|
536
550
|
- lib/llm/transport/curb.rb
|
|
537
551
|
- lib/llm/transport/execution.rb
|
|
@@ -552,6 +566,30 @@ files:
|
|
|
552
566
|
- lib/sequel/plugins/llm.rb
|
|
553
567
|
- llm.gemspec
|
|
554
568
|
- resources/deepdive.md
|
|
569
|
+
- resources/deepdive/advanced/cancellation.md
|
|
570
|
+
- resources/deepdive/advanced/compaction.md
|
|
571
|
+
- resources/deepdive/advanced/context.md
|
|
572
|
+
- resources/deepdive/advanced/guard.md
|
|
573
|
+
- resources/deepdive/advanced/tracer.md
|
|
574
|
+
- resources/deepdive/advanced/transformer.md
|
|
575
|
+
- resources/deepdive/advanced/transports.md
|
|
576
|
+
- resources/deepdive/everything_else/audio.md
|
|
577
|
+
- resources/deepdive/everything_else/cost.md
|
|
578
|
+
- resources/deepdive/everything_else/images.md
|
|
579
|
+
- resources/deepdive/everything_else/object.md
|
|
580
|
+
- resources/deepdive/everything_else/ocr.md
|
|
581
|
+
- resources/deepdive/fundamentals/agents.md
|
|
582
|
+
- resources/deepdive/fundamentals/builtin_tools.md
|
|
583
|
+
- resources/deepdive/fundamentals/concurrency.md
|
|
584
|
+
- resources/deepdive/fundamentals/database.md
|
|
585
|
+
- resources/deepdive/fundamentals/embeddings.md
|
|
586
|
+
- resources/deepdive/fundamentals/repl.md
|
|
587
|
+
- resources/deepdive/fundamentals/schema.md
|
|
588
|
+
- resources/deepdive/fundamentals/skills.md
|
|
589
|
+
- resources/deepdive/fundamentals/stream.md
|
|
590
|
+
- resources/deepdive/fundamentals/tools.md
|
|
591
|
+
- resources/deepdive/protocols/a2a.md
|
|
592
|
+
- resources/deepdive/protocols/mcp.md
|
|
555
593
|
homepage: https://r.uby.dev/llm/
|
|
556
594
|
licenses:
|
|
557
595
|
- MIT
|
|
@@ -560,6 +598,11 @@ metadata:
|
|
|
560
598
|
source_code_uri: https://github.com/r-uby-dev/llm.rb
|
|
561
599
|
documentation_uri: https://r.uby.dev/llm/
|
|
562
600
|
changelog_uri: https://r.uby.dev/api-docs/llm.rb/file.CHANGELOG.html
|
|
601
|
+
post_install_message: |2+
|
|
602
|
+
|
|
603
|
+
Learn more about llm.rb by reading the deepdive:
|
|
604
|
+
https://r.uby.dev/llm/deepdive
|
|
605
|
+
|
|
563
606
|
rdoc_options: []
|
|
564
607
|
require_paths:
|
|
565
608
|
- lib
|
|
@@ -574,7 +617,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
574
617
|
- !ruby/object:Gem::Version
|
|
575
618
|
version: '0'
|
|
576
619
|
requirements: []
|
|
577
|
-
rubygems_version: 4.0.
|
|
620
|
+
rubygems_version: 4.0.16
|
|
578
621
|
specification_version: 4
|
|
579
622
|
summary: Ruby's capable AI runtime
|
|
580
623
|
test_files: []
|
|
624
|
+
...
|
data/lib/llm/loop_guard.rb
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
##
|
|
4
|
-
# {LLM::LoopGuard LLM::LoopGuard} is the built-in implementation of
|
|
5
|
-
# llm.rb's `guard` capability.
|
|
6
|
-
#
|
|
7
|
-
# A guard is a context-level supervisor for agentic execution. It can inspect
|
|
8
|
-
# the current runtime state and return a warning string when pending tool work
|
|
9
|
-
# should be blocked before the loop keeps going.
|
|
10
|
-
#
|
|
11
|
-
# {LLM::LoopGuard LLM::LoopGuard} detects when a context is repeating the same
|
|
12
|
-
# tool-call pattern instead of making progress.
|
|
13
|
-
#
|
|
14
|
-
# The public interface is intentionally small:
|
|
15
|
-
# - `call(ctx)` returns `nil` when no intervention is needed
|
|
16
|
-
# - `call(ctx)` returns a warning string when pending tool execution should be blocked
|
|
17
|
-
#
|
|
18
|
-
# {LLM::Context LLM::Context} can use that warning to return in-band
|
|
19
|
-
# {LLM::GuardError LLM::GuardError} tool errors, and
|
|
20
|
-
# {LLM::Agent LLM::Agent} enables this guard by default through its wrapped
|
|
21
|
-
# context.
|
|
22
|
-
#
|
|
23
|
-
class LLM::LoopGuard
|
|
24
|
-
##
|
|
25
|
-
# The default number of repeated tool-call patterns required before
|
|
26
|
-
# the guard intervenes.
|
|
27
|
-
# @return [Integer]
|
|
28
|
-
DEFAULT_THRESHOLD = 3
|
|
29
|
-
|
|
30
|
-
##
|
|
31
|
-
# Returns the repetition threshold.
|
|
32
|
-
# @return [Integer]
|
|
33
|
-
attr_reader :threshold
|
|
34
|
-
|
|
35
|
-
##
|
|
36
|
-
# @param [Hash] config
|
|
37
|
-
# @option config [Integer] :threshold
|
|
38
|
-
# How many repeated tool-call patterns must appear at the tail of the
|
|
39
|
-
# sequence before the guard returns a warning.
|
|
40
|
-
def initialize(config = {})
|
|
41
|
-
@threshold = config.fetch(:threshold, DEFAULT_THRESHOLD)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
##
|
|
45
|
-
# Checks the current context for repeated tool-call patterns.
|
|
46
|
-
#
|
|
47
|
-
# This method inspects assistant tool calls only. It reduces each call to a
|
|
48
|
-
# `[tool_name, arguments]` signature and checks whether the tail of the
|
|
49
|
-
# sequence is repeating.
|
|
50
|
-
#
|
|
51
|
-
# @param [LLM::Context] ctx
|
|
52
|
-
# @return [String, nil]
|
|
53
|
-
# Returns a warning string when pending tool execution should be blocked,
|
|
54
|
-
# or `nil` when execution should continue.
|
|
55
|
-
def call(ctx)
|
|
56
|
-
repetitions = detect(ctx.messages.to_a)
|
|
57
|
-
repetitions ? warning(repetitions) : nil
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def detect(messages)
|
|
63
|
-
signatures = extract_signatures(messages)
|
|
64
|
-
return if signatures.size < threshold
|
|
65
|
-
check_repeating_pattern(signatures)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def warning(repetitions)
|
|
69
|
-
<<~MSG
|
|
70
|
-
SYSTEM NOTICE: Repeated tool-call pattern detected - the same pattern has repeated #{repetitions} times.
|
|
71
|
-
You are stuck in a loop and not making progress. Stop and try a fundamentally different approach:
|
|
72
|
-
- Re-read the relevant context before retrying
|
|
73
|
-
- Try a different tool or strategy
|
|
74
|
-
- Break the problem into smaller steps
|
|
75
|
-
- If a tool keeps failing, investigate why before retrying
|
|
76
|
-
MSG
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def extract_signatures(messages)
|
|
80
|
-
messages
|
|
81
|
-
.select { _1.respond_to?(:functions) && _1.assistant? }
|
|
82
|
-
.flat_map { |message| message.functions.map { [_1.name.to_s, _1.arguments.to_s] } }
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def check_repeating_pattern(sequence)
|
|
86
|
-
max_pattern_len = sequence.size / threshold
|
|
87
|
-
(1..max_pattern_len).each do |pattern_len|
|
|
88
|
-
count = count_tail_repetitions(sequence, pattern_len)
|
|
89
|
-
return count if count >= threshold
|
|
90
|
-
end
|
|
91
|
-
nil
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def count_tail_repetitions(sequence, length)
|
|
95
|
-
return 0 if sequence.size < length
|
|
96
|
-
pattern = sequence.last(length)
|
|
97
|
-
count = 1
|
|
98
|
-
pos = sequence.size - length
|
|
99
|
-
while pos >= length
|
|
100
|
-
candidate = sequence[(pos - length)...pos]
|
|
101
|
-
break unless candidate == pattern
|
|
102
|
-
count += 1
|
|
103
|
-
pos -= length
|
|
104
|
-
end
|
|
105
|
-
count
|
|
106
|
-
end
|
|
107
|
-
end
|