Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/ambient-inventory-agent/app/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ def _model_facing_schema(args_schema: Any) -> dict[str, Any]:
This is the tool's SIGNATURE — which arguments `find` takes. Nothing to do with
document shape: the agent discovers that itself via `collection-schema`.
"""
properties = args_schema.get("properties") if isinstance(args_schema, dict) else None
properties = (
args_schema.get("properties") if isinstance(args_schema, dict) else None
)
if not isinstance(properties, dict):
return {"type": "object", "properties": {}}

Expand Down Expand Up @@ -518,9 +520,7 @@ def stream_messages(chunk: Any) -> list[Any]:
]


def new_tool_calls(
msg: Any, seen: set[str]
) -> list[tuple[str, dict[str, Any], str]]:
def new_tool_calls(msg: Any, seen: set[str]) -> list[tuple[str, dict[str, Any], str]]:
"""(name, args, rendered command) for each tool call not yet reported.

A streamed message is re-delivered as later chunks arrive, so `seen` — the call
Expand Down
7 changes: 4 additions & 3 deletions apps/ambient-inventory-agent/app/investigator.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,6 @@ def _readable_thought(line: str) -> str:
return line if len(line) <= 400 else f"{line[:397]}…"




INVESTIGATOR_PROMPT = """\
You are the inventory monitor for Leafy Roasters, a coffee roaster, running on a \
schedule against the `{database}` MongoDB database. Find the component that has \
Expand Down Expand Up @@ -319,7 +317,10 @@ async def file_alert(**fields: Any) -> str:
document = self.repository.build_alert_document(
self._session_id, self._sweep_id, fields
)
payload = {"collection": "alerts", "documents": [_as_extended_json(document)]}
payload = {
"collection": "alerts",
"documents": [_as_extended_json(document)],
}
result = await insert.ainvoke(payload)
if "E11000" in str(result) or "duplicate key" in str(result).lower():
return "An alert for this component already exists; not filing again."
Expand Down
2 changes: 1 addition & 1 deletion apps/ambient-inventory-agent/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from .db import get_database
from .demo_data import ensure_indexes, ensure_validators, seed_demo_data
from .mcp_session import MCPUnavailable, get_mcp_session
from .monitor import InventoryMonitor
from .memory import close_checkpointer
from .monitor import InventoryMonitor
from .repository import InventoryRepository

STATIC_DIR = Path(__file__).parent / "static"
Expand Down
25 changes: 25 additions & 0 deletions apps/ambient-inventory-agent/app/static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const els = {
pageTitle: document.getElementById("pageTitle"),
alertBadge: document.getElementById("alertBadge"),
navItems: Array.from(document.querySelectorAll(".nav-item")),
themeToggle: document.getElementById("themeToggle"),
};

// The play control calls /api/demo/start, which re-mints the service-account token,
Expand Down Expand Up @@ -1279,6 +1280,30 @@ els.navItems.forEach((item) => {
});
});

/* ---------- Theme toggle ---------- */
// The pre-paint script in index.html already applied the stored choice; this only
// handles clicks and keeps the icon in sync.
function paintThemeIcon() {
const dark = document.documentElement.getAttribute("data-theme") === "dark";
// Show the theme you would switch TO, which is the convention users expect.
els.themeToggle.textContent = dark ? "☀" : "☾";
}

els.themeToggle.addEventListener("click", () => {
const root = document.documentElement;
const dark = root.getAttribute("data-theme") === "dark";
if (dark) root.removeAttribute("data-theme");
else root.setAttribute("data-theme", "dark");
try {
localStorage.setItem("theme", dark ? "light" : "dark");
} catch (e) {
// Private browsing — the toggle still works for this page load.
}
paintThemeIcon();
});

paintThemeIcon();

/* ---------- Boot ---------- */
render(true);
startSession().catch((error) => {
Expand Down
23 changes: 20 additions & 3 deletions apps/ambient-inventory-agent/app/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Leafy Roasters Inventory Assistant</title>
<script>
// Inline and BEFORE the stylesheet on purpose: applying data-theme after first
// paint makes the page flash light before going dark, which looks broken on a
// projector. A stored choice wins over the OS so either look can be forced.
(function () {
var saved = null;
try { saved = localStorage.getItem('theme'); } catch (e) { /* private mode */ }
var dark = saved
? saved === 'dark'
: window.matchMedia('(prefers-color-scheme: dark)').matches;
if (dark) document.documentElement.setAttribute('data-theme', 'dark');
})();
</script>
<link rel="stylesheet" href="/static/styles.css" />
</head>
<body>
Expand Down Expand Up @@ -48,9 +61,13 @@
<h1 id="pageTitle">Dashboard</h1>
</div>

<!-- Decorative only: this demo has no auth. Stands in for the shop owner the
agent is talking to, so the dashboard reads as somebody's account. -->
<span class="avatar">DW</span>
<div class="topbar-actions">
<button class="theme-toggle" id="themeToggle" type="button"
aria-label="Toggle dark mode" title="Toggle dark mode"></button>
<!-- Decorative only: this demo has no auth. Stands in for the shop owner the
agent is talking to, so the dashboard reads as somebody's account. -->
<span class="avatar">DW</span>
</div>
</header>

<main id="view" class="view"></main>
Expand Down
Loading
Loading