mage-ai 0.9.8__py3-none-any.whl → 0.9.9__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 mage-ai might be problematic. Click here for more details.

Files changed (158) hide show
  1. mage_ai/ai/constants.py +1 -0
  2. mage_ai/ai/generator.py +6 -0
  3. mage_ai/ai/{gen_doc_for_pipeline.py → generator_cmds.py} +5 -0
  4. mage_ai/ai/llm_pipeline_wizard.py +108 -3
  5. mage_ai/api/policies/BlockPolicy.py +1 -0
  6. mage_ai/api/policies/BlockTemplatePolicy.py +9 -0
  7. mage_ai/api/policies/LlmPolicy.py +3 -2
  8. mage_ai/api/policies/OauthAccessTokenPolicy.py +31 -0
  9. mage_ai/api/policies/PipelinePolicy.py +1 -0
  10. mage_ai/api/policies/ProjectPolicy.py +9 -0
  11. mage_ai/api/policies/SearchResultPolicy.py +32 -0
  12. mage_ai/api/policies/VariablePolicy.py +8 -0
  13. mage_ai/api/presenters/BlockTemplatePresenter.py +1 -0
  14. mage_ai/api/presenters/OauthAccessTokenPresenter.py +9 -0
  15. mage_ai/api/presenters/ProjectPresenter.py +2 -0
  16. mage_ai/api/presenters/SearchResultPresenter.py +73 -0
  17. mage_ai/api/resources/BlockResource.py +43 -4
  18. mage_ai/api/resources/BlockTemplateResource.py +15 -2
  19. mage_ai/api/resources/CustomTemplateResource.py +15 -3
  20. mage_ai/api/resources/FileContentResource.py +8 -1
  21. mage_ai/api/resources/FileResource.py +22 -2
  22. mage_ai/api/resources/OauthAccessTokenResource.py +24 -0
  23. mage_ai/api/resources/PipelineResource.py +70 -2
  24. mage_ai/api/resources/ProjectResource.py +15 -1
  25. mage_ai/api/resources/SearchResultResource.py +68 -0
  26. mage_ai/api/resources/VariableResource.py +25 -14
  27. mage_ai/cache/base.py +3 -0
  28. mage_ai/cache/block_action_object/__init__.py +282 -0
  29. mage_ai/cache/block_action_object/constants.py +4 -0
  30. mage_ai/cache/constants.py +1 -0
  31. mage_ai/data_integrations/destinations/constants.py +2 -0
  32. mage_ai/data_preparation/executors/k8s_pipeline_executor.py +1 -1
  33. mage_ai/data_preparation/models/block/__init__.py +20 -1
  34. mage_ai/data_preparation/models/block/dbt/utils/__init__.py +1 -0
  35. mage_ai/data_preparation/models/custom_templates/custom_block_template.py +8 -3
  36. mage_ai/data_preparation/models/custom_templates/utils.py +6 -3
  37. mage_ai/data_preparation/models/file.py +3 -0
  38. mage_ai/data_preparation/models/pipeline.py +10 -1
  39. mage_ai/data_preparation/models/{project.py → project/__init__.py} +17 -0
  40. mage_ai/data_preparation/models/project/constants.py +5 -0
  41. mage_ai/data_preparation/repo_manager.py +9 -6
  42. mage_ai/data_preparation/templates/constants.py +478 -1
  43. mage_ai/data_preparation/templates/template.py +9 -1
  44. mage_ai/orchestration/db/__init__.py +25 -0
  45. mage_ai/orchestration/pipeline_scheduler.py +23 -0
  46. mage_ai/server/constants.py +1 -1
  47. mage_ai/server/frontend_dist/404.html +2 -2
  48. mage_ai/server/frontend_dist/404.html.html +2 -2
  49. mage_ai/server/frontend_dist/_next/static/OwvTROmputQCA1Z9HEGDv/_buildManifest.js +1 -0
  50. mage_ai/server/frontend_dist/_next/static/chunks/{1005-ce36fe7ed460d006.js → 1005-16c1a6678de5311e.js} +1 -1
  51. mage_ai/server/frontend_dist/_next/static/chunks/1424-e22139f33196c5c1.js +1 -0
  52. mage_ai/server/frontend_dist/_next/static/chunks/1484-a76b2c31e4808379.js +1 -0
  53. mage_ai/server/frontend_dist/_next/static/chunks/2485-b569baad92049d6b.js +1 -0
  54. mage_ai/server/frontend_dist/_next/static/chunks/{2786-d8b593e5d7c42665.js → 2786-acce6ea0d9b4898e.js} +1 -1
  55. mage_ai/server/frontend_dist/_next/static/chunks/3654-573457b62efff6e2.js +1 -0
  56. mage_ai/server/frontend_dist/_next/static/chunks/3881-0eb04f7f7a244347.js +1 -0
  57. mage_ai/server/frontend_dist/_next/static/chunks/{4317-b112fe7bb532b998.js → 4317-3fe63fc9401685d6.js} +1 -1
  58. mage_ai/server/frontend_dist/_next/static/chunks/{4822-52d9d661b6bd1ae9.js → 4822-045cc7cdd7c95163.js} +1 -1
  59. mage_ai/server/frontend_dist/_next/static/chunks/{547-14029bdacc0ed267.js → 547-4ad2cdae967055b6.js} +1 -1
  60. mage_ai/server/frontend_dist/_next/static/chunks/6299-cf188c1b7a1bc33c.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/{7815-6dc55b5fd5d1f48a.js → 7815-fbd99c8f259d9e8b.js} +1 -1
  62. mage_ai/server/frontend_dist/_next/static/chunks/{8312-cdc4d6c3b9f53099.js → 8312-c88a3b1012e5448b.js} +1 -1
  63. mage_ai/server/frontend_dist/_next/static/chunks/{8952-492bf0e29d215ddd.js → 8952-e94a7334fcd5c68b.js} +1 -1
  64. mage_ai/server/frontend_dist/_next/static/chunks/9055-d0d25298cb5f4e45.js +1 -0
  65. mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-c7557dc9e725825e.js → _app-fa38a24707c76411.js} +1 -1
  66. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-b9dac983c75798f2.js +1 -0
  67. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{settings-17bb362b9683079c.js → settings-453aaa7bf78f8101.js} +1 -1
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/{[user]-bfa53c0ee79920a0.js → [user]-3b502aa6d1a04cad.js} +1 -1
  69. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/{new-2f7e6bf8e2a37380.js → new-dd41d718cbb5990c.js} +1 -1
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-ec748f838b7b8fad.js +1 -0
  71. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-bcc24120f5911f76.js +1 -0
  72. mage_ai/server/frontend_dist/_next/static/chunks/pages/{overview-8ffbc4b0e8a43266.js → overview-6f20b9e9cbec91d6.js} +1 -1
  73. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-373f6b8c9161e819.js → [...slug]-55212dfc15881ef2.js} +1 -1
  74. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{backfills-226bf0c5c1bfe004.js → backfills-6b4a82cd0516e121.js} +1 -1
  75. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-0705c99df236ec8a.js +1 -0
  76. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{logs-4ade07836fd577c9.js → logs-c294f5d74bd2d50f.js} +1 -1
  77. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-fd9eb711e89425e9.js → monitors-1b9e4abc54842cdf.js} +1 -1
  78. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{runs-027666ed18d3151e.js → runs-17ebe87e94242ae5.js} +1 -1
  79. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-48b60ca236a26818.js +1 -0
  80. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{syncs-de58e6b91e5e4552.js → syncs-5153f4665aaf8b17.js} +1 -1
  81. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/{[...slug]-432843576e1ed09e.js → [...slug]-1306e85191f6b47c.js} +1 -1
  82. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-ae31b1d0d8a4634d.js → triggers-2e731d343a26d46a.js} +1 -1
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-0fab737dbc9074fc.js +1 -0
  84. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-b2354688508b0755.js +1 -0
  85. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-a4f01b5c429757cc.js → users-6522c963087f18e8.js} +1 -1
  86. mage_ai/server/frontend_dist/_next/static/chunks/pages/{sign-in-1140f8ee7e89381a.js → sign-in-7dcd1257ca9660bb.js} +1 -1
  87. mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/{[...slug]-f59b3f04c5a49351.js → [...slug]-78a07e7fe8973811.js} +1 -1
  88. mage_ai/server/frontend_dist/_next/static/chunks/pages/{templates-dbb209ce131390a9.js → templates-19df643f52679d5a.js} +1 -1
  89. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-a1cf445565b68809.js +1 -0
  90. mage_ai/server/frontend_dist/files.html +2 -2
  91. mage_ai/server/frontend_dist/index.html +2 -2
  92. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  93. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  94. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  95. mage_ai/server/frontend_dist/manage/users.html +2 -2
  96. mage_ai/server/frontend_dist/manage.html +2 -2
  97. mage_ai/server/frontend_dist/overview.html +2 -2
  98. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  99. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  100. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  101. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  102. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  103. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  104. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  105. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  106. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  107. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  108. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  109. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  110. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  111. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  112. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  113. mage_ai/server/frontend_dist/pipelines.html +2 -2
  114. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  115. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  116. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  117. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  118. mage_ai/server/frontend_dist/settings.html +2 -2
  119. mage_ai/server/frontend_dist/sign-in.html +16 -16
  120. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  121. mage_ai/server/frontend_dist/templates.html +2 -2
  122. mage_ai/server/frontend_dist/terminal.html +2 -2
  123. mage_ai/server/frontend_dist/test.html +2 -2
  124. mage_ai/server/frontend_dist/triggers.html +2 -2
  125. mage_ai/server/frontend_dist/version-control.html +2 -2
  126. mage_ai/server/server.py +5 -0
  127. mage_ai/services/search/__init__.py +0 -0
  128. mage_ai/services/search/block_action_objects.py +33 -0
  129. mage_ai/services/search/constants.py +1 -0
  130. mage_ai/shared/array.py +7 -0
  131. mage_ai/shared/parsers.py +11 -2
  132. mage_ai/tests/shared/test_parsers.py +73 -0
  133. mage_ai/usage_statistics/constants.py +1 -0
  134. mage_ai/usage_statistics/logger.py +19 -1
  135. {mage_ai-0.9.8.dist-info → mage_ai-0.9.9.dist-info}/METADATA +9 -7
  136. {mage_ai-0.9.8.dist-info → mage_ai-0.9.9.dist-info}/RECORD +142 -129
  137. mage_ai/server/frontend_dist/_next/static/RcIgkp9pBXE1Rb4tOGR1L/_buildManifest.js +0 -1
  138. mage_ai/server/frontend_dist/_next/static/chunks/1424-de97c5aa0477894b.js +0 -1
  139. mage_ai/server/frontend_dist/_next/static/chunks/1484-c9d6bc33227070dd.js +0 -1
  140. mage_ai/server/frontend_dist/_next/static/chunks/2485-86c97f516c1abb9f.js +0 -1
  141. mage_ai/server/frontend_dist/_next/static/chunks/3215-c2f5f19b650f9a50.js +0 -1
  142. mage_ai/server/frontend_dist/_next/static/chunks/3654-bff4740b63cf280c.js +0 -1
  143. mage_ai/server/frontend_dist/_next/static/chunks/3881-7f121dbbe6e273cd.js +0 -1
  144. mage_ai/server/frontend_dist/_next/static/chunks/6299-97f283be01adf6a8.js +0 -1
  145. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-0df5a20d6f1aa606.js +0 -1
  146. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-1f6cb7656299cbd1.js +0 -1
  147. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-4894eabb442a039c.js +0 -1
  148. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-a9bd86bee73b5762.js +0 -1
  149. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-cf51793c2112915c.js +0 -1
  150. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-f1131ffe0d2a4a06.js +0 -1
  151. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-170943ca00445486.js +0 -1
  152. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-2ecda1f1437013f2.js +0 -1
  153. /mage_ai/server/frontend_dist/_next/static/{RcIgkp9pBXE1Rb4tOGR1L → OwvTROmputQCA1Z9HEGDv}/_middlewareManifest.js +0 -0
  154. /mage_ai/server/frontend_dist/_next/static/{RcIgkp9pBXE1Rb4tOGR1L → OwvTROmputQCA1Z9HEGDv}/_ssgManifest.js +0 -0
  155. {mage_ai-0.9.8.dist-info → mage_ai-0.9.9.dist-info}/LICENSE +0 -0
  156. {mage_ai-0.9.8.dist-info → mage_ai-0.9.9.dist-info}/WHEEL +0 -0
  157. {mage_ai-0.9.8.dist-info → mage_ai-0.9.9.dist-info}/entry_points.txt +0 -0
  158. {mage_ai-0.9.8.dist-info → mage_ai-0.9.9.dist-info}/top_level.txt +0 -0
mage_ai/ai/constants.py CHANGED
@@ -5,3 +5,4 @@ class LLMUseCase(str, Enum):
5
5
  GENERATE_COMMENT_FOR_BLOCK = 'generate_comment_for_block'
6
6
  GENERATE_DOC_FOR_BLOCK = 'generate_doc_for_block'
7
7
  GENERATE_DOC_FOR_PIPELINE = 'generate_doc_for_pipeline'
8
+ GENERATE_BLOCK_WITH_DESCRIPTION = 'generate_block_with_description'
mage_ai/ai/generator.py CHANGED
@@ -24,5 +24,11 @@ class Generator:
24
24
  return await LLMPipelineWizard().async_generate_pipeline_documentation(
25
25
  pipeline_uuid,
26
26
  )
27
+ elif use_case == LLMUseCase.GENERATE_BLOCK_WITH_DESCRIPTION:
28
+ from mage_ai.ai.llm_pipeline_wizard import LLMPipelineWizard
29
+
30
+ return await LLMPipelineWizard().async_generate_block_with_description(
31
+ request.get('block_description'),
32
+ )
27
33
 
28
34
  raise Exception(f'Use case {use_case} is not supported yet.')
@@ -42,5 +42,10 @@ def generate_pipeline_documentation(project_path: str = PROJECT_NAME_DEFAULT,
42
42
  ))['pipeline_doc'])
