azure-ai-evaluation 1.0.0b3__py3-none-any.whl → 1.0.0b5__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.

Potentially problematic release.


This version of azure-ai-evaluation might be problematic. Click here for more details.

Files changed (93) hide show
  1. azure/ai/evaluation/__init__.py +23 -1
  2. azure/ai/evaluation/{simulator/_helpers → _common}/_experimental.py +20 -9
  3. azure/ai/evaluation/_common/constants.py +9 -2
  4. azure/ai/evaluation/_common/math.py +29 -0
  5. azure/ai/evaluation/_common/rai_service.py +222 -93
  6. azure/ai/evaluation/_common/utils.py +328 -19
  7. azure/ai/evaluation/_constants.py +16 -8
  8. azure/ai/evaluation/_evaluate/{_batch_run_client → _batch_run}/__init__.py +3 -2
  9. azure/ai/evaluation/_evaluate/{_batch_run_client → _batch_run}/code_client.py +33 -17
  10. azure/ai/evaluation/_evaluate/{_batch_run_client/batch_run_context.py → _batch_run/eval_run_context.py} +14 -7
  11. azure/ai/evaluation/_evaluate/{_batch_run_client → _batch_run}/proxy_client.py +22 -4
  12. azure/ai/evaluation/_evaluate/_batch_run/target_run_context.py +35 -0
  13. azure/ai/evaluation/_evaluate/_eval_run.py +47 -14
  14. azure/ai/evaluation/_evaluate/_evaluate.py +370 -188
  15. azure/ai/evaluation/_evaluate/_telemetry/__init__.py +15 -16
  16. azure/ai/evaluation/_evaluate/_utils.py +77 -25
  17. azure/ai/evaluation/_evaluators/_bleu/_bleu.py +1 -1
  18. azure/ai/evaluation/_evaluators/_coherence/_coherence.py +16 -10
  19. azure/ai/evaluation/_evaluators/_coherence/coherence.prompty +76 -34
  20. azure/ai/evaluation/_evaluators/_common/_base_eval.py +76 -46
  21. azure/ai/evaluation/_evaluators/_common/_base_prompty_eval.py +26 -19
  22. azure/ai/evaluation/_evaluators/_common/_base_rai_svc_eval.py +62 -25
  23. azure/ai/evaluation/_evaluators/_content_safety/_content_safety.py +68 -36
  24. azure/ai/evaluation/_evaluators/_content_safety/_content_safety_chat.py +67 -46
  25. azure/ai/evaluation/_evaluators/_content_safety/_hate_unfairness.py +33 -4
  26. azure/ai/evaluation/_evaluators/_content_safety/_self_harm.py +33 -4
  27. azure/ai/evaluation/_evaluators/_content_safety/_sexual.py +33 -4
  28. azure/ai/evaluation/_evaluators/_content_safety/_violence.py +33 -4
  29. azure/ai/evaluation/_evaluators/_eci/_eci.py +7 -5
  30. azure/ai/evaluation/_evaluators/_f1_score/_f1_score.py +14 -6
  31. azure/ai/evaluation/_evaluators/_fluency/_fluency.py +22 -21
  32. azure/ai/evaluation/_evaluators/_fluency/fluency.prompty +66 -36
  33. azure/ai/evaluation/_evaluators/_gleu/_gleu.py +1 -1
  34. azure/ai/evaluation/_evaluators/_groundedness/_groundedness.py +51 -16
  35. azure/ai/evaluation/_evaluators/_groundedness/groundedness_with_query.prompty +113 -0
  36. azure/ai/evaluation/_evaluators/_groundedness/groundedness_without_query.prompty +99 -0
  37. azure/ai/evaluation/_evaluators/_meteor/_meteor.py +3 -7
  38. azure/ai/evaluation/_evaluators/_multimodal/__init__.py +20 -0
  39. azure/ai/evaluation/_evaluators/_multimodal/_content_safety_multimodal.py +130 -0
  40. azure/ai/evaluation/_evaluators/_multimodal/_content_safety_multimodal_base.py +57 -0
  41. azure/ai/evaluation/_evaluators/_multimodal/_hate_unfairness.py +96 -0
  42. azure/ai/evaluation/_evaluators/_multimodal/_protected_material.py +120 -0
  43. azure/ai/evaluation/_evaluators/_multimodal/_self_harm.py +96 -0
  44. azure/ai/evaluation/_evaluators/_multimodal/_sexual.py +96 -0
  45. azure/ai/evaluation/_evaluators/_multimodal/_violence.py +96 -0
  46. azure/ai/evaluation/_evaluators/_protected_material/_protected_material.py +46 -13
  47. azure/ai/evaluation/_evaluators/_qa/_qa.py +11 -6
  48. azure/ai/evaluation/_evaluators/_relevance/_relevance.py +23 -20
  49. azure/ai/evaluation/_evaluators/_relevance/relevance.prompty +78 -42
  50. azure/ai/evaluation/_evaluators/_retrieval/_retrieval.py +126 -80
  51. azure/ai/evaluation/_evaluators/_retrieval/retrieval.prompty +74 -24
  52. azure/ai/evaluation/_evaluators/_rouge/_rouge.py +2 -2
  53. azure/ai/evaluation/_evaluators/_service_groundedness/__init__.py +9 -0
  54. azure/ai/evaluation/_evaluators/_service_groundedness/_service_groundedness.py +150 -0
  55. azure/ai/evaluation/_evaluators/_similarity/_similarity.py +32 -15
  56. azure/ai/evaluation/_evaluators/_xpia/xpia.py +36 -10
  57. azure/ai/evaluation/_exceptions.py +26 -6
  58. azure/ai/evaluation/_http_utils.py +203 -132
  59. azure/ai/evaluation/_model_configurations.py +23 -6
  60. azure/ai/evaluation/_vendor/__init__.py +3 -0
  61. azure/ai/evaluation/_vendor/rouge_score/__init__.py +14 -0
  62. azure/ai/evaluation/_vendor/rouge_score/rouge_scorer.py +328 -0
  63. azure/ai/evaluation/_vendor/rouge_score/scoring.py +63 -0
  64. azure/ai/evaluation/_vendor/rouge_score/tokenize.py +63 -0
  65. azure/ai/evaluation/_vendor/rouge_score/tokenizers.py +53 -0
  66. azure/ai/evaluation/_version.py +1 -1
  67. azure/ai/evaluation/simulator/__init__.py +2 -1
  68. azure/ai/evaluation/simulator/_adversarial_scenario.py +5 -0
  69. azure/ai/evaluation/simulator/_adversarial_simulator.py +88 -60
  70. azure/ai/evaluation/simulator/_conversation/__init__.py +13 -12
  71. azure/ai/evaluation/simulator/_conversation/_conversation.py +4 -4
  72. azure/ai/evaluation/simulator/_data_sources/__init__.py +3 -0
  73. azure/ai/evaluation/simulator/_data_sources/grounding.json +1150 -0
  74. azure/ai/evaluation/simulator/_direct_attack_simulator.py +24 -66
  75. azure/ai/evaluation/simulator/_helpers/__init__.py +1 -2
  76. azure/ai/evaluation/simulator/_helpers/_simulator_data_classes.py +26 -5
  77. azure/ai/evaluation/simulator/_indirect_attack_simulator.py +98 -95
  78. azure/ai/evaluation/simulator/_model_tools/_identity_manager.py +67 -21
  79. azure/ai/evaluation/simulator/_model_tools/_proxy_completion_model.py +28 -11
  80. azure/ai/evaluation/simulator/_model_tools/_template_handler.py +68 -24
  81. azure/ai/evaluation/simulator/_model_tools/models.py +10 -10
  82. azure/ai/evaluation/simulator/_prompty/task_query_response.prompty +4 -9
  83. azure/ai/evaluation/simulator/_prompty/task_simulate.prompty +6 -5
  84. azure/ai/evaluation/simulator/_simulator.py +222 -169
  85. azure/ai/evaluation/simulator/_tracing.py +4 -4
  86. azure/ai/evaluation/simulator/_utils.py +6 -6
  87. {azure_ai_evaluation-1.0.0b3.dist-info → azure_ai_evaluation-1.0.0b5.dist-info}/METADATA +237 -52
  88. azure_ai_evaluation-1.0.0b5.dist-info/NOTICE.txt +70 -0
  89. azure_ai_evaluation-1.0.0b5.dist-info/RECORD +120 -0
  90. {azure_ai_evaluation-1.0.0b3.dist-info → azure_ai_evaluation-1.0.0b5.dist-info}/WHEEL +1 -1
  91. azure/ai/evaluation/_evaluators/_groundedness/groundedness.prompty +0 -49
  92. azure_ai_evaluation-1.0.0b3.dist-info/RECORD +0 -98
  93. {azure_ai_evaluation-1.0.0b3.dist-info → azure_ai_evaluation-1.0.0b5.dist-info}/top_level.txt +0 -0
