tinybird 0.0.1.dev255__py3-none-any.whl → 0.0.1.dev257__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.

@@ -1,8 +1,22 @@
1
+ from datetime import datetime
1
2
  from pathlib import Path
2
3
  from typing import Any
3
4
 
4
5
  from pydantic_ai import format_as_xml
5
6
 
7
+ from tinybird.prompts import (
8
+ connection_instructions,
9
+ copy_pipe_instructions,
10
+ datasource_example,
11
+ datasource_instructions,
12
+ gcs_connection_example,
13
+ kafka_connection_example,
14
+ materialized_pipe_instructions,
15
+ pipe_example,
16
+ pipe_instructions,
17
+ s3_connection_example,
18
+ sink_pipe_instructions,
19
+ )
6
20
  from tinybird.tb.modules.project import Project
7
21
 
8
22
  plan_instructions = """
@@ -18,15 +32,13 @@ Steps:
18
32
  5. Materialized datasource: [name] - [description] - Depends on: [resources]
19
33
  6. Sink: [name] - [description] - Depends on: [resources]
20
34
  7. Copy: [name] - [description] - Depends on: [resources]
21
- 8. Build project
22
- 9. Generate mock data: [datasource_name]
23
- 10. Append existing fixture: [fixture_pathname] - Target: [datasource_name]
35
+ 8. Generate mock data: [datasource_name]
36
+ 9. Append existing fixture: [fixture_pathname] - Target: [datasource_name]
24
37
 
25
38
  <dev_notes>
26
39
  You can skip steps where resources will not be created or updated.
27
- Always add 'Build project' step after generating resources.
28
- Always add 'Generate mock data' step after building project if a landing datasource was created without providing a fixture file.
29
- Always add 'Append existing fixture' step after building project if a landing datasource was created after providing a fixture file.
40
+ Always add 'Generate mock data' step if a landing datasource was created without providing a fixture file.
41
+ Always add 'Append existing fixture' step if a landing datasource was created after providing a fixture file.
30
42
  Solve the specific user request, do not add extra steps that are not related to the user request.
31
43
  Reuse the existing resources if possible.
32
44
  </dev_notes>
@@ -494,3 +506,139 @@ JOIN (SELECT id, col FROM huge_table WHERE id IN (SELECT id FROM small_table)) f
494
506
  ON small_table.id = filtered.id
495
507
  ```
496
508
  """
