liter_llm 1.17.3 → 1.18.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19482743f60ba9ade5386c54b0b066f735278e39374770764a8abb312fb7c544
4
- data.tar.gz: 80c1dabeaba2542c2d013b7dcebee1e6f0e22fbf71fa870b1fd1b2cb45859504
3
+ metadata.gz: c5bd204a264adbd698932331bb39e051c81aee3e41ec25694acabb29b0ca3fbb
4
+ data.tar.gz: 2435c21142430e5f33c6543e2c734000ba05520168f4cb0ebebad3f8da39bf5a
5
5
  SHA512:
6
- metadata.gz: '049bf1770b1dd29ae209bbd2bc8207fae5d572db4bccd6d7d3a12d62ea147ca2c0e9e731b807078f784efab6fec5d9a09f514239265c62b28d14e73f5ff0ea40'
7
- data.tar.gz: 8ee96a2a68f466c36b73a18b62e84131afd5715f67bb5b0ee9a0fc739d62db4209bd85ad4c15add462ee33691113102b2ba22f15f519ef687ebfa79fc847c196
6
+ metadata.gz: 5766c2a1de94770d1753f5c2e766ab2640687cb7a027ebf60164c295b9bcff408537e3ae4842dc421e66d3fd454e70b62bdc0901c4c7f9dd7c624e8168861d44
7
+ data.tar.gz: dbb82f17c226cb866f70e57f8346b30a127e469b07271d325be21a58ccd1b1b35fcb05e003e0dbaba146cf0bedd4b1432a9099eab4d9b2a69ab2b754327f73ce
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ <!-- This file is auto-generated by alef — DO NOT EDIT. -->
2
+ <!-- alef:hash:cd144fa3684b490bac9fd3b39ee03cefb1f07fcfecec6d7599e0314be7d775e3 -->
3
+ <!-- To regenerate: alef readme -->
4
+ <!-- To verify freshness: alef verify -->
5
+
1
6
  <p align="center">
2
7
  <picture>
3
8
  <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/xberg-io/assets@v1/banner/readme-banner-dark.svg">
@@ -1794,9 +1794,9 @@ checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
1794
1794
 
1795
1795
  [[package]]
1796
1796
  name = "liter-llm"
1797
- version = "1.17.3"
1797
+ version = "1.18.0"
1798
1798
  source = "registry+https://github.com/rust-lang/crates.io-index"
1799
- checksum = "11c241016acd3f9a7893561db6cedb20ea2a90bbcc751928145e09c0e6ac1dd5"
1799
+ checksum = "de5d980b9ebe69c204ce3dfcd1fb5f01cf374d6ecd99f04f791b98faec0a1b27"
1800
1800
  dependencies = [
1801
1801
  "ahash 0.8.12",
1802
1802
  "arc-swap",
@@ -1838,7 +1838,7 @@ dependencies = [
1838
1838
 
1839
1839
  [[package]]
1840
1840
  name = "liter-llm-rb"
1841
- version = "1.17.3"
1841
+ version = "1.18.0"
1842
1842
  dependencies = [
1843
1843
  "futures",
1844
1844
  "liter-llm",
@@ -2571,9 +2571,9 @@ dependencies = [
2571
2571
 
2572
2572
  [[package]]
2573
2573
  name = "rb-sys-build"
2574
- version = "0.9.128"
2574
+ version = "0.9.130"
2575
2575
  source = "registry+https://github.com/rust-lang/crates.io-index"
2576
- checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
2576
+ checksum = "05be6f9c86fe5482808162826f6c047d093b3670582296c770de1d94f8066694"
2577
2577
  dependencies = [
2578
2578
  "bindgen",
2579
2579
  "lazy_static",
@@ -1,6 +1,11 @@
1
+ # This file is auto-generated by alef — DO NOT EDIT.
2
+ # alef:hash:e221e01ba9179e68583cafd7161d7c43de4eacc42c13af77e2e5f1e4d63bc728
3
+ # To regenerate: alef generate
4
+ # To verify freshness: alef verify
5
+
1
6
  [package]
2
7
  name = "liter-llm-rb"
3
- version = "1.17.3"
8
+ version = "1.18.0"
4
9
  edition = "2024"
5
10
  license = "MIT"
6
11
  description = "Universal LLM API client with Rust-powered polyglot bindings."
@@ -17,18 +22,29 @@ path = "../src/lib.rs"
17
22
  crate-type = ["cdylib"]
18
23
 
19
24
  [features]
20
- default = ["native-http", "opendal-cache", "wasm-http", "tokenizer", "tower"]
25
+ default = ["native-http", "opendal-cache", "tokenizer", "tower", "wasm-http"]
21
26
  native-http = ["liter-llm/native-http"]
22
27
  opendal-cache = ["liter-llm/opendal-cache"]
23
- wasm-http = ["liter-llm/wasm-http"]
24
28
  tokenizer = ["liter-llm/tokenizer"]
25
29
  tower = ["liter-llm/tower"]
30
+ wasm-http = ["liter-llm/wasm-http"]
26
31
 
27
32
  [dependencies]
28
33
  futures = "0.3"
29
- liter-llm = { version = "1.17.3", features = ["native-http", "full"] }
34
+ liter-llm = { version = "1.18.0", features = ["native-http", "full"] }
30
35
  magnus = "0.8"
31
36
  rb-sys = ">=0.9, <0.9.128"
32
37
  serde = { version = "1", features = ["derive"] }
33
38
  serde_json = "1"
34
39
  tokio = { version = "1", features = ["rt-multi-thread"] }
40
+
41
+ # This crate deliberately does not use `[lints]` / `workspace = true`: its C-ABI /
42
+ # PyO3 / napi / ext-php-rs / NIF boundary requires `unsafe` code, and the workspace's
43
+ # `[workspace.lints.rust]` sets `unsafe_code = "deny"` -- an all-or-nothing table that
44
+ # would turn every such boundary into a compile error. The `[lints.clippy]` block below
45
+ # instead carries the subset of the workspace's deny-by-default lint policy this crate
46
+ # can actually satisfy. ~keep
47
+ [lints.clippy]
48
+ dbg_macro = "deny"
49
+ print_stderr = "deny"
50
+ print_stdout = "deny"
@@ -1,3 +1,8 @@
1
+ # This file is auto-generated by alef — DO NOT EDIT.
2
+ # alef:hash:7b1808d5f8bd88acdf4abf88f680c0db55f06da73e768c8e465d13b44f0c70bf
3
+ # To regenerate: alef generate
4
+ # To verify freshness: alef verify
5
+
1
6
  # frozen_string_literal: true
2
7
 
3
8
  require "mkmf"
@@ -1,5 +1,5 @@
1
1
  // This file is auto-generated by alef. DO NOT EDIT.
2
- // alef:hash:6cd4ed693a8d18aa4e3959a858f10dc6c9ddd62b2ddf72ca30c91065514f407b
2
+ // alef:hash:0e3211f6b85dad033da915446b280abf238ccc5297156d5b9c3942bc8c8bd78a
3
3
  // Re-generate with: alef generate
4
4
  #![allow(dead_code, unused_imports, unused_variables)]
5
5
  #![allow(
@@ -6461,6 +6461,7 @@ pub struct LlmConfig {
6461
6461
  cache: Option<LlmCacheConfig>,
6462
6462
  budget: Option<LlmBudgetConfig>,
6463
6463
  rate_limit: Option<LlmRateLimitConfig>,
6464
+ in_flight_limit: Option<LlmInFlightLimitConfig>,
6464
6465
  cost_tracking: Option<bool>,
6465
6466
  tracing: Option<bool>,
6466
6467
  cooldown_secs: Option<u64>,
@@ -6549,6 +6550,9 @@ impl LlmConfig {
6549
6550
  rate_limit: kwargs
6550
6551
  .get(ruby.to_symbol("rate_limit"))
6551
6552
  .and_then(|v| LlmRateLimitConfig::try_convert(v).ok()),
6553
+ in_flight_limit: kwargs
6554
+ .get(ruby.to_symbol("in_flight_limit"))
6555
+ .and_then(|v| LlmInFlightLimitConfig::try_convert(v).ok()),
6552
6556
  cost_tracking: kwargs
6553
6557
  .get(ruby.to_symbol("cost_tracking"))
6554
6558
  .and_then(|v| bool::try_convert(v).ok()),
@@ -6619,6 +6623,10 @@ impl LlmConfig {
6619
6623
  self.rate_limit.clone()
6620
6624
  }
6621
6625
 
6626
+ fn in_flight_limit(&self) -> Option<LlmInFlightLimitConfig> {
6627
+ self.in_flight_limit.clone()
6628
+ }
6629
+
6622
6630
  fn cost_tracking(&self) -> Option<bool> {
6623
6631
  self.cost_tracking
6624
6632
  }
@@ -6869,6 +6877,65 @@ impl LlmRateLimitConfig {
6869
6877
  }
6870
6878
  }
6871
6879
 
6880
+ #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
6881
+ #[serde(default)]
6882
+ #[magnus::wrap(class = "LiterLlm::LlmInFlightLimitConfig")]
6883
+ pub struct LlmInFlightLimitConfig {
6884
+ max_in_flight: Option<usize>,
6885
+ }
6886
+
6887
+ unsafe impl IntoValueFromNative for LlmInFlightLimitConfig {}
6888
+
6889
+ impl magnus::TryConvert for LlmInFlightLimitConfig {
6890
+ fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
6891
+ if let Ok(r) = <&LlmInFlightLimitConfig as magnus::TryConvert>::try_convert(val) {
6892
+ return Ok(r.clone());
6893
+ }
6894
+ let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
6895
+ s
6896
+ } else {
6897
+ val.funcall::<_, _, String>("to_json", ()).map_err(|e| {
6898
+ magnus::Error::new(
6899
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
6900
+ format!("no implicit conversion into LlmInFlightLimitConfig: {}", e),
6901
+ )
6902
+ })?
6903
+ };
6904
+ serde_json::from_str::<LlmInFlightLimitConfig>(&json_str).map_err(|e| {
6905
+ magnus::Error::new(
6906
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
6907
+ format!("failed to deserialize LlmInFlightLimitConfig: {}", e),
6908
+ )
6909
+ })
6910
+ }
6911
+ }
6912
+
6913
+ unsafe impl TryConvertOwned for LlmInFlightLimitConfig {}
6914
+
6915
+ impl Default for LlmInFlightLimitConfig {
6916
+ fn default() -> Self {
6917
+ liter_llm::client::LlmInFlightLimitConfig::default().into()
6918
+ }
6919
+ }
6920
+
6921
+ impl LlmInFlightLimitConfig {
6922
+ fn new(args: &[magnus::Value]) -> Result<Self, magnus::Error> {
6923
+ let ruby = unsafe { magnus::Ruby::get_unchecked() };
6924
+ let args = magnus::scan_args::scan_args::<(), (Option<magnus::RHash>,), (), (), (), ()>(args)?;
6925
+ let (kwargs_opt,) = args.optional;
6926
+ let kwargs = kwargs_opt.unwrap_or_else(|| ruby.hash_new());
6927
+ Ok(Self {
6928
+ max_in_flight: kwargs
6929
+ .get(ruby.to_symbol("max_in_flight"))
6930
+ .and_then(|v| usize::try_convert(v).ok()),
6931
+ })
6932
+ }
6933
+
6934
+ fn max_in_flight(&self) -> Option<usize> {
6935
+ self.max_in_flight
6936
+ }
6937
+ }
6938
+
6872
6939
  #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
6873
6940
  #[serde(default)]
6874
6941
  #[magnus::wrap(class = "LiterLlm::LlmProviderConfig")]
@@ -8520,6 +8587,65 @@ unsafe impl TryConvertOwned for SingleflightResult {}
8520
8587
 
8521
8588
  impl SingleflightResult {}
8522
8589
 
8590
+ #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
8591
+ #[serde(default)]
8592
+ #[magnus::wrap(class = "LiterLlm::InFlightLimitConfig")]
8593
+ pub struct InFlightLimitConfig {
8594
+ max_in_flight: Option<usize>,
8595
+ }
8596
+
8597
+ unsafe impl IntoValueFromNative for InFlightLimitConfig {}
8598
+
8599
+ impl magnus::TryConvert for InFlightLimitConfig {
8600
+ fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
8601
+ if let Ok(r) = <&InFlightLimitConfig as magnus::TryConvert>::try_convert(val) {
8602
+ return Ok(r.clone());
8603
+ }
8604
+ let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
8605
+ s
8606
+ } else {
8607
+ val.funcall::<_, _, String>("to_json", ()).map_err(|e| {
8608
+ magnus::Error::new(
8609
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
8610
+ format!("no implicit conversion into InFlightLimitConfig: {}", e),
8611
+ )
8612
+ })?
8613
+ };
8614
+ serde_json::from_str::<InFlightLimitConfig>(&json_str).map_err(|e| {
8615
+ magnus::Error::new(
8616
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
8617
+ format!("failed to deserialize InFlightLimitConfig: {}", e),
8618
+ )
8619
+ })
8620
+ }
8621
+ }
8622
+
8623
+ unsafe impl TryConvertOwned for InFlightLimitConfig {}
8624
+
8625
+ impl Default for InFlightLimitConfig {
8626
+ fn default() -> Self {
8627
+ liter_llm::InFlightLimitConfig::default().into()
8628
+ }
8629
+ }
8630
+
8631
+ impl InFlightLimitConfig {
8632
+ fn new(args: &[magnus::Value]) -> Result<Self, magnus::Error> {
8633
+ let ruby = unsafe { magnus::Ruby::get_unchecked() };
8634
+ let args = magnus::scan_args::scan_args::<(), (Option<magnus::RHash>,), (), (), (), ()>(args)?;
8635
+ let (kwargs_opt,) = args.optional;
8636
+ let kwargs = kwargs_opt.unwrap_or_else(|| ruby.hash_new());
8637
+ Ok(Self {
8638
+ max_in_flight: kwargs
8639
+ .get(ruby.to_symbol("max_in_flight"))
8640
+ .and_then(|v| usize::try_convert(v).ok()),
8641
+ })
8642
+ }
8643
+
8644
+ fn max_in_flight(&self) -> Option<usize> {
8645
+ self.max_in_flight
8646
+ }
8647
+ }
8648
+
8523
8649
  #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
8524
8650
  #[serde(default)]
8525
8651
  #[magnus::wrap(class = "LiterLlm::RateLimitConfig")]
@@ -9006,8 +9132,9 @@ impl magnus::IntoValue for ImageDetail {
9006
9132
  impl magnus::TryConvert for ImageDetail {
9007
9133
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9008
9134
  let s: String = magnus::TryConvert::try_convert(val)?;
9009
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9010
- // and a lowercase fallback so fixtures written in any of those styles work.
9135
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9136
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9137
+ // existing consumer code written in any of those styles keep working.
9011
9138
  match s.as_str() {
9012
9139
  "low" | "Low" => Ok(ImageDetail::Low),
9013
9140
  "high" | "High" => Ok(ImageDetail::High),
@@ -9166,8 +9293,9 @@ impl magnus::IntoValue for ToolType {
9166
9293
  impl magnus::TryConvert for ToolType {
9167
9294
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9168
9295
  let s: String = magnus::TryConvert::try_convert(val)?;
9169
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9170
- // and a lowercase fallback so fixtures written in any of those styles work.
9296
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9297
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9298
+ // existing consumer code written in any of those styles keep working.
9171
9299
  match s.as_str() {
9172
9300
  "function" | "Function" => Ok(ToolType::Function),
9173
9301
  other => Err(magnus::Error::new(
@@ -9265,8 +9393,9 @@ impl magnus::IntoValue for ToolChoiceMode {
9265
9393
  impl magnus::TryConvert for ToolChoiceMode {
9266
9394
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9267
9395
  let s: String = magnus::TryConvert::try_convert(val)?;
9268
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9269
- // and a lowercase fallback so fixtures written in any of those styles work.
9396
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9397
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9398
+ // existing consumer code written in any of those styles keep working.
9270
9399
  match s.as_str() {
9271
9400
  "auto" | "Auto" => Ok(ToolChoiceMode::Auto),
9272
9401
  "required" | "Required" => Ok(ToolChoiceMode::Required),
@@ -9428,8 +9557,9 @@ impl magnus::IntoValue for Modality {
9428
9557
  impl magnus::TryConvert for Modality {
9429
9558
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9430
9559
  let s: String = magnus::TryConvert::try_convert(val)?;
9431
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9432
- // and a lowercase fallback so fixtures written in any of those styles work.
9560
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9561
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9562
+ // existing consumer code written in any of those styles keep working.
9433
9563
  match s.as_str() {
9434
9564
  "text" | "Text" => Ok(Modality::Text),
9435
9565
  "audio" | "Audio" => Ok(Modality::Audio),
@@ -9480,8 +9610,9 @@ impl magnus::IntoValue for FinishReason {
9480
9610
  impl magnus::TryConvert for FinishReason {
9481
9611
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9482
9612
  let s: String = magnus::TryConvert::try_convert(val)?;
9483
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9484
- // and a lowercase fallback so fixtures written in any of those styles work.
9613
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9614
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9615
+ // existing consumer code written in any of those styles keep working.
9485
9616
  match s.as_str() {
9486
9617
  "stop" | "Stop" => Ok(FinishReason::Stop),
9487
9618
  "length" | "Length" => Ok(FinishReason::Length),
@@ -9532,8 +9663,9 @@ impl magnus::IntoValue for ReasoningEffort {
9532
9663
  impl magnus::TryConvert for ReasoningEffort {
9533
9664
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9534
9665
  let s: String = magnus::TryConvert::try_convert(val)?;
9535
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9536
- // and a lowercase fallback so fixtures written in any of those styles work.
9666
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9667
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9668
+ // existing consumer code written in any of those styles keep working.
9537
9669
  match s.as_str() {
9538
9670
  "low" | "Low" => Ok(ReasoningEffort::Low),
9539
9671
  "medium" | "Medium" => Ok(ReasoningEffort::Medium),
@@ -9577,8 +9709,9 @@ impl magnus::IntoValue for EmbeddingFormat {
9577
9709
  impl magnus::TryConvert for EmbeddingFormat {
9578
9710
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9579
9711
  let s: String = magnus::TryConvert::try_convert(val)?;
9580
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9581
- // and a lowercase fallback so fixtures written in any of those styles work.
9712
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
9713
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
9714
+ // existing consumer code written in any of those styles keep working.
9582
9715
  match s.as_str() {
9583
9716
  "float" | "Float" => Ok(EmbeddingFormat::Float),
9584
9717
  "base64" | "Base64" => Ok(EmbeddingFormat::Base64),
@@ -9598,6 +9731,7 @@ unsafe impl TryConvertOwned for EmbeddingFormat {}
9598
9731
  pub enum EmbeddingInput {
9599
9732
  Single(String),
9600
9733
  Multiple(Vec<String>),
9734
+ Multimodal(Vec<EmbeddingContentPart>),
9601
9735
  }
9602
9736
 
9603
9737
  impl Default for EmbeddingInput {
@@ -9649,6 +9783,70 @@ impl magnus::TryConvert for EmbeddingInput {
9649
9783
  unsafe impl IntoValueFromNative for EmbeddingInput {}
9650
9784
  unsafe impl TryConvertOwned for EmbeddingInput {}
9651
9785
 
9786
+ #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
9787
+ #[serde(tag = "type")]
9788
+ pub enum EmbeddingContentPart {
9789
+ #[serde(rename = "text")]
9790
+ Text { text: String },
9791
+ #[serde(rename = "image_url")]
9792
+ ImageUrl { image_url: ImageUrl },
9793
+ #[serde(rename = "image_base64")]
9794
+ ImageBase64 { image_base64: String },
9795
+ }
9796
+
9797
+ impl Default for EmbeddingContentPart {
9798
+ fn default() -> Self {
9799
+ Self::Text {
9800
+ text: Default::default(),
9801
+ }
9802
+ }
9803
+ }
9804
+
9805
+ impl magnus::IntoValue for EmbeddingContentPart {
9806
+ fn into_value_with(self, handle: &Ruby) -> magnus::Value {
9807
+ match serde_json::to_value(&self) {
9808
+ Ok(v) => json_to_ruby(handle, v),
9809
+ Err(_) => handle.qnil().into_value_with(handle),
9810
+ }
9811
+ }
9812
+ }
9813
+
9814
+ impl magnus::TryConvert for EmbeddingContentPart {
9815
+ fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9816
+ // For data enums with fields (e.g., PageAction), try to deserialize from JSON first.
9817
+ // For unit enums or when passed as a string, fall back to string-based conversion.
9818
+ let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
9819
+ s
9820
+ } else {
9821
+ val.funcall::<_, _, String>("to_json", ()).map_err(|e| {
9822
+ magnus::Error::new(
9823
+ unsafe { Ruby::get_unchecked() }.exception_type_error(),
9824
+ format!("no implicit conversion into EmbeddingContentPart: {}", e),
9825
+ )
9826
+ })?
9827
+ };
9828
+ // Try deserializing as JSON first (handles JSON strings like "\"markdown\"" or "{\"click\":{\"selector\":\"...\"}}\"")
9829
+ // For internally-tagged enums, a bare variant string is wrapped as {"<tag>": value}.
9830
+ // If that fails, try treating it as a plain string value and wrap in quotes
9831
+ // If both fail, try as Custom variant (for untagged enum support)
9832
+ serde_json::from_str(&json_str)
9833
+ .or_else(|_| serde_json::from_value(serde_json::json!({ "type": json_str })))
9834
+ .or_else(|_| serde_json::from_str(&format!("\"{json_str}\"")))
9835
+ .or_else(|_| {
9836
+ // Try as a JSON string for Custom variant (untagged enums accept any remaining value)
9837
+ match serde_json::to_value(&json_str) {
9838
+ Ok(val) => serde_json::from_value(val),
9839
+ Err(e) => Err(e),
9840
+ }
9841
+ })
9842
+ .map_err(|e| magnus::Error::new(unsafe { Ruby::get_unchecked() }.exception_type_error(), e.to_string()))
9843
+ }
9844
+ }
9845
+
9846
+ unsafe impl IntoValueFromNative for EmbeddingContentPart {}
9847
+ unsafe impl TryConvertOwned for EmbeddingContentPart {}
9848
+ impl EmbeddingContentPart {}
9849
+
9652
9850
  #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
9653
9851
  #[serde(untagged)]
9654
9852
  pub enum ModerationInput {
@@ -9849,7 +10047,7 @@ impl magnus::IntoValue for FilePurpose {
9849
10047
  let sym = match self {
9850
10048
  FilePurpose::Assistants => "assistants",
9851
10049
  FilePurpose::Batch => "batch",
9852
- FilePurpose::FineTune => "fine_tune",
10050
+ FilePurpose::FineTune => "fine-tune",
9853
10051
  FilePurpose::Vision => "vision",
9854
10052
  };
9855
10053
  handle.to_symbol(sym).into_value_with(handle)
@@ -9859,12 +10057,13 @@ impl magnus::IntoValue for FilePurpose {
9859
10057
  impl magnus::TryConvert for FilePurpose {
9860
10058
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9861
10059
  let s: String = magnus::TryConvert::try_convert(val)?;
9862
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9863
- // and a lowercase fallback so fixtures written in any of those styles work.
10060
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10061
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10062
+ // existing consumer code written in any of those styles keep working.
9864
10063
  match s.as_str() {
9865
10064
  "assistants" | "Assistants" => Ok(FilePurpose::Assistants),
9866
10065
  "batch" | "Batch" => Ok(FilePurpose::Batch),
9867
- "fine_tune" | "FineTune" => Ok(FilePurpose::FineTune),
10066
+ "fine-tune" | "fine_tune" | "FineTune" => Ok(FilePurpose::FineTune),
9868
10067
  "vision" | "Vision" => Ok(FilePurpose::Vision),
9869
10068
  other => Err(magnus::Error::new(
9870
10069
  unsafe { Ruby::get_unchecked() }.exception_arg_error(),
@@ -9915,8 +10114,9 @@ impl magnus::IntoValue for BatchStatus {
9915
10114
  impl magnus::TryConvert for BatchStatus {
9916
10115
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
9917
10116
  let s: String = magnus::TryConvert::try_convert(val)?;
9918
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
9919
- // and a lowercase fallback so fixtures written in any of those styles work.
10117
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10118
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10119
+ // existing consumer code written in any of those styles keep working.
9920
10120
  match s.as_str() {
9921
10121
  "validating" | "Validating" => Ok(BatchStatus::Validating),
9922
10122
  "failed" | "Failed" => Ok(BatchStatus::Failed),
@@ -10019,8 +10219,9 @@ impl magnus::IntoValue for StreamFormat {
10019
10219
  impl magnus::TryConvert for StreamFormat {
10020
10220
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
10021
10221
  let s: String = magnus::TryConvert::try_convert(val)?;
10022
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
10023
- // and a lowercase fallback so fixtures written in any of those styles work.
10222
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10223
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10224
+ // existing consumer code written in any of those styles keep working.
10024
10225
  match s.as_str() {
10025
10226
  "sse" | "Sse" => Ok(StreamFormat::Sse),
10026
10227
  "aws_event_stream" | "AwsEventStream" => Ok(StreamFormat::AwsEventStream),
@@ -10054,7 +10255,7 @@ impl magnus::IntoValue for AuthType {
10054
10255
  fn into_value_with(self, handle: &Ruby) -> magnus::Value {
10055
10256
  let sym = match self {
10056
10257
  AuthType::Bearer => "bearer",
10057
- AuthType::ApiKey => "api_key",
10258
+ AuthType::ApiKey => "api-key",
10058
10259
  AuthType::None => "none",
10059
10260
  AuthType::Unknown => "unknown",
10060
10261
  };
@@ -10065,11 +10266,12 @@ impl magnus::IntoValue for AuthType {
10065
10266
  impl magnus::TryConvert for AuthType {
10066
10267
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
10067
10268
  let s: String = magnus::TryConvert::try_convert(val)?;
10068
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
10069
- // and a lowercase fallback so fixtures written in any of those styles work.
10269
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10270
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10271
+ // existing consumer code written in any of those styles keep working.
10070
10272
  match s.as_str() {
10071
10273
  "bearer" | "Bearer" => Ok(AuthType::Bearer),
10072
- "api_key" | "ApiKey" => Ok(AuthType::ApiKey),
10274
+ "api-key" | "api_key" | "ApiKey" => Ok(AuthType::ApiKey),
10073
10275
  "none" | "None" => Ok(AuthType::None),
10074
10276
  "unknown" | "Unknown" => Ok(AuthType::Unknown),
10075
10277
  other => Err(magnus::Error::new(
@@ -10098,8 +10300,8 @@ impl Default for Enforcement {
10098
10300
  impl magnus::IntoValue for Enforcement {
10099
10301
  fn into_value_with(self, handle: &Ruby) -> magnus::Value {
10100
10302
  let sym = match self {
10101
- Enforcement::Hard => "hard",
10102
- Enforcement::Soft => "soft",
10303
+ Enforcement::Hard => "Hard",
10304
+ Enforcement::Soft => "Soft",
10103
10305
  };
10104
10306
  handle.to_symbol(sym).into_value_with(handle)
10105
10307
  }
@@ -10108,11 +10310,12 @@ impl magnus::IntoValue for Enforcement {
10108
10310
  impl magnus::TryConvert for Enforcement {
10109
10311
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
10110
10312
  let s: String = magnus::TryConvert::try_convert(val)?;
10111
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
10112
- // and a lowercase fallback so fixtures written in any of those styles work.
10313
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10314
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10315
+ // existing consumer code written in any of those styles keep working.
10113
10316
  match s.as_str() {
10114
- "hard" | "Hard" => Ok(Enforcement::Hard),
10115
- "soft" | "Soft" => Ok(Enforcement::Soft),
10317
+ "Hard" | "hard" => Ok(Enforcement::Hard),
10318
+ "Soft" | "soft" => Ok(Enforcement::Soft),
10116
10319
  other => Err(magnus::Error::new(
10117
10320
  unsafe { Ruby::get_unchecked() }.exception_arg_error(),
10118
10321
  format!("invalid Enforcement value: {other}"),
@@ -10199,9 +10402,9 @@ impl Default for CircuitState {
10199
10402
  impl magnus::IntoValue for CircuitState {
10200
10403
  fn into_value_with(self, handle: &Ruby) -> magnus::Value {
10201
10404
  let sym = match self {
10202
- CircuitState::Closed => "closed",
10203
- CircuitState::Open => "open",
10204
- CircuitState::HalfOpen => "half_open",
10405
+ CircuitState::Closed => "Closed",
10406
+ CircuitState::Open => "Open",
10407
+ CircuitState::HalfOpen => "HalfOpen",
10205
10408
  };
10206
10409
  handle.to_symbol(sym).into_value_with(handle)
10207
10410
  }
@@ -10210,12 +10413,13 @@ impl magnus::IntoValue for CircuitState {
10210
10413
  impl magnus::TryConvert for CircuitState {
10211
10414
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
10212
10415
  let s: String = magnus::TryConvert::try_convert(val)?;
10213
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
10214
- // and a lowercase fallback so fixtures written in any of those styles work.
10416
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10417
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10418
+ // existing consumer code written in any of those styles keep working.
10215
10419
  match s.as_str() {
10216
- "closed" | "Closed" => Ok(CircuitState::Closed),
10217
- "open" | "Open" => Ok(CircuitState::Open),
10218
- "half_open" | "HalfOpen" => Ok(CircuitState::HalfOpen),
10420
+ "Closed" | "closed" => Ok(CircuitState::Closed),
10421
+ "Open" | "open" => Ok(CircuitState::Open),
10422
+ "HalfOpen" | "half_open" => Ok(CircuitState::HalfOpen),
10219
10423
  other => Err(magnus::Error::new(
10220
10424
  unsafe { Ruby::get_unchecked() }.exception_arg_error(),
10221
10425
  format!("invalid CircuitState value: {other}"),
@@ -10242,8 +10446,8 @@ impl Default for HealthStatus {
10242
10446
  impl magnus::IntoValue for HealthStatus {
10243
10447
  fn into_value_with(self, handle: &Ruby) -> magnus::Value {
10244
10448
  let sym = match self {
10245
- HealthStatus::Healthy => "healthy",
10246
- HealthStatus::Unhealthy => "unhealthy",
10449
+ HealthStatus::Healthy => "Healthy",
10450
+ HealthStatus::Unhealthy => "Unhealthy",
10247
10451
  };
10248
10452
  handle.to_symbol(sym).into_value_with(handle)
10249
10453
  }
@@ -10252,11 +10456,12 @@ impl magnus::IntoValue for HealthStatus {
10252
10456
  impl magnus::TryConvert for HealthStatus {
10253
10457
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
10254
10458
  let s: String = magnus::TryConvert::try_convert(val)?;
10255
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
10256
- // and a lowercase fallback so fixtures written in any of those styles work.
10459
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10460
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10461
+ // existing consumer code written in any of those styles keep working.
10257
10462
  match s.as_str() {
10258
- "healthy" | "Healthy" => Ok(HealthStatus::Healthy),
10259
- "unhealthy" | "Unhealthy" => Ok(HealthStatus::Unhealthy),
10463
+ "Healthy" | "healthy" => Ok(HealthStatus::Healthy),
10464
+ "Unhealthy" | "unhealthy" => Ok(HealthStatus::Unhealthy),
10260
10465
  other => Err(magnus::Error::new(
10261
10466
  unsafe { Ruby::get_unchecked() }.exception_arg_error(),
10262
10467
  format!("invalid HealthStatus value: {other}"),
@@ -10284,9 +10489,9 @@ impl Default for RefreshOutcome {
10284
10489
  impl magnus::IntoValue for RefreshOutcome {
10285
10490
  fn into_value_with(self, handle: &Ruby) -> magnus::Value {
10286
10491
  let sym = match self {
10287
- RefreshOutcome::Disabled => "disabled",
10288
- RefreshOutcome::FromCache => "from_cache",
10289
- RefreshOutcome::Fetched => "fetched",
10492
+ RefreshOutcome::Disabled => "Disabled",
10493
+ RefreshOutcome::FromCache => "FromCache",
10494
+ RefreshOutcome::Fetched => "Fetched",
10290
10495
  };
10291
10496
  handle.to_symbol(sym).into_value_with(handle)
10292
10497
  }
@@ -10295,12 +10500,13 @@ impl magnus::IntoValue for RefreshOutcome {
10295
10500
  impl magnus::TryConvert for RefreshOutcome {
10296
10501
  fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
10297
10502
  let s: String = magnus::TryConvert::try_convert(val)?;
10298
- // Accept the serde wire name (snake_case), the PascalCase Rust variant name,
10299
- // and a lowercase fallback so fixtures written in any of those styles work.
10503
+ // Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
10504
+ // emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
10505
+ // existing consumer code written in any of those styles keep working.
10300
10506
  match s.as_str() {
10301
- "disabled" | "Disabled" => Ok(RefreshOutcome::Disabled),
10302
- "from_cache" | "FromCache" => Ok(RefreshOutcome::FromCache),
10303
- "fetched" | "Fetched" => Ok(RefreshOutcome::Fetched),
10507
+ "Disabled" | "disabled" => Ok(RefreshOutcome::Disabled),
10508
+ "FromCache" | "from_cache" => Ok(RefreshOutcome::FromCache),
10509
+ "Fetched" | "fetched" => Ok(RefreshOutcome::Fetched),
10304
10510
  other => Err(magnus::Error::new(
10305
10511
  unsafe { Ruby::get_unchecked() }.exception_arg_error(),
10306
10512
  format!("invalid RefreshOutcome value: {other}"),
@@ -12374,6 +12580,7 @@ impl From<liter_llm::client::LlmConfig> for LlmConfig {
12374
12580
  cache: val.cache.map(Into::into),
12375
12581
  budget: val.budget.map(Into::into),
12376
12582
  rate_limit: val.rate_limit.map(Into::into),
12583
+ in_flight_limit: val.in_flight_limit.map(Into::into),
12377
12584
  cost_tracking: val.cost_tracking,
12378
12585
  tracing: val.tracing,
12379
12586
  cooldown_secs: val.cooldown_secs,
@@ -12459,6 +12666,24 @@ impl From<liter_llm::client::LlmRateLimitConfig> for LlmRateLimitConfig {
12459
12666
  }
12460
12667
  }
12461
12668
 
12669
+ #[allow(clippy::needless_update)]
12670
+ impl From<LlmInFlightLimitConfig> for liter_llm::client::LlmInFlightLimitConfig {
12671
+ fn from(val: LlmInFlightLimitConfig) -> Self {
12672
+ Self {
12673
+ max_in_flight: val.max_in_flight,
12674
+ ..Default::default()
12675
+ }
12676
+ }
12677
+ }
12678
+
12679
+ impl From<liter_llm::client::LlmInFlightLimitConfig> for LlmInFlightLimitConfig {
12680
+ fn from(val: liter_llm::client::LlmInFlightLimitConfig) -> Self {
12681
+ Self {
12682
+ max_in_flight: val.max_in_flight,
12683
+ }
12684
+ }
12685
+ }
12686
+
12462
12687
  #[allow(clippy::needless_update)]
12463
12688
  impl From<LlmProviderConfig> for liter_llm::client::LlmProviderConfig {
12464
12689
  fn from(val: LlmProviderConfig) -> Self {
@@ -12779,6 +13004,14 @@ impl From<liter_llm::CacheConfig> for CacheConfig {
12779
13004
  }
12780
13005
  }
12781
13006
 
13007
+ impl From<liter_llm::InFlightLimitConfig> for InFlightLimitConfig {
13008
+ fn from(val: liter_llm::InFlightLimitConfig) -> Self {
13009
+ Self {
13010
+ max_in_flight: val.max_in_flight,
13011
+ }
13012
+ }
13013
+ }
13014
+
12782
13015
  #[allow(clippy::needless_update)]
12783
13016
  impl From<RateLimitConfig> for liter_llm::RateLimitConfig {
12784
13017
  fn from(val: RateLimitConfig) -> Self {
@@ -13169,6 +13402,7 @@ impl From<EmbeddingInput> for liter_llm::types::EmbeddingInput {
13169
13402
  match val {
13170
13403
  EmbeddingInput::Single(_0) => Self::Single(_0),
13171
13404
  EmbeddingInput::Multiple(_0) => Self::Multiple(_0.into_iter().collect()),
13405
+ EmbeddingInput::Multimodal(_0) => Self::Multimodal(_0.into_iter().map(Into::into).collect()),
13172
13406
  }
13173
13407
  }
13174
13408
  }
@@ -13178,6 +13412,37 @@ impl From<liter_llm::types::EmbeddingInput> for EmbeddingInput {
13178
13412
  match val {
13179
13413
  liter_llm::types::EmbeddingInput::Single(_0) => Self::Single(_0),
13180
13414
  liter_llm::types::EmbeddingInput::Multiple(_0) => Self::Multiple(_0.into_iter().collect()),
13415
+ liter_llm::types::EmbeddingInput::Multimodal(_0) => {
13416
+ Self::Multimodal(_0.into_iter().map(Into::into).collect())
13417
+ }
13418
+ }
13419
+ }
13420
+ }
13421
+
13422
+ impl From<EmbeddingContentPart> for liter_llm::types::EmbeddingContentPart {
13423
+ fn from(val: EmbeddingContentPart) -> Self {
13424
+ match val {
13425
+ EmbeddingContentPart::Text { text } => Self::Text { text: text },
13426
+ EmbeddingContentPart::ImageUrl { image_url } => Self::ImageUrl {
13427
+ image_url: image_url.into(),
13428
+ },
13429
+ EmbeddingContentPart::ImageBase64 { image_base64 } => Self::ImageBase64 {
13430
+ image_base64: image_base64,
13431
+ },
13432
+ }
13433
+ }
13434
+ }
13435
+
13436
+ impl From<liter_llm::types::EmbeddingContentPart> for EmbeddingContentPart {
13437
+ fn from(val: liter_llm::types::EmbeddingContentPart) -> Self {
13438
+ match val {
13439
+ liter_llm::types::EmbeddingContentPart::Text { text } => Self::Text { text: text.to_string() },
13440
+ liter_llm::types::EmbeddingContentPart::ImageUrl { image_url } => Self::ImageUrl {
13441
+ image_url: image_url.into(),
13442
+ },
13443
+ liter_llm::types::EmbeddingContentPart::ImageBase64 { image_base64 } => Self::ImageBase64 {
13444
+ image_base64: image_base64.to_string(),
13445
+ },
13181
13446
  }
13182
13447
  }
13183
13448
  }
@@ -14552,6 +14817,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
14552
14817
 
14553
14818
  class.define_method("rate_limit", method!(LlmConfig::rate_limit, 0))?;
14554
14819
 
14820
+ class.define_method("in_flight_limit", method!(LlmConfig::in_flight_limit, 0))?;
14821
+
14555
14822
  class.define_method("cost_tracking", method!(LlmConfig::cost_tracking, 0))?;
14556
14823
 
14557
14824
  class.define_method("tracing", method!(LlmConfig::tracing, 0))?;
@@ -14594,6 +14861,12 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
14594
14861
 
14595
14862
  class.define_method("window_seconds", method!(LlmRateLimitConfig::window_seconds, 0))?;
14596
14863
 
14864
+ let class = module.define_class("LlmInFlightLimitConfig", ruby.class_object())?;
14865
+
14866
+ class.define_singleton_method("new", function!(LlmInFlightLimitConfig::new, -1))?;
14867
+
14868
+ class.define_method("max_in_flight", method!(LlmInFlightLimitConfig::max_in_flight, 0))?;
14869
+
14597
14870
  let class = module.define_class("LlmProviderConfig", ruby.class_object())?;
14598
14871
 
14599
14872
  class.define_singleton_method("new", function!(LlmProviderConfig::new, -1))?;
@@ -14902,6 +15175,12 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
14902
15175
 
14903
15176
  let class = module.define_class("SingleflightResult", ruby.class_object())?;
14904
15177
 
15178
+ let class = module.define_class("InFlightLimitConfig", ruby.class_object())?;
15179
+
15180
+ class.define_singleton_method("new", function!(InFlightLimitConfig::new, -1))?;
15181
+
15182
+ class.define_method("max_in_flight", method!(InFlightLimitConfig::max_in_flight, 0))?;
15183
+
14905
15184
  let class = module.define_class("RateLimitConfig", ruby.class_object())?;
14906
15185
 
14907
15186
  class.define_singleton_method("new", function!(RateLimitConfig::new, -1))?;
@@ -1,5 +1,5 @@
1
1
  # This file is auto-generated by alef — DO NOT EDIT.
2
- # alef:hash:22279669d98fa4ccf8fbbb4ad5a2b8ac72ae4eb02a46d2c25430da6aad7b80fb
2
+ # alef:hash:a963d30e17380908f8f67a9244a29d7e6ad83445dac64977569ca4c3b4b53f6a
3
3
  # To regenerate: alef generate
4
4
  # To verify freshness: alef verify
5
5
  # frozen_string_literal: true
@@ -556,6 +556,93 @@ module LiterLlm
556
556
  end
557
557
  end
558
558
 
559
+ module LiterLlm
560
+ # A content part in a multimodal embedding input.
561
+ module EmbeddingContentPart
562
+ extend T::Helpers
563
+ extend T::Sig
564
+
565
+ interface!
566
+
567
+ # Dispatch from a Hash to the appropriate variant constructor.
568
+ # @param hash [Hash] with discriminator field and variant-specific fields
569
+ # @return [variant_class] an instance of the appropriate variant
570
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.untyped) }
571
+ def self.from_hash(hash)
572
+ discriminator = hash[:type] || hash["type"]
573
+ case discriminator
574
+ when "text" then EmbeddingContentPartText.from_hash(hash)
575
+ when "image_url" then EmbeddingContentPartImageUrl.from_hash(hash)
576
+ when "image_base64" then EmbeddingContentPartImageBase64.from_hash(hash)
577
+ else raise "Unknown discriminator: #{discriminator}"
578
+ end
579
+ end
580
+ end
581
+ ## Plain text.
582
+ EmbeddingContentPartText = Data.define(:text) do
583
+ include EmbeddingContentPart
584
+ extend T::Sig
585
+
586
+ # @return [String]
587
+ sig { returns(String) }
588
+ def text = super # rubocop:disable Lint/UselessMethodDefinition
589
+ sig { returns(T::Boolean) }
590
+ def text? = true
591
+ sig { returns(T::Boolean) }
592
+ def image_url? = false
593
+ sig { returns(T::Boolean) }
594
+ def image_base64? = false
595
+ # @param hash [Hash] deserialized from the native extension
596
+ # @return [self]
597
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
598
+ def self.from_hash(hash)
599
+ new(text: hash[:text] || hash["text"])
600
+ end
601
+ end
602
+ ## Image identified by a data URL or HTTP/HTTPS URL.
603
+ EmbeddingContentPartImageUrl = Data.define(:image_url) do
604
+ include EmbeddingContentPart
605
+ extend T::Sig
606
+
607
+ # @return [ImageUrl]
608
+ sig { returns(ImageUrl) }
609
+ def image_url = super # rubocop:disable Lint/UselessMethodDefinition
610
+ sig { returns(T::Boolean) }
611
+ def text? = false
612
+ sig { returns(T::Boolean) }
613
+ def image_url? = true
614
+ sig { returns(T::Boolean) }
615
+ def image_base64? = false
616
+ # @param hash [Hash] deserialized from the native extension
617
+ # @return [self]
618
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
619
+ def self.from_hash(hash)
620
+ new(image_url: hash[:image_url] || hash["image_url"])
621
+ end
622
+ end
623
+ ## Image encoded as a complete data URL.
624
+ EmbeddingContentPartImageBase64 = Data.define(:image_base64) do
625
+ include EmbeddingContentPart
626
+ extend T::Sig
627
+
628
+ # @return [String]
629
+ sig { returns(String) }
630
+ def image_base64 = super # rubocop:disable Lint/UselessMethodDefinition
631
+ sig { returns(T::Boolean) }
632
+ def text? = false
633
+ sig { returns(T::Boolean) }
634
+ def image_url? = false
635
+ sig { returns(T::Boolean) }
636
+ def image_base64? = true
637
+ # @param hash [Hash] deserialized from the native extension
638
+ # @return [self]
639
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
640
+ def self.from_hash(hash)
641
+ new(image_base64: hash[:image_base64] || hash["image_base64"])
642
+ end
643
+ end
644
+ end
645
+
559
646
  module LiterLlm
560
647
  # Document input for OCR — either a URL or inline base64 data.
561
648
  module OcrDocument
@@ -1,10 +1,10 @@
1
1
  # This file is auto-generated by alef — DO NOT EDIT.
2
- # alef:hash:2fa028ca6b2a895c045b5e1d6db85593c92d1c2c4245a025c8828d42585afb14
2
+ # alef:hash:9cad1aa634ead525aea0040c6902c806b7daab37eb7802e5be0d0c5f48aa8847
3
3
  # To regenerate: alef generate
4
4
  # To verify freshness: alef verify
5
5
  # frozen_string_literal: true
6
6
 
7
7
  module LiterLlm
8
8
  ## The version string for this package.
9
- VERSION = "1.17.3"
9
+ VERSION = "1.18.0"
10
10
  end
data/lib/liter_llm.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # This file is auto-generated by alef — DO NOT EDIT.
2
- # alef:hash:2b8f0579821576133e6d5bff77bf1b62637bc64e5b026d466a10ba1506d635fc
2
+ # alef:hash:b8684376c861ef7e78cc307694871bb74d674153abe531df23adc8a37901a153
3
3
  # To regenerate: alef generate
4
4
  # To verify freshness: alef verify
5
5
  # frozen_string_literal: true
data/sig/types.rbs CHANGED
@@ -1,5 +1,5 @@
1
1
  # This file is auto-generated by alef — DO NOT EDIT.
2
- # alef:hash:a5339cc792b0081109ce66c00a4664ef4c1c15ecb5f0096c5d6ff9a4cc32c72a
2
+ # alef:hash:182fb885a8ef562d0a181ae0aadb5dd6e9b1a440c76f7dffbfea998a71b1eb6d
3
3
  # To regenerate: alef generate
4
4
  # To verify freshness: alef verify
5
5
 
@@ -692,13 +692,14 @@ module LiterLlm
692
692
  attr_reader cache: LlmCacheConfig?
693
693
  attr_reader budget: LlmBudgetConfig?
694
694
  attr_reader rate_limit: LlmRateLimitConfig?
695
+ attr_reader in_flight_limit: LlmInFlightLimitConfig?
695
696
  attr_reader cost_tracking: bool?
696
697
  attr_reader tracing: bool?
697
698
  attr_reader cooldown_secs: Integer?
698
699
  attr_reader health_check_secs: Integer?
699
700
  attr_reader bedrock: BedrockConfig?
700
701
 
701
- def initialize: (?model: String, ?api_key: String, ?base_url: String, ?timeout_secs: Integer, ?max_retries: Integer, ?temperature: Float, ?max_tokens: Integer, ?load_env: bool, ?headers: Hash[String, String], ?providers: Array[LlmProviderConfig], ?cache: LlmCacheConfig, ?budget: LlmBudgetConfig, ?rate_limit: LlmRateLimitConfig, ?cost_tracking: bool, ?tracing: bool, ?cooldown_secs: Integer, ?health_check_secs: Integer, ?bedrock: BedrockConfig) -> void
702
+ def initialize: (?model: String, ?api_key: String, ?base_url: String, ?timeout_secs: Integer, ?max_retries: Integer, ?temperature: Float, ?max_tokens: Integer, ?load_env: bool, ?headers: Hash[String, String], ?providers: Array[LlmProviderConfig], ?cache: LlmCacheConfig, ?budget: LlmBudgetConfig, ?rate_limit: LlmRateLimitConfig, ?in_flight_limit: LlmInFlightLimitConfig, ?cost_tracking: bool, ?tracing: bool, ?cooldown_secs: Integer, ?health_check_secs: Integer, ?bedrock: BedrockConfig) -> void
702
703
  end
703
704
 
704
705
  class LlmCacheConfig
@@ -726,6 +727,12 @@ module LiterLlm
726
727
  def initialize: (?rpm: Integer, ?tpm: Integer, ?window_seconds: Integer) -> void
727
728
  end
728
729
 
730
+ class LlmInFlightLimitConfig
731
+ attr_reader max_in_flight: Integer?
732
+
733
+ def initialize: (?max_in_flight: Integer) -> void
734
+ end
735
+
729
736
  class LlmProviderConfig
730
737
  attr_reader name: String
731
738
  attr_reader base_url: String
@@ -878,6 +885,12 @@ module LiterLlm
878
885
  class SingleflightResult
879
886
  end
880
887
 
888
+ class InFlightLimitConfig
889
+ attr_reader max_in_flight: Integer?
890
+
891
+ def initialize: (?max_in_flight: Integer) -> void
892
+ end
893
+
881
894
  class RateLimitConfig
882
895
  attr_reader rpm: Integer?
883
896
  attr_reader tpm: Integer?
@@ -958,6 +971,9 @@ module LiterLlm
958
971
  class EmbeddingInput
959
972
  end
960
973
 
974
+ class EmbeddingContentPart
975
+ end
976
+
961
977
  class ModerationInput
962
978
  end
963
979
 
@@ -970,7 +986,7 @@ module LiterLlm
970
986
  end
971
987
 
972
988
  class FilePurpose
973
- type value = :assistants | :batch | :fine_tune | :vision
989
+ type value = :assistants | :batch | :fine-tune | :vision
974
990
  end
975
991
 
976
992
  class BatchStatus
@@ -985,26 +1001,26 @@ module LiterLlm
985
1001
  end
986
1002
 
987
1003
  class AuthType
988
- type value = :bearer | :api_key | :none | :unknown
1004
+ type value = :bearer | :api-key | :none | :unknown
989
1005
  end
990
1006
 
991
1007
  class Enforcement
992
- type value = :hard | :soft
1008
+ type value = :Hard | :Soft
993
1009
  end
994
1010
 
995
1011
  class CacheBackend
996
1012
  end
997
1013
 
998
1014
  class CircuitState
999
- type value = :closed | :open | :half_open
1015
+ type value = :Closed | :Open | :HalfOpen
1000
1016
  end
1001
1017
 
1002
1018
  class HealthStatus
1003
- type value = :healthy | :unhealthy
1019
+ type value = :Healthy | :Unhealthy
1004
1020
  end
1005
1021
 
1006
1022
  class RefreshOutcome
1007
- type value = :disabled | :from_cache | :fetched
1023
+ type value = :Disabled | :FromCache | :Fetched
1008
1024
  end
1009
1025
 
1010
1026
  def self.create_client: (String api_key, ?String base_url, ?Integer timeout_secs, ?Integer max_retries, ?String model_hint) -> DefaultClient
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liter_llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.3
4
+ version: 1.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Na'aman Hirschfeld
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-21 00:00:00.000000000 Z
11
+ date: 2026-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys