nitro_intelligence 2.7.0 → 3.0.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: d87085d656ea4f0e2ee7ee00f1d1e360de33aa91257847a7c127ba65082b5e7c
4
- data.tar.gz: f7587153b62be7ab17a60302ce8438ab483d35e9b499aee634c69cd1388cf2a9
3
+ metadata.gz: a6f2f9a233086c2c5b63e91124dd8ff9f6a838ba3eb1a7e08b382029efaf6c8a
4
+ data.tar.gz: d4b72f0693e8c10ad97d6ead9eebb469f69043d1323e49c097811530e17c5d90
5
5
  SHA512:
6
- metadata.gz: ea8307af597a82b4e7511589eb5258ab1006805a63e3cc358dc7db6b2ca55882b0e522701667d7b98f5d851e89b214b9290d3c9330ff27a8957290c3c00584c8
7
- data.tar.gz: 9a891b5281ec8f6f34b4611ab8a0204027b5c14a9b63ea02999f273386a06ab9b4d2a5410b18be0041b6acb4ad7ace1f8146c2115148dc81d70c12b2372a37a6
6
+ metadata.gz: caf47b70030388d5a3aaaa31e4fa9aa217b401e740fdd41a166539c12bfae0e9c4342e57543510a83af4c8c9788e7c50b752324273ee4a7302c903f754a5b14e
7
+ data.tar.gz: 426c37a3551965cee7946631d27b00b9e84e79620640cf1575a60d827a15f5e3b2ae1f40cde95e2df39efa15ec6c2a730ee3f66fbf1dcb4e4c0c148c037e5be2
@@ -48,12 +48,13 @@ module NitroIntelligence
48
48
  client.await_run(thread_id:, assistant_id:, messages:, **kwargs)
49
49
  end
50
50
 
51
- def review_tool_calls(thread_id:, reviewer_id:, tool_calls:, **kwargs)
51
+ def review_tool_calls(thread_id:, tool_calls:, **kwargs)
52
52
  reject_assistant_id!(kwargs)
53
- client.review_tool_calls(thread_id:, assistant_id:, reviewer_id:, tool_calls:, **kwargs)
53
+ client.review_tool_calls(thread_id:, assistant_id:, tool_calls:, **kwargs)
54
54
  end
55
55
 
56
- delegate :thread_state, :thread_messages, :tool_calls_pending_review, to: :client
56
+ delegate :thread_state, :thread_messages, :tool_calls_pending_review, :tool_calls_under_review,
57
+ to: :client
57
58
 
58
59
  private
59
60
 
@@ -1,6 +1,7 @@
1
1
  require "json"
2
2
  require "net/http"
3
3
  require "uri"
4
+ require "nitro_intelligence/tool_call_review_interrupt"
4
5
  require "nitro_intelligence/tool_call_review_validator"
5
6
 
6
7
  module NitroIntelligence
@@ -75,29 +76,53 @@ module NitroIntelligence
75
76
  end
76
77
  end
77
78
 
78
- def review_tool_calls(thread_id:, assistant_id:, reviewer_id:, tool_calls:, reviewed_at: DateTime.current.iso8601)
79
- resume = { reviewer_id:, reviewed_at:, tool_calls: }.with_indifferent_access
79
+ # The tool calls the thread's interrupt is holding, in the order the platform wants decisions
80
+ # for them, each with the `allowed_decisions` a reviewer may take on it. Empty when the thread
81
+ # is not waiting on a review.
82
+ #
83
+ # A tool the assistant is not configured to interrupt on runs without review, so an AI message
84
+ # can mix calls under review with calls that are only waiting to be executed. This reports the
85
+ # former; #tool_calls_pending_review reports both.
86
+ def tool_calls_under_review(thread_id:)
87
+ ToolCallReviewInterrupt.new(get_thread_state(thread_id:)).tool_calls
88
+ end
89
+
90
+ # Resumes an interrupted thread with one review per tool call the interrupt is holding. Each
91
+ # review is keyed by tool call id and names an `action` -- `approve`, `edit`, `reject` or
92
+ # `respond` -- from the decisions the interrupt allows for that tool. `edit` carries `args`,
93
+ # merged over the arguments the model asked for; `respond` carries the `message` returned to the
94
+ # model as the tool's result; `reject` may carry a `message` explaining the refusal.
95
+ #
96
+ # Assistants records nothing about who reviewed a tool call, and the resume payload it accepts
97
+ # has nowhere to carry it, so there is no reviewer argument to pass.
98
+ def review_tool_calls(thread_id:, assistant_id:, tool_calls:, context: {})
80
99
  thread = get_thread(thread_id:)
