edsl 0.1.33__py3-none-any.whl → 0.1.33.dev2__py3-none-any.whl

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 (63) hide show
  1. edsl/Base.py +3 -9
  2. edsl/__init__.py +0 -1
  3. edsl/__version__.py +1 -1
  4. edsl/agents/Agent.py +6 -6
  5. edsl/agents/Invigilator.py +3 -6
  6. edsl/agents/InvigilatorBase.py +27 -8
  7. edsl/agents/{PromptConstructor.py → PromptConstructionMixin.py} +29 -101
  8. edsl/config.py +34 -26
  9. edsl/coop/coop.py +2 -11
  10. edsl/data_transfer_models.py +73 -26
  11. edsl/enums.py +0 -2
  12. edsl/inference_services/GoogleService.py +1 -1
  13. edsl/inference_services/InferenceServiceABC.py +13 -44
  14. edsl/inference_services/OpenAIService.py +4 -7
  15. edsl/inference_services/TestService.py +15 -24
  16. edsl/inference_services/registry.py +0 -2
  17. edsl/jobs/Jobs.py +8 -18
  18. edsl/jobs/buckets/BucketCollection.py +15 -24
  19. edsl/jobs/buckets/TokenBucket.py +10 -64
  20. edsl/jobs/interviews/Interview.py +47 -115
  21. edsl/jobs/interviews/InterviewExceptionEntry.py +0 -2
  22. edsl/jobs/interviews/{InterviewExceptionCollection.py → interview_exception_tracking.py} +0 -16
  23. edsl/jobs/interviews/retry_management.py +39 -0
  24. edsl/jobs/runners/JobsRunnerAsyncio.py +170 -95
  25. edsl/jobs/runners/JobsRunnerStatusMixin.py +333 -0
  26. edsl/jobs/tasks/TaskHistory.py +0 -17
  27. edsl/language_models/LanguageModel.py +31 -26
  28. edsl/language_models/registry.py +9 -13
  29. edsl/questions/QuestionBase.py +14 -63
  30. edsl/questions/QuestionBudget.py +41 -93
  31. edsl/questions/QuestionFreeText.py +0 -6
  32. edsl/questions/QuestionMultipleChoice.py +23 -8
  33. edsl/questions/QuestionNumerical.py +4 -5
  34. edsl/questions/ResponseValidatorABC.py +5 -6
  35. edsl/questions/derived/QuestionLinearScale.py +1 -4
  36. edsl/questions/derived/QuestionTopK.py +1 -4
  37. edsl/questions/derived/QuestionYesNo.py +2 -8
  38. edsl/results/DatasetExportMixin.py +1 -5
  39. edsl/results/Result.py +1 -1
  40. edsl/results/Results.py +1 -4
  41. edsl/scenarios/FileStore.py +10 -71
  42. edsl/scenarios/Scenario.py +21 -86
  43. edsl/scenarios/ScenarioImageMixin.py +2 -2
  44. edsl/scenarios/ScenarioList.py +0 -13
  45. edsl/scenarios/ScenarioListPdfMixin.py +4 -150
  46. edsl/study/Study.py +0 -32
  47. edsl/surveys/Rule.py +1 -10
  48. edsl/surveys/RuleCollection.py +3 -19
  49. edsl/surveys/Survey.py +0 -7
  50. edsl/templates/error_reporting/interview_details.html +1 -6
  51. edsl/utilities/utilities.py +1 -9
  52. {edsl-0.1.33.dist-info → edsl-0.1.33.dev2.dist-info}/METADATA +1 -2
  53. {edsl-0.1.33.dist-info → edsl-0.1.33.dev2.dist-info}/RECORD +55 -61
  54. edsl/inference_services/TogetherAIService.py +0 -170
  55. edsl/jobs/runners/JobsRunnerStatus.py +0 -331
  56. edsl/questions/Quick.py +0 -41
  57. edsl/questions/templates/budget/__init__.py +0 -0
  58. edsl/questions/templates/budget/answering_instructions.jinja +0 -7
  59. edsl/questions/templates/budget/question_presentation.jinja +0 -7
  60. edsl/questions/templates/extract/__init__.py +0 -0
  61. edsl/questions/templates/rank/__init__.py +0 -0
  62. {edsl-0.1.33.dist-info → edsl-0.1.33.dev2.dist-info}/LICENSE +0 -0
  63. {edsl-0.1.33.dist-info → edsl-0.1.33.dev2.dist-info}/WHEEL +0 -0
