palimpzest 1.2.0__tar.gz → 1.3.1__tar.gz

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 (102) hide show
  1. {palimpzest-1.2.0/src/palimpzest.egg-info → palimpzest-1.3.1}/PKG-INFO +2 -1
  2. {palimpzest-1.2.0 → palimpzest-1.3.1}/pyproject.toml +2 -1
  3. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/constants.py +5 -5
  4. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/generators/generators.py +2 -13
  5. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/optimizer.py +1 -1
  6. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/rules.py +107 -76
  7. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/processor/config.py +9 -3
  8. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/processor/query_processor_factory.py +7 -1
  9. palimpzest-1.3.1/src/palimpzest/utils/model_helpers.py +88 -0
  10. {palimpzest-1.2.0 → palimpzest-1.3.1/src/palimpzest.egg-info}/PKG-INFO +2 -1
  11. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest.egg-info/requires.txt +1 -0
  12. palimpzest-1.2.0/src/palimpzest/utils/model_helpers.py +0 -61
  13. {palimpzest-1.2.0 → palimpzest-1.3.1}/LICENSE +0 -0
  14. {palimpzest-1.2.0 → palimpzest-1.3.1}/README.md +0 -0
  15. {palimpzest-1.2.0 → palimpzest-1.3.1}/setup.cfg +0 -0
  16. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/__init__.py +0 -0
  17. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/agents/__init__.py +0 -0
  18. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/agents/compute_agents.py +0 -0
  19. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/agents/search_agents.py +0 -0
  20. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/__init__.py +0 -0
  21. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/data/__init__.py +0 -0
  22. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/data/context.py +0 -0
  23. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/data/context_manager.py +0 -0
  24. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/data/dataset.py +0 -0
  25. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/data/index_dataset.py +0 -0
  26. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/data/iter_dataset.py +0 -0
  27. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/elements/__init__.py +0 -0
  28. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/elements/filters.py +0 -0
  29. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/elements/groupbysig.py +0 -0
  30. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/elements/records.py +0 -0
  31. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/lib/__init__.py +0 -0
  32. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/lib/schemas.py +0 -0
  33. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/core/models.py +0 -0
  34. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/policy.py +0 -0
  35. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/__init__.py +0 -0
  36. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/agent_prompts.py +0 -0
  37. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/aggregate_prompts.py +0 -0
  38. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/context_search.py +0 -0
  39. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/convert_prompts.py +0 -0
  40. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/critique_and_refine_prompts.py +0 -0
  41. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/filter_prompts.py +0 -0
  42. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/join_prompts.py +0 -0
  43. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/moa_aggregator_prompts.py +0 -0
  44. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/moa_proposer_prompts.py +0 -0
  45. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/prompt_factory.py +0 -0
  46. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/split_merge_prompts.py +0 -0
  47. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/split_proposer_prompts.py +0 -0
  48. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/utils.py +0 -0
  49. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/prompts/validator.py +0 -0
  50. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/__init__.py +0 -0
  51. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/__init__.py +0 -0
  52. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/all_sample_execution_strategy.py +0 -0
  53. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/execution_strategy.py +0 -0
  54. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/execution_strategy_type.py +0 -0
  55. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/mab_execution_strategy.py +0 -0
  56. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/parallel_execution_strategy.py +0 -0
  57. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/execution/single_threaded_execution_strategy.py +0 -0
  58. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/generators/__init__.py +0 -0
  59. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/__init__.py +0 -0
  60. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/aggregate.py +0 -0
  61. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/compute.py +0 -0
  62. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/convert.py +0 -0
  63. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/critique_and_refine.py +0 -0
  64. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/distinct.py +0 -0
  65. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/filter.py +0 -0
  66. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/join.py +0 -0
  67. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/limit.py +0 -0
  68. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/logical.py +0 -0
  69. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/mixture_of_agents.py +0 -0
  70. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/physical.py +0 -0
  71. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/project.py +0 -0
  72. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/rag.py +0 -0
  73. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/scan.py +0 -0
  74. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/search.py +0 -0
  75. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/split.py +0 -0
  76. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/operators/topk.py +0 -0
  77. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/__init__.py +0 -0
  78. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/cost_model.py +0 -0
  79. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/optimizer_strategy.py +0 -0
  80. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/optimizer_strategy_type.py +0 -0
  81. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/plan.py +0 -0
  82. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/primitives.py +0 -0
  83. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/optimizer/tasks.py +0 -0
  84. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/processor/__init__.py +0 -0
  85. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/query/processor/query_processor.py +0 -0
  86. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/schemabuilder/__init__.py +0 -0
  87. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/schemabuilder/schema_builder.py +0 -0
  88. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/tools/README.md +0 -0
  89. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/tools/__init__.py +0 -0
  90. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/tools/allenpdf.py +0 -0
  91. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/tools/pdfparser.py +0 -0
  92. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/tools/skema_tools.py +0 -0
  93. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/utils/__init__.py +0 -0
  94. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/utils/env_helpers.py +0 -0
  95. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/utils/hash_helpers.py +0 -0
  96. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/utils/progress.py +0 -0
  97. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/utils/udfs.py +0 -0
  98. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/validator/__init__.py +0 -0
  99. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest/validator/validator.py +0 -0
  100. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest.egg-info/SOURCES.txt +0 -0
  101. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest.egg-info/dependency_links.txt +0 -0
  102. {palimpzest-1.2.0 → palimpzest-1.3.1}/src/palimpzest.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: palimpzest