81
100
  raise ThreadResumptionError, "Thread #{thread_id} is not in the interrupted state" unless interrupted?(thread)
82
101
 
83
- thread_state = get_thread_state(thread_id:)
102
+ interrupt = ToolCallReviewInterrupt.new(get_thread_state(thread_id:))
103
+ tool_calls_under_review = interrupt.tool_calls
84
104
 
85
- @tool_call_review_validator.validate!(
86
- thread_state:,
87
- tool_calls: resume[:tool_calls],
88
- pending_tool_calls: tool_calls_pending_review(thread_id:)
89
- )
105
+ if tool_calls_under_review.empty?
106
+ raise ThreadResumptionError, "Thread #{thread_id} has no tool calls awaiting review"
107
+ end
108
+
109
+ @tool_call_review_validator.validate!(tool_calls:, tool_calls_under_review:)
90
110
 
91
111
  resume_run(
92
112
  thread_id:,
93
113
  assistant_id:,
94
- resume:,
95
- context: interrupt_context(thread_state)
114
+ resume: { decisions: interrupt.decisions(tool_calls) },
115
+ context:
96
116
  )
97
117
 
98
118
  nil
99
119
  end
100
120
 
121
+ # ContactCenter::VirtualConfirmationAgent::Client in nitro-web subclasses this to speak the
122
+ # VCA's own review protocol, and its override reaches `get_thread`, `interrupted?`,
123
+ # `get_thread_state` and `resume_run` below. Renaming any of the four breaks that override --
124
+ # loudly, in nitro-web's suite at bump time rather than in anything here. The subclass goes when
125
+ # the VCA moves onto this platform, and this note with it.
101
126
  private
102
127
 
103
128
  # Assistants accepts `initial_state` on thread creation but never applies it, so a brand new thread is
@@ -207,9 +232,19 @@ module NitroIntelligence
207
232
  raise RunError, run_response.body if run_response.code.to_i != 200
208
233
 
209
234
  run = JSON.parse(run_response.body)
235
+ raise_run_error!(run, RunError)
236
+
210
237
  Array(run["messages"]).last&.dig("content")
211
238
  end
212
239
 
240
+ def raise_run_error!(run, error)
241
+ failure = run["__error__"]
242
+ return if failure.blank?
243
+
244
+ detail = failure.is_a?(Hash) ? [failure["error"], failure["message"]].compact.join(": ") : failure.to_s
245
+ raise error, detail
246
+ end
247
+
213
248
  def resume_run(thread_id:, assistant_id:, resume:, context:)
