llm.rb 12.3.1 → 12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1be1cd2af0cc8a817e510b04d1d74efd08cedf714b3faff4bdb7a58345fe14f
4
- data.tar.gz: 3768fdf7f131d30c04d0ba83514bec31eb8d64de661980aa811a4e804a4df1e5
3
+ metadata.gz: cd29af290d188d501b82ef31aae35258d7b6987b14f51bdce68dfbcc3bdca671
4
+ data.tar.gz: 4def59348a5f33bd66248e654f75de05adc7bd8d188686c9464bcfca12a61dcb
5
5
  SHA512:
6
- metadata.gz: 667c546559bb199c7381fbea97171b5e82e874098c40a763004db85667038aa430fa98592c4d42b1426e4536e288e70c018278b9e7af9fcf9b6d972eabd65cbe
7
- data.tar.gz: 0163f85848ce7292905396458755d9ccb23298c6f7c6f06cf0532fb3bdb3517e1b188a022937eb540b823d82d7bc8d869549bc17c8d79767c5efe027bf5ae9be
6
+ metadata.gz: da29e5f492f1130249d5db09ce098aff34d6805d16ed1d8e6df120a3038c4e013dc4dc95a16fcf39dd68f5eacc813715a41c1de7b61befa28206914a26c1aa32
7
+ data.tar.gz: 310c5dab18e187fd8aabd66c363e192a0b556b7f26efd2d7c553416b60782921da94feec04b834549b023ac5f3064c74e411aa32e5981782b237aabe9938d1fb
data/CHANGELOG.md CHANGED
@@ -15,8 +15,163 @@
15
15
 
16
16
  ## What's next
17
17
 
18
+ Changes since `v12.4.0`.
19
+
20
+ ## v12.4.0
21
+
18
22
  Changes since `v12.3.1`.
19
23
 
24
+ This release brings major improvements to the curses-based REPL
25
+ (`LLM::Agent#repl`). The REPL now supports saving and restoring runtime
26
+ state across sessions, automatic paste-mode detection for fast bulk input,
27
+ a command system foundation with the `/exit` command, and several new
28
+ keybindings (Ctrl+F, Ctrl+K, Ctrl+Y). Tool calls are rendered with a
29
+ compact function-call syntax in the status bar.
30
+
31
+ Two new built-in tools — `LLM::Tool::Ls` and `LLM::Tool::Which` — are
32
+ available as opt-in additions for file listing and executable lookup.
33
+
34
+ Model metadata has been refreshed across providers, the REPL loop
35
+ internals have been refactored to use `catch`/`throw` for cleaner command
36
+ routing, and several bugs have been fixed including a tracer restoration
37
+ issue in the agent ensure clause and a missing cursor in the REPL input
38
+ area.
39
+
40
+ ### Add
41
+
42
+ * **repl: allow runtime state to be saved and restored** <br>
43
+ `LLM::Agent#repl` now accepts a `path:` option that serializes
44
+ runtime state to the filesystem. When the path already exists,
45
+ runtime state is restored when the read-eval-print loop starts.
46
+ Otherwise the path is written after the first turn, making it
47
+ possible to resume a session across process restarts.
48
+
49
+ * **repl: scroll to the bottom on submit** <br>
50
+ The curses-based REPL now scrolls the transcript to the bottom when
51
+ the user submits their input, so the latest response is visible
52
+ without needing to scroll down manually.
53
+
54
+ * **repl: add Ctrl+F to move the cursor forward** <br>
55
+ The curses-based REPL input now supports Ctrl+F to move the cursor
56
+ forward by one column, matching common terminal editing conventions
57
+ found in shells like `/bin/sh`.
58
+
59
+ * **repl: add Ctrl+K to erase from cursor to end of line** <br>
60
+ The curses-based REPL input now supports Ctrl+K to erase all text
61
+ from the cursor position to the end of the input buffer, matching
62
+ common terminal editing conventions found in shells like `/bin/sh`.
63
+
64
+ * **repl: add Ctrl+Y to paste previously killed text** <br>
65
+ The curses-based REPL input now supports Ctrl+Y to insert the most
66
+ recently killed text (via Ctrl+K) at the current cursor position,
67
+ matching the yank/paste convention found in shells like `/bin/sh`.
68
+ The killed text is stored in an internal copy buffer so it can be
69
+ pasted multiple times or at different cursor positions.
70
+
71
+ * **repl: add command system foundation** <br>
72
+ Add `LLM::Repl::Command` as a new base class for REPL commands,
73
+ along with the first built-in command `LLM::Repl::Command::Exit`
74
+ which exits the read-eval-print loop via `throw(:exit)`.
75
+ Commands are identified by a name and can be looked up through
76
+ `Command.find_by`. This is the foundation for the `/` command
77
+ syntax used in the REPL input line.
78
+
79
+ * **repl: connect the command system to user input** <br>
80
+ The curses-based REPL now routes user input through the command
81
+ system. Any input string beginning with `"/"` is matched against
82
+ the command registry via `Command.find_by`, and the corresponding
83
+ command is executed instead of being forwarded to the model.
84
+ This makes built-in commands like `/exit` functional from the
85
+ input line. Command arguments are not yet supported.
86
+
87
+ * **repl: add `LLM::Repl::Command.registry`** <br>
88
+ Add `LLM::Repl::Command.registry` for auto-registering command
89
+ subclasses. The `inherited` hook captures each new subclass and
90
+ stores it in the registry, making it possible to enumerate all
91
+ available commands at runtime. Built-in commands like Exit are
92
+ automatically registered when the command file is loaded.
93
+
94
+ * **repl: detect and handle paste mode in the input line** <br>
95
+ The curses-based REPL input now detects paste operations by tracking
96
+ the rate at which characters arrive. A paste rate of ≤50ms is
97
+ assumed to be a burst of characters that could only be explained by
98
+ a paste — no human types that fast. Multiline pastes are supported
99
+ through internal refactoring of the input handling logic.
100
+
101
+ * **repl: optimize paste mode rendering** <br>
102
+ Track the paste state with an internal `@paste` variable and switch
103
+ to a faster input path during paste operations. While in paste mode,
104
+ the input buffer is drained via `Curses.getch`, bypassing the more
105
+ expensive char-by-char render path used for ordinary interactive
106
+ input. This makes pasting large amounts of text noticeably faster.
107
+
108
+ * **Add `LLM::Tool::Ls`** <br>
109
+ Add a built-in tool for listing files and directories, with optional
110
+ glob pattern filtering to narrow results. <br>
111
+ It must be required explicitly with `require "llm/tools/ls"`.
112
+
113
+ * **Add `LLM::Tool::Which`** <br>
114
+ Add a built-in tool for locating an executable on the system PATH.
115
+ This lets an agent check whether a command is available before
116
+ attempting to run it, avoiding failed subprocess calls. <br>
117
+ It must be required explicitly with `require "llm/tools/which"`.
118
+
119
+ * **repl: render tool calls in a function-call syntax** <br>
120
+ The curses-based REPL status bar now renders tool calls with a
121
+ compact function-call syntax — `tool(key: value)` instead of
122
+ `tool: name`. Strings are quoted and truncated, arrays show their
123
+ first two elements, and hashes collapse to `{…}`, making it easier
124
+ to see what arguments the model is passing. The `tool done` status
125
+ message has been removed since the tool call itself conveys
126
+ completion information.
127
+
128
+ ### Change
129
+
130
+ * **Refresh model metadata** <br>
131
+ Update model listings, pricing, and capabilities across providers.
132
+ Fix GPT-5.6 model family names in the OpenAI registry (`gpt` to
133
+ `gpt-sol`, `gpt-nano` to `gpt-luna`, `gpt-mini` to `gpt-terra`).
134
+ Add OpenAI models (`gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`)
135
+ to the AWS Bedrock registry. Update DeepInfra pricing for
136
+ `DeepSeek-V3` and `Sky-T1-32B-Preview`. Fix Google model knowledge
137
+ cutoff dates.
138
+
139
+ * **repl: control the loop with catch & throw** <br>
140
+ The curses-based REPL input loop now uses `catch(:exit)` and
141
+ `throw(:exit)` instead of returning the `:exit` symbol and
142
+ breaking out of the loop. This enables the `/command` syntax
143
+ without requiring an `:exit` return value to be propagated
144
+ through a potentially deeply nested call path.
145
+
146
+ * **repl: replace Ctrl+D with shell-like delete-at-cursor** <br>
147
+ The curses-based REPL input now treats Ctrl+D as a delete action
148
+ that removes the character at the current cursor position, matching
149
+ the shell/Emacs convention where Ctrl+D deletes the character under
150
+ the cursor instead of signalling end-of-file. The previous Ctrl+D
151
+ behaviour (exiting the REPL) is superseded by the `/exit` command.
152
+
153
+ * **repl: switch to 'Thinking' mode after tool return** <br>
154
+ The curses-based REPL status line now switches to "Thinking" mode
155
+ after a tool returns, so the user can see the agent is processing
156
+ the tool result rather than showing a stale tool-call status.
157
+
158
+ ### Fix
159
+
160
+ * **agent: fix a subtle typo in the ensure clause** <br>
161
+ Fix a subtle typo in `LLM::Agent` where the deprecated `trace` local
162
+ variable was given preference over `tracer` (the preferred local name)
163
+ in an `ensure` clause. The `trace` local was supported for backward
164
+ compatibility but the ensure clause still referenced `trace` instead of
165
+ `tracer`, which meant the previous tracer was never restored when the
166
+ REPL session ended.
167
+
168
+ * **repl: restore the cursor in the input area** <br>
169
+ Remove the `Curses.curs_set(0)` call from the REPL redraw method,
170
+ which was inadvertently hiding the cursor and making it impossible
171
+ to see the current position in the input area. The input field is
172
+ now always drawn at its full height so the cursor position is
173
+ correctly maintained after each redraw.
174
+
20
175
  ## v12.3.1
21
176
 
22
177
  Changes since `v12.3.0`.
data/README.md CHANGED
@@ -129,28 +129,50 @@ This feature requires that the [curses](https://github.com/ruby/curses)
129
129
  and [kramdown](https://github.com/gettalong/kramdown) libraries are
130
130
  installed and available to require.
131
131
 
132
+ The TUI displays a status line with a context-usage bar and cost
133
+ counter, a scrollable transcript with markdown rendering, and a
134
+ multi-line input area. The UI stays responsive while the model
135
+ is generating a response.
136
+
137
+ ##### REPL: Agent
138
+
139
+ A REPL session is started by calling `repl` on any agent
140
+ instance. The session inherits the agent's model, tools,
141
+ skills, and instructions.
142
+
132
143
  ```ruby
133
144
  llm = LLM.deepseek(key: ENV["KEY"])
134
145
  agent = LLM::Agent.new(llm)
135
146
  agent.repl
136
147
  ```
137
148
 
138
- The read-eval-print loop accepts both `tools` and `skills`
139
- options that lets you attach additional tools or skills
140
- for the duration of the session. This is in addition to
141
- any tools or skills that might already be associated with
142
- an agent.
149
+ ##### REPL: State
150
+
151
+ The `path:` option accepts a file path where runtime state
152
+ is read from and written to. This lets you resume a
153
+ conversation across REPL sessions.
143
154
 
144
155
  ```ruby
145
156
  llm = LLM.deepseek(key: ENV["KEY"])
146
157
  agent = LLM::Agent.new(llm)
147
- agent.repl(tools: [Debugger], skills: [__dir__])
158
+ agent.repl(path: "session.json")
148
159
  ```
149
160
 
150
- A number of optional tools are distributed as part
151
- of llm.rb. They power the agents that can be found in
152
- the [agents/](agents/) directory, so they're optimized
153
- for developer tasks.
161
+ ##### REPL: Tools
162
+
163
+ The `tools` option lets you attach additional tools
164
+ for the duration of the session. This is in addition to
165
+ any tools that might already be associated with an agent.
166
+
167
+ A number of optional tools are distributed as part of
168
+ llm.rb. They power the agents that can be found in the
169
+ [agents/](agents/) directory.
170
+
171
+ ```ruby
172
+ llm = LLM.deepseek(key: ENV["KEY"])
173
+ agent = LLM::Agent.new(llm)
174
+ agent.repl(tools: [Debugger])
175
+ ```
154
176
 
155
177
  The following example starts a read-eval-print loop
156
178
  with all of the builtin tools available.
@@ -164,11 +186,23 @@ agent = LLM::Agent.new(llm)
164
186
  agent.repl(tools: LLM::Tool.subclasses)
165
187
  ```
166
188
 
167
- By default the tracer is disabled for the duration of
168
- the session. This can be configured through the
169
- `tracer` option. Setting it to `true` will configure
170
- the REPL to use the tracer associated with an instance
171
- of [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html).
189
+ ##### REPL: Skills
190
+
191
+ The `skills` option lets you load extra skill directories
192
+ without attaching them to an agent permanently.
193
+
194
+ ```ruby
195
+ llm = LLM.deepseek(key: ENV["KEY"])
196
+ agent = LLM::Agent.new(llm)
197
+ agent.repl(skills: [__dir__])
198
+ ```
199
+
200
+ ##### REPL: Tracer
201
+
202
+ By default the tracer is disabled for the duration of the
203
+ session. Setting `tracer: true` configures the REPL to use
204
+ the tracer associated with an instance of
205
+ [`LLM::Agent`](https://r.uby.dev/api-docs/llm.rb/LLM/Agent.html).
172
206
 
173
207
  ```ruby
174
208
  llm = LLM.deepseek(key: ENV["KEY"])
@@ -176,6 +210,29 @@ agent = LLM::Agent.new(llm, tracer: LLM.logger(llm, path: "agent.log"))
176
210
  agent.repl(tracer: true, tools: [Debugger])
177
211
  ```
178
212
 
213
+ ##### REPL: Input
214
+
215
+ The input area supports several keyboard shortcuts:
216
+
217
+ | Key | Action |
218
+ |---|---|
219
+ | `Enter` | Submit the current prompt |
220
+ | `Ctrl+A` | Jump to the start of the line |
221
+ | `Ctrl+E` | Jump to the end of the line |
222
+ | `Ctrl+F` | Move the cursor forward |
223
+ | `Ctrl+K` | Erase from cursor to the end of the line |
224
+ | `Ctrl+Y` | Paste previously killed text |
225
+ | `Ctrl+D` | Delete the character at the cursor |
226
+ | `Left / Right` | Move the cursor |
227
+ | `Up / Down` | Scroll the transcript |
228
+ | `/exit` | Leave the REPL |
229
+
230
+ ##### REPL: Commands
231
+
232
+ Commands are recognized by a `/` prefix and are backed by the
233
+ [`LLM::Repl::Command`](https://r.uby.dev/api-docs/llm.rb/LLM/Repl/Command.html)
234
+ class, which can be subclassed to add custom commands.
235
+
179
236
  #### LLM::MCP
180
237
 
181
238
  The Model Context Protocol (MCP) has first-class support
data/data/bedrock.json CHANGED
@@ -1064,6 +1064,59 @@
1064
1064
  "output": 2.75
1065
1065
  }
1066
1066
  },
1067
+ "openai.gpt-5.6-luna": {
1068
+ "id": "openai.gpt-5.6-luna",
1069
+ "name": "GPT-5.6 Luna",
1070
+ "description": "Cost-efficient GPT-5.6 model for fast, high-volume workloads",
1071
+ "family": "gpt-luna",
1072
+ "attachment": true,
1073
+ "reasoning": true,
1074
+ "reasoning_options": [
1075
+ {
1076
+ "type": "effort",
1077
+ "values": [
1078
+ "none",
1079
+ "low",
1080
+ "medium",
1081
+ "high",
1082
+ "xhigh",
1083
+ "max"
1084
+ ]
1085
+ }
1086
+ ],
1087
+ "tool_call": true,
1088
+ "structured_output": true,
1089
+ "temperature": false,
1090
+ "knowledge": "2026-02-16",
1091
+ "release_date": "2026-07-09",
1092
+ "last_updated": "2026-07-09",
1093
+ "modalities": {
1094
+ "input": [
1095
+ "text",
1096
+ "image",
1097
+ "pdf"
1098
+ ],
1099
+ "output": [
1100
+ "text"
1101
+ ]
1102
+ },
1103
+ "open_weights": false,
1104
+ "limit": {
1105
+ "context": 272000,
1106
+ "output": 128000
1107
+ },
1108
+ "provider": {
1109
+ "npm": "@ai-sdk/amazon-bedrock/mantle",
1110
+ "api": "https://bedrock-mantle.${AWS_REGION}.api.aws/openai/v1",
1111
+ "shape": "responses"
1112
+ },
1113
+ "cost": {
1114
+ "input": 1,
1115
+ "output": 6,
1116
+ "cache_read": 0.1,
1117
+ "cache_write": 1.25
1118
+ }
1119
+ },
1067
1120
  "openai.gpt-oss-safeguard-120b": {
1068
1121
  "id": "openai.gpt-oss-safeguard-120b",
1069
1122
  "name": "GPT OSS Safeguard 120B",
@@ -2520,6 +2573,59 @@
2520
2573
  "cache_read": 0.015
2521
2574
  }
2522
2575
  },
2576
+ "openai.gpt-5.6-sol": {
2577
+ "id": "openai.gpt-5.6-sol",
2578
+ "name": "GPT-5.6 Sol",
2579
+ "description": "Frontier GPT-5.6 model for complex professional work, coding, and agentic workflows",
2580
+ "family": "gpt-sol",
2581
+ "attachment": true,
2582
+ "reasoning": true,
2583
+ "reasoning_options": [
2584
+ {
2585
+ "type": "effort",
2586
+ "values": [
2587
+ "none",
2588
+ "low",
2589
+ "medium",
2590
+ "high",
2591
+ "xhigh",
2592
+ "max"
2593
+ ]
2594
+ }
2595
+ ],
2596
+ "tool_call": true,
2597
+ "structured_output": true,
2598
+ "temperature": false,
2599
+ "knowledge": "2026-02-16",
2600
+ "release_date": "2026-07-09",
2601
+ "last_updated": "2026-07-09",
2602
+ "modalities": {
2603
+ "input": [
2604
+ "text",
2605
+ "image",
2606
+ "pdf"
2607
+ ],
2608
+ "output": [
2609
+ "text"
2610
+ ]
2611
+ },
2612
+ "open_weights": false,
2613
+ "limit": {
2614
+ "context": 272000,
2615
+ "output": 128000
2616
+ },
2617
+ "provider": {
2618
+ "npm": "@ai-sdk/amazon-bedrock/mantle",
2619
+ "api": "https://bedrock-mantle.${AWS_REGION}.api.aws/openai/v1",
2620
+ "shape": "responses"
2621
+ },
2622
+ "cost": {
2623
+ "input": 5,
2624
+ "output": 30,
2625
+ "cache_read": 0.5,
2626
+ "cache_write": 6.25
2627
+ }
2628
+ },
2523
2629
  "us.anthropic.claude-haiku-4-5-20251001-v1:0": {
2524
2630
  "id": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
2525
2631
  "name": "Claude Haiku 4.5 (US)",
@@ -4037,6 +4143,59 @@
4037
4143
  "cache_write": 3.75
4038
4144
  }
4039
4145
  },
4146
+ "openai.gpt-5.6-terra": {
4147
+ "id": "openai.gpt-5.6-terra",
4148
+ "name": "GPT-5.6 Terra",
4149
+ "description": "Balanced GPT-5.6 model for capable, cost-efficient everyday work",
4150
+ "family": "gpt-terra",
4151
+ "attachment": true,
4152
+ "reasoning": true,
4153
+ "reasoning_options": [
4154
+ {
4155
+ "type": "effort",
4156
+ "values": [
4157
+ "none",
4158
+ "low",
4159
+ "medium",
4160
+ "high",
4161
+ "xhigh",
4162
+ "max"
4163
+ ]
4164
+ }
4165
+ ],
4166
+ "tool_call": true,
4167
+ "structured_output": true,
4168
+ "temperature": false,
4169
+ "knowledge": "2026-02-16",
4170
+ "release_date": "2026-07-09",
4171
+ "last_updated": "2026-07-09",
4172
+ "modalities": {
4173
+ "input": [
4174
+ "text",
4175
+ "image",
4176
+ "pdf"
4177
+ ],
4178
+ "output": [
4179
+ "text"
4180
+ ]
4181
+ },
4182
+ "open_weights": false,
4183
+ "limit": {
4184
+ "context": 272000,
4185
+ "output": 128000
4186
+ },
4187
+ "provider": {
4188
+ "npm": "@ai-sdk/amazon-bedrock/mantle",
4189
+ "api": "https://bedrock-mantle.${AWS_REGION}.api.aws/openai/v1",
4190
+ "shape": "responses"
4191
+ },
4192
+ "cost": {
4193
+ "input": 2.5,
4194
+ "output": 15,
4195
+ "cache_read": 0.25,
4196
+ "cache_write": 3.125
4197
+ }
4198
+ },
4040
4199
  "google.gemma-3-12b-it": {
4041
4200
  "id": "google.gemma-3-12b-it",
4042
4201
  "name": "Google Gemma 3 12B",
data/data/deepinfra.json CHANGED
@@ -33,8 +33,8 @@
33
33
  "output": 16384
34
34
  },
35
35
  "cost": {
36
- "input": 0.15,
37
- "output": 0.6
36
+ "input": 0.2,
37
+ "output": 0.8
38
38
  }
39
39
  },
40
40
  "meta-llama/Llama-4-Scout-17B-16E-Instruct": {
@@ -1065,9 +1065,9 @@
1065
1065
  "output": 131072
1066
1066
  },
1067
1067
  "cost": {
1068
- "input": 0.43,
1069
- "output": 1.74,
1070
- "cache_read": 0.08
1068
+ "input": 0.5,
1069
+ "output": 2,
1070
+ "cache_read": 0.1
1071
1071
  }
1072
1072
  },
1073
1073
  "zai-org/GLM-5": {
data/data/google.json CHANGED
@@ -491,7 +491,7 @@
491
491
  "reasoning_options": [],
492
492
  "tool_call": false,
493
493
  "temperature": true,
494
- "knowledge": "2025-06",
494
+ "knowledge": "2024-06",
495
495
  "release_date": "2025-08-26",
496
496
  "last_updated": "2025-08-26",
497
497
  "modalities": {
data/data/openai.json CHANGED
@@ -128,7 +128,7 @@
128
128
  "id": "gpt-5.6",
129
129
  "name": "GPT-5.6",
130
130
  "description": "Frontier GPT-5.6 model for complex professional work, coding, and agentic workflows",
131
- "family": "gpt",
131
+ "family": "gpt-sol",
132
132
  "attachment": true,
133
133
  "reasoning": true,
134
134
  "reasoning_options": [
@@ -1027,7 +1027,7 @@
1027
1027
  "id": "gpt-5.6-luna",
1028
1028
  "name": "GPT-5.6 Luna",
1029
1029
  "description": "Cost-efficient GPT-5.6 model for fast, high-volume workloads",
1030
- "family": "gpt-nano",
1030
+ "family": "gpt-luna",
1031
1031
  "attachment": true,
1032
1032
  "reasoning": true,
1033
1033
  "reasoning_options": [
@@ -1214,7 +1214,7 @@
1214
1214
  "id": "gpt-5.6-terra",
1215
1215
  "name": "GPT-5.6 Terra",
1216
1216
  "description": "Balanced GPT-5.6 model for capable, cost-efficient everyday work",
1217
- "family": "gpt-mini",
1217
+ "family": "gpt-terra",
1218
1218
  "attachment": true,
1219
1219
  "reasoning": true,
1220
1220
  "reasoning_options": [
@@ -2184,7 +2184,7 @@
2184
2184
  "id": "gpt-5.6-sol",
2185
2185
  "name": "GPT-5.6 Sol",
2186
2186
  "description": "Frontier GPT-5.6 model for complex professional work, coding, and agentic workflows",
2187
- "family": "gpt",
2187
+ "family": "gpt-sol",
2188
2188
  "attachment": true,
2189
2189
  "reasoning": true,
2190
2190
  "reasoning_options": [
data/lib/llm/agent.rb CHANGED
@@ -398,15 +398,18 @@ module LLM
398
398
  # By default this method disables the tracer for
399
399
  # the duration of the repl session, and restores
400
400
  # it afterwards.
401
- # @param [Boolean] tracer
402
- # When true, the tracer is kept alive during the
403
- # repl session. Default is false.
401
+ # @param [String] path
402
+ # The path to a file where runtime state is read
403
+ # from, and written to
404
404
  # @param [Array<LLM::Tool>] tools
405
405
  # Extra tools to attach for the repl session
406
406
  # @param [Array<String>] skills
407
407
  # Extra skills to attach for the repl session
408
+ # @param [Boolean] tracer
409
+ # When true, the tracer is kept alive during the
410
+ # repl session. Default is false.
408
411
  # @return [void]
409
- def repl(tracer: false, trace: nil, tools: [], skills: [])
412
+ def repl(path: nil, tools: [], skills: [], tracer: false, trace: nil)
410
413
  if trace != nil
411
414
  warn "llm.rb: trace option is deprecated, use tracer instead"
412
415
  tracer = trace
@@ -416,9 +419,9 @@ module LLM
416
419
  self.tracer = nil
417
420
  end
418
421
  require_relative "repl" unless defined?(::LLM::Repl)
419
- LLM::Repl.new(agent: self, tools:, skills:).start
422
+ LLM::Repl.new(agent: self, path:, tools:, skills:).start
420
423
  ensure
421
- if !trace
424
+ if !tracer
422
425
  self.tracer = previous
423
426
  end
424
427
  end
@@ -31,9 +31,8 @@ class LLM::Context
31
31
  end
32
32
  alias_method :restore, :deserialize
33
33
 
34
- ##
35
- # @param [Hash] payload
36
- # @return [LLM::Message]
34
+ private
35
+
37
36
  def deserialize_message(payload)
38
37
  tool_calls = deserialize_tool_calls(payload["tools"])
39
38
  returns = deserialize_returns(payload["content"]) if returns.nil?
@@ -46,8 +45,6 @@ class LLM::Context
46
45
  LLM::Message.new(payload["role"], content, extra)
47
46
  end
48
47
 
49
- private
50
-
51
48
  def deserialize_content(content)
52
49
  case content
53
50
  when Array