3
- Version: 1.2.0
3
+ Version: 1.3.1
4
4
  Summary: Palimpzest is a system which enables anyone to process AI-powered analytical queries simply by defining them in a declarative language
5
5
  Author-email: MIT DSG Semantic Management Lab <michjc@csail.mit.edu>
6
6
  Project-URL: homepage, https://palimpzest.org
@@ -34,6 +34,7 @@ Requires-Dist: PyLD>=2.0.4
34
34
  Requires-Dist: pyarrow>=20.0.0
35
35
  Requires-Dist: pypdf>=5.1.0
36
36
  Requires-Dist: pytest-mock>=3.14.0
37
+ Requires-Dist: python-dotenv>=1.2.1
37
38
  Requires-Dist: pyyaml>=6.0.1
38
39
  Requires-Dist: requests>=2.25
39
40
  Requires-Dist: ruff>=0.9.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "palimpzest"
3
- version = "1.2.0"
3
+ version = "1.3.1"
4
4
  description = "Palimpzest is a system which enables anyone to process AI-powered analytical queries simply by defining them in a declarative language"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -28,6 +28,7 @@ dependencies = [
28
28
  "pyarrow>=20.0.0",
29
29
  "pypdf>=5.1.0",
30
30
  "pytest-mock>=3.14.0",
31
+ "python-dotenv>=1.2.1",
31
32
  "pyyaml>=6.0.1",
32
33
  "requests>=2.25",
33
34
  "ruff>=0.9.0",
@@ -31,9 +31,9 @@ class Model(str, Enum):
31
31
  GEMINI_2_0_FLASH = "vertex_ai/gemini-2.0-flash"
32
32
  GEMINI_2_5_FLASH = "vertex_ai/gemini-2.5-flash"
33
33
  GEMINI_2_5_PRO = "vertex_ai/gemini-2.5-pro"
34
- GOOGLE_GEMINI_2_5_FLASH = "google/gemini-2.5-flash"
35
- GOOGLE_GEMINI_2_5_FLASH_LITE = "google/gemini-2.5-flash-lite"
36
- GOOGLE_GEMINI_2_5_PRO = "google/gemini-2.5-pro"
34
+ GOOGLE_GEMINI_2_5_FLASH = "gemini/gemini-2.5-flash"
35
+ GOOGLE_GEMINI_2_5_FLASH_LITE = "gemini/gemini-2.5-flash-lite"
36
+ GOOGLE_GEMINI_2_5_PRO = "gemini/gemini-2.5-pro"
37
37
  LLAMA_4_MAVERICK = "vertex_ai/meta/llama-4-maverick-17b-128e-instruct-maas"
38
38
  GPT_4o_AUDIO_PREVIEW = "openai/gpt-4o-audio-preview"
39
39
  GPT_4o_MINI_AUDIO_PREVIEW = "openai/gpt-4o-mini-audio-preview"
@@ -72,8 +72,8 @@ class Model(str, Enum):
72
72
  def is_vertex_model(self):
73
73
  return "vertex_ai" in self.value.lower()
74
74
 
75
- def is_google_model(self):
76
- return "google" in self.value.lower()
75
+ def is_google_ai_studio_model(self):
76
+ return "gemini/" in self.value.lower()
77
77
 
78
78
  def is_vllm_model(self):
79
79
  return "hosted_vllm" in self.value.lower()
@@ -108,7 +108,7 @@ class Generator(Generic[ContextType, InputType]):
108
108
  self,
109
109
  model: Model,
110
110
  prompt_strategy: PromptStrategy,
111
- reasoning_effort: str | None = None,
111
+ reasoning_effort: str | None,
112
112
  api_base: str | None = None,
113
113
  cardinality: Cardinality = Cardinality.ONE_TO_ONE,
114
114
  desc: str | None = None,
@@ -325,18 +325,7 @@ class Generator(Generic[ContextType, InputType]):
325
325
  if is_audio_op:
326
326
  completion_kwargs = {"modalities": ["text"], **completion_kwargs}
327
327
  if self.model.is_reasoning_model():
328
- if self.model.is_vertex_model():
329
- reasoning_effort = self.reasoning_effort
330
- if self.reasoning_effort is None and self.model == Model.GEMINI_2_5_PRO:
331
- reasoning_effort = "low"
332
- elif self.reasoning_effort is None:
333
- reasoning_effort = "disable"
334
- completion_kwargs = {"reasoning_effort": reasoning_effort, **completion_kwargs}
335
- elif self.model.is_anthropic_model() and self.reasoning_effort is not None:
336
- completion_kwargs = {"reasoning_effort": self.reasoning_effort, **completion_kwargs}
337
- elif self.model.is_openai_model():
338
- reasoning_effort = "minimal" if self.reasoning_effort is None else self.reasoning_effort
339
- completion_kwargs = {"reasoning_effort": reasoning_effort, **completion_kwargs}
328
+ completion_kwargs = {"reasoning_effort": self.reasoning_effort, **completion_kwargs}
340
329
  if self.model.is_vllm_model():
341
330
  completion_kwargs = {"api_base": self.api_base, "api_key": os.environ.get("VLLM_API_KEY", "fake-api-key"), **completion_kwargs}
342
331
  completion = litellm.completion(model=self.model_name, messages=messages, **completion_kwargs)
@@ -75,7 +75,7 @@ class Optimizer:
75
75
  cost_model: BaseCostModel,
76
76
  available_models: list[Model],
77
77
  join_parallelism: int = 64,
78
- reasoning_effort: str | None = None,
78
+ reasoning_effort: str | None = "default",
79
79
  api_base: str | None = None,
80
80
  verbose: bool = False,
81
81
  allow_bonded_query: bool = True,
@@ -54,6 +54,7 @@ from palimpzest.query.operators.search import (
54
54
  from palimpzest.query.operators.split import SplitConvert, SplitFilter
55
55
  from palimpzest.query.operators.topk import TopKOp
56
56
  from palimpzest.query.optimizer.primitives import Expression, Group, LogicalExpression, PhysicalExpression
57
+ from palimpzest.utils.model_helpers import resolve_reasoning_settings
57
58
 
58
59
  logger = logging.getLogger(__name__)
59
60
 
@@ -628,15 +629,17 @@ class LLMConvertBondedRule(ImplementationRule):
628
629
 
629
630
  # create variable physical operator kwargs for each model which can implement this logical_expression
630
631
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
631
- no_reasoning = runtime_kwargs["reasoning_effort"] in [None, "minimal", "low"]
632
- variable_op_kwargs = [
633
- {
634
- "model": model,
635
- "prompt_strategy": PromptStrategy.MAP_NO_REASONING if model.is_reasoning_model() and no_reasoning else PromptStrategy.MAP,
636
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
637
- }
638
- for model in models
639
- ]
632
+ variable_op_kwargs = []
633
+ for model in models:
634
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
635
+ prompt_strategy = PromptStrategy.MAP if use_reasoning_prompt else PromptStrategy.MAP_NO_REASONING
636
+ variable_op_kwargs.append(
637
+ {
638
+ "model": model,
639
+ "prompt_strategy": prompt_strategy,
640
+ "reasoning_effort": reasoning_effort,
641
+ }
642
+ )
640
643
 
641
644
  return cls._perform_substitution(logical_expression, LLMConvertBonded, runtime_kwargs, variable_op_kwargs)
642
645
 
@@ -665,18 +668,27 @@ class RAGRule(ImplementationRule):
665
668
 
666
669
  # create variable physical operator kwargs for each model which can implement this logical_expression
667
670
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
668
- variable_op_kwargs = [
669
- {
670
- "model": model,
671
- "prompt_strategy": PromptStrategy.MAP if phys_op_cls is RAGConvert else PromptStrategy.FILTER,
672
- "num_chunks_per_field": num_chunks_per_field,
673
- "chunk_size": chunk_size,
674
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
675
- }
676
- for model in models
677
- for num_chunks_per_field in cls.num_chunks_per_fields
678
- for chunk_size in cls.chunk_sizes
679
- ]
671
+ variable_op_kwargs = []
672
+ for model in models:
673
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
674
+ prompt_strategy = (
675
+ PromptStrategy.MAP if use_reasoning_prompt else PromptStrategy.MAP_NO_REASONING
676
+ if phys_op_cls is RAGConvert
677
+ else PromptStrategy.FILTER if use_reasoning_prompt else PromptStrategy.FILTER_NO_REASONING
678
+ )
679
+ variable_op_kwargs.extend(
680
+ [
681
+ {
682
+ "model": model,
683
+ "prompt_strategy": prompt_strategy,
684
+ "num_chunks_per_field": num_chunks_per_field,
685
+ "chunk_size": chunk_size,
686
+ "reasoning_effort": reasoning_effort,
687
+ }
688
+ for num_chunks_per_field in cls.num_chunks_per_fields
689
+ for chunk_size in cls.chunk_sizes
690
+ ]
691
+ )
680
692
 
681
693
  return cls._perform_substitution(logical_expression, phys_op_cls, runtime_kwargs, variable_op_kwargs)
682
694
 
@@ -704,6 +716,7 @@ class MixtureOfAgentsRule(ImplementationRule):
704
716
  phys_op_cls = MixtureOfAgentsConvert if isinstance(logical_expression.operator, ConvertScan) else MixtureOfAgentsFilter
705
717
 
706
718
  # create variable physical operator kwargs for each model which can implement this logical_expression
719
+ _, reasoning_effort = resolve_reasoning_settings(None, runtime_kwargs["reasoning_effort"])
707
720
  proposer_model_set = {model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)}
708
721
  aggregator_model_set = {model for model in runtime_kwargs["available_models"] if model.is_text_model()}
709
722
  variable_op_kwargs = [
@@ -711,7 +724,7 @@ class MixtureOfAgentsRule(ImplementationRule):
711
724
  "proposer_models": list(proposer_models),
712
725
  "temperatures": [temp] * len(proposer_models),
713
726
  "aggregator_model": aggregator_model,
714
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
727
+ "reasoning_effort": reasoning_effort,
715
728
  }
716
729
  for k in cls.num_proposer_models
717
730
  for temp in cls.temperatures
@@ -743,18 +756,27 @@ class CritiqueAndRefineRule(ImplementationRule):
743
756
 
744
757
  # create variable physical operator kwargs for each model which can implement this logical_expression
745
758
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
746
- variable_op_kwargs = [
747
- {
748
- "model": model,
749
- "critic_model": critic_model,
750
- "refine_model": refine_model,
751
- "prompt_strategy": PromptStrategy.MAP if phys_op_cls is CritiqueAndRefineConvert else PromptStrategy.FILTER,
752
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
753
- }
754
- for model in models
755
- for critic_model in models
756
- for refine_model in models
757
- ]
759
+ variable_op_kwargs = []
760
+ for model in models:
761
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
762
+ prompt_strategy = (
763
+ PromptStrategy.MAP if use_reasoning_prompt else PromptStrategy.MAP_NO_REASONING
764
+ if phys_op_cls is CritiqueAndRefineConvert
765
+ else PromptStrategy.FILTER if use_reasoning_prompt else PromptStrategy.FILTER_NO_REASONING
766
+ )
767
+ variable_op_kwargs.extend(
768
+ [
769
+ {
770
+ "model": model,
771
+ "critic_model": critic_model,
772
+ "refine_model": refine_model,
773
+ "prompt_strategy": prompt_strategy,
774
+ "reasoning_effort": reasoning_effort,
775
+ }
776
+ for critic_model in models
777
+ for refine_model in models
778
+ ]
779
+ )
758
780
 
759
781
  return cls._perform_substitution(logical_expression, phys_op_cls, runtime_kwargs, variable_op_kwargs)
760
782
 
@@ -782,12 +804,13 @@ class SplitRule(ImplementationRule):
782
804
 
783
805
  # create variable physical operator kwargs for each model which can implement this logical_expression
784
806
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
807
+ _, reasoning_effort = resolve_reasoning_settings(None, runtime_kwargs["reasoning_effort"])
785
808
  variable_op_kwargs = [
786
809
  {
787
810
  "model": model,
788
811
  "min_size_to_chunk": min_size_to_chunk,
789
812
  "num_chunks": num_chunks,
790
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
813
+ "reasoning_effort": reasoning_effort,
791
814
  }
792
815
  for model in models
793
816
  for min_size_to_chunk in cls.min_size_to_chunk
@@ -855,15 +878,17 @@ class LLMFilterRule(ImplementationRule):
855
878
 
856
879
  # create variable physical operator kwargs for each model which can implement this logical_expression
857
880
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
858
- no_reasoning = runtime_kwargs["reasoning_effort"] in [None, "minimal", "low"]
859
- variable_op_kwargs = [
860
- {
861
- "model": model,
862
- "prompt_strategy": PromptStrategy.FILTER_NO_REASONING if model.is_reasoning_model() and no_reasoning else PromptStrategy.FILTER,
863
- "reasoning_effort": runtime_kwargs["reasoning_effort"]
864
- }
865
- for model in models
866
- ]
881
+ variable_op_kwargs = []
882
+ for model in models:
883
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
884
+ prompt_strategy = PromptStrategy.FILTER if use_reasoning_prompt else PromptStrategy.FILTER_NO_REASONING
885
+ variable_op_kwargs.append(
886
+ {
887
+ "model": model,
888
+ "prompt_strategy": prompt_strategy,
889
+ "reasoning_effort": reasoning_effort,
890
+ }
891
+ )
867
892
 
868
893
  return cls._perform_substitution(logical_expression, LLMFilter, runtime_kwargs, variable_op_kwargs)
869
894
 
@@ -902,17 +927,19 @@ class NestedLoopsJoinRule(ImplementationRule):
902
927
 
903
928
  # create variable physical operator kwargs for each model which can implement this logical_expression
904
929
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
905
- no_reasoning = runtime_kwargs["reasoning_effort"] in [None, "minimal", "low"]
906
- variable_op_kwargs = [
907
- {
908
- "model": model,
909
- "prompt_strategy": PromptStrategy.JOIN_NO_REASONING if model.is_reasoning_model() and no_reasoning else PromptStrategy.JOIN,
910
- "join_parallelism": runtime_kwargs["join_parallelism"],
911
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
912
- "retain_inputs": not runtime_kwargs["is_validation"],
913
- }
914
- for model in models
915
- ]
930
+ variable_op_kwargs = []
931
+ for model in models:
932
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
933
+ prompt_strategy = PromptStrategy.JOIN if use_reasoning_prompt else PromptStrategy.JOIN_NO_REASONING
934
+ variable_op_kwargs.append(
935
+ {
936
+ "model": model,
937
+ "prompt_strategy": prompt_strategy,
938
+ "join_parallelism": runtime_kwargs["join_parallelism"],
939
+ "reasoning_effort": reasoning_effort,
940
+ "retain_inputs": not runtime_kwargs["is_validation"],
941
+ }
942
+ )
916
943
 
917
944
  return cls._perform_substitution(logical_expression, NestedLoopsJoin, runtime_kwargs, variable_op_kwargs)
918
945
 
@@ -934,18 +961,20 @@ class EmbeddingJoinRule(ImplementationRule):
934
961
 
935
962
  # create variable physical operator kwargs for each model which can implement this logical_expression
936
963
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression)]
937
- no_reasoning = runtime_kwargs["reasoning_effort"] in [None, "minimal", "low"]
938
- variable_op_kwargs = [
939
- {
940
- "model": model,
941
- "prompt_strategy": PromptStrategy.JOIN_NO_REASONING if model.is_reasoning_model() and no_reasoning else PromptStrategy.JOIN,
942
- "join_parallelism": runtime_kwargs["join_parallelism"],
943
- "reasoning_effort": runtime_kwargs["reasoning_effort"],
944
- "retain_inputs": not runtime_kwargs["is_validation"],
945
- "num_samples": 10, # TODO: iterate over different choices of num_samples
946
- }
947
- for model in models
948
- ]
964
+ variable_op_kwargs = []
965
+ for model in models:
966
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
967
+ prompt_strategy = PromptStrategy.JOIN if use_reasoning_prompt else PromptStrategy.JOIN_NO_REASONING
968
+ variable_op_kwargs.append(
969
+ {
970
+ "model": model,
971
+ "prompt_strategy": prompt_strategy,
972
+ "join_parallelism": runtime_kwargs["join_parallelism"],
973
+ "reasoning_effort": reasoning_effort,
974
+ "retain_inputs": not runtime_kwargs["is_validation"],
975
+ "num_samples": 10, # TODO: iterate over different choices of num_samples
976
+ }
977
+ )
949
978
 
