Feature Bento Ai Copilot
blockfeatureAI agent copilot bento workbench with model tuning sliders, live inference streaming, and token speed telemetry.
Installation
$pnpm dlx uipkge-ng@latest add feature-bento-ai-copilot$npx uipkge-ng@latest add feature-bento-ai-copilot$yarn dlx uipkge-ng@latest add feature-bento-ai-copilot$bunx uipkge-ng@latest add feature-bento-ai-copilotManifest:
https://uipkge.dev/r/angular/feature-bento-ai-copilot.jsonInstalls to:src/app/components/blocks/feature-bento-ai-copilot/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
CopilotModelMetricsinterface CopilotModelMetrics {
name: string
ttftMs: number
tokPerSec: number
costPer1k: string
}npm dependencies
Files installed (2)
src/app/components/blocks/feature-bento-ai-copilot/feature-bento-ai-copilot.component.ts12.3 kB
// AI agent copilot bento workbench with model tuning sliders, live inference // streaming, and token speed telemetry. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, DestroyRef, Input, computed, inject, signal } from '@angular/core' import { Activity, ArrowRight, BrainCircuit, Check, Copy, Cpu, LucideAngularModule, Play, Sliders, Sparkles, Zap, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component' export type CopilotModel = 'sonnet' | 'gpt4o' | 'gemini' export interface CopilotModelMetrics { name: string ttftMs: number tokPerSec: number costPer1k: string } const models: { id: CopilotModel; label: string }[] = [ { id: 'sonnet', label: 'Sonnet 3.5' }, { id: 'gpt4o', label: 'GPT-4o' }, { id: 'gemini', label: 'Gemini Pro' }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-feature-bento-ai-copilot, [ui-feature-bento-ai-copilot]', standalone: true, // React renders the root <section> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardContentComponent], template: ` <section data-slot="feature-bento-ai-copilot" [class]="rootClass"> <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <!-- Section Header --> <div class="mx-auto max-w-3xl space-y-4 text-center"> <a href="#ai-copilot" class="group border-border/80 bg-secondary/60 hover:bg-secondary text-foreground inline-flex items-center gap-2 rounded-full border px-3.5 py-1 text-xs font-medium shadow-2xs transition-colors" > <lucide-icon [img]="Sparkles" class="text-primary size-3.5" /> <span>Next-Gen AI Agent Workbench</span> <lucide-icon [img]="ArrowRight" class="text-muted-foreground size-3 transition-transform group-hover:translate-x-0.5" /> </a> <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl">{{ title }}</h2> <p class="text-muted-foreground text-base sm:text-lg">{{ description }}</p> </div> <!-- Bento Grid (2 Cards) --> <div class="mt-12 grid grid-cols-1 gap-6 lg:grid-cols-12"> <!-- Left: Model Tuning & Hyperparameters (5 Cols) --> <div ui-card class="border-border bg-card/80 flex flex-col justify-between shadow-xs backdrop-blur-xs lg:col-span-5" > <div ui-card-content class="space-y-5 p-6"> <div class="border-border flex items-center justify-between border-b pb-3"> <div class="flex items-center gap-2"> <lucide-icon [img]="Sliders" class="text-primary size-4" /> <span class="text-foreground text-sm font-semibold">Inference Hyperparameters</span> </div> <span ui-badge variant="outline" class="border-border font-mono text-xs"> {{ modelMetrics().name }} </span> </div> <!-- Model Switcher --> <div class="space-y-2"> <label class="text-muted-foreground text-xs font-semibold tracking-wider uppercase"> Foundation Model </label> <div class="grid grid-cols-3 gap-2"> @for (model of models; track model.id) { <button type="button" [class]="modelButtonClass(model.id)" (click)="selectedModel.set(model.id)"> {{ model.label }} </button> } </div> </div> <!-- Temperature Slider --> <div class="space-y-2"> <div class="flex items-center justify-between text-xs"> <span class="text-foreground font-medium">Sampling Temperature</span> <span class="text-primary font-mono font-bold">{{ temperature() }}</span> </div> <input type="range" min="0" max="1" step="0.1" [value]="temperature()" (input)="setTemperature($event)" class="accent-primary w-full cursor-pointer" aria-label="Sampling temperature" /> <div class="text-muted-foreground flex justify-between text-xs"> <span>0.0 (Deterministic)</span> <span>1.0 (Creative)</span> </div> </div> <!-- System Prompt Input --> <div class="space-y-2"> <label class="text-muted-foreground text-xs font-semibold tracking-wider uppercase"> System Directive </label> <textarea rows="3" [value]="systemPrompt()" (input)="systemPrompt.set($any($event.target).value)" class="border-border bg-muted/30 text-foreground focus-visible:ring-primary w-full rounded-md border p-2.5 font-mono text-xs focus-visible:ring-1 focus-visible:outline-none" ></textarea> </div> <!-- Action Button --> <button ui-button class="w-full gap-2 shadow-xs" [disabled]="isGenerating()" (click)="triggerGeneration()" > @if (!isGenerating()) { <lucide-icon [img]="Play" class="size-3.5" /> } @else { <lucide-icon [img]="Zap" class="size-3.5 animate-spin" /> } <span>{{ isGenerating() ? 'Streaming Inference...' : 'Synthesize UI Primitive' }}</span> </button> </div> </div> <!-- Right: Streaming Code Output & Real-time Telemetry (7 Cols) --> <div ui-card class="border-border bg-card/80 flex flex-col justify-between shadow-xs backdrop-blur-xs lg:col-span-7" > <div ui-card-content class="space-y-4 p-6"> <!-- Output Header & Telemetry --> <div class="border-border flex flex-wrap items-center justify-between gap-3 border-b pb-3"> <div class="flex items-center gap-2"> <lucide-icon [img]="BrainCircuit" class="text-success size-4" /> <span class="text-foreground text-sm font-semibold">Live Streaming Synthesis</span> </div> <div class="flex items-center gap-2"> <button ui-button variant="ghost" size="sm" class="h-7 gap-1 px-2 font-mono text-xs" (click)="copyCode()" > @if (copied()) { <lucide-icon [img]="Check" class="text-primary size-3.5" /> } @else { <lucide-icon [img]="Copy" class="size-3.5" /> } <span>{{ copied() ? 'Copied' : 'Copy SFC' }}</span> </button> </div> </div> <!-- Telemetry KPI Pill Row --> <div class="border-border bg-muted/20 grid grid-cols-3 gap-3 rounded-lg border p-3"> <div class="space-y-0.5"> <div class="text-muted-foreground flex items-center gap-1 text-xs"> <lucide-icon [img]="Activity" class="text-success size-3" /> <span>TTFT</span> </div> <div class="text-foreground font-mono text-sm font-bold">{{ modelMetrics().ttftMs }}ms</div> </div> <div class="space-y-0.5"> <div class="text-muted-foreground flex items-center gap-1 text-xs"> <lucide-icon [img]="Cpu" class="text-info size-3" /> <span>Velocity</span> </div> <div class="text-foreground font-mono text-sm font-bold">{{ modelMetrics().tokPerSec }} tok/s</div> </div> <div class="space-y-0.5"> <div class="text-muted-foreground flex items-center gap-1 text-xs"> <lucide-icon [img]="Zap" class="text-primary size-3" /> <span>Cost</span> </div> <div class="text-foreground font-mono text-sm font-bold">{{ modelMetrics().costPer1k }}/1k</div> </div> </div> <!-- Code Sandbox Block --> <div class="border-border bg-muted/50 text-foreground relative overflow-x-auto rounded-lg border p-4 font-mono text-xs" > <pre class="leading-relaxed"><code>{{ generatedStream() }}</code></pre> </div> </div> </div> </div> </div> </section> `, }) export class UiFeatureBentoAiCopilotComponent { protected readonly Activity = Activity protected readonly ArrowRight = ArrowRight protected readonly BrainCircuit = BrainCircuit protected readonly Check = Check protected readonly Copy = Copy protected readonly Cpu = Cpu protected readonly Play = Play protected readonly Sliders = Sliders protected readonly Sparkles = Sparkles protected readonly Zap = Zap protected readonly models = models @Input() title = 'AI Copilot tooling built directly into your component architecture.' @Input() description = 'Debug prompts, inspect LLM token streaming speeds, and synthesize Vue 3.5 and React 19 templates in real-time with sub-millisecond local latency.' @Input('class') className?: string readonly selectedModel = signal<CopilotModel>('sonnet') readonly temperature = signal(0.2) readonly isGenerating = signal(false) readonly systemPrompt = signal( 'You are a senior UI design engineer. Generate an accessible, zero-dependency KPI metric card for Vue 3.5 and React 19 using semantic Tailwind v4 tokens.', ) readonly generatedStream = signal( `<template>\n <Card class="border-border bg-card p-4">\n <div class="text-xs text-muted-foreground">MRR Growth</div>\n <div class="text-2xl font-bold">$124,500</div>\n <div class="text-xs text-success font-medium">+18.4% vs last month</div>\n </Card>\n</template>`, ) readonly copied = signal(false) private copyTimer: ReturnType<typeof setTimeout> | undefined private generateTimer: ReturnType<typeof setTimeout> | undefined constructor() { inject(DestroyRef).onDestroy(() => { clearTimeout(this.copyTimer) clearTimeout(this.generateTimer) }) } readonly modelMetrics = computed<CopilotModelMetrics>(() => { if (this.selectedModel() === 'sonnet') { return { name: 'Claude 3.5 Sonnet', ttftMs: 180, tokPerSec: 142, costPer1k: '$0.003' } } if (this.selectedModel() === 'gpt4o') { return { name: 'GPT-4o Omnimodel', ttftMs: 140, tokPerSec: 165, costPer1k: '$0.0025' } } return { name: 'Gemini 1.5 Pro', ttftMs: 160, tokPerSec: 155, costPer1k: '$0.00125' } }) get rootClass(): string { return cn('bg-background relative overflow-hidden py-16 sm:py-24', this.className) } modelButtonClass(id: CopilotModel): string { return cn( 'rounded-lg border p-2 text-center text-xs font-medium transition-colors', this.selectedModel() === id ? 'border-primary bg-primary/10 text-primary font-semibold' : 'border-border bg-muted/40 text-muted-foreground hover:text-foreground', ) } setTemperature(event: Event): void { this.temperature.set(parseFloat((event.target as HTMLInputElement).value)) } async copyCode(): Promise<void> { try { await navigator.clipboard.writeText(this.generatedStream()) this.copied.set(true) clearTimeout(this.copyTimer) this.copyTimer = setTimeout(() => this.copied.set(false), 2000) } catch { // fallback } } triggerGeneration(): void { this.isGenerating.set(true) clearTimeout(this.generateTimer) this.generateTimer = setTimeout(() => this.isGenerating.set(false), 1200) } }src/app/components/blocks/feature-bento-ai-copilot/index.ts0.1 kB
export { UiFeatureBentoAiCopilotComponent, type CopilotModel, type CopilotModelMetrics, } from './feature-bento-ai-copilot.component'
Raw manifest:https://uipkge.dev/r/angular/feature-bento-ai-copilot.json