prescient 0.6.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -268
  3. data/CHANGELOG.md +59 -0
  4. data/INTEGRATION_GUIDE.md +19 -1
  5. data/README.md +369 -21
  6. data/Steepfile +12 -12
  7. data/db/migrate/001_create_prescient_tables.rb +15 -16
  8. data/docker-compose.yml +22 -0
  9. data/examples/README.md +36 -1
  10. data/examples/custom_contexts.rb +4 -4
  11. data/examples/web_search.rb +34 -0
  12. data/exe/prescient +2 -2
  13. data/exe/prescient-mcp +7 -0
  14. data/lib/prescient/agent/audit_log.rb +37 -0
  15. data/lib/prescient/agent/cli_adapter.rb +29 -0
  16. data/lib/prescient/agent/configuration.rb +57 -0
  17. data/lib/prescient/agent/context.rb +56 -0
  18. data/lib/prescient/agent/error_serializer.rb +47 -0
  19. data/lib/prescient/agent/errors.rb +25 -0
  20. data/lib/prescient/agent/parser.rb +49 -0
  21. data/lib/prescient/agent/prompt_builder.rb +31 -0
  22. data/lib/prescient/agent/result.rb +36 -0
  23. data/lib/prescient/agent/runtime.rb +175 -0
  24. data/lib/prescient/agent/schema_validator.rb +215 -0
  25. data/lib/prescient/agent/tool_registry.rb +89 -0
  26. data/lib/prescient/agent.rb +22 -0
  27. data/lib/prescient/api.rb +346 -231
  28. data/lib/prescient/base.rb +370 -372
  29. data/lib/prescient/cli.rb +591 -402
  30. data/lib/prescient/client.rb +31 -4
  31. data/lib/prescient/configuration_loader.rb +511 -336
  32. data/lib/prescient/document_source.rb +114 -0
  33. data/lib/prescient/errors.rb +13 -3
  34. data/lib/prescient/mcp/authentication.rb +39 -0
  35. data/lib/prescient/mcp/configuration.rb +38 -0
  36. data/lib/prescient/mcp/rack.rb +243 -0
  37. data/lib/prescient/mcp/server.rb +202 -0
  38. data/lib/prescient/mcp/stdio.rb +42 -0
  39. data/lib/prescient/mcp.rb +8 -0
  40. data/lib/prescient/pgvector.rb +193 -189
  41. data/lib/prescient/provider/anthropic.rb +129 -125
  42. data/lib/prescient/provider/deepseek.rb +122 -118
  43. data/lib/prescient/provider/gemini.rb +153 -149
  44. data/lib/prescient/provider/huggingface.rb +191 -187
  45. data/lib/prescient/provider/mistral.rb +151 -147
  46. data/lib/prescient/provider/ollama.rb +168 -165
  47. data/lib/prescient/provider/openai.rb +174 -171
  48. data/lib/prescient/provider/xai.rb +122 -118
  49. data/lib/prescient/tool/search_api.rb +130 -0
  50. data/lib/prescient/tool/searxng.rb +128 -0
  51. data/lib/prescient/tool.rb +125 -0
  52. data/lib/prescient/version.rb +1 -1
  53. data/lib/prescient.rb +129 -55
  54. data/schema/prescient.configuration.schema.json +119 -0
  55. data/searxng/settings.yml +18 -0
  56. data/sig/prescient.rbs +228 -1
  57. metadata +33 -5
data/sig/prescient.rbs CHANGED
@@ -33,6 +33,224 @@ module Prescient
33
33
  class ProviderError < Error
34
34
  end
35
35
 
36
+ class ToolError < Error
37
+ end
38
+
39
+ class ToolConfigurationError < ToolError
40
+ end
41
+
42
+ class ToolConnectionError < ToolError
43
+ end
44
+
45
+ class ToolInvalidResponseError < ToolError
46
+ end
47
+
48
+ module Tool
49
+ class Base
50
+ DEFAULT_TIMEOUT: Integer
51
+ DEFAULT_MAX_RESULTS: Integer
52
+ MAX_QUERY_LENGTH: Integer
53
+ DEFAULT_MAX_RESPONSE_BYTES: Integer
54
+
55
+ attr_reader options: Hash[Symbol, untyped]
56
+
57
+ def initialize: (**untyped) -> void
58
+ def search: (String, **untyped) -> Hash[Symbol, untyped]
59
+ end
60
+
61
+ class Group < Base
62
+ attr_reader adapters: Array[Base]
63
+ def initialize: (adapters: Array[Base]) -> void
64
+ def search: (String, **untyped) -> Hash[Symbol, untyped]
65
+ end
66
+
67
+ class SearXNG < Base
68
+ def initialize: (**untyped) -> void
69
+ def search: (String, ?limit: Integer?, ?timeout: Numeric?) -> Hash[Symbol, untyped]
70
+ end
71
+
72
+ class SearchApi < Base
73
+ API_URL: String
74
+ def initialize: (**untyped) -> void
75
+ def search: (String, ?limit: Integer?, ?timeout: Numeric?) -> Hash[Symbol, untyped]
76
+ end
77
+ end
78
+
79
+ module DocumentSource
80
+ DEFAULT_MAX_DOCUMENTS: Integer
81
+ DEFAULT_MAX_BYTES: Integer
82
+
83
+ class Base
84
+ def initialize: (?max_documents: Integer, ?max_bytes: Integer) -> void
85
+ def fetch: () -> Array[Hash[String, untyped]]
86
+ end
87
+
88
+ class Memory < Base
89
+ def initialize: (documents: Array[Hash[String, untyped]] | Hash[String, untyped], ?max_documents: Integer, ?max_bytes: Integer) -> void
90
+ def fetch: () -> Array[Hash[String, untyped]]
91
+ end
92
+
93
+ class JsonFile < Base
94
+ def initialize: (path: String, ?max_documents: Integer, ?max_bytes: Integer) -> void
95
+ def fetch: () -> Array[Hash[String, untyped]]
96
+ end
97
+
98
+ class RedisJson < Base
99
+ def initialize: (client: untyped, key: String, ?max_documents: Integer, ?max_bytes: Integer) -> void
100
+ def fetch: () -> Array[Hash[String, untyped]]
101
+ end
102
+ end
103
+
104
+ module Agent
105
+ class Error < Prescient::Error
106
+ end
107
+ class ConfigurationError < Error
108
+ end
109
+ class MalformedActionError < Error
110
+ end
111
+ class UnauthorizedToolError < Error
112
+ end
113
+ class MaxLoopsExceededError < Error
114
+ end
115
+
116
+ class ErrorSerializer
117
+ def self.serialize: (Exception) -> Hash[Symbol, untyped]
118
+ end
119
+
120
+ class SchemaValidator
121
+ def self.validate!: (Hash[untyped, untyped], untyped) -> untyped
122
+ def initialize: (Hash[untyped, untyped]) -> void
123
+ def validate!: (untyped) -> untyped
124
+ end
125
+
126
+ class Configuration
127
+ DEFAULT_MAX_LOOPS: Integer
128
+ DEFAULT_MAX_CONTEXT_BYTES: Integer
129
+ DEFAULT_MAX_ACTION_BYTES: Integer
130
+ DEFAULT_MAX_OBSERVATION_BYTES: Integer
131
+ DEFAULT_MAX_TASK_BYTES: Integer
132
+ DEFAULT_MAX_RESPONSE_BYTES: Integer
133
+
134
+ attr_reader max_loops: Integer
135
+ attr_reader max_context_bytes: Integer
136
+ attr_reader max_action_bytes: Integer
137
+ attr_reader max_observation_bytes: Integer
138
+ attr_reader max_task_bytes: Integer
139
+ attr_reader max_response_bytes: Integer
140
+
141
+ attr_reader authorization: Proc?
142
+ attr_reader telemetry: Proc?
143
+ def initialize: (?max_loops: Integer, ?max_context_bytes: Integer, ?max_action_bytes: Integer, ?max_observation_bytes: Integer, ?max_task_bytes: Integer, ?max_response_bytes: Integer, ?authorization: Proc?, ?telemetry: Proc?) -> void
144
+ end
145
+
146
+ class AuditLog
147
+ FIELDS: Array[Symbol]
148
+ def initialize: (?path: String?, ?io: untyped) -> void
149
+ def call: (Hash[Symbol, untyped]) -> void
150
+ end
151
+
152
+ class Context
153
+ attr_reader messages: Array[Hash[Symbol, String]]
154
+ def initialize: (system_prompt: String, task: String, ?max_bytes: Integer) -> void
155
+ def append: (role: String, content: String) -> void
156
+ def to_a: () -> Array[Hash[Symbol, String]]
157
+ end
158
+
159
+ class Parser
160
+ ACTION_PATTERN: Regexp
161
+ def self.parse: (String, ?max_bytes: Integer) -> Hash[Symbol, untyped]?
162
+ def initialize: (?max_bytes: Integer) -> void
163
+ def parse: (String) -> Hash[Symbol, untyped]?
164
+ end
165
+
166
+ class PromptBuilder
167
+ def self.build: (system_instruction: String, tools: Array[ToolRegistry::Tool]) -> String
168
+ end
169
+
170
+ class ToolRegistry
171
+ class Tool
172
+ attr_reader name: Symbol
173
+ attr_reader description: String
174
+ attr_reader schema: Hash[untyped, untyped]
175
+ attr_reader callable: Proc
176
+ end
177
+
178
+ def initialize: (Hash[Symbol | String, untyped]) -> void
179
+ def all: () -> Array[Tool]
180
+ def invoke: (Symbol | String, Hash[String | Symbol, untyped]) -> untyped
181
+ end
182
+
183
+ class Result
184
+ attr_reader response: String
185
+ attr_reader provider: Symbol | String | nil
186
+ attr_reader model: String | nil
187
+ attr_reader loops_run: Integer
188
+ attr_reader metadata: Hash[untyped, untyped]
189
+ def initialize: (response: String, provider: Symbol | String | nil, model: String | nil, loops_run: Integer, ?success: bool, ?metadata: Hash[untyped, untyped]) -> void
190
+ def success?: () -> bool
191
+ def to_h: () -> Hash[Symbol, untyped]
192
+ end
193
+
194
+ class Runtime
195
+ def initialize: (?provider: Symbol?, ?client: untyped, ?tools: Hash[Symbol | String, untyped]?, ?tool_names: Array[Symbol | String], ?configuration: Configuration, ?system_prompt: String, ?provider_options: Hash[Symbol, untyped], ?generation_options: Hash[Symbol, untyped], ?authorization: Proc?, ?telemetry: Proc?, ?enable_fallback: bool, ?request_context: Hash[Symbol, untyped], ?audit_log: AuditLog?) -> void
196
+ def run: (String) -> Result
197
+ end
198
+
199
+ class CLIAdapter
200
+ def initialize: (?output: untyped, ?errors: untyped) -> void
201
+ def run: (task: String, ?client: untyped, ?provider: Symbol?, ?tool_names: Array[Symbol | String], ?max_loops: Integer, ?format: String, ?provider_options: Hash[Symbol, untyped], ?generation_options: Hash[Symbol, untyped], ?telemetry: Proc?) -> Integer
202
+ end
203
+ end
204
+
205
+ module MCP
206
+ interface _Authenticator
207
+ def call: (Hash[String, untyped]) -> untyped
208
+ end
209
+
210
+ class Configuration
211
+ DEFAULT_MAX_INPUT_BYTES: Integer
212
+ DEFAULT_TOOLS: Array[String]
213
+ SUPPORTED_RESOURCES: Array[String]
214
+ attr_reader name: String
215
+ attr_reader version: String
216
+ attr_reader max_input_bytes: Integer
217
+ attr_reader tools: Array[String]
218
+ attr_reader resources: Array[String]
219
+ def initialize: (?name: String, ?version: String, ?max_input_bytes: Integer, ?tools: Array[String], ?resources: Array[String]) -> void
220
+ end
221
+
222
+ class Server
223
+ def initialize: (?configuration: Configuration, ?client_factory: Proc?, ?authorization: Proc?) -> void
224
+ def initialize_result: () -> Hash[Symbol, untyped]
225
+ def dispatch: (Hash[String, untyped], ?context: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
226
+ def tools: () -> Array[Hash[String, untyped]]
227
+ def resources: () -> Array[Hash[String, untyped]]
228
+ def call_tool: (String | Symbol, ?Hash[String, untyped], ?context: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
229
+ def read_resource: (String | Symbol) -> Hash[Symbol, untyped]
230
+ end
231
+
232
+ class Stdio
233
+ def initialize: (?server: Server, ?input: untyped, ?output: untyped) -> void
234
+ def run: () -> void
235
+ end
236
+
237
+ class Rack
238
+ PROTOCOL_VERSION: String
239
+ SESSION_HEADER: String
240
+ PROTOCOL_HEADER: String
241
+ ALLOWED_ORIGINS_DEFAULT: Array[String]
242
+ def initialize: (authentication: _Authenticator, ?server: Server, ?request_context: Proc?, ?max_body_bytes: Integer, ?allowed_origins: Array[String], ?session_ttl: Numeric) -> void
243
+ def call: (Hash[String, untyped]) -> Array[untyped]
244
+ end
245
+
246
+ module Authentication
247
+ class BearerToken
248
+ def initialize: (token: String, ?principal: untyped) -> void
249
+ def call: (Hash[String, untyped]) -> untyped
250
+ end
251
+ end
252
+ end
253
+
36
254
  class Base
37
255
  attr_reader options: Hash[Symbol, untyped]
38
256
  attr_reader provider_name: String
@@ -257,11 +475,15 @@ module Prescient
257
475
  attr_accessor fallback_providers: Array[Symbol]
258
476
  attr_reader sensitive_keys: Array[Symbol]
259
477
  attr_reader providers: Hash[Symbol, Hash[Symbol, untyped]]
478
+ attr_reader tools: Hash[Symbol, Hash[Symbol, untyped]]
260
479
 
261
480
  def initialize: () -> void
262
481
  def sensitive_keys=: (Array[Symbol | String]) -> Array[Symbol]
263
482
  def add_provider: (Symbol | String, Class, **untyped) -> void
264
483
  def provider: (Symbol | String) -> untyped
484
+ def add_tool: (Symbol | String, Class, **untyped) -> void
485
+ def add_tool_group: (Symbol | String, Array[Hash[Symbol, untyped]]) -> void
486
+ def tool: (Symbol | String) -> untyped
265
487
  def available_providers: () -> Array[Symbol]
266
488
  end
267
489
 
@@ -304,7 +526,7 @@ module Prescient
304
526
  API_VERSION: String
305
527
  ROUTES: Hash[Array[String], Symbol]
306
528
 
307
- def initialize: (?authentication: untyped, ?max_body_bytes: Integer) -> void
529
+ def initialize: (?authentication: untyped, ?authorization: untyped, ?request_context: untyped, ?telemetry: Proc?, ?max_body_bytes: Integer) -> void
308
530
  def call: (Hash[String, untyped]) -> [Integer, Hash[String, String], Array[String]]
309
531
  end
310
532
 
@@ -313,6 +535,8 @@ module Prescient
313
535
  TOP_LEVEL_KEYS: Array[String]
314
536
  PROVIDER_TYPES: Hash[String, untyped]
315
537
  COMMON_PROVIDER_KEYS: Array[String]
538
+ TOOL_TYPES: Hash[String, untyped]
539
+ COMMON_TOOL_KEYS: Array[String]
316
540
  PROMPT_TEMPLATE_KEYS: Array[String]
317
541
  ATTR_KEYS: Array[String]
318
542
 
@@ -335,11 +559,14 @@ module Prescient
335
559
  def self.client: (?Symbol, ?enable_fallback: bool, ?provider_options: Hash[Symbol, untyped]) -> Client
336
560
  def self.generate_embedding: (String, ?provider: Symbol, ?enable_fallback: bool, **untyped) -> Array[Float]
337
561
  def self.generate_response: (String, ?Array[untyped], ?provider: Symbol, ?enable_fallback: bool, **untyped) -> Hash[Symbol, untyped]
562
+ def self.search_and_generate: (String, ?tool: Symbol | String, ?provider: Symbol, ?limit: Integer?, ?enable_fallback: bool, ?provider_options: Hash[Symbol, untyped], **untyped) -> Hash[Symbol, untyped]
338
563
  def self.health_check: (?provider: Symbol) -> Hash[Symbol, untyped]
564
+ def self.tool: (Symbol | String) -> untyped
339
565
 
340
566
  private
341
567
 
342
568
  def self.configure_default_providers: (Configuration, untyped) -> void
569
+ def self.configure_default_tools: (Configuration, untyped) -> void
343
570
  def self.configure_ollama: (Configuration, untyped) -> void
344
571
  def self.configure_openai: (Configuration, untyped) -> void
345
572
  def self.configure_anthropic: (Configuration, untyped) -> void
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prescient
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken C. Demanawa
@@ -23,13 +23,15 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: 0.24.0
26
- description: "Prescient provides a consistent interface for AI providers including
27
- OpenAI, Anthropic, \nOllama, and Hugging Face, with provider selection, retries,
28
- health checks, and automatic fallback.\n"
26
+ description: |
27
+ Prescient provides a consistent Ruby API, CLI, or REST API for AI providers including
28
+ Ollama, OpenAI, Anthropic, Hugging Face, Google Gemini, Mistral, DeepSeek, and xAI,
29
+ with provider selection, retries, health checks, and fallback across configured providers.
29
30
  email:
30
31
  - kenneth.c.demanawa@gmail.com
31
32
  executables:
32
33
  - prescient
34
+ - prescient-mcp
33
35
  extensions: []
34
36
  extra_rdoc_files: []
35
37
  files:
@@ -60,14 +62,36 @@ files:
60
62
  - examples/custom_prompts.rb
61
63
  - examples/rest_api.ru
62
64
  - examples/vector_search.rb
65
+ - examples/web_search.rb
63
66
  - exe/prescient
67
+ - exe/prescient-mcp
64
68
  - lib/prescient.rb
69
+ - lib/prescient/agent.rb
70
+ - lib/prescient/agent/audit_log.rb
71
+ - lib/prescient/agent/cli_adapter.rb
72
+ - lib/prescient/agent/configuration.rb
73
+ - lib/prescient/agent/context.rb
74
+ - lib/prescient/agent/error_serializer.rb
75
+ - lib/prescient/agent/errors.rb
76
+ - lib/prescient/agent/parser.rb
77
+ - lib/prescient/agent/prompt_builder.rb
78
+ - lib/prescient/agent/result.rb
79
+ - lib/prescient/agent/runtime.rb
80
+ - lib/prescient/agent/schema_validator.rb
81
+ - lib/prescient/agent/tool_registry.rb
65
82
  - lib/prescient/api.rb
66
83
  - lib/prescient/base.rb
67
84
  - lib/prescient/cli.rb
68
85
  - lib/prescient/client.rb
69
86
  - lib/prescient/configuration_loader.rb
87
+ - lib/prescient/document_source.rb
70
88
  - lib/prescient/errors.rb
89
+ - lib/prescient/mcp.rb
90
+ - lib/prescient/mcp/authentication.rb
91
+ - lib/prescient/mcp/configuration.rb
92
+ - lib/prescient/mcp/rack.rb
93
+ - lib/prescient/mcp/server.rb
94
+ - lib/prescient/mcp/stdio.rb
71
95
  - lib/prescient/pgvector.rb
72
96
  - lib/prescient/provider/anthropic.rb
73
97
  - lib/prescient/provider/deepseek.rb
@@ -77,9 +101,13 @@ files:
77
101
  - lib/prescient/provider/ollama.rb
78
102
  - lib/prescient/provider/openai.rb
79
103
  - lib/prescient/provider/xai.rb
104
+ - lib/prescient/tool.rb
105
+ - lib/prescient/tool/search_api.rb
106
+ - lib/prescient/tool/searxng.rb
80
107
  - lib/prescient/version.rb
81
108
  - schema/prescient.configuration.schema.json
82
109
  - scripts/setup-ollama-models.sh
110
+ - searxng/settings.yml
83
111
  - sig/prescient.rbs
84
112
  homepage: https://kanutocd.github.io/prescient
85
113
  licenses:
@@ -106,5 +134,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
134
  requirements: []
107
135
  rubygems_version: 4.0.16
108
136
  specification_version: 4
109
- summary: A boring AI provider abstraction for Ruby
137
+ summary: A boring AI provider gateway for Ruby
110
138
  test_files: []