@@ -6,13 +6,14 @@ import copy
6
6
  import json
7
7
  import time
8
8
  import uuid
9
- from typing import Dict, List
9
+ from typing import Any, Dict, List, Optional, cast
10
10
 
11
11
  from azure.ai.evaluation._http_utils import AsyncHttpPipeline, get_async_http_client
12
12
  from azure.ai.evaluation._user_agent import USER_AGENT
13
13
  from azure.core.exceptions import HttpResponseError
14
14
  from azure.core.pipeline.policies import AsyncRetryPolicy, RetryMode
15
15
 
16
+ from .._model_tools._template_handler import TemplateParameters
16
17
  from .models import OpenAIChatCompletionsModel
17
18
 
18
19
 
@@ -33,7 +34,15 @@ class SimulationRequestDTO:
33
34
  :type template_parameters: Dict
34
35
  """
35
36
 
36
- def __init__(self, url, headers, payload, params, templatekey, template_parameters):
37
+ def __init__(
38
+ self,
39
+ url: str,
40
+ headers: Dict[str, str],
41
+ payload: Dict[str, Any],
42
+ params: Dict[str, str],
43
+ templatekey: str,
44
+ template_parameters: Optional[TemplateParameters],
45
+ ):
37
46
  self.url = url
38
47
  self.headers = headers
39
48
  self.json = json.dumps(payload)
@@ -47,9 +56,12 @@ class SimulationRequestDTO:
47
56
  :return: The DTO as a dictionary.
48
57
  :rtype: Dict
49
58
  """