509
+
510
+
511
+ agent_system_prompt = f"""
512
+ You are a Tinybird Code, an agentic CLI that can help users to work with Tinybird.
513
+
514
+ You are an interactive CLI tool that helps users with data engineering tasks. Use the instructions below and the tools available to you to assist the user.
515
+
516
+ # Tone and style
517
+ You should be concise, direct, and to the point.
518
+ Remember that your output will be displayed on a command line interface. Your responses can use Github-flavored markdown for formatting. Do not use emojis.
519
+ Output text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use tools like Bash or code comments as means to communicate with the user during the session.
520
+ If you cannot or will not help the user with something, please do not say why or what it could lead to, since this comes across as preachy and annoying. Please offer helpful alternatives if possible, and otherwise keep your response to 1-2 sentences.
521
+ IMPORTANT: You should minimize output tokens as much as possible while maintaining helpfulness, quality, and accuracy. Only address the specific query or task at hand, avoiding tangential information unless absolutely critical for completing the request. If you can answer in 1-3 sentences or a short paragraph, please do.
522
+ IMPORTANT: You should NOT answer with unnecessary preamble or postamble (such as explaining your code or summarizing your action), unless the user asks you to.
523
+ IMPORTANT: Keep your responses short, since they will be displayed on a command line interface. You MUST answer concisely with fewer than 4 lines (not including tool use or code generation), unless user asks for detail. Answer the user's question directly, without elaboration, explanation, or details. One word answers are best. Avoid introductions, conclusions, and explanations. You MUST avoid text before/after your response, such as "The answer is <answer>.", "Here is the content of the file..." or "Based on the information provided, the answer is..." or "Here is what I will do next...". Here are some examples to demonstrate appropriate verbosity:
524
+
525
+ # Proactiveness
526
+ You are allowed to be proactive, but only when the user asks you to do something. You should strive to strike a balance between:
527
+ Doing the right thing when asked, including taking actions and follow-up actions
528
+ Not surprising the user with actions you take without asking
529
+ For example, if the user asks you how to approach something, you should do your best to answer their question first, and not immediately jump into taking actions.
530
+ Do not add additional code explanation summary unless requested by the user. After working on a file, just stop, rather than providing an explanation of what you did.
531
+
532
+ # Code style
533
+ IMPORTANT: DO NOT ADD ANY COMMENTS unless asked by the user.
534
+
535
+ # Tools
536
+ You have access to the following tools:
537
+ 1. `preview_datafile` - Preview the content of a datafile (datasource, endpoint, materialized, sink, copy, connection).
538
+ 2. `create_datafile` - Create a file in the project folder. Confirmation will be asked by the tool before creating the file.
539
+ 3. `plan` - Plan the creation or update of resources.
540
+ 4. `build` - Build the project.
541
+ 5. `deploy` - Deploy the project to Tinybird Cloud.
542
+ 6. `deploy_check` - Check if the project can be deployed to Tinybird Cloud before deploying it.
543
+ 7. `mock` - Create mock data for a landing datasource in Tinybird Cloud or Local.
544
+ 8. `analyze_file` - Analyze the content of a fixture file present in the project folder.
545
+ 9. `analyze_url` - Analyze the content of an external url.
546
+ 9. `append_file` - Append a file present in the project to a datasource in Tinybird Cloud or Local.
547
+ 10. `append_url` - Append an external url to a datasource in Tinybird Cloud or Local.
548
+ 11. `get_endpoint_stats` - Get metrics of the requests to an endpoint.
549
+ 12. `get_openapi_definition` - Get the OpenAPI definition for an endpoint in Tinybird Cloud or Local.
550
+ 13. `execute_query` - Execute a query against Tinybird Cloud or Local.
551
+ 13. `request_endpoint` - Request an endpoint against Tinybird Cloud or Local.
552
+ 14. `diff_resource` - Diff the content of a resource in Tinybird Cloud vs Tinybird Local vs Project local file.
553
+
554
+ # When creating or updating datafiles:
555
+ 1. Use `plan` tool to plan the creation or update of resources.
556
+ 2. If the user confirms the plan, go from 3 to 7 steps until all the resources are created, updated or skipped.
557
+ 3. Use `preview_datafile` tool to preview the content of a datafile.
558
+ 4. Without asking, use the `create_datafile` tool to create the datafile, because it will ask for confirmation before creating the file.
559
+ 5. Check the result of the `create_datafile` tool to see if the datafile was created successfully.
560
+ 6. If the datafile was created successfully, report the result to the user.
561
+ 7. If the datafile was not created, finish the process and just wait for a new user prompt.
562
+ 8. If the datafile was created successfully, but the built failed, try to fix the error and repeat the process.
563
+
564
+ # When creating a landing datasource given a .ndjson file:
565
+ - If the user does not specify anything about the desired schema, create a schema like this:
566
+ SCHEMA >
567
+ `data` String `json:$`
568
+
569
+ - Use always json paths with .ndjson files.
570
+
571
+ # When user wants to optimize an endpoint:
572
+ {endpoint_optimization_instructions}
573
+
574
+ IMPORTANT: If the user cancels some of the steps or there is an error in file creation, DO NOT continue with the plan. Stop the process and wait for the user before using any other tool.
575
+ IMPORTANT: Every time you finish a plan and start a new resource creation or update process, create a new plan before starting with the changes.
576
+
577
+ # Using deployment tools:
578
+ - Use `deploy_check` tool to check if the project can be deployed to Tinybird Cloud before deploying it.
579
+ - Use `deploy` tool to deploy the project to Tinybird Cloud.
580
+ - Only use deployment tools if user explicitly asks for it.
581
+
582
+ # When planning the creation or update of resources:
583
+ {plan_instructions}
584
+ {datafile_instructions}
585
+
586
+ # Working with datasource files:
587
+ {datasource_instructions}
588
+ {datasource_example}
589
+
590
+ # Working with any type of pipe file:
591
+ {pipe_instructions}
592
+ {pipe_example}
593
+
594
+ # Working with materialized pipe files:
595
+ {materialized_pipe_instructions}
596
+
597
+ # Working with sink pipe files:
598
+ {sink_pipe_instructions}
599
+
600
+ # Working with copy pipe files:
601
+ {copy_pipe_instructions}
602
+
603
+ # Working with SQL queries:
604
+ {sql_agent_instructions}
605
+ {sql_instructions}
606
+
607
+ # Working with connections files:
608
+ {connection_instructions}
609
+
610
+ # Connection examples:
611
+ Kafka: {kafka_connection_example}
612
+ S3: {s3_connection_example}
613
+ GCS: {gcs_connection_example}
614
+
615
+ # When executing a query or requesting/testing an endpoint:
616
+ - You need to be sure that the selected resource is updated to the last version in the environment you are working on.
617
+ - Use `diff_resource` tool to compare the content of the resource to compare the differences between environments.
618
+ - Project local file is the source of truth.
619
+ - If the resource is not present or updated to the last version in Tinybird Local, it means you need to build the project.
620
+ - If the resource is not present or updated to the last version in Tinybird Cloud, it means you need to deploy the project.
621
+
622
+ # How to use apppend tools:
623
+ - Use append as part of the creation of a new landing datasource if the user provided a file or an external url
624
+ - Use append if user explicitly asks for it
625
+ - Do not append data if user requests to test an endpoint
626
+
627
+ # How to use `mock` tool:
628
+ - Use `mock` tool as part of the creation of a new landing datasource if the user did not provided a file or an external url
629
+ - Use `mock` tool if user explicitly asks for it
630
+ - Do not use `mock` tool if user requests to test an endpoint.
631
+
632
+ # When sharing endpoints paths or urls:
633
+ - Use `get_openapi_definition` tool to get the url of the endpoint and parameters available.
634
+ - Do not share parts of the URL, share consumible URLs.
635
+ - ALWAYS include the api host in the url you share.
636
+ - ALWAYS include the token in the url like <base_url>/<path>?token=<token>
637
+ - Include dynamic parameters in the url if needed.
638
+ - `DateTime64` parameters accept values in format `YYYY-MM-DD HH:MM:SS.MMM`
639
+ - `DateTime` parameters accept values in format `YYYY-MM-DD HH:MM:SS`
640
+ - `Date` parameters accept values in format `YYYYMMDD`
641
+
642
+ # Info
643
+ Today is {datetime.now().strftime("%Y-%m-%d")}
644
+ """
@@ -5,96 +5,106 @@ from tinybird.tb.modules.agent.utils import TinybirdAgentContext, show_confirmat
5
5
  from tinybird.tb.modules.feedback_manager import FeedbackManager
