tinybird 0.0.1.dev281__py3-none-any.whl → 0.0.1.dev283__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.

@@ -184,7 +184,7 @@ class CopyParameters(Parameters):
184
184
 
185
185
  class MaterializedParameters(Parameters):
186
186
  MANDATORY_ATTRIBUTES = PipeParameters.MANDATORY_ATTRIBUTES.union({"datasource"})
187
- ACCEPTED_ATTRIBUTES = PipeParameters.ACCEPTED_ATTRIBUTES.union(MANDATORY_ATTRIBUTES)
187
+ ACCEPTED_ATTRIBUTES = PipeParameters.ACCEPTED_ATTRIBUTES.union(MANDATORY_ATTRIBUTES).union({"deployment_method"})
188
188
 
189
189
 
190
190
  class SinkParameters(Parameters):
@@ -294,6 +294,13 @@ class Datafile:
294
294
  def set_kind(self, kind: DatafileKind):
295
295
  self.kind = kind
296
296
 
297
+ def validate_standard_node(self, node: Dict[str, Any]):
298
+ for key in node.keys():
299
+ if key not in PipeParameters.valid_params():
300
+ raise DatafileValidationError(
301
+ f"Standard node {repr(node['name'])} has an invalid attribute ({PipeParameters.canonical_name(key)})"
302
+ )
303
+
297
304
  def validate_copy_node(self, node: Dict[str, Any]):
298
305
  if missing := [param for param in CopyParameters.required_params() if param not in node]:
299
306
  raise DatafileValidationError(
@@ -412,13 +419,6 @@ class Datafile:
412
419
 
413
420
  def validate(self):
414
421
  if self.kind == DatafileKind.pipe:
415
- # TODO(eclbg):
416
- # [x] node names are unique
417
- # [x] SQL in all nodes
418
- # [x] Materialized nodes have target datasource
419
- # [x] Only one materialized node
420
- # [x] Only one node of any specific type
421
- # (rbarbadillo): there's a HUGE amount of validations in api_pipes.py, we should somehow merge them
422
422
  non_standard_nodes_count = 0
423
423
  for node in self.nodes:
424
424
  node_type = node.get("type", "").lower()
@@ -432,10 +432,13 @@ class Datafile:
432
432
  self.validate_copy_node(node)
433
433
  if node_type == PipeNodeTypes.DATA_SINK:
434
434
  self.validate_sink_node(node)
435
+ if node_type in {PipeNodeTypes.STANDARD, ""}:
436
+ self.validate_standard_node(node)
435
437
  if node_type not in VALID_PIPE_NODE_TYPES:
436
438
  raise DatafileValidationError(
437
439
  f"Invalid node '{repr(node['name'])}' of type ({node_type}). Allowed node types: {VISIBLE_PIPE_NODE_TYPES}"
438
440
  )
441
+
439
442
  for token in self.tokens:
440
443
  if token["permission"].upper() != "READ":
441
444
  raise DatafileValidationError(
@@ -1983,6 +1986,7 @@ def parse(
1983
1986
  "include": include,
1984
1987
  "sql": sql("sql"),
1985
1988
  "version": version,
1989
+ "deployment_method": assign_var("deployment_method", allowed_values={"alter"}),
1986
1990
  "export_connection_name": assign_var("export_connection_name"),
1987
1991
  "export_schedule": assign_var("export_schedule"),
1988
1992
  "export_bucket_uri": assign_var("export_bucket_uri"),
tinybird/tb/__cli__.py CHANGED
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/forward/commands'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '0.0.1.dev281'
8
- __revision__ = 'a7365be'
7
+ __version__ = '0.0.1.dev283'
8
+ __revision__ = 'af675c9'
@@ -28,6 +28,7 @@ from tinybird.tb.modules.agent.memory import (
28
28
  get_last_messages_from_last_user_prompt,
29
29
  save_messages,
30
30
  )
31
+ from tinybird.tb.modules.agent.mock_agent import MockAgent
31
32
  from tinybird.tb.modules.agent.models import create_model
32
33
  from tinybird.tb.modules.agent.prompts import (
33
34
  agent_system_prompt,
@@ -45,7 +46,6 @@ from tinybird.tb.modules.agent.tools.deploy_check import deploy_check
45
46
  from tinybird.tb.modules.agent.tools.diff_resource import diff_resource
46
47
  from tinybird.tb.modules.agent.tools.get_endpoint_stats import get_endpoint_stats
47
48
  from tinybird.tb.modules.agent.tools.get_openapi_definition import get_openapi_definition
48
- from tinybird.tb.modules.agent.tools.mock import mock
49
49
  from tinybird.tb.modules.agent.tools.plan import plan
50
50
  from tinybird.tb.modules.agent.tools.secret import create_or_update_secrets
51
51
  from tinybird.tb.modules.agent.utils import AgentRunCancelled, TinybirdAgentContext, show_confirmation, show_input
@@ -111,7 +111,6 @@ class TinybirdAgent:
111
111
  Tool(build, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
112
112
  Tool(deploy, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
113
113
  Tool(deploy_check, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
114
- Tool(mock, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
115
114
  Tool(analyze_file, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
116
115
  Tool(analyze_url, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
117
116
  Tool(append_file, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
@@ -166,6 +165,16 @@ class TinybirdAgent:
166
165
  workspace_id=workspace_id,
167
166
  project=self.project,
168
167
  )
168
+ self.mock_agent = MockAgent(
169
+ dangerously_skip_permissions=self.dangerously_skip_permissions,
170
+ prompt_mode=prompt_mode,
171
+ thinking_animation=self.thinking_animation,
172
+ token=self.token,
173
+ user_token=self.user_token,
174
+ host=self.host,
175
+ workspace_id=workspace_id,
176
+ project=self.project,
177
+ )
169
178
 
170
179
  @self.agent.tool
171
180
  def manage_tests(ctx: RunContext[TinybirdAgentContext], task: str) -> str:
@@ -210,6 +219,25 @@ class TinybirdAgent:
210
219
  result = self.explore_agent.run(task, deps=ctx.deps, usage=ctx.usage)
211
220
  return result.output or "No result returned"
212
221
 
222
+ @self.agent.tool
223
+ def mock(
224
+ ctx: RunContext[TinybirdAgentContext], datasource_name: str, rows: int, data_format: str, task: str
225
+ ) -> str:
226
+ """Generate mock data for a datasource.
227
+
228
+ Args:
229
+ datasource_name (str): The datasource name to generate mock data for. Required.
230
+ rows (int): Number of rows to create. If not provided, the default is 10. Required.
231
+ data_format (str): Format of the mock data to create. Options: ndjson, csv. Required.
232
+ task (str): Extra details about how to generate the mock data (nested json if any, sample row to help with the generation, etc). Required.
233
+
234
+ Returns:
235
+ str: The result of the mock data generation.
236
+ """
237
+ user_input = f"Datasource name: {datasource_name}\nRows: {rows}\nData format: {data_format}\nTask: {task}"
238
+ result = self.mock_agent.run(user_input, deps=ctx.deps, usage=ctx.usage)
239
+ return result.output or "No result returned"
240
+
213
241
  @self.agent.instructions
214
242
  def get_local_host(ctx: RunContext[TinybirdAgentContext]) -> str:
215
243
  return f"""
@@ -50,6 +50,11 @@ You can do the following:
50
50
  - Executing SQL queries against Tinybird Cloud or Tinybird Local.
51
51
  - Requesting endpoints in Tinybird Cloud or Tinybird Local.
52
52
  - Visualizing data as a chart using execute_query tool with the `script` parameter.
53
+
54
+ IMPORTANT: Use always the last environment used in previous queries or endpoint requests (cloud_or_local: str). If you don't have any information about the last environment, use None.
55
+ IMPORTANT: If some resource is not found in a environment, you can use the `diff_resource` tool to check the status across environments.
56
+
57
+ Once you finish the task, return a valid response for the task to complete.
53
58
  """,
54
59
  tone_and_style_instructions,
55
60
  explore_data_instructions,
@@ -0,0 +1,206 @@
1
+ from datetime import datetime
2
+
3
+ from pydantic_ai import Agent, RunContext, Tool
4
+ from pydantic_ai.messages import ModelMessage
5
+ from pydantic_ai.usage import Usage
6
+
7
+ from tinybird.tb.modules.agent.animations import ThinkingAnimation
8
+ from tinybird.tb.modules.agent.models import create_model
9
+ from tinybird.tb.modules.agent.prompts import resources_prompt
10
+ from tinybird.tb.modules.agent.tools.mock import generate_mock_fixture
11
+ from tinybird.tb.modules.agent.utils import TinybirdAgentContext
12
+ from tinybird.tb.modules.project import Project
13
+
14
+ mock_sql_instructions = """
15
+ ## When generating the SQL query to generate mock data
16
+
17
+ Given the schema for a Tinybird datasource, return a valid clickhouse sql query to generate some random data that matches that schema.
18
+ Response format MUST be just a valid clickhouse sql query.
19
+
20
+ <example>
21
+ <example_datasource_schema>
22
+ SCHEMA >
23
+ experience_gained Int16 `json:$.experience_gained`,
24
+ level Int16 `json:$.level`,
25
+ monster_kills Int16 `json:$.monster_kills`,
26
+ player_id String `json:$.player_id`,
27
+ pvp_kills Int16 `json:$.pvp_kills`,
28
+ quest_completions Int16 `json:$.quest_completions`,
29
+ timestamp DateTime `json:$.timestamp`
30
+ </example_datasource_schema>
31
+ <example_output>
32
+
33
+ SELECT
34
+ rand() % 1000 AS experience_gained, -- Random experience gained between 0 and 999
35
+ 1 + rand() % 100 AS level, -- Random level between 1 and 100
36
+ rand() % 500 AS monster_kills, -- Random monster kills between 0 and 499
37
+ concat('player_', toString(rand() % 10000)) AS player_id, -- Random player IDs like "player_1234"
38
+ rand() % 50 AS pvp_kills, -- Random PvP kills between 0 and 49
39
+ rand() % 200 AS quest_completions, -- Random quest completions between 0 and 199
40
+ now() - rand() % 86400 AS timestamp -- Random timestamp within the last day
41
+ FROM numbers(10)
42
+ </example_output>
43
+ </example>
44
+
45
+ <instructions>
46
+ - The query MUST return a random sample of data that matches the schema.
47
+ - The query MUST return a valid clickhouse sql query.
48
+ - The query MUST be valid for clickhouse and Tinybird.
49
+ - FROM numbers([number_of_rows]) part is mandatory.
50
+ - If json paths are present (e.g. `userAgent` String `json:$.userAgent`), rely on the json paths to generate the sample record.
51
+ - If the schema has nested json paths (e.g. `json:$.location.country`), generate nested JSON objects accordingly.
52
+ - Use recent dates to avoid generating dates that are too far in the past.
53
+ - Do NOT include ```clickhouse or ```sql or any other wrapping text to the sql query.
54
+ - Do NOT use any of these functions: elementAt
55
+ - Do NOT add a semicolon at the end of the query
56
+ - Do NOT add any FORMAT at the end of the query, because it will be added later by Tinybird.
57
+ - Do not use any function that is not present in the list of general functions, character insensitive functions and aggregate functions.
58
+ - If the function is not present in the list, the sql query will fail, so avoid at all costs to use any function that is not present in the list.
59
+ </instructions>
60
+
61
+ <more_examples>
62
+ # Examples with different schemas, like an array field or a nested JSON field:
63
+
64
+ ## Example schema with an array field:
65
+
66
+ ### Schema:
67
+
68
+ SCHEMA >
69
+ `order_id` UInt64 `json:$.order_id`,
70
+ `customer_id` UInt64 `json:$.customer_id`,
71
+ `order_date` DateTime `json:$.order_date`,
72
+ `total_amount` Float64 `json:$.total_amount`,
73
+ `items` Array(String) `json:$.items[:]` // This is an array field
74
+
75
+ ### Desired final output of the query:
76
+ {
77
+ "order_id": 123456,
78
+ "customer_id": 7890,
79
+ "order_date": "2024-11-30T10:30:00.000Z",
80
+ "total_amount": 150.0,
81
+ "items": ["item1", "item2", "item3"]
82
+ }
83
+
84
+ ### Example SQL output with an array field:
85
+
86
+ SELECT
87
+ concat('ord_', toString(rand() % 10000)) AS order_id,
88
+ concat('cust_', toString(rand() % 10000)) AS customer_id,
89
+ now() - rand() % 86400 AS order_date,
90
+ rand() % 1000 AS total_amount,
91
+ arrayMap(x -> concat('item_', toString(x)), range(1, rand() % 5 + 1)) AS items
92
+ FROM numbers(ROWS)
93
+
94
+ ## Example schema with nested JSON paths:
95
+
96
+ ### Schema:
97
+
98
+ SCHEMA >
99
+ `timestamp` DateTime `json:$.timestamp`,
100
+ `location_country` String `json:$.location.country`,
101
+ `location_region` String `json:$.location.region`,
102
+ `location_city` String `json:$.location.city`,
103
+ `location_latitude` String `json:$.location.latitude`,
104
+ `location_longitude` String `json:$.location.longitude`
105
+
106
+ ### Important: Understanding JSON paths
107
+ When you see json paths like `json:$.location.country`, it means the data should be structured as nested JSON:
108
+ - `json:$.location.country` → the country field is nested inside the location object
109
+ - `json:$.location.region` → the region field is nested inside the location object
110
+
111
+ ### Desired final output structure:
112
+ {
113
+ "timestamp": "2024-11-30T10:30:00.000Z",
114
+ "location": {
115
+ "country": "United States",
116
+ "region": "California",
117
+ "city": "San Francisco",
118
+ "latitude": "37.7749",
119
+ "longitude": "-122.4194"
120
+ }
121
+ }
122
+
123
+ ### Example SQL output for nested JSON paths:
124
+
125
+ SELECT
126
+ timestamp,
127
+ CAST(concat('{
128
+ "country": "', country, '",
129
+ "region": "', region, '",
130
+ "city": "', city, '",
131
+ "latitude": "', latitude, '",
132
+ "longitude": "', longitude, '"
133
+ }'), 'JSON') AS location
134
+ FROM
135
+ (
136
+ SELECT
137
+ now() - rand() % 86400 AS timestamp,
138
+ ['United States', 'Canada', 'United Kingdom', 'Germany', 'France'][(rand() % 5) + 1] AS country,
139
+ ['California', 'Texas', 'New York', 'Ontario', 'London'][(rand() % 5) + 1] AS region,
140
+ ['San Francisco', 'Los Angeles', 'New York', 'Toronto', 'London'][(rand() % 5) + 1] AS city,
141
+ toString(round(rand() * 180 - 90, 4)) AS latitude,
142
+ toString(round(rand() * 360 - 180, 4)) AS longitude
143
+ FROM numbers(10)
144
+ )
145
+ </more_examples>
146
+ """
147
+
148
+
149
+ class MockAgent:
150
+ def __init__(
151
+ self,
152
+ dangerously_skip_permissions: bool,
153
+ prompt_mode: bool,
154
+ token: str,
155
+ user_token: str,
156
+ host: str,
157
+ workspace_id: str,
158
+ project: Project,
159
+ thinking_animation: ThinkingAnimation,
160
+ ):
161
+ self.dangerously_skip_permissions = dangerously_skip_permissions or prompt_mode
162
+ self.token = token
163
+ self.user_token = user_token
164
+ self.host = host
165
+ self.workspace_id = workspace_id
166
+ self.project = project
167
+ self.thinking_animation = thinking_animation
168
+ self.messages: list[ModelMessage] = []
169
+ self.agent = Agent(
170
+ deps_type=TinybirdAgentContext,
171
+ instructions=[
172
+ f"""
173
+ You are part of Tinybird Code, an agentic CLI that can help users to work with Tinybird.
174
+ You are a sub-agent of the main Tinybird Code agent. You are responsible for generating mock data for a datasource.
175
+ You will be given a datasource name and you will use `generate_mock_fixture` tool to generate a sql query to execute to generate the mock data.
176
+ When finish return the result of the mock data generation: the path of the fixture file, the number of rows generated, the datasource name and if the data was appended to the datasource.
177
+
178
+ # Info
179
+ Today is {datetime.now().strftime("%Y-%m-%d")}
180
+ """,
181
+ mock_sql_instructions,
182
+ ],
183
+ tools=[
184
+ Tool(
185
+ generate_mock_fixture,
186
+ docstring_format="google",
187
+ require_parameter_descriptions=True,
188
+ takes_ctx=True,
189
+ ),
190
+ ],
191
+ )
192
+
193
+ @self.agent.instructions
194
+ def get_project_files(ctx: RunContext[TinybirdAgentContext]) -> str:
195
+ return resources_prompt(self.project)
196
+
197
+ def run(self, task: str, deps: TinybirdAgentContext, usage: Usage):
198
+ result = self.agent.run_sync(
199
+ task,
200
+ deps=deps,
201
+ usage=usage,
202
+ message_history=self.messages,
203
+ model=create_model(self.user_token, self.host, self.workspace_id, run_id=deps.run_id),
204
+ )
205
+ self.messages.extend(result.new_messages())
206
+ return result
@@ -1,9 +1,35 @@
1
1
  from typing import Optional
2
2
 
3
3
  from anthropic import AsyncAnthropic
4
- from httpx import AsyncClient
4
+ from httpx import AsyncClient, HTTPStatusError
5
5
  from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelName
6
6
  from pydantic_ai.providers.anthropic import AnthropicProvider
7
+ from pydantic_ai.retries import AsyncTenacityTransport, wait_retry_after
8
+ from tenacity import AsyncRetrying, retry_if_exception_type, stop_after_attempt, wait_exponential
9
+
10
+
11
+ def create_retrying_client(token: str, workspace_id: str):
12
+ """Create a client with smart retry handling for multiple error types."""
13
+
14
+ def should_retry_status(response):
15
+ """Raise exceptions for retryable HTTP status codes."""
16
+ if response.status_code in (400, 429, 502, 503, 504):
17
+ response.raise_for_status() # This will raise HTTPStatusError
18
+
19
+ transport = AsyncTenacityTransport(
20
+ controller=AsyncRetrying(
21
+ # Retry on HTTP errors and connection issues
22
+ retry=retry_if_exception_type((HTTPStatusError, ConnectionError)),
23
+ # Smart waiting: respects Retry-After headers, falls back to exponential backoff
24
+ wait=wait_retry_after(fallback_strategy=wait_exponential(multiplier=1, max=60), max_wait=300),
25
+ # Stop after 5 attempts
26
+ stop=stop_after_attempt(5),
27
+ # Re-raise the last exception if all retries fail
28
+ reraise=True,
29
+ ),
30
+ validate_response=should_retry_status,
31
+ )
32
+ return AsyncClient(transport=transport, params={"token": token, "workspace_id": workspace_id})
7
33
 
8
34
 
9
35
  def create_model(
@@ -19,7 +45,7 @@ def create_model(
19
45
 
20
46
  client = AsyncAnthropic(
21
47
  base_url=base_url,
22
- http_client=AsyncClient(params={"token": token, "workspace_id": workspace_id}),
48
+ http_client=create_retrying_client(token, workspace_id),
23
49
  auth_token=token,
24
50
  default_headers=default_headers,
25
51
  )
@@ -19,7 +19,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
19
19
  def create_datafile(
20
20
  ctx: RunContext[TinybirdAgentContext], name: str, type: str, description: str, content: str, pathname: str
21
21
  ) -> str:
22
- """Given a resource representation, create or update a datafile in the project folder
22
+ """Given a resource representation, create or update a datafile (.datasource, .connection, .pipe) in the project folder
23
23
 
24
24
  Args:
25
25
  name (str): The name of the datafile. Required.
@@ -35,7 +35,12 @@ def deploy(ctx: RunContext[TinybirdAgentContext], allow_destructive_operations:
35
35
  ctx.deps.thinking_animation.start()
36
36
  return f"User did not confirm deployment and gave the following feedback: {feedback}"
37
37
 
38
- click.echo(FeedbackManager.highlight(message="» Deploying project..."))
38
+ allow_destructive_operations_flag = " --allow-destructive-operations" if allow_destructive_operations else ""
39
+ click.echo(
40
+ FeedbackManager.highlight(
41
+ message=f"» Running command: tb --cloud deploy{allow_destructive_operations_flag}"
42
+ )
43
+ )
39
44
  ctx.deps.deploy_project(allow_destructive_operations=allow_destructive_operations)
40
45
  click.echo(FeedbackManager.success(message="✓ Project deployed successfully"))
41
46
  ctx.deps.thinking_animation.start()
@@ -1,7 +1,9 @@
1
+ import click
1
2
  from pydantic_ai import RunContext
2
3
 
3
4
  from tinybird.tb.modules.agent.utils import TinybirdAgentContext, show_confirmation, show_input
4
5
  from tinybird.tb.modules.exceptions import CLIDeploymentException
6
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
5
7
 
6
8
 
7
9
  def deploy_check(ctx: RunContext[TinybirdAgentContext]) -> str:
@@ -18,6 +20,7 @@ def deploy_check(ctx: RunContext[TinybirdAgentContext]) -> str:
18
20
  ctx.deps.thinking_animation.start()
19
21
  return f"User did not confirm deployment check and gave the following feedback: {feedback}"
20
22
 
23
+ click.echo(FeedbackManager.highlight(message="» Running command: tb --cloud deploy --check"))
21
24
  ctx.deps.deploy_check_project()
22
25
  ctx.deps.thinking_animation.start()
23
26
  return "Project can be deployed"
@@ -8,7 +8,7 @@ import click
8
8
  import humanfriendly
9
9
  from pydantic_ai import RunContext
10
10
 
11
- from tinybird.tb.modules.agent.utils import TinybirdAgentContext
11
+ from tinybird.tb.modules.agent.utils import TinybirdAgentContext, show_env_options
12
12
  from tinybird.tb.modules.common import echo_safe_humanfriendly_tables_format_pretty_table
13
13
  from tinybird.tb.modules.feedback_manager import FeedbackManager
14
14
 
@@ -35,23 +35,24 @@ def execute_query(
35
35
  ctx: RunContext[TinybirdAgentContext],
36
36
  query: str,
37
37
  task: str,
38
- cloud: Optional[bool] = None,
38
+ cloud_or_local: Optional[str] = None,
39
39
  script: Optional[str] = None,
40
40
  export_format: Optional[str] = None,
41
+ explanation_why_not_know_about_last_environment: Optional[str] = None,
41
42
  ):
42
43
  """Execute a query and return the result as a table, chart or exported file.
43
44
 
44
45
  Args:
45
46
  query (str): The query to execute. Required.
46
47
  task (str): The purpose of the query. Required.
47
- cloud (bool): Whether to execute the query on cloud or local. If None (user didn't specify), will ask user to clarify. Defaults to local (False) in dangerous skip permissions mode.
48
+ cloud_or_local (str): Whether to execute the query on cloud or local. Use the last environment used in previous queries or endpoint requests. If you don't have any information about the last environment, use None. Options: cloud, local.
48
49
  script (str): Python script using plotext to render the query results as a chart. The script will have access to 'data' (list of dicts), 'meta' (list of column info dicts), 'terminal_width' and 'terminal_height' variables. Always use plt.theme("clear") for transparent background and plt.plot_size(terminal_width, terminal_height) for proper sizing. For bar charts, use the simple versions: plt.simple_bar(), plt.simple_multiple_bar(), and plt.simple_stacked_bar(). Optional.
49
50
  export_format (str): The format to export the query results to. Options: csv, json, ndjson. Optional.
51
+ explanation_why_not_know_about_last_environment (str): Why you don't know about the last environment used in previous queries or endpoint requests. Required.
50
52
 
51
53
  Returns:
52
54
  str: The result of the query.
53
55
  """
54
-
55
56
  try:
56
57
  for forbidden_command in forbidden_commands:
57
58
  if forbidden_command in query.lower():
@@ -61,24 +62,21 @@ def execute_query(
61
62
  if query.lower().startswith(forbidden_command):
62
63
  return f"Error executing query: {forbidden_command} is not allowed."
63
64
 
64
- # Handle cloud parameter - ask user if uncertain and not in dangerous skip mode
65
- if cloud is None:
65
+ # Handle cloud_or_local parameter - ask user if uncertain and not in dangerous skip mode
66
+ if cloud_or_local is None:
66
67
  if ctx.deps.dangerously_skip_permissions:
67
68
  # Default to local when in dangerous skip mode
68
- cloud = False
69
+ cloud_or_local = "local"
69
70
  else:
70
71
  # Ask the user to choose execution mode
71
- from tinybird.tb.modules.agent.utils import show_env_options
72
72
 
73
73
  cloud = show_env_options(ctx)
74
74
  if cloud is None:
75
75
  return "Query execution cancelled by user."
76
+ cloud_or_local = "cloud" if cloud else "local"
76
77
 
77
- cloud_or_local = "cloud" if cloud else "local"
78
78
  ctx.deps.thinking_animation.stop()
79
-
80
79
  click.echo(FeedbackManager.highlight(message=f"» Executing query to {cloud_or_local}:\n{query}\n"))
81
-
82
80
  is_templating = query.strip().startswith("%")
83
81
  query_format = "JSON"
84
82
  if export_format == "csv":
@@ -94,7 +92,7 @@ def execute_query(
94
92
  else:
95
93
  query = f"SELECT * FROM ({query}) FORMAT {query_format}"
96
94
 
97
- execute_query = ctx.deps.execute_query_cloud if cloud else ctx.deps.execute_query_local
95
+ execute_query = ctx.deps.execute_query_cloud if cloud_or_local == "cloud" else ctx.deps.execute_query_local
98
96
  result = execute_query(query=query)
99
97
  if export_format:
100
98
  file_extension = f".{export_format}"
@@ -4,50 +4,98 @@ from pydantic_ai import RunContext
4
4
  from tinybird.tb.modules.agent.utils import (
5
5
  AgentRunCancelled,
6
6
  TinybirdAgentContext,
7
+ create_terminal_box,
7
8
  show_confirmation,
8
9
  show_input,
9
10
  )
10
- from tinybird.tb.modules.common import echo_safe_humanfriendly_tables_format_pretty_table
11
+ from tinybird.tb.modules.common import echo_safe_humanfriendly_tables_format_pretty_table, format_data_to_ndjson
11
12
  from tinybird.tb.modules.datafile.fixture import persist_fixture
12
13
  from tinybird.tb.modules.feedback_manager import FeedbackManager
13
14
 
14
15
 
15
- def mock(
16
- ctx: RunContext[TinybirdAgentContext], datasource_name: str, data_format: str, rows: int, description: str
16
+ def generate_mock_fixture(
17
+ ctx: RunContext[TinybirdAgentContext], datasource_name: str, sql: str, data_format: str, rows: int, task: str
17
18
  ) -> str:
18
- """Create mock data for a datasource
19
+ """Given a datasource name and a sql query to execute, generate a fixture file with mock data and append it to the datasource.
19
20
 
20
21
  Args:
21
22
  datasource_name (str): Name of the datasource to create mock data for. Required.
23
+ sql (str): SQL query to execute to generate the mock data. Required.
22
24
  data_format (str): Format of the mock data to create. Options: ndjson, csv. Required.
23
25
  rows (int): Number of rows to create. If not provided, the default is 10. Required.
24
- description (str): Extra details about how to generate the mock data (nested json if any, sample row to help with the generation, etc). You can use this to fix issues with the mock data generation. Required.
26
+ task (str): Extra details about how to generate the mock data (nested json if any, sample row to help with the generation, etc). You can use this to fix issues with the mock data generation. Required.
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()
31
- cloud_or_local = "Local"
33
+
34
+ click.echo(FeedbackManager.highlight(message=f"» Generating mock data for datasource '{datasource_name}'..."))
35
+ try:
36
+ sql_format = "JSON" if data_format == "ndjson" else "CSV"
37
+ sql = f"SELECT * FROM ({sql}) LIMIT {rows} FORMAT {sql_format}"
38
+ result = ctx.deps.execute_query_local(query=sql)
39
+ except Exception as e:
40
+ click.echo(
41
+ FeedbackManager.error(message="✗ Failed to generate a valid SQL query for generating mock data.\n{e}")
42
+ )
43
+ ctx.deps.thinking_animation.start()
44
+ return f"Failed to generate a valid sql for generating mock data for datasource '{datasource_name}'. SQL: {sql}\nError: {e}"
45
+
46
+ preview_content = ""
47
+ if sql_format == "JSON":
48
+ data = result.get("data", [])[:rows]
49
+ preview_content = str(format_data_to_ndjson(data[:10]))
50
+
51
+ if len(data) != rows:
52
+ raise Exception(
53
+ f"Failed to generate a valid sql for generating mock data for datasource '{datasource_name}'. Rows generated: {len(data)} != {rows}. SQL: {sql}\nError: {result}"
54
+ )
55
+
56
+ error_response = result.get("error", None)
57
+ if error_response:
58
+ raise Exception(
59
+ f"Failed to generate a valid sql for generating mock data for datasource '{datasource_name}'. SQL: {sql}\nError: {error_response}"
60
+ )
61
+
62
+ else:
63
+ data = result
64
+ preview_content = str(data[:1000])
65
+
66
+ if isinstance(data, dict):
67
+ data = data.get("data", [])[:rows]
68
+ preview_content = str(format_data_to_ndjson(data[:10]))
69
+
70
+ content = create_terminal_box(preview_content, title=f"fixtures/{datasource_name}.{data_format}")
71
+ click.echo(content)
72
+ click.echo("Showing a preview of the file.\n")
32
73
  confirmation = show_confirmation(
33
- title=f"Generate mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local}?",
74
+ title=f"Create fixture file for datasource '{datasource_name}'?",
34
75
  skip_confirmation=ctx.deps.dangerously_skip_permissions,
35
76
  )
36
77
 
37
78
  if confirmation == "review":
38
79
  feedback = show_input(ctx.deps.workspace_name)
39
80
  ctx.deps.thinking_animation.start()
40
- return f"User did not confirm mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local} and gave the following feedback: {feedback}"
81
+ return f"User did not confirm mock data for datasource '{datasource_name}' in Tinybird Local and gave the following feedback: {feedback}"
41
82
 
42
- click.echo(FeedbackManager.highlight(message=f"» Generating mock data for {datasource_name}..."))
43
- data = ctx.deps.mock_data(
44
- datasource_name=datasource_name, data_format=data_format, rows=rows, context=description
45
- )
46
83
  fixture_path = persist_fixture(datasource_name, data, ctx.deps.folder, format=data_format)
84
+ fixture_path_name = f"fixtures/{fixture_path.name}"
85
+ click.echo(FeedbackManager.success(message=f"✓ {fixture_path_name} created"))
86
+ confirmation = show_confirmation(
87
+ title=f"Append {fixture_path_name} to datasource '{datasource_name}'?",
88
+ skip_confirmation=ctx.deps.dangerously_skip_permissions,
89
+ )
90
+ if confirmation == "review":
91
+ feedback = show_input(ctx.deps.workspace_name)
92
+ ctx.deps.thinking_animation.start()
93
+ return f"Mock data was generated in {fixture_path_name} but user did not confirm appending {fixture_path_name} to datasource '{datasource_name}' in Tinybird Local and gave the following feedback: {feedback}"
94
+
47
95
  ctx.deps.append_data_local(datasource_name=datasource_name, path=str(fixture_path))
48
- click.echo(FeedbackManager.success(message=f"✓ Data generated for {datasource_name}"))
96
+ click.echo(FeedbackManager.success(message=f"✓ Data appended to datasource '{datasource_name}'"))
49
97
  ctx.deps.thinking_animation.start()
50
- return f"Mock data generated successfully for datasource '{datasource_name}' in Tinybird {cloud_or_local}"
98
+ return f"Mock data generated in {fixture_path_name} and appended to datasource '{datasource_name}' in Tinybird Local"
51
99
  except AgentRunCancelled as e:
52
100
  raise e
53
101
  except Exception as e:
@@ -84,4 +132,4 @@ def mock(
84
132
  error_message = error_message + "\nBuild the project again."
85
133
 
86
134
  ctx.deps.thinking_animation.start()
87
- return f"Error generating mock data for datasource '{datasource_name}' in Tinybird {cloud_or_local}: {error_message}"
135
+ return f"Error generating mock data for datasource '{datasource_name}' in Tinybird Local: {error_message}"
@@ -13,30 +13,32 @@ def request_endpoint(
13
13
  ctx: RunContext[TinybirdAgentContext],
14
14
  endpoint_name: str,
15
15
  params: Optional[dict[str, str]] = None,
16
- cloud: Optional[bool] = None,
16
+ cloud_or_local: Optional[str] = None,
17
+ explanation_why_not_know_about_last_environment: Optional[str] = None,
17
18
  ):
18
19
  """Request an endpoint:
19
20
 
20
21
  Args:
21
22
  endpoint_name (str): The name of the endpoint to request. Required.
22
23
  params (dict): The parameters to pass to the endpoint. Optional.
23
- cloud (bool): Whether to request the endpoint on cloud or local. If None (user didn't specify), will ask user to clarify. Defaults to local (False) in dangerous skip permissions mode.
24
+ cloud_or_local (str): Whether to request the endpoint on cloud or local. Use the last environment used in previous queries or endpoint requests. If you don't have any information about the last environment, use None. Options: cloud, local. Optional.
25
+ explanation_why_not_know_about_last_environment (str): Why you don't know about the last environment used in previous queries or endpoint requests. Required.
24
26
 
25
27
  Returns:
26
28
  str: The result of the query.
27
29
  """
28
30
  try:
29
31
  # Handle cloud parameter - ask user if uncertain and not in dangerous skip mode
30
- if cloud is None:
32
+ if cloud_or_local is None:
31
33
  if ctx.deps.dangerously_skip_permissions:
32
34
  # Default to local when in dangerous skip mode
33
- cloud = False
35
+ cloud_or_local = "local"
34
36
  else:
35
37
  # Ask the user to choose execution mode
36
38
  cloud = show_env_options(ctx)
37
39
  if cloud is None:
38
40
  return "Endpoint request cancelled by user."
39
- cloud_or_local = "cloud" if cloud else "local"
41
+ cloud_or_local = "cloud" if cloud else "local"
40
42
  ctx.deps.thinking_animation.stop()
41
43
  with_params = f" with params {params}" if params else ""
42
44
  click.echo(
@@ -45,7 +47,9 @@ def request_endpoint(
45
47
  )
46
48
  )
47
49
 
48
- request_endpoint = ctx.deps.request_endpoint_cloud if cloud else ctx.deps.request_endpoint_local
50
+ request_endpoint = (
51
+ ctx.deps.request_endpoint_cloud if cloud_or_local == "cloud" else ctx.deps.request_endpoint_local
52
+ )
49
53
  result = request_endpoint(endpoint_name=endpoint_name, params=params)
50
54
 
51
55
  # Apply output limiting using the utility function
@@ -257,19 +257,31 @@ def open_url(url: str, *, new_tab: bool = False) -> bool:
257
257
 
258
258
  # 2. Inside WSL, prefer `wslview` if the user has it (wslu package).
259
259
  if _running_in_wsl() and shutil.which("wslview"):
260
- subprocess.Popen(["wslview", url])
261
- return True
260
+ try:
261
+ subprocess.Popen(["wslview", url])
262
+ return True
263
+ except Exception:
264
+ # wslview not found, continue to next fallback
265
+ pass
262
266
 
263
267
  # 3. Secondary WSL fallback use Windows **start** through cmd.exe.
264
268
  # Empty "" argument is required so long URLs are not treated as a window title.
265
269
  if _running_in_wsl():
266
- subprocess.Popen(["cmd.exe", "/c", "start", "", url])
267
- return True
270
+ try:
271
+ subprocess.Popen(["cmd.exe", "/c", "start", "", url])
272
+ return True
273
+ except Exception:
274
+ # cmd.exe not found, continue to next fallback
275
+ pass
268
276
 
269
277
  # 4. Unix last-ditch fallback xdg-open (most minimal container images have it)
270
278
  if shutil.which("xdg-open"):
271
- subprocess.Popen(["xdg-open", url])
272
- return True
279
+ try:
280
+ subprocess.Popen(["xdg-open", url])
281
+ return True
282
+ except Exception:
283
+ # xdg-open not found, continue to next fallback
284
+ pass
273
285
 
274
286
  # 5. If everything failed, let the caller know.
275
287
  return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev281
3
+ Version: 0.0.1.dev283
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -22,7 +22,8 @@ Requires-Dist: humanfriendly~=8.2
22
22
  Requires-Dist: plotext==5.3.2
23
23
  Requires-Dist: prompt_toolkit==3.0.48
24
24
  Requires-Dist: pydantic~=2.11.7
25
- Requires-Dist: pydantic-ai-slim[anthropic]~=0.4.2
25
+ Requires-Dist: pydantic-ai-slim[anthropic]~=0.5.0
26
+ Requires-Dist: pydantic-ai-slim[retries]~=0.5.0
26
27
  Requires-Dist: pyperclip==1.8.2
27
28
  Requires-Dist: pyyaml<6.1,>=6.0
28
29
  Requires-Dist: requests<3,>=2.28.1
@@ -12,12 +12,12 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
12
12
  tinybird/tornado_template.py,sha256=jjNVDMnkYFWXflmT8KU_Ssbo5vR8KQq3EJMk5vYgXRw,41959
13
13
  tinybird/ch_utils/constants.py,sha256=fPgZtwbr1ymxaW7uqVWHKmAbt7uGj3SxCCS3xsEMJqA,4151
14
14
  tinybird/ch_utils/engine.py,sha256=4X1B-iuhdW_mxKnX_m3iCsxgP9RPVgR75g7yH1vsJ6A,40851
15
- tinybird/datafile/common.py,sha256=lN-fNCaxtFWQAd0WN5Q-mgljM7F8sYOBQcU1JJogw1g,105324
15
+ tinybird/datafile/common.py,sha256=uRSQnSS3yv1iuJRZHgenphe-g1TEjZr04ICcl7QYcZw,105521
16
16
  tinybird/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
17
17
  tinybird/datafile/parse_connection.py,sha256=tRyn2Rpr1TeWet5BXmMoQgaotbGdYep1qiTak_OqC5E,1825
18
18
  tinybird/datafile/parse_datasource.py,sha256=ssW8QeFSgglVFi3sDZj_HgkJiTJ2069v2JgqnH3CkDE,1825
19
19
  tinybird/datafile/parse_pipe.py,sha256=xf4m0Tw44QWJzHzAm7Z7FwUoUUtr7noMYjU1NiWnX0k,3880
20
- tinybird/tb/__cli__.py,sha256=9wnnbBnxhukXrxUWvBtiFSmvyluJ20h0GDJBGnLWbwc,247
20
+ tinybird/tb/__cli__.py,sha256=8_dK8yTeERaUVdxzXjY4VYtJfAjyXwipOX_Oo4Ki8cc,247
21
21
  tinybird/tb/check_pypi.py,sha256=Gp0HkHHDFMSDL6nxKlOY51z7z1Uv-2LRexNTZSHHGmM,552
22
22
  tinybird/tb/cli.py,sha256=FdDFEIayjmsZEVsVSSvRiVYn_FHOVg_zWQzchnzfWho,1008
23
23
  tinybird/tb/client.py,sha256=IQRaInDjOwr9Fzaz3_xXc3aUGqh94tM2lew7IZbB9eM,53733
@@ -47,7 +47,7 @@ tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCf
47
47
  tinybird/tb/modules/local.py,sha256=kW3IHwJPvhBsa1eMh_xzow9Az3yYpHthkzsLSHeP5HE,6512
48
48
  tinybird/tb/modules/local_common.py,sha256=mFhidxVeGnDA_UHss-bRY8_UzU0V5iZ3HGnVqlnMzY0,17730
49
49
  tinybird/tb/modules/login.py,sha256=zerXZqIv15pbFk5XRt746xGcVnp01YmL_403byBf4jQ,1245
50
- tinybird/tb/modules/login_common.py,sha256=IfthYbHmC7EtsCXCB1iF4TngPOwfaHJ6Dfi_t7oBXnI,11640
50
+ tinybird/tb/modules/login_common.py,sha256=CKXD_BjivhGUmBtNbLTJwzQDr6885C72XPZjo0GLLvI,12010
51
51
  tinybird/tb/modules/logout.py,sha256=sniI4JNxpTrVeRCp0oGJuQ3yRerG4hH5uz6oBmjv724,1009
52
52
  tinybird/tb/modules/materialization.py,sha256=8fdbTTxFSk0Sjet3pcEk_x-cs4RGpgl6toN8vrMLXJE,5630
53
53
  tinybird/tb/modules/mock.py,sha256=ET8sRpmXnQsd2sSJXH_KCdREU1_XQgkORru6T357Akc,3260
@@ -69,14 +69,15 @@ tinybird/tb/modules/watch.py,sha256=No0bK1M1_3CYuMaIgylxf7vYFJ72lTJe3brz6xQ-mJo,
69
69
  tinybird/tb/modules/workspace.py,sha256=USsG8YEXlwf7F2PjTMCuQ2lB8ya-erbv8VywNJYq6mc,11173
70
70
  tinybird/tb/modules/workspace_members.py,sha256=5JdkJgfuEwbq-t6vxkBhYwgsiTDxF790wsa6Xfif9nk,8608
71
71
  tinybird/tb/modules/agent/__init__.py,sha256=i3oe3vDIWWPaicdCM0zs7D7BJ1W0k7th93ooskHAV00,54
72
- tinybird/tb/modules/agent/agent.py,sha256=TWaYS5od0ns0XKu9UKURdzSmDKxQk-Dm0oxLO8PtLic,33940
72
+ tinybird/tb/modules/agent/agent.py,sha256=Pr_YXAFmCzYwtLmsEKo9_BCN01RYKckH_d8-YeqHWsQ,35282
73
73
  tinybird/tb/modules/agent/animations.py,sha256=4WOC5_2BracttmMCrV0H91tXfWcUzQHBUaIJc5FA7tE,3490
74
74
  tinybird/tb/modules/agent/banner.py,sha256=l6cO5Fi7lbVKp-GsBP8jf3IkjOWxg2jpAt9NBCy0WR8,4085
75
75
  tinybird/tb/modules/agent/command_agent.py,sha256=Wcdtmo7vJZ5EbBFW9J7zPCME0ShG_KqF6-qHmMB1XXk,3103
76
76
  tinybird/tb/modules/agent/compactor.py,sha256=BK5AxZFhrp3xWnsRnYaleiYoIWtVNc-_m650Hsopt8g,13841
77
- tinybird/tb/modules/agent/explore_agent.py,sha256=HkzKmggfSMz7S3RSeKnZXufq-z_U0tTQJpF7JfNIaGQ,3504
77
+ tinybird/tb/modules/agent/explore_agent.py,sha256=W5pp99wixVSyb66qEVwBv8rZWpJ7JgzjJ_sN4d9u4Gg,3903
78
78
  tinybird/tb/modules/agent/memory.py,sha256=vBewB_64L_wHoT4tLT6UX2uxcHwSY880QZ26F9rPqXs,3793
79
- tinybird/tb/modules/agent/models.py,sha256=IAxqlnHy8c2OeSnDrrSp2Mg38W9_r0GsDM87Wv-YNfM,925
79
+ tinybird/tb/modules/agent/mock_agent.py,sha256=zbAZfAqdSLUtMr2VqO0erWpzjT2F1tTcuYjvHb-gvbA,8023
80
+ tinybird/tb/modules/agent/models.py,sha256=eokO8XlY-kVJOsbqiVporGUAOCyKAXCO5xgTEK9SM6Y,2208
80
81
  tinybird/tb/modules/agent/prompts.py,sha256=kc_47G9iEyf2p7_C-71Fa5JEwyH2RSYc4vzBHCc1JKE,39971
81
82
  tinybird/tb/modules/agent/testing_agent.py,sha256=AtwtJViH7805i7djyBgDb7SSUtDyJnw0TWJu6lBFsrg,2953
82
83
  tinybird/tb/modules/agent/utils.py,sha256=4jsQCAH2zBx13w20DOBrrDnQq9n2rKG9sGhBkJYiPzs,31744
@@ -84,16 +85,16 @@ tinybird/tb/modules/agent/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
84
85
  tinybird/tb/modules/agent/tools/analyze.py,sha256=CR5LXg4fou-zYEksqnjpJ0icvxJVoKnTctoI1NRvqCM,3873
85
86
  tinybird/tb/modules/agent/tools/append.py,sha256=6uByExBpb9rVzB0tebWyLFbfkjEPSNxIGFbZrJTaGVI,8056
86
87
  tinybird/tb/modules/agent/tools/build.py,sha256=Hm-xDAP9ckMiKquT-DmDg5H0yxZefLOaWKANyoVSaEQ,846
87
- tinybird/tb/modules/agent/tools/datafile.py,sha256=LvfDtEdgEWAeirTcx7yO6mfYshEuhWr2M1hoISIbg-g,10641
88
- tinybird/tb/modules/agent/tools/deploy.py,sha256=uDhg5VHC5nEMMBt5LXpcicVepGz67R3p-_5QN45vCFE,1807
89
- tinybird/tb/modules/agent/tools/deploy_check.py,sha256=2Wr9hQfKPlhqhumOv5TNl_xFctvdq_DHZ2dI2h_LggY,1048
88
+ tinybird/tb/modules/agent/tools/datafile.py,sha256=cXLVKEXCL37UKGRRhVVMzDcIsU1IWPLoKciAOHTRtZY,10675
89
+ tinybird/tb/modules/agent/tools/deploy.py,sha256=6Vmm0lCG8XKE2iUF_ZJrOqXbTFhoe3anPzYCFehQ3_E,2027
90
+ tinybird/tb/modules/agent/tools/deploy_check.py,sha256=pE3d9TPtXVKZjYbU0G6ORAGI86lN5K_4JKUriClERbM,1229
90
91
  tinybird/tb/modules/agent/tools/diff_resource.py,sha256=_9xHcDzCTKk_E1wKQbuktVqV6U9sA0kqYaBxWvtliX0,2613
91
- tinybird/tb/modules/agent/tools/execute_query.py,sha256=59Z_9Rl1NPRxMI3e-rIG8kfKRWgDgFt4j2GYO_Tzu7w,8845
92
+ tinybird/tb/modules/agent/tools/execute_query.py,sha256=DL2jsZ0jaEqFIkGoiWfR-IUAwsgoF0D-_JUhq7xe4gA,9145
92
93
  tinybird/tb/modules/agent/tools/get_endpoint_stats.py,sha256=r2FrXg1L1s_Llr1tPdJ6k_gu6qw7qLsAXOkbz3eTk1g,2307
93
94
  tinybird/tb/modules/agent/tools/get_openapi_definition.py,sha256=4TIMO2XzHBMhpt9zIWRfjjPZbThT8r_iPS4CVHcItE0,2904
94
- tinybird/tb/modules/agent/tools/mock.py,sha256=RvdsKIr0vKEs91GuK5vKg0fDj8SI-cdcX4XqgvnSwuQ,4508
95
+ tinybird/tb/modules/agent/tools/mock.py,sha256=kBRRdMZny7dsU2ncZrPGLT6APVfVfB8tXUJwbV7WVmE,7022
95
96
  tinybird/tb/modules/agent/tools/plan.py,sha256=2KHLNkr2f1RfkbAR4mCVsv94LGosXd8-ky7v6BB1OtQ,985
96
- tinybird/tb/modules/agent/tools/request_endpoint.py,sha256=xseEDQez2xfnPWNOoGnRmHB2KR9WLCx_q-vzS6NtaOY,3972
97
+ tinybird/tb/modules/agent/tools/request_endpoint.py,sha256=bsLWrMn-ofJM3nn9vm8j_U8fdopVd3H5L0ii6ji-Kuw,4359
97
98
  tinybird/tb/modules/agent/tools/run_command.py,sha256=ypvIU0j1XVUWghqt-dpWHm3GQIYsZwE7kRHC3Wau_H0,1708
98
99
  tinybird/tb/modules/agent/tools/secret.py,sha256=wUeM-5CCjXiwLEF-H121VypOw3_77OMoZthJedPENl4,4254
99
100
  tinybird/tb/modules/agent/tools/test.py,sha256=4XuEWVHLOTSO51Z9xJ08dTjk0j3IWY_JlPtSBO5aaUs,10373
@@ -117,8 +118,8 @@ tinybird/tb_cli_modules/config.py,sha256=IsgdtFRnUrkY8-Zo32lmk6O7u3bHie1QCxLwgp4
117
118
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
118
119
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
119
120
  tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
120
- tinybird-0.0.1.dev281.dist-info/METADATA,sha256=addYJX1brd0zshl7fSjLVDq8u-7mtD9ylBkRy0n2GXk,1763
121
- tinybird-0.0.1.dev281.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
122
- tinybird-0.0.1.dev281.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
123
- tinybird-0.0.1.dev281.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
124
- tinybird-0.0.1.dev281.dist-info/RECORD,,
121
+ tinybird-0.0.1.dev283.dist-info/METADATA,sha256=6lWTa6dFJZANfdNXseGB49yrAW9KIAtcvxLBKyneSkQ,1811
122
+ tinybird-0.0.1.dev283.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
123
+ tinybird-0.0.1.dev283.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
124
+ tinybird-0.0.1.dev283.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
125
+ tinybird-0.0.1.dev283.dist-info/RECORD,,