ums.utils.types

This represents the basic types used to interact with the management. The types are implemented using pydantic. It provides validation, allow JSON serialization and works well with FastAPI which is used internally for the http request between the agents and the management.

Example

        ex = AgentMessage(
                id="ex1",
                riddle={
                        "context":"Example 1",
                        "question":"Get the name of the person."
                },
                data=[
                        RiddleData(
                                type=RiddleDataType.TEXT,
                                file_plain="./cv.txt"
                        )
                ]
        )
        ex.status.extract.required = False
        {
                "id": "ex1",
                "sub_ids": [],
                "riddle": {
                        "context": "Example 1",
                        "question": "Get the name of the person.",
                        "solutions_before": []
                },
                "solution": null,
                "data": [
                        {
                                "type": "text",
                                "file_plain": "/ums-agenten/share/cv.txt",
                                "file_extracted": null
                        }
                ],
                "status": {
                        "extract": {
                                "required": false,
                                "finished": false
                        },
                        "solve": {
                                "required": true,
                                "finished": false
                        },
                        "validate": {
                                "required": true,
                                "finished": false
                        },
                        "trial": 0,
                        "solved": false
                }
        }
        ex.solution = RiddleSolution(
                solution="Otto",
                explanation="Written in line 6 after 'Name:'"
        )
        {
                ...
                "solution": {
                        "solution": "Otto",
                        "explanation": "Written in line 6 after 'Name:'",
                        "used_data": [],
                        "accepted": false,
                        "review": null
                },
                ...
        }
  1# Agenten Plattform
  2#
  3# (c) 2024 Magnus Bender
  4# 	Institute of Humanities-Centered Artificial Intelligence (CHAI)
  5# 	Universitaet Hamburg
  6# 	https://www.chai.uni-hamburg.de/~bender
  7#  
  8# source code released under the terms of GNU Public License Version 3
  9# https://www.gnu.org/licenses/gpl-3.0.txt
 10
 11"""
 12	This represents the basic types used to interact with the management.
 13	The types are implemented using [pydantic](https://docs.pydantic.dev/).
 14	It provides validation, allow JSON serialization and works well with [FastAPI](https://fastapi.tiangolo.com/) which is used internally for the http request between the agents and the management.
 15
 16	### Example
 17
 18	```python
 19		ex = AgentMessage(
 20			id="ex1",
 21			riddle={
 22				"context":"Example 1",
 23				"question":"Get the name of the person."
 24			},
 25			data=[
 26				RiddleData(
 27					type=RiddleDataType.TEXT,
 28					file_plain="./cv.txt"
 29				)
 30			]
 31		)
 32		ex.status.extract.required = False
 33	```
 34	```json
 35		{
 36			"id": "ex1",
 37			"sub_ids": [],
 38			"riddle": {
 39				"context": "Example 1",
 40				"question": "Get the name of the person.",
 41				"solutions_before": []
 42			},
 43			"solution": null,
 44			"data": [
 45				{
 46					"type": "text",
 47					"file_plain": "/ums-agenten/share/cv.txt",
 48					"file_extracted": null
 49				}
 50			],
 51			"status": {
 52				"extract": {
 53					"required": false,
 54					"finished": false
 55				},
 56				"solve": {
 57					"required": true,
 58					"finished": false
 59				},
 60				"validate": {
 61					"required": true,
 62					"finished": false
 63				},
 64				"trial": 0,
 65				"solved": false
 66			}
 67		}
 68	```
 69	```python
 70		ex.solution = RiddleSolution(
 71			solution="Otto",
 72			explanation="Written in line 6 after 'Name:'"
 73		)
 74	```
 75	```json
 76		{
 77			...
 78			"solution": {
 79				"solution": "Otto",
 80				"explanation": "Written in line 6 after 'Name:'",
 81				"used_data": [],
 82				"accepted": false,
 83				"review": null
 84			},
 85			...
 86		}
 87	```
 88
 89"""
 90
 91import os
 92
 93from enum import Enum
 94
 95from typing import List, Any
 96from typing_extensions import Annotated
 97
 98from pydantic import (
 99    BaseModel,
100    ValidationError, ValidationInfo,
101    ValidatorFunctionWrapHandler
102)
103from pydantic.functional_validators import WrapValidator, AfterValidator
104
105from ums.utils.const import SHARE_PATH
106
107class RiddleInformation(BaseModel):
108	"""
109		This is the basic class used as superclass for all message and infos
110		about a riddle.
111	"""
112
113class RiddleDataType(Enum):
114	"""
115		Enum for the three types of data used in a riddle.
116	"""
117	
118	TEXT = "text"
119	IMAGE = "image"
120	AUDIO = "audio"
121
122def _check_data_file(file_name:str) -> str:
123	if not file_name.startswith('/'):
124		file_name = os.path.join(SHARE_PATH, file_name)
125	
126	assert file_name.startswith(SHARE_PATH), "The data file needs to be in {}!".format(SHARE_PATH)
127
128	file_name = os.path.realpath(file_name, strict=False)
129
130	assert os.path.isfile(file_name), "The data file {} does not exist!".format(file_name)
131	
132	return file_name
133
134def _ignore_file_missing(
135		v: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
136	) -> str:
137	try:
138		return handler(v)
139	except ValidationError:
140		if not info.context is None and \
141			"require_file_exists" in info.context and \
142			info.context["require_file_exists"] == False and \
143			isinstance(v, str):
144				return "missing:{}".format(v)
145		else:
146			raise
147
148class RiddleData(RiddleInformation):
149
150	"""
151		A data item to be used to solve the riddle
152	"""
153
154	type: RiddleDataType
155	"""
156		The type of the data item.
157	"""
158
159	file_plain: Annotated[str, AfterValidator(_check_data_file), WrapValidator(_ignore_file_missing)] 
160	"""
161		The plain file (as path to file system) without any processing.
162
163		The path will be validated and must start with `SHARE_PATH` (or be relative to `SHARE_PATH`).
164		The file must exist.
165	"""
166
167	file_extracted: Annotated[str, AfterValidator(_check_data_file), WrapValidator(_ignore_file_missing)] | None = None
168	"""
169		The processed files (as path to file system), i.e., a schematic file containing all extracted informations.
170
171		The path will be validated and must start with `SHARE_PATH` (or be relative to `SHARE_PATH`).
172		The file must exist.
173	"""
174
175
176
177class RiddleSolution(RiddleInformation):
178	"""
179		A solution of a riddle.
180	"""
181
182	solution: str
183	"""
184		The textual value of the solution.
185	"""
186
187	explanation: str
188	"""
189		An explanation of the solution.
190	"""
191
192	used_data: List[RiddleData] = []
193	"""
194		The data items used to create the solution (optional).
195	"""
196
197	accepted : bool = False
198	"""
199		If the solution is accepted by validator/ gatekeeper.
200	"""
201
202	review: str | None = None
203	"""
204		A review of the solution (if None: not tried to validate)
205	"""
206
207class Riddle(RiddleInformation):
208	"""
209		The riddle (the task description and possibly a solution)
210	"""
211	
212	context: str
213	"""
214		The context of the riddle (as textual string).
215	"""
216
217	question: str
218	"""
219		The actual main question of the riddle (as textual string).
220	"""
221
222	solutions_before: List[RiddleSolution] = []
223	"""
224		If already tried to solve this riddle before, the (not accepted) solutions are stored here
225	"""
226
227class RiddleSubStatus(RiddleInformation):
228	"""
229		The sub status for each possible step a riddle may go though.
230	"""
231	
232	required: bool = True
233	"""
234		Is this step required (i.e., requested)
235	"""
236
237	finished: bool = False
238	"""
239		Was this step already executed.
240	"""
241
242class RiddleStatus(RiddleInformation):
243	"""
244		The status of a riddle, will be mostly changed by Management when the riddle is sent to different agents while solving it.
245	"""
246	
247	extract: RiddleSubStatus = RiddleSubStatus()
248	"""
249		The first extract step (image, text, audio -> more sematic data)
250
251		The `RiddleData` items in `AgentMessage.data` shall have `file_extracted` afterwards. 
252	"""
253	
254	solve: RiddleSubStatus = RiddleSubStatus()
255	"""
256		The *main* solving step.
257
258		`AgentMessage.solution` shall be an `RiddleSolution` afterwards.
259	"""
260
261	validate: RiddleSubStatus = RiddleSubStatus()
262	"""
263		The validation step, i.e., does the gatekeeper accept the solution in `AgentMessage.solution`.
264	"""
265
266	trial: int = 0
267	"""
268		A counter for the number of trials.
269		Each time the gatekeeper does not accept a solution of this riddle, the value is incremented.
270	"""
271
272	solved: bool = False
273	"""
274		True, after the gatekeeper accepts the solution at `AgentMessage.solution`
275	"""
276
277class AgentMessage(RiddleInformation):
278	"""
279		The basic message, which is sent be the agent and the management.
280		The objects will be JSON en- and decoded.
281	"""
282
283	id: str
284	"""
285		The riddle id, e.g., ``ex1``
286		This is a unique string and identifies the riddle.
287	"""
288
289	sub_ids: List[str] = []
290	"""
291		There might be cases, when an agent decided to split in riddle in multiple *smaller* steps.
292		Each *sub* riddle will then get its own id (i.e., ``ex1-sub1``) while the sub id is added here as reference.
293	"""
294
295	riddle: Riddle
296	"""
297		The riddle to solve.
298	"""
299
300	solution: RiddleSolution | None = None
301	"""
302		The solution of the riddle (or empty if no solution available)
303	"""
304
305	data: List[RiddleData] = []
306	"""
307		The data to get the solution from.
308	"""
309
310	status: RiddleStatus = RiddleStatus()
311	"""
312		The status of the riddle.
313	"""
314
315class AgentResponse(RiddleInformation):
316	"""
317		Returned by the management when receiving an `AgentMessage`.
318	"""
319
320	count : int
321	"""
322		The count of the message (overall numeric id).
323	"""
324
325	msg: str|None = None
326	"""
327		An additional message.
328	"""
329
330	error: bool = False
331	"""
332		If an error occurred.
333	"""
334
335	error_msg: str|None = None
336	"""
337		Error message (if `error` )
338	"""
339
340class MessageDbRow(BaseModel):
341	"""
342		Object representing a database row.
343	"""
344
345	count : int
346	"""
347		The count (primary key) of the item.
348	"""
349
350	sender : str
351	"""
352		The sender of the message.
353	""" 
354
355	recipient : str
356	"""
357		The recipient of the message
358	"""
359
360	time : int
361	"""
362		The time (unix timestamp) the message was received/ sent.
363	"""
364
365	message : AgentMessage
366	"""
367		The message  received/ sent.
368	"""
369
370	processed : bool
371	"""
372		Did the management process the message, i.e., did the tasks necessary for this message (mostly only relevant for received messages).
373	"""
374
375	solution : bool|None = None
376	"""
377		Does this message contain a valid solution?
378		True if contains valid solution, False if solution not valid, Null/None if not applicable
379	"""
class RiddleInformation(pydantic.main.BaseModel):
108class RiddleInformation(BaseModel):
109	"""
110		This is the basic class used as superclass for all message and infos
111		about a riddle.
112	"""