6
6
 
7
7
 
8
- def append_file(ctx: RunContext[TinybirdAgentContext], datasource_name: str, fixture_pathname: str) -> str:
8
+ def append_file(
9
+ ctx: RunContext[TinybirdAgentContext], datasource_name: str, fixture_pathname: str, cloud: bool = False
10
+ ) -> str:
9
11
  """Append existing fixture to a datasource
10
12
 
11
13
  Args:
12
14
  datasource_name: Name of the datasource to append fixture to
13
15
  fixture_pathname: Path to the fixture file to append
16
+ cloud: Whether to append the fixture to the cloud or local environment. Optional.
14
17
 
15
18
  Returns:
16
19
  str: Message indicating the success or failure of the appending
17
20
  """
18
21
  try:
19
22
  ctx.deps.thinking_animation.stop()
23
+ cloud_or_local = "Cloud" if cloud else "Local"
20
24
  confirmation = show_confirmation(
21
- title=f"Append fixture {fixture_pathname} to datasource {datasource_name}?",
25
+ title=f"Append fixture {fixture_pathname} to datasource '{datasource_name}' in Tinybird {cloud_or_local}?",
22
26
  skip_confirmation=ctx.deps.dangerously_skip_permissions,
23
27
  )
24
28
 
25
29
  if confirmation == "review":
26
- click.echo()
27
30
  feedback = show_input(ctx.deps.workspace_name)
28
31
  ctx.deps.thinking_animation.start()
29
- return (
30
- f"User did not confirm appending {fixture_pathname} fixture and gave the following feedback: {feedback}"
31
- )
32
+ return f"User did not confirm appending {fixture_pathname} fixture in Tinybird {cloud_or_local} and gave the following feedback: {feedback}"
32
33
 
33
34
  if confirmation == "cancel":
34
35
  ctx.deps.thinking_animation.start()
35
- return f"User rejected appending {fixture_pathname} fixture. Skip this step"
36
+ return f"User rejected appending {fixture_pathname} fixture in Tinybird {cloud_or_local}. Skip this step"
36
37
 
37
38
  ctx.deps.thinking_animation.stop()
38
- click.echo(FeedbackManager.highlight(message=f"\n» Appending {fixture_pathname} to {datasource_name}..."))
39
- ctx.deps.append_data(datasource_name=datasource_name, path=fixture_pathname)
39
+ click.echo(FeedbackManager.highlight(message=f"» Appending {fixture_pathname} to {datasource_name}..."))
40
+ if cloud:
41
+ ctx.deps.append_data_cloud(datasource_name=datasource_name, path=fixture_pathname)
42
+ else:
43
+ ctx.deps.append_data_local(datasource_name=datasource_name, path=fixture_pathname)
40
44
  click.echo(FeedbackManager.success(message=f"✓ Data appended to {datasource_name}"))
