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
3 changes: 2 additions & 1 deletion examples/audiobook-curator/src/cli/library-audit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Agent, agent } from '@agent-bundle/runtime';
import { z } from 'zod';

import { CuratorDocument } from '../components/curator-document.js';
import { libraryAuditCliHeadline } from '../components/headlines.js';
import { LibraryAnalysis } from '../components/library-analysis.js';
import { DataList } from '../components/primitives.js';
import type { LibraryAuditReceipt } from '../library.js';
Expand Down Expand Up @@ -45,7 +46,7 @@ export default async function LibraryAudit({ input, signal }: CliRouteProps<type
summary.missingChapters + summary.missingTitle + summary.probeFailures;
return (
<CuratorDocument
headline={`Audited ${String(summary.files)} files (${String(summary.bytes)} bytes) across ${String(total)} sources.`}
headline={libraryAuditCliHeadline(receipt, total)}
receipt={receipt}
>
<Agent.Markdown>## Library audit</Agent.Markdown>
Expand Down
8 changes: 7 additions & 1 deletion examples/audiobook-curator/src/components/headlines.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import type { AudibleSearchReceipt } from '../audible.ts';
import type { ConvertReceipt } from '../conversion.ts';
import type { IntegrityAuditReceipt } from '../integrity-audit.ts';
import type { InventoryReceipt, SelectionReceipt } from '../library.ts';
import type { InventoryReceipt, LibraryAuditReceipt, SelectionReceipt } from '../library.ts';

export const inventoryHeadline = (receipt: InventoryReceipt): string =>
`Inventoried ${receipt.summary.files} media files with ${receipt.summary.errors} retained errors.`;

export const libraryAuditHeadline = (receipt: LibraryAuditReceipt): string =>
`Audited ${receipt.summary.files} library media files and found ${receipt.duplicateCandidates.length} duplicate candidate groups.`;

export const libraryAuditCliHeadline = (receipt: LibraryAuditReceipt, sourceCount: number): string =>
`Audited ${String(receipt.summary.files)} files (${String(receipt.summary.bytes)} bytes) across ${String(sourceCount)} sources.`;

export const selectionHeadline = (receipt: SelectionReceipt): string => {
const reviewCount = receipt.selections.filter((selection) => selection.reviewRequired).length;
return `Selected ${receipt.selections.length} source groups; ${reviewCount} require review.`;
Expand Down
24 changes: 17 additions & 7 deletions examples/audiobook-curator/src/components/library-shelf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ export interface AuditShelfProps {
readonly receipt: LibraryAuditReceipt;
}

export const AuditShelf = ({ receipt }: AuditShelfProps) => {
const summaryFields: Field[] = [
export const AuditSummary = ({ receipt }: AuditShelfProps) => {
const fields: Field[] = [
{ label: 'Files', value: receipt.summary.files },
{ label: 'Total bytes', value: receipt.summary.bytes },
{ label: 'Missing album', value: receipt.summary.missingAlbum },
Expand All @@ -74,13 +74,23 @@ export const AuditShelf = ({ receipt }: AuditShelfProps) => {
{ label: 'Missing title', value: receipt.summary.missingTitle },
{ label: 'Probe failures', value: receipt.summary.probeFailures },
];
return <DataList fields={fields} />;
};

export const AuditFileCards = ({ receipt }: AuditShelfProps) => (
<>
{receipt.files.slice(0, maximumCards).map((file) => (
<FileCard {...fileCardModel(file)} key={file.path} />
))}
<RemainingFiles count={receipt.files.length} />
</>
);

export const AuditShelf = ({ receipt }: AuditShelfProps) => {
return (
<>
<DataList fields={summaryFields} />
{receipt.files.slice(0, maximumCards).map((file) => (
<FileCard {...fileCardModel(file)} key={file.path} />
))}
<RemainingFiles count={receipt.files.length} />
<AuditSummary receipt={receipt} />
<AuditFileCards receipt={receipt} />
{receipt.duplicateCandidates.slice(0, 10).map((group) => (
<CandidateGroupCallout
files={group.files}
Expand Down
25 changes: 5 additions & 20 deletions examples/audiobook-curator/src/mcp/curator/tools/audit_library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import { Agent, agent } from '@agent-bundle/runtime';
import React, { Suspense } from 'react';
import type { ToolRouteProps } from 'agent-bundle';

import { FileCard } from '../../../components/audiobook-card.js';
import { CuratorDocument } from '../../../components/curator-document.js';
import { libraryAuditHeadline } from '../../../components/headlines.js';
import { LibraryAnalysis } from '../../../components/library-analysis.js';
import { DataList } from '../../../components/primitives.js';
import { fileCardModel } from '../../../components/view-models.js';
import { AuditFileCards, AuditSummary } from '../../../components/library-shelf.js';
import type { LibraryAuditReceipt } from '../../../library.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../../../operations/discovery.js';

Expand All @@ -30,25 +29,11 @@ export default async function Route({ input, signal }: ToolRouteProps<typeof inp
});
return (
<CuratorDocument
headline={`Audited ${receipt.summary.files} library media files and found ${receipt.duplicateCandidates.length} duplicate candidate groups.`}
headline={libraryAuditHeadline(receipt)}
receipt={receipt}
>
<DataList fields={[
{ label: 'Files', value: receipt.summary.files },
{ label: 'Total bytes', value: receipt.summary.bytes },
{ label: 'Missing album', value: receipt.summary.missingAlbum },
{ label: 'Missing artwork', value: receipt.summary.missingArtwork },
{ label: 'Missing author', value: receipt.summary.missingAuthor },
{ label: 'Missing chapters', value: receipt.summary.missingChapters },
{ label: 'Missing title', value: receipt.summary.missingTitle },
{ label: 'Probe failures', value: receipt.summary.probeFailures },
]} />
{receipt.files.slice(0, 20).map((file) => (
<FileCard {...fileCardModel(file)} key={file.path} />
))}
{receipt.files.length > 20
? <Agent.Markdown>{`_+${String(receipt.files.length - 20)} more files retained in the structured receipt._`}</Agent.Markdown>
: null}
<AuditSummary receipt={receipt} />
<AuditFileCards receipt={receipt} />
<Suspense fallback={<Agent.Progress completed={0} message="Analyzing duplicate and multipart groups" />}>
<LibraryAnalysis receipt={receipt} signal={signal} />
</Suspense>
Expand Down
Loading