typeagent-py 0.1.0__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 (55) hide show
  1. typeagent/aitools/auth.py +61 -0
  2. typeagent/aitools/embeddings.py +232 -0
  3. typeagent/aitools/utils.py +244 -0
  4. typeagent/aitools/vectorbase.py +175 -0
  5. typeagent/knowpro/answer_context_schema.py +49 -0
  6. typeagent/knowpro/answer_response_schema.py +34 -0
  7. typeagent/knowpro/answers.py +577 -0
  8. typeagent/knowpro/collections.py +759 -0
  9. typeagent/knowpro/common.py +9 -0
  10. typeagent/knowpro/convknowledge.py +112 -0
  11. typeagent/knowpro/convsettings.py +94 -0
  12. typeagent/knowpro/convutils.py +49 -0
  13. typeagent/knowpro/date_time_schema.py +32 -0
  14. typeagent/knowpro/field_helpers.py +87 -0
  15. typeagent/knowpro/fuzzyindex.py +144 -0
  16. typeagent/knowpro/interfaces.py +818 -0
  17. typeagent/knowpro/knowledge.py +88 -0
  18. typeagent/knowpro/kplib.py +125 -0
  19. typeagent/knowpro/query.py +1128 -0
  20. typeagent/knowpro/search.py +628 -0
  21. typeagent/knowpro/search_query_schema.py +165 -0
  22. typeagent/knowpro/searchlang.py +729 -0
  23. typeagent/knowpro/searchlib.py +345 -0
  24. typeagent/knowpro/secindex.py +100 -0
  25. typeagent/knowpro/serialization.py +390 -0
  26. typeagent/knowpro/textlocindex.py +179 -0
  27. typeagent/knowpro/utils.py +17 -0
  28. typeagent/mcp/server.py +139 -0
  29. typeagent/podcasts/podcast.py +473 -0
  30. typeagent/podcasts/podcast_import.py +105 -0
  31. typeagent/storage/__init__.py +25 -0
  32. typeagent/storage/memory/__init__.py +13 -0
  33. typeagent/storage/memory/collections.py +68 -0
  34. typeagent/storage/memory/convthreads.py +81 -0
  35. typeagent/storage/memory/messageindex.py +178 -0
  36. typeagent/storage/memory/propindex.py +289 -0
  37. typeagent/storage/memory/provider.py +84 -0
  38. typeagent/storage/memory/reltermsindex.py +318 -0
  39. typeagent/storage/memory/semrefindex.py +660 -0
  40. typeagent/storage/memory/timestampindex.py +176 -0
  41. typeagent/storage/sqlite/__init__.py +31 -0
  42. typeagent/storage/sqlite/collections.py +362 -0
  43. typeagent/storage/sqlite/messageindex.py +382 -0
  44. typeagent/storage/sqlite/propindex.py +119 -0
  45. typeagent/storage/sqlite/provider.py +293 -0
  46. typeagent/storage/sqlite/reltermsindex.py +328 -0
  47. typeagent/storage/sqlite/schema.py +248 -0
  48. typeagent/storage/sqlite/semrefindex.py +156 -0
  49. typeagent/storage/sqlite/timestampindex.py +146 -0
  50. typeagent/storage/utils.py +41 -0
  51. typeagent_py-0.1.0.dist-info/METADATA +28 -0
  52. typeagent_py-0.1.0.dist-info/RECORD +55 -0
  53. typeagent_py-0.1.0.dist-info/WHEEL +5 -0
  54. typeagent_py-0.1.0.dist-info/licenses/LICENSE +21 -0
  55. typeagent_py-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,345 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+