43
43
 
44
44
 
45
+ @app.command()
46
+ def generate_block_with_description(block_description: str):
47
+ print(asyncio.run(LLMPipelineWizard().async_generate_block_with_description(block_description)))
48
+
49
+
45
50
  if __name__ == '__main__':
46
51
  app()
@@ -1,17 +1,27 @@
1
1
  import asyncio
2
+ import json
3
+ import os
2
4
 
5
+ import openai
3
6
  from langchain.chains import LLMChain
4
7
  from langchain.llms import OpenAI
5
8
  from langchain.prompts import PromptTemplate
6
9
 
10
+ from mage_ai.data_cleaner.transformer_actions.constants import ActionType, Axis
7
11
  from mage_ai.data_preparation.models.block import Block
8
12
  from mage_ai.data_preparation.models.constants import (
9
13
  NON_PIPELINE_EXECUTABLE_BLOCK_TYPES,
10
14
  BlockLanguage,
11
15
  BlockType,
16
+ PipelineType,
12
17
  )
13
18
  from mage_ai.data_preparation.models.pipeline import Pipeline
14
- from mage_ai.data_preparation.repo_manager import get_repo_path
19
+ from mage_ai.data_preparation.repo_manager import get_repo_config, get_repo_path
20
+ from mage_ai.data_preparation.templates.template import fetch_template_source
21
+ from mage_ai.io.base import DataSource
22
+ from mage_ai.server.logger import Logger
23
+
24
+ logger = Logger().new_server_logger(__name__)
15
25
 