214
249
  run_response = post(
215
250
  path: "/threads/#{thread_id}/runs/wait",
@@ -224,17 +259,16 @@ module NitroIntelligence
224
259
 
225
260
  raise ThreadResumptionError, run_response.body if run_response.code.to_i != 200
226
261
 
227
- JSON.parse(run_response.body)
262
+ run = JSON.parse(run_response.body)
263
+ raise_run_error!(run, ThreadResumptionError)
264
+
265
+ run
228
266
  end
229
267
 
230
268
  def interrupted?(thread)
231
269
  thread["status"] == "interrupted"
232
270
  end
233
271
 
234
- def interrupt_context(thread_state)
235
- thread_state.dig("interrupts", 0, "value", "context") || {}
236
- end
237
-
238
272
  def messages_in(thread_state)
239
273
  Array(thread_state.dig("values", "messages"))
240
274
  end
@@ -61,10 +61,9 @@ module NitroIntelligence
61
61
 
62
62
  private
63
63
 
64
- # `last_response` carries the HTTP metadata of the response a typed model was
65
- # built from. The client leaves it unset on nested and locally constructed
66
- # models, and on endpoints returning raw or binary payloads, so both the
67
- # method and its value are optional.
64
+ # `last_response` carries the HTTP metadata of the response a model was built
65
+ # from. The client leaves it unset on nested and locally constructed models,
66
+ # so both the method and its value are optional.
68
67
  def response_headers(response)
69
68
  return nil unless response.respond_to?(:last_response)
70
69
 
@@ -79,11 +79,13 @@ module NitroIntelligence
79
79
  output = handle_text_to_speech_upload(tempfile, trace_id)
80
80
  end
81
81
 
82
- # We only get StringIO object as a response, so there are no usage details
83
- # and no resolved model to record. The requested model and the input are
84
- # already on the observation from before the request ran.
82
+ # Usage details and the resolved model are read off a response body, and
83
+ # this endpoint's body is audio, so neither is available here. The
84
+ # requested model and the input are already on the observation from
85
+ # before the request ran.
85
86
  trace_attributes = {
86
87
  output:,
88
+ cost_details: @base_handler.cost_details(tts),
87
89
  }
88
90
 
89
91
  [tts, trace_attributes]
@@ -18,10 +18,6 @@ module NitroIntelligence
18
18
  config_accessor :observability_projects, default: []
19
19
  config_accessor :observability_user_id, default: ""
20
20
 
21
- # Deprecated: configure `assistants_config` instead. Keeps its original `{}` default through the
22
- # deprecation window, so a host building the hash up in place still has one to build on.
23
- config_accessor :agent_server_config, default: {}
24
-
25
21
  class << self
26
22
  def configure
27
23
  yield config
@@ -0,0 +1,135 @@
1
+ require "active_support/core_ext/hash/indifferent_access"
2
+
3
+ module NitroIntelligence
4
+ # The tool calls one interrupt is holding, and the resume payload that answers them.
5
+ #
6
+ # LangChain's `HumanInTheLoopMiddleware` publishes `action_requests` -- a tool name, its arguments
7
+ # and a description -- alongside a `review_configs` entry per tool naming the decisions a reviewer
8
+ # may take. It resumes with `decisions`, one per action request, matched to them by position.
9
+ #
10
+ # Action requests carry no tool call id, and ids are what a review interface works in, so each is
11
+ # matched back onto the tool calls of the thread's last AI message -- the ones the middleware built
12
+ # them from -- to recover the id. The order of `#tool_calls` is the order `decisions` must be in.
13
+ class ToolCallReviewInterrupt
14
+ def initialize(thread_state)
15
+ @thread_state = thread_state
16
+ end
17
+
18
+ def tool_calls
19
+ @tool_calls ||= build_tool_calls
20
+ end
21
+
22
+ # The `command.resume` payload for the reviews, ordered to match the action requests. Callers
23
+ # key their reviews by tool call id; the platform wants a positional list.
24
+ def decisions(reviews)
25
+ reviews = reviews.with_indifferent_access
26
+
27
+ tool_calls.map { |tool_call| decision_for(tool_call, reviews[tool_call["id"]]) }
28
+ end
29
+
30
+ private
31
+
32
+ def build_tool_calls
33
+ unmatched = last_ai_tool_calls.dup
34
+
35
+ action_requests.map do |action_request|
36
+ tool_call = take_matching_tool_call(unmatched, action_request)
37
+
38
+ {
39
+ "previous_message_id" => previous_message_id,
40
+ "id" => tool_call["id"],
41
+ "name" => tool_call["name"],
42
+ "args" => tool_call["args"] || {},
43
+ "allowed_decisions" => allowed_decisions_by_tool_name.fetch(action_request["name"], []),
44
+ }
45
+ end
46
+ end
47
+
48
+ # Arguments distinguish two calls to the same tool, and a name-only match covers a platform that
49
+ # reformats them on the way into the interrupt.
50
+ def take_matching_tool_call(unmatched, action_request)
51
+ name = action_request["name"]
52
+ index = unmatched.index { |tool_call| tool_call["name"] == name && tool_call["args"] == action_request["args"] }
53
+ index ||= unmatched.index { |tool_call| tool_call["name"] == name }
54
+
55
+ unless index
56
+ raise Assistants::ThreadResumptionError,
57
+ "No tool call on the thread matches the interrupt's action request for `#{name}`"
58
+ end
59
+
60
+ unmatched.delete_at(index)
61
+ end
62
+
63
+ # An action this does not recognise is refused rather than read as an approval. #review_tool_calls
64
+ # validates before it gets here, so this fires for a caller building a resume payload itself --
65
+ # or for a decision the platform gains and this does not, where running the tool for a reviewer
66
+ # who asked for something else is the one outcome human review exists to prevent.
67
+ def decision_for(tool_call, review)
68
+ review = (review || {}).with_indifferent_access
69
+
70
+ case review[:action].to_s
71
+ when "approve"
72
+ { "type" => "approve" }
73
+ when "edit"
74
+ { "type" => "edit", "edited_action" => edited_action(tool_call, review) }
75
+ when "reject"
76
+ review[:message].nil? ? { "type" => "reject" } : { "type" => "reject", "message" => review[:message] }
77
+ when "respond"
78
+ { "type" => "respond", "message" => review[:message] }
79
+ else
80
+ raise Assistants::ThreadResumptionError,
81
+ "Tool call #{tool_call['id']} has no review naming `approve`, `edit`, `reject` or `respond`"
82
+ end
83
+ end
84
+
85
+ # Edited arguments are merged over the call the model made, so a reviewer changing one of them
86
+ # does not have to restate the rest -- and cannot drop one by omitting it.
87
+ def edited_action(tool_call, review)
88
+ {
89
+ "name" => tool_call["name"],
90
+ "args" => tool_call["args"].merge(review[:args] || {}),
91
+ }
92
+ end
93
+
94
+ def interrupt_value
95
+ @interrupt_value ||= @thread_state.dig("interrupts", 0, "value") || {}
96
+ end
97
+
98
+ def action_requests
99
+ Array(interrupt_value["action_requests"])
100
+ end
101
+
102
+ def allowed_decisions_by_tool_name
103
+ @allowed_decisions_by_tool_name ||= Array(interrupt_value["review_configs"]).to_h do |review_config|
104
+ [review_config["action_name"], Array(review_config["allowed_decisions"]).map(&:to_s)]
105
+ end
106
+ end
107
+
108
+ def last_ai_tool_calls
109
+ Array(last_ai_message&.dig("tool_calls"))
110
+ end
111
+
112
+ # An interrupt only ever holds the tool calls of the message the model has just produced.
113
+ def last_ai_message_index
114
+ @last_ai_message_index ||= messages.rindex do |message|
115
+ message["type"] == "ai" && Array(message["tool_calls"]).any?
116
+ end
117
+ end
118
+
119
+ def last_ai_message
120
+ last_ai_message_index && messages[last_ai_message_index]
121
+ end
122
+
123
+ # The message the reviewer needs to read to judge the call, as #tool_calls_pending_review
124
+ # reports it: the one immediately before the tool-call attempt.
125
+ def previous_message_id
126
+ return nil if last_ai_message_index.nil? || last_ai_message_index.zero?
127
+
128
+ messages[last_ai_message_index - 1]&.dig("id")
129
+ end
130
+
131
+ def messages
132
+ @messages ||= Array(@thread_state.dig("values", "messages"))
133
+ end
134
+ end
135
+ end
@@ -1,29 +1,34 @@
1
1
  require "active_support/core_ext/hash/indifferent_access"
2
2
 
3
3
  module NitroIntelligence
4
+ # The reviews a caller submitted, checked against the tool calls the interrupt is holding, before
5
+ # anything is sent. Raises `Assistants::ThreadResumptionError` on the first problem it finds.
6
+ #
7
+ # Internal to `Assistants#review_tool_calls`, which builds the only instance there is. What
8
+ # `#validate!` takes follows what that method needs and has changed with it before, so it carries
9
+ # no promise to anything calling it directly.
4
10
  class ToolCallReviewValidator
5
- def validate!(thread_state:, tool_calls:, pending_tool_calls:)
11
+ def validate!(tool_calls:, tool_calls_under_review:)
6
12
  tool_calls = normalize_tool_calls(tool_calls)
7
- pending_tool_calls_by_id = Array(pending_tool_calls).index_by { |tool_call| tool_call["id"] }
8
- review_actions = Array(thread_state.dig("interrupts", 0, "value", "review_actions"))
13
+ tool_calls_under_review_by_id = Array(tool_calls_under_review).index_by { |tool_call| tool_call["id"] }
9
14
 
10
15
  tool_calls.each do |tool_call_id, review|
11
- pending_tool_call = pending_tool_calls_by_id[tool_call_id]&.with_indifferent_access
12
- raise_error!("Unknown tool call ids: #{tool_call_id}") unless pending_tool_call
16
+ tool_call_under_review = tool_calls_under_review_by_id[tool_call_id]&.with_indifferent_access
17
+ raise_error!("Unknown tool call ids: #{tool_call_id}") unless tool_call_under_review
13
18
 
14
19
  review = normalize_review(tool_call_id, review)
15
20
  review_action = review[:action].to_s
16
21
 
17
- unless review_actions.include?(review_action)
22
+ unless Array(tool_call_under_review[:allowed_decisions]).include?(review_action)
18
23
  raise_error!("Invalid review action `#{review_action}` for tool call #{tool_call_id}")
19
24
  end
20
25
 
21
- validate_edited_args!(tool_call_id:, review:, pending_tool_call:) if review_action == "edit"
26
+ validate_review_details!(tool_call_id:, review:, review_action:, tool_call_under_review:)
22
27
  end
23
28
 
24
29
  validate_completeness!(
25
30
  submitted_tool_call_ids: tool_calls.keys,
26
- pending_tool_calls:
31
+ tool_calls_under_review:
27
32
  )
28
33
  end
29
34
 
@@ -41,19 +46,45 @@ module NitroIntelligence
41
46
  review.with_indifferent_access
42
47
  end
43
48
 
44
- def validate_edited_args!(tool_call_id:, review:, pending_tool_call:)
49
+ def validate_review_details!(tool_call_id:, review:, review_action:, tool_call_under_review:)
50
+ case review_action
51
+ when "edit"
52
+ validate_edited_args!(tool_call_id:, review:, tool_call_under_review:)
53
+ when "reject"
54
+ # The middleware falls back to its own wording when a rejection carries no reason.
55
+ validate_message!(tool_call_id:, review:, required: false)
56
+ when "respond"
57
+ # The message is returned to the model as the tool's result, so there is nothing to send
58
+ # without it.
59
+ validate_message!(tool_call_id:, review:, required: true)
60
+ end
61
+ end
62
+
63
+ def validate_edited_args!(tool_call_id:, review:, tool_call_under_review:)
45
64
  provided_args = review[:args]
46
65
  raise_error!("Edited args for tool call #{tool_call_id} must be a hash") unless provided_args.is_a?(Hash)
47
66
 
48
- valid_arg_names = pending_tool_call.fetch(:args, {}).keys.map(&:to_s)
67
+ valid_arg_names = tool_call_under_review.fetch(:args, {}).keys.map(&:to_s)
49
68
  invalid_arg_names = provided_args.keys.map(&:to_s) - valid_arg_names
50
69
  return if invalid_arg_names.empty?
51
70
 
52
71
  raise_error!("Invalid edited args for tool call #{tool_call_id}: #{invalid_arg_names.join(', ')}")
53
72
  end
54
73
 
55
- def validate_completeness!(submitted_tool_call_ids:, pending_tool_calls:)
56
- missing_tool_call_ids = Array(pending_tool_calls).filter_map do |tool_call|
74
+ def validate_message!(tool_call_id:, review:, required:)
75
+ message = review[:message]
76
+
77
+ if message.nil?
78
+ raise_error!("Review for tool call #{tool_call_id} must include a message") if required
79
+ return
80
+ end
81
+
82
+ raise_error!("Message for tool call #{tool_call_id} must be a string") unless message.is_a?(String)
83
+ raise_error!("Review for tool call #{tool_call_id} must include a message") if required && message.blank?
84
+ end
85
+
86
+ def validate_completeness!(submitted_tool_call_ids:, tool_calls_under_review:)
87
+ missing_tool_call_ids = Array(tool_calls_under_review).filter_map do |tool_call|
57
88
  tool_call_id = tool_call["id"].to_s
58
89
  tool_call_id unless submitted_tool_call_ids.include?(tool_call_id)
59
90
  end
@@ -1,3 +1,3 @@
1
1
  module NitroIntelligence
2
- VERSION = "2.7.0".freeze
2
+ VERSION = "3.0.0".freeze
3
3
  end
@@ -6,13 +6,11 @@ require "langfuse"
6
6
  require "openai"
7
7
 
8
8
  require "nitro_intelligence/version"
9
- require "nitro_intelligence/agent_server"
10
9
  require "nitro_intelligence/assistant_registry"
11
10
  require "nitro_intelligence/assistants"
12
11
  require "nitro_intelligence/client/base"
13
12
  require "nitro_intelligence/client/client"
14
13
  require "nitro_intelligence/configuration"
15
- require "nitro_intelligence/deprecation"
16
14
  require "nitro_intelligence/media/image_generation"
17
15
  require "nitro_intelligence/models/model_catalog"
18
16
  require "nitro_intelligence/observability/project_client_registry"
@@ -29,18 +27,12 @@ module NitroIntelligence
29
27
  # configuration decides which one a host gets: one that has not reshaped its config keeps
30
28
  # the client it already had.
31
29
  def assistants
32
- current = assistants_config.to_h.deep_stringify_keys
30
+ current = configuration.assistants_config.to_h.deep_stringify_keys
33
31
  return AssistantRegistry.new(current) if current.key?(AssistantRegistry::DEFINITIONS_KEY)
34
32
 
35
33
  Assistants.new(**current.symbolize_keys)
36
34
  end
37
35
 
38
- # Deprecated: use `NitroIntelligence.assistants`.
39
- def agent_server
40
- deprecator.warn("`NitroIntelligence.agent_server` is deprecated. Use `NitroIntelligence.assistants` instead.")
41
- assistants
42
- end
43
-
44
36
  def cache
45
37
  configuration.cache_provider
46
38
  end
@@ -54,20 +46,5 @@ module NitroIntelligence
54
46
  base_url: configuration.observability_base_url
55
47
  )