50
- if self.templateParameters is not None:
51
- self.templateParameters = {str(k): str(v) for k, v in self.templateParameters.items()}
52
- return self.__dict__
59
+ toReturn = self.__dict__.copy()
60
+
61
+ if toReturn["templateParameters"] is not None:
62
+ toReturn["templateParameters"] = {str(k): str(v) for k, v in toReturn["templateParameters"].items()}
63
+
64
+ return toReturn
53
65
 
54
66
  def to_json(self):
55
67
  """Convert the DTO to a JSON string.
@@ -73,12 +85,12 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
73
85
  :keyword kwargs: Additional keyword arguments to pass to the parent class.
74
86
  """
75
87
 
76
- def __init__(self, name: str, template_key: str, template_parameters, *args, **kwargs) -> None:
88
+ def __init__(self, name: str, template_key: str, template_parameters: TemplateParameters, **kwargs) -> None:
77
89
  self.tkey = template_key
78
90
  self.tparam = template_parameters
79
- self.result_url = None
91
+ self.result_url: Optional[str] = None
80
92
 
81
- super().__init__(name=name, *args, **kwargs)
93
+ super().__init__(name=name, **kwargs)
82
94
 
83
95
  def format_request_data(self, messages: List[Dict], **request_params) -> Dict: # type: ignore[override]
