freeplay 0.3.23__py3-none-any.whl → 0.3.24__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.
freeplay/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from .freeplay import Freeplay
2
2
  from .resources.prompts import PromptInfo
3
- from .resources.recordings import CallInfo, ResponseInfo, RecordPayload, TestRunInfo, UsageTokens
3
+ from .model import TestRunInfo
4
+ from .resources.recordings import CallInfo, ResponseInfo, RecordPayload, UsageTokens
4
5
  from .resources.sessions import SessionInfo, TraceInfo
5
6
  from .support import CustomMetadata
6
7
 
freeplay/model.py CHANGED
@@ -13,6 +13,12 @@ class TestRun:
13
13
  inputs: List[TestRunInput]
14
14
 
15
15
 
16
+ @dataclass
17
+ class TestRunInfo:
18
+ test_run_id: str
19
+ test_case_id: str
20
+
21
+
16
22
  class OpenAIFunctionCall(TypedDict):
17
23
  name: str
18
24
  arguments: str
@@ -9,11 +9,12 @@ from requests import HTTPError
9
9
  from freeplay import api_support
10
10
  from freeplay.errors import FreeplayClientError, FreeplayError
11
11
  from freeplay.llm_parameters import LLMParameters
12
- from freeplay.model import InputVariables, OpenAIFunctionCall
12
+ from freeplay.model import InputVariables, OpenAIFunctionCall, TestRunInfo
13
13
  from freeplay.resources.prompts import PromptInfo, MediaInputMap, MediaInput, MediaInputUrl
14
14
  from freeplay.resources.sessions import SessionInfo, TraceInfo
15
15
  from freeplay.support import CallSupport
16
16
 
17
+
17
18
  logger = logging.getLogger(__name__)
18
19
 
19
20
 
@@ -65,11 +66,6 @@ class ResponseInfo:
65
66
  response_tokens: Optional[int] = None
66
67
 
67
68
 
68
- @dataclass
69
- class TestRunInfo:
70
- test_run_id: str
71
- test_case_id: str
72
-
73
69
 
74
70
  @dataclass
75
71
  class RecordPayload:
@@ -3,6 +3,7 @@ from dataclasses import dataclass
3
3
  from typing import Optional, Dict, Union
4
4
 
5
5
  from freeplay.errors import FreeplayClientError
6
+ from freeplay.model import TestRunInfo
6
7
  from freeplay.support import CallSupport, CustomMetadata
7
8
 
8
9
 
@@ -40,7 +41,8 @@ class TraceInfo:
40
41
  self,
41
42
  project_id: str,
42
43
  output: str,
43
- eval_results: Optional[Dict[str, Union[bool, float]]] = None
44
+ eval_results: Optional[Dict[str, Union[bool, float]]] = None,
45
+ test_run_info: Optional[TestRunInfo] = None
44
46
  ) -> None:
45
47
  if self.input is None:
46
48
  raise FreeplayClientError("Input must be set before recording output")
@@ -52,7 +54,8 @@ class TraceInfo:
52
54
  output,
53
55
  agent_name=self.agent_name,
54
56
  custom_metadata=self.custom_metadata,
55
- eval_results=eval_results
57
+ eval_results=eval_results,
58
+ test_run_info=test_run_info
56
59
  )
57
60
 
58
61
 
@@ -1,39 +1,75 @@
1
1
  from dataclasses import dataclass
2
- from typing import List, Optional, Dict
2
+ from typing import List, Optional, Dict, Any
3
+ import warnings
3
4
 
4
- from freeplay.model import InputVariables
5
- from freeplay.resources.recordings import TestRunInfo
5
+ from freeplay.model import InputVariables, TestRunInfo
6
6
  from freeplay.support import CallSupport, SummaryStatistics
7
7
 
8
-
9
8
  @dataclass
10
- class TestCase:
9
+ class CompletionTestCase:
11
10
  def __init__(
12
11
  self,
13
12
  test_case_id: str,
14
13
  variables: InputVariables,
15
14
  output: Optional[str],
16
- history: Optional[List[Dict[str, str]]]
15
+ history: Optional[List[Dict[str, str]]],
16
+ custom_metadata: Optional[Dict[str, str]]
17
17
  ):
18
18
  self.id = test_case_id
19
19
  self.variables = variables
20
20
  self.output = output
21
21
  self.history = history
22
+ self.custom_metadata = custom_metadata
22
23
 