56
48
  end
57
-
58
- private
59
-
60
- # A host that has migrated is left alone, so a stale `agent_server_config` cannot override the
61
- # configuration it was replaced by.
62
- def assistants_config
63
- current_config = configuration.assistants_config
64
- legacy_config = configuration.agent_server_config
65
- return current_config if current_config.present? || legacy_config.blank?
66
-
67
- deprecator.warn(
68
- "`agent_server_config` is deprecated. Configure `assistants_config` instead."
69
- )
70
- legacy_config
71
- end
72
49
  end
73
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nitro_intelligence
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Artemenko
@@ -57,14 +57,14 @@ dependencies:
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0.79'
60
+ version: '0.86'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0.79'
67
+ version: '0.86'
68
68
  description: The Ruby client for Nitro Intelligence
69
69
  email:
70
70
  - igor.artemenko@powerhrg.com
@@ -75,7 +75,6 @@ files:
75
75
  - Rakefile
76
76
  - docs/README.md
77
77
  - lib/nitro_intelligence.rb
78
- - lib/nitro_intelligence/agent_server.rb
79
78
  - lib/nitro_intelligence/assistant.rb
80
79
  - lib/nitro_intelligence/assistant_registry.rb
81
80
  - lib/nitro_intelligence/assistants.rb