84
96
  """Format the request data to query the model with.
@@ -160,7 +172,6 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
160
172
  }
161
173
  # add all additional headers
162
174
  headers.update(self.additional_headers) # type: ignore[arg-type]
163
-
164
175
  params = {}
165
176
  if self.api_version:
166
177
  params["api-version"] = self.api_version
@@ -184,8 +195,8 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
184
195
  message=f"Received unexpected HTTP status: {response.status_code} {response.text()}", response=response
185
196
  )
186
197
 
187
- response = response.json()
188
- self.result_url = response["location"]
198
+ response_data = response.json()
199
+ self.result_url = cast(str, response_data["location"])
189
200
 
190
201
  retry_policy = AsyncRetryPolicy( # set up retry configuration
191
202
  retry_on_status_codes=[202], # on which statuses to retry
@@ -202,6 +213,12 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
202
213
  time.sleep(15)
203
214
 
204
215
  async with get_async_http_client().with_policies(retry_policy=retry_policy) as exp_retry_client:
216
+ token = await self.token_manager.get_token_async()
217
+ proxy_headers = {
218
+ "Authorization": f"Bearer {token}",
219
+ "Content-Type": "application/json",
220
+ "User-Agent": USER_AGENT,
221
+ }
205
222
  response = await exp_retry_client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
206
223
  self.result_url, headers=proxy_headers
207
224
  )
@@ -2,25 +2,66 @@
2
2
  # Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  # ---------------------------------------------------------
4
4
 
5
- from typing import Optional
5
+ from typing import Dict, List, Optional, TypedDict, cast
6
+
7
+ from typing_extensions import NotRequired
6
8
 
7
9
  from azure.ai.evaluation._model_configurations import AzureAIProject
8
10
 
9
11
  from ._rai_client import RAIClient
10
12
 
11
- CONTENT_HARM_TEMPLATES_COLLECTION_KEY = set(
12
- [
13
- "adv_qa",
14
- "adv_conversation",
15
- "adv_summarization",
16
- "adv_search",
17
- "adv_rewrite",
18
- "adv_content_gen_ungrounded",
19
- "adv_content_gen_grounded",
20
- "adv_content_protected_material",
21
- "adv_politics",
22
- ]
23
- )
13
+ CONTENT_HARM_TEMPLATES_COLLECTION_KEY = {
14
+ "adv_qa",
15
+ "adv_conversation",
16
+ "adv_summarization",
17
+ "adv_search",
18
+ "adv_rewrite",
19
+ "adv_content_gen_ungrounded",
20
+ "adv_content_gen_grounded",
21
+ "adv_content_protected_material",
22
+ "adv_politics",
23
+ }
24
+
25
+
26
+ class TemplateParameters(TypedDict):
27
+ """Parameters used in Templates
28
+
29
+ .. note::
30
+
31
+ This type is good enough to type check, but is incorrect. It's meant to represent a dictionary with a known
32
+ `metadata` key (Dict[str, str]), a known `ch_template_placeholder` key (str), and an unknown number of keys
33
+ that map to `str` values.
34
+
35
+ In typescript, this type would be spelled:
36
+
37
+ .. code-block:: typescript
38
+
39
+ type AdversarialTemplateParameters = {
40
+ [key: string]: string
41
+ ch_template_placeholder: string
42
+ metadata: {[index: string]: string} # Doesn't typecheck but gets the point across
43
+ }
44
+
45
+ At time of writing, this isn't possible to express with a TypedDict. TypedDicts must be "closed" in that
46
+ they fully specify all the keys they can contain.
47
+
48
+ `PEP 728 – TypedDict with Typed Extra Items <https://peps.python.org/pep-0728/>` is a proposal to support
49
+ this, but would only be available in Python 3.13 at the earliest.
50
+ """
51
+
52
+ metadata: Dict[str, str]
53
+ conversation_starter: str
54
+ ch_template_placeholder: str
55
+ group_of_people: NotRequired[str]
56
+ category: NotRequired[str]
57
+ target_population: NotRequired[str]
58
+ topic: NotRequired[str]
59
+
60
+
61
+ class _CategorizedParameter(TypedDict):
62
+ parameters: List[TemplateParameters]
63
+ category: str
64
+ parameters_key: str
24
65
 
25
66
 
26
67
  class ContentHarmTemplatesUtils:
@@ -85,13 +126,19 @@ class AdversarialTemplate:
85
126
  :param template_parameters: The template parameters.
86
127
  """
87
128
 
88
- def __init__(self, template_name, text, context_key, template_parameters=None) -> None:
129
+ def __init__(
130
+ self,
131
+ template_name: str,
132
+ text: Optional[str],
133
+ context_key: List,
134
+ template_parameters: Optional[List[TemplateParameters]] = None,
135
+ ) -> None:
89
136
  self.text = text
90
137
  self.context_key = context_key
91
138
  self.template_name = template_name
92
- self.template_parameters = template_parameters
139
+ self.template_parameters = template_parameters or []
93
140
 
94
- def __str__(self):
141
+ def __str__(self) -> str:
95
142
  return "{{ch_template_placeholder}}"
96
143
 
97
144
 
