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,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The {LLM::Function LLM::Function} class represents a local
5
+ # function that can be called by an LLM.
6
+ #
7
+ # @example example #1
8
+ # LLM.function(:system) do |fn|
9
+ # fn.name "system"
10
+ # fn.description "Runs system commands"
11
+ # fn.params do |schema|
12
+ # schema.object(command: schema.string.required)
13
+ # end
14
+ # fn.define do |command:|
15
+ # {success: Kernel.system(command)}
16
+ # end
17
+ # end
18
+ #
19
+ # @example example #2
20
+ # class System < LLM::Tool
21
+ # name "system"
22
+ # description "Runs system commands"
23
+ # params do |schema|
24
+ # schema.object(command: schema.string.required)
25
+ # end
26
+ #
27
+ # def call(command:)
28
+ # {success: Kernel.system(command)}
29
+ # end
30
+ # end
31
+ class LLM::Function
32
+ class Return < Struct.new(:id, :name, :value)
33
+ end
34
+
35
+ ##
36
+ # Returns the function ID
37
+ # @return [String, nil]
38
+ attr_accessor :id
39
+
40
+ ##
41
+ # Returns function arguments
42
+ # @return [Array, nil]
43
+ attr_accessor :arguments
44
+
45
+ ##
46
+ # @param [String] name The function name
47
+ # @yieldparam [LLM::Function] self The function object
48
+ def initialize(name, &b)
49
+ @name = name
50
+ @schema = LLM::Schema.new
51
+ @called = false
52
+ @cancelled = false
53
+ yield(self) if block_given?
54
+ end
55
+
56
+ ##
57
+ # Set (or get) the function name
58
+ # @param [String] name The function name
59
+ # @return [void]
60
+ def name(name = nil)
61
+ if name
62
+ @name = name.to_s
63
+ else
64
+ @name
65
+ end
66
+ end
67
+
68
+ ##
69
+ # Set (or get) the function description
70
+ # @param [String] desc The function description
71
+ # @return [void]
72
+ def description(desc = nil)
73
+ if desc
74
+ @description = desc
75
+ else
76
+ @description
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Set (or get) the function parameters
82
+ # @yieldparam [LLM::Schema] schema The schema object
83
+ # @return [void]
84
+ def params
85
+ if block_given?
86
+ if @params
87
+ @params.merge!(yield(@schema))
88
+ else
89
+ @params = yield(@schema)
90
+ end
91
+ else
92
+ @params
93
+ end
94
+ end
95
+
96
+ ##
97
+ # Set the function implementation
98
+ # @param [Proc, Class] b The function implementation
99
+ # @return [void]
100
+ def define(klass = nil, &b)
101
+ @runner = klass || b
102
+ end
103
+ alias_method :register, :define
104
+
105
+ ##
106
+ # Call the function
107
+ # @return [LLM::Function::Return] The result of the function call
108
+ def call
109
+ runner = ((Class === @runner) ? @runner.new : @runner)
110
+ Return.new(id, name, runner.call(**arguments))
111
+ ensure
112
+ @called = true
113
+ end
114
+
115
+ ##
116
+ # Returns a value that communicates that the function call was cancelled
117
+ # @example
118
+ # llm = LLM.openai(key: ENV["KEY"])
119
+ # bot = LLM::Bot.new(llm, tools: [fn1, fn2])
120
+ # bot.chat "I want to run the functions"
121
+ # bot.chat bot.functions.map(&:cancel)
122
+ # @return [LLM::Function::Return]
123
+ def cancel(reason: "function call cancelled")
124
+ Return.new(id, name, {cancelled: true, reason:})
125
+ ensure
126
+ @cancelled = true
127
+ end
128
+
129
+ ##
130
+ # Returns true when a function has been called
131
+ # @return [Boolean]
132
+ def called?
133
+ @called
134
+ end
135
+
136
+ ##
137
+ # Returns true when a function has been cancelled
138
+ # @return [Boolean]
139
+ def cancelled?
140
+ @cancelled
141
+ end
142
+
143
+ ##
144
+ # Returns true when a function has neither been called nor cancelled
145
+ # @return [Boolean]
146
+ def pending?
147
+ !@called && !@cancelled
148
+ end
149
+
150
+ ##
151
+ # @return [Hash]
152
+ def format(provider)
153
+ case provider.class.to_s
154
+ when "LLM::Gemini"
155
+ {name: @name, description: @description, parameters: @params}.compact
156
+ when "LLM::Anthropic"
157
+ {name: @name, description: @description, input_schema: @params}.compact
158
+ else
159
+ format_openai(provider)
160
+ end
161
+ end
162
+
163
+ def format_openai(provider)
164
+ case provider.class.to_s
165
+ when "LLM::OpenAI::Responses"
166
+ {
167
+ type: "function", name: @name, description: @description,
168
+ parameters: @params.to_h.merge(additionalProperties: false), strict: true
169
+ }.compact
170
+ else
171
+ {
172
+ type: "function", name: @name,
173
+ function: {name: @name, description: @description, parameters: @params}
174
+ }.compact
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ class Message
5
+ ##
6
+ # Returns the role of the message
7
+ # @return [Symbol]
8
+ attr_reader :role
9
+
10
+ ##
11
+ # Returns the content of the message
12
+ # @return [String]
13
+ attr_reader :content
14
+
15
+ ##
16
+ # Returns extra context associated with the message
17
+ # @return [Hash]
18
+ attr_reader :extra
19
+
20
+ ##
21
+ # Returns a new message
22
+ # @param [Symbol] role
23
+ # @param [String] content
24
+ # @param [Hash] extra
25
+ # @return [LLM::Message]
26
+ def initialize(role, content, extra = {})
27
+ @role = role.to_s
28
+ @content = content
29
+ @extra = extra
30
+ end
31
+
32
+ ##
33
+ # Returns a hash representation of the message
34
+ # @return [Hash]
35
+ def to_h
36
+ {role:, content:}
37
+ end
38
+
39
+ ##
40
+ # Returns true when two objects have the same role and content
41
+ # @param [Object] other
42
+ # The other object to compare
43
+ # @return [Boolean]
44
+ def ==(other)
45
+ if other.respond_to?(:to_h)
46
+ to_h == other.to_h
47
+ else
48
+ false
49
+ end
50
+ end
51
+ alias_method :eql?, :==
52
+
53
+ ##
54
+ # Try to parse the content as JSON
55
+ # @return [Hash]
56
+ def content!
57
+ JSON.parse(content)
58
+ end
59
+
60
+ ##
61
+ # @return [Array<LLM::Function>]
62
+ def functions
63
+ @functions ||= tool_calls.map do |fn|
64
+ function = tools.find { _1.name.to_s == fn["name"] }.dup
65
+ function.tap { _1.id = fn.id }
66
+ function.tap { _1.arguments = fn.arguments }
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Marks the message as read
72
+ # @return [void]
73
+ def read!
74
+ @read = true
75
+ end
76
+
77
+ ##
78
+ # Returns true when the message has been read
79
+ # @return [Boolean]
80
+ def read?
81
+ @read
82
+ end
83
+
84
+ ##
85
+ # Returns true when the message is an assistant message
86
+ # @return [Boolean]
87
+ def assistant?
88
+ role == "assistant" || role == "model"
89
+ end
90
+
91
+ ##
92
+ # Returns true when the message is a system message
93
+ # @return [Boolean]
94
+ def system?
95
+ role == "system"
96
+ end
97
+
98
+ ##
99
+ # Returns true when the message is a user message
100
+ # @return [Boolean]
101
+ def user?
102
+ role == "user"
103
+ end
104
+
105
+ ##
106
+ # @return [Boolean]
107
+ # Returns true when the message requests a function call
108
+ def tool_call?
109
+ tool_calls.any?
110
+ end
111
+
112
+ ##
113
+ # @return [Boolean]
114
+ # Returns true when the message represents a function return
115
+ def tool_return?
116
+ LLM::Function::Return === content ||
117
+ [*content].grep(LLM::Function::Return).any?
118
+ end
119
+
120
+ ##
121
+ # @note
122
+ # This method returns a response for assistant messages,
123
+ # and it returns nil for non-assistant messages
124
+ # @return [LLM::Response, nil]
125
+ # Returns the response associated with the message, or nil
126
+ def response
127
+ extra[:response]
128
+ end
129
+
130
+ ##
131
+ # @note
132
+ # This method might return annotations for assistant messages,
133
+ # and it returns an empty array for non-assistant messages
134
+ # Returns annotations associated with the message
135
+ # @return [Array<LLM::Object>]
136
+ def annotations
137
+ @annotations ||= LLM::Object.from_hash(extra["annotations"] || [])
138
+ end
139
+
140
+ ##
141
+ # @note
142
+ # This method returns token usage for assistant messages,
143
+ # and it returns an empty object for non-assistant messages
144
+ # Returns token usage statistics
145
+ # @return [LLM::Object]
146
+ def usage
147
+ @usage ||= if response
148
+ LLM::Object.from_hash({
149
+ input_tokens: response.prompt_tokens || 0,
150
+ output_tokens: response.completion_tokens || 0,
151
+ total_tokens: response.total_tokens || 0
152
+ })
153
+ else
154
+ LLM::Object.from_hash({})
155
+ end
156
+ end
157
+ alias_method :token_usage, :usage
158
+
159
+ ##
160
+ # Returns a string representation of the message
161
+ # @return [String]
162
+ def inspect
163
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} " \
164
+ "tool_call=#{tool_calls.any?} role=#{role.inspect} " \
165
+ "content=#{content.inspect}>"
166
+ end
167
+
168
+ private
169
+
170
+ def tool_calls
171
+ @tool_calls ||= LLM::Object.from_hash(@extra[:tool_calls] || [])
172
+ end
173
+
174
+ def tools
175
+ response&.__tools__ || []
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @private
5
+ class LLM::Mime
6
+ EXTNAME = /\A\.[a-zA-Z0-9]+\z/
7
+ private_constant :EXTNAME
8
+
9
+ ##
10
+ # Lookup a mime type
11
+ # @return [String, nil]
12
+ def self.[](key)
13
+ key = key.respond_to?(:path) ? key.path : key
14
+ extname = (key =~ EXTNAME) ? key : File.extname(key)
15
+ types[extname] || "application/octet-stream"
16
+ end
17
+
18
+ ##
19
+ # Returns a Hash of mime types
20
+ # @return [Hash]
21
+ def self.types
22
+ @types ||= {
23
+ # Images
24
+ ".png" => "image/png",
25
+ ".jpg" => "image/jpeg",
26
+ ".jpeg" => "image/jpeg",
27
+ ".webp" => "image/webp",
28
+ ".gif" => "image/gif",
29
+ ".bmp" => "image/bmp",
30
+ ".tif" => "image/tiff",
31
+ ".tiff" => "image/tiff",
32
+ ".svg" => "image/svg+xml",
33
+ ".ico" => "image/x-icon",
34
+ ".apng" => "image/apng",
35
+ ".jfif" => "image/jpeg",
36
+ ".heic" => "image/heic",
37
+
38
+ # Videos
39
+ ".flv" => "video/x-flv",
40
+ ".mov" => "video/quicktime",
41
+ ".mpeg" => "video/mpeg",
42
+ ".mpg" => "video/mpeg",
43
+ ".mp4" => "video/mp4",
44
+ ".webm" => "video/webm",
45
+ ".wmv" => "video/x-ms-wmv",
46
+ ".3gp" => "video/3gpp",
47
+ ".avi" => "video/x-msvideo",
48
+ ".mkv" => "video/x-matroska",
49
+ ".ogv" => "video/ogg",
50
+ ".m4v" => "video/x-m4v",
51
+ ".m2ts" => "video/mp2t",
52
+ ".mts" => "video/mp2t",
53
+
54
+ # Audio
55
+ ".aac" => "audio/aac",
56
+ ".flac" => "audio/flac",
57
+ ".mp3" => "audio/mpeg",
58
+ ".m4a" => "audio/mp4",
59
+ ".mpga" => "audio/mpeg",
60
+ ".opus" => "audio/opus",
61
+ ".pcm" => "audio/L16",
62
+ ".wav" => "audio/wav",
63
+ ".weba" => "audio/webm",
64
+ ".oga" => "audio/ogg",
65
+ ".ogg" => "audio/ogg",
66
+ ".mid" => "audio/midi",
67
+ ".midi" => "audio/midi",
68
+ ".aiff" => "audio/aiff",
69
+ ".aif" => "audio/aiff",
70
+ ".amr" => "audio/amr",
71
+ ".mka" => "audio/x-matroska",
72
+ ".caf" => "audio/x-caf",
73
+
74
+ # Documents
75
+ ".pdf" => "application/pdf",
76
+ ".txt" => "text/plain",
77
+ ".md" => "text/markdown",
78
+ ".markdown" => "text/markdown",
79
+ ".mkd" => "text/markdown",
80
+ ".doc" => "application/msword",
81
+ ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
82
+ ".xls" => "application/vnd.ms-excel",
83
+ ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
84
+ ".ppt" => "application/vnd.ms-powerpoint",
85
+ ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
86
+ ".csv" => "text/csv",
87
+ ".json" => "application/json",
88
+ ".xml" => "application/xml",
89
+ ".html" => "text/html",
90
+ ".htm" => "text/html",
91
+ ".odt" => "application/vnd.oasis.opendocument.text",
92
+ ".odp" => "application/vnd.oasis.opendocument.presentation",
93
+ ".ods" => "application/vnd.oasis.opendocument.spreadsheet",
94
+ ".rtf" => "application/rtf",
95
+ ".epub" => "application/epub+zip",
96
+
97
+ # Code
98
+ ".js" => "application/javascript",
99
+ ".jsx" => "text/jsx",
100
+ ".ts" => "application/typescript",
101
+ ".tsx" => "text/tsx",
102
+ ".css" => "text/css",
103
+ ".c" => "text/x-c",
104
+ ".cpp" => "text/x-c++",
105
+ ".h" => "text/x-c",
106
+ ".rb" => "text/x-ruby",
107
+ ".py" => "text/x-python",
108
+ ".java" => "text/x-java-source",
109
+ ".sh" => "application/x-sh",
110
+ ".php" => "application/x-httpd-php",
111
+ ".yml" => "text/yaml",
112
+ ".yaml" => "text/yaml",
113
+ ".go" => "text/x-go",
114
+ ".rs" => "text/rust",
115
+
116
+ # Fonts
117
+ ".woff" => "font/woff",
118
+ ".woff2" => "font/woff2",
119
+ ".ttf" => "font/ttf",
120
+ ".otf" => "font/otf",
121
+
122
+ # Archives
123
+ ".zip" => "application/zip",
124
+ ".tar" => "application/x-tar",
125
+ ".gz" => "application/gzip",
126
+ ".bz2" => "application/x-bzip2",
127
+ ".xz" => "application/x-xz",
128
+ ".rar" => "application/vnd.rar",
129
+ ".7z" => "application/x-7z-compressed",
130
+ ".tar.gz" => "application/gzip",
131
+ ".tar.bz2" => "application/x-bzip2",
132
+ ".apk" => "application/vnd.android.package-archive",
133
+ ".exe" => "application/x-msdownload",
134
+
135
+ # Others
136
+ ".ics" => "text/calendar",
137
+ ".vcf" => "text/vcard"
138
+ }
139
+ end
140
+ end
@@ -0,0 +1,101 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ ##
5
+ # @private
6
+ class LLM::Multipart
7
+ require "securerandom"
8
+
9
+ ##
10
+ # @return [String]
11
+ attr_reader :boundary
12
+
13
+ ##
14
+ # @param [Hash] params
15
+ # Request parameters
16
+ # @return [LLM::Multipart]
17
+ def initialize(params)
18
+ @boundary = "BOUNDARY__#{SecureRandom.hex(16)}"
19
+ @params = params
20
+ end
21
+
22
+ ##
23
+ # Returns the multipart content type
24
+ # @return [String]
25
+ def content_type
26
+ "multipart/form-data; boundary=#{@boundary}"
27
+ end
28
+
29
+ ##
30
+ # Returns the multipart request body
31
+ # @return [String]
32
+ def body
33
+ io = StringIO.new("".b)
34
+ [*parts, StringIO.new("--#{@boundary}--\r\n".b)].each { IO.copy_stream(_1.tap(&:rewind), io) }
35
+ io.tap(&:rewind)
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :params
41
+
42
+ def file(locals, file)
43
+ locals = locals.merge(attributes(file))
44
+ build_file(locals) do |body|
45
+ IO.copy_stream(file.path, body)
46
+ body << "\r\n"
47
+ end
48
+ end
49
+
50
+ def form(locals, value)
51
+ locals = locals.merge(value:)
52
+ build_form(locals) do |body|
53
+ body << value.to_s
54
+ body << "\r\n"
55
+ end
56
+ end
57
+
58
+ def build_file(locals)
59
+ StringIO.new("".b).tap do |io|
60
+ io << "--#{locals[:boundary]}" \
61
+ "\r\n" \
62
+ "Content-Disposition: form-data; name=\"#{locals[:key]}\";" \
63
+ "filename=\"#{locals[:filename]}\"" \
64
+ "\r\n" \
65
+ "Content-Type: #{locals[:content_type]}" \
66
+ "\r\n\r\n"
67
+ yield(io)
68
+ end
69
+ end
70
+
71
+ def build_form(locals)
72
+ StringIO.new("".b).tap do |io|
73
+ io << "--#{locals[:boundary]}" \
74
+ "\r\n" \
75
+ "Content-Disposition: form-data; name=\"#{locals[:key]}\"" \
76
+ "\r\n\r\n"
77
+ yield(io)
78
+ end
79
+ end
80
+
81
+ ##
82
+ # Returns the multipart request body parts
83
+ # @return [Array<String>]
84
+ def parts
85
+ params.map do |key, value|
86
+ locals = {key: key.to_s.b, boundary: boundary.to_s.b}
87
+ if value.respond_to?(:path)
88
+ file(locals, value)
89
+ else
90
+ form(locals, value)
91
+ end
92
+ end
93
+ end
94
+
95
+ def attributes(file)
96
+ {
97
+ filename: File.basename(file.path).b,
98
+ content_type: LLM::Mime[file].b
99
+ }
100
+ end
101
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LLM::Object
4
+ ##
5
+ # @private
6
+ module Builder
7
+ ##
8
+ # @example
9
+ # obj = LLM::Object.from_hash(person: {name: 'John'})
10
+ # obj.person.name # => 'John'
11
+ # obj.person.class # => LLM::Object
12
+ # @param [Hash, LLM::Object, Array] obj
13
+ # A Hash object
14
+ # @return [LLM::Object]
15
+ # An LLM::Object object initialized by visiting `obj` with recursion
16
+ def from_hash(obj)
17
+ case obj
18
+ when self then from_hash(obj.to_h)
19
+ when Array then obj.map { |v| from_hash(v) }
20
+ else
21
+ visited = {}
22
+ obj.each { visited[_1] = visit(_2) }
23
+ new(visited)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def visit(value)
30
+ case value
31
+ when self then from_hash(value.to_h)
32
+ when Hash then from_hash(value)
33
+ when Array then value.map { |v| visit(v) }
34
+ else value
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LLM::Object
4
+ ##
5
+ # @private
6
+ module Kernel
7
+ def tap(...)
8
+ ::Kernel.instance_method(:tap).bind(self).call(...)
9
+ end
10
+
11
+ def instance_of?(...)
12
+ ::Kernel.instance_method(:instance_of?).bind(self).call(...)
13
+ end
14
+
15
+ def extend(...)
16
+ ::Kernel.instance_method(:extend).bind(self).call(...)
17
+ end
18
+
19
+ def method(...)
20
+ ::Kernel.instance_method(:method).bind(self).call(...)
21
+ end
22
+
23
+ def kind_of?(...)
24
+ ::Kernel.instance_method(:kind_of?).bind(self).call(...)
25
+ end
26
+ alias_method :is_a?, :kind_of?
27
+
28
+ def respond_to?(m, include_private = false)
29
+ @h.key?(m.to_sym) || self.class.instance_methods.include?(m) || super
30
+ end
31
+
32
+ def respond_to_missing?(m, include_private = false)
33
+ @h.key?(m.to_sym) || super
34
+ end
35
+
36
+ def object_id
37
+ ::Kernel.instance_method(:object_id).bind(self).call
38
+ end
39
+
40
+ def class
41
+ ::Kernel.instance_method(:class).bind(self).call
42
+ end
43
+
44
+ def inspect
45
+ "#<#{self.class}:0x#{object_id.to_s(16)} properties=#{to_h.inspect}>"
46
+ end
47
+ alias_method :to_s, :inspect
48
+
49
+ def pretty_print(q)
50
+ q.text(inspect)
51
+ end
52
+ end
53
+ end