lex-llm 0.6.15 → 0.6.16
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3ba576c21739b35e60594706468f7a05769871b25e5acd466ae01cbc451eec70
|
|
4
|
+
data.tar.gz: e0ac7077fdc03270059abe385f202b681928e62d667f0cefad10a0a7d1b79760
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 997f024896ce8d0eb54d8574615312c0280efea81ecae75859b3bd702b8dd65aae0fbd5f615801e3e43b9d50cf6079ce4638d9a39488edb7e3a86887ee94a977
|
|
7
|
+
data.tar.gz: 3a33857e99d99a8f3358e781d46903560cb6932026d6889be2a922e23b865f3c2dacef4e38bd6a34e52af35474eab7f7e935d4c68360a8c56e2758836648d589
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.16 - 2026-08-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Interleaved streaming tool-call fragments are correlated by provider index.** `ToolCall` now carries the provider wire index, and `StreamAccumulator` maps continuation fragments back to the call opened at that index. Parallel calls no longer send every id-less fragment to the most recently opened call, which previously lost one call's arguments and contaminated another's.
|
|
7
|
+
|
|
3
8
|
## 0.6.15 - 2026-07-31
|
|
4
9
|
|
|
5
10
|
### Fixed
|
|
@@ -26,6 +26,7 @@ module Legion
|
|
|
26
26
|
@untagged_preamble_pending = true
|
|
27
27
|
@untagged_preamble_buffer = +''
|
|
28
28
|
@latest_tool_call_id = nil
|
|
29
|
+
@index_to_id = {}
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def add(chunk)
|
|
@@ -158,13 +159,15 @@ module Legion
|
|
|
158
159
|
end
|
|
159
160
|
|
|
160
161
|
def start_tool_call(tool_call)
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
resolved_id = tool_call.id.empty? ? SecureRandom.uuid : tool_call.id
|
|
163
|
+
@tool_calls[resolved_id] = ToolCall.new(
|
|
164
|
+
id: resolved_id,
|
|
163
165
|
name: tool_call.name,
|
|
164
166
|
arguments: mutable_tool_arguments(tool_call.arguments),
|
|
165
167
|
thought_signature: tool_call.thought_signature
|
|
166
168
|
)
|
|
167
|
-
@latest_tool_call_id =
|
|
169
|
+
@latest_tool_call_id = resolved_id
|
|
170
|
+
@index_to_id[tool_call.index] = resolved_id unless tool_call.index.nil?
|
|
168
171
|
end
|
|
169
172
|
|
|
170
173
|
def mutable_tool_arguments(arguments)
|
|
@@ -186,10 +189,20 @@ module Legion
|
|
|
186
189
|
thought_signature: tool_call.thought_signature
|
|
187
190
|
)
|
|
188
191
|
@latest_tool_call_id = generated_id
|
|
192
|
+
@index_to_id[tool_call.index] = generated_id unless tool_call.index.nil?
|
|
189
193
|
end
|
|
190
194
|
|
|
195
|
+
# Correlate a continuation fragment (id=nil, name=nil) to its call by the
|
|
196
|
+
# provider's authoritative wire index. Interleaved parallel calls
|
|
197
|
+
# (opener0, opener1, frag0, frag1, ...) only reassemble correctly when
|
|
198
|
+
# each fragment lands on the call at ITS index; recency (@latest_tool_call_id)
|
|
199
|
+
# sends every fragment to the last-opened call, losing one call's arguments
|
|
200
|
+
# and contaminating the other. Recency is retained only as the fallback for
|
|
201
|
+
# providers that emit no index.
|
|
191
202
|
def append_tool_call_fragment(tool_call)
|
|
192
|
-
|
|
203
|
+
target_id = @index_to_id[tool_call.index] if tool_call.index
|
|
204
|
+
target_id ||= @latest_tool_call_id
|
|
205
|
+
existing = @tool_calls[target_id]
|
|
193
206
|
return unless existing
|
|
194
207
|
|
|
195
208
|
existing.arguments << tool_call.arguments.to_s
|
|
@@ -5,14 +5,19 @@ module Legion
|
|
|
5
5
|
module Llm
|
|
6
6
|
# Represents a function call from an AI model to a Tool.
|
|
7
7
|
class ToolCall
|
|
8
|
-
attr_reader :id, :name, :arguments
|
|
8
|
+
attr_reader :id, :name, :arguments, :index
|
|
9
9
|
attr_accessor :thought_signature
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# index carries the provider's authoritative wire position
|
|
12
|
+
# (delta.tool_calls[N].index) so the StreamAccumulator can correlate
|
|
13
|
+
# interleaved argument fragments to the right parallel call by index
|
|
14
|
+
# rather than by recency. nil for non-streaming/single-call paths.
|
|
15
|
+
def initialize(id:, name:, arguments: {}, thought_signature: nil, index: nil)
|
|
12
16
|
@id = id
|
|
13
17
|
@name = name
|
|
14
18
|
@arguments = arguments
|
|
15
19
|
@thought_signature = thought_signature
|
|
20
|
+
@index = index
|
|
16
21
|
end
|
|
17
22
|
|
|
18
23
|
def to_h
|