flo-ai 0.0.5.dev3__tar.gz → 0.0.5.dev5__tar.gz

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 (58) hide show
  1. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/PKG-INFO +1 -1
  2. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_node.py +69 -1
  3. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/parsers/flo_json_parser.py +64 -19
  4. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/pyproject.toml +1 -1
  5. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/LICENSE +0 -0
  6. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/README.md +0 -0
  7. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/__init__.py +0 -0
  8. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/builders/__init__.py +0 -0
  9. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/builders/yaml_builder.py +0 -0
  10. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/callbacks/__init__.py +0 -0
  11. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/callbacks/flo_callbacks.py +0 -0
  12. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/callbacks/flo_execution_logger.py +0 -0
  13. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/common/README.md +0 -0
  14. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/common/__init__.py +0 -0
  15. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/common/flo_langchain_logger.py +0 -0
  16. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/common/flo_logger.py +0 -0
  17. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/constants/__init__.py +0 -0
  18. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/constants/common_constants.py +0 -0
  19. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/constants/flo_node_contants.py +0 -0
  20. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/constants/prompt_constants.py +0 -0
  21. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/core.py +0 -0
  22. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/error/flo_exception.py +0 -0
  23. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/factory/agent_factory.py +0 -0
  24. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/helpers/utils.py +0 -0
  25. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/__init__.py +0 -0
  26. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/delegate.py +0 -0
  27. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/exception.py +0 -0
  28. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_agent.py +0 -0
  29. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_delegation_agent.py +0 -0
  30. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_executable.py +0 -0
  31. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_llm_agent.py +0 -0
  32. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_member.py +0 -0
  33. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_reflection_agent.py +0 -0
  34. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_routed_team.py +0 -0
  35. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_team.py +0 -0
  36. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/models/flo_tool_agent.py +0 -0
  37. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/parsers/flo_parser.py +0 -0
  38. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/parsers/flo_pydantic_parser.py +0 -0
  39. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/retrievers/__init__.py +0 -0
  40. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/retrievers/flo_compression_pipeline.py +0 -0
  41. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/retrievers/flo_multi_query.py +0 -0
  42. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/retrievers/flo_retriever.py +0 -0
  43. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/router/__init__.py +0 -0
  44. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/router/flo_linear.py +0 -0
  45. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/router/flo_llm_router.py +0 -0
  46. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/router/flo_router.py +0 -0
  47. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/router/flo_router_factory.py +0 -0
  48. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/router/flo_supervisor.py +0 -0
  49. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/state/__init__.py +0 -0
  50. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/state/flo_data_collector.py +0 -0
  51. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/state/flo_kv_collector.py +0 -0
  52. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/state/flo_session.py +0 -0
  53. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/state/flo_state.py +0 -0
  54. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/storage/data_collector.py +0 -0
  55. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/tools/__init__.py +0 -0
  56. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/tools/flo_tool.py +0 -0
  57. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/yaml/config.py +0 -0
  58. {flo_ai-0.0.5.dev3 → flo_ai-0.0.5.dev5}/flo_ai/yaml/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flo-ai
3
- Version: 0.0.5.dev3
3
+ Version: 0.0.5.dev5
4
4
  Summary: A easy way to create structured AI agents
5
5
  License: MIT
6
6
  Author: vizsatiz
@@ -25,15 +25,22 @@ class FloNode:
25
25
  name: str,
26
26
  kind: ExecutableType,
27
27
  delegate: Optional[Delegate] = None,
28
+ async_func: functools.partial = None,
28
29
  ) -> None:
29
30
  self.name = name
30
31
  self.func = func
31
32
  self.kind: ExecutableType = kind
32
33
  self.delegate = delegate
34
+ self.async_func = async_func
33
35
 
34
36
  def invoke(self, query, config):
35
37
  return self.func({STATE_NAME_MESSAGES: [HumanMessage(content=query)]})
36
38
 
39
+ async def ainvoke(self, query, config):
40
+ return await self.async_func(
41
+ {STATE_NAME_MESSAGES: [HumanMessage(content=query)]}
42
+ )
43
+
37
44
  class Builder:
38
45
  def __init__(self, session: FloSession) -> None:
39
46
  self.session = session
