llm-shell 0.9.2 → 0.10.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 (258) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +61 -66
  3. data/lib/llm/shell/command.rb +40 -40
  4. data/lib/llm/shell/commands/clear_screen.rb +4 -18
  5. data/lib/llm/shell/commands/debug_mode.rb +12 -0
  6. data/lib/llm/shell/commands/dir_import.rb +4 -20
  7. data/lib/llm/shell/commands/disable_tool.rb +33 -0
  8. data/lib/llm/shell/commands/enable_tool.rb +33 -0
  9. data/lib/llm/shell/commands/file_import.rb +4 -20
  10. data/lib/llm/shell/commands/help.rb +23 -36
  11. data/lib/llm/shell/commands/show_chat.rb +4 -19
  12. data/lib/llm/shell/commands/show_version.rb +4 -20
  13. data/lib/llm/shell/commands/system_prompt.rb +4 -18
  14. data/lib/llm/shell/completion.rb +5 -5
  15. data/lib/llm/shell/config.rb +4 -5
  16. data/lib/llm/shell/formatter.rb +1 -2
  17. data/lib/llm/shell/internal/coderay/lib/coderay/duo.rb +81 -0
  18. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/_map.rb +17 -0
  19. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/comment_filter.rb +25 -0
  20. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/count.rb +39 -0
  21. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/debug.rb +49 -0
  22. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/debug_lint.rb +63 -0
  23. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/div.rb +23 -0
  24. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/encoder.rb +190 -0
  25. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/filter.rb +58 -0
  26. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html/css.rb +65 -0
  27. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html/numbering.rb +108 -0
  28. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html/output.rb +164 -0
  29. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html.rb +333 -0
  30. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/json.rb +83 -0
  31. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/lines_of_code.rb +45 -0
  32. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/lint.rb +59 -0
  33. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/null.rb +18 -0
  34. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/page.rb +24 -0
  35. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/span.rb +23 -0
  36. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/statistic.rb +95 -0
  37. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/terminal.rb +195 -0
  38. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/text.rb +46 -0
  39. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/token_kind_filter.rb +111 -0
  40. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/xml.rb +72 -0
  41. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/yaml.rb +50 -0
  42. data/lib/llm/shell/internal/coderay/lib/coderay/encoders.rb +18 -0
  43. data/lib/llm/shell/internal/coderay/lib/coderay/for_redcloth.rb +95 -0
  44. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/file_type.rb +151 -0
  45. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/plugin.rb +55 -0
  46. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/plugin_host.rb +221 -0
  47. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/word_list.rb +72 -0
  48. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/_map.rb +24 -0
  49. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/c.rb +189 -0
  50. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/clojure.rb +217 -0
  51. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/cpp.rb +217 -0
  52. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/css.rb +196 -0
  53. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/debug.rb +75 -0
  54. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/delphi.rb +144 -0
  55. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/diff.rb +221 -0
  56. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/erb.rb +81 -0
  57. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/go.rb +208 -0
  58. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/groovy.rb +268 -0
  59. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/haml.rb +168 -0
  60. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/html.rb +275 -0
  61. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/java/builtin_types.rb +421 -0
  62. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/java.rb +174 -0
  63. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/java_script.rb +236 -0
  64. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/json.rb +98 -0
  65. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/lua.rb +280 -0
  66. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/php.rb +527 -0
  67. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/python.rb +287 -0
  68. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/raydebug.rb +75 -0
  69. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/ruby/patterns.rb +178 -0
  70. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/ruby/string_state.rb +79 -0
  71. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/ruby.rb +477 -0
  72. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/sass.rb +232 -0
  73. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/scanner.rb +337 -0
  74. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/sql.rb +169 -0
  75. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/taskpaper.rb +36 -0
  76. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/text.rb +26 -0
  77. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/xml.rb +17 -0
  78. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/yaml.rb +140 -0
  79. data/lib/llm/shell/internal/coderay/lib/coderay/scanners.rb +27 -0
  80. data/lib/llm/shell/internal/coderay/lib/coderay/styles/_map.rb +7 -0
  81. data/lib/llm/shell/internal/coderay/lib/coderay/styles/alpha.rb +153 -0
  82. data/lib/llm/shell/internal/coderay/lib/coderay/styles/style.rb +18 -0
  83. data/lib/llm/shell/internal/coderay/lib/coderay/styles.rb +15 -0
  84. data/lib/llm/shell/internal/coderay/lib/coderay/token_kinds.rb +85 -0
  85. data/lib/llm/shell/internal/coderay/lib/coderay/tokens.rb +164 -0
  86. data/lib/llm/shell/internal/coderay/lib/coderay/tokens_proxy.rb +55 -0
  87. data/lib/llm/shell/internal/coderay/lib/coderay/version.rb +3 -0
  88. data/lib/llm/shell/internal/coderay/lib/coderay.rb +284 -0
  89. data/lib/llm/shell/internal/io-line/lib/io/line/multiple.rb +19 -0
  90. data/lib/{io → llm/shell/internal/io-line/lib/io}/line.rb +2 -0
  91. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/builder.rb +31 -0
  92. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/conversable.rb +37 -0
  93. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/prompt/completion.rb +49 -0
  94. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/prompt/respond.rb +49 -0
  95. data/lib/llm/shell/internal/llm.rb/lib/llm/bot.rb +150 -0
  96. data/lib/llm/shell/internal/llm.rb/lib/llm/buffer.rb +162 -0
  97. data/lib/llm/shell/internal/llm.rb/lib/llm/client.rb +36 -0
  98. data/lib/llm/shell/internal/llm.rb/lib/llm/error.rb +49 -0
  99. data/lib/llm/shell/internal/llm.rb/lib/llm/eventhandler.rb +44 -0
  100. data/lib/llm/shell/internal/llm.rb/lib/llm/eventstream/event.rb +69 -0
  101. data/lib/llm/shell/internal/llm.rb/lib/llm/eventstream/parser.rb +88 -0
  102. data/lib/llm/shell/internal/llm.rb/lib/llm/eventstream.rb +8 -0
  103. data/lib/llm/shell/internal/llm.rb/lib/llm/file.rb +91 -0
  104. data/lib/llm/shell/internal/llm.rb/lib/llm/function.rb +177 -0
  105. data/lib/llm/shell/internal/llm.rb/lib/llm/message.rb +178 -0
  106. data/lib/llm/shell/internal/llm.rb/lib/llm/mime.rb +140 -0
  107. data/lib/llm/shell/internal/llm.rb/lib/llm/multipart.rb +101 -0
  108. data/lib/llm/shell/internal/llm.rb/lib/llm/object/builder.rb +38 -0
  109. data/lib/llm/shell/internal/llm.rb/lib/llm/object/kernel.rb +53 -0
  110. data/lib/llm/shell/internal/llm.rb/lib/llm/object.rb +89 -0
  111. data/lib/llm/shell/internal/llm.rb/lib/llm/provider.rb +352 -0
  112. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/error_handler.rb +36 -0
  113. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/files.rb +155 -0
  114. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/format/completion_format.rb +88 -0
  115. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/format.rb +29 -0
  116. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/models.rb +54 -0
  117. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/completion.rb +39 -0
  118. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/enumerable.rb +11 -0
  119. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/file.rb +23 -0
  120. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/web_search.rb +21 -0
  121. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/stream_parser.rb +66 -0
  122. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic.rb +138 -0
  123. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/deepseek/format/completion_format.rb +68 -0
  124. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/deepseek/format.rb +27 -0
  125. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/deepseek.rb +75 -0
  126. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/audio.rb +73 -0
  127. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/error_handler.rb +47 -0
  128. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/files.rb +146 -0
  129. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/format/completion_format.rb +69 -0
  130. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/format.rb +39 -0
  131. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/images.rb +133 -0
  132. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/models.rb +60 -0
  133. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/completion.rb +35 -0
  134. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/embedding.rb +8 -0
  135. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/file.rb +11 -0
  136. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/files.rb +15 -0
  137. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/image.rb +31 -0
  138. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/models.rb +15 -0
  139. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/web_search.rb +22 -0
  140. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/stream_parser.rb +86 -0
  141. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini.rb +173 -0
  142. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/llamacpp.rb +74 -0
  143. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/error_handler.rb +36 -0
  144. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/format/completion_format.rb +77 -0
  145. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/format.rb +29 -0
  146. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/models.rb +56 -0
  147. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/response/completion.rb +28 -0
  148. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/response/embedding.rb +9 -0
  149. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/stream_parser.rb +44 -0
  150. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama.rb +116 -0
  151. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/audio.rb +91 -0
  152. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/error_handler.rb +46 -0
  153. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/files.rb +134 -0
  154. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format/completion_format.rb +90 -0
  155. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format/moderation_format.rb +35 -0
  156. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format/respond_format.rb +72 -0
  157. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format.rb +54 -0
  158. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/images.rb +109 -0
  159. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/models.rb +55 -0
  160. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/moderations.rb +65 -0
  161. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/audio.rb +7 -0
  162. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/completion.rb +40 -0
  163. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/embedding.rb +9 -0
  164. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/enumerable.rb +23 -0
  165. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/file.rb +7 -0
  166. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/image.rb +16 -0
  167. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/moderations.rb +34 -0
  168. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/responds.rb +48 -0
  169. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/web_search.rb +21 -0
  170. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/responses/stream_parser.rb +76 -0
  171. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/responses.rb +99 -0
  172. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/stream_parser.rb +86 -0
  173. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/vector_stores.rb +228 -0
  174. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai.rb +206 -0
  175. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/xai/images.rb +58 -0
  176. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/xai.rb +72 -0
  177. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/zai.rb +74 -0
  178. data/lib/llm/shell/internal/llm.rb/lib/llm/response.rb +67 -0
  179. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/array.rb +26 -0
  180. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/boolean.rb +13 -0
  181. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/integer.rb +43 -0
  182. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/leaf.rb +78 -0
  183. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/null.rb +13 -0
  184. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/number.rb +43 -0
  185. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/object.rb +41 -0
  186. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/string.rb +34 -0
  187. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/version.rb +8 -0
  188. data/lib/llm/shell/internal/llm.rb/lib/llm/schema.rb +81 -0
  189. data/lib/llm/shell/internal/llm.rb/lib/llm/server_tool.rb +32 -0
  190. data/lib/llm/shell/internal/llm.rb/lib/llm/tool/param.rb +75 -0
  191. data/lib/llm/shell/internal/llm.rb/lib/llm/tool.rb +78 -0
  192. data/lib/llm/shell/internal/llm.rb/lib/llm/utils.rb +19 -0
  193. data/lib/llm/shell/internal/llm.rb/lib/llm/version.rb +5 -0
  194. data/lib/llm/shell/internal/llm.rb/lib/llm.rb +121 -0
  195. data/lib/llm/shell/internal/optparse/lib/optionparser.rb +2 -0
  196. data/lib/llm/shell/internal/optparse/lib/optparse/ac.rb +70 -0
  197. data/lib/llm/shell/internal/optparse/lib/optparse/date.rb +18 -0
  198. data/lib/llm/shell/internal/optparse/lib/optparse/kwargs.rb +27 -0
  199. data/lib/llm/shell/internal/optparse/lib/optparse/shellwords.rb +7 -0
  200. data/lib/llm/shell/internal/optparse/lib/optparse/time.rb +11 -0
  201. data/lib/llm/shell/internal/optparse/lib/optparse/uri.rb +7 -0
  202. data/lib/llm/shell/internal/optparse/lib/optparse/version.rb +80 -0
  203. data/lib/llm/shell/internal/optparse/lib/optparse.rb +2469 -0
  204. data/lib/llm/shell/internal/paint/lib/paint/constants.rb +104 -0
  205. data/lib/llm/shell/internal/paint/lib/paint/pa.rb +13 -0
  206. data/lib/llm/shell/internal/paint/lib/paint/rgb_colors.rb +14 -0
  207. data/lib/llm/shell/internal/paint/lib/paint/shortcuts.rb +100 -0
  208. data/lib/llm/shell/internal/paint/lib/paint/shortcuts_version.rb +5 -0
  209. data/lib/llm/shell/internal/paint/lib/paint/util.rb +16 -0
  210. data/lib/llm/shell/internal/paint/lib/paint/version.rb +5 -0
  211. data/lib/llm/shell/internal/paint/lib/paint.rb +261 -0
  212. data/lib/llm/shell/internal/reline/lib/reline/config.rb +378 -0
  213. data/lib/llm/shell/internal/reline/lib/reline/face.rb +199 -0
  214. data/lib/llm/shell/internal/reline/lib/reline/history.rb +76 -0
  215. data/lib/llm/shell/internal/reline/lib/reline/io/ansi.rb +322 -0
  216. data/lib/llm/shell/internal/reline/lib/reline/io/dumb.rb +120 -0
  217. data/lib/llm/shell/internal/reline/lib/reline/io/windows.rb +530 -0
  218. data/lib/llm/shell/internal/reline/lib/reline/io.rb +55 -0
  219. data/lib/llm/shell/internal/reline/lib/reline/key_actor/base.rb +37 -0
  220. data/lib/llm/shell/internal/reline/lib/reline/key_actor/composite.rb +17 -0
  221. data/lib/llm/shell/internal/reline/lib/reline/key_actor/emacs.rb +517 -0
  222. data/lib/llm/shell/internal/reline/lib/reline/key_actor/vi_command.rb +518 -0
  223. data/lib/llm/shell/internal/reline/lib/reline/key_actor/vi_insert.rb +517 -0
  224. data/lib/llm/shell/internal/reline/lib/reline/key_actor.rb +8 -0
  225. data/lib/llm/shell/internal/reline/lib/reline/key_stroke.rb +119 -0
  226. data/lib/llm/shell/internal/reline/lib/reline/kill_ring.rb +125 -0
  227. data/lib/llm/shell/internal/reline/lib/reline/line_editor.rb +2356 -0
  228. data/lib/llm/shell/internal/reline/lib/reline/unicode/east_asian_width.rb +1292 -0
  229. data/lib/llm/shell/internal/reline/lib/reline/unicode.rb +421 -0
  230. data/lib/llm/shell/internal/reline/lib/reline/version.rb +3 -0
  231. data/lib/llm/shell/internal/reline/lib/reline.rb +527 -0
  232. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/generated_parser.rb +712 -0
  233. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/handler.rb +268 -0
  234. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/local_date.rb +35 -0
  235. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/local_date_time.rb +42 -0
  236. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/local_time.rb +40 -0
  237. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/parser.rb +21 -0
  238. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/scanner.rb +92 -0
  239. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/string_utils.rb +40 -0
  240. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/version.rb +5 -0
  241. data/lib/llm/shell/internal/tomlrb/lib/tomlrb.rb +49 -0
  242. data/lib/llm/shell/options.rb +1 -1
  243. data/lib/llm/shell/renderer.rb +2 -3
  244. data/lib/llm/shell/repl.rb +21 -16
  245. data/lib/llm/shell/tool.rb +42 -0
  246. data/lib/llm/shell/tools/read_file.rb +15 -0
  247. data/lib/llm/shell/tools/system.rb +17 -0
  248. data/lib/llm/shell/tools/write_file.rb +16 -0
  249. data/lib/llm/shell/version.rb +1 -1
  250. data/lib/llm/shell.rb +83 -39
  251. data/libexec/llm-shell/shell +4 -6
  252. data/llm-shell.gemspec +0 -4
  253. metadata +233 -63
  254. data/lib/llm/function.rb +0 -17
  255. data/lib/llm/shell/command/extension.rb +0 -42
  256. data/lib/llm/shell/commands/utils.rb +0 -21
  257. data/lib/llm/shell/functions/read_file.rb +0 -22
  258. data/lib/llm/shell/functions/write_file.rb +0 -22
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ ##
5
+ # {LLM::Buffer LLM::Buffer} provides an Enumerable object that
6
+ # yields each message in a conversation on-demand, and only sends
7
+ # a request to the LLM when a response is needed.
8
+ class Buffer
9
+ include Enumerable
10
+
11
+ ##
12
+ # @param [LLM::Provider] provider
13
+ # @return [LLM::Buffer]
14
+ def initialize(provider)
15
+ @provider = provider
16
+ @pending = []
17
+ @completed = []
18
+ end
19
+
20
+ ##
21
+ # @yield [LLM::Message]
22
+ # Yields each message in the conversation thread
23
+ # @raise (see LLM::Provider#complete)
24
+ # @return [void]
25
+ def each(...)
26
+ if block_given?
27
+ empty! unless @pending.empty?
28
+ @completed.each { yield(_1) }
29
+ else
30
+ enum_for(:each, ...)
31
+ end
32
+ end
33
+
34
+ ##
35
+ # Returns an array of unread messages
36
+ # @see LLM::Message#read?
37
+ # @see LLM::Message#read!
38
+ # @return [Array<LLM::Message>]
39
+ def unread
40
+ reject(&:read?)
41
+ end
42
+
43
+ ##
44
+ # Find a message (in descending order)
45
+ # @return [LLM::Message, nil]
46
+ def find(...)
47
+ reverse_each.find(...)
48
+ end
49
+
50
+ ##
51
+ # Returns the last message(s) in the buffer
52
+ # @param [Integer, nil] n
53
+ # The number of messages to return
54
+ # @return [LLM::Message, Array<LLM::Message>, nil]
55
+ def last(n = nil)
56
+ if @pending.empty?
57
+ n.nil? ? @completed.last : @completed.last(n)
58
+ else
59
+ n.nil? ? to_a.last : to_a.last(n)
60
+ end
61
+ end
62
+
63
+ ##
64
+ # @param [[LLM::Message, Hash, Symbol]] item
65
+ # A message and its parameters
66
+ # @return [void]
67
+ def <<(item)
68
+ @pending << item
69
+ self
70
+ end
71
+ alias_method :push, :<<
72
+
73
+ ##
74
+ # @param [Integer, Range] index
75
+ # The message index
76
+ # @return [LLM::Message, nil]
77
+ # Returns a message, or nil
78
+ def [](index)
79
+ if @pending.empty?
80
+ if Range === index
81
+ slice = @completed[index]
82
+ (slice.nil? || slice.size < index.size) ? to_a[index] : slice
83
+ else
84
+ @completed[index]
85
+ end
86
+ else
87
+ to_a[index]
88
+ end
89
+ end
90
+
91
+ ##
92
+ # @return [String]
93
+ def inspect
94
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} " \
95
+ "completed_count=#{@completed.size} pending_count=#{@pending.size}>"
96
+ end
97
+
98
+ ##
99
+ # Returns true when the buffer is empty
100
+ # @return [Boolean]
101
+ def empty?
102
+ @pending.empty? and @completed.empty?
103
+ end
104
+
105
+ ##
106
+ # @example
107
+ # llm = LLM.openai(key: ENV["KEY"])
108
+ # bot = LLM::Bot.new(llm, stream: $stdout)
109
+ # bot.chat "Hello", role: :user
110
+ # bot.messages.flush
111
+ # @see LLM::Bot#drain
112
+ # @note
113
+ # This method is especially useful when using the streaming API.
114
+ # Drains the buffer and returns all messages as an array
115
+ # @return [Array<LLM::Message>]
116
+ def drain
117
+ to_a
118
+ end
119
+ alias_method :flush, :drain
120
+
121
+ private
122
+
123
+ def empty!
124
+ message, params, method = @pending.pop
125
+ if method == :complete
126
+ complete!(message, params)
127
+ elsif method == :respond
128
+ respond!(message, params)
129
+ else
130
+ raise LLM::Error, "Unknown method: #{method}"
131
+ end
132
+ end
133
+
134
+ def complete!(message, params)
135
+ oldparams = @pending.map { _1[1] }
136
+ pendings = @pending.map { _1[0] }
137
+ messages = [*@completed, *pendings]
138
+ role = message.role
139
+ completion = @provider.complete(
140
+ message.content,
141
+ [*oldparams, params.merge(role:, messages:)].inject({}, &:merge!)
142
+ )
143
+ @completed.concat([*pendings, message, *completion.choices[0]])
144
+ @pending.clear
145
+ end
146
+
147
+ def respond!(message, params)
148
+ oldparams = @pending.map { _1[1] }
149
+ pendings = @pending.map { _1[0] }
150
+ messages = [*pendings]
151
+ role = message.role
152
+ params = [
153
+ *oldparams,
154
+ params.merge(input: messages),
155
+ @response ? {previous_response_id: @response.response_id} : {}
156
+ ].inject({}, &:merge!)
157
+ @response = @provider.responses.create(message.content, params.merge(role:))
158
+ @completed.concat([*pendings, message, *@response.choices[0]])
159
+ @pending.clear
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ ##
5
+ # @api private
6
+ module Client
7
+ private
8
+
9
+ ##
10
+ # @api private
11
+ def persistent_client
12
+ LLM.lock(:clients) do
13
+ if clients[client_id]
14
+ clients[client_id]
15
+ else
16
+ require "net/http/persistent" unless defined?(Net::HTTP::Persistent)
17
+ client = Net::HTTP::Persistent.new(name: self.class.name)
18
+ client.read_timeout = timeout
19
+ clients[client_id] = client
20
+ end
21
+ end
22
+ end
23
+
24
+ ##
25
+ # @api private
26
+ def transient_client
27
+ client = Net::HTTP.new(host, port)
28
+ client.read_timeout = timeout
29
+ client.use_ssl = ssl
30
+ client
31
+ end
32
+
33
+ def client_id = "#{host}:#{port}:#{timeout}:#{ssl}"
34
+ def clients = self.class.clients
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ ##
5
+ # The superclass of all LLM errors
6
+ class Error < RuntimeError
7
+ def initialize(...)
8
+ block_given? ? yield(self) : nil
9
+ super
10
+ end
11
+ end
12
+
13
+ ##
14
+ # The superclass of all HTTP protocol errors
15
+ class ResponseError < Error
16
+ ##
17
+ # @return [Net::HTTPResponse]
18
+ # Returns the response associated with an error
19
+ attr_accessor :response
20
+
21
+ def message
22
+ [super, response.body].join("\n")
23
+ end
24
+ end
25
+
26
+ ##
27
+ # HTTPUnauthorized
28
+ UnauthorizedError = Class.new(ResponseError)
29
+
30
+ ##
31
+ # HTTPTooManyRequests
32
+ RateLimitError = Class.new(ResponseError)
33
+
34
+ ##
35
+ # HTTPServerError
36
+ ServerError = Class.new(ResponseError)
37
+
38
+ ##
39
+ # When no images are found in a response
40
+ NoImageError = Class.new(ResponseError)
41
+
42
+ ##
43
+ # When an given an input object that is not understood
44
+ FormatError = Class.new(Error)
45
+
46
+ ##
47
+ # When given a prompt object that is not understood
48
+ PromptError = Class.new(FormatError)
49
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ ##
5
+ # @private
6
+ class EventHandler
7
+ ##
8
+ # @param [#parse!] parser
9
+ # @return [LLM::EventHandler]
10
+ def initialize(parser)
11
+ @parser = parser
12
+ end
13
+
14
+ ##
15
+ # "data:" event callback
16
+ # @param [LLM::EventStream::Event] event
17
+ # @return [void]
18
+ def on_data(event)
19
+ return if event.end?
20
+ chunk = JSON.parse(event.value)
21
+ @parser.parse!(chunk)
22
+ rescue JSON::ParserError
23
+ end
24
+
25
+ ##
26
+ # Callback for when *any* of chunk of data
27
+ # is received, regardless of whether it has
28
+ # a field name or not. Primarily for ollama,
29
+ # which does emit Server-Sent Events (SSE).
30
+ # @param [LLM::EventStream::Event] event
31
+ # @return [void]
32
+ def on_chunk(event)
33
+ return if event.end?
34
+ chunk = JSON.parse(event.chunk)
35
+ @parser.parse!(chunk)
36
+ rescue JSON::ParserError
37
+ end
38
+
39
+ ##
40
+ # Returns a fully constructed response body
41
+ # @return [LLM::Object]
42
+ def body = @parser.body
43
+ end
44
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM::EventStream
4
+ ##
5
+ # @private
6
+ class Event
7
+ FIELD_REGEXP = /[^:]+/
8
+ VALUE_REGEXP = /(?<=: ).+/
9
+
10
+ ##
11
+ # Returns the field name
12
+ # @return [Symbol]
13
+ attr_reader :field
14
+
15
+ ##
16
+ # Returns the field value
17
+ # @return [String]
18
+ attr_reader :value
19
+
20
+ ##
21
+ # Returns the full chunk
22
+ # @return [String]
23
+ attr_reader :chunk
24
+
25
+ ##
26
+ # @param [String] chunk
27
+ # @return [LLM::EventStream::Event]
28
+ def initialize(chunk)
29
+ @field = chunk[FIELD_REGEXP]
30
+ @value = chunk[VALUE_REGEXP]
31
+ @chunk = chunk
32
+ end
33
+
34
+ ##
35
+ # Returns true when the event represents an "id" chunk
36
+ # @return [Boolean]
37
+ def id?
38
+ @field == "id"
39
+ end
40
+
41
+ ##
42
+ # Returns true when the event represents a "data" chunk
43
+ # @return [Boolean]
44
+ def data?
45
+ @field == "data"
46
+ end
47
+
48
+ ##
49
+ # Returns true when the event represents an "event" chunk
50
+ # @return [Boolean]
51
+ def event?
52
+ @field == "event"
53
+ end
54
+
55
+ ##
56
+ # Returns true when the event represents a "retry" chunk
57
+ # @return [Boolean]
58
+ def retry?
59
+ @field == "retry"
60
+ end
61
+
62
+ ##
63
+ # Returns true when a chunk represents the end of the stream
64
+ # @return [Boolean]
65
+ def end?
66
+ @value == "[DONE]"
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM::EventStream
4
+ ##
5
+ # @private
6
+ class Parser
7
+ ##
8
+ # @return [LLM::EventStream::Parser]
9
+ def initialize
10
+ @buffer = StringIO.new
11
+ @events = Hash.new { |h, k| h[k] = [] }
12
+ @offset = 0
13
+ @visitors = []
14
+ end
15
+
16
+ ##
17
+ # Register a visitor
18
+ # @param [#on_data] visitor
19
+ # @return [void]
20
+ def register(visitor)
21
+ @visitors << visitor
22
+ end
23
+
24
+ ##
25
+ # Subscribe to an event
26
+ # @param [Symbol] evtname
27
+ # @param [Proc] block
28
+ # @return [void]
29
+ def on(evtname, &block)
30
+ @events[evtname.to_s] << block
31
+ end
32
+
33
+ ##
34
+ # Append an event to the internal buffer
35
+ # @return [void]
36
+ def <<(event)
37
+ io = StringIO.new(event)
38
+ IO.copy_stream io, @buffer
39
+ each_line { parse!(_1) }
40
+ end
41
+
42
+ ##
43
+ # Returns the internal buffer
44
+ # @return [String]
45
+ def body
46
+ @buffer.string
47
+ end
48
+
49
+ ##
50
+ # Free the internal buffer
51
+ # @return [void]
52
+ def free
53
+ @buffer.truncate(0)
54
+ @buffer.rewind
55
+ end
56
+
57
+ private
58
+
59
+ def parse!(event)
60
+ event = Event.new(event)
61
+ dispatch(event)
62
+ end
63
+
64
+ def dispatch(event)
65
+ @visitors.each { dispatch_visitor(_1, event) }
66
+ @events[event.field].each { _1.call(event) }
67
+ end
68
+
69
+ def dispatch_visitor(visitor, event)
70
+ method = "on_#{event.field}"
71
+ if visitor.respond_to?(method)
72
+ visitor.public_send(method, event)
73
+ elsif visitor.respond_to?("on_chunk")
74
+ visitor.on_chunk(event)
75
+ end
76
+ end
77
+
78
+ def each_line
79
+ string.each_line.with_index do
80
+ next if _2 < @offset
81
+ yield(_1)
82
+ @offset += 1
83
+ end
84
+ end
85
+
86
+ def string = @buffer.string
87
+ end
88
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @private
5
+ module LLM::EventStream
6
+ require_relative "eventstream/parser"
7
+ require_relative "eventstream/event"
8
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # {LLM::File LLM::File} represents a local file. It can be used
5
+ # as a prompt with certain providers (eg: Ollama, Gemini),
6
+ # and as an input with certain methods. It is usually not necessary
7
+ # to create an instance of LLM::File directly.
8
+ class LLM::File
9
+ ##
10
+ # @return [String]
11
+ # Returns the path to the file
12
+ attr_reader :path
13
+
14
+ def initialize(path)
15
+ @path = path
16
+ end
17
+
18
+ ##
19
+ # @return [String]
20
+ # Returns basename of the file
21
+ def basename
22
+ File.basename(path)
23
+ end
24
+
25
+ ##
26
+ # @return [String]
27
+ # Returns the MIME type of the file
28
+ def mime_type
29
+ LLM::Mime[path]
30
+ end
31
+
32
+ ##
33
+ # @return [Boolean]
34
+ # Returns true if the file is an image
35
+ def image?
36
+ mime_type.start_with?("image/")
37
+ end
38
+
39
+ ##
40
+ # @return [Boolean]
41
+ # Returns true if the file is a PDF document
42
+ def pdf?
43
+ mime_type == "application/pdf"
44
+ end
45
+
46
+ ##
47
+ # @return [Integer]
48
+ # Returns the size of the file in bytes
49
+ def bytesize
50
+ File.size(path)
51
+ end
52
+
53
+ ##
54
+ # @return [String]
55
+ # Returns the file contents in base64
56
+ def to_b64
57
+ [File.binread(path)].pack("m0")
58
+ end
59
+
60
+ ##
61
+ # @return [String]
62
+ # Returns the file contents in base64 URL format
63
+ def to_data_uri
64
+ "data:#{mime_type};base64,#{to_b64}"
65
+ end
66
+
67
+ ##
68
+ # @return [File]
69
+ # Yields an IO object suitable to be streamed
70
+ def with_io
71
+ io = File.open(path, "rb")
72
+ yield(io)
73
+ ensure
74
+ io.close
75
+ end
76
+ end
77
+
78
+ ##
79
+ # @param [String, File, LLM::Response] obj
80
+ # The path to the file, or an existing file reference
81
+ # @return [LLM::File]
82
+ def LLM.File(obj)
83
+ case obj
84
+ when File
85
+ obj.close unless obj.closed?
86
+ LLM.File(obj.path)
87
+ when LLM::File, LLM::Response then obj
88
+ when String then LLM::File.new(obj)
89
+ else raise TypeError, "don't know how to handle #{obj.class} objects"
90
+ end
91
+ end