950
979
  return cls._perform_substitution(logical_expression, EmbeddingJoin, runtime_kwargs, variable_op_kwargs)
951
980
 
@@ -966,15 +995,17 @@ class SemanticAggregateRule(ImplementationRule):
966
995
 
967
996
  # create variable physical operator kwargs for each model which can implement this logical_expression
968
997
  models = [model for model in runtime_kwargs["available_models"] if cls._model_matches_input(model, logical_expression) and not model.is_llama_model()]
969
- no_reasoning = runtime_kwargs["reasoning_effort"] in [None, "minimal", "low"]
970
- variable_op_kwargs = [
971
- {
972
- "model": model,
973
- "prompt_strategy": PromptStrategy.AGG_NO_REASONING if model.is_reasoning_model() and no_reasoning else PromptStrategy.AGG,
974
- "reasoning_effort": runtime_kwargs["reasoning_effort"]
975
- }
976
- for model in models
977
- ]
998
+ variable_op_kwargs = []
999
+ for model in models:
1000
+ use_reasoning_prompt, reasoning_effort = resolve_reasoning_settings(model, runtime_kwargs["reasoning_effort"])
1001
+ prompt_strategy = PromptStrategy.AGG if use_reasoning_prompt else PromptStrategy.AGG_NO_REASONING
1002
+ variable_op_kwargs.append(
1003
+ {
1004
+ "model": model,
1005
+ "prompt_strategy": prompt_strategy,
1006
+ "reasoning_effort": reasoning_effort,
1007
+ }
1008
+ )
978
1009
 
979
1010
  return cls._perform_substitution(logical_expression, SemanticAggregate, runtime_kwargs, variable_op_kwargs)
980
1011
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from pydantic import BaseModel, ConfigDict, Field
2
4
 
3
5
  from palimpzest.constants import Model
@@ -18,7 +20,7 @@ class QueryProcessorConfig(BaseModel):
18
20
  policy: Policy = Field(default_factory=MaxQuality)
19
21
  enforce_types: bool = Field(default=False)
20
22
  scan_start_idx: int = Field(default=0)
21
- num_samples: int = Field(default=None)
23
+ num_samples: int | None = Field(default=None)
22
24
  verbose: bool = Field(default=False)
23
25
  progress: bool = Field(default=True)
24
26
  available_models: list[Model] | None = Field(default=None)
@@ -26,8 +28,8 @@ class QueryProcessorConfig(BaseModel):
26
28
  max_workers: int | None = Field(default=64)
27
29
  join_parallelism: int = Field(default=64)
28
30
  batch_size: int | None = Field(default=None)
29
- reasoning_effort: str | None = Field(default=None) # Gemini: "disable", "low", "medium", "high"
30
- use_vertex: bool = Field(default=True) # Whether to use Vertex models for Gemini or Google models
31
+ reasoning_effort: str | None = Field(default="default") # Gemini: "disable", "low", "medium", "high"
32
+ use_vertex: bool = Field(default=False) # Whether to use Vertex models for Gemini or Google models
31
33
  gemini_credentials_path: str | None = Field(default=None) # Path to Gemini credentials file