This is the basic class used as superclass for all message and infos about a riddle.

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class RiddleDataType(enum.Enum):
114class RiddleDataType(Enum):
115	"""
116		Enum for the three types of data used in a riddle.
117	"""
118	
119	TEXT = "text"
120	IMAGE = "image"
121	AUDIO = "audio"

Enum for the three types of data used in a riddle.

TEXT = <RiddleDataType.TEXT: 'text'>
IMAGE = <RiddleDataType.IMAGE: 'image'>
AUDIO = <RiddleDataType.AUDIO: 'audio'>
Inherited Members
enum.Enum
name
value
class RiddleData(RiddleInformation):
149class RiddleData(RiddleInformation):
150
151	"""
152		A data item to be used to solve the riddle
153	"""
154
155	type: RiddleDataType
156	"""
157		The type of the data item.
158	"""
159
160	file_plain: Annotated[str, AfterValidator(_check_data_file), WrapValidator(_ignore_file_missing)] 
161	"""
162		The plain file (as path to file system) without any processing.
163
164		The path will be validated and must start with `SHARE_PATH` (or be relative to `SHARE_PATH`).
165		The file must exist.
166	"""
167
168	file_extracted: Annotated[str, AfterValidator(_check_data_file), WrapValidator(_ignore_file_missing)] | None = None
169	"""
170		The processed files (as path to file system), i.e., a schematic file containing all extracted informations.
171
172		The path will be validated and must start with `SHARE_PATH` (or be relative to `SHARE_PATH`).
173		The file must exist.
174	"""

