prescient 0.7.0 → 0.8.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/.rubocop.yml +21 -268
- data/CHANGELOG.md +37 -0
- data/INTEGRATION_GUIDE.md +7 -1
- data/README.md +210 -1
- data/Steepfile +12 -12
- data/db/migrate/001_create_prescient_tables.rb +15 -16
- data/examples/README.md +2 -1
- data/examples/custom_contexts.rb +4 -4
- data/exe/prescient +2 -2
- data/exe/prescient-mcp +7 -0
- data/lib/prescient/agent/audit_log.rb +37 -0
- data/lib/prescient/agent/cli_adapter.rb +29 -0
- data/lib/prescient/agent/configuration.rb +57 -0
- data/lib/prescient/agent/context.rb +56 -0
- data/lib/prescient/agent/error_serializer.rb +47 -0
- data/lib/prescient/agent/errors.rb +25 -0
- data/lib/prescient/agent/parser.rb +49 -0
- data/lib/prescient/agent/prompt_builder.rb +31 -0
- data/lib/prescient/agent/result.rb +36 -0
- data/lib/prescient/agent/runtime.rb +175 -0
- data/lib/prescient/agent/schema_validator.rb +215 -0
- data/lib/prescient/agent/tool_registry.rb +89 -0
- data/lib/prescient/agent.rb +22 -0
- data/lib/prescient/api.rb +337 -274
- data/lib/prescient/base.rb +370 -372
- data/lib/prescient/cli.rb +586 -526
- data/lib/prescient/client.rb +7 -6
- data/lib/prescient/configuration_loader.rb +492 -488
- data/lib/prescient/document_source.rb +114 -0
- data/lib/prescient/errors.rb +1 -3
- data/lib/prescient/mcp/authentication.rb +39 -0
- data/lib/prescient/mcp/configuration.rb +38 -0
- data/lib/prescient/mcp/rack.rb +243 -0
- data/lib/prescient/mcp/server.rb +202 -0
- data/lib/prescient/mcp/stdio.rb +42 -0
- data/lib/prescient/mcp.rb +8 -0
- data/lib/prescient/pgvector.rb +193 -189
- data/lib/prescient/provider/anthropic.rb +129 -125
- data/lib/prescient/provider/deepseek.rb +122 -118
- data/lib/prescient/provider/gemini.rb +153 -149
- data/lib/prescient/provider/huggingface.rb +191 -187
- data/lib/prescient/provider/mistral.rb +151 -147
- data/lib/prescient/provider/ollama.rb +168 -165
- data/lib/prescient/provider/openai.rb +174 -169
- data/lib/prescient/provider/xai.rb +122 -118
- data/lib/prescient/tool/search_api.rb +125 -121
- data/lib/prescient/tool/searxng.rb +123 -119
- data/lib/prescient/tool.rb +100 -98
- data/lib/prescient/version.rb +1 -1
- data/lib/prescient.rb +68 -62
- data/sig/prescient.rbs +176 -1
- metadata +23 -1
data/lib/prescient/tool.rb
CHANGED
|
@@ -1,123 +1,125 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Execute a search using the tool.
|
|
29
|
-
# @param query [String] Search query
|
|
30
|
-
# @param options [Hash] Per-request options
|
|
31
|
-
# @return [Hash] Normalized tool result
|
|
32
|
-
# @raise [NotImplementedError] If the adapter does not support searching
|
|
33
|
-
def search(query, **options)
|
|
34
|
-
raise NotImplementedError, "#{self.class} must implement #search"
|
|
35
|
-
end
|
|
3
|
+
module Prescient
|
|
4
|
+
# Namespace for external capability adapters.
|
|
5
|
+
module Tool
|
|
6
|
+
autoload :SearXNG, "prescient/tool/searxng"
|
|
7
|
+
autoload :SearchApi, "prescient/tool/search_api"
|
|
8
|
+
|
|
9
|
+
# Base contract for explicit external tool invocation.
|
|
10
|
+
class Base
|
|
11
|
+
# @return [Integer] Default request timeout in seconds
|
|
12
|
+
DEFAULT_TIMEOUT = 5
|
|
13
|
+
# @return [Integer] Default maximum number of returned results
|
|
14
|
+
DEFAULT_MAX_RESULTS = 5
|
|
15
|
+
# @return [Integer] Maximum accepted search query length
|
|
16
|
+
MAX_QUERY_LENGTH = 2_000
|
|
17
|
+
# @return [Integer] Maximum accepted tool response size in bytes
|
|
18
|
+
DEFAULT_MAX_RESPONSE_BYTES = 1_048_576
|
|
19
|
+
|
|
20
|
+
# @return [Hash<Symbol, untyped>] Tool configuration options
|
|
21
|
+
attr_reader :options
|
|
22
|
+
|
|
23
|
+
# @param options [Hash] Tool-specific configuration options
|
|
24
|
+
def initialize(**options)
|
|
25
|
+
@options = options
|
|
26
|
+
validate_configuration!
|
|
27
|
+
end
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
# Execute a search using the tool.
|
|
30
|
+
# @param query [String] Search query
|
|
31
|
+
# @param options [Hash] Per-request options
|
|
32
|
+
# @return [Hash] Normalized tool result
|
|
33
|
+
# @raise [NotImplementedError] If the adapter does not support searching
|
|
34
|
+
def search(query, **options)
|
|
35
|
+
raise NotImplementedError, "#{self.class} must implement #search"
|
|
36
|
+
end
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
# @return [void]
|
|
41
|
-
def validate_configuration!
|
|
42
|
-
# Override in subclasses.
|
|
43
|
-
end
|
|
38
|
+
protected
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
raise Prescient::ToolConfigurationError, 'search query must be a non-empty string'
|
|
40
|
+
# Validate adapter configuration.
|
|
41
|
+
# @return [void]
|
|
42
|
+
def validate_configuration!
|
|
43
|
+
# Override in subclasses.
|
|
50
44
|
end
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
# @param query [String] Search query
|
|
47
|
+
# @return [String] Validated query
|
|
48
|
+
def validate_query(query)
|
|
49
|
+
unless query.is_a?(String) && !query.strip.empty?
|
|
50
|
+
raise Prescient::ToolConfigurationError, "search query must be a non-empty string"
|
|
51
|
+
end
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
cleaned_query = query.strip
|
|
54
|
+
if cleaned_query.length > MAX_QUERY_LENGTH
|
|
55
|
+
raise Prescient::ToolConfigurationError,
|
|
56
|
+
"search query cannot contain more than #{MAX_QUERY_LENGTH} characters"
|
|
57
|
+
end
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
# @return [Integer] Validated result limit
|
|
63
|
-
def result_limit(value)
|
|
64
|
-
limit = value.nil? ? @options.fetch(:max_results, DEFAULT_MAX_RESULTS) : value
|
|
65
|
-
unless limit.is_a?(Integer) && limit.positive?
|
|
66
|
-
raise Prescient::ToolConfigurationError, 'max_results must be a positive integer'
|
|
59
|
+
cleaned_query
|
|
67
60
|
end
|
|
68
61
|
|
|
69
|
-
[limit
|
|
70
|
-
|
|
62
|
+
# @param value [Object] Requested result limit
|
|
63
|
+
# @return [Integer] Validated result limit
|
|
64
|
+
def result_limit(value)
|
|
65
|
+
limit = value.nil? ? @options.fetch(:max_results, DEFAULT_MAX_RESULTS) : value
|
|
66
|
+
unless limit.is_a?(Integer) && limit.positive?
|
|
67
|
+
raise Prescient::ToolConfigurationError, "max_results must be a positive integer"
|
|
68
|
+
end
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
# @return [Numeric] Validated timeout
|
|
74
|
-
def request_timeout(value)
|
|
75
|
-
timeout = value.nil? ? @options.fetch(:timeout, DEFAULT_TIMEOUT) : value
|
|
76
|
-
unless timeout.is_a?(Numeric) && timeout.positive?
|
|
77
|
-
raise Prescient::ToolConfigurationError, 'timeout must be a positive number'
|
|
70
|
+
[limit, 20].min
|
|
78
71
|
end
|
|
79
72
|
|
|
80
|
-
timeout
|
|
81
|
-
|
|
73
|
+
# @param value [Object] Requested timeout
|
|
74
|
+
# @return [Numeric] Validated timeout
|
|
75
|
+
def request_timeout(value)
|
|
76
|
+
timeout = value.nil? ? @options.fetch(:timeout, DEFAULT_TIMEOUT) : value
|
|
77
|
+
unless timeout.is_a?(Numeric) && timeout.positive?
|
|
78
|
+
raise Prescient::ToolConfigurationError, "timeout must be a positive number"
|
|
79
|
+
end
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
def max_response_bytes
|
|
85
|
-
value = @options.fetch(:max_response_bytes, DEFAULT_MAX_RESPONSE_BYTES)
|
|
86
|
-
unless value.is_a?(Integer) && value.positive?
|
|
87
|
-
raise Prescient::ToolConfigurationError,
|
|
88
|
-
'max_response_bytes must be a positive integer'
|
|
81
|
+
timeout
|
|
89
82
|
end
|
|
90
83
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
attr_reader :adapters
|
|
84
|
+
# @return [Integer] Maximum accepted response size
|
|
85
|
+
def max_response_bytes
|
|
86
|
+
value = @options.fetch(:max_response_bytes, DEFAULT_MAX_RESPONSE_BYTES)
|
|
87
|
+
unless value.is_a?(Integer) && value.positive?
|
|
88
|
+
raise Prescient::ToolConfigurationError,
|
|
89
|
+
"max_response_bytes must be a positive integer"
|
|
90
|
+
end
|
|
99
91
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
super
|
|
103
|
-
@adapters = adapters
|
|
104
|
-
raise Prescient::ToolConfigurationError, 'tool group requires an adapter' if @adapters.empty?
|
|
92
|
+
value
|
|
93
|
+
end
|
|
105
94
|
end
|
|
106
95
|
|
|
107
|
-
#
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
failures << e
|
|
96
|
+
# Ordered implementations for one logical tool capability.
|
|
97
|
+
class Group < Base
|
|
98
|
+
# @return [Array<Base>] Ordered capability implementations
|
|
99
|
+
attr_reader :adapters
|
|
100
|
+
|
|
101
|
+
# @param adapters [Array<Base>] Ordered capability implementations
|
|
102
|
+
def initialize(adapters:)
|
|
103
|
+
super
|
|
104
|
+
@adapters = adapters
|
|
105
|
+
raise Prescient::ToolConfigurationError, "tool group requires an adapter" if @adapters.empty?
|
|
118
106
|
end
|
|
119
107
|
|
|
120
|
-
|
|
108
|
+
# Execute the first successful adapter, falling back only for transient
|
|
109
|
+
# connection and rate-limit failures.
|
|
110
|
+
# @param query [String] Search query
|
|
111
|
+
# @param options [Hash] Per-request options
|
|
112
|
+
# @return [Hash] Normalized tool result
|
|
113
|
+
def search(query, **options)
|
|
114
|
+
failures = []
|
|
115
|
+
@adapters.each do |adapter|
|
|
116
|
+
return adapter.search(query, **options)
|
|
117
|
+
rescue Prescient::ToolConnectionError, Prescient::RateLimitError => e
|
|
118
|
+
failures << e
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
raise failures.last
|
|
122
|
+
end
|
|
121
123
|
end
|
|
122
124
|
end
|
|
123
125
|
end
|
data/lib/prescient/version.rb
CHANGED
data/lib/prescient.rb
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
5
|
-
Prescient.autoload :Tool,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
require_relative
|
|
9
|
-
require_relative
|
|
10
|
-
require_relative
|
|
11
|
-
require_relative
|
|
12
|
-
require_relative
|
|
13
|
-
require_relative
|
|
14
|
-
require_relative
|
|
15
|
-
require_relative
|
|
16
|
-
require_relative
|
|
17
|
-
require_relative
|
|
3
|
+
require_relative "prescient/version"
|
|
4
|
+
require_relative "prescient/errors"
|
|
5
|
+
Prescient.autoload :Tool, "prescient/tool"
|
|
6
|
+
Prescient.autoload :DocumentSource, "prescient/document_source"
|
|
7
|
+
Prescient.autoload :Agent, "prescient/agent"
|
|
8
|
+
require_relative "prescient/pgvector"
|
|
9
|
+
require_relative "prescient/base"
|
|
10
|
+
require_relative "prescient/provider/ollama"
|
|
11
|
+
require_relative "prescient/provider/anthropic"
|
|
12
|
+
require_relative "prescient/provider/openai"
|
|
13
|
+
require_relative "prescient/provider/huggingface"
|
|
14
|
+
require_relative "prescient/provider/gemini"
|
|
15
|
+
require_relative "prescient/provider/mistral"
|
|
16
|
+
require_relative "prescient/provider/deepseek"
|
|
17
|
+
require_relative "prescient/provider/xai"
|
|
18
|
+
require_relative "prescient/configuration_loader"
|
|
19
|
+
require_relative "prescient/client"
|
|
18
20
|
|
|
19
21
|
# Main Prescient module for AI provider abstraction
|
|
20
22
|
#
|
|
@@ -34,10 +36,13 @@ require_relative 'prescient/client'
|
|
|
34
36
|
# @example Embedding generation
|
|
35
37
|
# embedding = client.generate_embedding("Some text to embed")
|
|
36
38
|
# puts embedding.length # => 1536 (for OpenAI text-embedding-3-small)
|
|
39
|
+
# rubocop:disable Metrics/ModuleLength
|
|
37
40
|
module Prescient
|
|
38
|
-
autoload :Tool,
|
|
39
|
-
autoload :
|
|
40
|
-
autoload :
|
|
41
|
+
autoload :Tool, "prescient/tool"
|
|
42
|
+
autoload :DocumentSource, "prescient/document_source"
|
|
43
|
+
autoload :API, "prescient/api"
|
|
44
|
+
autoload :CLI, "prescient/cli"
|
|
45
|
+
autoload :MCP, "prescient/mcp"
|
|
41
46
|
|
|
42
47
|
# Configure Prescient with custom settings and providers
|
|
43
48
|
#
|
|
@@ -60,7 +65,7 @@ module Prescient
|
|
|
60
65
|
#
|
|
61
66
|
# @return [Configuration] The current configuration
|
|
62
67
|
def self.configuration
|
|
63
|
-
@
|
|
68
|
+
@configuration ||= Configuration.new
|
|
64
69
|
end
|
|
65
70
|
|
|
66
71
|
# Look up a configured external tool.
|
|
@@ -74,7 +79,7 @@ module Prescient
|
|
|
74
79
|
#
|
|
75
80
|
# @return [Configuration] New configuration instance
|
|
76
81
|
def self.reset_configuration!
|
|
77
|
-
@
|
|
82
|
+
@configuration = Configuration.new
|
|
78
83
|
end
|
|
79
84
|
|
|
80
85
|
# Load configuration from a YAML file and replace the current configuration.
|
|
@@ -87,7 +92,7 @@ module Prescient
|
|
|
87
92
|
# @param env [Hash] Environment variables used while loading configuration
|
|
88
93
|
# @return [Configuration] The loaded configuration
|
|
89
94
|
def self.load_configuration(path = nil, env: ENV)
|
|
90
|
-
effective_path = path || env[
|
|
95
|
+
effective_path = path || env["PRESCIENT_CONFIG"]
|
|
91
96
|
configuration = if effective_path
|
|
92
97
|
ConfigurationLoader.load_file(effective_path, env:)
|
|
93
98
|
else
|
|
@@ -97,7 +102,7 @@ module Prescient
|
|
|
97
102
|
end
|
|
98
103
|
end
|
|
99
104
|
|
|
100
|
-
@
|
|
105
|
+
@configuration = configuration
|
|
101
106
|
end
|
|
102
107
|
|
|
103
108
|
# Configuration class for managing Prescient settings and providers
|
|
@@ -106,7 +111,7 @@ module Prescient
|
|
|
106
111
|
# provider registration and instantiation.
|
|
107
112
|
class Configuration
|
|
108
113
|
# @return [Array<Symbol>] Built-in provider option keys removed from output
|
|
109
|
-
DEFAULT_SENSITIVE_KEYS = [
|
|
114
|
+
DEFAULT_SENSITIVE_KEYS = %i[api_key password token secret].freeze
|
|
110
115
|
|
|
111
116
|
# @return [Symbol] The default provider to use when none specified
|
|
112
117
|
attr_accessor :default_provider
|
|
@@ -173,8 +178,8 @@ module Prescient
|
|
|
173
178
|
def add_provider(name, provider_class, **options)
|
|
174
179
|
provider_name = name.to_sym
|
|
175
180
|
@providers[provider_name] = {
|
|
176
|
-
class:
|
|
177
|
-
options: options
|
|
181
|
+
class: provider_class,
|
|
182
|
+
options: options
|
|
178
183
|
}
|
|
179
184
|
@provider_instances.delete(provider_name)
|
|
180
185
|
end
|
|
@@ -200,8 +205,8 @@ module Prescient
|
|
|
200
205
|
def add_tool(name, tool_class, **options)
|
|
201
206
|
tool_name = name.to_sym
|
|
202
207
|
@tools[tool_name] = {
|
|
203
|
-
class:
|
|
204
|
-
options: options
|
|
208
|
+
class: tool_class,
|
|
209
|
+
options: options
|
|
205
210
|
}
|
|
206
211
|
@tool_instances.delete(tool_name)
|
|
207
212
|
end
|
|
@@ -229,7 +234,7 @@ module Prescient
|
|
|
229
234
|
adapters: tool_config[:adapters].map do |adapter|
|
|
230
235
|
adapter_options = adapter[:options] # : Hash[Symbol, untyped]
|
|
231
236
|
adapter[:class].new(**adapter_options)
|
|
232
|
-
end
|
|
237
|
+
end
|
|
233
238
|
)
|
|
234
239
|
return @tool_instances[tool_name]
|
|
235
240
|
end
|
|
@@ -268,105 +273,105 @@ module Prescient
|
|
|
268
273
|
end
|
|
269
274
|
|
|
270
275
|
def configure_default_tools(config, env)
|
|
271
|
-
return unless env[
|
|
276
|
+
return unless env["SEARXNG_URL"]
|
|
272
277
|
|
|
273
|
-
config.add_tool(:web_search, Prescient::Tool::SearXNG, url: env[
|
|
278
|
+
config.add_tool(:web_search, Prescient::Tool::SearXNG, url: env["SEARXNG_URL"])
|
|
274
279
|
end
|
|
275
280
|
|
|
276
281
|
def configure_ollama(config, env)
|
|
277
282
|
config.add_provider(
|
|
278
283
|
:ollama,
|
|
279
284
|
Prescient::Provider::Ollama,
|
|
280
|
-
url:
|
|
281
|
-
embedding_model: env.fetch(
|
|
282
|
-
chat_model:
|
|
285
|
+
url: env.fetch("OLLAMA_URL", "http://localhost:11434"),
|
|
286
|
+
embedding_model: env.fetch("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text"),
|
|
287
|
+
chat_model: env.fetch("OLLAMA_CHAT_MODEL", "llama3.2:3b")
|
|
283
288
|
)
|
|
284
289
|
end
|
|
285
290
|
|
|
286
291
|
def configure_openai(config, env)
|
|
287
|
-
return unless env[
|
|
292
|
+
return unless env["OPENAI_API_KEY"]
|
|
288
293
|
|
|
289
294
|
config.add_provider(
|
|
290
295
|
:openai,
|
|
291
296
|
Prescient::Provider::OpenAI,
|
|
292
|
-
api_key:
|
|
293
|
-
embedding_model: env.fetch(
|
|
294
|
-
chat_model:
|
|
297
|
+
api_key: env["OPENAI_API_KEY"],
|
|
298
|
+
embedding_model: env.fetch("OPENAI_EMBEDDING_MODEL", "text-embedding-3-small"),
|
|
299
|
+
chat_model: env.fetch("OPENAI_CHAT_MODEL", "gpt-4.1-mini")
|
|
295
300
|
)
|
|
296
301
|
end
|
|
297
302
|
|
|
298
303
|
def configure_anthropic(config, env)
|
|
299
|
-
return unless env[
|
|
304
|
+
return unless env["ANTHROPIC_API_KEY"]
|
|
300
305
|
|
|
301
306
|
config.add_provider(
|
|
302
307
|
:anthropic,
|
|
303
308
|
Prescient::Provider::Anthropic,
|
|
304
|
-
api_key: env[
|
|
305
|
-
model:
|
|
309
|
+
api_key: env["ANTHROPIC_API_KEY"],
|
|
310
|
+
model: env.fetch("ANTHROPIC_MODEL", "claude-sonnet-4-20250514")
|
|
306
311
|
)
|
|
307
312
|
end
|
|
308
313
|
|
|
309
314
|
def configure_gemini(config, env)
|
|
310
|
-
return unless env[
|
|
315
|
+
return unless env["GEMINI_API_KEY"]
|
|
311
316
|
|
|
312
317
|
config.add_provider(
|
|
313
318
|
:gemini,
|
|
314
319
|
Prescient::Provider::Gemini,
|
|
315
|
-
api_key:
|
|
316
|
-
embedding_model: env.fetch(
|
|
317
|
-
chat_model:
|
|
320
|
+
api_key: env["GEMINI_API_KEY"],
|
|
321
|
+
embedding_model: env.fetch("GEMINI_EMBEDDING_MODEL", "gemini-embedding-001"),
|
|
322
|
+
chat_model: env.fetch("GEMINI_CHAT_MODEL", "gemini-2.5-flash")
|
|
318
323
|
)
|
|
319
324
|
end
|
|
320
325
|
|
|
321
326
|
def configure_huggingface(config, env)
|
|
322
|
-
return unless env[
|
|
327
|
+
return unless env["HUGGINGFACE_API_KEY"]
|
|
323
328
|
|
|
324
329
|
config.add_provider(
|
|
325
330
|
:huggingface,
|
|
326
331
|
Prescient::Provider::HuggingFace,
|
|
327
|
-
api_key:
|
|
332
|
+
api_key: env["HUGGINGFACE_API_KEY"],
|
|
328
333
|
embedding_model: env.fetch(
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
),
|
|
332
|
-
chat_model: env.fetch(
|
|
333
|
-
'HUGGINGFACE_CHAT_MODEL',
|
|
334
|
-
'google/gemma-2-2b-it',
|
|
334
|
+
"HUGGINGFACE_EMBEDDING_MODEL",
|
|
335
|
+
"sentence-transformers/all-MiniLM-L6-v2"
|
|
335
336
|
),
|
|
337
|
+
chat_model: env.fetch(
|
|
338
|
+
"HUGGINGFACE_CHAT_MODEL",
|
|
339
|
+
"google/gemma-2-2b-it"
|
|
340
|
+
)
|
|
336
341
|
)
|
|
337
342
|
end
|
|
338
343
|
|
|
339
344
|
def configure_deepseek(config, env)
|
|
340
|
-
return unless env[
|
|
345
|
+
return unless env["DEEPSEEK_API_KEY"]
|
|
341
346
|
|
|
342
347
|
config.add_provider(
|
|
343
348
|
:deepseek,
|
|
344
349
|
Prescient::Provider::DeepSeek,
|
|
345
|
-
api_key:
|
|
346
|
-
chat_model: env.fetch(
|
|
350
|
+
api_key: env["DEEPSEEK_API_KEY"],
|
|
351
|
+
chat_model: env.fetch("DEEPSEEK_CHAT_MODEL", "deepseek-v4-flash")
|
|
347
352
|
)
|
|
348
353
|
end
|
|
349
354
|
|
|
350
355
|
def configure_xai(config, env)
|
|
351
|
-
return unless env[
|
|
356
|
+
return unless env["XAI_API_KEY"]
|
|
352
357
|
|
|
353
358
|
config.add_provider(
|
|
354
359
|
:xai,
|
|
355
360
|
Prescient::Provider::XAI,
|
|
356
|
-
api_key:
|
|
357
|
-
chat_model: env.fetch(
|
|
361
|
+
api_key: env["XAI_API_KEY"],
|
|
362
|
+
chat_model: env.fetch("XAI_CHAT_MODEL", "grok-4.5")
|
|
358
363
|
)
|
|
359
364
|
end
|
|
360
365
|
|
|
361
366
|
def configure_mistral(config, env)
|
|
362
|
-
return unless env[
|
|
367
|
+
return unless env["MISTRAL_API_KEY"]
|
|
363
368
|
|
|
364
369
|
config.add_provider(
|
|
365
370
|
:mistral,
|
|
366
371
|
Prescient::Provider::Mistral,
|
|
367
|
-
api_key:
|
|
368
|
-
embedding_model: env.fetch(
|
|
369
|
-
chat_model:
|
|
372
|
+
api_key: env["MISTRAL_API_KEY"],
|
|
373
|
+
embedding_model: env.fetch("MISTRAL_EMBEDDING_MODEL", "mistral-embed"),
|
|
374
|
+
chat_model: env.fetch("MISTRAL_CHAT_MODEL", "mistral-large-latest")
|
|
370
375
|
)
|
|
371
376
|
end
|
|
372
377
|
end
|
|
@@ -377,3 +382,4 @@ module Prescient
|
|
|
377
382
|
configure_default_tools(config, ENV)
|
|
378
383
|
end
|
|
379
384
|
end
|
|
385
|
+
# rubocop:enable Metrics/ModuleLength
|