4
+ """
5
+ INTERNAL LIBRARY
6
+ Functions that help with creating search and property terms
7
+ """
8
+
9
+ from typing import cast
10
+
11
+ from .interfaces import (
12
+ ISemanticRefCollection,
13
+ KnowledgePropertyName,
14
+ PropertySearchTerm,
15
+ ScoredSemanticRefOrdinal,
16
+ SearchTerm,
17
+ SearchTermGroup,
18
+ SearchTermGroupTypes,
19
+ SemanticRef,
20
+ Term,
21
+ )
22
+ from ..storage.memory.propindex import PropertyNames
23
+
24
+
25
+ def create_search_term(
26
+ text: str,
27
+ weight: float | None = None,
28
+ exact_match_value: bool = False,
29
+ ) -> SearchTerm:
30
+ """
31
+ Create a search term with an optional weight
32
+
33
+ Args:
34
+ text: term text
35
+ weight: optional weight for the term
36
+ exact_match_value: if True, configures term to only match exactly
37
+
38
+ Returns:
39
+ SearchTerm
40
+ """
41
+ term = Term(text=text, weight=weight)
42
+ related_terms = [] if exact_match_value else None
43
+ return SearchTerm(term=term, related_terms=related_terms)
44
+
45
+
46
+ def create_property_search_term(
47
+ name: str,
48
+ value: str,
49
+ exact_match_value: bool = False,
50
+ ) -> PropertySearchTerm:
51
+ """
52
+ Create a new property search term from the given name and value
53
+
54
+ Args:
55
+ name: property name
56
+ value: property value
57
+ exact_match_value: if True, configures propertyValue to only match exactly
58
+
59
+ Returns:
60
+ PropertySearchTerm
61
+ """
62
+ # Check if this is one of our well known predefined values
63
+ if name in (
64
+ "name",
65
+ "type",
66
+ "verb",
67
+ "subject",
68
+ "object",
69
+ "indirectObject",
70
+ "tag",
71
+ "topic",
72
+ ):
73
+ property_name: KnowledgePropertyName | SearchTerm = cast(
74
+ KnowledgePropertyName, name
75
+ )
76
+ else:
77
+ property_name = create_search_term(name)
78
+
79
+ property_value = create_search_term(value)
80
+ if exact_match_value:
81
+ # No related terms should be matched for this term
82
+ property_value.related_terms = []
83
+
84
+ return PropertySearchTerm(
85
+ property_name=property_name, property_value=property_value
86
+ )
87
+
88
+
89
+ def create_and_term_group(*terms: SearchTermGroupTypes) -> SearchTermGroup:
90
+ """
91
+ Create a term group whose matches are intersected
92
+
93
+ Args:
94
+ terms: search terms to group
95
+
96
+ Returns:
97
+ SearchTermGroup with "and" boolean operation
98
+ """
99
+ return SearchTermGroup(boolean_op="and", terms=list(terms))
100
+
101
+
102
+ def create_or_term_group(*terms: SearchTermGroupTypes) -> SearchTermGroup:
103
+ """
104
+ Create a term group whose matches are union-ed
105
+
106
+ Args:
107
+ terms: search terms to group
108
+
109
+ Returns:
110
+ SearchTermGroup with "or" boolean operation
111
+ """
112
+ return SearchTermGroup(boolean_op="or", terms=list(terms))
113
+
114
+
115
+ def create_or_max_term_group(*terms: SearchTermGroupTypes) -> SearchTermGroup:
116
+ """
117
+ Create an or_max search group
118
+
119
+ Args:
120
+ terms: search terms to group
121
+
122
+ Returns:
123
+ SearchTermGroup with "or_max" boolean operation
124
+ """
125
+ return SearchTermGroup(boolean_op="or_max", terms=list(terms))
126
+
127
+
128
+ def create_search_terms(terms: list[str]) -> list[SearchTerm]:
129
+ """
130
+ Create an array of SearchTerms from the given term strings.
131
+ You can also provide related terms for each term string by using the following syntax:
132
+ 'novel;book;bestseller': Here, 'book' and 'bestseller' become related terms for 'novel'
133
+
134
+ Args:
135
+ terms: term text, with optional embedded related terms
136
+
137
+ Returns:
138
+ list of SearchTerm
139
+ """
140
+ search_terms: list[SearchTerm] = []
141
+ for term in terms:
142
+ search_term = _parse_search_term(term)
143
+ if search_term:
144
+ search_terms.append(search_term)
145
+ return search_terms
146
+
147
+
148
+ def _parse_search_term(text: str) -> SearchTerm | None:
149
+ """Parse a search term string with optional related terms separated by ';'."""
150
+ term_strings = _split_term_values(text, ";")
151
+ if len(term_strings) > 0:
152
+ term_strings = [t.lower() for t in term_strings]
153
+ search_term = SearchTerm(term=Term(text=term_strings[0]))
154
+ if len(term_strings) > 1:
155
+ search_term.related_terms = []
156
+ for i in range(1, len(term_strings)):
157
+ search_term.related_terms.append(Term(text=term_strings[i]))
158
+ return search_term
159
+ return None
160
+
161
+
162
+ def create_property_search_terms(
163
+ property_name_values: dict[str, str],
164
+ ) -> list[PropertySearchTerm]:
165
+ """
166
+ Create property search from the given record of name, value pairs
167
+ To search for multiple values for same property name, the value should be a ',' separated list of sub values
168
+
169
+ Args:
170
+ property_name_values: dictionary of property name to value mappings
171
+
172
+ Returns:
173
+ list of PropertySearchTerm
174
+ """
175
+ property_search_terms: list[PropertySearchTerm] = []
176
+ for property_name, property_value in property_name_values.items():
177
+ all_values = _split_term_values(property_value, ",")
178
+ for value in all_values:
179
+ property_search_terms.append(
180
+ create_property_search_term(property_name, value)
181
+ )
182
+ return property_search_terms
183
+
184
+
185
+ def create_topic_search_term_group(
186
+ topic_terms: str | list[str],
187
+ exact_match: bool = False,
188
+ ) -> SearchTermGroup:
189
+ """
190
+ Create a search term group for topic searches.
191
+
192
+ Args:
193
+ topic_terms: single topic term or list of topic terms
194
+ exact_match: if True, force exact matching
195
+
196
+ Returns:
197
+ SearchTermGroup for topic search
198
+ """
199
+ term_group = create_or_max_term_group()
200
+ if isinstance(topic_terms, str):
201
+ term_group.terms.append(
202
+ create_property_search_term(
203
+ PropertyNames.Topic.value,
204
+ topic_terms,
205
+ exact_match,
206
+ )
207
+ )
208
+ else:
209
+ for term in topic_terms:
210
+ term_group.terms.append(
211
+ create_property_search_term(
212
+ PropertyNames.Topic.value, term, exact_match
213
+ )
214
+ )
215
+ return term_group
216
+
217
+
218
+ def create_entity_search_term_group(
219
+ name: str | None = None,
220
+ type_: str | None = None,
221
+ facet_name: str | None = None,
222
+ facet_value: str | None = None,
223
+ exact_match: bool = False,
224
+ ) -> SearchTermGroup:
225
+ """
226
+ Create a search term group for entity searches.
227
+
228
+ Args:
229
+ name: entity name to search for
230
+ type_: entity type to search for
231
+ facet_name: facet name to search for
232
+ facet_value: facet value to search for
233
+ exact_match: if True, force exact matching
234
+
235
+ Returns:
236
+ SearchTermGroup for entity search
237
+ """
238
+ term_group = create_or_max_term_group()
239
+ if name:
240
+ term_group.terms.append(
241
+ create_property_search_term(
242
+ PropertyNames.EntityName.value,
243
+ name,
244
+ exact_match,
245
+ )
246
+ )
247
+ if type_:
248
+ term_group.terms.append(
249
+ create_property_search_term(
250
+ PropertyNames.EntityType.value,
251
+ type_,
252
+ exact_match,
253
+ )
254
+ )
255
+ if facet_name:
256
+ term_group.terms.append(
257
+ create_property_search_term(
258
+ PropertyNames.FacetName.value,
259
+ facet_name,
260
+ exact_match,
261
+ )
262
+ )
263
+ if facet_value:
264
+ term_group.terms.append(
265
+ create_property_search_term(
266
+ PropertyNames.FacetValue.value,
267
+ facet_value,
268
+ exact_match,
269
+ )
270
+ )
271
+ return term_group
272
+
273
+
274
+ def create_tag_search_term_group(
275
+ tags: list[str],
276
+ exact_match: bool = True,
277
+ ) -> SearchTermGroup:
278
+ """
279
+ Create a search term group for tag searches.
280
+
281
+ Args:
282
+ tags: list of tags to search for
283
+ exact_match: if True, force exact matching (default True)
284
+
285
+ Returns:
286
+ SearchTermGroup for tag search
287
+ """
288
+ term_group = create_or_max_term_group()
289
+ for tag in tags:
290
+ term_group.terms.append(
291
+ create_property_search_term(PropertyNames.Tag.value, tag, exact_match)
292
+ )
293
+ return term_group
294
+
295
+
296
+ def _split_term_values(term: str, split_char: str) -> list[str]:
297
+ """Split term values by the given character, trimming and removing empty strings."""
298
+ # Simple implementation - in TS this uses kpLib.split with trim and removeEmpty options
299
+ parts = [part.strip() for part in term.split(split_char)]
300
+ return [part for part in parts if part]
301
+
302
+
303
+ def create_multiple_choice_question(
304
+ question: str,
305
+ choices: list[str],
306
+ add_none: bool = True,
307
+ ) -> str:
308
+ """
309
+ Create a multiple choice question string.
310
+
311
+ Args:
312
+ question: the question text
313
+ choices: list of choices
314
+ add_none: if True, add "None of the above" option
315
+
316
+ Returns:
317
+ formatted multiple choice question string
318
+ """
319
+ text = question
320
+ if len(choices) > 0:
321
+ text = f"Multiple choice question:\n{question}\n"
322
+ text += "Answer using *one or more* of the following choices *only*:\n"
323
+ for choice in choices:
324
+ text += f"- {choice.strip()}\n"
325
+ if add_none:
326
+ text += "- None of the above\n"
327
+ return text
328
+
329
+
330
+ async def get_semantic_refs_from_scored_ordinals(
331
+ semantic_refs: ISemanticRefCollection,
332
+ scored_ordinals: list[ScoredSemanticRefOrdinal],
333
+ ) -> list[SemanticRef]:
334
+ """
335
+ Get semantic references from scored ordinals.
336
+
337
+ Args:
338
+ semantic_refs: collection of semantic references
339
+ scored_ordinals: list of scored semantic reference ordinals
340
+
341
+ Returns:
342
+ list of SemanticRef objects
343
+ """
344
+ ordinals = [sr.semantic_ref_ordinal for sr in scored_ordinals]
345
+ return await semantic_refs.get_multiple(ordinals)
@@ -0,0 +1,100 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+
4
+ from ..aitools.embeddings import AsyncEmbeddingModel
5
+ from ..aitools.vectorbase import TextEmbeddingIndexSettings
6
+ from .convsettings import ConversationSettings
7
+ from .interfaces import (
8
+ IConversation,
9
+ IConversationSecondaryIndexes,
10
+ IMessage,
11
+ IStorageProvider,
12
+ ITermToSemanticRefIndex,
13
+ TextLocation,
14
+ )
15
+ from ..storage.memory.messageindex import build_message_index
16
+ from ..storage.memory.propindex import PropertyIndex, build_property_index
17
+ from ..storage.memory.reltermsindex import (
18
+ RelatedTermsIndex,
19
+ build_related_terms_index,
20
+ )
21
+ from .convsettings import RelatedTermIndexSettings
22
+ from ..storage.memory.timestampindex import (
23
+ TimestampToTextRangeIndex,
24
+ build_timestamp_index,
25
+ )
26
+
27
+
28
+ class ConversationSecondaryIndexes(IConversationSecondaryIndexes):
29
+ def __init__(
30
+ self,
31
+ storage_provider: IStorageProvider,
32
+ settings: RelatedTermIndexSettings,
33
+ ):
34
+ self._storage_provider = storage_provider
35
+ # Initialize all indexes through storage provider immediately
36
+ self.property_to_semantic_ref_index = None
37
+ self.timestamp_index = None
38
+ self.term_to_related_terms_index = None
39
+ self.threads = None
40
+ self.message_index = None
41
+
42
+ @classmethod
43
+ async def create(
44
+ cls,
45
+ storage_provider: IStorageProvider,
46
+ settings: RelatedTermIndexSettings,
47
+ ) -> "ConversationSecondaryIndexes":
48
+ """Create and initialize a ConversationSecondaryIndexes with all indexes."""
49
+ self = cls(storage_provider, settings)
50
+ # Initialize all indexes from storage provider
51
+ self.property_to_semantic_ref_index = (
52
+ await storage_provider.get_property_index()
53
+ )
54
+ self.timestamp_index = await storage_provider.get_timestamp_index()
55
+ self.term_to_related_terms_index = (
56
+ await storage_provider.get_related_terms_index()
57
+ )
58
+ self.threads = await storage_provider.get_conversation_threads()
59
+ self.message_index = await storage_provider.get_message_text_index()
60
+ return self
61
+
62
+
63
+ async def build_secondary_indexes[
64
+ TMessage: IMessage,
65
+ TTermToSemanticRefIndex: ITermToSemanticRefIndex,
66
+ ](
67
+ conversation: IConversation[TMessage, TTermToSemanticRefIndex],
68
+ conversation_settings: ConversationSettings,
69
+ ) -> None:
70
+ if conversation.secondary_indexes is None:
71
+ storage_provider = await conversation_settings.get_storage_provider()
72
+ conversation.secondary_indexes = await ConversationSecondaryIndexes.create(
73
+ storage_provider, conversation_settings.related_term_index_settings
74
+ )
75
+ else:
76
+ storage_provider = await conversation_settings.get_storage_provider()
77
+ await build_transient_secondary_indexes(conversation, conversation_settings)
78
+ await build_related_terms_index(
79
+ conversation, conversation_settings.related_term_index_settings
80
+ )
81
+ if conversation.secondary_indexes is not None:
82
+ await build_message_index(
83
+ conversation,
84
+ storage_provider,
85
+ )
86
+
87
+
88
+ async def build_transient_secondary_indexes[
89
+ TMessage: IMessage, TTermToSemanticRefIndex: ITermToSemanticRefIndex
90
+ ](
91
+ conversation: IConversation[TMessage, TTermToSemanticRefIndex],
92
+ settings: ConversationSettings,
93
+ ) -> None:
94
+ if conversation.secondary_indexes is None:
95
+ conversation.secondary_indexes = await ConversationSecondaryIndexes.create(
96
+ await settings.get_storage_provider(),
97
+ (settings.related_term_index_settings),
98
+ )
99
+ await build_property_index(conversation)
100
+ await build_timestamp_index(conversation)