16
26
  BLOCK_LANGUAGE_TO_FILE_TYPE_VARIABLE = {
17
27
  BlockLanguage.MARKDOWN: 'markdown script',
@@ -39,11 +49,58 @@ Write a detailed summarization of the data pipeline based on the content provide
39
49
  ```{block_content}```
40
50
  """
41
51
  TRANSFORMERS_FOLDER = 'transformers'
52
+ CLASSIFICATION_FUNCTION_NAME = "classify_description"
53
+ TEMPLATE_CLASSIFICATION_FUNCTION = [
54
+ {
55
+ "name": CLASSIFICATION_FUNCTION_NAME,
56
+ "description": "Classify the code description provided into following properties.",
57
+ "parameters": {
58
+ "type": "object",
59
+ "properties": {
60
+ BlockType.__name__: {
61
+ "type": "string",
62
+ "description": "Type of the code block. It either "
63
+ "loads data from a source, export data to a source "
64
+ "or transform data from one format to another.",
65
+ "enum": ["data_exporter", "data_loader", "transformer"]
66
+ },
67
+ BlockLanguage.__name__: {
68
+ "type": "string",
69
+ "description": "Programming language of the code block.",
70
+ "enum": [type.name.lower() for type in BlockLanguage]
71
+ },
72
+ PipelineType.__name__: {
73
+ "type": "string",
74
+ "description": "Type of pipeline description to build.",
75
+ "enum": [type.name.lower() for type in PipelineType]
76
+ },
77
+ ActionType.__name__: {
78
+ "type": "string",
79
+ "description": f"If {BlockType.__name__} is transformer, "
80
+ f"{ActionType.__name__} specifies what kind "
81
+ "of action the code performs.",
82
+ "enum": [type.name.lower() for type in ActionType]
83
+ },
84
+ DataSource.__name__: {
85
+ "type": "string",
86
+ "description": f"If {BlockType.__name__} is data_loader or "
87
+ f"data_exporter, {DataSource.__name__} field specify "
88
+ "where the data loads from or exports to.",
89
+ "enum": [type.name.lower() for type in DataSource]
90
+ },
91
+ },
92
+ "required": [BlockType.__name__, BlockLanguage.__name__, PipelineType.__name__],
93
+ },
94
+ }
95
+ ]
42
96
 
43
97
 
44
98
  class LLMPipelineWizard:
45
99
  def __init__(self):
46
- self.llm = OpenAI(temperature=0)
100
+ repo_config = get_repo_config()
101
+ openai_api_key = repo_config.openai_api_key or os.getenv('OPENAI_API_KEY')
102
+ openai.api_key = openai_api_key
103
+ self.llm = OpenAI(openai_api_key=openai_api_key, temperature=0)
47
104
 
48
105
  async def __async_llm_generate_documentation(
49
106
  self,
@@ -68,6 +125,54 @@ class LLMPipelineWizard:
68
125
  purpose=purpose,
69
126
  add_on_prompt=add_on_prompt)
70
127
 
128
+ def __load_template_params(self, function_args: json):
129
+ block_type = BlockType(function_args[BlockType.__name__].lower())
130
+ block_language = BlockLanguage(
131
+ function_args.get(BlockLanguage.__name__, "python").lower())
132
+ pipeline_type = PipelineType(function_args.get(PipelineType.__name__, "python").lower())
133
+ config = {}
134
+ config['action_type'] = function_args.get(ActionType.__name__, None)
135
+ if config['action_type']:
136
+ if config['action_type'] in [
137
+ ActionType.FILTER,
138
+ ActionType.DROP_DUPLICATE,
139
+ ActionType.REMOVE,
140
+ ActionType.SORT
141
+ ]:
142
+ config['axis'] = Axis.ROW
143
+ else:
144
+ config['axis'] = Axis.COLUMN
145
+ config['data_source'] = function_args.get(DataSource.__name__, None)
146
+ return block_type, block_language, pipeline_type, config
147
+
148
+ async def async_generate_block_with_description(self, block_description: str) -> dict:
149
+ messages = [{"role": "user", "content": block_description}]
150
+ response = await openai.ChatCompletion.acreate(
151
+ model="gpt-3.5-turbo-0613",
152
+ messages=messages,
153
+ functions=TEMPLATE_CLASSIFICATION_FUNCTION,
154
+ function_call={"name": CLASSIFICATION_FUNCTION_NAME}, # explicitly set function call
155
+ )
156
+ response_message = response["choices"][0]["message"]
157
+ if response_message.get("function_call"):
158
+ function_args = json.loads(response_message["function_call"]["arguments"])
159
+ block_type, block_language, pipeline_type, config = self.__load_template_params(
160
+ function_args)
161
+ return dict(
162
+ block_type=block_type,
163
+ configuration=config,
164
+ content=fetch_template_source(
165
+ block_type=block_type,
166
+ config=config,
167
+ language=block_language,
168
+ pipeline_type=pipeline_type,
169
+ ),
170
+ language=block_language,
171
+ )
172
+ else:
173
+ logger.error("Failed to interpret the description as a block template.")
174
+ return None
175
+
71
176
  async def async_generate_pipeline_documentation(
72
177
  self,
73
178
  pipeline_uuid: str,
@@ -92,7 +197,7 @@ class LLMPipelineWizard:
92
197
  chain = LLMChain(llm=self.llm, prompt=prompt_template)
93
198
  pipeline_doc = chain.run(block_content=block_docs_content)
94
199
  return dict(
95
- block_content=block_docs,
200
+ block_docs=block_docs,
96
201
  pipeline_doc=pipeline_doc,
97
202
  )
98
203
 
@@ -56,6 +56,7 @@ BlockPolicy.allow_read([
56
56
  ], condition=lambda policy: policy.has_at_least_viewer_role())
57
57
 
58
58
  BlockPolicy.allow_write([
59
+ 'block_action_object',
59
60
  'color',
60
61
  'config',
61
62
  'configuration',
@@ -25,3 +25,12 @@ BlockTemplatePolicy.allow_read(BlockTemplatePresenter.default_attributes + [], s
25
25
  constants.DETAIL,
26
26
  constants.LIST,
27
27
  ], condition=lambda policy: policy.has_at_least_viewer_role())
28
+
29
+
30
+ BlockTemplatePolicy.allow_query([
31
+ 'show_all',
32
+ ], scopes=[
33
+ OauthScope.CLIENT_PRIVATE,
34
+ ], on_action=[
35
+ constants.LIST,
36
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
@@ -23,9 +23,10 @@ LlmPolicy.allow_actions([
23
23
  OauthScope.CLIENT_PRIVATE,
24
24
  ], condition=lambda policy: policy.has_at_least_editor_role())
25
25
 
26
+
26
27
  LlmPolicy.allow_read([
28
+ 'response',
27
29
  'use_case',
28
- 'request',
29
30
  ], scopes=[
30
31
  OauthScope.CLIENT_PRIVATE,
31
32
  ], on_action=[
@@ -34,8 +35,8 @@ LlmPolicy.allow_read([
34
35
 
35
36
 
36
37
  LlmPolicy.allow_write([
38
+ 'request',
37
39
  'use_case',
38
- 'response',
39
40
  ], scopes=[
40
41
  OauthScope.CLIENT_PRIVATE,
41
42
  ], on_action=[
@@ -0,0 +1,31 @@
1
+ from mage_ai.api.oauth_scope import OauthScope
2
+ from mage_ai.api.operations import constants
3
+ from mage_ai.api.policies.BasePolicy import BasePolicy
4
+ from mage_ai.api.presenters.OauthAccessTokenPresenter import OauthAccessTokenPresenter
5
+
6
+
7
+ class OauthAccessTokenPolicy(BasePolicy):
8
+ pass
9
+
10
+
11
+ OauthAccessTokenPolicy.allow_actions([
12
+ constants.LIST,
13
+ ], scopes=[
14
+ OauthScope.CLIENT_PRIVATE,
15
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
16
+
17
+
18
+ OauthAccessTokenPolicy.allow_read(OauthAccessTokenPresenter.default_attributes, scopes=[
19
+ OauthScope.CLIENT_PRIVATE,
20
+ ], on_action=[
21
+ constants.LIST,
22
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
23
+
24
+
25
+ OauthAccessTokenPolicy.allow_query([
26
+ 'show_all',
27
+ ], scopes=[
28
+ OauthScope.CLIENT_PRIVATE,
29
+ ], on_action=[
30
+ constants.LIST,
31
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
@@ -96,6 +96,7 @@ PipelinePolicy.allow_write([
96
96
  'callbacks',
97
97
  'conditionals',
98
98
  'extensions',
99
+ 'llm',
99
100
  'schedules',
100
101
  ] + PipelinePresenter.default_attributes, scopes=[
101
102
  OauthScope.CLIENT_PRIVATE,
@@ -35,3 +35,12 @@ ProjectPolicy.allow_write([
35
35
  ], on_action=[
36
36
  constants.UPDATE,
37
37
  ], condition=lambda policy: policy.has_at_least_viewer_role())
38
+
39
+ ProjectPolicy.allow_write([
40
+ 'features',
41
+ 'openai_api_key',
42
+ ], scopes=[
43
+ OauthScope.CLIENT_PRIVATE,
44
+ ], on_action=[
45
+ constants.UPDATE,
46
+ ], condition=lambda policy: policy.has_at_least_editor_role())
@@ -0,0 +1,32 @@
1
+ from mage_ai.api.oauth_scope import OauthScope
2
+ from mage_ai.api.operations import constants
3
+ from mage_ai.api.policies.BasePolicy import BasePolicy
4
+ from mage_ai.api.presenters.SearchResultPresenter import SearchResultPresenter
5
+
6
+
7
+ class SearchResultPolicy(BasePolicy):
8
+ pass
9
+
10
+
11
+ SearchResultPolicy.allow_actions([
12
+ constants.CREATE,
13
+ ], scopes=[
14
+ OauthScope.CLIENT_PRIVATE,
15
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
16
+
17
+ SearchResultPolicy.allow_read(SearchResultPresenter.default_attributes, scopes=[
18
+ OauthScope.CLIENT_PRIVATE,
19
+ ], on_action=[
20
+ constants.CREATE,
21
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
22
+
23
+ SearchResultPolicy.allow_write([
24
+ 'pipeline_type',
25
+ 'query',
26
+ 'ratio',
27
+ 'type',
28
+ ], scopes=[
29
+ OauthScope.CLIENT_PRIVATE,
30
+ ], on_action=[
31
+ constants.CREATE,
32
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
@@ -55,3 +55,11 @@ VariablePolicy.allow_write([
55
55
  constants.CREATE,
56
56
  constants.UPDATE,
57
57
  ], condition=lambda policy: policy.has_at_least_editor_role_and_notebook_edit_access())
58
+
59
+ VariablePolicy.allow_query([
60
+ 'global_only',
61
+ ], scopes=[
62
+ OauthScope.CLIENT_PRIVATE,
63
+ ], on_action=[
64
+ constants.LIST,
65
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
@@ -9,4 +9,5 @@ class BlockTemplatePresenter(BasePresenter):
9
9
  'language',
10
10
  'name',
11
11
  'path',
12
+ 'template_variables',
12
13
  ]
@@ -0,0 +1,9 @@
1
+ from mage_ai.api.presenters.BasePresenter import BasePresenter
2
+
3
+
4
+ class OauthAccessTokenPresenter(BasePresenter):
5
+ default_attributes = [
6
+ 'expires',
7
+ 'token',
8
+ 'user_id',
9
+ ]
@@ -3,9 +3,11 @@ from mage_ai.api.presenters.BasePresenter import BasePresenter
3
3
 
4
4
  class ProjectPresenter(BasePresenter):
5
5
  default_attributes = [
6
+ 'features',
6
7
  'help_improve_mage',
7
8
  'latest_version',
8
9
  'name',
10
+ 'openai_api_key',
9
11
  'project_uuid',
10
12
  'version',
11
13
  ]
@@ -0,0 +1,73 @@
1
+ from mage_ai.api.operations import constants
2
+ from mage_ai.api.presenters.BasePresenter import BasePresenter
3
+ from mage_ai.cache.block_action_object.constants import (
4
+ OBJECT_TYPE_BLOCK_FILE,
5
+ OBJECT_TYPE_CUSTOM_BLOCK_TEMPLATE,
6
+ OBJECT_TYPE_MAGE_TEMPLATE,
7
+ )
8
+ from mage_ai.services.search.constants import SEARCH_TYPE_BLOCK_ACTION_OBJECTS
9
+ from mage_ai.shared.hash import merge_dict
10
+ from mage_ai.shared.strings import remove_extension_from_filename
11
+
12
+
13
+ class SearchResultPresenter(BasePresenter):
14
+ default_attributes = [
15
+ 'results',
16
+ 'type',
17
+ 'uuid',
18
+ ]
19
+
20
+ def present(self, **kwargs):
21
+ display_format = kwargs['format']
22
+
23
+ if constants.CREATE != display_format:
24
+ return self.model
25
+
26
+ results = self.model.get('results', [])
27
+ search_type = self.model.get('type')
28
+ results_transformed = []
29
+
30
+ if SEARCH_TYPE_BLOCK_ACTION_OBJECTS == search_type:
31
+ for result in results:
32
+ block_action_object = result.get('block_action_object')
33
+ object_type = result.get('object_type')
34
+ uuid = result.get('uuid')
35
+
36
+ block_type = None
37
+ description = block_action_object.get('description')
38
+ language = block_action_object.get('language')
39
+ title = None
40
+
41
+ if OBJECT_TYPE_BLOCK_FILE == object_type:
42
+ block_type = block_action_object.get('type')
43
+ u = block_action_object.get('uuid')
44
+ title = ' '.join(list(filter(lambda x: x, [
45
+ remove_extension_from_filename(u).replace('_', ' ') if u else u,
46
+ ])))
47
+ elif OBJECT_TYPE_CUSTOM_BLOCK_TEMPLATE == object_type:
48
+ block_type = block_action_object.get('block_type')
49
+ template_name = block_action_object.get('name')
50
+ template_uuid = block_action_object.get('template_uuid')
51
+ u = template_name or template_uuid
52
+ title = ' '.join(list(filter(lambda x: x, [
53
+ remove_extension_from_filename(u).replace('_', ' ') if u else u,
54
+ ])))
55
+ elif OBJECT_TYPE_MAGE_TEMPLATE == object_type:
56
+ block_type = block_action_object.get('block_type')
57
+ u = block_action_object.get('name')
58
+ title = ' '.join(list(filter(lambda x: x, [
59
+ remove_extension_from_filename(u).replace('_', ' ') if u else u,
60
+ ])))
61
+
62
+ results_transformed.append(dict(
63
+ block_type=block_type,
64
+ description=description,
65
+ language=language,
66
+ object_type=object_type,
67
+ title=title,
68
+ uuid=uuid,
69
+ ))
70
+
71
+ return merge_dict(self.model, dict(
72
+ results=results_transformed,
73
+ ))
@@ -3,6 +3,12 @@ import urllib.parse
3
3
  from mage_ai.api.errors import ApiError
4
4
  from mage_ai.api.resources.GenericResource import GenericResource
5
5
  from mage_ai.cache.block import BlockCache
6
+ from mage_ai.cache.block_action_object import BlockActionObjectCache
7
+ from mage_ai.cache.block_action_object.constants import (
8
+ OBJECT_TYPE_BLOCK_FILE,
9
+ OBJECT_TYPE_CUSTOM_BLOCK_TEMPLATE,
10
+ OBJECT_TYPE_MAGE_TEMPLATE,
11
+ )
6
12
  from mage_ai.data_preparation.models.block import Block
7
13
  from mage_ai.data_preparation.models.block.dbt import DBTBlock
8
14
  from mage_ai.data_preparation.models.block.utils import clean_name
@@ -29,6 +35,31 @@ class BlockResource(GenericResource):
29
35
  content = payload.get('content')
30
36
  language = payload.get('language')
31
37
  name = payload.get('name')
38
+ block_name = name or payload.get('uuid')
39
+
40
+ payload_config = payload.get('config') or {}
41
+
42
+ block_action_object = payload.get('block_action_object')
43
+ if block_action_object:
44
+ object_type = block_action_object.get('object_type')
45
+
46
+ cache_block_action_object = await BlockActionObjectCache.initialize_cache()
47
+ mapping = cache_block_action_object.load_all_data()
48
+ objects_mapping = mapping.get(object_type)
49
+ object_uuid = block_action_object.get('uuid')
50
+ object_from_cache = objects_mapping.get(object_uuid)
51
+
52
+ if OBJECT_TYPE_BLOCK_FILE == object_type:
53
+ block_name = object_from_cache.get('uuid')
54
+ block_type = object_from_cache.get('type')
55
+ language = object_from_cache.get('language')
56
+ elif OBJECT_TYPE_CUSTOM_BLOCK_TEMPLATE == object_type:
57
+ payload_config['custom_template_uuid'] = object_from_cache.get('template_uuid')
58
+ elif OBJECT_TYPE_MAGE_TEMPLATE == object_type:
59
+ block_type = object_from_cache.get('block_type')
60
+ language = object_from_cache.get('language')
61
+ payload_config['template_path'] = object_from_cache.get('path')
62
+ payload_config['template_variables'] = object_from_cache.get('template_variables')
32
63
 
33
64
  """
34
65
  New DBT models include "content" in its block create payload,
@@ -47,9 +78,6 @@ class BlockResource(GenericResource):
47
78
  Please choose a different model name, or add a DBT model by \
48
79
  selecting single model from file.')
49
80
 
50
- payload_config = payload.get('config')
51
-
52
- block_name = name or payload.get('uuid')
53
81
  block_attributes = dict(
54
82
  color=payload.get('color'),
55
83
  config=payload_config,
@@ -104,6 +132,9 @@ class BlockResource(GenericResource):
104
132
  cache = await BlockCache.initialize_cache()
105
133
  cache.add_pipeline(block, pipeline)
106
134
 
135
+ cache_block_action_object = await BlockActionObjectCache.initialize_cache()
136
+ cache_block_action_object.update_block(block)
137
+
107
138
  return self(block, user, **kwargs)
108
139
 
109
140
  @classmethod
@@ -189,10 +220,16 @@ class BlockResource(GenericResource):
189
220
  if pipeline:
190
221
  cache.remove_pipeline(self.model, pipeline.uuid)
191
222
 
223
+ cache_block_action_object = await BlockActionObjectCache.initialize_cache()
224
+ cache_block_action_object.update_block(self.model, remove=True)
225
+
192
226
  return self.model.delete(force=force)
193
227
 
194
228
  @safe_db_query
195
- def update(self, payload, **kwargs):
229
+ async def update(self, payload, **kwargs):
230
+ cache_block_action_object = await BlockActionObjectCache.initialize_cache()
231
+ cache_block_action_object.update_block(self.model, remove=True)
232
+
196
233
  query = kwargs.get('query', {})
197
234
  update_state = query.get('update_state', [False])
198
235
  if update_state:
@@ -202,6 +239,8 @@ class BlockResource(GenericResource):
202
239
  update_state=update_state,
203
240
  )
204
241
 
242
+ cache_block_action_object.update_block(self.model)
243
+
205
244
  async def get_pipelines_from_cache(self):
206
245
  await BlockCache.initialize_cache()
207
246
 
@@ -1,6 +1,10 @@
1
1
  from mage_ai.api.errors import ApiError
2
2
  from mage_ai.api.resources.GenericResource import GenericResource
3
- from mage_ai.data_preparation.templates.constants import TEMPLATES, TEMPLATES_BY_UUID
3
+ from mage_ai.data_preparation.templates.constants import (
4
+ TEMPLATES,
5
+ TEMPLATES_BY_UUID,
6
+ TEMPLATES_ONLY_FOR_V2,
7
+ )
4
8
  from mage_ai.orchestration.db import safe_db_query
5
9
 
6
10
 
@@ -8,8 +12,17 @@ class BlockTemplateResource(GenericResource):
8
12
  @classmethod
9
13
  @safe_db_query
10
14
  def collection(self, query, meta, user, **kwargs):
15
+ show_all = query.get('show_all', [None])
16
+ if show_all:
17
+ show_all = show_all[0]
18
+
19
+ arr = TEMPLATES.copy()
20
+
21
+ if show_all:
22
+ arr += TEMPLATES_ONLY_FOR_V2.copy()
23
+
11
24
  return self.build_result_set(
12
- TEMPLATES,
25
+ arr,
13
26
  user,
14
27
  **kwargs,
15
28
  )
@@ -1,6 +1,7 @@
1
1
  import urllib.parse
2
2
  from mage_ai.api.errors import ApiError
3
3
  from mage_ai.api.resources.GenericResource import GenericResource
4
+ from mage_ai.cache.block_action_object import BlockActionObjectCache
4
5
  from mage_ai.data_preparation.models.custom_templates.constants import (
5
6
  DIRECTORY_FOR_BLOCK_TEMPLATES,
6
7
  DIRECTORY_FOR_PIPELINE_TEMPLATES,
@@ -51,7 +52,7 @@ class CustomTemplateResource(GenericResource):
51
52
  )
52
53
 
53
54
  @classmethod
54
- def create(self, payload, user, **kwargs):
55
+ async def create(self, payload, user, **kwargs):
55
56
  custom_template = None
56
57
  object_type = payload.get(OBJECT_TYPE_KEY)
57
58
  template_uuid = payload.get('template_uuid')
@@ -76,6 +77,9 @@ class CustomTemplateResource(GenericResource):
76
77
  )
