tinybird 0.0.1.dev239__tar.gz → 0.0.1.dev240__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tinybird might be problematic. Click here for more details.

Files changed (125) hide show
  1. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/PKG-INFO +4 -3
  2. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/__cli__.py +2 -2
  3. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/__init__.py +3 -0
  4. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/agent.py +212 -0
  5. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/banner.py +55 -0
  6. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/client.py +42 -0
  7. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/memory.py +41 -0
  8. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/models.py +20 -0
  9. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/prompts.py +83 -0
  10. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/tools/__init__.py +0 -0
  11. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/tools/create_datafile.py +62 -0
  12. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/tools/explore.py +15 -0
  13. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/tools/plan.py +45 -0
  14. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/tools/preview_datafile.py +24 -0
  15. tinybird-0.0.1.dev240/tinybird/tb/modules/agent/utils.py +382 -0
  16. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/cli.py +1 -1
  17. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird.egg-info/PKG-INFO +4 -3
  18. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird.egg-info/SOURCES.txt +13 -1
  19. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird.egg-info/requires.txt +3 -2
  20. tinybird-0.0.1.dev239/tinybird/tb/modules/agent.py +0 -80
  21. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/setup.cfg +0 -0
  22. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/__cli__.py +0 -0
  23. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/ch_utils/constants.py +0 -0
  24. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/ch_utils/engine.py +0 -0
  25. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/check_pypi.py +0 -0
  26. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/client.py +0 -0
  27. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/config.py +0 -0
  28. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/connectors.py +0 -0
  29. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/context.py +0 -0
  30. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/datafile/common.py +0 -0
  31. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/datafile/exceptions.py +0 -0
  32. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/datafile/parse_connection.py +0 -0
  33. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/datafile/parse_datasource.py +0 -0
  34. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/datafile/parse_pipe.py +0 -0
  35. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/datatypes.py +0 -0
  36. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/feedback_manager.py +0 -0
  37. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/git_settings.py +0 -0
  38. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/prompts.py +0 -0
  39. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/sql.py +0 -0
  40. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/sql_template.py +0 -0
  41. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/sql_template_fmt.py +0 -0
  42. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/sql_toolset.py +0 -0
  43. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/syncasync.py +0 -0
  44. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/check_pypi.py +0 -0
  45. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/cli.py +0 -0
  46. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/client.py +0 -0
  47. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/config.py +0 -0
  48. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/build.py +0 -0
  49. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/cicd.py +0 -0
  50. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/common.py +0 -0
  51. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/config.py +0 -0
  52. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/connection.py +0 -0
  53. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/copy.py +0 -0
  54. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/create.py +0 -0
  55. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/build.py +0 -0
  56. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/build_common.py +0 -0
  57. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  58. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  59. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/diff.py +0 -0
  60. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/fixture.py +0 -0
  61. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/format_common.py +0 -0
  62. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  63. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  64. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  65. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/playground.py +0 -0
  66. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datafile/pull.py +0 -0
  67. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/datasource.py +0 -0
  68. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/deployment.py +0 -0
  69. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/deprecations.py +0 -0
  70. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/dev_server.py +0 -0
  71. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/endpoint.py +0 -0
  72. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/exceptions.py +0 -0
  73. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/feedback_manager.py +0 -0
  74. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/info.py +0 -0
  75. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/infra.py +0 -0
  76. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/job.py +0 -0
  77. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/llm.py +0 -0
  78. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/llm_utils.py +0 -0
  79. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/local.py +0 -0
  80. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/local_common.py +0 -0
  81. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/login.py +0 -0
  82. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/logout.py +0 -0
  83. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/materialization.py +0 -0
  84. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/mock.py +0 -0
  85. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/open.py +0 -0
  86. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/pipe.py +0 -0
  87. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/project.py +0 -0
  88. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/regions.py +0 -0
  89. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/secret.py +0 -0
  90. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/shell.py +0 -0
  91. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/sink.py +0 -0
  92. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/table.py +0 -0
  93. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/telemetry.py +0 -0
  94. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/test.py +0 -0
  95. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  96. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  97. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/token.py +0 -0
  98. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/watch.py +0 -0
  99. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/workspace.py +0 -0
  100. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb/modules/workspace_members.py +0 -0
  101. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli.py +0 -0
  102. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/auth.py +0 -0
  103. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/branch.py +0 -0
  104. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/cicd.py +0 -0
  105. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/cli.py +0 -0
  106. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/common.py +0 -0
  107. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/config.py +0 -0
  108. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/connection.py +0 -0
  109. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/datasource.py +0 -0
  110. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/exceptions.py +0 -0
  111. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/fmt.py +0 -0
  112. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/job.py +0 -0
  113. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/pipe.py +0 -0
  114. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/regions.py +0 -0
  115. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/tag.py +0 -0
  116. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/telemetry.py +0 -0
  117. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/test.py +0 -0
  118. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  119. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  120. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/workspace.py +0 -0
  121. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  122. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird/tornado_template.py +0 -0
  123. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird.egg-info/dependency_links.txt +0 -0
  124. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird.egg-info/entry_points.txt +0 -0
  125. {tinybird-0.0.1.dev239 → tinybird-0.0.1.dev240}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev239