A data item to be used to solve the riddle

The type of the data item.

file_plain: Annotated[str, AfterValidator(func=<function _check_data_file at 0x101e08fe0>), WrapValidator(func=<function _ignore_file_missing at 0x10210be20>, json_schema_input_type=PydanticUndefined)]

The plain file (as path to file system) without any processing.

The path will be validated and must start with SHARE_PATH (or be relative to SHARE_PATH). The file must exist.

file_extracted: Optional[Annotated[str, AfterValidator(func=<function _check_data_file at 0x101e08fe0>), WrapValidator(func=<function _ignore_file_missing at 0x10210be20>, json_schema_input_type=PydanticUndefined)]]

The processed files (as path to file system), i.e., a schematic file containing all extracted informations.

The path will be validated and must start with SHARE_PATH (or be relative to SHARE_PATH). The file must exist.

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class RiddleSolution(RiddleInformation):
178class RiddleSolution(RiddleInformation):
179	"""
180		A solution of a riddle.
181	"""
182
183	solution: str
184	"""
185		The textual value of the solution.
186	"""
187
188	explanation: str
189	"""
190		An explanation of the solution.
191	"""
192
193	used_data: List[RiddleData] = []
194	"""
195		The data items used to create the solution (optional).
196	"""
197
198	accepted : bool = False
199	"""
200		If the solution is accepted by validator/ gatekeeper.
201	"""
202
203	review: str | None = None
204	"""
205		A review of the solution (if None: not tried to validate)
206	"""

