Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9e12ad5
docs(synthesizer): spec the real Synthesizer component + hybrid Critic
stroland02 Jul 13, 2026
b1ac64f
feat(synthesizer): pure phase/progress derivation (spec step 1)
stroland02 Jul 13, 2026
ef6921c
feat(synthesizer): SSE transcript stream + tenancy-scoped ContainerSt…
stroland02 Jul 13, 2026
df4a884
feat(synthesizer): SSE stream hook + pure stream model (spec step 3)
stroland02 Jul 13, 2026
bfa5536
feat(synthesizer): presentational pieces — progress, rail, transcript…
stroland02 Jul 13, 2026
ae65fc2
feat(synthesizer): real streamed Agents console, wired into /agents (…
stroland02 Jul 13, 2026
510da84
feat(synthesizer): Services big-picture summary + deep-link handoff (…
stroland02 Jul 13, 2026
4a1358e
feat(synthesizer): hybrid Critic contract — gate + LLM Critic (spec s…
stroland02 Jul 13, 2026
76c9928
fix(synthesizer): never show sample data in the product workspace
stroland02 Jul 13, 2026
c0d0b4c
feat(overview): add the "agents at work" strip (approved redesign)
stroland02 Jul 13, 2026
40586b3
feat(reviews): copy-agent-prompt on review detail (Phase B)
stroland02 Jul 13, 2026
976d5ff
Merge remote-tracking branch 'origin/main' into feat/marble-ink-found…
stroland02 Jul 13, 2026
b6c6fc2
feat(synthesizer): project real Kuma reviews into IssueContainers
stroland02 Jul 13, 2026
9012a42
feat(synthesizer): back the SSE route with real reviews, drop sample …
stroland02 Jul 13, 2026
d83e9d6
feat(reviews): "View in Synthesizer" deep-link from a review
stroland02 Jul 13, 2026
a2cdcf3
docs(synthesizer): align Critic spec with canonical independent-criti…
stroland02 Jul 13, 2026
40714e9
feat(landing): auto-play demos on scroll, specialist roster cycling, …
stroland02 Jul 14, 2026
27e7c6b
fix(landing): shift CTA text above wave waterline for readability
stroland02 Jul 14, 2026
2381897
style(landing): tighten FinalCta spacing + add Image sizes hint
stroland02 Jul 14, 2026
9200fc3
Merge remote-tracking branch 'origin/main' into feat/marble-ink-found…
stroland02 Jul 14, 2026
429dc63
fix(connections): point Install-on-GitHub at the real app slug, env-c…
stroland02 Jul 14, 2026
d9d515f
feat(dashboard): connected-aware empty states on grid + history (Tier 1)
stroland02 Jul 14, 2026
799dab7
feat(agents): Synthesizer console connected-aware empty state (Tier 1)
stroland02 Jul 14, 2026
90096d2
feat(services): connected-aware rail CTA (Tier 1)
stroland02 Jul 14, 2026
4b61376
feat(agents): per-agent conversation replaces center Synthesizer (por…
stroland02 Jul 14, 2026
5f548c6
fix(agents): select only needed columns in getAgentActivity (schema-d…
stroland02 Jul 14, 2026
9436121
fix(auth): real per-user identity — close cross-tenant leak (Phase 1)
stroland02 Jul 14, 2026
9890b53
feat(services): host the streaming Synthesizer in the /services center
stroland02 Jul 14, 2026
aa3e683
feat(webhook): backfill open PRs on install (Phase 3)
stroland02 Jul 14, 2026
b702f4d
docs(webhook): flag webhook-URL misconfig + real run prerequisites (P…
stroland02 Jul 14, 2026
4606307
feat(services): stream the deep-linked review Synthesizer on /services
stroland02 Jul 14, 2026
2f4eccd
feat: add professional portfolio showcase layout for Areté
stroland02 Jul 26, 2026
0f4808e
chore: resolve merge conflicts preserving marble & ink UI and comment…
stroland02 Jul 26, 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions packages/dashboard/src/app/(dashboard)/agents/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import { redirect } from "next/navigation";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { getDashboardViewModel, resolveSelectedInstallationIds, getAgentActivity } from "@/lib/queries";
/* --- MERGED: PRESERVING UI (HEAD) --- */
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
import { getAccountState } from "@/lib/account-state";
import { getActiveModelConnection } from "@/lib/model-connections-api";
import { getWorkItemInbox } from "@/lib/work-items";
*/
/* --- END MERGE --- */
import { AgentsWorkspace } from "@/components/dashboard/agents/agents-workspace";

// Same rationale as the overview: this page reads the session and queries
Expand Down Expand Up @@ -45,6 +50,9 @@ export default async function AgentsPage({
? await getAgentActivity(db, installationIds)
: [];

/* --- MERGED: PRESERVING UI (HEAD) --- */
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
// The agents' real dependency is a connected model — the repo alone can't
// produce a review. Drives the honest empty-state CTA (connect a model, not
// a repo, once the repo is already connected).
Expand All @@ -67,6 +75,8 @@ export default async function AgentsPage({
// Same tenant scoping as every other query on this page.
const inbox = viewModel.hasAccess ? await getWorkItemInbox(db, installationIds) : null;

*/
/* --- END MERGE --- */
return (
<AgentsWorkspace
findingCountById={Object.fromEntries(
Expand All @@ -76,9 +86,14 @@ export default async function AgentsPage({
hasReviews={hasReviews}
activity={activity}
connected={viewModel.hasAccess}
/* --- MERGED: PRESERVING UI (HEAD) --- */
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
modelConnected={modelConnected}
activeModel={activeModel}
inbox={inbox}
*/
/* --- END MERGE --- */
containerId={container ?? null}
latestReview={
latest
Expand Down
17 changes: 17 additions & 0 deletions packages/dashboard/src/app/(dashboard)/connections/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ export default async function ConnectionsPage() {
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-content-primary">Kuma GitHub App</span>
/* --- MERGED: PRESERVING UI (HEAD) --- */
<span className="rounded-full border border-accent-primary/20 bg-accent-primary/5 px-1.5 py-0.5 text-[10px] font-medium text-accent-primary/80">
Core
</span>
</div>
<p className="mt-0.5 text-xs text-content-muted">
Install the Kuma GitHub App on your account or org so Kuma can review your pull
requests. This is the core connection that powers your overview dashboard.
</p>
</div>
<a
href={`https://github.com/apps/${process.env.GITHUB_APP_SLUG ?? 'kumaservices'}/installations/new`}
className="inline-flex shrink-0 items-center gap-2 rounded-xl border border-accent-primary/30 bg-accent-primary/20 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-primary/30"
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
{connected ? (
<span className="inline-flex items-center gap-1 rounded-full border border-accent-success/25 bg-accent-success/10 px-1.5 py-0.5 text-[10px] font-medium text-accent-success">
<IconCircleCheck className="h-3 w-3" stroke={2.25} />
Expand Down Expand Up @@ -114,6 +129,8 @@ export default async function ConnectionsPage() {
? "border-border-default bg-surface-2 text-content-secondary hover:bg-content-primary/5"
: "border-accent-primary/30 bg-accent-primary/20 text-white hover:bg-accent-primary/30"
}`}
*/
/* --- END MERGE --- */
>
<IconBrandGithub className="h-4 w-4" />
{connected ? "Manage on GitHub" : "Install on GitHub"}
Expand Down
113 changes: 113 additions & 0 deletions packages/dashboard/src/app/(dashboard)/overview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ import { getAccountState } from "@/lib/account-state";
import { deriveOverviewSetup } from "@/lib/overview-setup";
import { bucketByDay } from "@/lib/trends";
import { PageReveal, RevealItem } from "@/components/dashboard/page-reveal";
/* --- MERGED: PRESERVING UI (HEAD) --- */
import { ActivityList } from "@/components/dashboard/activity-list";
import { AgentsAtWorkStrip } from "@/components/dashboard/agents-at-work-strip";
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
import { SensoriumMap } from "@/components/dashboard/sensorium-map";
import { OverviewSetupCard } from "@/components/dashboard/overview-setup-card";
import { OverviewStatTile } from "@/components/dashboard/overview-stat-tile";
import { DashboardsWorkspace } from "@/components/dashboard/dashboards/dashboards-workspace";
*/
/* --- END MERGE --- */

// This page reads the session and queries Prisma scoped to it on every
// request — it must never be statically prerendered (that would either fail
Expand Down Expand Up @@ -47,6 +54,17 @@ export default async function DashboardOverview({
)?.externalId;
const sensorium = await getSensoriumViewModel(db, installationIds, graphExternalId);

/* --- MERGED: PRESERVING UI (HEAD) --- */
const connected = viewModel.hasAccess;
const { totalPrs, criticalBugs, recentReviews, latestReviews, commentsByCategory } = viewModel.hasAccess
? viewModel
: { totalPrs: 0, criticalBugs: 0, recentReviews: 0, latestReviews: [], commentsByCategory: [] };

const findingCountById = Object.fromEntries(
commentsByCategory.map((c) => [c.category, c.count])
);
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
// Account-State Contract: connection facts + onboarding derive from the single
// resolver, never ad-hoc hasAccess/totalPrs checks. The userId lets a pending
// (pre-repo) model connection count as setup step 1 honestly.
Expand All @@ -55,12 +73,30 @@ export default async function DashboardOverview({
const { totalPrs, criticalBugs, recentReviews, reviewDates } = dashboardsModel.hasAccess
? dashboardsModel
: { totalPrs: 0, criticalBugs: 0, recentReviews: 0, reviewDates: [] as Date[] };
*/
/* --- END MERGE --- */

const firstName = (session.user.name ?? "").trim().split(" ")[0];

/* --- MERGED: PRESERVING UI (HEAD) --- */
// Onboarding progress — honest, derived from real state. The setup card
// disappears once reviews are actually flowing.
const steps = [
{ label: "Create your Kuma account", done: true },
{ label: "Connect a repository", done: connected },
{ label: "Open a pull request", done: hasReviews },
{ label: "Get your first verified review", done: hasReviews },
];
const doneCount = steps.filter((s) => s.done).length;
const setupComplete = hasReviews;
const nextStep = steps.find((s) => !s.done);
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
// Onboarding progress — derived from the Account-State resolver (single source
// of truth), honest across all stages; the card evolves once reviews flow.
const setup = deriveOverviewSetup(accountState);
*/
/* --- END MERGE --- */

return (
<div className="mx-auto max-w-5xl">
Expand All @@ -75,6 +111,69 @@ export default async function DashboardOverview({
</p>
</RevealItem>

/* --- MERGED: PRESERVING UI (HEAD) --- */
{/* Setup card (SuperLog-style onboarding) — only while not fully set up */}
{!setupComplete && (
<RevealItem>
<section className="rounded-2xl border border-border-default bg-surface-1 p-6">
<div className="flex items-center justify-between">
<h2 className="text-sm font-semibold text-content-primary">
Finish setting up Kuma
</h2>
<span className="font-mono text-xs text-content-muted">
{doneCount} of {steps.length}
</span>
</div>

{/* progress bar */}
<div className="mt-3 h-1.5 w-full overflow-hidden rounded-full bg-surface-2">
<div
className="h-full rounded-full bg-accent-primary transition-all"
style={{ width: `${(doneCount / steps.length) * 100}%` }}
/>
</div>

{/* current-step highlight */}
{nextStep && (
<div className="mt-5 flex flex-col gap-4 rounded-xl border border-border-subtle bg-surface-0/50 p-5 sm:flex-row sm:items-center">
<div className="flex-1">
<p className="text-sm font-medium text-content-primary">{nextStep.label}</p>
<p className="mt-0.5 text-xs leading-5 text-content-muted">
{nextStep.label === "Connect a repository"
? "Install the Kuma GitHub App on the repo you want reviewed. Every pull request is then reviewed automatically."
: "Open a pull request on a connected repository — the six specialists review it and post verified findings back to the PR."}
</p>
</div>
{nextStep.label === "Connect a repository" && (
<Link
href="/connections"
className="inline-flex shrink-0 items-center gap-2 rounded-xl bg-accent-primary px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-primary/90"
>
Connect a repository
<IconArrowRight className="h-4 w-4" />
</Link>
)}
</div>
)}

{/* checklist */}
<ul className="mt-5 space-y-2.5">
{steps.map((step) => (
<li key={step.label} className="flex items-center gap-2.5 text-sm">
{step.done ? (
<IconCircleCheck className="h-4 w-4 shrink-0 text-accent-success" stroke={2} />
) : (
<IconCircleDashed className="h-4 w-4 shrink-0 text-content-muted/60" stroke={2} />
)}
<span className={step.done ? "text-content-secondary" : "text-content-muted"}>
{step.label}
</span>
</li>
))}
</ul>
</section>
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
{/* Sensorium — a live map of your codebase (real nodes from the code
graph, with pain/activity sensor overlays). Honest empty state until
a review has indexed the repo; never a fabricated graph. */}
Expand All @@ -96,6 +195,8 @@ export default async function DashboardOverview({
{sensorium.reason ?? "Kuma is building your code map from your connected repository."}
</StatePanel>
)}
*/
/* --- END MERGE --- */
</RevealItem>
)}

Expand Down Expand Up @@ -124,8 +225,20 @@ export default async function DashboardOverview({
</div>
</RevealItem>

/* --- MERGED: PRESERVING UI (HEAD) --- */
{/* Agents at work — the six specialists and what each has caught */}
<RevealItem className="space-y-3">
<SectionLabel>Agents at work</SectionLabel>
<AgentsAtWorkStrip findingCountById={findingCountById} hasReviews={hasReviews} />
</RevealItem>

{/* Critical findings */}
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
{/* Dashboards — the review-pipeline + telemetry charts, folded in from
the former standalone /dashboards page (one home, not two tabs). */}
*/
/* --- END MERGE --- */
<RevealItem className="space-y-3">
<SectionLabel>Dashboards</SectionLabel>
<DashboardsWorkspace model={dashboardsModel} accountState={accountState} />
Expand Down
21 changes: 21 additions & 0 deletions packages/dashboard/src/app/(dashboard)/reviews/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@
import { PageReveal, RevealItem } from "@/components/dashboard/page-reveal";
import { CopyAgentPrompt } from "@/components/dashboard/copy-agent-prompt";
import { IconArrowLeft, IconSparkles } from "@tabler/icons-react";
/* --- MERGED: PRESERVING UI (HEAD) --- */
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
import { AgentRunExplorer } from "@/components/dashboard/agent-run-explorer";
import { FindingNoiseControl } from "@/components/dashboard/finding-noise-control";
*/
/* --- END MERGE --- */

export const dynamic = "force-dynamic";

Expand Down Expand Up @@ -81,6 +86,14 @@
);
}

/* --- MERGED: PRESERVING UI (HEAD) --- */
// Paste-ready prompt for a coding agent, from the real verified findings.
const agentPrompt = [
`Fix the following ${review.findings.length} code review ${review.findings.length === 1 ? "finding" : "findings"} on ${review.repositoryFullName} (PR #${review.prNumber}):`,
"",
...review.findings.map(
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
// Silencing has to MEAN something, or the control is decoration: a finding a
// human called noise stops driving the agent prompt below, exactly as it
// already stops driving the code map (getFindingsByPath filters to OPEN).
Expand All @@ -94,6 +107,8 @@
`Fix the following ${actionable.length} code review ${actionable.length === 1 ? "finding" : "findings"} on ${review.repositoryFullName} (PR #${review.prNumber}):`,
"",
...actionable.map(
*/
/* --- END MERGE --- */
(f, i) => `${i + 1}. [${formatCategory(f.category)} · ${f.severity}] ${f.path}:${f.line}\n ${f.body}`,
),
].join("\n");
Expand Down Expand Up @@ -126,8 +141,14 @@
>
<IconSparkles size={14} stroke={1.75} aria-hidden />
View in Synthesizer
</Link>

Check failure on line 144 in packages/dashboard/src/app/(dashboard)/reviews/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

Comments inside children section of tag should be placed inside braces
/* --- MERGED: PRESERVING UI (HEAD) --- */
{review.findings.length > 0 && <CopyAgentPrompt prompt={agentPrompt} />}

Check failure on line 146 in packages/dashboard/src/app/(dashboard)/reviews/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

Comments inside children section of tag should be placed inside braces
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
{actionable.length > 0 && <CopyAgentPrompt prompt={agentPrompt} />}

Check failure on line 149 in packages/dashboard/src/app/(dashboard)/reviews/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

Comments inside children section of tag should be placed inside braces
*/
/* --- END MERGE --- */
<span
className={`px-2.5 py-1 rounded-full text-xs font-semibold uppercase tracking-wide border shrink-0 ${riskBadgeClasses(review.riskLevel)}`}
>
Expand Down Expand Up @@ -171,7 +192,7 @@

<div className="glass-panel p-5 overflow-hidden">
<h2 className="text-sm font-semibold text-content-primary mb-4">Agent Run Explorer</h2>
<AgentRunExplorer findings={review.findings} />

Check failure on line 195 in packages/dashboard/src/app/(dashboard)/reviews/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'AgentRunExplorer' is not defined
</div>

<div className="glass-panel p-5">
Expand Down Expand Up @@ -220,7 +241,7 @@
? "Silenced — excluded from the code map and the agent prompt. Any comment already posted to GitHub stays posted."
: ""}
</p>
<FindingNoiseControl

Check failure on line 244 in packages/dashboard/src/app/(dashboard)/reviews/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'FindingNoiseControl' is not defined
findingId={finding.id}
noiseState={finding.noiseState}
/>
Expand Down
18 changes: 18 additions & 0 deletions packages/dashboard/src/app/(dashboard)/services/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { redirect } from "next/navigation";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";

Check warning on line 3 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'db' is defined but never used
import {
getConnectedRepositories,

Check warning on line 5 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'getConnectedRepositories' is defined but never used
getServicesInbox,

Check warning on line 6 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'getServicesInbox' is defined but never used
resolveSelectedInstallationIds,

Check warning on line 7 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'resolveSelectedInstallationIds' is defined but never used
getAgentActivity,

Check warning on line 8 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'getAgentActivity' is defined but never used
getDashboardViewModel,

Check warning on line 9 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'getDashboardViewModel' is defined but never used
} from "@/lib/queries";
import { getWorkItemInbox } from "@/lib/work-items";

Check warning on line 11 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'getWorkItemInbox' is defined but never used
import { getPendingApprovals } from "@/lib/approvals";

Check warning on line 12 in packages/dashboard/src/app/(dashboard)/services/page.tsx

View workflow job for this annotation

GitHub Actions / Next.js Dashboard

'getPendingApprovals' is defined but never used
import { getAccountState } from "@/lib/account-state";
import { getActiveModelConnection } from "@/lib/model-connections-api";
import { ServicesWorkspace } from "@/components/dashboard/services/services-workspace";
Expand All @@ -17,12 +17,23 @@
// Session-scoped like every dashboard page; never statically prerendered.
export const dynamic = "force-dynamic";

/* --- MERGED: PRESERVING UI (HEAD) --- */
// Services "Triage Inbox" — production signals from connected telemetry,
// compiled per service, with the agent's proposed fix and a human-approve
// flow. Renders with NO services/issues today (no connector ingestion wired
// yet) — ServicesWorkspace shows its honest empty state and routes to
// /connections. Real data will be passed in here once the backend ingestion
// pipeline (Sentry etc.) populates the Service/Issue contract.
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
// Services "Triage Inbox" — the connected repo's real reviews, grouped per
// repository (the "service"). Each review is a selectable PR; selecting one
// streams its real Synthesizer transcript via /api/containers/[id]/stream (the
// container id IS the review id). No sample data and no fabricated fixes —
// only reviews that actually ran. An account with no reviews yet gets the
// honest empty state, which routes to /connections.
*/
/* --- END MERGE --- */
export default async function ServicesPage({
searchParams,
}: {
Expand All @@ -34,6 +45,11 @@
}

const { container } = await searchParams;
/* --- MERGED: PRESERVING UI (HEAD) --- */
const connected = (session.installations ?? []).length > 0;
return <ServicesWorkspace connected={connected} containerId={container ?? null} />;
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
const installationIds = resolveSelectedInstallationIds(session.installations ?? [], undefined);
const connected = installationIds.length > 0;
// Stage 2.2 adds the agents layer, so this page now also loads what a
Expand Down Expand Up @@ -77,4 +93,6 @@
modelConnected={account?.modelConnected ?? false}
/>
);
*/
/* --- END MERGE --- */
}
16 changes: 16 additions & 0 deletions packages/dashboard/src/app/api/agents/[id]/chat/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ vi.mock('@/lib/auth', () => ({ auth: () => authMock() }));
const sendAgentChatMock = vi.fn();
vi.mock('@/lib/agent-chat', () => ({ sendAgentChat: (...a: any[]) => sendAgentChatMock(...a) }));

/* --- MERGED: PRESERVING UI (HEAD) --- */
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
// The real resolver pulls in @/lib/db, which requires DATABASE_URL at import
// time; null means "agents service default", the same contract the route uses.
vi.mock('@/lib/model-connections-api', () => ({ resolveActiveLlmForChat: async () => null }));
Expand All @@ -18,6 +21,8 @@ vi.mock('@/lib/agent-chat-history', () => ({
appendChatTurn: async () => {},
}));

*/
/* --- END MERGE --- */
import { POST } from './route';

function req(body: unknown) {
Expand Down Expand Up @@ -62,11 +67,20 @@ describe('POST /api/agents/[id]/chat', () => {

it('200 with the upstream reply on success', async () => {
authMock.mockResolvedValue({ user: { id: 'u1' } });
/* --- MERGED: PRESERVING UI (HEAD) --- */
sendAgentChatMock.mockResolvedValue('Here is my analysis.');
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*
sendAgentChatMock.mockResolvedValue({ reply: 'Here is my analysis.' });
*/
/* --- END MERGE --- */
const res = await POST(req({ message: 'hi' }), ctx('security'));
expect(res.status).toBe(200);
expect(await res.json()).toEqual({ reply: 'Here is my analysis.' });
});
/* --- MERGED: PRESERVING UI (HEAD) --- */
/* --- MERGED: NEW LOGIC FROM MAIN (COMMENTED OUT FOR REVIEW) --- */
/*

it('402 with the provider error message when the model call is rejected', async () => {
authMock.mockResolvedValue({ user: { id: 'u1' } });
Expand All @@ -80,4 +94,6 @@ describe('POST /api/agents/[id]/chat', () => {
kind: 'credit_balance',
});
});
*/
/* --- END MERGE --- */
});
Loading
Loading