3
+ Version: 0.0.1.dev240
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -8,7 +8,7 @@ Author-email: support@tinybird.co
8
8
  Requires-Python: >=3.9, <3.14
9
9
  Description-Content-Type: text/x-rst
10
10
  Requires-Dist: aiofiles==24.1.0
11
- Requires-Dist: anthropic==0.42.0
11
+ Requires-Dist: anthropic==0.55.0
12
12
  Requires-Dist: boto3
13
13
  Requires-Dist: click<8.2,>=8.1.6
14
14
  Requires-Dist: clickhouse-toolset==0.34.dev0
@@ -20,7 +20,8 @@ Requires-Dist: docker==7.1.0
20
20
  Requires-Dist: GitPython~=3.1.32
21
21
  Requires-Dist: humanfriendly~=8.2
22
22
  Requires-Dist: prompt_toolkit==3.0.48
23
- Requires-Dist: pydantic~=2.8.0
23
+ Requires-Dist: pydantic~=2.11.7
24
+ Requires-Dist: pydantic-ai-slim[anthropic]~=0.3.1
24
25
  Requires-Dist: pyperclip==1.8.2
25
26
  Requires-Dist: pyyaml<6.1,>=6.0
26
27
  Requires-Dist: requests<3,>=2.28.1
@@ -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.dev239'
8
- __revision__ = '960f37b'
7
+ __version__ = '0.0.1.dev240'
8
+ __revision__ = '268407c'
@@ -0,0 +1,3 @@
1
+ from .agent import run_agent
2
+
3
+ __all__ = ["run_agent"]
@@ -0,0 +1,212 @@
1
+ import sys
2
+ from datetime import datetime
3
+
4
+ import click
5
+ from prompt_toolkit import prompt
6
+ from prompt_toolkit.cursor_shapes import CursorShape
7
+ from prompt_toolkit.styles import Style
8
+ from pydantic_ai import Agent, Tool
9
+ from pydantic_ai.messages import ModelMessage
10
+
11
+ from tinybird.prompts import (
12
+ connection_instructions,
13
+ copy_pipe_instructions,
14
+ datasource_example,
15
+ datasource_instructions,
16
+ gcs_connection_example,
17
+ kafka_connection_example,
18
+ materialized_pipe_instructions,
19
+ pipe_example,
20
+ pipe_instructions,
21
+ s3_connection_example,
22
+ sink_pipe_instructions,
23
+ )
24
+ from tinybird.tb.modules.agent.banner import display_banner
25
+ from tinybird.tb.modules.agent.client import TinybirdClient
26
+ from tinybird.tb.modules.agent.memory import clear_history, load_history
27
+ from tinybird.tb.modules.agent.models import create_model
28
+ from tinybird.tb.modules.agent.prompts import datafile_instructions, plan_instructions, sql_instructions
29
+ from tinybird.tb.modules.agent.tools.create_datafile import create_datafile
30
+ from tinybird.tb.modules.agent.tools.explore import explore_data
31
+ from tinybird.tb.modules.agent.tools.plan import plan
32
+ from tinybird.tb.modules.agent.tools.preview_datafile import preview_datafile
33
+ from tinybird.tb.modules.agent.utils import TinybirdAgentContext
34
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
35
+
36
+
37
+ class TinybirdAgent:
38
+ def __init__(self, token: str, host: str, folder: str):
39
+ self.token = token
40
+ self.host = host
41
+ self.folder = folder
42
+ self.messages: list[ModelMessage] = []
43
+ self.agent = Agent(
44
+ model=create_model(token, host),
45
+ deps_type=TinybirdAgentContext,
46
+ system_prompt=f"""
47
+ You are a Tinybird Code, an agentic CLI that can help users to work with Tinybird.
48
+
49
+ 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.
50
+
51
+ # Tone and style
52
+ You should be concise, direct, and to the point.
53
+ Remember that your output will be displayed on a command line interface. Your responses can use Github-flavored markdown for formatting.
54
+ 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.
55
+ 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.
56
+ 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.
57
+ 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.
58
+ 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:
59
+
60
+ # Proactiveness
61
+ You are allowed to be proactive, but only when the user asks you to do something. You should strive to strike a balance between:
62
+ Doing the right thing when asked, including taking actions and follow-up actions
63
+ Not surprising the user with actions you take without asking
64
+ 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.
65
+ 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.
66
+
67
+ # Code style
68
+ IMPORTANT: DO NOT ADD ANY COMMENTS unless asked by the user.
69
+
70
+ # Tools
71
+ You have access to the following tools:
72
+ 1. `explore_data` - Explore data in the current workspace
73
+ 2. `preview_datafile` - Preview the content of a datafile (datasource, endpoint, materialized, sink, copy, connection).
74
+ 3. `create_datafile` - Create a file in the project folder. Confirmation will be asked by the tool before creating the file.
75
+ 4. `plan` - Plan the creation or update of resources.
76
+
77
+
78
+ # When creating or updating datafiles:
79
+ 1. Use `plan` tool to plan the creation or update of resources.
80
+ 2. If the user confirms the plan, go from 3 to 7 steps until all the resources are created, updated or skipped.
81
+ 3. Use `preview_datafile` tool to preview the content of a datafile.
82
+ 4. Without asking, use the `create_datafile` tool to create the datafile, because it will ask for confirmation before creating the file.
83
+ 5. Check the result of the `create_datafile` tool to see if the datafile was created successfully.
84
+ 6. If the datafile was created successfully, report the result to the user.
85
+ 7. If the datafile was not created successfully, finish the process and just wait for a new user prompt.
86
+
87
+ IMPORTANT: If the user cancels some of the steps or there is an error, DO NOT continue with the plan. Stop the process and wait for the user before using any other tool.
88
+
89
+ # When planning the creation or update of resources:
90
+ {plan_instructions}
91
+ {datafile_instructions}
92
+
93
+ # Working with datasource files:
94
+ {datasource_instructions}
95
+ {datasource_example}
96
+
97
+ # Working with any type of pipe file:
98
+ {pipe_instructions}
99
+ {pipe_example}
100
+
101
+ # Working with materialized pipe files:
102
+ {materialized_pipe_instructions}
103
+
104
+ # Working with sink pipe files:
105
+ {sink_pipe_instructions}
106
+
107
+ # Working with copy pipe files:
108
+ {copy_pipe_instructions}
109
+
110
+ # Working with SQL queries:
111
+ {sql_instructions}
112
+
113
+ # Working with connections files:
114
+ {connection_instructions}
115
+
116
+ # Connection examples:
117
+ Kafka: {kafka_connection_example}
118
+ S3: {s3_connection_example}
119
+ GCS: {gcs_connection_example}
120
+
121
+ # Info
122
+ Today is {datetime.now().strftime("%Y-%m-%d")}
123
+ """,
124
+ tools=[
125
+ Tool(explore_data, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
126
+ Tool(preview_datafile, docstring_format="google", require_parameter_descriptions=True, takes_ctx=False),
127
+ Tool(create_datafile, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
128
+ Tool(plan, docstring_format="google", require_parameter_descriptions=True, takes_ctx=False),
129
+ ],
130
+ )
131
+
132
+ def _keep_recent_messages(self) -> list[ModelMessage]:
133
+ """Keep only the last 5 messages to manage token usage."""
134
+ return self.messages[-5:] if len(self.messages) > 5 else self.messages
135
+
136
+ def run(self, user_prompt: str) -> None:
137
+ result = self.agent.run_sync(
138
+ user_prompt,
139
+ deps=TinybirdAgentContext(
140
+ client=TinybirdClient(token=self.token, host=self.host),
141
+ folder=self.folder,
142
+ ),
143
+ message_history=self.messages,
144
+ )
145
+ new_messages = result.new_messages()
146
+ self.messages.extend(new_messages)
147
+ click.echo("\n")
148
+ click.echo(result.output)
149
+ click.echo("\n")
150
+
151
+
152
+ def run_agent(token: str, host: str, folder: str):
153
+ display_banner()
154
+
155
+ try:
156
+ agent = TinybirdAgent(token, host, folder)
157
+ click.echo()
158
+ click.echo(FeedbackManager.success(message="Welcome to Tinybird Code"))
159
+ click.echo(FeedbackManager.info(message="Describe what you want to create and I'll help you build it"))
160
+ click.echo(FeedbackManager.info(message="Commands: 'exit', 'quit', 'help', or Ctrl+C to exit"))
161
+ click.echo()
162
+
163
+ except Exception as e:
164
+ click.echo(FeedbackManager.error(message=f"Failed to initialize agent: {e}"))
165
+ return
166
+
167
+ # Interactive loop
168
+ try:
169
+ while True:
170
+ try:
171
+ user_input = prompt(
172
+ [("class:prompt", "tb » ")],
173
+ history=load_history(),
174
+ cursor=CursorShape.BLOCK,
175
+ style=Style.from_dict(
176
+ {
177
+ "prompt": "#40a8a8 bold",
178
+ "": "", # Normal color for user input
179
+ }
180
+ ),
181
+ )
182
+
183
+ if user_input.lower() in ["exit", "quit"]:
184
+ click.echo(FeedbackManager.info(message="Goodbye!"))
185
+ break
186
+ elif user_input.lower() == "clear":
187
+ clear_history()
188
+ continue
189
+ elif user_input.lower() == "help":
190
+ click.echo()
191
+ click.echo(FeedbackManager.info(message="Tinybird Code Help:"))
192
+ click.echo("• Describe what you want to create: 'Create a user analytics system'")
193
+ click.echo("• Ask for specific resources: 'Create a pipe to aggregate daily clicks'")
194
+ click.echo("• Request data sources: 'Set up a Kafka connection for events'")
195
+ click.echo("• Type 'exit' or 'quit' to leave")
196
+ click.echo()
197
+ continue
198
+ elif user_input.strip() == "":
199
+ continue
200
+ else:
201
+ agent.run(user_input)
202
+
203
+ except KeyboardInterrupt:
204
+ click.echo(FeedbackManager.info(message="Goodbye!"))
205
+ break
206
+ except EOFError:
207
+ click.echo(FeedbackManager.info(message="Goodbye!"))
208
+ break
209
+
210
+ except Exception as e:
211
+ click.echo(FeedbackManager.error(message=f"Error: {e}"))
212
+ sys.exit(1)
@@ -0,0 +1,55 @@
1
+ import click
2
+
3
+
4
+ def display_banner():
5
+ reset = "\033[0m"
6
+
7
+ click.echo("\n")
8
+ # The Tinybird Code ASCII art banner
9
+ banner = [
10
+ " ████████╗██╗███╗ ██╗██╗ ██╗██████╗ ██╗██████╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗",
11
+ " ╚══██╔══╝██║████╗ ██║╚██╗ ██╔╝██╔══██╗██║██╔══██╗██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗██╔════╝",
12
+ " ██║ ██║██╔██╗ ██║ ╚████╔╝ ██████╔╝██║██████╔╝██║ ██║ ██║ ██║ ██║██║ ██║█████╗ ",
13
+ " ██║ ██║██║╚██╗██║ ╚██╔╝ ██╔══██╗██║██╔══██╗██║ ██║ ██║ ██║ ██║██║ ██║██╔══╝ ",
14
+ " ██║ ██║██║ ╚████║ ██║ ██████╔╝██║██║ ██║██████╔╝ ╚██████╗╚██████╔╝██████╔╝███████╗",
15
+ " ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝",
16
+ ]
17
+
18
+ def interpolate_color(start_rgb, end_rgb, factor):
19
+ """Interpolate between two RGB colors"""
20
+ return [int(start_rgb[i] + (end_rgb[i] - start_rgb[i]) * factor) for i in range(3)]
21
+
22
+ def rgb_to_ansi(r, g, b):
23
+ """Convert RGB values to ANSI escape code"""
24
+ return f"\033[38;2;{r};{g};{b}m"
25
+
26
+ # Define start and end colors for smooth gradient
27
+ start_color = [0, 128, 128] # Deep teal
28
+ end_color = [100, 200, 180] # Light turquoise
29
+
30
+ # Print each line with a very smooth horizontal gradient
31
+ for line in banner:
32
+ colored_line = ""
33
+ # Count non-space characters for gradient calculation
34
+ non_space_chars = sum(1 for char in line if char != " ")
35
+ char_count = 0
36
+
37
+ for char in line:
38
+ if char == " ":
39
+ colored_line += char
40
+ continue
41
+
42
+ # Calculate smooth gradient position (0.0 to 1.0)
43
+ if non_space_chars > 1:
44
+ gradient_position = char_count / (non_space_chars - 1)
45
+ else:
46
+ gradient_position = 0
47
+
48
+ # Interpolate color
49
+ current_rgb = interpolate_color(start_color, end_color, gradient_position)
50
+ color_code = rgb_to_ansi(*current_rgb)
51
+
52
+ colored_line += f"{color_code}{char}"
53
+ char_count += 1
54
+
55
+ click.echo(colored_line + reset)
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Dict, Optional
3
+
4
+ import httpx
5
+
6
+
7
+ @dataclass
8
+ class TinybirdClient:
9
+ def __init__(self, host: str, token: str):
10
+ self.host = host
11
+ self.token = token
12
+ self.client = httpx.Client(
13
+ timeout=30.0,
14
+ headers={"Accept": "application/json", "User-Agent": "Python/APIClient"},
15
+ )
16
+ self.insights: list[str] = []
17
+
18
+ def __aenter__(self):
19
+ return self
20
+
21
+ def __aexit__(self, exc_type, exc_val, exc_tb):
22
+ self.close()
23
+
24
+ def close(self):
25
+ """Close the underlying HTTP client."""
26
+ self.client.close()
27
+
28
+ def _get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> str:
29
+ if params is None:
30
+ params = {}
31
+ params["token"] = self.token
32
+ url = f"{self.host}{endpoint}"
33
+ response = self.client.get(url, params=params)
34
+ try:
35
+ response.raise_for_status()
36
+ except Exception as e:
37
+ raise Exception(response.json().get("error", str(e))) from e
38
+ return response.text
39
+
40
+ def explore_data(self, prompt: str) -> str:
41
+ params = {"prompt": prompt, "host": self.host, "origin": "cli"}
42
+ return self._get("/v1/agents/explore", params)
@@ -0,0 +1,41 @@
1
+ from pathlib import Path
2
+ from typing import Optional
3
+
4
+ from prompt_toolkit.history import FileHistory
5
+
6
+
7
+ def get_history_file_path():
8
+ """Get the history file path based on current working directory"""
9
+ # Get current working directory
10
+ cwd = Path.cwd()
11
+
12
+ # Get user's home directory
13
+ home = Path.home()
14
+
15
+ # Calculate relative path from home to current directory
16
+ try:
17
+ relative_path = cwd.relative_to(home)
18
+ except ValueError:
19
+ # If current directory is not under home, use absolute path components
20
+ relative_path = Path(*cwd.parts[1:]) if cwd.is_absolute() else cwd
21
+
22
+ # Create history directory structure
23
+ history_dir = home / ".tinybird" / "projects" / relative_path
24
+ history_dir.mkdir(parents=True, exist_ok=True)
25
+
26
+ # Return history file path
27
+ return history_dir / "history.txt"
28
+
29
+
30
+ def load_history() -> Optional[FileHistory]:
31
+ try:
32
+ history_file = get_history_file_path()
33
+ return FileHistory(str(history_file))
34
+ except Exception:
35
+ return None
36
+
37
+
38
+ def clear_history():
39
+ """Clear the history file"""
40
+ history_file = get_history_file_path()
41
+ history_file.unlink(missing_ok=True)
@@ -0,0 +1,20 @@
1
+ from anthropic import AsyncAnthropic
2
+ from httpx import AsyncClient
3
+ from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelName
4
+ from pydantic_ai.providers.anthropic import AnthropicProvider
5
+
6
+
7
+ def create_model(
8
+ token: str,
9
+ base_url: str = "https://api.wadus3.aws.tinybird.co",
10
+ model: AnthropicModelName = "claude-4-sonnet-20250514",
11
+ ):
12
+ client = AsyncAnthropic(
13
+ base_url=base_url,
14
+ http_client=AsyncClient(params={"token": token}),
15
+ auth_token=token,
16
+ )
17
+ return AnthropicModel(
18
+ model_name=model,
19
+ provider=AnthropicProvider(anthropic_client=client),
20
+ )
@@ -0,0 +1,83 @@
1
+ plan_instructions = """
2
+ When asked to create a plan, you MUST respond with this EXACT format and NOTHING ELSE:
3
+
4
+ PLAN_DESCRIPTION: [One sentence describing what will be built]
5
+
6
+ STEPS:
7
+ 1. CREATE_DATASOURCE: [name] - [description] - DEPENDS_ON: none
8
+ 2. CREATE_ENDPOINT: [name] - [description] - DEPENDS_ON: [resource_name]
9
+ 3. CREATE_MATERIALIZED_PIPE: [name] - [description] - DEPENDS_ON: [resource_name]
10
+ 4. CREATE_MATERIALIZED_DATASOURCE: [name] - [description] - DEPENDS_ON: [resource_name]
11
+ 5. CREATE_SINK: [name] - [description] - DEPENDS_ON: [resource_name]
12
+ 6. CREATE_COPY: [name] - [description] - DEPENDS_ON: [resource_name]
13
+ 7. CREATE_CONNECTION: [name] - [description] - DEPENDS_ON: none
14
+
15
+ You can skip steps where resources will not be created or updated.
16
+
17
+ ESTIMATED_RESOURCES: [total number of steps]
18
+
19
+ RESOURCE_DEPENDENCIES:
20
+ [resource_name]: [resource_name]
21
+ """
22
+
23
+
24
+ sql_instructions = """
25
+ <sql_instructions>
26
+ - The SQL query must be a valid ClickHouse SQL query that mixes ClickHouse syntax and Tinybird templating syntax (Tornado templating language under the hood).
27
+ - SQL queries with parameters must start with "%" character and a newline on top of every query to be able to use the parameters. Examples:
28
+ <invalid_query_with_parameters_no_%_on_top>
29
+ SELECT * FROM events WHERE session_id={{String(my_param, "default_value")}}
30
+ </invalid_query_with_parameters_no_%_on_top>
31
+ <valid_query_with_parameters_with_%_on_top>
32
+ %
33
+ SELECT * FROM events WHERE session_id={{String(my_param, "default_value")}}
34
+ </valid_query_with_parameters_with_%_on_top>
35
+ - The Parameter functions like this one {{String(my_param_name,default_value)}} can be one of the following: String, DateTime, Date, Float32, Float64, Int, Integer, UInt8, UInt16, UInt32, UInt64, UInt128, UInt256, Int8, Int16, Int32, Int64, Int128, Int256
36
+ - Parameter names must be different from column names. Pass always the param name and a default value to the function.
37
+ - Use ALWAYS hardcoded values for default values for parameters.
38
+ - Code inside the template {{template_expression}} follows the rules of Tornado templating language so no module is allowed to be imported. So for example you can't use now() as default value for a DateTime parameter. You need an if else block like this:
39
+ <invalid_condition_with_now>
40
+ AND timestamp BETWEEN {{DateTime(start_date, now() - interval 30 day)}} AND {{DateTime(end_date, now())}}
41
+ </invalid_condition_with_now>
42
+ <valid_condition_without_now>
43
+ {{%if not defined(start_date)%}}
44
+ timestamp BETWEEN now() - interval 30 day
45
+ {{%else%}}
46
+ timestamp BETWEEN {{DateTime(start_date)}}
47
+ {{%end%}}
48
+ {{%if not defined(end_date)%}}
49
+ AND now()
50
+ {{%else%}}
51
+ AND {{DateTime(end_date)}}
52
+ {{%end%}}
53
+ </valid_condition_without_now>
54
+ - Parameters must not be quoted.
55
+ - When you use defined function with a paremeter inside, do NOT add quotes around the parameter:
56
+ <invalid_defined_function_with_parameter>{{% if defined('my_param') %}}</invalid_defined_function_with_parameter>
57
+ <valid_defined_function_without_parameter>{{% if defined(my_param) %}}</valid_defined_function_without_parameter>
58
+ - Use datasource names as table names when doing SELECT statements.
59
+ - Do not use pipe names as table names.
60
+ - The available datasource names to use in the SQL are the ones present in the existing_resources section or the ones you will create.
61
+ - Use node names as table names only when nodes are present in the same file.
62
+ - Do not reference the current node name in the SQL.
63
+ - SQL queries only accept SELECT statements with conditions, aggregations, joins, etc.
64
+ - Do NOT use CREATE TABLE, INSERT INTO, CREATE DATABASE, etc.
65
+ - Use ONLY SELECT statements in the SQL section.
66
+ - INSERT INTO is not supported in SQL section.
67
+ - When using functions try always ClickHouse functions first, then SQL functions.
68
+ - Parameters are never quoted in any case.
69
+ - Use the following syntax in the SQL section for the iceberg table function: iceberg('s3://bucket/path/to/table', {{tb_secret('aws_access_key_id')}}, {{tb_secret('aws_secret_access_key')}})
70
+ - Use the following syntax in the SQL section for the postgres table function: postgresql('host:port', 'database', 'table', {{tb_secret('db_username')}}, {{tb_secret('db_password')}}), 'schema')
71
+ </sql_instructions>
72
+ """
73
+
74
+ datafile_instructions = """
75
+ <datafile_instructions>
76
+ - Endpoint files will be created under the `/endpoints` folder.
77
+ - Materialized pipe files will be created under the `/materialized` folder.
78
+ - Sink pipe files will be created under the `/sinks` folder.
79
+ - Copy pipe files will be created under the `/copies` folder.
80
+ - Connection files will be created under the `/connections` folder.
81
+ - Datasource files will be created under the `/datasources` folder.
82
+ </datafile_instructions>
83
+ """
@@ -0,0 +1,62 @@
1
+ from pathlib import Path
2
+
3
+ import click
4
+ from pydantic_ai import RunContext
5
+
6
+ from tinybird.tb.modules.agent.utils import Datafile, TinybirdAgentContext, show_options
7
+
8
+
9
+ def get_resource_confirmation(resource: Datafile) -> bool:
10
+ """Get user confirmation for creating a resource"""
11
+ while True:
12
+ result = show_options(
13
+ options=[f"Yes, create {resource.type} '{resource.name}'", "No, and tell Tinybird Code what to do"],
14
+ title=f"What would you like to do with {resource.type} '{resource.name}'?",
15
+ )
16
+
17
+ if result is None: # Cancelled
18
+ return False
19
+
20
+ if result.startswith("Yes"):
21
+ return True
22
+ elif result.startswith("No"):
23
+ return False
24
+
25
+ return False
26
+
27
+
28
+ def create_datafile(ctx: RunContext[TinybirdAgentContext], resource: Datafile) -> str:
29
+ """Given a resource representation, create a file in the project folder
30
+
31
+ Args:
32
+ resource (Datafile): The resource to create. Required.
33
+
34
+ Returns:
35
+ str: If the resource was created or not.
36
+ """
37
+ try:
38
+ click.echo()
39
+ click.echo(resource.content)
40
+ confirmation = get_resource_confirmation(resource)
41
+
42
+ if not confirmation:
43
+ return f"Resource {resource.pathname} was not created. User cancelled creation."
44
+
45
+ resource.pathname = resource.pathname.removeprefix("/")
46
+
47
+ path = Path(ctx.deps.folder) / resource.pathname
48
+
49
+ folder_path = path.parent
50
+
51
+ if not folder_path.exists():
52
+ folder_path.mkdir()
53
+
54
+ if not path.exists():
55
+ path.touch()
56
+
57
+ path.write_text(resource.content)
58
+
59
+ return f"Created {resource.pathname}"
60
+
61
+ except Exception as e:
62
+ return f"Error creating {resource.pathname}: {e}"
@@ -0,0 +1,15 @@
1
+ from pydantic_ai import RunContext
2
+
3
+ from tinybird.tb.modules.agent.utils import TinybirdAgentContext
4
+
5
+
6
+ def explore_data(ctx: RunContext[TinybirdAgentContext], prompt: str):
7
+ """Explore production data in the current workspace
8
+
9
+ Args:
10
+ prompt (str): The prompt to explore data with. Required.
11
+
12
+ Returns:
13
+ str: The result of the exploration.
14
+ """
15
+ return ctx.deps.client.explore_data(prompt)
@@ -0,0 +1,45 @@
1
+ import click
2
+
3
+ from tinybird.tb.modules.agent.utils import show_options
4
+
5
+
6
+ def get_plan_confirmation() -> bool:
7
+ """Get user confirmation for implementing a plan"""
8
+ while True:
9
+ result = show_options(
10
+ options=["Yes, implement the plan", "No, and tell Tinybird Code what to do"],
11
+ title="Do you want to implement the plan?",
12
+ )
13
+
14
+ if result is None: # Cancelled
15
+ return False
16
+
17
+ if result.startswith("Yes"):
18
+ return True
19
+ elif result.startswith("No"):
20
+ return False
21
+
22
+ return False
23
+
24
+
25
+ def plan(plan: str) -> str:
26
+ """Given a plan, ask the user for confirmation to implement it
27
+
28
+ Args:
29
+ plan (str): The plan to implement. Required.
30
+
31
+ Returns:
32
+ str: If the plan was implemented or not.
33
+ """
34
+ try:
35
+ click.echo()
36
+ click.echo(plan)
37
+ confirmation = get_plan_confirmation()
38
+
39
+ if not confirmation:
40
+ return "Plan was not implemented. User cancelled implementation."
41
+
42
+ return "User confirmed the plan. Implementing..."
43
+
44
+ except Exception as e:
45
+ return f"Error implementing the plan: {e}"
@@ -0,0 +1,24 @@
1
+ from tinybird.tb.modules.agent.utils import Datafile
2
+
3
+
4
+ def preview_datafile(name: str, type: str, description: str, content: str, pathname: str) -> Datafile:
5
+ """Preview the content of a datafile before creating it
6
+
7
+ Args:
8
+ name (str): The name of the datafile. Required.
9
+ type (str): The type of the datafile. Options: datasource, endpoint, materialized, sink, copy, connection. Required.
10
+ description (str): The description of the datafile. Required.
11
+ content (str): The content of the datafile. Required.
12
+ pathname (str): The pathname of the datafile where the file will be created. Required.
13
+
14
+ Returns:
15
+ Datafile: The datafile preview.
16
+ """
17
+
18
+ return Datafile(
19
+ type=type,
20
+ name=name,
21
+ content=content,
22
+ description=description,
23
+ pathname=pathname,
24
+ )