ask-agent 0.27.0 → 0.27.1

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: f67174ee80499aad6a21ff621f02c341daf0e992392996d577218aec2d8987ab
4
- data.tar.gz: 25b21cc738b1e106730330b3ec28b118545f96a296898e4e9b3e337b4a2bf9a0
3
+ metadata.gz: f1728d64a66438d1ff5ed51490420b7f9f87d806fc8a5bd98317d9c4de44e68e
4
+ data.tar.gz: 2172947edba0c5a906ebdc01643eaa0adda23d1405d22dcb0dd5a662c71e4944
5
5
  SHA512:
6
- metadata.gz: 74fdca8fecf20a3707bf162a319a0b4fa910f3718745fa8276235200e66e98ddd9a005cd7d4ce4bb5fc7d74321a1a86983934cc17041e6a20e58bce48156ce75
7
- data.tar.gz: 78250a88b07fe2265e276ab5f156dd1c712315585eb906d81a198825c63450cf470ec48702bfbab2ac4b4d757523ff53a86d28646293e21809891626af4616c7
6
+ metadata.gz: cb6be0c48b35c3b7e68ba73edc98fbe9209ffcdc58ee2a7524dd12ea0d3202b0d62397f449579d4b8154b97876cfc57da1031eb004a02fb25c61765b11e764bd
7
+ data.tar.gz: e2d4f5c8fa6808c0d1e73e9d237c56d8e48fb4bc8630b9bf0feb89309bab872a1bca8a42d603030dafadeeb30d203e35e413a533dded5d3a9086e8b8031ef3fc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.27.1] — 2026-08-06
2
+
3
+ ### Fixed
4
+
5
+ - **`chat.ask` / `chat.stream.ask` events now measure real LLM latency.** The
6
+ event was emitted after the call without a block, so `event.duration` was
7
+ ~0ms and duration metrics (e.g. `ask_llm_duration_seconds`,
8
+ `llm.duration_ms` spans) were meaningless. The provider call now runs
9
+ inside the instrument block; tokens/cost/tool_calls are enriched through a
10
+ shared nested `usage` payload hash (known only after the call returns) and
11
+ subscribers read it from there. Instrumentation failures can no longer
12
+ fail an `ask` — a wrapper error before the call falls through and runs the
13
+ call without telemetry, and a subscriber error after success returns the
14
+ response.
15
+
1
16
  ## [0.27.0] — 2026-08-06
2
17
 
3
18
  ### Added
@@ -73,8 +73,6 @@ module Ask
73
73
  }.compact
74
74
  )
75
75
 
76
- emit_instrumentation(stream, response_msg)
77
-
78
76
  response_msg
79
77
  end
80
78
 
@@ -208,20 +206,35 @@ module Ask
208
206
  begin
209
207
  req = build_request(stream)
210
208
 
211
- result = if @middleware_pipeline
212
- @middleware_pipeline.invoke(provider, req) do
209
+ # The chat.ask event wraps the actual provider call so
210
+ # event.duration measures the true LLM latency. Tokens/cost are
211
+ # only known once the call returns, so the (mutable) payload is
212
+ # passed into the block and enriched there — before the event's
213
+ # finish fires.
214
+ response = instrument_llm_call(stream) do |payload|
215
+ result = if @middleware_pipeline
216
+ @middleware_pipeline.invoke(provider, req) do
217
+ call_provider(req, calls_acc, &block)
218
+ end
219
+ else
213
220
  call_provider(req, calls_acc, &block)
214
221
  end
215
- else
216
- call_provider(req, calls_acc, &block)
217
- end
218
222
 
219
- # Flush any buffered stream transforms (e.g. TextBuffer)
220
- if block && @transform_pipeline
221
- flush_transforms(&block)
223
+ # Flush any buffered stream transforms (e.g. TextBuffer)
224
+ if block && @transform_pipeline
225
+ flush_transforms(&block)
226
+ end
227
+
228
+ response = build_response_from_result(result, calls_acc, stream)
229
+ usage = payload[:usage] ||= {}
230
+ usage[:input_tokens] = response.input_tokens
231
+ usage[:output_tokens] = response.output_tokens
232
+ usage[:cost] = response.cost
233
+ usage[:tool_calls] = response.tool_call?
234
+ response
222
235
  end
223
236
 
224
- return build_response_from_result(result, calls_acc, stream)
237
+ return response
225
238
  rescue Ask::RateLimitError => e
226
239
  raise if attempt >= MAX_CHAT_RETRIES - 1
227
240
 
@@ -357,28 +370,47 @@ module Ask
357
370
  nil
358
371
  end
359
372
 
360
- def emit_instrumentation(stream, response_msg)
361
- return unless defined?(Ask::Instrumentation)
362
-
373
+ # Run the provider call inside the chat.ask event so event.duration
374
+ # measures the real LLM latency. The event payload is yielded to the
375
+ # block so the caller can enrich it (tokens, cost) before the event
376
+ # finishes.
377
+ #
378
+ # Instrumentation must never break the chat loop: a subscriber error
379
+ # after the call succeeded is swallowed (the response is returned);
380
+ # an error before the block ran falls through and runs the call
381
+ # without telemetry. Only real LLM errors propagate.
382
+ def instrument_llm_call(stream)
363
383
  payload = {
364
384
  model: @model_id,
365
385
  provider: @model_info.provider,
366
- input_tokens: response_msg.input_tokens,
367
- output_tokens: response_msg.output_tokens,
368
- cost: response_msg.cost,
369
- tool_calls: response_msg.tool_call?,
370
386
  stream: stream,
371
387
  middleware: @middleware_pipeline&.configured?,
372
- stream_transforms: @transform_pipeline&.configured?
388
+ stream_transforms: @transform_pipeline&.configured?,
389
+ # Tokens/cost are only known once the call returns, and
390
+ # instrument() copies the payload shallowly — this nested hash is
391
+ # shared with the event, so in-block enrichment is visible to
392
+ # subscribers at finish time.
393
+ usage: {}
373
394
  }.compact
374
395
 
375
- if stream
376
- Ask::Instrumentation.instrument("chat.stream.ask", payload)
396
+ called = false
397
+ result = nil
398
+ if defined?(Ask::Instrumentation)
399
+ Ask::Instrumentation.instrument(stream ? "chat.stream.ask" : "chat.ask", payload) do
400
+ called = true
401
+ result = yield(payload)
402
+ end
377
403
  else
378
- Ask::Instrumentation.instrument("chat.ask", payload)
404
+ called = true
405
+ result = yield(payload)
379
406
  end
407
+ result
380
408
  rescue StandardError
381
- nil
409
+ return result if called && !result.nil?
410
+
411
+ raise if called
412
+
413
+ yield({})
382
414
  end
383
415
  end
384
416
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ask
4
4
  module Agent
5
- VERSION = "0.27.0"
5
+ VERSION = "0.27.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.27.0
4
+ version: 0.27.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto