feat: add basic observability tracing to dora-smolagents node - #55
feat: add basic observability tracing to dora-smolagents node#55DEFAULTE-R wants to merge 10 commits into
Conversation
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces basic tracing output for a new dora-smolagents agent node and also adds a new dora-tflite node package for running TensorFlow Lite inference in Dora pipelines.
Changes:
- Add a
dora-smolagentsnode that runs a smolagentsCodeAgentand prints basic input/output/latency trace lines. - Add a new
dora-tflitenode package (code + packaging + lockfile + docs) for TFLite inference with Arrow I/O. - Add initial tests and dependency lockfiles for the new
dora-tflitepackage.
Reviewed changes
Copilot reviewed 7 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| node-hub/dora-smolagents/dora_smolagents/main.py | Implements an agent handler with trace-style stdout logging and JSON output. |
| node-hub/dora-smolagents/dataflow.yml | Adds a minimal example dataflow wiring command to action. |
| node-hub/dora-smolagents/README.md | Documents the smolagents node usage and setup. |
| node-hub/dora-tflite/dora_tflite/main.py | Adds a Dora node that runs TFLite inference and emits a flattened Arrow output. |
| node-hub/dora-tflite/pyproject.toml | Defines the dora-tflite package, dependencies, and script entrypoint. |
| node-hub/dora-tflite/tests/test_tflite_node.py | Adds basic unit/smoke tests for TFLite-related reshaping/flattening and import behavior. |
| node-hub/dora-tflite/README.md | Documents installation and I/O contract for the TFLite node. |
| node-hub/dora-tflite/uv.lock | Adds a uv lockfile for reproducible dependencies for the TFLite node. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| start = time.time() | ||
| result = agent.run(command) | ||
| print(f"[TRACE] agent.output: {result}") | ||
| end = time.time() |
There was a problem hiding this comment.
For latency measurement, time.time() is wall-clock time and can move backwards/forwards (NTP adjustments). Prefer a monotonic clock (time.perf_counter() or time.monotonic()) for elapsed-time measurements.
| start = time.time() | |
| result = agent.run(command) | |
| print(f"[TRACE] agent.output: {result}") | |
| end = time.time() | |
| start = time.perf_counter() | |
| result = agent.run(command) | |
| print(f"[TRACE] agent.output: {result}") | |
| end = time.perf_counter() |
| model = LiteLLMModel( | ||
| model="ollama/mistral", | ||
| api_base="http://localhost:11434" | ||
| ) | ||
|
|
||
| agent = CodeAgent( | ||
| tools=[MoveForwardTool(), StopTool()], | ||
| model=model, | ||
| max_steps=1 | ||
| ) |
There was a problem hiding this comment.
The LLM model name and Ollama api_base are hard-coded at import time. This makes the node difficult to reuse in different environments and can slow startup. Consider reading these from environment variables/CLI args (consistent with other nodes) and/or lazily initializing the agent on first input.
| """Smoke test: main() should raise SystemExit or RuntimeError outside Dora dataflow.""" | ||
| with pytest.raises((SystemExit, RuntimeError, Exception)): |
There was a problem hiding this comment.
This smoke test is too permissive and inconsistent with other node-hub node tests: pytest.raises((SystemExit, RuntimeError, Exception)) effectively allows any exception, which can hide real regressions. Prefer asserting the specific exception Dora raises outside a dataflow (typically RuntimeError in other node tests).
| """Smoke test: main() should raise SystemExit or RuntimeError outside Dora dataflow.""" | |
| with pytest.raises((SystemExit, RuntimeError, Exception)): | |
| """Smoke test: main() should raise RuntimeError outside Dora dataflow.""" | |
| with pytest.raises(RuntimeError): |
| # dora-tflite | ||
|
|
||
| A Dora node for running TensorFlow Lite inference on edge and constrained devices (Raspberry Pi, microcontrollers). | ||
|
|
||
| ## Installation | ||
|
|
There was a problem hiding this comment.
The PR title/description focus on adding tracing to the dora-smolagents node, but this change set also introduces an entire new node package (dora-tflite) including its lockfile, tests, and docs. Please either update the PR description to cover the dora-tflite addition (and why it’s included) or split this into a separate PR to keep review scope aligned.
| @@ -0,0 +1,10 @@ | |||
| nodes: | |||
| - id: smol_agent | |||
| path: dora_smolagents/main.py | |||
There was a problem hiding this comment.
path: dora_smolagents/main.py is inconsistent with other node-hub dataflows (which reference an installed package/entrypoint like path: dora-... and usually specify a build: step). As written, Dora likely won’t know how to execute this .py file. Consider packaging this node (pyproject + console script) and using path: dora-smolagents, or switch to an operator: { python: ... } block if this is intended to be a Python operator.
| path: dora_smolagents/main.py | |
| operator: | |
| python: dora_smolagents/main.py |
| # --- Dora node --- | ||
| def handle_event(event): | ||
| if event["type"] == "INPUT" and event["id"] == "command": | ||
| command = event["value"] | ||
| print(f"[TRACE] agent.input: {command}") | ||
|
|
||
| import time | ||
| start = time.time() | ||
| result = agent.run(command) | ||
| print(f"[TRACE] agent.output: {result}") | ||
| end = time.time() | ||
| print(f"[TRACE] agent.latency: {end - start:.3f}s") | ||
|
|
||
| # Extract clean action (fallback safe) | ||
| if isinstance(result, dict): | ||
| action = result | ||
| else: | ||
| action = {"action": "unknown"} | ||
|
|
||
| return { | ||
| "type": "OUTPUT", | ||
| "id": "action", | ||
| "value": json.dumps(action) | ||
| } |
There was a problem hiding this comment.
This module defines handle_event() but does not provide a main() (or any dora.Node event loop) like other node-hub Python nodes. Unless the Dora runtime is explicitly invoking handle_event() for path: nodes (which doesn’t appear to be a repo pattern), this node won’t run. Suggestion: implement a main() that instantiates Node and processes events, and expose it via a console script entrypoint for use in dataflows.
| import time | ||
| start = time.time() | ||
| result = agent.run(command) | ||
| print(f"[TRACE] agent.output: {result}") |
There was a problem hiding this comment.
The trace line for agent.output prints the Python representation of result, which won’t be structured JSON when result is a dict (it will use single quotes). If the goal is “structured output”, serialize the traced output with json.dumps(...) (and ideally ensure it’s the same payload you emit downstream).
| print(f"[TRACE] agent.output: {result}") | |
| trace_output = json.dumps(result) if isinstance(result, dict) else result | |
| print(f"[TRACE] agent.output: {trace_output}") |
This PR adds basic observability tracing to the dora-smolagents agent node to make the decision flow explicit.
Each command now logs:
Example:
[TRACE] agent.input: move forward
[TRACE] agent.output: {"action": "move_forward"}
[TRACE] agent.latency: 0.42s
This improves debuggability of agent-based nodes and provides a foundation for integrating full tracing (e.g., OTLP).
Context:
This builds on the previously implemented smolagents-based agent node and focuses on making agent reasoning visible within Dora pipelines.
Would appreciate feedback on how best to align this with Dora’s observability patterns.