Class: DSPy::LM
- Inherits:
-
Object
- Object
- DSPy::LM
- Extended by:
- T::Sig
- Defined in:
- lib/dspy/lm.rb,
lib/dspy/lm/usage.rb,
lib/dspy/lm/errors.rb,
lib/dspy/lm/adapter.rb,
lib/dspy/lm/message.rb,
lib/dspy/lm/response.rb,
lib/dspy/lm/chat_strategy.rb,
lib/dspy/lm/json_strategy.rb,
lib/dspy/lm/vision_models.rb,
lib/dspy/lm/adapter_factory.rb,
lib/dspy/lm/message_builder.rb
Defined Under Namespace
Modules: MessageFactory, ResponseMetadataFactory, UsageFactory, VisionModels Classes: Adapter, AdapterError, AdapterFactory, AnthropicResponseMetadata, ChatStrategy, ConfigurationError, Error, GeminiResponseMetadata, IncompatibleImageFeatureError, JSONStrategy, Message, MessageBuilder, MissingAPIKeyError, MissingAdapterError, MissingOfficialSDKError, OpenAIResponseMetadata, OpenAIUsage, Response, ResponseMetadata, UnsupportedProviderError, UnsupportedVersionError, Usage
Instance Attribute Summary collapse
-
#adapter ⇒ Object
readonly
Returns the value of attribute adapter.
-
#api_key ⇒ Object
readonly
Returns the value of attribute api_key.
-
#data_format ⇒ Object
readonly
Returns the value of attribute data_format.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#model_id ⇒ Object
readonly
Returns the value of attribute model_id.
-
#provider ⇒ Object
readonly
Returns the value of attribute provider.
-
#schema_format ⇒ Object
readonly
Returns the value of attribute schema_format.
Instance Method Summary collapse
- #chat(inference_module, input_values, &block) ⇒ Object
- #execute_raw_chat(messages, &streaming_block) ⇒ Object
-
#initialize(model_id, api_key: nil, schema_format: :json, data_format: :json, **options) ⇒ LM
constructor
A new instance of LM.
-
#messages_to_hash_array(messages) ⇒ Object
Convert Message objects to hash array for adapters.
-
#normalize_messages(messages) ⇒ Object
Convert messages to normalized Message objects.
- #raw_chat(messages = nil, &block) ⇒ Object
- #validate_messages!(messages) ⇒ Object
Constructor Details
#initialize(model_id, api_key: nil, schema_format: :json, data_format: :json, **options) ⇒ LM
Returns a new instance of LM.
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/dspy/lm.rb', line 30 def initialize(model_id, api_key: nil, schema_format: :json, data_format: :json, **) @model_id = model_id @api_key = api_key @schema_format = schema_format @data_format = data_format # Parse provider and model from model_id @provider, @model = parse_model_id(model_id) # Create appropriate adapter with options @adapter = AdapterFactory.create(model_id, api_key: api_key, **) end |
Instance Attribute Details
#adapter ⇒ Object (readonly)
Returns the value of attribute adapter.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def adapter @adapter end |
#api_key ⇒ Object (readonly)
Returns the value of attribute api_key.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def api_key @api_key end |
#data_format ⇒ Object (readonly)
Returns the value of attribute data_format.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def data_format @data_format end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def model @model end |
#model_id ⇒ Object (readonly)
Returns the value of attribute model_id.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def model_id @model_id end |
#provider ⇒ Object (readonly)
Returns the value of attribute provider.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def provider @provider end |
#schema_format ⇒ Object (readonly)
Returns the value of attribute schema_format.
28 29 30 |
# File 'lib/dspy/lm.rb', line 28 def schema_format @schema_format end |
Instance Method Details
#chat(inference_module, input_values, &block) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/dspy/lm.rb', line 43 def chat(inference_module, input_values, &block) # Capture the current DSPy context before entering Sync block parent_context = DSPy::Context.current.dup Sync do # Properly restore the context in the new fiber created by Sync # We need to set both thread and fiber storage for the new context system thread_key = :"dspy_context_#{Thread.current.object_id}" Thread.current[thread_key] = parent_context Thread.current[:dspy_context] = parent_context # Keep for backward compatibility Fiber[:dspy_context] = parent_context signature_class = inference_module.signature_class # Build messages from inference module = (inference_module, input_values) # Execute with instrumentation response = instrument_lm_request(, signature_class.name) do chat_with_strategy(, signature_class, &block) end # Parse response (no longer needs separate instrumentation) parsed_result = parse_response(response, input_values, signature_class) parsed_result end end |
#execute_raw_chat(messages, &streaming_block) ⇒ Object
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/dspy/lm.rb', line 438 def execute_raw_chat(, &streaming_block) # Generate unique request ID for tracking request_id = SecureRandom.hex(8) start_time = Time.now # Store request context for correlation Thread.current[:dspy_request_id] = request_id Thread.current[:dspy_request_start_time] = start_time begin response = instrument_lm_request(, 'RawPrompt') do # Convert messages to hash format for adapter = () # Direct adapter call, no strategies or JSON parsing adapter.chat(messages: , signature: nil, &streaming_block) end # Return raw response content, not parsed JSON response.content ensure # Clean up thread-local storage Thread.current[:dspy_request_id] = nil Thread.current[:dspy_request_start_time] = nil end end |
#messages_to_hash_array(messages) ⇒ Object
Convert Message objects to hash array for adapters
505 506 507 508 509 510 511 512 513 |
# File 'lib/dspy/lm.rb', line 505 def () .map do |msg| if msg.is_a?(Message) msg.to_h else msg end end end |
#normalize_messages(messages) ⇒ Object
Convert messages to normalized Message objects
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/dspy/lm.rb', line 465 def () # Validate array format first unless .is_a?(Array) raise ArgumentError, "messages must be an array" end return if .all? { |m| m.is_a?(Message) } # Convert hash messages to Message objects normalized = [] .each_with_index do |msg, index| if msg.is_a?(Message) normalized << msg elsif msg.is_a?(Hash) # Validate hash has required fields unless msg.key?(:role) && msg.key?(:content) raise ArgumentError, "Message at index #{index} must have :role and :content" end # Validate role valid_roles = %w[system user assistant] unless valid_roles.include?(msg[:role]) raise ArgumentError, "Invalid role at index #{index}: #{msg[:role]}. Must be one of: #{valid_roles.join(', ')}" end # Create Message object = MessageFactory.create(msg) if .nil? raise ArgumentError, "Failed to create Message from hash at index #{index}" end normalized << else raise ArgumentError, "Message at index #{index} must be a Message object or hash with :role and :content" end end normalized end |
#raw_chat(messages = nil, &block) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/dspy/lm.rb', line 72 def raw_chat( = nil, &block) # Support both array format and builder DSL if block_given? && .nil? # DSL mode - block is for building messages builder = MessageBuilder.new yield builder = builder. streaming_block = nil else # Array mode - block is for streaming ||= [] streaming_block = block end # Normalize and validate messages = () # Execute with instrumentation execute_raw_chat(, &streaming_block) end |
#validate_messages!(messages) ⇒ Object
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
# File 'lib/dspy/lm.rb', line 416 def () unless .is_a?(Array) raise ArgumentError, "messages must be an array" end .each_with_index do |, index| # Accept both Message objects and hash format for backward compatibility if .is_a?(Message) # Already validated by type system next elsif .is_a?(Hash) && .key?(:role) && .key?(:content) # Legacy hash format - validate role valid_roles = %w[system user assistant] unless valid_roles.include?([:role]) raise ArgumentError, "Invalid role at index #{index}: #{message[:role]}. Must be one of: #{valid_roles.join(', ')}" end else raise ArgumentError, "Message at index #{index} must be a Message object or hash with :role and :content" end end end |