41
45
  ctx.deps.thinking_animation.start()
42
- return f"Data appended to {datasource_name}"
46
+ return f"Data appended to {datasource_name} in Tinybird {cloud_or_local}"
43
47
  except Exception as e:
44
48
  error_message = str(e)
45
49
  ctx.deps.thinking_animation.stop()
46
50
  click.echo(FeedbackManager.error(message=error_message))
47
51
  error_message = handle_quarantine_error(ctx, error_message, datasource_name)
48
52
  ctx.deps.thinking_animation.start()
49
- return f"Error appending fixture {fixture_pathname} to {datasource_name}: {error_message}"
53
+ return f"Error appending fixture {fixture_pathname} to {datasource_name} in Tinybird {cloud_or_local}: {error_message}"
50
54
 
51
55
 
52
- def append_url(ctx: RunContext[TinybirdAgentContext], datasource_name: str, fixture_url: str) -> str:
56
+ def append_url(
57
+ ctx: RunContext[TinybirdAgentContext], datasource_name: str, fixture_url: str, cloud: bool = False
58
+ ) -> str:
53
59
  """Append existing fixture to a datasource
54
60
 
55
61
  Args:
56
62
  datasource_name: Name of the datasource to append fixture to
57
63
  fixture_url: external url to the fixture file to append
64
+ cloud: Whether to append the fixture to the cloud or local environment. Optional.
58
65
 
59
66
  Returns:
60
67
  str: Message indicating the success or failure of the appending
61
68
  """
62
69
  try:
63
70
  ctx.deps.thinking_animation.stop()
71
+ cloud_or_local = "Cloud" if cloud else "Local"
64
72
  confirmation = show_confirmation(
65
- title=f"Append URL {fixture_url} to datasource {datasource_name}?",
73
+ title=f"Append URL {fixture_url} to datasource '{datasource_name}' in Tinybird {cloud_or_local}?",
66
74
  skip_confirmation=ctx.deps.dangerously_skip_permissions,
67
75
  )
68
76
 
69
77
  if confirmation == "review":
70
- click.echo()
71
78
  feedback = show_input(ctx.deps.workspace_name)
72
79
  ctx.deps.thinking_animation.start()
73
- return f"User did not confirm appending URL {fixture_url} and gave the following feedback: {feedback}"
80
+ return f"User did not confirm appending URL {fixture_url} in Tinybird {cloud_or_local} and gave the following feedback: {feedback}"
74
81
 
75
82
  if confirmation == "cancel":
76
83
  ctx.deps.thinking_animation.start()
77
- return f"User rejected appending URL {fixture_url}. Skip this step"
84
+ return f"User rejected appending URL {fixture_url} in Tinybird {cloud_or_local}. Skip this step"
78
85
 
79
86
  ctx.deps.thinking_animation.stop()
80
- click.echo(FeedbackManager.highlight(message=f"\n» Appending {fixture_url} to {datasource_name}..."))
81
- ctx.deps.append_data(datasource_name=datasource_name, path=fixture_url)
87
+ click.echo(FeedbackManager.highlight(message=f"» Appending {fixture_url} to {datasource_name}..."))
88
+ if cloud:
89
+ ctx.deps.append_data_cloud(datasource_name=datasource_name, path=fixture_url)
90
+ else:
91
+ ctx.deps.append_data_local(datasource_name=datasource_name, path=fixture_url)
82
92
  click.echo(FeedbackManager.success(message=f"✓ Data appended to {datasource_name}"))
83
93
  ctx.deps.thinking_animation.start()
84
- return f"Data appended to {datasource_name}"
94
+ return f"Data appended to {datasource_name} in Tinybird {cloud_or_local}"
85
95
  except Exception as e:
86
96
  error_message = str(e)
87
97
  ctx.deps.thinking_animation.stop()
88
98
  click.echo(FeedbackManager.error(message=error_message))
89
99
  error_message = handle_quarantine_error(ctx, error_message, datasource_name)
90
100
  ctx.deps.thinking_animation.start()
91
- return f"Error appending URL {fixture_url} to {datasource_name}: {error_message}"
101
+ return f"Error appending URL {fixture_url} to {datasource_name} in Tinybird {cloud_or_local}: {error_message}"
92
102
 
93
103
 
94
104
  def handle_quarantine_error(ctx: RunContext[TinybirdAgentContext], error_message: str, datasource_name: str) -> str:
95
105
  try:
96
106
  if "in quarantine" in error_message:
97
- click.echo(FeedbackManager.highlight(message=f"\n» Looking for errors in {datasource_name}_quarantine..."))
107
+ click.echo(FeedbackManager.highlight(message=f"» Looking for errors in {datasource_name}_quarantine..."))
98
108
  query = (
99
109
  f"select * from {datasource_name}_quarantine order by insertion_date desc limit 5 FORMAT CSVWithNames"
100
110
  )
@@ -9,7 +9,7 @@ def build(ctx: RunContext[TinybirdAgentContext]) -> str:
9
9
  """Build the project"""
10
10
  try:
11
11
  ctx.deps.thinking_animation.stop()
12
- click.echo(FeedbackManager.highlight(message="\n» Building project..."))
12
+ click.echo(FeedbackManager.highlight(message="» Building project..."))
13
13
  ctx.deps.build_project(test=False, silent=False)
14
14
  ctx.deps.thinking_animation.start()
15
15
  return "Project built successfully"
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from pathlib import Path
2
3
 
3
4
  import click
@@ -34,7 +35,6 @@ def create_datafile(ctx: RunContext[TinybirdAgentContext], resource: Datafile) -
34
35
  else:
35
36
  content = create_terminal_box(resource.content, title=resource.pathname)
36
37
  click.echo(content)
37
-
38
38
  action = "Create" if not exists else "Update"
39
39
  confirmation = show_confirmation(
40
40
  title=f"{action} '{resource.pathname}'?",
@@ -42,7 +42,6 @@ def create_datafile(ctx: RunContext[TinybirdAgentContext], resource: Datafile) -
42
42
  )
43
43
 
44
44
  if confirmation == "review":
45
- click.echo()
46
45
  feedback = show_input(ctx.deps.workspace_name)
47
46
  ctx.deps.thinking_animation.start()
48
47
  return f"User did not confirm the proposed changes and gave the following feedback: {feedback}"
@@ -51,15 +50,14 @@ def create_datafile(ctx: RunContext[TinybirdAgentContext], resource: Datafile) -
51
50
  ctx.deps.thinking_animation.start()
52
51
  return f"User cancelled {action} of {resource.pathname}. Stop resource creation."
53
52
 
54
- action_text = "Creating" if not exists else "Updating"
55
- click.echo(FeedbackManager.highlight(message=f"\n» {action_text} {resource.pathname}..."))
53
+ click.echo(FeedbackManager.highlight(message=f"» Building {resource.pathname}..."))
56
54
  folder_path = path.parent
57
55
  folder_path.mkdir(parents=True, exist_ok=True)
58
56
  path.touch(exist_ok=True)
59
57
  path.write_text(resource.content)
60
- ctx.deps.build_project(test=True, silent=True)
58
+ ctx.deps.build_project(test=False, silent=True)
61
59
  action_text = "created" if not exists else "updated"
62
- click.echo(FeedbackManager.success(message=f"✓ {resource.pathname} {action_text} successfully"))
60
+ click.echo(FeedbackManager.success(message=f"✓ {resource.pathname} {action_text}"))
63
61
  ctx.deps.thinking_animation.start()
64
62
  return f"{action_text} {resource.pathname}"
65
63
 
@@ -73,3 +71,56 @@ def create_datafile(ctx: RunContext[TinybirdAgentContext], resource: Datafile) -
73
71
  click.echo(FeedbackManager.error(message=e))
74
72
  ctx.deps.thinking_animation.start()
75
73
  return f"Error creating {resource.pathname}: {e}"
