umgefahren commited on
Commit
b9d684c
Β·
unverified Β·
0 Parent(s):

Initial commit

Browse files
Files changed (9) hide show
  1. .env +3 -0
  2. .gitignore +10 -0
  3. .python-version +1 -0
  4. Dockerfile +17 -0
  5. README.md +0 -0
  6. agent.py +455 -0
  7. main.py +237 -0
  8. pyproject.toml +10 -0
  9. uv.lock +0 -0
.env ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ GOOGLE_GENAI_USE_VERTEXAI=TRUE
2
+ GOOGLE_CLOUD_PROJECT=vibecoder-459110
3
+ GOOGLE_CLOUD_LOCATION=us-central1
.gitignore ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM ghcr.io/astral-sh/uv:alpine
2
+
3
+ RUN apk add curl python3
4
+
5
+ RUN curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
6
+
7
+ COPY pyproject.toml .
8
+
9
+ RUN uv sync
10
+
11
+ COPY *.py .
12
+
13
+ ENV GOOGLE_GENAI_USE_VERTEXAI=TRUE
14
+ ENV GOOGLE_CLOUD_LOCATION=us-central1
15
+ ENV GOOGLE_CLOUD_PROJECT=vibecoder-459110
16
+
17
+ CMD ["uv", "run", "main.py"]
README.md ADDED
File without changes
agent.py ADDED
@@ -0,0 +1,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from google.adk.agents import Agent
2
+ from google.adk.sessions import InMemorySessionService
3
+ from google.adk.runners import Runner
4
+ from google.adk.tools import (
5
+ ToolContext,
6
+ FunctionTool,
7
+ built_in_code_execution,
8
+ google_search,
9
+ )
10
+ from google.genai import types
11
+ import asyncio
12
+ import dotenv
13
+ import os
14
+ import subprocess
15
+ import shutil
16
+
17
+ dotenv.load_dotenv()
18
+
19
+
20
+ def read_code(tool_context: ToolContext, start_line: int = 0, end_line: int = 9999999):
21
+ """
22
+ Read the code written so far. The code is arduino code.
23
+ You can optionally select which part of the code you would like to get.
24
+
25
+ Args:
26
+ start_line (int): The first line of the code part you want (defaults to 0)
27
+ end_line (int): The last line of the code part you want (defaults to infinity)
28
+
29
+ Returns:
30
+ str: The (part of the) code written so far.
31
+ """
32
+ code: str = tool_context.state.get("code", "")
33
+ return "\n".join(code.splitlines()[start_line:end_line])
34
+
35
+
36
+ def write_code(tool_context: ToolContext, code: str):
37
+ """
38
+ Write code to the main file. Only put Arduino code here.
39
+ This is the only place where you are allowed to put code. Don't put code in the chat, only write it here.
40
+
41
+ Args:
42
+ code (str): The code you want to write to the main file.
43
+ """
44
+ tool_context.state["code"] = code
45
+
46
+
47
+ COMPONENT_INFO_DICT = {
48
+ "Arduino Uno R3": {
49
+ "pins": {
50
+ "D0": "Serial (USART) RX + GPIO",
51
+ "D1": "Serial (USART) TX + GPIO",
52
+ "D2": "External interrupt (INT0) + GPIO",
53
+ "D3": "External interrupt (INT1) + PWM + GPIO",
54
+ "D4": "GPIO",
55
+ "D5": "PWM + GPIO",
56
+ "D6": "PWM + GPIO",
57
+ "D7": "GPIO",
58
+ "D8": "GPIO",
59
+ "D9": "PWM + GPIO",
60
+ "D10": "PWM + GPIO",
61
+ "D11": "PWM + GPIO",
62
+ "D12": "GPIO",
63
+ "D13": "GPIO",
64
+ "GND": "Ground",
65
+ "D14": "GPIO + A[0]",
66
+ "D15": "GPIO + A[1]",
67
+ "D16": "GPIO + A[2]",
68
+ "D17": "GPIO + A[3]",
69
+ "D18": "GPIO + I2C SDA + A[4]",
70
+ "D19": "GPIO + I2C SCL + A[5]",
71
+ "GND": "Ground",
72
+ "GND": "Ground",
73
+ "+5V": "+5V OUT",
74
+ "+3.3V": "+3.3V OUT",
75
+ }
76
+ },
77
+ "Button": {
78
+ "pins": {
79
+ "D0": "Pin 1",
80
+ "D1": "Pin 2",
81
+ }
82
+ },
83
+ "SSD1306": {
84
+ "pins": {
85
+ "VCC": "Supply Voltage",
86
+ "GND": "Ground",
87
+ "SCL": "I2C clock line",
88
+ "SDA": "I2C data line",
89
+ }
90
+ },
91
+ "LED Green": {
92
+ "pins": {
93
+ "an": "Anode",
94
+ "ka": "Kathode",
95
+ }
96
+ },
97
+ "LED Blue": {
98
+ "pins": {
99
+ "an": "Anode",
100
+ "ka": "Kathode",
101
+ }
102
+ },
103
+ "LED Red": {
104
+ "pins": {
105
+ "an": "Anode",
106
+ "ka": "Kathode",
107
+ }
108
+ },
109
+ "Resistor 10k": {
110
+ "resistance": "10k Ohm",
111
+ "pins": {
112
+ "an": "Anode",
113
+ "ka": "Kathode",
114
+ },
115
+ },
116
+ "Resistor 1k": {
117
+ "resistance": "1k Ohm",
118
+ "pins": {
119
+ "an": "Anode",
120
+ "ka": "Kathode",
121
+ },
122
+ },
123
+ "Resistor 100": {
124
+ "resistance": "100 Ohm",
125
+ "pins": {
126
+ "an": "Anode",
127
+ "ka": "Kathode",
128
+ },
129
+ },
130
+ }
131
+
132
+
133
+ def list_components():
134
+ """
135
+ List available components you can use to build complex systems.
136
+ If you want more information on how to use them, use your web search tool.
137
+
138
+ Retruns:
139
+ list[str]: A list of names of components
140
+ """
141
+ return list(COMPONENT_INFO_DICT.keys())
142
+
143
+
144
+ def component_info(component_name: str):
145
+ """
146
+ Get information on a component.
147
+ For the moment this only includes the pins of the component.
148
+
149
+ Args:
150
+ component_name (str): Name of the component
151
+
152
+ Returns:
153
+ dict[str, str]: A dictionary of the pins and a description
154
+ """
155
+ if not component_name in COMPONENT_INFO_DICT.keys():
156
+ return {
157
+ "error": "Component with this name does not exist",
158
+ }
159
+ return {"success": True, "component_info": COMPONENT_INFO_DICT[component_name]}
160
+
161
+
162
+ def add_component(tool_context: ToolContext, component_name: str, id: str):
163
+ """
164
+ Add a component to the diagram. You need to write that component later.
165
+ Use list components to find out which components you are allowed to use.
166
+
167
+ Args:
168
+ component_name (str): The name of the component you want to add.
169
+ id (str): The id of the component you use to refer to the component later.
170
+ """
171
+ if not component_name in COMPONENT_INFO_DICT.keys():
172
+ return {
173
+ "error": "The component you wanted is not available in the list of allowed components"
174
+ }
175
+ if not "components" in tool_context.state:
176
+ tool_context.state["components"] = {}
177
+ components = tool_context.state["components"]
178
+ components[id] = component_name
179
+ tool_context.state["components"] = components
180
+ return {"success": True}
181
+
182
+
183
+ def add_wire(
184
+ tool_context: ToolContext, start_id: str, start_pin: str, end_id: str, end_pin: str
185
+ ):
186
+ """
187
+ Add a wire between two components in our schematic.
188
+ Note that a component has to first be added to the schematic.
189
+
190
+ Args:
191
+ start_id (str): The id of the component where the wire starts.
192
+ start_pin (str): The pin on the start component of the wire.
193
+ end_id (str): The id of the component where the wire ends.
194
+ end_pin (str): The pin on the end component of the wire.
195
+ """
196
+ if not "wires" in tool_context.state:
197
+ tool_context.state["wires"] = []
198
+ if not "components" in tool_context.state:
199
+ tool_context.state["components"] = {}
200
+ if not start_id in tool_context.state["components"]:
201
+ return {
202
+ "error": f"Component with id {start_id} not added to list of components"
203
+ }
204
+ if not end_id in tool_context.state["components"]:
205
+ return {"error": f"Component with id {end_id} not added to list of components"}
206
+ wires = tool_context.state["wires"]
207
+ wires.append(
208
+ {
209
+ "start_id": start_id,
210
+ "start_pin": start_pin,
211
+ "end_id": end_id,
212
+ "end_pin": end_pin,
213
+ }
214
+ )
215
+ tool_context.state["wires"] = wires
216
+ return {
217
+ "success": True,
218
+ }
219
+
220
+
221
+ def del_component(
222
+ tool_context: ToolContext,
223
+ id: str,
224
+ ):
225
+ """
226
+ Delete a component from the schematic.
227
+ If you delete a component, all wires connected to it will be deleted as well.
228
+
229
+ Args:
230
+ id (str): The id of the component you want to delete.
231
+ """
232
+ if not "components" in tool_context.state:
233
+ return {"error": "No components to delete"}
234
+ components = tool_context.state["components"]
235
+ if not id in components:
236
+ return {"error": f"Component with id {id} not found"}
237
+ del components[id]
238
+ tool_context.state["components"] = components
239
+ wires = tool_context.state["wires"]
240
+ if not wires:
241
+ return {
242
+ "success": True,
243
+ }
244
+ while True:
245
+ removed = False
246
+ for wire in wires:
247
+ if wire["start_id"] == id or wire["end_id"] == id:
248
+ removed = True
249
+ wires.remove(wire)
250
+ break
251
+ if not removed:
252
+ break
253
+
254
+ tool_context.state["wires"] = wires
255
+ return {
256
+ "success": True,
257
+ }
258
+
259
+
260
+ def del_wire(
261
+ tool_context: ToolContext,
262
+ start_id: str,
263
+ start_pin: str,
264
+ end_id: str,
265
+ end_pin: str,
266
+ ):
267
+ """
268
+ Delete a wire between two components in our schematic.
269
+
270
+ Args:
271
+ start_id (str): The id of the component where the wire starts.
272
+ start_pin (str): The pin on the start component of the wire.
273
+ end_id (str): The id of the component where the wire ends.
274
+ end_pin (str): The pin on the end component of the wire.
275
+ """
276
+ if not "wires" in tool_context.state:
277
+ return {"error": "No wires to delete"}
278
+ if not "components" in tool_context.state:
279
+ return {"error": "No components to delete"}
280
+ wires = tool_context.state["wires"]
281
+ for wire in wires:
282
+ if (
283
+ wire["start_id"] == start_id
284
+ and wire["start_pin"] == start_pin
285
+ and wire["end_id"] == end_id
286
+ and wire["end_pin"] == end_pin
287
+ ):
288
+ wires.remove(wire)
289
+ break
290
+ else:
291
+ return {"error": f"Wire with id {start_id} not found"}
292
+ tool_context.state["wires"] = wires
293
+ return {
294
+ "success": True,
295
+ }
296
+
297
+
298
+ def compile_with_arduino(
299
+ tool_context: ToolContext,
300
+ ):
301
+ """
302
+ Compile the code with the Arduino CLI.
303
+ """
304
+
305
+ code = tool_context.state.get("code")
306
+ if not code:
307
+ return {"error": "No code to compile"}
308
+
309
+
310
+ shutil.rmtree('/tmp/arduino_project')
311
+ os.mkdir('/tmp/arduino_project')
312
+
313
+ with open("/tmp/arduino_project/arduino_project.ino", "w") as f:
314
+ f.write(code)
315
+
316
+ # Compile with the Arduino CLI
317
+ result = subprocess.run(
318
+ ["arduino-cli", "compile", "--fqbn", "arduino:avr:uno", "/tmp/arduino_project", "--build-path", "/tmp/arduino_project/output"],
319
+ capture_output=True,
320
+ )
321
+ if result.returncode != 0:
322
+ return {
323
+ "error": "Compilation failed",
324
+ "output": result.stderr.decode("utf-8"),
325
+ }
326
+ return {
327
+ "success": True,
328
+ "output": result.stdout.decode("utf-8"),
329
+ }
330
+
331
+ def search_library(
332
+ name: str,
333
+ ):
334
+ """
335
+ Search for a library with the Arduino CLI.
336
+ Args:
337
+ name (str): The name of the library you want to search for.
338
+
339
+ Returns:
340
+ list[str]: A list of libraries that match the search term.
341
+ """
342
+
343
+ # Search for the library with the Arduino CLI
344
+ result = subprocess.run(
345
+ ["arduino-cli", "lib", "search", name],
346
+ capture_output=True,
347
+ )
348
+ if result.returncode != 0:
349
+ return {
350
+ "error": "Library search failed",
351
+ "output": result.stderr.decode("utf-8"),
352
+ }
353
+ output = result.stdout.decode("utf-8").splitlines()[:25]
354
+ return {
355
+ "success": True,
356
+ "output": "\n".join(output),
357
+ }
358
+
359
+ def add_library(name: str):
360
+ """
361
+ Install a library for the Arduino CLI.
362
+
363
+ Args:
364
+ name (str): The name of the library you want to install.
365
+ """
366
+ # Install the library with the Arduino CLI
367
+ result = subprocess.run(
368
+ ["arduino-cli", "lib", "install", name],
369
+ capture_output=True,
370
+ )
371
+ if result.returncode != 0:
372
+ return {
373
+ "error": "Library installation failed",
374
+ "output": result.stderr.decode("utf-8"),
375
+ }
376
+ return {
377
+ "success": True,
378
+ "output": result.stdout.decode("utf-8"),
379
+ }
380
+
381
+
382
+ root_agent = Agent(
383
+ name="coding_agent",
384
+ model="gemini-2.5-flash-preview-04-17",
385
+ description=("Agent to write Arduino code."),
386
+ instruction=(
387
+ "You are an expert programming agent tasked with designing a system involvin an Arduino and aditional hardware."
388
+ "You are required to wire up everythinb by yourself. It's not an option to just add the components and write teh code."
389
+ "When writing code always use the appropriate tools you where given to ouptut the code. Don't output any code in the chat."
390
+ "When you are done, compile the code with the Arduino CLI, without asking for confirmation."
391
+ ),
392
+ tools=[
393
+ FunctionTool(func=write_code),
394
+ FunctionTool(func=read_code),
395
+ FunctionTool(func=list_components),
396
+ FunctionTool(func=add_component),
397
+ FunctionTool(func=list_components),
398
+ FunctionTool(func=component_info),
399
+ FunctionTool(func=del_component),
400
+ FunctionTool(func=add_wire),
401
+ FunctionTool(func=del_wire),
402
+ FunctionTool(func=compile_with_arduino),
403
+ FunctionTool(func=search_library),
404
+ FunctionTool(func=add_library),
405
+ ],
406
+ )
407
+
408
+ session_service = InMemorySessionService()
409
+
410
+ APP_NAME = "weather_tutorial_app"
411
+ USER_ID = "user_1"
412
+ SESSION_ID = "session_001"
413
+
414
+ session = session_service.create_session(
415
+ app_name=APP_NAME,
416
+ user_id=USER_ID,
417
+ session_id=SESSION_ID,
418
+ )
419
+
420
+ runner = Runner(agent=root_agent, app_name=APP_NAME, session_service=session_service)
421
+
422
+
423
+ async def call_agent_async(query: str, runner, user_id, session_id):
424
+ print(f"\n>>> User Query: {query}")
425
+
426
+ content = types.Content(role="user", parts=[types.Part(text=query)])
427
+ final_response_text = "Agent did not produce a final response."
428
+
429
+ async for event in runner.run_async(
430
+ user_id=user_id, session_id=session_id, new_message=content
431
+ ):
432
+ print(
433
+ f" [Event] Author: {event.author}, Type: {type(event).__name__}, Final: {event.is_final_response()}, Content: {event.content}"
434
+ )
435
+ if event.is_final_response():
436
+ if event.content and event.content.parts:
437
+ final_response_text = event.content.parts[0].text
438
+
439
+ print(f"<<< Agent Response: {final_response_text}")
440
+
441
+
442
+ async def run_conversation():
443
+ await call_agent_async(
444
+ "What is the current time in new york?",
445
+ runner=runner,
446
+ user_id=USER_ID,
447
+ session_id=SESSION_ID,
448
+ )
449
+
450
+
451
+ if __name__ == "__main__":
452
+ try:
453
+ asyncio.run(run_conversation())
454
+ except Exception as e:
455
+ print(f"An error occured: {e}")
main.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from agent import session_service, root_agent, APP_NAME, runner
3
+ from google.genai import types
4
+ from pprint import pprint, pformat
5
+ from uuid import uuid4
6
+ import os
7
+ import tempfile
8
+
9
+
10
+ def generate_mermaid(components, wires=[], direction: str = "LR") -> str:
11
+ """
12
+ Build a Mermaid-JS flow-chart for a simple β€œhigh-level” schematic.
13
+
14
+ Parameters
15
+ ----------
16
+ components : list[dict]
17
+ Each dict needs the keys
18
+ β€’ 'component_name' – human-readable label (e.g. "Arduino Uno R3")
19
+ β€’ 'id' – unique node ID used in the diagram
20
+ wires : list[dict]
21
+ Each dict needs the keys
22
+ β€’ 'start_id', 'start_pin' – origin node & pin
23
+ β€’ 'end_id', 'end_pin' – destination node & pin
24
+ direction : str, optional
25
+ Flow direction for the chart header; one of "LR", "RL", "TB", "TD".
26
+ Defaults to "LR" (left-to-right).
27
+
28
+ Returns
29
+ -------
30
+ str
31
+ A Markdown-fenced Mermaid block you can drop straight into GitHub,
32
+ Obsidian, Notion, etc.
33
+ """
34
+
35
+ mermaid = [f"```mermaid", f"flowchart {direction}"]
36
+
37
+ # 1) Declare nodes
38
+ for node_id, node_name in components.items():
39
+ label = f"{node_name}\n({node_id})"
40
+ mermaid.append(f' {node_id}["{label}"]')
41
+
42
+ # 2) Draw labelled connections
43
+ for wire in wires:
44
+ start = wire["start_id"]
45
+ end = wire["end_id"]
46
+ label = f'{wire["start_pin"]} β†’ {wire["end_pin"]}'
47
+ mermaid.append(f' {start} -- "{label}" --> {end}')
48
+
49
+ mermaid.append("```")
50
+ return "\n".join(mermaid)
51
+
52
+
53
+ async def interact_with_agent(
54
+ prompt,
55
+ history: list[gr.ChatMessage],
56
+ session_id: gr.State,
57
+ local_storage: gr.BrowserState,
58
+ request: gr.Request,
59
+ ):
60
+ messages = []
61
+ messages.append(
62
+ gr.ChatMessage(
63
+ role="assistant", content="Thinking...", metadata={"status": "pending"}
64
+ )
65
+ )
66
+ yield messages, None, None, None
67
+ # yield messages
68
+
69
+ user_id = local_storage[0]
70
+
71
+ print(user_id)
72
+ print(session_id)
73
+
74
+ session = session_service.get_session(
75
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
76
+ )
77
+
78
+ if session is None:
79
+ session = session_service.create_session(
80
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
81
+ )
82
+
83
+ fetch_code = lambda: session_service.get_session(
84
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
85
+ ).state.get("code")
86
+ fetch_components = lambda: session_service.get_session(
87
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
88
+ ).state.get("components")
89
+ fetch_wires = lambda: session_service.get_session(
90
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
91
+ ).state.get("wires")
92
+
93
+ def mermaid_assemble():
94
+ components = fetch_components()
95
+ wires = fetch_wires()
96
+ if components == None:
97
+ return gr.Markdown("No components yet")
98
+ if wires == None:
99
+ wires = []
100
+ mermaid = generate_mermaid(components, wires)
101
+ return gr.Markdown(mermaid)
102
+
103
+ content = types.Content(role="user", parts=[types.Part(text=prompt)])
104
+
105
+ temp = None
106
+
107
+ async for event in runner.run_async(
108
+ user_id=user_id, session_id=session_id, new_message=content
109
+ ):
110
+ """
111
+ print(
112
+ f" [Event] Author: {event.author}, Type: {type(event).__name__}, Final: {event.is_final_response()}, Content: {event.content}"
113
+ )
114
+ """
115
+ for call in event.get_function_calls():
116
+ messages.append(
117
+ gr.ChatMessage(
118
+ role="assistant",
119
+ content=(
120
+ f"Invoking {call.name} with args: \n {pformat(call.args)}"
121
+ if not call.name == "write_code"
122
+ else gr.Code(call.args["code"], language="cpp")
123
+ ),
124
+ metadata={"title": f"πŸ› οΈ Used tool {call.name}"},
125
+ )
126
+ )
127
+ yield messages, None, None, None
128
+ for call in event.get_function_responses():
129
+ if call.name == "compile_with_arduino" and call.response["success"]:
130
+ temp = tempfile.gettempdir()
131
+
132
+ temp_uuid = str(uuid4())
133
+ temp = os.path.join(temp, f"{temp_uuid}.ino.elf")
134
+
135
+
136
+ with open(temp, "wb") as f:
137
+ with open(
138
+ "/tmp/arduino_project/output/arduino_project.ino.elf", "rb"
139
+ ) as f2:
140
+ f.write(f2.read())
141
+
142
+ yield messages, None, None, gr.DownloadButton(
143
+ "Download ELF",
144
+ temp,
145
+ variant="primary",
146
+ render=False,
147
+ interactive=True,
148
+ )
149
+ if event.is_final_response():
150
+ messages.append(
151
+ gr.ChatMessage(role="assistant", content=event.content.parts[0].text)
152
+ )
153
+ yield messages, gr.Code(
154
+ language="cpp", value=fetch_code()
155
+ ), mermaid_assemble(), (
156
+ None
157
+ if not temp
158
+ else gr.DownloadButton(
159
+ "Download ELF",
160
+ temp,
161
+ variant="primary",
162
+ render=False,
163
+ interactive=True,
164
+ )
165
+ )
166
+
167
+ session = session_service.get_session(
168
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
169
+ )
170
+
171
+ pprint(session.state)
172
+
173
+
174
+ with gr.Blocks() as demo:
175
+ session_id = gr.State(str(uuid4()))
176
+ code = gr.Code(language="cpp", render=False)
177
+ markdown_schematic = gr.Markdown(render=False)
178
+ local_storage = gr.BrowserState([str(uuid4())])
179
+ download_button = gr.DownloadButton(
180
+ "Download ELF",
181
+ "/tmp/arduino_project/output/arduino_project.ino.elf",
182
+ interactive=False,
183
+ render=False,
184
+ )
185
+
186
+ with gr.Row():
187
+ gr.Markdown(
188
+ """
189
+ # Arduino Hardware and Software
190
+ """
191
+ )
192
+ with gr.Row():
193
+ with gr.Column():
194
+ chatbot = gr.Chatbot(label="Agent", type="messages")
195
+
196
+ def clear_chat():
197
+ return [
198
+ str(uuid4()),
199
+ gr.Code(language="cpp", render=False),
200
+ gr.Markdown(render=False),
201
+ gr.DownloadButton(
202
+ "Download ELF",
203
+ "/tmp/arduino_project/output/arduino_project.ino.elf",
204
+ render=False,
205
+ interactive=False,
206
+ ),
207
+ ]
208
+
209
+ chatbot.clear(
210
+ lambda: clear_chat(),
211
+ outputs=[session_id, code, markdown_schematic, download_button],
212
+ )
213
+ chat_interface = gr.ChatInterface(
214
+ interact_with_agent,
215
+ chatbot=chatbot,
216
+ type="messages",
217
+ examples=[
218
+ [
219
+ 'Design a schematic and write code for an arduino driven "Joke of the day machine" where the user presses a physical button and then a random joke of the day is displayed on the display.'
220
+ ],
221
+ ["Write a Hello World program for an Arduino Uno"],
222
+ ["Write a program to blink an LED on an Arduino Uno"],
223
+ ],
224
+ additional_inputs=[session_id, local_storage],
225
+ additional_outputs=[code, markdown_schematic, download_button],
226
+ fill_height=True,
227
+ show_progress="full",
228
+ )
229
+ with gr.Column():
230
+ code.render()
231
+ markdown_schematic.render()
232
+
233
+ with gr.Row():
234
+ download_button.render()
235
+
236
+ # mm
237
+ demo.launch()
pyproject.toml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "arducoder-prototype"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "google-adk>=0.5.0",
9
+ "gradio>=5.29.1",
10
+ ]
uv.lock ADDED
The diff for this file is too large to render. See raw diff