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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -268
  3. data/CHANGELOG.md +37 -0
  4. data/INTEGRATION_GUIDE.md +7 -1
  5. data/README.md +210 -1
  6. data/Steepfile +12 -12
  7. data/db/migrate/001_create_prescient_tables.rb +15 -16
  8. data/examples/README.md +2 -1
  9. data/examples/custom_contexts.rb +4 -4
  10. data/exe/prescient +2 -2
  11. data/exe/prescient-mcp +7 -0
  12. data/lib/prescient/agent/audit_log.rb +37 -0
  13. data/lib/prescient/agent/cli_adapter.rb +29 -0
  14. data/lib/prescient/agent/configuration.rb +57 -0
  15. data/lib/prescient/agent/context.rb +56 -0
  16. data/lib/prescient/agent/error_serializer.rb +47 -0
  17. data/lib/prescient/agent/errors.rb +25 -0
  18. data/lib/prescient/agent/parser.rb +49 -0
  19. data/lib/prescient/agent/prompt_builder.rb +31 -0
  20. data/lib/prescient/agent/result.rb +36 -0
  21. data/lib/prescient/agent/runtime.rb +175 -0
  22. data/lib/prescient/agent/schema_validator.rb +215 -0
  23. data/lib/prescient/agent/tool_registry.rb +89 -0
  24. data/lib/prescient/agent.rb +22 -0
  25. data/lib/prescient/api.rb +337 -274
  26. data/lib/prescient/base.rb +370 -372
  27. data/lib/prescient/cli.rb +586 -526
  28. data/lib/prescient/client.rb +7 -6
  29. data/lib/prescient/configuration_loader.rb +492 -488
  30. data/lib/prescient/document_source.rb +114 -0
  31. data/lib/prescient/errors.rb +1 -3
  32. data/lib/prescient/mcp/authentication.rb +39 -0
  33. data/lib/prescient/mcp/configuration.rb +38 -0
  34. data/lib/prescient/mcp/rack.rb +243 -0
  35. data/lib/prescient/mcp/server.rb +202 -0
  36. data/lib/prescient/mcp/stdio.rb +42 -0
  37. data/lib/prescient/mcp.rb +8 -0
  38. data/lib/prescient/pgvector.rb +193 -189
  39. data/lib/prescient/provider/anthropic.rb +129 -125
  40. data/lib/prescient/provider/deepseek.rb +122 -118
  41. data/lib/prescient/provider/gemini.rb +153 -149
  42. data/lib/prescient/provider/huggingface.rb +191 -187
  43. data/lib/prescient/provider/mistral.rb +151 -147
  44. data/lib/prescient/provider/ollama.rb +168 -165
  45. data/lib/prescient/provider/openai.rb +174 -169
  46. data/lib/prescient/provider/xai.rb +122 -118
  47. data/lib/prescient/tool/search_api.rb +125 -121
  48. data/lib/prescient/tool/searxng.rb +123 -119
  49. data/lib/prescient/tool.rb +100 -98
  50. data/lib/prescient/version.rb +1 -1
  51. data/lib/prescient.rb +68 -62
  52. data/sig/prescient.rbs +176 -1
  53. metadata +23 -1
@@ -1,123 +1,125 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Namespace for external capability adapters.
4
- module Prescient::Tool
5
- autoload :SearXNG, 'prescient/tool/searxng'
6
- autoload :SearchApi, 'prescient/tool/search_api'
7
-
8
- # Base contract for explicit external tool invocation.
9
- class Base
10
- # @return [Integer] Default request timeout in seconds
11
- DEFAULT_TIMEOUT = 5
12
- # @return [Integer] Default maximum number of returned results
13
- DEFAULT_MAX_RESULTS = 5
14
- # @return [Integer] Maximum accepted search query length
15
- MAX_QUERY_LENGTH = 2_000
16
- # @return [Integer] Maximum accepted tool response size in bytes
17
- DEFAULT_MAX_RESPONSE_BYTES = 1_048_576
18
-
19
- # @return [Hash<Symbol, untyped>] Tool configuration options
20
- attr_reader :options
21
-
22
- # @param options [Hash] Tool-specific configuration options
23
- def initialize(**options)
24
- @options = options
25
- validate_configuration!
26
- end
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
- protected
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
- # Validate adapter configuration.
40
- # @return [void]
41
- def validate_configuration!
42
- # Override in subclasses.
43
- end
38
+ protected
44
39
 