24
+ class TestCase(CompletionTestCase):
25
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
26
+ warnings.warn(
27
+ "'TestCase' is deprecated; use 'CompletionTestCase' instead.",
28
+ DeprecationWarning,
29
+ stacklevel=2,
30
+ )
31
+ super().__init__(*args, **kwargs)
23
32
 
33
+ class TraceTestCase:
34
+ def __init__(
35
+ self,
36
+ test_case_id: str,
37
+ input: str,
38
+ output: Optional[str],
39
+ custom_metadata: Optional[Dict[str, str]]
40
+ ):
41
+ self.id = test_case_id
42
+ self.input = input
43
+ self.output = output
44
+ self.custom_metadata = custom_metadata
24
45
  @dataclass
25
46
  class TestRun:
26
47
  def __init__(
27
48
  self,
28
49
  test_run_id: str,
29
- test_cases: List[TestCase]
50
+ test_cases: List[CompletionTestCase] = [],
51
+ trace_test_cases: List[TraceTestCase] = []
30
52
  ):
31
53
  self.test_run_id = test_run_id
32
54
  self.test_cases = test_cases
55
+ self.trace_test_cases = trace_test_cases
33
56
 
34
- def get_test_cases(self) -> List[TestCase]:
57
+ def __must_not_be_both_trace_and_completion(self) -> None:
58
+ if self.test_cases and len(self.test_cases) > 0 and self.trace_test_cases and len(self.trace_test_cases) > 0:
59
+ raise ValueError("Test case and trace test case cannot both be present")
60
+
61
+ def get_test_cases(self) -> List[CompletionTestCase]:
62
+ self.__must_not_be_both_trace_and_completion()
63
+ if len(self.trace_test_cases) > 0:
64
+ raise ValueError("Completion test cases are not present. Please use get_trace_test_cases() instead.")
35
65
  return self.test_cases
36
66
 
67
+ def get_trace_test_cases(self) -> List[TraceTestCase]:
68
+ self.__must_not_be_both_trace_and_completion()
69
+ if len(self.test_cases) > 0:
70
+ raise ValueError("Trace test cases are not present. Please use get_test_cases() instead.")
71
+ return self.trace_test_cases
72
+
37
73
  def get_test_run_info(self, test_case_id: str) -> TestRunInfo:
38
74
  return TestRunInfo(self.test_run_id, test_case_id)
39
75
 
@@ -69,14 +105,22 @@ class TestRuns:
69
105
  test_run = self.call_support.create_test_run(
70
106
  project_id, testlist, include_outputs, name, description, flavor_name)
71
107
  test_cases = [
72
- TestCase(test_case_id=test_case.id,
108
+ CompletionTestCase(test_case_id=test_case.id,
73
109
  variables=test_case.variables,
74
110
  output=test_case.output,
75
- history=test_case.history)
111
+ history=test_case.history,
112
+ custom_metadata=test_case.custom_metadata)
76
113
  for test_case in test_run.test_cases
77
114
  ]
115
+ trace_test_cases = [
116
+ TraceTestCase(test_case_id=test_case.id,
117
+ input=test_case.input,
118
+ output=test_case.output,
119
+ custom_metadata=test_case.custom_metadata)
120
+ for test_case in test_run.trace_test_cases
121
+ ]
78
122
 
79
- return TestRun(test_run.test_run_id, test_cases)
123
+ return TestRun(test_run.test_run_id, test_cases, trace_test_cases)
80
124
 
81
125
  def get(self, project_id: str, test_run_id: str) -> TestRunResults:
82
126
  test_run_results = self.call_support.get_test_run_results(project_id, test_run_id)
freeplay/support.py CHANGED
@@ -1,11 +1,11 @@
1
- from dataclasses import dataclass, field
1
+ from dataclasses import dataclass, field, asdict
2
2
  from json import JSONEncoder
3
3
  from typing import Optional, Dict, Any, List, Union, Literal
4
4
 
5
5
  from freeplay import api_support
6
6
  from freeplay.api_support import try_decode
7
7
  from freeplay.errors import freeplay_response_error, FreeplayServerError
8
- from freeplay.model import InputVariables, FeedbackValue, NormalizedMessage
8
+ from freeplay.model import InputVariables, FeedbackValue, NormalizedMessage, TestRunInfo
9
9
 
10
10
  CustomMetadata = Optional[Dict[str, Union[str, int, float, bool]]]
11
11
 
@@ -83,22 +83,38 @@ class PromptTemplateEncoder(JSONEncoder):
83
83
 
