dify_llm 1.8.1 → 1.9.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/README.md +12 -7
- data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +117 -69
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +12 -12
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +7 -7
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +6 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +8 -8
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +9 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +7 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +9 -9
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +4 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +11 -11
- data/lib/generators/ruby_llm/generator_helpers.rb +131 -87
- data/lib/generators/ruby_llm/install/install_generator.rb +75 -79
- data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +3 -0
- data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +1 -1
- data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +88 -85
- data/lib/generators/ruby_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +15 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +49 -0
- data/lib/ruby_llm/active_record/acts_as.rb +17 -8
- data/lib/ruby_llm/active_record/chat_methods.rb +41 -13
- data/lib/ruby_llm/active_record/message_methods.rb +11 -2
- data/lib/ruby_llm/active_record/model_methods.rb +1 -1
- data/lib/ruby_llm/aliases.json +62 -20
- data/lib/ruby_llm/attachment.rb +8 -0
- data/lib/ruby_llm/chat.rb +13 -2
- data/lib/ruby_llm/configuration.rb +6 -1
- data/lib/ruby_llm/connection.rb +4 -4
- data/lib/ruby_llm/content.rb +23 -0
- data/lib/ruby_llm/message.rb +11 -6
- data/lib/ruby_llm/model/info.rb +4 -0
- data/lib/ruby_llm/models.json +9410 -7793
- data/lib/ruby_llm/models.rb +14 -22
- data/lib/ruby_llm/provider.rb +23 -1
- data/lib/ruby_llm/providers/anthropic/chat.rb +22 -3
- data/lib/ruby_llm/providers/anthropic/content.rb +44 -0
- data/lib/ruby_llm/providers/anthropic/media.rb +2 -1
- data/lib/ruby_llm/providers/anthropic/models.rb +15 -0
- data/lib/ruby_llm/providers/anthropic/streaming.rb +2 -0
- data/lib/ruby_llm/providers/anthropic/tools.rb +20 -18
- data/lib/ruby_llm/providers/bedrock/media.rb +2 -1
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +15 -0
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +2 -0
- data/lib/ruby_llm/providers/dify/chat.rb +16 -5
- data/lib/ruby_llm/providers/gemini/chat.rb +352 -69
- data/lib/ruby_llm/providers/gemini/media.rb +59 -1
- data/lib/ruby_llm/providers/gemini/tools.rb +146 -25
- data/lib/ruby_llm/providers/gemini/transcription.rb +116 -0
- data/lib/ruby_llm/providers/gemini.rb +2 -1
- data/lib/ruby_llm/providers/gpustack/media.rb +1 -0
- data/lib/ruby_llm/providers/ollama/media.rb +1 -0
- data/lib/ruby_llm/providers/openai/chat.rb +7 -2
- data/lib/ruby_llm/providers/openai/media.rb +2 -1
- data/lib/ruby_llm/providers/openai/streaming.rb +7 -2
- data/lib/ruby_llm/providers/openai/tools.rb +26 -6
- data/lib/ruby_llm/providers/openai/transcription.rb +70 -0
- data/lib/ruby_llm/providers/openai.rb +1 -0
- data/lib/ruby_llm/providers/vertexai/transcription.rb +16 -0
- data/lib/ruby_llm/providers/vertexai.rb +3 -0
- data/lib/ruby_llm/stream_accumulator.rb +10 -4
- data/lib/ruby_llm/tool.rb +126 -0
- data/lib/ruby_llm/transcription.rb +35 -0
- data/lib/ruby_llm/utils.rb +46 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +6 -0
- metadata +25 -3
data/lib/ruby_llm/models.rb
CHANGED
|
@@ -10,16 +10,19 @@ module RubyLLM
|
|
|
10
10
|
@instance ||= new
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def
|
|
14
|
-
|
|
13
|
+
def schema_file
|
|
14
|
+
File.expand_path('models_schema.json', __dir__)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def
|
|
18
|
-
|
|
17
|
+
def load_models(file = RubyLLM.config.model_registry_file)
|
|
18
|
+
read_from_json(file)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def
|
|
22
|
-
File.
|
|
21
|
+
def read_from_json(file = RubyLLM.config.model_registry_file)
|
|
22
|
+
data = File.exist?(file) ? File.read(file) : '[]'
|
|
23
|
+
JSON.parse(data, symbolize_names: true).map { |model| Model::Info.new(model) }
|
|
24
|
+
rescue JSON::ParserError
|
|
25
|
+
[]
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
def refresh!(remote_only: false)
|
|
@@ -151,26 +154,15 @@ module RubyLLM
|
|
|
151
154
|
end
|
|
152
155
|
|
|
153
156
|
def initialize(models = nil)
|
|
154
|
-
@models = models || load_models
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def load_models
|
|
158
|
-
read_from_json
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def load_from_json!
|
|
162
|
-
@models = read_from_json
|
|
157
|
+
@models = models || self.class.load_models
|
|
163
158
|
end
|
|
164
159
|
|
|
165
|
-
def
|
|
166
|
-
|
|
167
|
-
JSON.parse(data, symbolize_names: true).map { |model| Model::Info.new(model) }
|
|
168
|
-
rescue JSON::ParserError
|
|
169
|
-
[]
|
|
160
|
+
def load_from_json!(file = RubyLLM.config.model_registry_file)
|
|
161
|
+
@models = self.class.read_from_json(file)
|
|
170
162
|
end
|
|
171
163
|
|
|
172
|
-
def save_to_json
|
|
173
|
-
File.write(
|
|
164
|
+
def save_to_json(file = RubyLLM.config.model_registry_file)
|
|
165
|
+
File.write(file, JSON.pretty_generate(all.map(&:to_h)))
|
|
174
166
|
end
|
|
175
167
|
|
|
176
168
|
def all
|
data/lib/ruby_llm/provider.rb
CHANGED
|
@@ -82,6 +82,13 @@ module RubyLLM
|
|
|
82
82
|
parse_image_response(response, model:)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
def transcribe(audio_file, model:, language:, **options)
|
|
86
|
+
file_part = build_audio_file_part(audio_file)
|
|
87
|
+
payload = render_transcription_payload(file_part, model:, language:, **options)
|
|
88
|
+
response = @connection.post transcription_url, payload
|
|
89
|
+
parse_transcription_response(response, model:)
|
|
90
|
+
end
|
|
91
|
+
|
|
85
92
|
def configured?
|
|
86
93
|
configuration_requirements.all? { |req| @config.send(req) }
|
|
87
94
|
end
|
|
@@ -160,9 +167,13 @@ module RubyLLM
|
|
|
160
167
|
providers[name.to_sym] = provider_class
|
|
161
168
|
end
|
|
162
169
|
|
|
170
|
+
def resolve(name)
|
|
171
|
+
providers[name.to_sym]
|
|
172
|
+
end
|
|
173
|
+
|
|
163
174
|
def for(model)
|
|
164
175
|
model_info = Models.find(model)
|
|
165
|
-
|
|
176
|
+
resolve model_info.provider
|
|
166
177
|
end
|
|
167
178
|
|
|
168
179
|
def providers
|
|
@@ -192,6 +203,17 @@ module RubyLLM
|
|
|
192
203
|
|
|
193
204
|
private
|
|
194
205
|
|
|
206
|
+
def build_audio_file_part(file_path)
|
|
207
|
+
expanded_path = File.expand_path(file_path)
|
|
208
|
+
mime_type = Marcel::MimeType.for(Pathname.new(expanded_path))
|
|
209
|
+
|
|
210
|
+
Faraday::Multipart::FilePart.new(
|
|
211
|
+
expanded_path,
|
|
212
|
+
mime_type,
|
|
213
|
+
File.basename(expanded_path)
|
|
214
|
+
)
|
|
215
|
+
end
|
|
216
|
+
|
|
195
217
|
def try_parse_json(maybe_json)
|
|
196
218
|
return maybe_json unless maybe_json.is_a?(String)
|
|
197
219
|
|
|
@@ -25,6 +25,8 @@ module RubyLLM
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def build_system_content(system_messages)
|
|
28
|
+
return [] if system_messages.empty?
|
|
29
|
+
|
|
28
30
|
if system_messages.length > 1
|
|
29
31
|
RubyLLM.logger.warn(
|
|
30
32
|
"Anthropic's Claude implementation only supports a single system message. " \
|
|
@@ -32,7 +34,15 @@ module RubyLLM
|
|
|
32
34
|
)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
system_messages.
|
|
37
|
+
system_messages.flat_map do |msg|
|
|
38
|
+
content = msg.content
|
|
39
|
+
|
|
40
|
+
if content.is_a?(RubyLLM::Content::Raw)
|
|
41
|
+
content.value
|
|
42
|
+
else
|
|
43
|
+
Media.format_content(content)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
36
46
|
end
|
|
37
47
|
|
|
38
48
|
def build_base_payload(chat_messages, model, stream)
|
|
@@ -66,12 +76,21 @@ module RubyLLM
|
|
|
66
76
|
end
|
|
67
77
|
|
|
68
78
|
def build_message(data, content, tool_use_blocks, response)
|
|
79
|
+
usage = data['usage'] || {}
|
|
80
|
+
cached_tokens = usage['cache_read_input_tokens']
|
|
81
|
+
cache_creation_tokens = usage['cache_creation_input_tokens']
|
|
82
|
+
if cache_creation_tokens.nil? && usage['cache_creation'].is_a?(Hash)
|
|
83
|
+
cache_creation_tokens = usage['cache_creation'].values.compact.sum
|
|
84
|
+
end
|
|
85
|
+
|
|
69
86
|
Message.new(
|
|
70
87
|
role: :assistant,
|
|
71
88
|
content: content,
|
|
72
89
|
tool_calls: Tools.parse_tool_calls(tool_use_blocks),
|
|
73
|
-
input_tokens:
|
|
74
|
-
output_tokens:
|
|
90
|
+
input_tokens: usage['input_tokens'],
|
|
91
|
+
output_tokens: usage['output_tokens'],
|
|
92
|
+
cached_tokens: cached_tokens,
|
|
93
|
+
cache_creation_tokens: cache_creation_tokens,
|
|
75
94
|
model_id: data['model'],
|
|
76
95
|
raw: response
|
|
77
96
|
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Anthropic
|
|
6
|
+
# Helper for constructing Anthropic native content blocks.
|
|
7
|
+
class Content
|
|
8
|
+
class << self
|
|
9
|
+
def new(text = nil, cache: false, cache_control: nil, parts: nil, **extras)
|
|
10
|
+
payload = resolve_payload(
|
|
11
|
+
text: text,
|
|
12
|
+
parts: parts,
|
|
13
|
+
cache: cache,
|
|
14
|
+
cache_control: cache_control,
|
|
15
|
+
extras: extras
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
RubyLLM::Content::Raw.new(payload)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def resolve_payload(text:, parts:, cache:, cache_control:, extras:)
|
|
24
|
+
return Array(parts) if parts
|
|
25
|
+
|
|
26
|
+
raise ArgumentError, 'text or parts must be provided' if text.nil?
|
|
27
|
+
|
|
28
|
+
block = { type: 'text', text: text }.merge(extras)
|
|
29
|
+
control = determine_cache_control(cache_control, cache)
|
|
30
|
+
block[:cache_control] = control if control
|
|
31
|
+
|
|
32
|
+
[block]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def determine_cache_control(cache_control, cache_flag)
|
|
36
|
+
return cache_control if cache_control
|
|
37
|
+
|
|
38
|
+
{ type: 'ephemeral' } if cache_flag
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -7,7 +7,8 @@ module RubyLLM
|
|
|
7
7
|
module Media
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
def format_content(content)
|
|
10
|
+
def format_content(content) # rubocop:disable Metrics/PerceivedComplexity
|
|
11
|
+
return content.value if content.is_a?(RubyLLM::Content::Raw)
|
|
11
12
|
return [format_text(content.to_json)] if content.is_a?(Hash) || content.is_a?(Array)
|
|
12
13
|
return [format_text(content)] unless content.is_a?(Content)
|
|
13
14
|
|
|
@@ -42,6 +42,21 @@ module RubyLLM
|
|
|
42
42
|
def extract_output_tokens(data)
|
|
43
43
|
data.dig('message', 'usage', 'output_tokens') || data.dig('usage', 'output_tokens')
|
|
44
44
|
end
|
|
45
|
+
|
|
46
|
+
def extract_cached_tokens(data)
|
|
47
|
+
data.dig('message', 'usage', 'cache_read_input_tokens') || data.dig('usage', 'cache_read_input_tokens')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def extract_cache_creation_tokens(data)
|
|
51
|
+
direct = data.dig('message', 'usage',
|
|
52
|
+
'cache_creation_input_tokens') || data.dig('usage', 'cache_creation_input_tokens')
|
|
53
|
+
return direct if direct
|
|
54
|
+
|
|
55
|
+
breakdown = data.dig('message', 'usage', 'cache_creation') || data.dig('usage', 'cache_creation')
|
|
56
|
+
return unless breakdown.is_a?(Hash)
|
|
57
|
+
|
|
58
|
+
breakdown.values.compact.sum
|
|
59
|
+
end
|
|
45
60
|
end
|
|
46
61
|
end
|
|
47
62
|
end
|
|
@@ -18,6 +18,8 @@ module RubyLLM
|
|
|
18
18
|
content: data.dig('delta', 'text'),
|
|
19
19
|
input_tokens: extract_input_tokens(data),
|
|
20
20
|
output_tokens: extract_output_tokens(data),
|
|
21
|
+
cached_tokens: extract_cached_tokens(data),
|
|
22
|
+
cache_creation_tokens: extract_cache_creation_tokens(data),
|
|
21
23
|
tool_calls: extract_tool_calls(data)
|
|
22
24
|
)
|
|
23
25
|
end
|
|
@@ -12,6 +12,8 @@ module RubyLLM
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def format_tool_call(msg)
|
|
15
|
+
return { role: 'assistant', content: msg.content.value } if msg.content.is_a?(RubyLLM::Content::Raw)
|
|
16
|
+
|
|
15
17
|
content = []
|
|
16
18
|
|
|
17
19
|
content << Media.format_text(msg.content) unless msg.content.nil? || msg.content.empty?
|
|
@@ -29,7 +31,7 @@ module RubyLLM
|
|
|
29
31
|
def format_tool_result(msg)
|
|
30
32
|
{
|
|
31
33
|
role: 'user',
|
|
32
|
-
content: [format_tool_result_block(msg)]
|
|
34
|
+
content: msg.content.is_a?(RubyLLM::Content::Raw) ? msg.content.value : [format_tool_result_block(msg)]
|
|
33
35
|
}
|
|
34
36
|
end
|
|
35
37
|
|
|
@@ -51,15 +53,18 @@ module RubyLLM
|
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
def function_for(tool)
|
|
54
|
-
|
|
56
|
+
input_schema = tool.params_schema ||
|
|
57
|
+
RubyLLM::Tool::SchemaDefinition.from_parameters(tool.parameters)&.json_schema
|
|
58
|
+
|
|
59
|
+
declaration = {
|
|
55
60
|
name: tool.name,
|
|
56
61
|
description: tool.description,
|
|
57
|
-
input_schema:
|
|
58
|
-
type: 'object',
|
|
59
|
-
properties: clean_parameters(tool.parameters),
|
|
60
|
-
required: required_parameters(tool.parameters)
|
|
61
|
-
}
|
|
62
|
+
input_schema: input_schema || default_input_schema
|
|
62
63
|
}
|
|
64
|
+
|
|
65
|
+
return declaration if tool.provider_params.empty?
|
|
66
|
+
|
|
67
|
+
RubyLLM::Utils.deep_merge(declaration, tool.provider_params)
|
|
63
68
|
end
|
|
64
69
|
|
|
65
70
|
def extract_tool_calls(data)
|
|
@@ -89,17 +94,14 @@ module RubyLLM
|
|
|
89
94
|
tool_calls.empty? ? nil : tool_calls
|
|
90
95
|
end
|
|
91
96
|
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def required_parameters(parameters)
|
|
102
|
-
parameters.select { |_, param| param.required }.keys
|
|
97
|
+
def default_input_schema
|
|
98
|
+
{
|
|
99
|
+
'type' => 'object',
|
|
100
|
+
'properties' => {},
|
|
101
|
+
'required' => [],
|
|
102
|
+
'additionalProperties' => false,
|
|
103
|
+
'strict' => true
|
|
104
|
+
}
|
|
103
105
|
end
|
|
104
106
|
end
|
|
105
107
|
end
|
|
@@ -10,7 +10,8 @@ module RubyLLM
|
|
|
10
10
|
|
|
11
11
|
module_function
|
|
12
12
|
|
|
13
|
-
def format_content(content)
|
|
13
|
+
def format_content(content) # rubocop:disable Metrics/PerceivedComplexity
|
|
14
|
+
return content.value if content.is_a?(RubyLLM::Content::Raw)
|
|
14
15
|
return [Anthropic::Media.format_text(content.to_json)] if content.is_a?(Hash) || content.is_a?(Array)
|
|
15
16
|
return [Anthropic::Media.format_text(content)] unless content.is_a?(Content)
|
|
16
17
|
|
|
@@ -32,6 +32,21 @@ module RubyLLM
|
|
|
32
32
|
data.dig('message', 'usage', 'output_tokens') || data.dig('usage', 'output_tokens')
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def extract_cached_tokens(data)
|
|
36
|
+
data.dig('message', 'usage', 'cache_read_input_tokens') || data.dig('usage', 'cache_read_input_tokens')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def extract_cache_creation_tokens(data)
|
|
40
|
+
direct = data.dig('message', 'usage',
|
|
41
|
+
'cache_creation_input_tokens') || data.dig('usage', 'cache_creation_input_tokens')
|
|
42
|
+
return direct if direct
|
|
43
|
+
|
|
44
|
+
breakdown = data.dig('message', 'usage', 'cache_creation') || data.dig('usage', 'cache_creation')
|
|
45
|
+
return unless breakdown.is_a?(Hash)
|
|
46
|
+
|
|
47
|
+
breakdown.values.compact.sum
|
|
48
|
+
end
|
|
49
|
+
|
|
35
50
|
private
|
|
36
51
|
|
|
37
52
|
def extract_content_by_type(data)
|
|
@@ -59,6 +59,8 @@ module RubyLLM
|
|
|
59
59
|
content: extract_streaming_content(data),
|
|
60
60
|
input_tokens: extract_input_tokens(data),
|
|
61
61
|
output_tokens: extract_output_tokens(data),
|
|
62
|
+
cached_tokens: extract_cached_tokens(data),
|
|
63
|
+
cache_creation_tokens: extract_cache_creation_tokens(data),
|
|
62
64
|
tool_calls: extract_tool_calls(data)
|
|
63
65
|
}
|
|
64
66
|
end
|
|
@@ -6,12 +6,23 @@ module RubyLLM
|
|
|
6
6
|
# Chat methods of the Dify API integration
|
|
7
7
|
module Chat
|
|
8
8
|
def upload_document(document_path, original_filename = nil)
|
|
9
|
-
|
|
9
|
+
path_like = if document_path.respond_to?(:path)
|
|
10
|
+
document_path.path
|
|
11
|
+
elsif document_path.respond_to?(:to_path)
|
|
12
|
+
document_path.to_path
|
|
13
|
+
else
|
|
14
|
+
document_path
|
|
15
|
+
end
|
|
16
|
+
pn = Pathname.new(path_like)
|
|
10
17
|
mime_type = RubyLLM::MimeType.for pn
|
|
11
|
-
original_filename ||=
|
|
18
|
+
original_filename ||= if document_path.respond_to?(:original_filename)
|
|
19
|
+
document_path.original_filename
|
|
20
|
+
else
|
|
21
|
+
pn.basename.to_s
|
|
22
|
+
end
|
|
12
23
|
payload = {
|
|
13
|
-
file: Faraday::Multipart::FilePart.new(
|
|
14
|
-
user: config
|
|
24
|
+
file: Faraday::Multipart::FilePart.new(path_like, mime_type, original_filename),
|
|
25
|
+
user: (@config&.dify_user || 'dify-user')
|
|
15
26
|
}
|
|
16
27
|
@connection.upload('v1/files/upload', payload)
|
|
17
28
|
end
|
|
@@ -34,7 +45,7 @@ module RubyLLM
|
|
|
34
45
|
query: current_message_content.is_a?(Content) ? current_message_content.text : current_message_content,
|
|
35
46
|
response_mode: (stream ? 'streaming' : 'blocking'),
|
|
36
47
|
conversation_id: latest_conversation_id,
|
|
37
|
-
user: config
|
|
48
|
+
user: (@config&.dify_user || 'dify-user'),
|
|
38
49
|
files: format_files(current_message_content)
|
|
39
50
|
}
|
|
40
51
|
end
|