77
78
 
78
79
  custom_template.save()
80
+
81
+ cache = await BlockActionObjectCache.initialize_cache()
82
+ cache.update_custom_block_template(custom_template)
79
83
  elif DIRECTORY_FOR_PIPELINE_TEMPLATES == object_type:
80
84
  custom_template = CustomPipelineTemplate.load(template_uuid=template_uuid)
81
85
 
@@ -120,13 +124,21 @@ class CustomTemplateResource(GenericResource):
120
124
  print(f'[WARNING] CustomTemplateResource.member: {err}')
121
125
  raise ApiError(ApiError.RESOURCE_NOT_FOUND)
122
126
 
123
- def delete(self, **kwargs):
127
+ async def delete(self, **kwargs):
128
+ cache = await BlockActionObjectCache.initialize_cache()
129
+ cache.update_custom_block_template(self.model, remove=True)
124
130
  self.model.delete
125
131
 
126
- def update(self, payload, **kwargs):
132
+ async def update(self, payload, **kwargs):
133
+ cache = await BlockActionObjectCache.initialize_cache()
134
+
135
+ cache.update_custom_block_template(self.model, remove=True)
136
+
127
137
  for key, value in ignore_keys(payload, [
128
138
  'uuid',
129
139
  OBJECT_TYPE_KEY,
130
140
  ]).items():