84
84
  class TestCaseTestRunResponse:
85
85
  def __init__(self, test_case: Dict[str, Any]):
86
- self.variables: InputVariables = test_case['variables']
87
86
  self.id: str = test_case['test_case_id']
87
+ self.variables: InputVariables = test_case['variables']
88
88
  self.output: Optional[str] = test_case.get('output')
89
89
  self.history: Optional[List[Dict[str, Any]]] = test_case.get('history')
90
+ self.custom_metadata: Optional[Dict[str, str]] = test_case.get('custom_metadata')
90
91
 
92
+ class TraceTestCaseTestRunResponse:
93
+ def __init__(self, test_case: Dict[str, Any]):
94
+ self.id: str = test_case['test_case_id']
95
+ self.input: str = test_case['input']
96
+ self.output: Optional[str] = test_case.get('output')
97
+ self.custom_metadata: Optional[Dict[str, str]] = test_case.get('custom_metadata')
91
98
 
92
99
  class TestRunResponse:
93
100
  def __init__(
94
101
  self,
95
102
  test_run_id: str,
96
- test_cases: List[Dict[str, Any]]
103
+ test_cases: Optional[List[Dict[str, Any]]],
104
+ trace_test_cases: Optional[List[Dict[str, Any]]]
97
105
  ):
106
+ if test_cases and trace_test_cases:
107
+ raise ValueError("Test cases and trace test cases cannot both be present.")
108
+
98
109
  self.test_cases = [
99
110
  TestCaseTestRunResponse(test_case)
100
- for test_case in test_cases
111
+ for test_case in (test_cases or []) if test_case is not None
112
+ ]
113
+ self.trace_test_cases = [
114
+ TraceTestCaseTestRunResponse(test_case)
115
+ for test_case in (trace_test_cases or []) if test_case is not None
101
116
  ]
117
+
102
118
  self.test_run_id = test_run_id
103
119
 
104
120
 
@@ -267,7 +283,7 @@ class CallSupport:
267
283
 
268
284
  json_dom = response.json()
269
285
 
270
- return TestRunResponse(json_dom['test_run_id'], json_dom['test_cases'])
286
+ return TestRunResponse(json_dom['test_run_id'], json_dom['test_cases'], json_dom['trace_test_cases'])
271
287
 
272
288
  def get_test_run_results(
273
289
  self,
@@ -299,18 +315,21 @@ class CallSupport:
299
315
  output: str,
300
316
  agent_name: Optional[str] = None,
301
317
  custom_metadata: CustomMetadata = None,
302
- eval_results: Optional[Dict[str, Union[bool, float]]] = None
318
+ eval_results: Optional[Dict[str, Union[bool, float]]] = None,
319
+ test_run_info: Optional[TestRunInfo] = None
303
320
  ) -> None:
321
+ payload = {
322
+ 'agent_name': agent_name,
323
+ 'input': input,
324
+ 'output': output,
325
+ 'custom_metadata': custom_metadata,
326
+ 'eval_results': eval_results,
327
+ 'test_run_info': asdict(test_run_info) if test_run_info else None
328
+ }
304
329
  response = api_support.post_raw(
305
330
  self.freeplay_api_key,
306
331
  f'{self.api_base}/v2/projects/{project_id}/sessions/{session_id}/traces/id/{trace_id}',
307
- {
308
- 'agent_name': agent_name,
309
- 'input': input,
310
- 'output': output,
311
- 'custom_metadata': custom_metadata,
312
- 'eval_results': eval_results,
313
- }
332
+ payload
314
333
  )
315
334
  if response.status_code != 201:
316
335
  raise freeplay_response_error('Error while recording trace.', response)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: freeplay
3
- Version: 0.3.23
3
+ Version: 0.3.24
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: FreePlay Engineering
@@ -1,23 +1,23 @@
1
- freeplay/__init__.py,sha256=tzEFgRyriPBWPo04jTgR6MxzXUqIHBlUJZvuBj5kFiE,464
1
+ freeplay/__init__.py,sha256=ljXF0vHC3oGgk-vLyJFawr7MZKOj_ExYJJsVdrpqZoM,482
2
2
  freeplay/api_support.py,sha256=Kn2x3g6yloHQl3NwFRjbZE9BnIh7d1sgwGwC0mHuvw4,2483
3
3
  freeplay/errors.py,sha256=vwotUBldxDzREZOmLUeoiDoZjcvDwgH1AMwKBLhLooE,807