edsl/Base.py CHANGED
@@ -47,27 +47,21 @@ class PersistenceMixin:
47
47
  self,
48
48
  description: Optional[str] = None,
49
49
  visibility: Optional[str] = "unlisted",
50
- expected_parrot_url: Optional[str] = None,
51
50
  ):
52
51
  """Post the object to coop."""
53
52
  from edsl.coop import Coop
54
53
 
55
- c = Coop(url=expected_parrot_url)
54
+ c = Coop()
56
55
  return c.create(self, description, visibility)
57
56
 
58
57
  @classmethod
59
- def pull(
60
- cls,
61
- uuid: Optional[Union[str, UUID]] = None,
62
- url: Optional[str] = None,
63
- expected_parrot_url: Optional[str] = None,
64
- ):
58
+ def pull(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
65
59
  """Pull the object from coop."""
66
60
  from edsl.coop import Coop
67
61
  from edsl.coop.utils import ObjectRegistry
68
62
 
69
63
  object_type = ObjectRegistry.get_object_type_by_edsl_class(cls)
70
- coop = Coop(url=expected_parrot_url)
64
+ coop = Coop()
71
65
  return coop.get(uuid, url, object_type)
72
66
 
73
67
  @classmethod
edsl/__init__.py CHANGED
@@ -23,7 +23,6 @@ from edsl.questions import QuestionNumerical
23
23
  from edsl.questions import QuestionYesNo
24
24
  from edsl.questions import QuestionBudget
25
25
  from edsl.questions import QuestionRank
26
- from edsl.questions import QuestionTopK
27
26
 
28
27
  from edsl.scenarios import Scenario
29
28
  from edsl.scenarios import ScenarioList
edsl/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.33"
1
+ __version__ = "0.1.33.dev1"
edsl/agents/Agent.py CHANGED
@@ -586,9 +586,9 @@ class Agent(Base):
586
586
  if dynamic_traits_func:
587
587
  func = inspect.getsource(dynamic_traits_func)
588
588
  raw_data["dynamic_traits_function_source_code"] = func
589
- raw_data[
590
- "dynamic_traits_function_name"
591
- ] = self.dynamic_traits_function_name
589
+ raw_data["dynamic_traits_function_name"] = (
590
+ self.dynamic_traits_function_name
591
+ )
592
592
  if hasattr(self, "answer_question_directly"):
593
593
  raw_data.pop(
594
594
  "answer_question_directly", None
@@ -604,9 +604,9 @@ class Agent(Base):
604
604
  raw_data["answer_question_directly_source_code"] = inspect.getsource(
605
605
  answer_question_directly_func
606
606
  )
607
- raw_data[
608
- "answer_question_directly_function_name"
609
- ] = self.answer_question_directly_function_name
607
+ raw_data["answer_question_directly_function_name"] = (
608
+ self.answer_question_directly_function_name
609
+ )
610
610
 
611
611
  return raw_data
612
612
 
@@ -2,13 +2,14 @@
2
2
 
3
3
  from typing import Dict, Any, Optional
4
4
 
5
+ from edsl.exceptions import AgentRespondedWithBadJSONError
5
6
  from edsl.prompts.Prompt import Prompt
6
7
  from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
7
8
  from edsl.prompts.registry import get_classes as prompt_lookup
8
9
  from edsl.exceptions.questions import QuestionAnswerValidationError
10
+ from edsl.agents.PromptConstructionMixin import PromptConstructorMixin
9
11
  from edsl.agents.InvigilatorBase import InvigilatorBase
10
12
  from edsl.data_transfer_models import AgentResponseDict, EDSLResultObjectInput
11
- from edsl.agents.PromptConstructor import PromptConstructor
12
13
 
13
14
 
14
15
  class NotApplicable(str):
@@ -18,13 +19,9 @@ class NotApplicable(str):
18
19
  return instance
19
20
 
20
21
 
21
- class InvigilatorAI(InvigilatorBase):
22
+ class InvigilatorAI(PromptConstructorMixin, InvigilatorBase):
22
23
  """An invigilator that uses an AI model to answer questions."""
23
24
 
24
- def get_prompts(self) -> Dict[str, Prompt]:
25
- """Return the prompts used."""
26
- return self.prompt_constructor.get_prompts()
27
-
28
25
  async def async_answer_question(self) -> AgentResponseDict:
29
26
  """Answer a question using the AI model.
30
27
 
@@ -14,7 +14,6 @@ from edsl.surveys.MemoryPlan import MemoryPlan
14
14
  from edsl.language_models.LanguageModel import LanguageModel
15
15
 
16
16
  from edsl.data_transfer_models import EDSLResultObjectInput
17
- from edsl.agents.PromptConstructor import PromptConstructor
18
17
 
19
18
 
20
19
  class InvigilatorBase(ABC):
@@ -28,7 +27,16 @@ class InvigilatorBase(ABC):
28
27
 
29
28
  This returns an empty prompt because there is no memory the agent needs to have at q0.
30
29
 
30
+ >>> InvigilatorBase.example().create_memory_prompt("q0")
31
+ Prompt(text=\"""\""")
31
32
 
33
+ >>> i = InvigilatorBase.example()
34
+ >>> i.current_answers = {"q0": "Prior answer"}
35
+ >>> i.memory_plan.add_single_memory("q1", "q0")
36
+ >>> i.create_memory_prompt("q1")
37
+ Prompt(text=\"""
38
+ Before the question you are now answering, you already answered the following question(s):
39
+ ...
32
40
  """
33
41
 
34
42
  def __init__(
@@ -64,11 +72,6 @@ class InvigilatorBase(ABC):
64
72
  None # placeholder for the raw response from the model
65
73
  )
66
74
 
67
- @property
68
- def prompt_constructor(self) -> PromptConstructor:
69
- """Return the prompt constructor."""
70
- return PromptConstructor(self)
71
-
72
75
  def to_dict(self):
73
76
  attributes = [
74
77
  "agent",
@@ -204,6 +207,22 @@ class InvigilatorBase(ABC):
204
207
 
205
208
  return main()
206
209
 
210
+ def create_memory_prompt(self, question_name: str) -> Prompt:
211
+ """Create a memory for the agent.
212
+
213
+ The returns a memory prompt for the agent.
214
+
215
+ >>> i = InvigilatorBase.example()
216
+ >>> i.current_answers = {"q0": "Prior answer"}
217
+ >>> i.memory_plan.add_single_memory("q1", "q0")
218
+ >>> p = i.create_memory_prompt("q1")
219
+ >>> p.text.strip().replace("\\n", " ").replace("\\t", " ")
220
+ 'Before the question you are now answering, you already answered the following question(s): Question: Do you like school? Answer: Prior answer'
221
+ """
222
+ return self.memory_plan.get_memory_prompt_fragment(
223
+ question_name, self.current_answers
224
+ )
225
+
207
226
  @classmethod
208
227
  def example(
209
228
  cls, throw_an_exception=False, question=None, scenario=None, survey=None
@@ -266,9 +285,9 @@ class InvigilatorBase(ABC):
266
285
 
267
286
  memory_plan = MemoryPlan(survey=survey)
268
287
  current_answers = None
269
- from edsl.agents.PromptConstructor import PromptConstructor
288
+ from edsl.agents.PromptConstructionMixin import PromptConstructorMixin
270
289
 
271
- class InvigilatorExample(InvigilatorBase):
290
+ class InvigilatorExample(PromptConstructorMixin, InvigilatorBase):
272
291
  """An example invigilator."""
273
292
 
274
293
  async def async_answer_question(self):
@@ -1,15 +1,16 @@
1
1
  from __future__ import annotations
2
- from typing import Dict, Any, Optional, Set
2
+ from typing import Dict, Any, Optional
3
3
  from collections import UserList
4
- import enum
5
-
6
- from jinja2 import Environment, meta
7
4
 
5
+ # from functools import reduce
8
6
  from edsl.prompts.Prompt import Prompt
9
- from edsl.data_transfer_models import ImageInfo
7
+
8
+ # from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
10
9
  from edsl.prompts.registry import get_classes as prompt_lookup
11
10
  from edsl.exceptions import QuestionScenarioRenderError
12
11
 
12
+ import enum
13
+
13
14
 
14
15
  class PromptComponent(enum.Enum):
15
16
  AGENT_INSTRUCTIONS = "agent_instructions"
@@ -18,21 +19,6 @@ class PromptComponent(enum.Enum):
18
19
  PRIOR_QUESTION_MEMORY = "prior_question_memory"
19
20
 
20
21
 
21
- def get_jinja2_variables(template_str: str) -> Set[str]:
22
- """
23
- Extracts all variable names from a Jinja2 template using Jinja2's built-in parsing.
24
-
25
- Args:
26
- template_str (str): The Jinja2 template string
27
-
28
- Returns:
29
- Set[str]: A set of variable names found in the template
30
- """
31
- env = Environment()
32
- ast = env.parse(template_str)
33
- return meta.find_undeclared_variables(ast)
34
-
35
-
36
22
  class PromptList(UserList):
37
23
  separator = Prompt(" ")
38
24
 
@@ -151,7 +137,7 @@ class PromptPlan:
151
137
  }
152
138
 
153
139
 
154
- class PromptConstructor:
140
+ class PromptConstructorMixin:
155
141
  """Mixin for constructing prompts for the LLM call.
156
142
 
157
143
  The pieces of a prompt are:
@@ -163,40 +149,16 @@ class PromptConstructor:
163
149
  This is mixed into the Invigilator class.
164
150
  """
165
151
 
166
- def __init__(self, invigilator):
167
- self.invigilator = invigilator
168
- self.agent = invigilator.agent
169
- self.question = invigilator.question
170
- self.scenario = invigilator.scenario
171
- self.survey = invigilator.survey
172
- self.model = invigilator.model
173
- self.current_answers = invigilator.current_answers
174
- self.memory_plan = invigilator.memory_plan
175
- self.prompt_plan = PromptPlan() # Assuming PromptPlan is defined elsewhere
176
-
177
- # prompt_plan = PromptPlan()
178
-
179
- @property
180
- def scenario_image_keys(self):
181
- image_entries = []
182
-
183
- for key, value in self.scenario.items():
184
- if isinstance(value, ImageInfo):
185
- image_entries.append(key)
186
- return image_entries
152
+ prompt_plan = PromptPlan()
187
153
 
188
154
  @property
189
155
  def agent_instructions_prompt(self) -> Prompt:
190
156
  """
191
157
  >>> from edsl.agents.InvigilatorBase import InvigilatorBase
192
158
  >>> i = InvigilatorBase.example()
193
- >>> i.prompt_constructor.agent_instructions_prompt
159
+ >>> i.agent_instructions_prompt
194
160
  Prompt(text=\"""You are answering questions as if you were a human. Do not break character.\""")
195
161
  """
196
- from edsl import Agent
197
-
198
- if self.agent == Agent(): # if agent is empty, then return an empty prompt
199
- return Prompt(text="")
200
162
  if not hasattr(self, "_agent_instructions_prompt"):
201
163
  applicable_prompts = prompt_lookup(
202
164
  component_type="agent_instructions",
@@ -214,17 +176,12 @@ class PromptConstructor:
214
176
  """
215
177
  >>> from edsl.agents.InvigilatorBase import InvigilatorBase
216
178
  >>> i = InvigilatorBase.example()
217
- >>> i.prompt_constructor.agent_persona_prompt
179
+ >>> i.agent_persona_prompt
218
180
  Prompt(text=\"""You are an agent with the following persona:
219
181
  {'age': 22, 'hair': 'brown', 'height': 5.5}\""")
220
182
 
221
183
  """
222
184
  if not hasattr(self, "_agent_persona_prompt"):
223
- from edsl import Agent
224
-
225
- if self.agent == Agent(): # if agent is empty, then return an empty prompt
226
- return Prompt(text="")
227
-
228
185
  if not hasattr(self.agent, "agent_persona"):
229
186
  applicable_prompts = prompt_lookup(
230
187
  component_type="agent_persona",
@@ -269,29 +226,27 @@ class PromptConstructor:
269
226
  d[new_question].comment = answer
270
227
  return d
271
228
 
272
- @property
273
- def question_image_keys(self):
274
- raw_question_text = self.question.question_text
275
- variables = get_jinja2_variables(raw_question_text)
276
- question_image_keys = []
277
- for var in variables:
278
- if var in self.scenario_image_keys:
279
- question_image_keys.append(var)
280
- return question_image_keys
281
-
282
229
  @property
283
230
  def question_instructions_prompt(self) -> Prompt:
284
231
  """
285
232
  >>> from edsl.agents.InvigilatorBase import InvigilatorBase
286
233
  >>> i = InvigilatorBase.example()
287
- >>> i.prompt_constructor.question_instructions_prompt
234
+ >>> i.question_instructions_prompt
288
235
  Prompt(text=\"""...
289
236
  ...
290
237
  """
291
238
  if not hasattr(self, "_question_instructions_prompt"):
292
239
  question_prompt = self.question.get_instructions(model=self.model.model)
293
240
 
294
- # Are any of the scenario values ImageInfo
241
+ # TODO: Try to populate the answers in the question object if they are available
242
+ # d = self.survey.question_names_to_questions()
243
+ # for question, answer in self.current_answers.items():
244
+ # if question in d:
245
+ # d[question].answer = answer
246
+ # else:
247
+ # # adds a comment to the question
248
+ # if (new_question := question.split("_comment")[0]) in d:
249
+ # d[new_question].comment = answer
295
250
 
296
251
  question_data = self.question.data.copy()
297
252
 
@@ -299,6 +254,8 @@ class PromptConstructor:
299
254
  # This is used when the user is using the question_options as a variable from a sceario
300
255
  # if "question_options" in question_data:
301
256
  if isinstance(self.question.data.get("question_options", None), str):
257
+ from jinja2 import Environment, meta
258
+
302
259
  env = Environment()
303
260
  parsed_content = env.parse(self.question.data["question_options"])
304
261
  question_option_key = list(
@@ -312,13 +269,8 @@ class PromptConstructor:
312
269
  self.question.question_options = question_options
313
270
 
314
271
  replacement_dict = (
315
- {key: "<see image>" for key in self.scenario_image_keys}
316
- | question_data
317
- | {
318
- k: v
319
- for k, v in self.scenario.items()
320
- if k not in self.scenario_image_keys
321
- } # don't include images in the replacement dict
272
+ question_data
273
+ | self.scenario
322
274
  | self.prior_answers_dict()
323
275
  | {"agent": self.agent}
324
276
  | {
@@ -328,10 +280,9 @@ class PromptConstructor:
328
280
  ),
329
281
  }
330
282
  )
331
-
283
+ # breakpoint()
332
284
  rendered_instructions = question_prompt.render(replacement_dict)
333
-
334
- # is there anything left to render?
285
+ # breakpoint()
335
286
  undefined_template_variables = (
336
287
  rendered_instructions.undefined_template_variables({})
337
288
  )
@@ -349,9 +300,7 @@ class PromptConstructor:
349
300
  f"Question instructions still has variables: {undefined_template_variables}."
350
301
  )
351
302
 
352
- ####################################
353
- # Check if question has instructions - these are instructions in a Survey that can apply to multiple follow-on questions
354
- ####################################
303
+ # Check if question has an instructions
355
304
  relevant_instructions = self.survey.relevant_instructions(
356
305
  self.question.question_name
357
306
  )
@@ -380,23 +329,6 @@ class PromptConstructor:
380
329
  self._prior_question_memory_prompt = memory_prompt
381
330
  return self._prior_question_memory_prompt
382
331
 
383
- def create_memory_prompt(self, question_name: str) -> Prompt:
384
- """Create a memory for the agent.
385
-
386
- The returns a memory prompt for the agent.
387
-
388
- >>> from edsl.agents.InvigilatorBase import InvigilatorBase
389
- >>> i = InvigilatorBase.example()
390
- >>> i.current_answers = {"q0": "Prior answer"}
391
- >>> i.memory_plan.add_single_memory("q1", "q0")
392
- >>> p = i.prompt_constructor.create_memory_prompt("q1")
393
- >>> p.text.strip().replace("\\n", " ").replace("\\t", " ")
394
- 'Before the question you are now answering, you already answered the following question(s): Question: Do you like school? Answer: Prior answer'
395
- """
396
- return self.memory_plan.get_memory_prompt_fragment(
397
- question_name, self.current_answers
398
- )
399
-
400
332
  def construct_system_prompt(self) -> Prompt:
401
333
  """Construct the system prompt for the LLM call."""
402
334
  import warnings
@@ -431,13 +363,9 @@ class PromptConstructor:
431
363
  question_instructions=self.question_instructions_prompt,
432
364
  prior_question_memory=self.prior_question_memory_prompt,
433
365
  )
434
- if len(self.question_image_keys) > 1:
435
- raise ValueError("We can only handle one image per question.")
436
- elif len(self.question_image_keys) == 1:
437
- prompts["encoded_image"] = self.scenario[
438
- self.question_image_keys[0]
439
- ].encoded_image
440
366
 
367
+ if hasattr(self.scenario, "has_image") and self.scenario.has_image:
368
+ prompts["encoded_image"] = self.scenario["encoded_image"]
441
369
  return prompts
442
370
 
443
371
  def _get_scenario_with_image(self) -> Scenario:
edsl/config.py CHANGED
@@ -1,65 +1,73 @@
1
1
  """This module provides a Config class that loads environment variables from a .env file and sets them as class attributes."""
2
2
 
3
3
  import os
4
- from dotenv import load_dotenv, find_dotenv
5
4
  from edsl.exceptions import (
6
5
  InvalidEnvironmentVariableError,
7
6
  MissingEnvironmentVariableError,
8
7
  )
8
+ from dotenv import load_dotenv, find_dotenv
9
9
 
10
10
  # valid values for EDSL_RUN_MODE
11
- EDSL_RUN_MODES = [
12
- "development",
13
- "development-testrun",
14
- "production",
15
- ]
11
+ EDSL_RUN_MODES = ["development", "development-testrun", "production"]
16
12
 
17
13
  # `default` is used to impute values only in "production" mode
18
14
  # `info` gives a brief description of the env var
19
15
  CONFIG_MAP = {
20
16
  "EDSL_RUN_MODE": {
21
17
  "default": "production",
22
- "info": "This config var determines the run mode of the application.",
18
+ "info": "This env var determines the run mode of the application.",
19
+ },
20
+ "EDSL_DATABASE_PATH": {
21
+ "default": f"sqlite:///{os.path.join(os.getcwd(), '.edsl_cache/data.db')}",
22
+ "info": "This env var determines the path to the cache file.",
23
+ },
24
+ "EDSL_LOGGING_PATH": {
25
+ "default": f"{os.path.join(os.getcwd(), 'interview.log')}",
26
+ "info": "This env var determines the path to the log file.",
23
27
  },
24
28
  "EDSL_API_TIMEOUT": {
25
29
  "default": "60",
26
- "info": "This config var determines the maximum number of seconds to wait for an API call to return.",
30
+ "info": "This env var determines the maximum number of seconds to wait for an API call to return.",
27
31
  },
28
32
  "EDSL_BACKOFF_START_SEC": {
29
33
  "default": "1",
30
- "info": "This config var determines the number of seconds to wait before retrying a failed API call.",
34
+ "info": "This env var determines the number of seconds to wait before retrying a failed API call.",
31
35
  },
32
- "EDSL_BACKOFF_MAX_SEC": {
36
+ "EDSL_MAX_BACKOFF_SEC": {
33
37
  "default": "60",
34
- "info": "This config var determines the maximum number of seconds to wait before retrying a failed API call.",
38
+ "info": "This env var determines the maximum number of seconds to wait before retrying a failed API call.",
35
39
  },
36
- "EDSL_DATABASE_PATH": {
37
- "default": f"sqlite:///{os.path.join(os.getcwd(), '.edsl_cache/data.db')}",
38
- "info": "This config var determines the path to the cache file.",
40
+ "EDSL_MAX_ATTEMPTS": {
41
+ "default": "5",
42
+ "info": "This env var determines the maximum number of times to retry a failed API call.",
39
43
  },
40
44
  "EDSL_DEFAULT_MODEL": {
41
45
  "default": "gpt-4o",
42
- "info": "This config var holds the default model that will be used if a model is not explicitly passed.",
46
+ "info": "This env var holds the default model name.",
43
47
  },
44
- "EDSL_FETCH_TOKEN_PRICES": {
45
- "default": "True",
46
- "info": "This config var determines whether to fetch prices for tokens used in remote inference",
47
- },
48
- "EDSL_MAX_ATTEMPTS": {
49
- "default": "5",
50
- "info": "This config var determines the maximum number of times to retry a failed API call.",
48
+ "EDSL_SERVICE_TPM_BASELINE": {
49
+ "default": "2000000",
50
+ "info": "This env var holds the maximum number of tokens per minute for all models. Model-specific values such as EDSL_SERVICE_TPM_OPENAI will override this.",
51
51
  },
52
52
  "EDSL_SERVICE_RPM_BASELINE": {
53
53
  "default": "100",
54
- "info": "This config var holds the maximum number of requests per minute. Model-specific values provided in env vars such as EDSL_SERVICE_RPM_OPENAI will override this. value for the corresponding model",
54
+ "info": "This env var holds the maximum number of requests per minute for OpenAI. Model-specific values such as EDSL_SERVICE_RPM_OPENAI will override this.",
55
55
  },
56
- "EDSL_SERVICE_TPM_BASELINE": {
56
+ "EDSL_SERVICE_TPM_OPENAI": {
57
57
  "default": "2000000",
58
- "info": "This config var holds the maximum number of tokens per minute for all models. Model-specific values provided in env vars such as EDSL_SERVICE_TPM_OPENAI will override this value for the corresponding model.",
58
+ "info": "This env var holds the maximum number of tokens per minute for OpenAI.",
59
+ },
60
+ "EDSL_SERVICE_RPM_OPENAI": {
61
+ "default": "100",
62
+ "info": "This env var holds the maximum number of requests per minute for OpenAI.",
63
+ },
64
+ "EDSL_FETCH_TOKEN_PRICES": {
65
+ "default": "True",
66
+ "info": "Whether to fetch the prices for tokens",
59
67
  },
60
68
  "EXPECTED_PARROT_URL": {
61
69
  "default": "https://www.expectedparrot.com",
62
- "info": "This config var holds the URL of the Expected Parrot API.",
70
+ "info": "This env var holds the URL of the Expected Parrot API.",
63
71
  },
64
72
  }
65
73
 
edsl/coop/coop.py CHANGED
@@ -59,16 +59,8 @@ class Coop:
59
59
  Send a request to the server and return the response.
60
60
  """
61
61
  url = f"{self.url}/{uri}"
62
- method = method.upper()
63
- if payload is None:
64
- timeout = 20
65
- elif (
66
- method.upper() == "POST"
67
- and "json_string" in payload
68
- and payload.get("json_string") is not None
69
- ):
70
- timeout = max(20, (len(payload.get("json_string", "")) // (1024 * 1024)))
71
62
  try:
63
+ method = method.upper()
72
64
  if method in ["GET", "DELETE"]:
73
65
  response = requests.request(
74
66
  method, url, params=params, headers=self.headers, timeout=timeout
@@ -85,7 +77,7 @@ class Coop:
85
77
  else:
86
78
  raise Exception(f"Invalid {method=}.")
87
79
  except requests.ConnectionError:
88
- raise requests.ConnectionError(f"Could not connect to the server at {url}.")
80
+ raise requests.ConnectionError("Could not connect to the server.")
89
81
 
90
82
  return response
91
83
 
@@ -95,7 +87,6 @@ class Coop:
95
87
  """
96
88
  if response.status_code >= 400:
97
89
  message = response.json().get("detail")
98
- # print(response.text)
99
90
  if "Authorization" in message:
100
91
  print(message)
101
92
  message = "Please provide an Expected Parrot API key."
@@ -1,6 +1,4 @@
1
1
  from typing import NamedTuple, Dict, List, Optional, Any
2
- from dataclasses import dataclass, fields
3
- import reprlib
4
2
 
5
3
 
6
4
  class ModelInputs(NamedTuple):
@@ -47,27 +45,76 @@ class EDSLResultObjectInput(NamedTuple):
47
45
  cost: Optional[float] = None
48
46
 
49
47
 
50
- @dataclass
51
- class ImageInfo:
52
- file_path: str
53
- file_name: str
54
- image_format: str
55
- file_size: int
56
- encoded_image: str
57
-
58
- def __repr__(self):
59
- reprlib_instance = reprlib.Repr()
60
- reprlib_instance.maxstring = 30 # Limit the string length for the encoded image
61
-
62
- # Get all fields except encoded_image
63
- field_reprs = [
64
- f"{f.name}={getattr(self, f.name)!r}"
65
- for f in fields(self)
66
- if f.name != "encoded_image"
67
- ]
68
-
69
- # Add the reprlib-restricted encoded_image field
70
- field_reprs.append(f"encoded_image={reprlib_instance.repr(self.encoded_image)}")
71
-
72
- # Join everything to create the repr
73
- return f"{self.__class__.__name__}({', '.join(field_reprs)})"
48
+ # from collections import UserDict
49
+
50
+
51
+ # class AgentResponseDict(UserDict):
52
+ # """A dictionary to store the response of the agent to a question."""
53
+
54
+ # def __init__(
55
+ # self,
56
+ # *,
57
+ # question_name,
58
+ # answer,
59
+ # prompts,
60
+ # generated_tokens: str,
61
+ # usage=None,
62
+ # comment=None,
63
+ # cached_response=None,
64
+ # raw_model_response=None,
65
+ # simple_model_raw_response=None,
66
+ # cache_used=None,
67
+ # cache_key=None,
68
+ # ):
69
+ # """Initialize the AgentResponseDict object."""
70
+ # usage = usage or {"prompt_tokens": 0, "completion_tokens": 0}
71
+ # if generated_tokens is None:
72
+ # raise ValueError("generated_tokens must be provided")
73
+ # self.data = {
74
+ # "answer": answer,
75
+ # "comment": comment,
76
+ # "question_name": question_name,
77
+ # "prompts": prompts,
78
+ # "usage": usage,
79
+ # "cached_response": cached_response,
80
+ # "raw_model_response": raw_model_response,
81
+ # "simple_model_raw_response": simple_model_raw_response,
82
+ # "cache_used": cache_used,
83
+ # "cache_key": cache_key,
84
+ # "generated_tokens": generated_tokens,
85
+ # }
86
+
87
+ # @property
88
+ # def data(self):
89
+ # return self._data
90
+
91
+ # @data.setter
92
+ # def data(self, value):
93
+ # self._data = value
94
+
95
+ # def __getitem__(self, key):
96
+ # return self.data.get(key, None)
97
+
98
+ # def __setitem__(self, key, value):
99
+ # self.data[key] = value
100
+
101
+ # def __delitem__(self, key):
102
+ # del self.data[key]
103
+
104
+ # def __iter__(self):
105
+ # return iter(self.data)
106
+
107
+ # def __len__(self):
108
+ # return len(self.data)
109
+
110
+ # def keys(self):
111
+ # return self.data.keys()
112
+
113
+ # def values(self):
114
+ # return self.data.values()
115
+
116
+ # def items(self):
117
+ # return self.data.items()
118
+
119
+ # def is_this_same_model(self):
120
+ # return True
edsl/enums.py CHANGED
@@ -63,7 +63,6 @@ class InferenceServiceType(EnumWithChecks):
63
63
  AZURE = "azure"
64
64
  OLLAMA = "ollama"
65
65
  MISTRAL = "mistral"
66
- TOGETHER = "together"
67
66
 
68
67
 
69
68
  service_to_api_keyname = {
@@ -77,7 +76,6 @@ service_to_api_keyname = {
77
76
  InferenceServiceType.GROQ.value: "GROQ_API_KEY",
78
77
  InferenceServiceType.BEDROCK.value: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"],
79
78
  InferenceServiceType.MISTRAL.value: "MISTRAL_API_KEY",
80
- InferenceServiceType.TOGETHER.value: "TOGETHER_API_KEY",
81
79
  }
82
80
 
83
81