131
141
  setattr(self.model, key, value)
132
142
  self.model.save()
143
+
144
+ cache.update_custom_block_template(self.model)
@@ -2,6 +2,8 @@ import urllib.parse
2
2
 
3
3
  from mage_ai.api.errors import ApiError
4
4
  from mage_ai.api.resources.GenericResource import GenericResource
5
+ from mage_ai.cache.block_action_object import BlockActionObjectCache
6
+ from mage_ai.data_preparation.models.block import Block
5
7
  from mage_ai.data_preparation.models.file import File
6
8
  from mage_ai.orchestration.db import safe_db_query
7
9
  from mage_ai.settings.repo import get_repo_path
@@ -16,7 +18,7 @@ class FileContentResource(GenericResource):
16
18
  file = File.from_path(file_path, get_repo_path())
17
19
  return self(file, user, **kwargs)
18
20
 
19
- def update(self, payload, **kwargs):
21
+ async def update(self, payload, **kwargs):
20
22
  error = ApiError.RESOURCE_INVALID.copy()
21
23
 
22
24
  content = payload.get('content')
@@ -31,3 +33,8 @@ class FileContentResource(GenericResource):
31
33
  content = file_version.content()
32
34
 
33
35
  self.model.update_content(content)
36
+
37
+ block_type = Block.block_type_from_path(self.model.dir_path)
38
+ if block_type:
39
+ cache_block_action_object = await BlockActionObjectCache.initialize_cache()
40
+ cache_block_action_object.update_block(block_file_absolute_path=self.model.file_path)