4
4
  freeplay/freeplay.py,sha256=J04-erDD6rI2SAje_Nsf3x5Qx-Z6p8gQvGrMRHFWoD4,1602
5
5
  freeplay/freeplay_cli.py,sha256=lmdsYwzdpWmUKHz_ieCzB-e6j1EnDHlVw3XIEyP_NEk,3460
6
6
  freeplay/llm_parameters.py,sha256=bQbfuC8EICF0XMZQa5pwI3FkQqxmCUVqHO3gYHy3Tg8,898
7
- freeplay/model.py,sha256=o0de_RZ2WTJ4m5OJw1ZVfC2xG6zBq_XShBrRt1laEjc,1405
7
+ freeplay/model.py,sha256=GI3qPRouwdrBFOPBrcQFt5O0chtlSNvl8jAstePuYlA,1480
8
8
  freeplay/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  freeplay/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  freeplay/resources/adapters.py,sha256=6ZAPpoLeOkUkV1s9VNQNsYrnupV0-sy11zFfKfctM1Y,9296
11
11
  freeplay/resources/customer_feedback.py,sha256=bw8MfEOKbGgn4FOyvcADrcs9GhcpNXNTgxKjBjIzywE,899
12
12
  freeplay/resources/prompts.py,sha256=mnL1VscMGM7D4ulGf3CBGQKdsSj8I5Wf_6nJEYa7mZI,23353
13
- freeplay/resources/recordings.py,sha256=z2ARII1jCnmNh1GU3hGnXZUz5IF_KhyayQum71k-h9c,9213
14
- freeplay/resources/sessions.py,sha256=J5A3CjiV2MFqQyxN3TWTvJaa9jmMza58mRFRq2v9iAk,3746
13
+ freeplay/resources/recordings.py,sha256=V8KAPWnYAQ2-gqwyAJveD8a_AaBPYT32N_xbPU4S27M,9153
14
+ freeplay/resources/sessions.py,sha256=dZtd9nq2nH8pmXxQOJitBnN5Jl3kjggDItDcjC69TYo,3883
15
15
  freeplay/resources/test_cases.py,sha256=nXL_976RwSJDT6OWDM4GEzbcOzcGkJ9ulvb0XOzCRDM,2240
16
- freeplay/resources/test_runs.py,sha256=Tp2N-odInT5XEEWrEsVhdgfnsclOE8n92_C8gTwO2MI,2623
17
- freeplay/support.py,sha256=kQMItnMGZT5TOdPQsSiKOlBbBqO4AyR91vito6wt4JM,12275
16
+ freeplay/resources/test_runs.py,sha256=u7bBfJ3Ro5DJZQdjCAXj4Xj-3fYmtQIGhy8vJeluJvQ,4668
17
+ freeplay/support.py,sha256=AcaG6vkmI9r6_eNFoX29eTh4MRjdb4To5wIEm78v7IE,13299
18
18
  freeplay/utils.py,sha256=Xvt4mNLXLL7E6MI2hTuDLV5cl5Y83DgdjCZSyDGMjR0,3187
19
- freeplay-0.3.23.dist-info/LICENSE,sha256=_jzIw45hB1XHGxiQ8leZ0GH_X7bR_a8qgxaqnHbCUOo,1064
20
- freeplay-0.3.23.dist-info/METADATA,sha256=IW54IuEE9o5_huw03dbWjekNpyWXyRofb_x9AEFUZf0,1661
21
- freeplay-0.3.23.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
22
- freeplay-0.3.23.dist-info/entry_points.txt,sha256=32s3rf2UUCqiJT4jnClEXZhdXlvl30uwpcxz-Gsy4UU,54
23
- freeplay-0.3.23.dist-info/RECORD,,
19
+ freeplay-0.3.24.dist-info/LICENSE,sha256=_jzIw45hB1XHGxiQ8leZ0GH_X7bR_a8qgxaqnHbCUOo,1064
20
+ freeplay-0.3.24.dist-info/METADATA,sha256=o8XujEUGJhQzw3ONbL91BPC38d-JcUfL24sIGLaaHZM,1661
21
+ freeplay-0.3.24.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
22
+ freeplay-0.3.24.dist-info/entry_points.txt,sha256=32s3rf2UUCqiJT4jnClEXZhdXlvl30uwpcxz-Gsy4UU,54
23
+ freeplay-0.3.24.dist-info/RECORD,,