tinybird 0.0.1.dev43__py3-none-any.whl → 0.0.1.dev44__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 tinybird might be problematic. Click here for more details.
- tinybird/prompts.py +30 -3
- tinybird/tb/__cli__.py +2 -2
- tinybird/tb/cli.py +1 -1
- tinybird/tb/modules/build.py +21 -16
- tinybird/tb/modules/cli.py +2 -57
- tinybird/tb/modules/common.py +2 -1
- tinybird/tb/modules/copy.py +1 -1
- tinybird/tb/modules/create.py +105 -46
- tinybird/tb/modules/datafile/build.py +12 -221
- tinybird/tb/modules/datasource.py +1 -1
- tinybird/tb/modules/deployment.py +1 -1
- tinybird/tb/modules/endpoint.py +89 -2
- tinybird/tb/modules/materialization.py +146 -0
- tinybird/tb/modules/mock.py +56 -16
- tinybird/tb/modules/pipe.py +2 -321
- tinybird/tb/modules/project.py +10 -4
- tinybird/tb/modules/test.py +72 -37
- tinybird/tb/modules/update.py +1 -1
- {tinybird-0.0.1.dev43.dist-info → tinybird-0.0.1.dev44.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev43.dist-info → tinybird-0.0.1.dev44.dist-info}/RECORD +23 -23
- tinybird/tb/modules/build_client.py +0 -199
- {tinybird-0.0.1.dev43.dist-info → tinybird-0.0.1.dev44.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev43.dist-info → tinybird-0.0.1.dev44.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev43.dist-info → tinybird-0.0.1.dev44.dist-info}/top_level.txt +0 -0
tinybird/prompts.py
CHANGED
|
@@ -397,9 +397,19 @@ Follow the instructions and generate the following response with no additional t
|
|
|
397
397
|
"""
|
|
398
398
|
|
|
399
399
|
|
|
400
|
-
def create_prompt(existing_resources: str) -> str:
|
|
400
|
+
def create_prompt(existing_resources: str, feedback: str = "", history: str = "") -> str:
|
|
401
|
+
feedback_history = ""
|
|
402
|
+
if feedback and history:
|
|
403
|
+
feedback_history = f"""In case the <feedback> and <history> tags are present and not empty,
|
|
404
|
+
it means there was a previous attempt to generate the resources and the user provided feedback and history about previous responses.
|
|
405
|
+
Use the following feedback and history to regenerate the response:
|
|
406
|
+
Feedback to improve the response:
|
|
407
|
+
{feedback}
|
|
408
|
+
History of previous results:
|
|
409
|
+
{history}"""
|
|
410
|
+
|
|
401
411
|
return """
|
|
402
|
-
You are a Tinybird expert. You will be given a prompt to generate Tinybird resources: datasources and/or pipes.
|
|
412
|
+
You are a Tinybird expert. You will be given a prompt to generate new or update existing Tinybird resources: datasources and/or pipes.
|
|
403
413
|
<existing_resources>{existing_resources}</existing_resources>
|
|
404
414
|
{datasource_instructions}
|
|
405
415
|
{pipe_instructions}
|
|
@@ -408,6 +418,9 @@ You are a Tinybird expert. You will be given a prompt to generate Tinybird resou
|
|
|
408
418
|
{pipe_example}
|
|
409
419
|
{copy_pipe_instructions}
|
|
410
420
|
{materialized_pipe_instructions}
|
|
421
|
+
|
|
422
|
+
{feedback_history}
|
|
423
|
+
|
|
411
424
|
Use the following format to generate the response and do not wrap it in any other text, including the <response> tag.
|
|
412
425
|
<response>
|
|
413
426
|
<resource>
|
|
@@ -426,10 +439,21 @@ Use the following format to generate the response and do not wrap it in any othe
|
|
|
426
439
|
pipe_example=pipe_example,
|
|
427
440
|
copy_pipe_instructions=copy_pipe_instructions,
|
|
428
441
|
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
442
|
+
feedback_history=feedback_history,
|
|
429
443
|
)
|
|
430
444
|
|
|
431
445
|
|
|
432
|
-
def mock_prompt(rows: int) -> str:
|
|
446
|
+
def mock_prompt(rows: int, feedback: str = "", history: str = "") -> str:
|
|
447
|
+
feedback_history = ""
|
|
448
|
+
if feedback and history:
|
|
449
|
+
feedback_history = f"""In case the <feedback> and <history> tags are present and not empty,
|
|
450
|
+
it means there was a previous attempt to generate the resources and the user provided feedback and history about previous responses.
|
|
451
|
+
Use the following feedback and history to regenerate the response:
|
|
452
|
+
Feedback to improve the response:
|
|
453
|
+
{feedback}
|
|
454
|
+
History of previous results:
|
|
455
|
+
{history}"""
|
|
456
|
+
|
|
433
457
|
return f"""
|
|
434
458
|
Given the schema for a Tinybird datasource, return a can you create a clickhouse sql query to generate some random data that matches that schema.
|
|
435
459
|
|
|
@@ -570,6 +594,9 @@ Follow the instructions and generate the following response with no additional t
|
|
|
570
594
|
<response>
|
|
571
595
|
<sql>[raw sql query here]</sql>
|
|
572
596
|
</response>
|
|
597
|
+
|
|
598
|
+
{feedback_history}
|
|
599
|
+
|
|
573
600
|
"""
|
|
574
601
|
|
|
575
602
|
|
tinybird/tb/__cli__.py
CHANGED
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev44'
|
|
8
|
+
__revision__ = '637cb4c'
|
tinybird/tb/cli.py
CHANGED
|
@@ -6,7 +6,6 @@ if sys.platform == "win32":
|
|
|
6
6
|
|
|
7
7
|
import tinybird.tb.modules.auth
|
|
8
8
|
import tinybird.tb.modules.build
|
|
9
|
-
import tinybird.tb.modules.build_client
|
|
10
9
|
import tinybird.tb.modules.cli
|
|
11
10
|
import tinybird.tb.modules.common
|
|
12
11
|
import tinybird.tb.modules.copy
|
|
@@ -18,6 +17,7 @@ import tinybird.tb.modules.fmt
|
|
|
18
17
|
import tinybird.tb.modules.job
|
|
19
18
|
import tinybird.tb.modules.local
|
|
20
19
|
import tinybird.tb.modules.login
|
|
20
|
+
import tinybird.tb.modules.materialization
|
|
21
21
|
import tinybird.tb.modules.mock
|
|
22
22
|
import tinybird.tb.modules.pipe
|
|
23
23
|
import tinybird.tb.modules.tag
|
tinybird/tb/modules/build.py
CHANGED
|
@@ -12,6 +12,7 @@ import requests
|
|
|
12
12
|
from tinybird.client import TinyB
|
|
13
13
|
from tinybird.tb.modules.cli import cli
|
|
14
14
|
from tinybird.tb.modules.common import push_data
|
|
15
|
+
from tinybird.tb.modules.datafile.build import folder_build
|
|
15
16
|
from tinybird.tb.modules.datafile.fixture import build_fixture_name, get_fixture_dir
|
|
16
17
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
17
18
|
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
@@ -37,9 +38,10 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
37
38
|
if file_changed and file_changed.endswith(".ndjson"):
|
|
38
39
|
rebuild_fixture(project, tb_client, file_changed)
|
|
39
40
|
else:
|
|
40
|
-
build_project(project, tb_client)
|
|
41
|
+
build_project(project, tb_client, file_changed)
|
|
41
42
|
try:
|
|
42
43
|
if file_changed:
|
|
44
|
+
asyncio.run(folder_build(project, filenames=[file_changed]))
|
|
43
45
|
build_and_print_resource(tb_client, file_changed, diff)
|
|
44
46
|
except Exception:
|
|
45
47
|
pass
|
|
@@ -61,7 +63,7 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
61
63
|
shell.run()
|
|
62
64
|
|
|
63
65
|
|
|
64
|
-
def build_project(project: Project, tb_client: TinyB) -> None:
|
|
66
|
+
def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str] = None) -> None:
|
|
65
67
|
MULTIPART_BOUNDARY_DATA_PROJECT = "data_project://"
|
|
66
68
|
DATAFILE_TYPE_TO_CONTENT_TYPE = {
|
|
67
69
|
".datasource": "text/plain",
|
|
@@ -103,20 +105,23 @@ def build_project(project: Project, tb_client: TinyB) -> None:
|
|
|
103
105
|
if build_result == "success":
|
|
104
106
|
datasources = result.get("datasources", [])
|
|
105
107
|
pipes = result.get("pipes", [])
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
if not file_changed:
|
|
109
|
+
for ds in datasources:
|
|
110
|
+
ds_path_str: Optional[str] = next(
|
|
111
|
+
(p for p in project_files if p.endswith(ds.get("name") + ".datasource")), None
|
|
112
|
+
)
|
|
113
|
+
if ds_path_str:
|
|
114
|
+
ds_path = Path(ds_path_str)
|
|
115
|
+
ds_path_str = ds_path_str.replace(f"{project.folder}/", "")
|
|
116
|
+
click.echo(FeedbackManager.info(message=f"✓ {ds_path_str} created"))
|
|
117
|
+
for pipe in pipes:
|
|
118
|
+
pipe_name = pipe.get("name")
|
|
119
|
+
pipe_path_str: Optional[str] = next(
|
|
120
|
+
(p for p in project_files if p.endswith(pipe_name + ".pipe")), None
|
|
121
|
+
)
|
|
122
|
+
if pipe_path_str:
|
|
123
|
+
pipe_path_str = pipe_path_str.replace(f"{project.folder}/", "")
|
|
124
|
+
click.echo(FeedbackManager.info(message=f"✓ {pipe_path_str} created"))
|
|
120
125
|
|
|
121
126
|
try:
|
|
122
127
|
for filename in project_files:
|
tinybird/tb/modules/cli.py
CHANGED
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import os
|
|
9
|
-
import pprint
|
|
10
9
|
from os import getcwd
|
|
11
10
|
from pathlib import Path
|
|
12
|
-
from typing import Any, Callable, Dict,
|
|
11
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
13
12
|
|
|
14
13
|
import click
|
|
15
14
|
import humanfriendly
|
|
@@ -35,13 +34,7 @@ from tinybird.tb.modules.common import (
|
|
|
35
34
|
)
|
|
36
35
|
from tinybird.tb.modules.config import CLIConfig
|
|
37
36
|
from tinybird.tb.modules.datafile.build import build_graph
|
|
38
|
-
from tinybird.tb.modules.datafile.common import Datafile, DatafileSyntaxError
|
|
39
37
|
from tinybird.tb.modules.datafile.diff import diff_command
|
|
40
|
-
from tinybird.tb.modules.datafile.exceptions import (
|
|
41
|
-
ParseException,
|
|
42
|
-
)
|
|
43
|
-
from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
|
|
44
|
-
from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
|
|
45
38
|
from tinybird.tb.modules.datafile.pull import folder_pull
|
|
46
39
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
47
40
|
from tinybird.tb.modules.llm import LLM
|
|
@@ -132,55 +125,7 @@ async def cli(
|
|
|
132
125
|
ctx.ensure_object(dict)["project"] = project
|
|
133
126
|
|
|
134
127
|
|
|
135
|
-
@cli.command(
|
|
136
|
-
@click.argument("filenames", type=click.Path(exists=True), nargs=-1, default=None)
|
|
137
|
-
@click.option("--debug", is_flag=True, default=False, help="Print internal representation")
|
|
138
|
-
@click.pass_context
|
|
139
|
-
def check(ctx: Context, filenames: List[str], debug: bool) -> None:
|
|
140
|
-
"""Check file syntax."""
|
|
141
|
-
|
|
142
|
-
if not filenames:
|
|
143
|
-
project: Project = ctx.ensure_object(dict)["project"]
|
|
144
|
-
filenames = project.get_project_files()
|
|
145
|
-
|
|
146
|
-
def process(filenames: Iterable):
|
|
147
|
-
parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
|
|
148
|
-
incl_suffix = ".incl"
|
|
149
|
-
try:
|
|
150
|
-
for filename in filenames:
|
|
151
|
-
if os.path.isdir(filename):
|
|
152
|
-
process(filenames=filename)
|
|
153
|
-
|
|
154
|
-
click.echo(FeedbackManager.info_processing_file(filename=filename))
|
|
155
|
-
|
|
156
|
-
file_suffix = Path(filename).suffix
|
|
157
|
-
if file_suffix == incl_suffix:
|
|
158
|
-
click.echo(FeedbackManager.info_ignoring_incl_file(filename=filename))
|
|
159
|
-
continue
|
|
160
|
-
|
|
161
|
-
doc: Datafile
|
|
162
|
-
parser = parser_matrix.get(file_suffix)
|
|
163
|
-
if not parser:
|
|
164
|
-
raise ParseException(FeedbackManager.error_unsupported_datafile(extension=file_suffix))
|
|
165
|
-
|
|
166
|
-
doc = parser(filename)
|
|
167
|
-
|
|
168
|
-
click.echo(FeedbackManager.success_processing_file(filename=filename))
|
|
169
|
-
if debug:
|
|
170
|
-
pp = pprint.PrettyPrinter()
|
|
171
|
-
for x in doc.nodes:
|
|
172
|
-
pp.pprint(x)
|
|
173
|
-
|
|
174
|
-
except DatafileSyntaxError as e:
|
|
175
|
-
# TODO(eclbg): add the filename to the error message
|
|
176
|
-
raise CLIException(str(e))
|
|
177
|
-
except ParseException as e:
|
|
178
|
-
raise CLIException(FeedbackManager.error_exception(error=e))
|
|
179
|
-
|
|
180
|
-
process(filenames=filenames)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
@cli.command(hidden=True)
|
|
128
|
+
@cli.command()
|
|
184
129
|
@click.option(
|
|
185
130
|
"--folder", default=None, type=click.Path(exists=True, file_okay=False), help="Folder where files will be placed"
|
|
186
131
|
)
|
tinybird/tb/modules/common.py
CHANGED
|
@@ -163,7 +163,7 @@ def generate_datafile(
|
|
|
163
163
|
force: Optional[bool] = False,
|
|
164
164
|
_format: Optional[str] = "csv",
|
|
165
165
|
folder: Optional[str] = None,
|
|
166
|
-
):
|
|
166
|
+
) -> Path:
|
|
167
167
|
p = Path(filename)
|
|
168
168
|
base = Path("datasources")
|
|
169
169
|
if folder:
|
|
@@ -190,6 +190,7 @@ def generate_datafile(
|
|
|
190
190
|
fixture_file.write(data[: data.rfind(newline)])
|
|
191
191
|
else:
|
|
192
192
|
click.echo(FeedbackManager.error_file_already_exists(file=f))
|
|
193
|
+
return f
|
|
193
194
|
|
|
194
195
|
|
|
195
196
|
async def get_current_workspace(config: CLIConfig) -> Optional[Dict[str, Any]]:
|
tinybird/tb/modules/copy.py
CHANGED
tinybird/tb/modules/create.py
CHANGED
|
@@ -18,6 +18,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
|
18
18
|
from tinybird.tb.modules.llm import LLM
|
|
19
19
|
from tinybird.tb.modules.llm_utils import extract_xml, parse_xml
|
|
20
20
|
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
21
|
+
from tinybird.tb.modules.project import Project
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
@cli.command()
|
|
@@ -41,8 +42,10 @@ from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
|
41
42
|
)
|
|
42
43
|
@click.option("--rows", type=int, default=10, help="Number of events to send")
|
|
43
44
|
@click.option("--cursor", default=False, is_flag=True, help="Create .cursorrules file with Tinybird rules")
|
|
45
|
+
@click.pass_context
|
|
44
46
|
@coro
|
|
45
47
|
async def create(
|
|
48
|
+
ctx: click.Context,
|
|
46
49
|
data: Optional[str],
|
|
47
50
|
prompt: Optional[str],
|
|
48
51
|
folder: Optional[str],
|
|
@@ -50,13 +53,14 @@ async def create(
|
|
|
50
53
|
cursor: bool,
|
|
51
54
|
) -> None:
|
|
52
55
|
"""Initialize a new project."""
|
|
56
|
+
project: Project = ctx.ensure_object(dict)["project"]
|
|
53
57
|
folder = folder or getcwd()
|
|
54
58
|
folder_path = Path(folder)
|
|
55
59
|
if not folder_path.exists():
|
|
56
60
|
folder_path.mkdir()
|
|
57
61
|
|
|
58
62
|
try:
|
|
59
|
-
config = CLIConfig.get_project_config(
|
|
63
|
+
config = CLIConfig.get_project_config(str(project.path))
|
|
60
64
|
tb_client = config.get_client()
|
|
61
65
|
user_token: Optional[str] = None
|
|
62
66
|
if prompt:
|
|
@@ -80,7 +84,7 @@ async def create(
|
|
|
80
84
|
click.echo(FeedbackManager.success(message="✓ Scaffolding completed!\n"))
|
|
81
85
|
|
|
82
86
|
click.echo(FeedbackManager.highlight(message="\n» Creating resources..."))
|
|
83
|
-
|
|
87
|
+
result = await create_resources(local_client, tb_client, user_token, data, prompt, folder)
|
|
84
88
|
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
85
89
|
|
|
86
90
|
if not already_has_cicd(folder):
|
|
@@ -89,7 +93,7 @@ async def create(
|
|
|
89
93
|
await init_cicd(data_project_dir=os.path.relpath(folder))
|
|
90
94
|
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
91
95
|
|
|
92
|
-
if
|
|
96
|
+
if should_generate_fixtures(result):
|
|
93
97
|
click.echo(FeedbackManager.highlight(message="\n» Generating fixtures..."))
|
|
94
98
|
|
|
95
99
|
if data:
|
|
@@ -110,7 +114,7 @@ async def create(
|
|
|
110
114
|
datasource_content = datasource_path.read_text()
|
|
111
115
|
has_json_path = "`json:" in datasource_content
|
|
112
116
|
if has_json_path:
|
|
113
|
-
prompt = f"<datasource_schema>{datasource_content}</datasource_schema
|
|
117
|
+
prompt = f"<datasource_schema>{datasource_content}</datasource_schema>"
|
|
114
118
|
response = llm.ask(system_prompt=mock_prompt(rows), prompt=prompt)
|
|
115
119
|
sql = extract_xml(response, "sql")
|
|
116
120
|
sql = sql.split("FORMAT")[0]
|
|
@@ -139,9 +143,10 @@ def validate_project_structure(folder: str) -> bool:
|
|
|
139
143
|
return all((Path(folder) / path).exists() for path in PROJECT_PATHS)
|
|
140
144
|
|
|
141
145
|
|
|
142
|
-
def
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
def should_generate_fixtures(result: str) -> bool:
|
|
147
|
+
if not result:
|
|
148
|
+
return False
|
|
149
|
+
return "<type>datasource</type>" in result
|
|
145
150
|
|
|
146
151
|
|
|
147
152
|
def already_has_cicd(folder: str) -> bool:
|
|
@@ -168,12 +173,12 @@ async def create_resources(
|
|
|
168
173
|
prompt: Optional[str],
|
|
169
174
|
folder: str,
|
|
170
175
|
):
|
|
171
|
-
|
|
176
|
+
result = ""
|
|
172
177
|
folder_path = Path(folder)
|
|
173
178
|
if data:
|
|
174
179
|
path = folder_path / data
|
|
175
180
|
format = path.suffix.lstrip(".")
|
|
176
|
-
await _generate_datafile(str(path), local_client, format=format, force=
|
|
181
|
+
await _generate_datafile(str(path), local_client, format=format, force=True)
|
|
177
182
|
name = data.split(".")[0]
|
|
178
183
|
generate_pipe_file(
|
|
179
184
|
f"{name}_endpoint",
|
|
@@ -185,7 +190,10 @@ TYPE ENDPOINT
|
|
|
185
190
|
""",
|
|
186
191
|
folder,
|
|
187
192
|
)
|
|
188
|
-
|
|
193
|
+
result = (
|
|
194
|
+
f"<response><resource><type>datasource</type><name>{name}</name><content></content></resource></response>"
|
|
195
|
+
)
|
|
196
|
+
|
|
189
197
|
elif prompt and user_token:
|
|
190
198
|
datasource_paths = [
|
|
191
199
|
Path(folder) / "datasources" / f
|
|
@@ -212,41 +220,74 @@ TYPE ENDPOINT
|
|
|
212
220
|
]
|
|
213
221
|
)
|
|
214
222
|
llm = LLM(user_token=user_token, host=tb_client.host)
|
|
215
|
-
result =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
223
|
+
result = ""
|
|
224
|
+
iterations = 0
|
|
225
|
+
history = ""
|
|
226
|
+
generated_paths: list[Path] = []
|
|
227
|
+
|
|
228
|
+
while iterations < 10:
|
|
229
|
+
feedback = ""
|
|
230
|
+
if iterations > 0:
|
|
231
|
+
feedback = click.prompt("\nFollow-up instructions or continue", default="continue")
|
|
232
|
+
if iterations > 0 and (not feedback or feedback in ("continue", "ok", "exit", "quit", "q")):
|
|
233
|
+
break
|
|
234
|
+
else:
|
|
235
|
+
if iterations > 0:
|
|
236
|
+
click.echo(FeedbackManager.highlight(message="\n» Creating resources..."))
|
|
237
|
+
for path in generated_paths:
|
|
238
|
+
path.unlink()
|
|
239
|
+
generated_paths = []
|
|
240
|
+
|
|
241
|
+
save_context(prompt, feedback)
|
|
242
|
+
result = llm.ask(system_prompt=create_prompt(resources_xml, feedback, history), prompt=prompt)
|
|
243
|
+
result = extract_xml(result, "response")
|
|
244
|
+
history = (
|
|
245
|
+
history
|
|
246
|
+
+ f"""
|
|
247
|
+
<result_iteration_{iterations}>
|
|
248
|
+
{result}
|
|
249
|
+
</result_iteration_{iterations}>
|
|
250
|
+
"""
|
|
251
|
+
)
|
|
252
|
+
resources = parse_xml(result, "resource")
|
|
253
|
+
datasources = []
|
|
254
|
+
pipes = []
|
|
255
|
+
for resource_xml in resources:
|
|
256
|
+
resource_type = extract_xml(resource_xml, "type")
|
|
257
|
+
name = extract_xml(resource_xml, "name")
|
|
258
|
+
content = extract_xml(resource_xml, "content")
|
|
259
|
+
resource = {
|
|
260
|
+
"name": name,
|
|
261
|
+
"content": content,
|
|
262
|
+
}
|
|
263
|
+
if resource_type.lower() == "datasource":
|
|
264
|
+
datasources.append(resource)
|
|
265
|
+
elif resource_type.lower() == "pipe":
|
|
266
|
+
pipes.append(resource)
|
|
267
|
+
|
|
268
|
+
for ds in datasources:
|
|
269
|
+
content = ds["content"].replace("```", "")
|
|
270
|
+
filename = f"{ds['name']}.datasource"
|
|
271
|
+
datasource_path = generate_datafile(
|
|
272
|
+
content,
|
|
273
|
+
filename=filename,
|
|
274
|
+
data=None,
|
|
275
|
+
_format="ndjson",
|
|
276
|
+
force=True,
|
|
277
|
+
folder=folder,
|
|
278
|
+
)
|
|
279
|
+
generated_paths.append(datasource_path)
|
|
280
|
+
for pipe in pipes:
|
|
281
|
+
content = pipe["content"].replace("```", "")
|
|
282
|
+
pipe_path = generate_pipe_file(pipe["name"], content, folder)
|
|
283
|
+
generated_paths.append(pipe_path)
|
|
284
|
+
|
|
285
|
+
iterations += 1
|
|
286
|
+
|
|
287
|
+
if iterations == 10:
|
|
288
|
+
click.echo(FeedbackManager.info(message="Too many iterations. Change the prompt and try again."))
|
|
289
|
+
|
|
290
|
+
return result
|
|
250
291
|
|
|
251
292
|
|
|
252
293
|
def init_git(folder: str):
|
|
@@ -266,7 +307,7 @@ def init_git(folder: str):
|
|
|
266
307
|
raise CLIException(f"Error initializing Git: {e}")
|
|
267
308
|
|
|
268
309
|
|
|
269
|
-
def generate_pipe_file(name: str, content: str, folder: str):
|
|
310
|
+
def generate_pipe_file(name: str, content: str, folder: str) -> Path:
|
|
270
311
|
def is_copy(content: str) -> bool:
|
|
271
312
|
return re.search(r"TYPE copy", content, re.IGNORECASE) is not None
|
|
272
313
|
|
|
@@ -292,6 +333,7 @@ def generate_pipe_file(name: str, content: str, folder: str):
|
|
|
292
333
|
with open(f"{f}", "w") as file:
|
|
293
334
|
file.write(content)
|
|
294
335
|
click.echo(FeedbackManager.info_file_created(file=f.relative_to(folder)))
|
|
336
|
+
return f.relative_to(folder)
|
|
295
337
|
|
|
296
338
|
|
|
297
339
|
def already_has_cursorrules(folder: str) -> bool:
|
|
@@ -301,3 +343,20 @@ def already_has_cursorrules(folder: str) -> bool:
|
|
|
301
343
|
def create_cursorrules(folder: str):
|
|
302
344
|
cursorrules_file = Path(folder) / ".cursorrules"
|
|
303
345
|
cursorrules_file.write_text(cursorrules_prompt)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def get_context_file() -> Path:
|
|
349
|
+
context_file = Path(os.path.expanduser("~/.tb_create_context"))
|
|
350
|
+
if not context_file.exists():
|
|
351
|
+
context_file.touch()
|
|
352
|
+
return context_file
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def get_context() -> str:
|
|
356
|
+
context_file = get_context_file()
|
|
357
|
+
return context_file.read_text()
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def save_context(prompt: str, feedback: str):
|
|
361
|
+
context_file = get_context_file()
|
|
362
|
+
context_file.write_text(f"- {prompt}\n{feedback}")
|