A solution of a riddle.

solution: str

The textual value of the solution.

explanation: str

An explanation of the solution.

used_data: List[RiddleData]

The data items used to create the solution (optional).

accepted: bool

If the solution is accepted by validator/ gatekeeper.

review: str | None

A review of the solution (if None: not tried to validate)

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class Riddle(RiddleInformation):
208class Riddle(RiddleInformation):
209	"""
210		The riddle (the task description and possibly a solution)
211	"""
212	
213	context: str
214	"""
215		The context of the riddle (as textual string).
216	"""
217
218	question: str
219	"""
220		The actual main question of the riddle (as textual string).
221	"""
222
223	solutions_before: List[RiddleSolution] = []
224	"""
225		If already tried to solve this riddle before, the (not accepted) solutions are stored here
226	"""

The riddle (the task description and possibly a solution)

context: str

The context of the riddle (as textual string).

question: str

The actual main question of the riddle (as textual string).

solutions_before: List[RiddleSolution]

If already tried to solve this riddle before, the (not accepted) solutions are stored here

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class RiddleSubStatus(RiddleInformation):
228class RiddleSubStatus(RiddleInformation):
229	"""
230		The sub status for each possible step a riddle may go though.
231	"""
232	
233	required: bool = True
234	"""
235		Is this step required (i.e., requested)
236	"""
237
238	finished: bool = False
239	"""
240		Was this step already executed.
241	"""

The sub status for each possible step a riddle may go though.

required: bool

Is this step required (i.e., requested)

finished: bool

Was this step already executed.

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class RiddleStatus(RiddleInformation):
243class RiddleStatus(RiddleInformation):
244	"""
245		The status of a riddle, will be mostly changed by Management when the riddle is sent to different agents while solving it.
246	"""
247	
248	extract: RiddleSubStatus = RiddleSubStatus()
249	"""
250		The first extract step (image, text, audio -> more sematic data)
251
252		The `RiddleData` items in `AgentMessage.data` shall have `file_extracted` afterwards. 
253	"""
254	
255	solve: RiddleSubStatus = RiddleSubStatus()
256	"""
257		The *main* solving step.
258
259		`AgentMessage.solution` shall be an `RiddleSolution` afterwards.
260	"""
261
262	validate: RiddleSubStatus = RiddleSubStatus()
263	"""
264		The validation step, i.e., does the gatekeeper accept the solution in `AgentMessage.solution`.
265	"""
266
267	trial: int = 0
268	"""
269		A counter for the number of trials.
270		Each time the gatekeeper does not accept a solution of this riddle, the value is incremented.
271	"""
272
273	solved: bool = False
274	"""
275		True, after the gatekeeper accepts the solution at `AgentMessage.solution`
276	"""

The status of a riddle, will be mostly changed by Management when the riddle is sent to different agents while solving it.

extract: RiddleSubStatus

The first extract step (image, text, audio -> more sematic data)

The RiddleData items in AgentMessage.data shall have file_extracted afterwards.

The main solving step.

AgentMessage.solution shall be an RiddleSolution afterwards.