@@ -47,7 +54,17 @@ class FloNode:
47
54
  model_name=flo_agent.model_name,
48
55
  data_collector=flo_agent.data_collector,
49
56
  )
50
- return FloNode(agent_func, flo_agent.name, flo_agent.type)
57
+ agent_func_async = functools.partial(
58
+ FloNode.Builder.__async_teamflo_agent_node,
59
+ agent=flo_agent.runnable,
60
+ name=flo_agent.name,
61
+ session=self.session,
62
+ model_name=flo_agent.model_name,
63
+ data_collector=flo_agent.data_collector,
64
+ )
65
+ return FloNode(
66
+ agent_func, flo_agent.name, flo_agent.type, async_func=agent_func_async
67
+ )
51
68
 
52
69
  def build_from_reflection(self, flo_agent: FloReflectionAgent) -> 'FloNode':
53
70
  agent_func = functools.partial(
@@ -154,6 +171,57 @@ class FloNode:
154
171
  ]
155
172
  return {STATE_NAME_MESSAGES: [AIMessage(content=output, name=name)]}
156
173
 
174
+ @staticmethod
175
+ async def __async_teamflo_agent_node(
176
+ state: TeamFloAgentState,
177
+ agent: AgentExecutor,
178
+ name: str,
179
+ session: FloSession,
180
+ model_name: str,
181
+ data_collector: Optional[FloDataCollector] = None,
182
+ ):
183
+ agent_cbs: List[FloAgentCallback] = FloNode.Builder.__filter_callbacks(
184
+ session, FloAgentCallback
185
+ )
186
+ flo_cbs: List[FloCallback] = FloNode.Builder.__filter_callbacks(
187
+ session, FloCallback
188
+ )
189
+ [
190
+ callback.on_agent_start(name, model_name, state['messages'], **{})
191
+ for callback in agent_cbs
192
+ ]
193
+ [
194
+ callback.on_agent_start(name, model_name, state['messages'], **{})
195
+ for callback in flo_cbs
196
+ ]
197
+ try:
198
+ result = await agent.ainvoke(state)
199
+ output = result if isinstance(result, str) else result['output']
200
+ if data_collector is not None:
201
+ get_logger().info(
202
+ 'appending output to data collector', session=session
203
+ )
204
+ data_collector.append(output)
205
+ except Exception as e:
206
+ [
207
+ callback.on_agent_error(name, model_name, e, **{})
208
+ for callback in agent_cbs
209
+ ]
210
+ [
211
+ callback.on_agent_error(name, model_name, e, **{})
212
+ for callback in flo_cbs
213
+ ]
214
+ raise e
215
+ [
216
+ callback.on_agent_end(name, model_name, output, **{})
217
+ for callback in agent_cbs
218
+ ]
219
+ [
220
+ callback.on_agent_start(name, model_name, output, **{})
221
+ for callback in flo_cbs
222
+ ]
223
+ return {STATE_NAME_MESSAGES: [AIMessage(content=output, name=name)]}
224
+
157
225
  @staticmethod
158
226
  def __filter_callbacks(session: FloSession, type: Type):
159
227
  cbs = session.callbacks
@@ -18,6 +18,7 @@ class ParseContract:
18
18
  class FloJsonParser(FloParser):
19
19
  def __init__(self, parse_contract: ParseContract):
20
20
  self.contract = parse_contract
21
+ self._cached_models = {}
21
22
  super().__init__()
22
23
 
23
24
  def __dict_list_to_csv_string(self, data):
@@ -35,30 +36,76 @@ class FloJsonParser(FloParser):
35
36
 
36
37
  return f'```\n{csv_string}```'
37
38
 
