Add vanilla agent dashboard - #78
Merged
Merged
Conversation
DidierRLopes
commented
Sep 15, 2025
Contributor
- Add vanilla agent dashboard
- Clean up financial prompt optimizer
- Improve README
piiq
approved these changes
Sep 18, 2025
piiq
left a comment
Member
There was a problem hiding this comment.
I've asked GPT-5 for strategies to improve the 40 example to make it easier to comprehend. Here's the response (edited)
Here are concrete ways to simplify this example so it clearly demonstrates “getting the active tab context and its widgets” without extra noise.
Key pain points:
- Heavy formatting logic: The format_widget function builds tables, truncates text, and handles many fields, which distracts from the core idea.
- Nested loops and O(n²) search: Matching tab widgets to full details by scanning all_widgets repeatedly makes the code longer and harder to follow.
- Repeated branching: Handling primary/secondary/dashboard/fallback separately leads to verbose, duplicated logic.
- Conditional streaming by role: Special-casing “human” adds branching that isn’t necessary for a simple demo.
Simplification strategies
- Focus on the active tab:
- Show only the active tab and a short list of its widgets. Optionally add “show all tabs” later.
- Use simple text output:
- Replace tables with short bullet lines: “- Name (id: X) — short description”.
- Index widgets by UUID:
- Build a dict once: by_uuid = {str(w.uuid): w for w in widgets} to map dashboard references quickly and clearly.
- Single path for gathering widgets:
- Combine primary and secondary once into a list; avoid repeated conditionals later.
- Single streaming path:
- Always stream one compact message; skip separate generators/role checks.
- Small helpers:
short(text, width=120)to tidy and truncate text.gather_widgets(request)to combine widget sources.active_tab(info)to pick the active or first tab.
Lean /v1/query sketch
from textwrap import shorten
from fastapi import FastAPI
from sse_starlette.sse import EventSourceResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from openbb_ai.models import QueryRequest
from openbb_ai import message_chunk
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], allow_credentials=True,
allow_methods=["*"], allow_headers=["*"],
)
@app.get("/agents.json")
def get_copilot_description():
return JSONResponse(content={
"vanilla_agent_dashboard_widgets": {
"name": "Vanilla Agent Dashboard Widgets",
"description": "Show active tab and its widgets.",
"endpoints": {"query": "http://localhost:7777/v1/query"},
"features": {"streaming": True},
}
})
def short(text: str, width: int = 120) -> str:
text = (text or "").replace("\n", " ").strip()
return shorten(text, width=width, placeholder="...") if text else "no description"
def gather_widgets(req: QueryRequest):
items = []
if req.widgets:
if req.widgets.primary: items += req.widgets.primary
if req.widgets.secondary: items += req.widgets.secondary
return items
def active_tab(info):
if not info or not info.tabs: return None
if info.current_tab_id:
for t in info.tabs:
if t.tab_id == info.current_tab_id:
return t
return info.tabs[0]
@app.post("/v1/query")
async def query(request: QueryRequest) -> EventSourceResponse:
widgets = gather_widgets(request)
by_uuid = {str(getattr(w, "uuid", "")): w for w in widgets}
info = request.workspace_state.current_dashboard_info if request.workspace_state else None
tab = active_tab(info)
lines = []
if tab:
lines.append(f"Active tab: {tab.tab_id}")
for tw in (tab.widgets or []):
w = by_uuid.get(str(tw.widget_uuid))
name = (getattr(w, "name", None) or getattr(w, "widget_id", None)
or getattr(tw, "name", None) or "Widget")
wid = getattr(w, "widget_id", None) or "N/A"
desc = short(getattr(w, "description", None))
lines.append(f"- {name} (id: {wid}) — {desc}")
elif widgets:
lines.append("Widgets in context:")
for w in widgets:
name = w.name or w.widget_id or "Widget"
lines.append(f"- {name}")
else:
lines.append("No widgets found on your dashboard.")
async def stream():
yield message_chunk("\n".join(lines)).model_dump()
return EventSourceResponse(stream(), media_type="text/event-stream")- Keeps SSE and shows only the essentials: active tab and its widgets.
- Gather widgets once from primary + secondary.
- Build by_uuid for O(1) lookups.
- Select active tab; fall back to the first tab or to a simple “widgets in context” list if no tab info.
- Produce a short, readable list of lines and stream them as one message.
Why this is easier to grasp
- The example demonstrates a single concept—active tab context—without formatting complexity.
- The data path is linear and obvious: gather → index → pick tab → list widgets.
- Helpers isolate small, reusable bits and reduce mental load.
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.