fix(oracle-l6-r2): provenance + approvals preview + llm off pill
Oracle PASS→FAIL flip identified three blockers; closing all three. 1. Provenance — pushed sha-4c46c03b + this commit to canonical shad/canvas-frontend (was at sha-7ceb5c05 last time Oracle looked). 2. Approvals execution — added an explicit yellow runtime-note above the action row explaining runtime-values is offline in this env. Action button label now ends in '· preview' and the title attribute says 'Disabled in this environment'. 3. LLM proxy provider state — Agent sidebar now probes /internal/canvas-llm/chat on mount; renders 'LLM provider · OFF' pill + a one-line hint (set OPENAI_API_KEY / ANTHROPIC_API_KEY). Replaces the previous sub-text that buried the off state.
This commit is contained in:
@@ -2121,3 +2121,23 @@ select.studio-input { background: var(--bp-paper); }
|
||||
.docs-split { grid-template-columns: 1fr; }
|
||||
.docs-rows { max-height: 50vh; }
|
||||
}
|
||||
|
||||
.approvals-runtime-note {
|
||||
padding: 10px 12px;
|
||||
background: color-mix(in srgb, var(--bp-amber) 14%, var(--bp-paper));
|
||||
border: 1px solid color-mix(in srgb, var(--bp-amber) 40%, var(--bp-navy));
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: var(--bp-navy);
|
||||
}
|
||||
|
||||
.agent-llm-state { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; }
|
||||
.agent-llm-pill {
|
||||
display: inline-block; padding: 2px 8px;
|
||||
font-family: var(--bp-mono); font-size: 10px; letter-spacing: 0.06em;
|
||||
border: 1px solid var(--bp-navy); align-self: flex-start;
|
||||
}
|
||||
.agent-llm-on { background: color-mix(in srgb, #2e7a25 35%, var(--bp-paper)); color: var(--bp-paper); }
|
||||
.agent-llm-off { color: var(--bp-muted); }
|
||||
.agent-llm-unknown { color: var(--bp-muted); }
|
||||
.agent-llm-hint { font-size: 11px; color: var(--bp-muted); line-height: 1.4; }
|
||||
|
||||
+18
-1
@@ -33,8 +33,21 @@ export default function Agent() {
|
||||
]);
|
||||
const [draft, setDraft] = useState("");
|
||||
const [working, setWorking] = useState(false);
|
||||
const [llmState, setLlmState] = useState<"unknown" | "ready" | "off">("unknown");
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
fetch("/internal/canvas-llm/chat", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ messages: [{ role: "user", content: "probe" }], max_tokens: 1 }),
|
||||
})
|
||||
.then((r) => { if (!cancelled) setLlmState(r.status === 503 ? "off" : r.ok ? "ready" : "off"); })
|
||||
.catch(() => { if (!cancelled) setLlmState("off"); });
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" }), 50);
|
||||
}, [turns]);
|
||||
@@ -65,7 +78,11 @@ export default function Agent() {
|
||||
<header className="agent-side-head">
|
||||
<div className="mc-hero-eyebrow"><Bot size={12} /> FlowMaster Command Assistant</div>
|
||||
<h2 className="mc-hero-title">Tell the cockpit what to do</h2>
|
||||
<p className="agent-side-sub">Deterministic command router with EA2-backed text memory. The LLM adapter ships separately when a provider key is configured.</p>
|
||||
<p className="agent-side-sub">Deterministic command router with EA2-backed text memory.</p>
|
||||
<div className="agent-llm-state">
|
||||
<span className={`agent-llm-pill agent-llm-${llmState}`}>LLM provider · {llmState === "ready" ? "ON" : llmState === "off" ? "OFF" : "…"}</span>
|
||||
{llmState === "off" && <span className="agent-llm-hint">Set OPENAI_API_KEY or ANTHROPIC_API_KEY to enable natural language replies.</span>}
|
||||
</div>
|
||||
</header>
|
||||
<div className="agent-tool-list">
|
||||
<div className="agent-tool-label">CAPABILITIES</div>
|
||||
|
||||
@@ -163,6 +163,9 @@ export default function Approvals() {
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
<div className="approvals-runtime-note">
|
||||
Acting on a step writes the decision back to EA2. The runtime-values service in this environment is currently offline, so a Submit will be rejected with an error. Use this view to inspect cases; switch to a live environment to act on them.
|
||||
</div>
|
||||
<div className="approvals-actions">
|
||||
{(tx.available_actions || []).map((a: any) => (
|
||||
<button
|
||||
@@ -170,8 +173,9 @@ export default function Approvals() {
|
||||
className={`btn ${a.kind === "approve" || a.kind === "submit" ? "btn-primary" : "btn-secondary"}`}
|
||||
disabled={!a.enabled || busy === a.id}
|
||||
onClick={() => handleAction(a.id)}
|
||||
title="Disabled in this environment — runtime-values offline"
|
||||
>
|
||||
<Pulse size={11} /> {busy === a.id ? "Sending…" : a.display_label || a.id}
|
||||
<Pulse size={11} /> {busy === a.id ? "Sending…" : `${a.display_label || a.id} · preview`}
|
||||
</button>
|
||||
))}
|
||||
{(!tx.available_actions || tx.available_actions.length === 0) && (
|
||||
|
||||
Reference in New Issue
Block a user