74
+
75
+
76
+ def read_file(ctx: RunContext[TinybirdAgentContext], path: str) -> str:
77
+ """Reads the content of a file.
78
+
79
+ Args:
80
+ path (str): The path to the file to read. Required.
81
+
82
+ Returns:
83
+ str: The content of the file.
84
+ """
85
+ try:
86
+ ctx.deps.thinking_animation.stop()
87
+ click.echo(FeedbackManager.highlight(message=f"» Reading file {path}..."))
88
+ result = ""
89
+ with open(os.path.join(ctx.deps.folder, path), "r") as f:
90
+ result = f.read()
91
+ ctx.deps.thinking_animation.start()
92
+ except FileNotFoundError:
93
+ result = f"Error: File {path} not found (double check the file path)"
94
+
95
+ ctx.deps.thinking_animation.start()
96
+ return result
97
+
98
+
99
+ def update_file(ctx: RunContext[TinybirdAgentContext], path: str, content: str):
100
+ """Updates the content of a file.
101
+
102
+ Args:
103
+ path (str): The path to the file to update. Required.
104
+ content (str): The full file content to write. Required.
105
+ """
106
+ try:
107
+ with open(os.path.join(ctx.deps.folder, path), "w") as f:
108
+ f.write(content)
109
+ except FileNotFoundError:
110
+ return f"Error: File {path} not found (double check the file path)"
111
+
112
+ return "ok"
113
+
114
+
115
+ def create_file(ctx: RunContext[TinybirdAgentContext], path: str, content: str):
116
+ """Creates a new file with the given content.
117
+
118
+ Args:
119
+ path (str): The path to the file to create. Required.
120
+ content (str): The full file content to write. Required.
121
+ """
122
+ os.makedirs(os.path.dirname(os.path.join(ctx.deps.folder, path)), exist_ok=True)
123
+ with open(os.path.join(ctx.deps.folder, path), "w") as f:
124
+ f.write(content)
125
+
126
+ return "ok"
@@ -15,7 +15,6 @@ def deploy(ctx: RunContext[TinybirdAgentContext]) -> str:
15
15
  )
16
16
 
17
17
  if confirmation == "review":
18
- click.echo()
19
18
  feedback = show_input(ctx.deps.workspace_name)
20
19
  ctx.deps.thinking_animation.start()
21
20
  return f"User did not confirm deployment and gave the following feedback: {feedback}"
@@ -24,13 +23,11 @@ def deploy(ctx: RunContext[TinybirdAgentContext]) -> str:
24
23
  ctx.deps.thinking_animation.start()
25
24
  return "User cancelled deployment. Stop deployment."
26
25
 
27
- click.echo(FeedbackManager.highlight(message="\n» Deploying project..."))
26
+ click.echo(FeedbackManager.highlight(message="» Deploying project..."))
28
27
  ctx.deps.deploy_project()
29
28
  click.echo(FeedbackManager.success(message="✓ Project deployed successfully"))
30
29
  ctx.deps.thinking_animation.start()
31
30
  return "Project deployed successfully"
32
31
  except Exception as e:
33
- ctx.deps.thinking_animation.stop()
34
- click.echo(FeedbackManager.error(message=e))
35
32
  ctx.deps.thinking_animation.start()
36
33
  return f"Error depoying project: {e}"
@@ -1,8 +1,6 @@
1
- import click
2
1
  from pydantic_ai import RunContext
3
2
 
4
3
  from tinybird.tb.modules.agent.utils import TinybirdAgentContext, show_confirmation, show_input
5
- from tinybird.tb.modules.feedback_manager import FeedbackManager
6
4
 
7
5
 
8
6
  def deploy_check(ctx: RunContext[TinybirdAgentContext]) -> str:
@@ -15,7 +13,6 @@ def deploy_check(ctx: RunContext[TinybirdAgentContext]) -> str:
15
13
  )
16
14
 
17
15
  if confirmation == "review":
18
- click.echo()
19
16
  feedback = show_input(ctx.deps.workspace_name)
20
17
  ctx.deps.thinking_animation.start()
21
18
  return f"User did not confirm deployment check and gave the following feedback: {feedback}"
@@ -28,7 +25,5 @@ def deploy_check(ctx: RunContext[TinybirdAgentContext]) -> str:
28
25
  ctx.deps.thinking_animation.start()
29
26
  return "Project can be deployed"
30
27
  except Exception as e:
31
- ctx.deps.thinking_animation.stop()
32
- click.echo(FeedbackManager.error(message=e))
33
28
  ctx.deps.thinking_animation.start()
34
29
  return f"Project cannot be deployed: {e}"
@@ -18,9 +18,7 @@ def diff_resource(ctx: RunContext[TinybirdAgentContext], resource: Datafile) ->
18
18
  """
19
19
  try:
20
20
  ctx.deps.thinking_animation.stop()
21
- click.echo(
22
- FeedbackManager.highlight(message=f"\n» Comparing content of {resource.pathname} with Tinybird Cloud")
23
- )
21
+ click.echo(FeedbackManager.highlight(message=f"» Comparing content of {resource.pathname} with Tinybird Cloud"))
24
22
  resource.pathname = resource.pathname.removeprefix("/")
25
23
  project_file_path = Path(ctx.deps.folder) / resource.pathname
26
24
  if not project_file_path.exists():
@@ -7,7 +7,7 @@ from tinybird.tb.modules.common import echo_safe_humanfriendly_tables_format_pre
7
7
  from tinybird.tb.modules.feedback_manager import FeedbackManager
8
8
 
9
9
 
10
- def execute_query(ctx: RunContext[TinybirdAgentContext], query: str, task: str, cloud: bool = True):
10
+ def execute_query(ctx: RunContext[TinybirdAgentContext], query: str, task: str, cloud: bool = False):
11
11
  """Execute a query:
12
12
 
13
13
  Args:
@@ -6,7 +6,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
6
6
 
7
7
 
8
8
  def get_endpoint_stats(
9
- ctx: RunContext[TinybirdAgentContext], endpoint_name: str, interval_days: int = 1, cloud: bool = True
9
+ ctx: RunContext[TinybirdAgentContext], endpoint_name: str, interval_days: int = 1, cloud: bool = False
10
10
  ):
11
11
  """Get stats for an endpoint:
12
12
 
@@ -46,6 +46,5 @@ def get_endpoint_stats(
46
46
 
47
47
  result = execute_query(query=query)
48
48
  click.echo(FeedbackManager.success(message="✓ Done!"))
49
- click.echo()
50
49
  ctx.deps.thinking_animation.start()
51
50
  return f"Result for {endpoint_name} in the last {interval_days} {days}: {result}"
@@ -6,34 +6,48 @@ from tinybird.tb.modules.agent.utils import TinybirdAgentContext
6
6
  from tinybird.tb.modules.feedback_manager import FeedbackManager
7
7
 
8
8
 
9
- def get_openapi_definition(ctx: RunContext[TinybirdAgentContext], cloud: bool = True):
10
- """Get the OpenAPI definition for all endpoints in the project:
9
+ def get_openapi_definition(ctx: RunContext[TinybirdAgentContext], endpoint_name: str, cloud: bool = False):
10
+ """Get the OpenAPI definition for an endpoint:
11
11
 
12
12
  Args:
13
- cloud (bool): Whether to get the OpenAPI spec from cloud or local. Optional.
13
+ endpoint_name (str): The name of the endpoint to get the OpenAPI definition for. Required.
14
+ cloud (bool): Whether to get the OpenAPI definition from cloud or local. Optional.
14
15
 
15
16
  Returns:
16
- str: The OpenAPI spec for all endpoints in the project.
17
+ str: The OpenAPI definition for the endpoint.
17
18
  """
18
19
 
19
20
  cloud_or_local = "Cloud" if cloud else "Local"
20
21
  ctx.deps.thinking_animation.stop()
21
22
 
22
- click.echo(FeedbackManager.highlight(message=f"» Accessing Tinybird {cloud_or_local} endpoints"))
23
+ click.echo(
24
+ FeedbackManager.highlight(
25
+ message=f"» Checking OpenAPI definition for '{endpoint_name}' in Tinybird {cloud_or_local}"
26
+ )
27
+ )
23
28
  try:
24
- url = f"{ctx.deps.host}/v0/pipes/openapi.json"
29
+ host = ctx.deps.host if cloud else ctx.deps.local_host
30
+ token = ctx.deps.token if cloud else ctx.deps.local_token
31
+ url = f"{host}/v0/pipes/openapi.json"
25
32
 
26
- result = requests.get(url, headers={"Authorization": f"Bearer {ctx.deps.token}"})
33
+ result = requests.get(url, headers={"Authorization": f"Bearer {token}"})
27
34
  if result.status_code != 200:
28
- raise Exception(f"Failed to get OpenAPI spec: {result.status_code} {result.text}")
35
+ raise Exception(f"Failed to get OpenAPI definition: {result.status_code} {result.text}")
29
36
 
30
- openapi_spec = result.text
37
+ data = result.json()
38
+ openapi_definition = str(data["paths"].get(f"/pipes/{endpoint_name}.{{format}}", ""))
39
+
40
+ if not openapi_definition:
41
+ raise Exception(f"Endpoint {endpoint_name} not found in OpenAPI definition")
42
+
43
+ if not cloud:
44
+ # TODO(rafa): This is a temporary fix to get the correct host for the local environment.
45
+ openapi_definition = openapi_definition.replace("http://localhost:8001", host)
31
46
 
32
47
  click.echo(FeedbackManager.success(message="✓ Done!"))
33
- click.echo()
34
48
  ctx.deps.thinking_animation.start()
35
- return f"OpenAPI spec for {cloud_or_local} endpoints: {openapi_spec}. <dev_note>Add the base url to each path so the user can copy paste if needed: {ctx.deps.host}</dev_note>"
49
+ return f"OpenAPI definition for {cloud_or_local} endpoints: {openapi_definition}. <dev_note>Add the base url to each path so the user can copy paste if needed: {host}</dev_note>"
36
50
  except Exception as e:
37
- click.echo(FeedbackManager.error(message=f"Error getting OpenAPI spec: {e}"))
51
+ click.echo(FeedbackManager.error(message=f"Error getting OpenAPI definition: {e}"))
38
52
  ctx.deps.thinking_animation.start()
39
- return f"Error getting OpenAPI spec: {e}"
53
+ return f"Error getting OpenAPI definition: {e}"
@@ -14,6 +14,7 @@ def mock(
14
14
  data_format: str,
15
15
  rows: int,
16
16
  context: Optional[str] = None,
17
+ cloud: bool = False,
17
18
  ) -> str:
18
19
  """Create mock data for a datasource
19
20
 
@@ -22,34 +23,38 @@ def mock(
22
23
  data_format: Format of the mock data to create. Options: ndjson, csv
23
24
  rows: Number of rows to create. If not provided, the default is 10
24
25
  context: Extra context to be used to generate the mock data. Optional.
26
+ cloud: Whether to generate the mock data in the cloud or local environment. Optional.
25
27
 
26
28
  Returns:
27
29
  str: Message indicating the success or failure of the mock data generation
28
30
  """
29
31
  try:
30
32
  ctx.deps.thinking_animation.stop()
33
+ cloud_or_local = "Cloud" if cloud else "Local"
31
34
  confirmation = show_confirmation(
32
- title=f"Generate mock data for datasource '{datasource_name}'?",
35
+ title=f"Generate mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local}?",
33
36
  skip_confirmation=ctx.deps.dangerously_skip_permissions,
34
37
  )
35
38
 
36
39
  if confirmation == "review":
37
- click.echo()
38
40
  feedback = show_input(ctx.deps.workspace_name)
39
41
  ctx.deps.thinking_animation.start()
40
- return f"User did not confirm mock data generation and gave the following feedback: {feedback}"
42
+ return f"User did not confirm mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local} and gave the following feedback: {feedback}"
41
43
 
42
44
  if confirmation == "cancel":
43
45
  ctx.deps.thinking_animation.start()
44
- return "User cancelled mock data generation. Stop mock data generation."
46
+ return f"User cancelled mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local}. Stop mock data generation."
45
47
 
46
- click.echo(FeedbackManager.highlight(message=f"\n» Generating mock data for {datasource_name}..."))
48
+ click.echo(FeedbackManager.highlight(message=f"» Generating mock data for {datasource_name}..."))
47
49
  data = ctx.deps.mock_data(datasource_name=datasource_name, data_format=data_format, rows=rows, context=context)
48
50
  fixture_path = persist_fixture(datasource_name, data, ctx.deps.folder, format=data_format)
49
- ctx.deps.append_data(datasource_name=datasource_name, path=str(fixture_path))
51
+ if cloud:
52
+ ctx.deps.append_data_cloud(datasource_name=datasource_name, path=str(fixture_path))
53
+ else:
54
+ ctx.deps.append_data_local(datasource_name=datasource_name, path=str(fixture_path))
50
55
  click.echo(FeedbackManager.success(message=f"✓ Data generated for {datasource_name}"))
51
56
  ctx.deps.thinking_animation.start()
52
- return f"Mock data generated successfully for datasource {datasource_name}"
57
+ return f"Mock data generated successfully for datasource '{datasource_name}' in Tinybird {cloud_or_local}"
53
58
  except Exception as e:
54
59
  ctx.deps.thinking_animation.stop()
55
60
  error_message = str(e)
@@ -57,7 +62,7 @@ def mock(
57
62
  try:
58
63
  if "in quarantine" in error_message:
59
64
  click.echo(
60
- FeedbackManager.highlight(message=f"\n» Looking for errors in {datasource_name}_quarantine...")
65
+ FeedbackManager.highlight(message=f"» Looking for errors in {datasource_name}_quarantine...")
61
66
  )
62
67
  query = f"select * from {datasource_name}_quarantine order by insertion_date desc limit 5 FORMAT CSVWithNames"
63
68
  quarantine_data = ctx.deps.execute_query_local(query=query)
@@ -69,5 +74,8 @@ def mock(
69
74
  except Exception as quarantine_error:
70
75
  error_message = error_message + f"\nError accessing to {datasource_name}_quarantine: {quarantine_error}"
71
76
 
77
+ if "must be created first with 'mode=create'" in error_message:
78
+ error_message = error_message + "\nBuild the project again."
79
+
72
80
  ctx.deps.thinking_animation.start()
73
- return f"Error generating mock data: {error_message}"
81
+ return f"Error generating mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local}: {error_message}"