32
34
  api_base: str | None = Field(default=None) # API base URL for vLLM
33
35
 
@@ -53,3 +55,7 @@ class QueryProcessorConfig(BaseModel):
53
55
  def to_dict(self) -> dict:
54
56
  """Convert the config to a dict representation."""
55
57
  return self.model_dump()
58
+
59
+ def copy(self) -> QueryProcessorConfig:
60
+ """Create a copy of the config."""
61
+ return QueryProcessorConfig(**self.to_dict())
@@ -2,6 +2,8 @@ import logging
2
2
  import os
3
3
  from enum import Enum
4
4
 
5
+ from dotenv import load_dotenv
6
+
5
7
  from palimpzest.core.data.dataset import Dataset
6
8
  from palimpzest.core.elements.records import DataRecordCollection
7
9
  from palimpzest.query.execution.execution_strategy import ExecutionStrategy, SentinelExecutionStrategy
@@ -108,7 +110,7 @@ class QueryProcessorFactory:
108
110
  raise ValueError("ANTHROPIC_API_KEY must be set to use Anthropic models.")
109
111
  if model.is_together_model() and not together_key:
110
112
  raise ValueError("TOGETHER_API_KEY must be set to use Together models.")
111
- if model.is_google_model() and not (gemini_key or google_key or config.gemini_credentials_path):
113
+ if model.is_google_ai_studio_model() and not (gemini_key or google_key or config.gemini_credentials_path):
112
114
  raise ValueError("GEMINI_API_KEY, GOOGLE_API_KEY, or gemini_credentials path must be set to use Google Gemini models.")