@@ -94,7 +93,6 @@ files:
94
93
  - lib/nitro_intelligence/client/observed.rb
95
94
  - lib/nitro_intelligence/client/observers/langfuse_observer.rb
96
95
  - lib/nitro_intelligence/configuration.rb
97
- - lib/nitro_intelligence/deprecation.rb
98
96
  - lib/nitro_intelligence/langfuse_extension.rb
99
97
  - lib/nitro_intelligence/langfuse_tracer_provider.rb
100
98
  - lib/nitro_intelligence/media/audio.rb
@@ -113,6 +111,7 @@ files:
113
111
  - lib/nitro_intelligence/observability/prompt_store.rb
114
112
  - lib/nitro_intelligence/observability/upload_handler.rb
115
113
  - lib/nitro_intelligence/reporter.rb
114
+ - lib/nitro_intelligence/tool_call_review_interrupt.rb
116
115
  - lib/nitro_intelligence/tool_call_review_validator.rb
117
116
  - lib/nitro_intelligence/trace.rb
118
117
  - lib/nitro_intelligence/version.rb
@@ -1,12 +0,0 @@
1
- require "active_support/deprecation/constant_accessor"
2
- require "nitro_intelligence/assistants"
3
- require "nitro_intelligence/deprecation"
4
-
5
- module NitroIntelligence
6
- include ActiveSupport::Deprecation::DeprecatedConstantAccessor
7
-
8
- # Deprecated: the agent server is now Nitro Intelligence Assistants. Resolved through
9
- # `const_missing` so that the old name returns the real class rather than a stand-in for it,
10
- # keeping `is_a?`, `===`, `rescue` and the nested error constants working on upgrade.
11
- deprecate_constant :AgentServer, "NitroIntelligence::Assistants", deprecator:
12
- end
@@ -1,11 +0,0 @@
1
- require "active_support/deprecation"
2
-
3
- module NitroIntelligence
4
- class << self
5
- # Deprecations introduced while the agent server was renamed to Nitro Intelligence Assistants.
6
- # The names they cover are removed in 3.0.
7
- def deprecator
8
- @deprecator ||= ActiveSupport::Deprecation.new("3.0", "Nitro Intelligence")
9
- end
10
- end
11
- end