45
- # @param query [String] Search query
46
- # @return [String] Validated query
47
- def validate_query(query)
48
- unless query.is_a?(String) && !query.strip.empty?
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
- cleaned_query = query.strip
53
- if cleaned_query.length > MAX_QUERY_LENGTH
54
- raise Prescient::ToolConfigurationError,
55
- "search query cannot contain more than #{MAX_QUERY_LENGTH} characters"
56
- end
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
- cleaned_query
59
- end
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
- # @param value [Object] Requested result limit
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, 20].min
70
- end
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
- # @param value [Object] Requested timeout
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
- end
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
- # @return [Integer] Maximum accepted response size
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
- value
92
- end
93
- end
94
-
95
- # Ordered implementations for one logical tool capability.
96
- class Group < Base
97
- # @return [Array<Base>] Ordered capability implementations
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
- # @param adapters [Array<Base>] Ordered capability implementations
101
- def initialize(adapters:)
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
- # Execute the first successful adapter, falling back only for transient
108
- # connection and rate-limit failures.
109
- # @param query [String] Search query
110
- # @param options [Hash] Per-request options
111
- # @return [Hash] Normalized tool result
112
- def search(query, **options)
113
- failures = []
114
- @adapters.each do |adapter|
115
- return adapter.search(query, **options)
116
- rescue Prescient::ToolConnectionError, Prescient::RateLimitError => e
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
- raise failures.last
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Prescient
4
4
  # Current Prescient gem version.
5
- VERSION = '0.7.0'
5
+ VERSION = "0.8.0"
6
6
  end
data/lib/prescient.rb CHANGED
@@ -1,20 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'prescient/version'
4
- require_relative 'prescient/errors'
5
- Prescient.autoload :Tool, 'prescient/tool'
6
- require_relative 'prescient/pgvector'
7
- require_relative 'prescient/base'
8
- require_relative 'prescient/provider/ollama'
9
- require_relative 'prescient/provider/anthropic'
10
- require_relative 'prescient/provider/openai'
11
- require_relative 'prescient/provider/huggingface'
12
- require_relative 'prescient/provider/gemini'
13
- require_relative 'prescient/provider/mistral'
14
- require_relative 'prescient/provider/deepseek'
15
- require_relative 'prescient/provider/xai'
16
- require_relative 'prescient/configuration_loader'
17
- require_relative 'prescient/client'
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, 'prescient/tool'
39
- autoload :API, 'prescient/api'
40
- autoload :CLI, 'prescient/cli'
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
- @_configuration ||= Configuration.new
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
- @_configuration = Configuration.new
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['PRESCIENT_CONFIG']
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
- @_configuration = configuration
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 = [:api_key, :password, :token, :secret].freeze
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: provider_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: tool_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['SEARXNG_URL']
276
+ return unless env["SEARXNG_URL"]
272
277
 
273
- config.add_tool(:web_search, Prescient::Tool::SearXNG, url: env['SEARXNG_URL'])
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: env.fetch('OLLAMA_URL', 'http://localhost:11434'),
281
- embedding_model: env.fetch('OLLAMA_EMBEDDING_MODEL', 'nomic-embed-text'),
282
- chat_model: env.fetch('OLLAMA_CHAT_MODEL', 'llama3.2:3b'),
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['OPENAI_API_KEY']
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: env['OPENAI_API_KEY'],
293
- embedding_model: env.fetch('OPENAI_EMBEDDING_MODEL', 'text-embedding-3-small'),
294
- chat_model: env.fetch('OPENAI_CHAT_MODEL', 'gpt-4.1-mini'),
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['ANTHROPIC_API_KEY']
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['ANTHROPIC_API_KEY'],
305
- model: env.fetch('ANTHROPIC_MODEL', 'claude-sonnet-4-20250514'),
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['GEMINI_API_KEY']
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: env['GEMINI_API_KEY'],
316
- embedding_model: env.fetch('GEMINI_EMBEDDING_MODEL', 'gemini-embedding-001'),
317
- chat_model: env.fetch('GEMINI_CHAT_MODEL', 'gemini-2.5-flash'),
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['HUGGINGFACE_API_KEY']
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: env['HUGGINGFACE_API_KEY'],
332
+ api_key: env["HUGGINGFACE_API_KEY"],
328
333
  embedding_model: env.fetch(
329
- 'HUGGINGFACE_EMBEDDING_MODEL',
330
- 'sentence-transformers/all-MiniLM-L6-v2',
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['DEEPSEEK_API_KEY']
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: env['DEEPSEEK_API_KEY'],
346
- chat_model: env.fetch('DEEPSEEK_CHAT_MODEL', 'deepseek-v4-flash'),
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['XAI_API_KEY']
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: env['XAI_API_KEY'],
357
- chat_model: env.fetch('XAI_CHAT_MODEL', 'grok-4.5'),
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['MISTRAL_API_KEY']
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: env['MISTRAL_API_KEY'],
368
- embedding_model: env.fetch('MISTRAL_EMBEDDING_MODEL', 'mistral-embed'),
369
- chat_model: env.fetch('MISTRAL_CHAT_MODEL', 'mistral-large-latest'),
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