113
115
  if model.is_vllm_model() and config.api_base is None:
114
116
  raise ValueError("api_base must be set to use vLLM models.")
@@ -168,6 +170,9 @@ class QueryProcessorFactory:
168
170
  if config is None:
169
171
  config = QueryProcessorConfig()
170
172
 
173
+ # make a copy of the config to avoid modifying the original
174
+ config = config.copy()
175
+
171
176
  # apply any additional keyword arguments to the config and validate its contents
172
177
  config, validator = cls._config_validation_and_normalization(config, train_dataset, validator)
173
178
 
@@ -194,6 +199,7 @@ class QueryProcessorFactory:
194
199
  train_dataset: dict[str, Dataset] | None = None,
195
200
  validator: Validator | None = None,
196
201
  ) -> DataRecordCollection:
202
+ load_dotenv(override=True)
197
203
  logger.info(f"Creating processor for dataset: {dataset}")
198
204
  processor = cls.create_processor(dataset, config, train_dataset, validator)
199
205
  logger.info(f"Created processor: {processor}")
@@ -0,0 +1,88 @@
1
+ import os
2
+
3
+ from palimpzest.constants import Model
4
+
5
+
6
+ def get_models(include_embedding: bool = False, use_vertex: bool = False, gemini_credentials_path: str | None = None, api_base: str | None = None) -> list[Model]:
7
+ """
8
+ Return the set of models which the system has access to based on the set environment variables.
9
+ """
10
+ models = []
11
+ if os.getenv("OPENAI_API_KEY") not in [None, ""]:
12
+ openai_models = [model for model in Model if model.is_openai_model()]
13
+ if not include_embedding:
14
+ openai_models = [
15
+ model for model in openai_models if not model.is_embedding_model()
16
+ ]
17
+ models.extend(openai_models)
18
+
19
+ if os.getenv("TOGETHER_API_KEY") not in [None, ""]:
20
+ together_models = [model for model in Model if model.is_together_model()]
21
+ if not include_embedding:
22
+ together_models = [
23
+ model for model in together_models if not model.is_embedding_model()
24
+ ]
25
+ models.extend(together_models)
26
+
27
+ if os.getenv("ANTHROPIC_API_KEY") not in [None, ""]:
28
+ anthropic_models = [model for model in Model if model.is_anthropic_model()]
29
+ if not include_embedding:
30
+ anthropic_models = [
31
+ model for model in anthropic_models if not model.is_embedding_model()
32
+ ]
33
+ models.extend(anthropic_models)
34
+
35
+ gemini_credentials_path = (
36
+ os.path.join(os.path.expanduser("~"), ".config", "gcloud", "application_default_credentials.json")
37
+ if gemini_credentials_path is None
38
+ else gemini_credentials_path
39
+ )
40
+ if os.getenv("GEMINI_API_KEY") not in [None, ""] or (use_vertex and os.path.exists(gemini_credentials_path)):
41
+ vertex_models = [model for model in Model if model.is_vertex_model()]
42
+ google_ai_studio_models = [model for model in Model if model.is_google_ai_studio_model()]
43
+ if not include_embedding:
44
+ vertex_models = [
45
+ model for model in vertex_models if not model.is_embedding_model()
46
+ ]
47
+ if use_vertex:
48
+ models.extend(vertex_models)
49
+ else:
50
+ models.extend(google_ai_studio_models)
51
+
52
+ if api_base is not None:
53
+ vllm_models = [model for model in Model if model.is_vllm_model()]
54
+ if not include_embedding:
55
+ vllm_models = [
56
+ model for model in vllm_models if not model.is_embedding_model()
57
+ ]
58
+ models.extend(vllm_models)
59
+
60
+ return models
61
+
62
+
63
+ def resolve_reasoning_settings(model: Model | None, reasoning_effort: str | None) -> tuple[bool, str]:
64
+ """
65
+ Resolve the reasoning settings based on the model and provided reasoning effort.
66
+ Returns a tuple indicating whether reasoning prompt should be used and the reasoning effort level.
67
+ By default, we use the reasoning prompt everywhere while setting the model reasoning effort to None (or minimal).
68
+ If a user explicitly provides a reasoning_effort, we pass that through to the model.
69
+ If the user explicitly disables reasoning_effort, we disable the reasoning prompt as well.
70
+ """
71
+ # turn off reasoning prompt if reasoning_effort is in [None, "disable", "minimal", "low"]
72
+ use_reasoning_prompt = reasoning_effort not in [None, "disable", "minimal", "low"]
73
+
74
+ # if reasoning_effort is set to "default", set it to None to use model defaults
75
+ if reasoning_effort == "default":
76
+ reasoning_effort = None
77
+
78
+ # translate reasoning_effort into model-specific settings
79
+ if model is not None and model.is_reasoning_model():
80
+ if model.is_vertex_model() or model.is_google_ai_studio_model():
81
+ if reasoning_effort is None and model in [Model.GEMINI_2_5_PRO, Model.GOOGLE_GEMINI_2_5_PRO]:
82
+ reasoning_effort = "low"
83
+ elif reasoning_effort is None:
84
+ reasoning_effort = "disable"
85
+ elif model.is_openai_model():
86
+ reasoning_effort = "minimal" if reasoning_effort in [None, "disable", "minimal", "low"] else reasoning_effort
87
+
88
+ return use_reasoning_prompt, reasoning_effort
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: palimpzest
3
- Version: 1.2.0
3
+ Version: 1.3.1
4
4
  Summary: Palimpzest is a system which enables anyone to process AI-powered analytical queries simply by defining them in a declarative language