@@ -106,16 +153,13 @@ class AdversarialTemplateHandler:
106
153
  """
107
154
 
108
155
  def __init__(self, azure_ai_project: AzureAIProject, rai_client: RAIClient) -> None:
109
- self.cached_templates_source = {}
110
- # self.template_env = JinjaEnvironment(loader=JinjaFileSystemLoader(searchpath=template_dir))
111
156
  self.azure_ai_project = azure_ai_project
112
- self.categorized_ch_parameters = None
157
+ self.categorized_ch_parameters: Optional[Dict[str, _CategorizedParameter]] = None
113
158
  self.rai_client = rai_client
114
159
 
115
- async def _get_content_harm_template_collections(self, collection_key):
116
-
160
+ async def _get_content_harm_template_collections(self, collection_key: str) -> List[AdversarialTemplate]:
117
161
  if self.categorized_ch_parameters is None:
118
- categorized_parameters = {}
162
+ categorized_parameters: Dict[str, _CategorizedParameter] = {}
119
163
  util = ContentHarmTemplatesUtils
120
164
 
121
165
  parameters = await self.rai_client.get_contentharm_parameters()
@@ -123,7 +167,7 @@ class AdversarialTemplateHandler:
123
167
  for k in parameters.keys():
124
168
  template_key = util.get_template_key(k)
125
169
  categorized_parameters[template_key] = {
126
- "parameters": parameters[k],
170
+ "parameters": cast(List[TemplateParameters], parameters[k]),
127
171
  "category": util.get_template_category(k),
128
172
  "parameters_key": k,
129
173
  }
@@ -49,10 +49,10 @@ class LLMBase(ABC):
49
49
  Base class for all LLM models.
50
50
  """
51
51
 
52
- def __init__(self, endpoint_url: str, name: str = "unknown", additional_headers: Optional[dict] = {}):
52
+ def __init__(self, endpoint_url: str, name: str = "unknown", additional_headers: Optional[Dict[str, str]] = None):
53
53
  self.endpoint_url = endpoint_url
54
54
  self.name = name
55
- self.additional_headers = additional_headers
55
+ self.additional_headers = additional_headers or {}
56
56
  self.logger = logging.getLogger(repr(self))
57
57
 
58
58
  # Metric tracking
@@ -208,7 +208,7 @@ class OpenAICompletionsModel(LLMBase):
208
208
  *,
209
209
  endpoint_url: str,
210
210
  name: str = "OpenAICompletionsModel",
211
- additional_headers: Optional[dict] = {},
211
+ additional_headers: Optional[Dict[str, str]] = None,
212
212
  api_version: Optional[str] = "2023-03-15-preview",
213
213
  token_manager: APITokenManager,
214
214
  azureml_model_deployment: Optional[str] = None,
@@ -220,7 +220,7 @@ class OpenAICompletionsModel(LLMBase):
220
220
  frequency_penalty: Optional[float] = 0,
221
221
  presence_penalty: Optional[float] = 0,
222
222
  stop: Optional[Union[List[str], str]] = None,
223
- image_captions: Dict[str, str] = {},
223
+ image_captions: Optional[Dict[str, str]] = None,
224
224
  images_dir: Optional[str] = None, # Note: unused, kept for class compatibility
225
225
  ):
226
226
  super().__init__(endpoint_url=endpoint_url, name=name, additional_headers=additional_headers)
@@ -234,7 +234,7 @@ class OpenAICompletionsModel(LLMBase):
234
234
  self.n = n
235
235
  self.frequency_penalty = frequency_penalty
236
236
  self.presence_penalty = presence_penalty
237
- self.image_captions = image_captions
237
+ self.image_captions = image_captions or {}
238
238
 
239
239
  # Default stop to end token if not provided
240
240
  if not stop:
@@ -263,7 +263,7 @@ class OpenAICompletionsModel(LLMBase):
263
263
  def get_model_params(self):
264
264
  return {param: getattr(self, param) for param in self.model_param_names if getattr(self, param) is not None}
265
265
 
266
- def format_request_data(self, prompt: str, **request_params) -> Dict[str, str]:
266
+ def format_request_data(self, prompt: Dict[str, str], **request_params) -> Dict[str, str]: # type: ignore[override]
267
267
  """
268
268
  Format the request data for the OpenAI API.
269
269
  """
@@ -328,7 +328,7 @@ class OpenAICompletionsModel(LLMBase):
328
328
  # Format prompts and tag with index
329
329
  request_datas: List[Dict] = []
330
330
  for idx, prompt in enumerate(prompts):
331
- prompt: Dict[str, str] = self.format_request_data(prompt, **request_params)
331
+ prompt = self.format_request_data(prompt, **request_params)
332
332
  prompt[self.prompt_idx_key] = idx # type: ignore[assignment]
333
333
  request_datas.append(prompt)
334
334
 
@@ -447,7 +447,7 @@ class OpenAICompletionsModel(LLMBase):
447
447
 
448
448
  self._log_request(request_data)
449
449
 
450
- token = await self.token_manager.get_token()
450
+ token = self.token_manager.get_token()
451
451
 
452
452
  headers = {
453
453
  "Content-Type": "application/json",
@@ -522,8 +522,8 @@ class OpenAIChatCompletionsModel(OpenAICompletionsModel):
522
522
  formats the prompt for chat completion.
523
523
  """
524
524
 
525
- def __init__(self, name="OpenAIChatCompletionsModel", *args, **kwargs):
526
- super().__init__(name=name, *args, **kwargs)
525
+ def __init__(self, name="OpenAIChatCompletionsModel", **kwargs):
526
+ super().__init__(name=name, **kwargs)
527
527
 
528
528
  def format_request_data(self, messages: List[dict], **request_params): # type: ignore[override]
529
529
  request_data = {"messages": messages, **self.get_model_params()}
@@ -3,11 +3,6 @@ name: TaskSimulatorQueryResponse
3
3
  description: Gets queries and responses from a blob of text
4
4
  model:
5
5
  api: chat
6
- configuration:
7
- type: azure_openai
8
- azure_deployment: ${env:AZURE_DEPLOYMENT}
9
- api_key: ${env:AZURE_OPENAI_API_KEY}
10
- azure_endpoint: ${env:AZURE_OPENAI_ENDPOINT}
11
6
  parameters:
12
7
  temperature: 0.0
13
8
  top_p: 1.0
@@ -41,8 +36,8 @@ On January 24, 1984, former Apple CEO Steve Jobs introduced the first Macintosh.
41
36
  Some years later, research firms IDC and Gartner reported that Apple's market share in the U.S. had increased to about 6%.
42
37
  <|text_end|>
43
38
  Output with 5 QnAs:
44
- [
45
- {
39
+ {
40
+ "qna":[{
46
41
  "q": "When did the former Apple CEO Steve Jobs introduced the first Macintosh?",
47
42
  "r": "January 24, 1984"
48
43
  },
@@ -61,8 +56,8 @@ Output with 5 QnAs:
61
56
  {
62
57
  "q": "What was the percentage increase of Apple's market share in the U.S., as reported by research firms IDC and Gartner?",
63
58
  "r": "6%"
64
- }
65
- ]
59
+ }]
60
+ }
66
61
  Text:
67
62
  <|text_start|>
68
63
  {{ text }}
@@ -3,10 +3,6 @@ name: TaskSimulatorWithPersona
3
3
  description: Simulates a user to complete a conversation
4
4
  model:
5
5
  api: chat
6
- configuration:
7
- type: azure_openai
8
- azure_deployment: ${env:AZURE_DEPLOYMENT}
9
- azure_endpoint: ${env:AZURE_OPENAI_ENDPOINT}
10
6
  parameters:
11
7
  temperature: 0.0
12
8
  top_p: 1.0
@@ -20,6 +16,9 @@ inputs:
20
16
  type: string
21
17
  conversation_history:
22
18
  type: dict
19
+ action:
20
+ type: string
21
+ default: continue the converasation and make sure the task is completed by asking relevant questions
23
22
 
24
23
  ---
25
24
  system:
@@ -29,8 +28,10 @@ Output must be in JSON format
29
28
  Here's a sample output:
30
29
  {
31
30
  "content": "Here is my follow-up question.",
32
- "user": "user"
31
+ "role": "user"
33
32
  }
34
33
 
35
34
  Output with a json object that continues the conversation, given the conversation history:
36
35
  {{ conversation_history }}
36
+
37
+ {{ action }}