38
- def __create_contract_from_json(self) -> BaseModel:
39
+ def __create_nested_model(
40
+ self, field_def: Dict[str, Any], model_name: str
41
+ ) -> BaseModel:
42
+ """Creates a nested Pydantic model for object types"""
43
+ if model_name in self._cached_models:
44
+ return self._cached_models[model_name]
45
+
46
+ nested_fields = {}
47
+ for nested_field in field_def['fields']:
48
+ nested_type = self.__get_field_type_annotation(
49
+ nested_field, f"{model_name}_{nested_field['name']}"
50
+ )
51
+ field_description = nested_field['description']
52
+ nested_fields[nested_field['name']] = (
53
+ nested_type,
54
+ Field(..., description=field_description),
55
+ )
56
+
57
+ NestedModel = create_model(model_name, **nested_fields)
58
+ self._cached_models[model_name] = NestedModel
59
+ return NestedModel
60
+
61
+ def __get_field_type_annotation(
62
+ self, field: Dict[str, Any], model_name: str
63
+ ) -> Any:
64
+ """Determines the type annotation for a field, handling nested objects"""
39
65
  type_mapping = {
40
66
  'str': str,
41
67
  'int': int,
42
68
  'bool': bool,
43
69
  'float': float,
44
- 'literal': Literal,
70
+ 'literal': self.__create_literal_type,
71
+ 'object': lambda f: self.__create_nested_model(f, model_name),
72
+ 'array': lambda f: List[
73
+ self.__get_field_type_annotation(f['items'], f'{model_name}_item')
74
+ ],
45
75
  }
76
+
77
+ field_type = field['type']
78
+ type_handler = type_mapping.get(field_type)
79
+
80
+ if type_handler is None:
81
+ raise ValueError(f'Unsupported type: {field_type}')
82
+
83
+ return (
84
+ type_handler(field)
85
+ if field_type in ['literal', 'object', 'array']
86
+ else type_handler
87
+ )
88
+
89
+ def __create_literal_type(self, field: Dict[str, Any]) -> Any:
90
+ """Creates a Literal type from field definition"""
91
+ literal_values = field.get('values', [])
92
+ if not literal_values:
93
+ raise ValueError(
94
+ f"Field '{field['name']}' of type 'literal' must specify 'values'."
95
+ )
96
+ literals = [literal_value['value'] for literal_value in literal_values]
97
+ return Literal[tuple(literals)]
98
+
99
+ def __create_contract_from_json(self) -> BaseModel:
46
100
  pydantic_fields = {}
47
101
  for field in self.contract.fields:
48
- field_type = field['type']
49
- if field_type == 'literal':
102
+ field_type = self.__get_field_type_annotation(
103
+ field, f"{self.contract.name}_{field['name']}"
104
+ )
105
+
106
+ if field['type'] == 'literal':
50
107
  literal_values = field.get('values', [])
51
- if not literal_values:
52
- raise ValueError(
53
- f"Field '{field['name']}' of type 'literal' must specify 'values'."
54
- )
55
- literals = [literal_value['value'] for literal_value in literal_values]
56
- field_type_annotation = Literal[tuple(literals)]
57
- default_prompt = (
58
- field['default_value_prompt']
59
- if 'default_value_prompt' in field
60
- else ''
61
- )
108
+ default_prompt = field.get('default_value_prompt', '')
62
109
  field_description = f"""
63
110
  {field['description']}
64
111
  Following are the list of possibles values and its correponding description:
@@ -68,13 +115,10 @@ class FloJsonParser(FloParser):
68
115
  {default_prompt}
69
116
  """
70
117
  else:
71
- field_type_annotation = type_mapping.get(field_type)
72
- if field_type_annotation is None:
73
- raise ValueError(f'Unsupported type: {field_type}')
74
118
  field_description = field['description']
75
119
 
76
120
  pydantic_fields[field['name']] = (
77
- field_type_annotation,
121
+ field_type,
78
122
  Field(..., description=field_description),
79
123
  )
80
124
 
@@ -86,6 +130,7 @@ class FloJsonParser(FloParser):
86
130
  pydantic_object=self.__create_contract_from_json()
87
131
  ).get_format_instructions()
88
132
 
133
+ @staticmethod
89
134
  def create(json_dict: Optional[Dict] = None, json_path: Optional[str] = None):
90
135
  return FloJsonParser.Builder(json_dict=json_dict, json_path=json_path).build()
91
136
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "flo-ai"
3
- version = "0.0.5-dev3"
3
+ version = "0.0.5-dev5"
4
4
  description = "A easy way to create structured AI agents"
5
5
  authors = ["vizsatiz <vishnu@rootfor.xyz>"]
6
6
  license = "MIT"
File without changes
File without changes
File without changes