5
5
  Author-email: MIT DSG Semantic Management Lab <michjc@csail.mit.edu>
6
6
  Project-URL: homepage, https://palimpzest.org
@@ -34,6 +34,7 @@ Requires-Dist: PyLD>=2.0.4
34
34
  Requires-Dist: pyarrow>=20.0.0
35
35
  Requires-Dist: pypdf>=5.1.0
36
36
  Requires-Dist: pytest-mock>=3.14.0
37
+ Requires-Dist: python-dotenv>=1.2.1
37
38
  Requires-Dist: pyyaml>=6.0.1
38
39
  Requires-Dist: requests>=2.25
39
40
  Requires-Dist: ruff>=0.9.0
@@ -17,6 +17,7 @@ PyLD>=2.0.4
17
17
  pyarrow>=20.0.0
18
18
  pypdf>=5.1.0
19
19
  pytest-mock>=3.14.0
20
+ python-dotenv>=1.2.1
20
21
  pyyaml>=6.0.1
21
22
  requests>=2.25
22
23
  ruff>=0.9.0
@@ -1,61 +0,0 @@
1
- import os
2
-
3
- from palimpzest.constants import Model
4
-
5
-
6
- # TODO: better handle vertex vs. google for gemini models
7
- def get_models(include_embedding: bool = False, use_vertex: bool = True, gemini_credentials_path: str | None = None, api_base: str | None = None) -> list[Model]:
8
- """
9
- Return the set of models which the system has access to based on the set environment variables.
10
- """
11
- models = []
12
- if os.getenv("OPENAI_API_KEY") is not None:
13
- openai_models = [model for model in Model if model.is_openai_model()]
14
- if not include_embedding:
15
- openai_models = [
16
- model for model in openai_models if not model.is_embedding_model()
17
- ]
18
- models.extend(openai_models)
19
-
20
- if os.getenv("TOGETHER_API_KEY") is not None:
21
- together_models = [model for model in Model if model.is_together_model()]
22
- if not include_embedding:
23
- together_models = [
24
- model for model in together_models if not model.is_embedding_model()
25
- ]
26
- models.extend(together_models)
27
-
28
- if os.getenv("ANTHROPIC_API_KEY") is not None:
29
- anthropic_models = [model for model in Model if model.is_anthropic_model()]
30
- if not include_embedding:
31
- anthropic_models = [
32
- model for model in anthropic_models if not model.is_embedding_model()
33
- ]
34
- models.extend(anthropic_models)
35
-
36
- gemini_credentials_path = (
37
- os.path.join(os.path.expanduser("~"), ".config", "gcloud", "application_default_credentials.json")
38
- if gemini_credentials_path is None
39
- else gemini_credentials_path
40
- )
41
- if os.getenv("GEMINI_API_KEY") is not None or os.path.exists(gemini_credentials_path):
42
- vertex_models = [model for model in Model if model.is_vertex_model()]
43
- google_models = [model for model in Model if model.is_google_model()]
44
- if not include_embedding:
45
- vertex_models = [
46
- model for model in vertex_models if not model.is_embedding_model()
47
- ]
48
- if use_vertex:
49
- models.extend(vertex_models)
50
- else:
51
- models.extend(google_models)
52
-
53
- if api_base is not None:
54
- vllm_models = [model for model in Model if model.is_vllm_model()]
55
- if not include_embedding:
56
- vllm_models = [
57
- model for model in vllm_models if not model.is_embedding_model()
58
- ]
59
- models.extend(vllm_models)
60
-
61
- return models
File without changes
File without changes
File without changes