Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4927b3a
feat(observability): patter.* OTel span attributes (Python only) + 0.…
nicolotognoni May 8, 2026
db5d58b
fix(dashboard,pipeline): hydrate cost/latency from top-level + barge-…
nicolotognoni May 9, 2026
8a12d61
feat(barge-in): opt-in confirmation strategies (MinWords reference impl)
nicolotognoni May 9, 2026
0452c51
fix+feat: dashboard hydrate, first-audio anchor, barge-in confirmatio…
nicolotognoni May 9, 2026
c585f6d
feat(0.6.1): cost split + STT methodology fix + prewarm + 13 review f…
nicolotognoni May 10, 2026
cbe1886
fix(0.6.1): WS handoff prewarm + dashboard regressions + first-turn l…
nicolotognoni May 10, 2026
655858e
fix(0.6.1): roll back STT debounce, dashboard threshold, Krisp TS sca…
nicolotognoni May 11, 2026
8507a34
fix: revert ElevenLabs HTTP→WS default flip from 4ff09bd
nicolotognoni May 13, 2026
b4477de
fix(0.6.1): dashboard live merge + firstMessage barge-in + drain mark…
nicolotognoni May 12, 2026
686e2f3
fix(metrics): align EOU semantics + unit (ms) across Python/TS
nicolotognoni May 12, 2026
b8edc53
feat(ts): observability OTel no-op stubs for SDK parity
nicolotognoni May 12, 2026
a1c4666
fix(0.6.1): Cerebras usage-chunk log + Krisp TS status refresh (re-ba…
nicolotognoni May 12, 2026
e7553e5
fix(ts): correct ElevenLabsTTS export comment — HTTP REST default, no…
nicolotognoni May 13, 2026
87da541
fix(pipeline): always pace prewarmed first-message audio by playout d…
nicolotognoni May 13, 2026
898b70c
fix(pipeline): correct first-message burst pacing with initialFillCom…
nicolotognoni May 13, 2026
2836d9c
fix(pipeline): one-shot barge-in + first-message crackle + barge-in gate
nicolotognoni May 14, 2026
feb5f4a
feat(dashboard): multi-select delete + privacy/dark toggles + dark-mo…
nicolotognoni May 14, 2026
dfaa29f
fix(dashboard): MetricsPanel Latency/Cost tabs render at the same height
nicolotognoni May 14, 2026
6975873
feat(providers): add OpenAIRealtime2 engine for gpt-realtime-2 (GA Re…
nicolotognoni May 14, 2026
6f6c8e0
fix(openai-realtime-2): bidirectional audio transcoding + outbound ch…
nicolotognoni May 15, 2026
edbd68e
chore(release): 0.6.1
nicolotognoni May 17, 2026
0077910
chore: pre-commit end-of-file-fixer on cartesia-stt.ts
nicolotognoni May 17, 2026
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
772 changes: 762 additions & 10 deletions CHANGELOG.md

Large diffs are not rendered by default.

405 changes: 404 additions & 1 deletion dashboard-app/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion dashboard-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"build": "tsc --noEmit && vite build",
"preview": "vite preview",
"lint": "tsc --noEmit",
"test": "vitest run",
"sync": "node ./scripts/sync.mjs"
},
"dependencies": {
Expand All @@ -21,6 +22,7 @@
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vite-plugin-singlefile": "^2.0.3"
"vite-plugin-singlefile": "^2.0.3",
"vitest": "^2.1.4"
}
}
36 changes: 34 additions & 2 deletions dashboard-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { Topbar } from './components/Topbar';
import { PageHeader } from './components/PageHeader';
import { Metric, type MetricBucket } from './components/Metric';
import { CallTable, type Call } from './components/CallTable';
import { fmtCostUSD } from './components/format';
import { LiveCallPanel } from './components/LiveCallPanel';
import { MetricsPanel } from './components/MetricsPanel';
import { useDashboardData } from './hooks/useDashboardData';
import { useTranscript } from './hooks/useTranscript';
import { useUiPrefs } from './hooks/useUiPrefs';
import { deleteCalls } from './lib/api';
import {
bucketStrategyForRange,
computeSparkline,
Expand Down Expand Up @@ -53,7 +56,9 @@ function pickPhoneNumber(calls: readonly Call[]): string {
}

export function App() {
const { calls, aggregates, isStreaming, error, refresh } = useDashboardData();
const { calls, aggregates, isStreaming, error, refresh, removeCallsLocal } =
useDashboardData();
const { revealed, dark, toggleRevealed, toggleDark } = useUiPrefs();
const [selectedId, setSelectedId] = useState<string | null>(null);
const [search, setSearch] = useState('');
const [range, setRange] = useState<RangeKey>('24h');
Expand Down Expand Up @@ -156,13 +161,33 @@ export function App() {
refresh().catch(() => undefined);
};

const handleDeleteCalls = async (ids: readonly string[]): Promise<void> => {
if (ids.length === 0) return;
// Optimistic local removal so the rows vanish immediately. The SSE
// ``calls_deleted`` event triggers a refresh shortly after; if the
// server rejects an id (race with a status callback), it re-appears.
removeCallsLocal(ids);
if (ids.includes(selectedId ?? '')) setSelectedId(null);
try {
await deleteCalls(ids);
} catch {
// Pull the authoritative snapshot back if the call failed so the UI
// is consistent with the server's view.
await refresh().catch(() => undefined);
}
};

return (
<>
<Topbar
liveCount={liveCount}
todayCount={totalCount}
phoneNumber={phoneNumber}
sdkVersion={SDK_VERSION}
revealed={revealed}
dark={dark}
onToggleRevealed={toggleRevealed}
onToggleDark={toggleDark}
/>
<div className="page">
<PageHeader range={range} setRange={(r) => setRange(r as RangeKey)} />
Expand All @@ -174,6 +199,7 @@ export function App() {
spark={sparkTotalCalls.heights}
buckets={toBuckets(sparkTotalCalls)}
onSelectCall={setSelectedId}
kind="count"
/>
<Metric
label="Avg latency p95"
Expand All @@ -182,13 +208,15 @@ export function App() {
spark={sparkLatency.heights}
buckets={toBuckets(sparkLatency)}
onSelectCall={setSelectedId}
kind="latency"
/>
<Metric
label={`Spend · ${RANGE_LABEL[range]}`}
value={`$${rangeSpend.toFixed(2)}`}
value={fmtCostUSD(rangeSpend)}
spark={sparkSpend.heights}
buckets={toBuckets(sparkSpend)}
onSelectCall={setSelectedId}
kind="spend"
/>
<Metric
label="Active now"
Expand All @@ -199,6 +227,7 @@ export function App() {
spark={sparkLive.heights}
buckets={toBuckets(sparkLive)}
onSelectCall={setSelectedId}
kind="count"
/>
</div>

Expand All @@ -210,6 +239,8 @@ export function App() {
newId={null}
search={search}
setSearch={setSearch}
onDeleteCalls={handleDeleteCalls}
revealed={revealed}
/>
<div className="rr">
<LiveCallPanel
Expand All @@ -220,6 +251,7 @@ export function App() {
setRecording={setRecording}
muted={muted}
setMuted={setMuted}
revealed={revealed}
/>
<MetricsPanel call={selected} />
</div>
Expand Down
Loading
Loading