nitro_intelligence 4.0.0 → 4.1.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 +4 -4
- data/.yardopts +9 -0
- data/Rakefile +21 -1
- data/docs/ASSISTANTS.md +594 -0
- data/docs/CHANGELOG.md +243 -0
- data/docs/README.md +140 -4
- data/lib/nitro_intelligence/assistant.rb +70 -1
- data/lib/nitro_intelligence/assistant_registry.rb +18 -0
- data/lib/nitro_intelligence/assistants.rb +146 -24
- data/lib/nitro_intelligence/client/base.rb +88 -8
- data/lib/nitro_intelligence/client/client.rb +20 -0
- data/lib/nitro_intelligence/client/factory.rb +1 -0
- data/lib/nitro_intelligence/client/handlers/audio_transcription_handler.rb +3 -1
- data/lib/nitro_intelligence/client/handlers/base_handler.rb +17 -2
- data/lib/nitro_intelligence/client/handlers/chat_handler.rb +3 -1
- data/lib/nitro_intelligence/client/handlers/decision_handler.rb +75 -0
- data/lib/nitro_intelligence/client/handlers/image_handler.rb +3 -1
- data/lib/nitro_intelligence/client/handlers/observed/audio_transcription_handler.rb +30 -12
- data/lib/nitro_intelligence/client/handlers/observed/chat_handler.rb +16 -3
- data/lib/nitro_intelligence/client/handlers/observed/decision_handler.rb +72 -0
- data/lib/nitro_intelligence/client/handlers/observed/image_handler.rb +20 -5
- data/lib/nitro_intelligence/client/handlers/observed/text_to_speech_handler.rb +27 -9
- data/lib/nitro_intelligence/client/handlers/text_to_speech_handler.rb +3 -1
- data/lib/nitro_intelligence/client/observed.rb +8 -0
- data/lib/nitro_intelligence/client/observers/langfuse_observer.rb +35 -7
- data/lib/nitro_intelligence/configuration.rb +46 -0
- data/lib/nitro_intelligence/decision.rb +105 -0
- data/lib/nitro_intelligence/langfuse_extension.rb +1 -0
- data/lib/nitro_intelligence/langfuse_tracer_provider.rb +7 -6
- data/lib/nitro_intelligence/media/audio.rb +6 -0
- data/lib/nitro_intelligence/media/image.rb +14 -1
- data/lib/nitro_intelligence/media/image_generation.rb +14 -2
- data/lib/nitro_intelligence/media/media.rb +4 -0
- data/lib/nitro_intelligence/models/model.rb +7 -0
- data/lib/nitro_intelligence/models/model_catalog.rb +3 -0
- data/lib/nitro_intelligence/models/model_factory.rb +2 -0
- data/lib/nitro_intelligence/null_cache.rb +2 -0
- data/lib/nitro_intelligence/observability/project.rb +41 -2
- data/lib/nitro_intelligence/observability/project_client.rb +10 -1
- data/lib/nitro_intelligence/observability/project_client_registry.rb +18 -0
- data/lib/nitro_intelligence/observability/prompt.rb +4 -3
- data/lib/nitro_intelligence/observability/prompt_resolver.rb +2 -0
- data/lib/nitro_intelligence/observability/prompt_store.rb +9 -0
- data/lib/nitro_intelligence/observability/upload_handler.rb +3 -1
- data/lib/nitro_intelligence/pending_review.rb +36 -1
- data/lib/nitro_intelligence/railtie.rb +1 -0
- data/lib/nitro_intelligence/reporter.rb +29 -0
- data/lib/nitro_intelligence/review_decision.rb +2 -0
- data/lib/nitro_intelligence/run_result.rb +31 -0
- data/lib/nitro_intelligence/tool_call_review_interrupt.rb +2 -0
- data/lib/nitro_intelligence/tool_call_review_validator.rb +2 -0
- data/lib/nitro_intelligence/trace.rb +8 -0
- data/lib/nitro_intelligence/version.rb +2 -1
- data/lib/nitro_intelligence.rb +37 -0
- metadata +7 -1
|
@@ -7,6 +7,7 @@ require "uri"
|
|
|
7
7
|
|
|
8
8
|
module NitroIntelligence
|
|
9
9
|
module Observability
|
|
10
|
+
# @api private
|
|
10
11
|
class UploadHandler
|
|
11
12
|
attr_reader :uploaded_media
|
|
12
13
|
|
|
@@ -58,7 +59,7 @@ module NitroIntelligence
|
|
|
58
59
|
payload
|
|
59
60
|
end
|
|
60
61
|
|
|
61
|
-
def upload(trace_id, upload_queue: Queue.new)
|
|
62
|
+
def upload(trace_id, observation_id:, upload_queue: Queue.new)
|
|
62
63
|
until upload_queue.empty?
|
|
63
64
|
media = upload_queue.pop
|
|
64
65
|
|
|
@@ -68,6 +69,7 @@ module NitroIntelligence
|
|
|
68
69
|
# returns {"mediaId" -> "", "uploadUrl" => ""}
|
|
69
70
|
upload_url_response = get_upload_url({
|
|
70
71
|
traceId: trace_id,
|
|
72
|
+
observationId: observation_id,
|
|
71
73
|
contentType: media.mime_type,
|
|
72
74
|
contentLength: content_length,
|
|
73
75
|
sha256Hash: content_sha256,
|
|
@@ -20,29 +20,46 @@ module NitroIntelligence
|
|
|
20
20
|
# response of a paused `/runs/wait` (which reports `__interrupt__`); both carry the messages the
|
|
21
21
|
# tool calls are matched back onto.
|
|
22
22
|
class PendingReview
|
|
23
|
+
# @api private
|
|
23
24
|
REPLY_ACTION = "__reply__".freeze
|
|
24
25
|
|
|
26
|
+
# @api private
|
|
25
27
|
# What a reviewer may do with a reply. LangChain's `respond` supplies a tool's result, which a
|
|
26
28
|
# reply does not have, so it is never offered for one, whatever the interrupt lists.
|
|
27
29
|
REPLY_DECISIONS = %w[approve edit reject].freeze
|
|
28
30
|
|
|
31
|
+
# @api private
|
|
29
32
|
KIND_NAMES = { tool_calls: "tool calls", reply: "a reply" }.freeze
|
|
30
33
|
|
|
31
34
|
# The draft reply a reviewer is asked to approve, edit or reject.
|
|
35
|
+
#
|
|
36
|
+
# @!attribute [r] content
|
|
37
|
+
# @return [String] the draft
|
|
38
|
+
# @!attribute [r] allowed_decisions
|
|
39
|
+
# @return [Array<String>] what the reviewer may do, from `approve`, `edit` and `reject`
|
|
40
|
+
# @!attribute [r] description
|
|
41
|
+
# @return [String, nil] the guidance the pause gives the reviewer
|
|
42
|
+
# @!attribute [r] interrupt_id
|
|
43
|
+
# @return [String] the pause, as {PendingReview#interrupt_id}
|
|
32
44
|
Reply = Struct.new(:content, :allowed_decisions, :description, :interrupt_id, keyword_init: true)
|
|
33
45
|
|
|
34
46
|
# The pending review in a thread state, or nil when the thread is not paused.
|
|
47
|
+
#
|
|
48
|
+
# @api private
|
|
35
49
|
def self.from_thread_state(thread_state)
|
|
36
50
|
interrupt = Array(thread_state["interrupts"]).first
|
|
37
51
|
interrupt && new(interrupt:, messages: Array(thread_state.dig("values", "messages")))
|
|
38
52
|
end
|
|
39
53
|
|
|
40
54
|
# The pending review in a `/runs/wait` response, or nil when the run did not pause.
|
|
55
|
+
#
|
|
56
|
+
# @api private
|
|
41
57
|
def self.from_run(run)
|
|
42
58
|
interrupt = Array(run["__interrupt__"]).first
|
|
43
59
|
interrupt && new(interrupt:, messages: Array(run["messages"]))
|
|
44
60
|
end
|
|
45
61
|
|
|
62
|
+
# @api private
|
|
46
63
|
def initialize(interrupt:, messages:)
|
|
47
64
|
@interrupt = interrupt.to_h
|
|
48
65
|
@messages = messages
|
|
@@ -50,25 +67,35 @@ module NitroIntelligence
|
|
|
50
67
|
|
|
51
68
|
# Identifies this pause. A thread that has moved on -- a new message superseded the review, or
|
|
52
69
|
# another reviewer decided it first -- reports a different interrupt, or none.
|
|
70
|
+
#
|
|
71
|
+
# @return [String, nil] nil for a tool-call pause the service reported without an id, which
|
|
72
|
+
# {Assistants#review} then resumes without checking that it is still the same pause
|
|
53
73
|
def interrupt_id
|
|
54
74
|
@interrupt["id"] || @interrupt["interrupt_id"]
|
|
55
75
|
end
|
|
56
76
|
|
|
57
|
-
#
|
|
77
|
+
# What the run is paused on.
|
|
78
|
+
#
|
|
79
|
+
# @return [Symbol] `:tool_calls` or `:reply`
|
|
58
80
|
def kind
|
|
59
81
|
action_name == REPLY_ACTION ? :reply : :tool_calls
|
|
60
82
|
end
|
|
61
83
|
|
|
84
|
+
# @return [Boolean] whether the run is paused on its tool calls
|
|
62
85
|
def tool_calls?
|
|
63
86
|
kind == :tool_calls
|
|
64
87
|
end
|
|
65
88
|
|
|
89
|
+
# @return [Boolean] whether the run is paused on its reply
|
|
66
90
|
def reply?
|
|
67
91
|
kind == :reply
|
|
68
92
|
end
|
|
69
93
|
|
|
70
94
|
# The tool calls the interrupt is holding, as `Assistants#tool_calls_under_review` reports them.
|
|
71
95
|
# Empty when the pause is on a reply.
|
|
96
|
+
#
|
|
97
|
+
# @return [Array<Hash>] each with `previous_message_id`, `id`, `name`, `args` and
|
|
98
|
+
# `allowed_decisions`
|
|
72
99
|
def tool_calls
|
|
73
100
|
return [] unless tool_calls?
|
|
74
101
|
|
|
@@ -76,6 +103,8 @@ module NitroIntelligence
|
|
|
76
103
|
end
|
|
77
104
|
|
|
78
105
|
# The held draft, or nil when the pause is not on a reply.
|
|
106
|
+
#
|
|
107
|
+
# @return [Reply, nil]
|
|
79
108
|
def reply
|
|
80
109
|
return nil unless reply?
|
|
81
110
|
|
|
@@ -92,6 +121,8 @@ module NitroIntelligence
|
|
|
92
121
|
# thread moved on between reading this pause and resuming it -- it decides nothing, and the
|
|
93
122
|
# thread stays paused on the newer interrupt. An interrupt reported without an id can only be
|
|
94
123
|
# resumed unkeyed.
|
|
124
|
+
#
|
|
125
|
+
# @api private
|
|
95
126
|
def resume(decisions)
|
|
96
127
|
interrupt_id.blank? ? { decisions: } : { interrupt_id => { decisions: } }
|
|
97
128
|
end
|
|
@@ -110,6 +141,8 @@ module NitroIntelligence
|
|
|
110
141
|
# state still on the reported pause (a new message may already have moved it on), or when the
|
|
111
142
|
# state cannot be read, it is false and the result stands as returned. That a stale decision is
|
|
112
143
|
# never applied is guaranteed by the keyed resume, not by this.
|
|
144
|
+
#
|
|
145
|
+
# @api private
|
|
113
146
|
def unapplied_resume?(run:, run_id:)
|
|
114
147
|
paused_on = self.class.from_run(run)&.interrupt_id
|
|
115
148
|
return false if interrupt_id.blank? || run_id.blank? || paused_on.blank? || paused_on == interrupt_id
|
|
@@ -127,6 +160,8 @@ module NitroIntelligence
|
|
|
127
160
|
# For a reply, `reviews` is a single review hash. For tool calls, it is either a hash of reviews
|
|
128
161
|
# keyed by tool call id, as `Assistants#review_tool_calls` has always taken them, or a list of
|
|
129
162
|
# reviews that each carry their tool call's `id`.
|
|
163
|
+
#
|
|
164
|
+
# @api private
|
|
130
165
|
def decisions(reviews)
|
|
131
166
|
return [reply_decision(reviews)] if reply?
|
|
132
167
|
|
|
@@ -3,15 +3,33 @@ require "net/http"
|
|
|
3
3
|
require "uri"
|
|
4
4
|
|
|
5
5
|
module NitroIntelligence
|
|
6
|
+
# Records evaluations of traces in Cerebro.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# reporter = NitroIntelligence::Reporter.new(observability_project_slug: "my-feature-project")
|
|
10
|
+
# reporter.score(name: "precision", value: 0.5, trace_id:)
|
|
6
11
|
class Reporter
|
|
12
|
+
# Raised by {#create_dataset_item} when Cerebro does not store the item. The message carries the
|
|
13
|
+
# response's status and body.
|
|
7
14
|
class DatasetItemError < StandardError; end
|
|
8
15
|
|
|
16
|
+
# @param observability_project_slug [String] the Cerebro project the traces are recorded in
|
|
17
|
+
# @raise [Observability::Project::NotFoundError] when `observability_projects` does not configure
|
|
18
|
+
# the project
|
|
9
19
|
def initialize(observability_project_slug:)
|
|
10
20
|
@observability_project_slug = observability_project_slug
|
|
11
21
|
@project_client = fetch_project_client
|
|
12
22
|
@host = NitroIntelligence.config.observability_base_url
|
|
13
23
|
end
|
|
14
24
|
|
|
25
|
+
# Adds an item to a dataset in the project, for evaluating prompts against later.
|
|
26
|
+
#
|
|
27
|
+
# @param attributes [Hash] the item, as Langfuse's `POST /api/public/dataset-items` takes it:
|
|
28
|
+
# `datasetName`, `input`, `expectedOutput`, `metadata`, `sourceTraceId` and the rest
|
|
29
|
+
# @return [Net::HTTPSuccess] the response
|
|
30
|
+
# @raise [DatasetItemError] when Cerebro does not store the item
|
|
31
|
+
# @example
|
|
32
|
+
# reporter.create_dataset_item({ datasetName: "sms-screening", input: { message: }, expectedOutput: "yes" })
|
|
15
33
|
def create_dataset_item(attributes)
|
|
16
34
|
uri = URI("#{@host}/api/public/dataset-items")
|
|
17
35
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
@@ -35,6 +53,17 @@ module NitroIntelligence
|
|
|
35
53
|
response
|
|
36
54
|
end
|
|
37
55
|
|
|
56
|
+
# Scores a trace. Scoring it again under the same `id` replaces the score.
|
|
57
|
+
#
|
|
58
|
+
# @param trace_id [String] the trace, such as {Trace.create_id} gives for a seed
|
|
59
|
+
# @param name [String] what the score measures
|
|
60
|
+
# @param value [Numeric, String, Boolean] the score: a number, `true` or `false` for `:boolean`,
|
|
61
|
+
# or the category's name for `:categorical`
|
|
62
|
+
# @param id [String] identifies the score, so that recording it again replaces it. Defaults to
|
|
63
|
+
# one per trace and name.
|
|
64
|
+
# @param data_type [Symbol] `:numeric`, `:boolean` or `:categorical`
|
|
65
|
+
# @return [void]
|
|
66
|
+
# @raise [ArgumentError] when `value` does not suit `data_type`
|
|
38
67
|
def score(trace_id:, name:, value:, id: "#{trace_id}-#{name}", data_type: :numeric)
|
|
39
68
|
@project_client.observability_client.create_score(
|
|
40
69
|
id:,
|
|
@@ -2,6 +2,8 @@ module NitroIntelligence
|
|
|
2
2
|
# The `command.resume` decisions a review sends, and the check on the `message` a decision
|
|
3
3
|
# carries, shared by tool call reviews and reply reviews. Each caller keeps its own
|
|
4
4
|
# error wording, so this reports what is wrong rather than raising.
|
|
5
|
+
#
|
|
6
|
+
# @api private
|
|
5
7
|
module ReviewDecision
|
|
6
8
|
module_function
|
|
7
9
|
|
|
@@ -16,36 +16,61 @@ module NitroIntelligence
|
|
|
16
16
|
# finished run still showing it was cut off before delivery recorded an outcome. Treat a
|
|
17
17
|
# pending reply as not sent; the next customer message removes it and the model answers both. A
|
|
18
18
|
# field the stamp does not carry, or carries as the wrong type, is nil.
|
|
19
|
+
#
|
|
20
|
+
# @!attribute [r] status
|
|
21
|
+
# @return [String, nil] `"delivered"`, `"failed"` or `"pending"`
|
|
22
|
+
# @!attribute [r] tool
|
|
23
|
+
# @return [String, nil] the delivery tool's name
|
|
24
|
+
# @!attribute [r] attempts
|
|
25
|
+
# @return [Integer, nil] how many times the platform called the tool
|
|
26
|
+
# @!attribute [r] error
|
|
27
|
+
# @return [String, nil] the tool's error, when delivery failed
|
|
28
|
+
# @!attribute [r] result
|
|
29
|
+
# @return [Object, nil] what the tool returned, when it succeeded
|
|
30
|
+
# @!attribute [r] delivered_at
|
|
31
|
+
# @return [String, nil] when the reply was delivered, as an ISO 8601 timestamp
|
|
32
|
+
# @!attribute [r] failed_at
|
|
33
|
+
# @return [String, nil] when delivery gave up, as an ISO 8601 timestamp
|
|
19
34
|
Delivery = Struct.new(:status, :tool, :attempts, :error, :result, :delivered_at, :failed_at,
|
|
20
35
|
keyword_init: true) do
|
|
36
|
+
# @return [Boolean] whether the platform delivered the reply
|
|
21
37
|
def delivered?
|
|
22
38
|
status == "delivered"
|
|
23
39
|
end
|
|
24
40
|
|
|
41
|
+
# @return [Boolean] whether delivery failed
|
|
25
42
|
def failed?
|
|
26
43
|
status == "failed"
|
|
27
44
|
end
|
|
28
45
|
|
|
46
|
+
# @return [Boolean] whether delivery was cut off before it recorded an outcome
|
|
29
47
|
def pending?
|
|
30
48
|
status == "pending"
|
|
31
49
|
end
|
|
32
50
|
end
|
|
33
51
|
|
|
52
|
+
# @api private
|
|
34
53
|
# The `response_metadata.review` type the platform stamps on a draft when it pauses on it.
|
|
35
54
|
PENDING_REVIEW = "pending".freeze
|
|
36
55
|
|
|
37
56
|
# The response exactly as Assistants returned it.
|
|
57
|
+
#
|
|
58
|
+
# @return [Hash]
|
|
38
59
|
attr_reader :raw
|
|
39
60
|
|
|
61
|
+
# @api private
|
|
40
62
|
def initialize(run)
|
|
41
63
|
@raw = run.to_h
|
|
42
64
|
end
|
|
43
65
|
|
|
66
|
+
# @return [Boolean] whether the run paused for review
|
|
44
67
|
def interrupted?
|
|
45
68
|
Array(raw["__interrupt__"]).any?
|
|
46
69
|
end
|
|
47
70
|
|
|
48
71
|
# What the paused run is waiting on, or nil when it did not pause.
|
|
72
|
+
#
|
|
73
|
+
# @return [PendingReview, nil]
|
|
49
74
|
def review
|
|
50
75
|
return @review if defined?(@review)
|
|
51
76
|
|
|
@@ -53,6 +78,8 @@ module NitroIntelligence
|
|
|
53
78
|
end
|
|
54
79
|
|
|
55
80
|
# The run's messages as Assistants reports them, oldest first.
|
|
81
|
+
#
|
|
82
|
+
# @return [Array<Hash>]
|
|
56
83
|
def messages
|
|
57
84
|
Array(raw["messages"])
|
|
58
85
|
end
|
|
@@ -61,12 +88,16 @@ module NitroIntelligence
|
|
|
61
88
|
# Nil while the run is paused, and when it ended without one: a rejected draft is removed,
|
|
62
89
|
# leaving a tool result or the human's message last, and an earlier turn's text is never the
|
|
63
90
|
# reply. Blank text is no reply.
|
|
91
|
+
#
|
|
92
|
+
# @return [String, nil]
|
|
64
93
|
def reply
|
|
65
94
|
reply_message && text(reply_message["content"]).presence
|
|
66
95
|
end
|
|
67
96
|
|
|
68
97
|
# The reply's delivery, or nil when the reply carries no delivery stamp: no reply, or no
|
|
69
98
|
# delivery tool configured for the assistant.
|
|
99
|
+
#
|
|
100
|
+
# @return [Delivery, nil]
|
|
70
101
|
def delivery
|
|
71
102
|
return @delivery if defined?(@delivery)
|
|
72
103
|
|
|
@@ -11,6 +11,8 @@ module NitroIntelligence
|
|
|
11
11
|
# Action requests carry no tool call id, and ids are what a review interface works in, so each is
|
|
12
12
|
# matched back onto the tool calls of the thread's last AI message -- the ones the middleware built
|
|
13
13
|
# them from -- to recover the id. The order of `#tool_calls` is the order `decisions` must be in.
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
14
16
|
class ToolCallReviewInterrupt
|
|
15
17
|
def initialize(thread_state)
|
|
16
18
|
@thread_state = thread_state
|
|
@@ -8,6 +8,8 @@ module NitroIntelligence
|
|
|
8
8
|
# Internal to `Assistants#review_tool_calls`, which builds the only instance there is. What
|
|
9
9
|
# `#validate!` takes follows what that method needs and has changed with it before, so it carries
|
|
10
10
|
# no promise to anything calling it directly.
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
11
13
|
class ToolCallReviewValidator
|
|
12
14
|
def validate!(tool_calls:, tool_calls_under_review:)
|
|
13
15
|
tool_calls = normalize_tool_calls(tool_calls)
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
module NitroIntelligence
|
|
2
|
+
# Trace IDs, for correlating an observed request with what else a host records about it.
|
|
2
3
|
module Trace
|
|
4
|
+
# The ID of the trace a request passing `trace_seed: seed` is recorded under. The same seed
|
|
5
|
+
# always gives the same ID.
|
|
6
|
+
#
|
|
7
|
+
# @param seed [String] the request's `trace_seed`, such as a document's ID
|
|
8
|
+
# @return [String] the trace ID
|
|
9
|
+
# @example
|
|
10
|
+
# NitroIntelligence::Trace.create_id(seed: "document-123")
|
|
3
11
|
def self.create_id(seed:)
|
|
4
12
|
Langfuse::TraceId.create(seed:)
|
|
5
13
|
end
|
data/lib/nitro_intelligence.rb
CHANGED
|
@@ -17,16 +17,48 @@ require "nitro_intelligence/models/model_catalog"
|
|
|
17
17
|
require "nitro_intelligence/observability/project_client_registry"
|
|
18
18
|
require "nitro_intelligence/reporter"
|
|
19
19
|
|
|
20
|
+
# The Ruby client for the Nitro Intelligence Platform.
|
|
21
|
+
#
|
|
22
|
+
# The public API is everything in this reference not marked `@api private`, and follows Semantic
|
|
23
|
+
# Versioning. `docs/README.md` and `docs/ASSISTANTS.md` are guides to using it, not a list of
|
|
24
|
+
# everything public. What the reference leaves out may change in any release.
|
|
20
25
|
module NitroIntelligence
|
|
26
|
+
# @!attribute [rw] configuration
|
|
27
|
+
# @api private
|
|
28
|
+
# @return [Class<Configuration>]
|
|
21
29
|
mattr_accessor :configuration, default: Configuration
|
|
22
30
|
|
|
23
31
|
class << self
|
|
32
|
+
# @!method configure
|
|
33
|
+
# Sets the configuration, normally once, from an initializer.
|
|
34
|
+
# @yieldparam config [ActiveSupport::Configurable::Configuration] the settings that
|
|
35
|
+
# {Configuration} lists
|
|
36
|
+
# @return [void]
|
|
37
|
+
# @example
|
|
38
|
+
# NitroIntelligence.configure do |config|
|
|
39
|
+
# config.inference_api_key = ENV.fetch("NITRO_INTELLIGENCE_API_KEY")
|
|
40
|
+
# end
|
|
41
|
+
# @!method config
|
|
42
|
+
# The current configuration.
|
|
43
|
+
# @return [ActiveSupport::Configurable::Configuration] the settings that {Configuration} lists
|
|
44
|
+
# @!method logger
|
|
45
|
+
# @api private
|
|
46
|
+
# @!method environment
|
|
47
|
+
# @api private
|
|
24
48
|
delegate :configure, :config, :logger, :environment, to: :configuration
|
|
25
49
|
|
|
26
50
|
# A registry addressable by name when `assistants_config` carries `definitions`, and the
|
|
27
51
|
# single pre-registry client otherwise. The two shapes are mutually exclusive, so the
|
|
28
52
|
# configuration decides which one a host gets: one that has not reshaped its config keeps
|
|
29
53
|
# the client it already had.
|
|
54
|
+
#
|
|
55
|
+
# @return [AssistantRegistry, Assistants]
|
|
56
|
+
# @raise [ArgumentError] without `definitions`, when `assistants_config` has no `api_key`, as
|
|
57
|
+
# it does by default
|
|
58
|
+
# @raise [Assistants::ConfigurationError] without `definitions`, when `assistants_config`
|
|
59
|
+
# has a blank `api_key` or `user_id`
|
|
60
|
+
# @example
|
|
61
|
+
# NitroIntelligence.assistants["candidate-concierge"].run(thread_id:, messages:)
|
|
30
62
|
def assistants
|
|
31
63
|
current = configuration.assistants_config.to_h.deep_stringify_keys
|
|
32
64
|
return AssistantRegistry.new(current) if current.key?(AssistantRegistry::DEFINITIONS_KEY)
|
|
@@ -34,14 +66,19 @@ module NitroIntelligence
|
|
|
34
66
|
Assistants.new(**current.symbolize_keys)
|
|
35
67
|
end
|
|
36
68
|
|
|
69
|
+
# @api private
|
|
37
70
|
def cache
|
|
38
71
|
configuration.cache_provider
|
|
39
72
|
end
|
|
40
73
|
|
|
74
|
+
# @api private
|
|
41
75
|
def model_catalog
|
|
42
76
|
@model_catalog ||= ModelCatalog.new(configuration.model_config)
|
|
43
77
|
end
|
|
44
78
|
|
|
79
|
+
# Each Cerebro project's client.
|
|
80
|
+
#
|
|
81
|
+
# @return [Observability::ProjectClientRegistry]
|
|
45
82
|
def project_client_registry
|
|
46
83
|
@project_client_registry ||= Observability::ProjectClientRegistry.new(
|
|
47
84
|
base_url: configuration.observability_base_url
|
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: 4.
|
|
4
|
+
version: 4.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Igor Artemenko
|
|
@@ -72,7 +72,10 @@ executables: []
|
|
|
72
72
|
extensions: []
|
|
73
73
|
extra_rdoc_files: []
|
|
74
74
|
files:
|
|
75
|
+
- ".yardopts"
|
|
75
76
|
- Rakefile
|
|
77
|
+
- docs/ASSISTANTS.md
|
|
78
|
+
- docs/CHANGELOG.md
|
|
76
79
|
- docs/README.md
|
|
77
80
|
- lib/nitro_intelligence.rb
|
|
78
81
|
- lib/nitro_intelligence/assistant.rb
|
|
@@ -84,15 +87,18 @@ files:
|
|
|
84
87
|
- lib/nitro_intelligence/client/handlers/audio_transcription_handler.rb
|
|
85
88
|
- lib/nitro_intelligence/client/handlers/base_handler.rb
|
|
86
89
|
- lib/nitro_intelligence/client/handlers/chat_handler.rb
|
|
90
|
+
- lib/nitro_intelligence/client/handlers/decision_handler.rb
|
|
87
91
|
- lib/nitro_intelligence/client/handlers/image_handler.rb
|
|
88
92
|
- lib/nitro_intelligence/client/handlers/observed/audio_transcription_handler.rb
|
|
89
93
|
- lib/nitro_intelligence/client/handlers/observed/chat_handler.rb
|
|
94
|
+
- lib/nitro_intelligence/client/handlers/observed/decision_handler.rb
|
|
90
95
|
- lib/nitro_intelligence/client/handlers/observed/image_handler.rb
|
|
91
96
|
- lib/nitro_intelligence/client/handlers/observed/text_to_speech_handler.rb
|
|
92
97
|
- lib/nitro_intelligence/client/handlers/text_to_speech_handler.rb
|
|
93
98
|
- lib/nitro_intelligence/client/observed.rb
|
|
94
99
|
- lib/nitro_intelligence/client/observers/langfuse_observer.rb
|
|
95
100
|
- lib/nitro_intelligence/configuration.rb
|
|
101
|
+
- lib/nitro_intelligence/decision.rb
|
|
96
102
|
- lib/nitro_intelligence/deprecator.rb
|
|
97
103
|
- lib/nitro_intelligence/langfuse_extension.rb
|
|
98
104
|
- lib/nitro_intelligence/langfuse_tracer_provider.rb
|