44from pydantic import BaseModel , Field
55
66
7- class BaseItem (BaseModel ):
7+ class Item (BaseModel ):
8+ id : uuid .UUID = Field (default_factory = uuid .uuid4 )
89 content : Any = Field (default = None )
10+
11+ class ItemRemove (BaseModel ):
912 id : uuid .UUID
1013
11- class Item (BaseItem ):
12- id : uuid .UUID = Field (default_factory = uuid .uuid4 )
14+ class ChatTurn (BaseModel ):
15+ id : int # easier for the LLMs to parse
16+ user_question : str
17+ ai_response : str
18+ data : list [Item ]
1319
14- class ItemRemove ( BaseItem ):
15- ...
20+ class ChatTurnRemove ( BaseModel ):
21+ id : int # easier for the LLMs to parse
1622
17- def add_item (existing : Item | list [Item ], update : BaseItem | list [BaseItem ]) -> list [Item ]:
18- """Merges two lists of Items, deleting or updating Items by ID.
23+ ItemUpdate = Item | ItemRemove | list [Item | ItemRemove ]
24+
25+ def add_item (existing : Item | list [Item ], update : ItemUpdate ) -> list [Item ]:
26+ """Merge Items into an existing list, replacing or removing entries by ID.
1927
2028 Args:
21- existing (list[Item]): A base list of Item objects
22- update (list[BaseItem]): A list of Item or ItemRemove objects
29+ existing (Item | list[Item]):
30+ The current `Item` or list of `Item` objects to be merged into.
31+ update (ItemUpdate):
32+ An `Item`, `ItemRemove`, or a list containing a mix of `Item` and
33+ `ItemRemove` objects that specify changes to apply.
2334
2435 Returns:
25- list[Item]: The merged list
36+ list[Item]:
37+ The merged list of `Item` objects after applying the updates and deletions.
38+
39+ Raises:
40+ ValueError:
41+ If an `ItemRemove` references an ID that does not exist in `existing`.
2642 """
2743 if not isinstance (existing , list ):
2844 existing = [existing ]
@@ -31,7 +47,7 @@ def add_item(existing: Item|list[Item], update: BaseItem|list[BaseItem]) -> list
3147 update = [update ]
3248
3349 # copying to avoid modifying the existing list
34- merged : list [Item ] = existing .copy () or []
50+ merged : list [Item ] = existing .copy ()
3551
3652 ids_to_idx = {item .id : idx for idx , item in enumerate (existing )}
3753
@@ -55,3 +71,34 @@ def add_item(existing: Item|list[Item], update: BaseItem|list[BaseItem]) -> list
5571 merged = [item for item in merged if item .id not in ids_to_remove ]
5672
5773 return merged
74+
75+ def add_chat_turn (existing : dict [int , ChatTurn ], update : dict [int , ChatTurn | ChatTurnRemove ]) -> dict [int , ChatTurn ]:
76+ """Merge chat turns into an existing dictionary, replacing or removing entries by key.
77+
78+ Args:
79+ existing (dict[int, ChatTurn]):
80+ The current dictionary of chat turns to be updated.
81+ update (dict[int, ChatTurn | ChatTurnRemove]):
82+ The dictionary containing additions, replacements, or deletions to apply.
83+
84+ Returns:
85+ dict[int, ChatTurn]:
86+ The updated dictionary of chat turns.
87+
88+ Raises:
89+ ValueError:
90+ If a `ChatTurnRemove` references a key not present in `existing`.
91+ """
92+ merged = existing .copy ()
93+
94+ for k , v in update .items ():
95+ if isinstance (v , ChatTurnRemove ):
96+ if k not in merged :
97+ raise ValueError (
98+ f"Attempted to delete non-existent chat turn '{ k } '"
99+ )
100+ del merged [k ]
101+ else :
102+ merged [k ] = v
103+
104+ return merged
0 commit comments