@classmethod
@typing_extensions.deprecated('The `validate` method is deprecated; use `model_validate` instead.', category=None)
def validate(cls, value: Any) -> Self:
1383    @classmethod
1384    @typing_extensions.deprecated('The `validate` method is deprecated; use `model_validate` instead.', category=None)
1385    def validate(cls, value: Any) -> Self:  # noqa: D102
1386        warnings.warn(
1387            'The `validate` method is deprecated; use `model_validate` instead.', category=PydanticDeprecatedSince20
1388        )
1389        return cls.model_validate(value)

The validation step, i.e., does the gatekeeper accept the solution in AgentMessage.solution.

trial: int

A counter for the number of trials. Each time the gatekeeper does not accept a solution of this riddle, the value is incremented.

solved: bool

True, after the gatekeeper accepts the solution at AgentMessage.solution

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
update_forward_refs
class AgentMessage(RiddleInformation):
278class AgentMessage(RiddleInformation):
279	"""
280		The basic message, which is sent be the agent and the management.
281		The objects will be JSON en- and decoded.
282	"""
283
284	id: str
285	"""
286		The riddle id, e.g., ``ex1``
287		This is a unique string and identifies the riddle.
288	"""
289
290	sub_ids: List[str] = []
291	"""
292		There might be cases, when an agent decided to split in riddle in multiple *smaller* steps.
293		Each *sub* riddle will then get its own id (i.e., ``ex1-sub1``) while the sub id is added here as reference.
294	"""
295
296	riddle: Riddle
297	"""
298		The riddle to solve.
299	"""
300
301	solution: RiddleSolution | None = None
302	"""
303		The solution of the riddle (or empty if no solution available)
304	"""
305
306	data: List[RiddleData] = []
307	"""
308		The data to get the solution from.
309	"""
310
311	status: RiddleStatus = RiddleStatus()
312	"""
313		The status of the riddle.
314	"""

The basic message, which is sent be the agent and the management. The objects will be JSON en- and decoded.

id: str

The riddle id, e.g., ex1 This is a unique string and identifies the riddle.

sub_ids: List[str]

There might be cases, when an agent decided to split in riddle in multiple smaller steps. Each sub riddle will then get its own id (i.e., ex1-sub1) while the sub id is added here as reference.

riddle: Riddle

The riddle to solve.

solution: RiddleSolution | None

The solution of the riddle (or empty if no solution available)

data: List[RiddleData]

The data to get the solution from.

status: RiddleStatus

The status of the riddle.

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class AgentResponse(RiddleInformation):
316class AgentResponse(RiddleInformation):
317	"""
318		Returned by the management when receiving an `AgentMessage`.
319	"""
320
321	count : int
322	"""
323		The count of the message (overall numeric id).
324	"""
325
326	msg: str|None = None
327	"""
328		An additional message.
329	"""
330
331	error: bool = False
332	"""
333		If an error occurred.
334	"""
335
336	error_msg: str|None = None
337	"""
338		Error message (if `error` )
339	"""

Returned by the management when receiving an AgentMessage.

count: int

The count of the message (overall numeric id).

msg: str | None

An additional message.

error: bool

If an error occurred.

error_msg: str | None

Error message (if error )

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class MessageDbRow(pydantic.main.BaseModel):
341class MessageDbRow(BaseModel):
342	"""
343		Object representing a database row.
344	"""
345
346	count : int
347	"""
348		The count (primary key) of the item.
349	"""
350
351	sender : str
352	"""
353		The sender of the message.
354	""" 
355
356	recipient : str
357	"""
358		The recipient of the message
359	"""
360
361	time : int
362	"""
363		The time (unix timestamp) the message was received/ sent.
364	"""
365
366	message : AgentMessage
367	"""
368		The message  received/ sent.
369	"""
370
371	processed : bool
372	"""
373		Did the management process the message, i.e., did the tasks necessary for this message (mostly only relevant for received messages).
374	"""
375
376	solution : bool|None = None
377	"""
378		Does this message contain a valid solution?
379		True if contains valid solution, False if solution not valid, Null/None if not applicable
380	"""

Object representing a database row.

count: int

The count (primary key) of the item.

sender: str

The sender of the message.

recipient: str

The recipient of the message

time: int

The time (unix timestamp) the message was received/ sent.

message: AgentMessage

The message received/ sent.

processed: bool

Did the management process the message, i.e., did the tasks necessary for this message (mostly only relevant for received messages).

solution: bool | None

Does this message contain a valid solution? True if contains valid solution, False if solution not valid, Null/None if not applicable

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs