Skip to main content

ngx-ai-devtools-angular-llm-debugger

Floating DevTools panel for intercepting and debugging OpenAI, Anthropic, Gemini, Mistral, Groq, and Cohere API calls in Angular apps with cost tracking and streaming support

Jump to install

Source facts

Repository
reason-machines/devtools-skills
Last source activity
June 17, 2026 at 17:08
Detected SKILL.md language
English
Stars
4
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
ngx-ai-devtools-angular-llm-debugger
description
Floating DevTools panel for intercepting and debugging OpenAI, Anthropic, Gemini, Mistral, Groq, and Cohere API calls in Angular apps with cost tracking and streaming support
triggers
["add AI devtools to my Angular app","debug LLM calls in Angular","track OpenAI API costs in development","intercept Anthropic requests in my app","show me AI API tokens and costs","set up ngx-ai-devtools","monitor streaming AI responses","replay LLM calls in Angular"]
# ngx-ai-devtools Angular LLM Debugger > Skill by [ara.so](https://ara.so) — Devtools Skills collection. Network-tab-style DevTools for debugging LLM API calls in Angular applications. Intercepts and displays prompts, responses, token counts, costs, and streaming data for OpenAI, Anthropic, Google Gemini, Mistral, Groq, and Cohere — all without leaving the browser. ## What It Does `ngx-ai-devtools` automatically intercepts all LLM API calls made from your Angular app (via `fetch`, `HttpClient`, or official SDKs) and displays them in a floating DevTools panel. It: - Auto-detects provider (OpenAI, Anthropic, Gemini, etc.) and parses request/response - Calculates cost per call using embedded pricing tables - Handles Server-Sent Events (SSE) streaming with delta accumulation - Shows tool/function calls with arguments - Provides one-click replay functionality - Tracks time-to-first-token and running session totals - Persists history across reloads (optional) - Works with any SDK or raw `fetch` calls ## Installation ```bash npm install ngx-ai-devtools ``` **Requirements:** Angular 18.1+ (uses signals, standalone components, `@let` syntax) ## Basic Setup Add `provideAiDevtools()` to your application config: ```typescript // app.config.ts import { ApplicationConfig } from '@angular/core'; import { provideAiDevtools } from 'ngx-ai-devtools'; import { environment } from './environments/environment'; export const appConfig: ApplicationConfig = { providers: [ provideAiDevtools({ enabled: !environment.production, // Disable in production }), ], }; ``` A floating launcher pill appears in the bottom-right corner. All LLM calls are now intercepted and displayed. ## Configuration Options All options are optional. Pass them to `provideAiDevtools()`: ```typescript provideAiDevtools({ // When false, no patching or UI overhead enabled: !environment.production, // Maximum calls retained in memory (FIFO) maxCalls: 200, // Persist call history to localStorage across reloads persist: true, // Launcher position on screen position: 'bottom-left', // 'bottom-right' | 'top-right' | 'top-left' // Hide request/response bodies in UI (still recorded) redact: false, // Auto-inject UI into document.body autoMount: true, // Additional URL patterns to treat as LLM endpoints (for proxies/custom gateways) additionalEndpoints: [ '/api/llm-proxy', '/v1/internal-gateway', 'custom-llm.example.com' ], }); ``` ## Usage with Different SDKs ### OpenAI SDK ```typescript import OpenAI from 'openai'; import { Component } from '@angular/core'; @Component({ selector: 'app-chat', template: `<button (click)="sendMessage()">Send</button>`, }) export class ChatComponent { private openai = new OpenAI({ apiKey: process.env['OPENAI_API_KEY'], dangerouslyAllowBrowser: true, // Only for dev/demo }); async sendMessage() { const completion = await this.openai.chat.completions.create({ model: 'gpt-4o', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain quantum computing in simple terms' } ], temperature: 0.7, }); console.log(completion.choices[0].message.content); // Call automatically appears in ngx-ai-devtools panel } } ``` ### Streaming with OpenAI ```typescript async streamResponse() { const stream = await this.openai.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: 'Count to 10' }], stream: true, // Enable streaming }); for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content || ''; console.log(content); // Deltas accumulate in real-time in the devtools panel } } ``` ### Anthropic SDK ```typescript import Anthropic from '@anthropic-ai/sdk'; @Component({ selector: 'app-claude', template: `<button (click)="askClaude()">Ask Claude</button>`, }) export class ClaudeComponent { private anthropic = new Anthropic({ apiKey: process.env['ANTHROPIC_API_KEY'], }); async askClaude() { const message = await this.anthropic.messages.create({ model: 'claude-sonnet-4-20250514', max_tokens: 1024, messages: [ { role: 'user', content: 'Write a haiku about TypeScript' } ], }); console.log(message.content[0].text); } } ``` ### Angular HttpClient (Raw API Calls) ```typescript import { HttpClient, HttpHeaders } from '@angular/common/http'; import { inject, Component } from '@angular/core'; @Component({ selector: 'app-gemini', template: `<button (click)="callGemini()">Call Gemini</button>`, }) export class GeminiComponent { private http = inject(HttpClient); callGemini() { const headers = new HttpHeaders({ 'Content-Type': 'application/json', }); const body = { contents: [{ parts: [{ text: 'Explain the theory of relativity' }] }] }; this.http.post( `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key=${process.env['GEMINI_API_KEY']}`, body, { headers } ).subscribe(response => { console.log(response); // Appears in devtools automatically }); } } ``` ### Raw Fetch (Works Anywhere) ```typescript async callMistral() { const response = await fetch('https://api.mistral.ai/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env['MISTRAL_API_KEY']}` }, body: JSON.stringify({ model: 'mistral-large-latest', messages: [{ role: 'user', content: 'Hello!' }] }) }); const data = await response.json(); console.log(data); // Intercepted and displayed in devtools } ``` ## Programmatic API Access the devtools service directly in your components: ```typescript import { Component, computed, inject } from '@angular/core'; import { AiDevtoolsService } from 'ngx-ai-devtools'; @Component({ selector: 'app-cost-dashboard', template: ` <div class="stats"> <div>Total Calls: {{ stats().count }}</div> <div>Total Cost: ${{ stats().totalCost | number:'1.4-4' }}</div> <div>Total Tokens: {{ stats().totalTokens | number }}</div> <div>Avg Latency: {{ stats().avgLatency }}ms</div> </div> <button (click)="clearHistory()">Clear History</button> <button (click)="togglePanel()">Toggle Panel</button> @if (selectedCall()) { <div>Selected: {{ selectedCall()?.model }}</div> } `, }) export class CostDashboard { private devtools = inject(AiDevtoolsService); // Signal-based reactive state stats = computed(() => this.devtools.stats()); calls = this.devtools.calls; selectedCall = this.devtools.selected; clearHistory() { this.devtools.clear(); } togglePanel() { const currentState = this.devtools.ui().open; this.devtools.setOpen(!currentState); } } ``` ### Service API Reference | Member | Type | Description | |--------|------|-------------| | `calls` | `Signal<LlmCall[]>` | All recorded calls, newest first | | `filtered` | `Signal<LlmCall[]>` | Filtered view matching search | | `selected` | `Signal<LlmCall \| null>` | Currently selected call | | `stats` | `Signal<Stats>` | `{ count, totalCost, totalTokens, avgLatency }` | | `ui` | `Signal<UiState>` | `{ open, selectedId, filter }` | | `clear()` | `() => void` | Drop all recorded calls | | `setOpen(boolean)` | `(boolean) => void` | Open/close panel | | `select(id)` | `(string \| null) => void` | Select a call by ID | | `setFilter(string)` | `(string) => void` | Set search filter | | `replay(id)` | `(string) => Promise<string \| null>` | Re-issue a call | ## Common Patterns ### Budget Alerts ```typescript import { Component, effect, inject } from '@angular/core'; import { AiDevtoolsService } from 'ngx-ai-devtools'; @Component({ selector: 'app-budget-monitor', template: `<div>Session cost: ${{ currentCost() }}</div>`, }) export class BudgetMonitor { private devtools = inject(AiDevtoolsService); private readonly BUDGET_LIMIT = 5.00; // $5 limit currentCost = this.devtools.stats().totalCost; constructor() { effect(() => { const cost = this.devtools.stats().totalCost; if (cost > this.BUDGET_LIMIT) { console.warn(`⚠️ Budget exceeded: $${cost.toFixed(4)}`); // Disable AI features, show warning, etc. } }); } } ``` ### Call Replay for Testing ```typescript async testPromptVariation(callId: string) { // Replay exact same request const newCallId = await this.devtools.replay(callId); if (newCallId) { console.log('Replayed call ID:', newCallId); // Compare results in the UI } } ``` ### Filter Calls Programmatically ```typescript searchForExpensiveCalls() { this.devtools.setFilter('gpt-4'); // Show only GPT-4 calls } showOnlyErrors() { const errorCalls = this.devtools.calls().filter(call => call.error); console.log('Failed calls:', errorCalls); } ``` ### Custom Component Integration If `autoMount: false`, manually place the component: ```typescript // app.config.ts provideAiDevtools({ enabled: true, autoMount: false, // Manual placement }); // app.component.ts import { Component } from '@angular/core'; import { NgxAiDevtoolsComponent } from 'ngx-ai-devtools'; @Component({ selector: 'app-root', standalone: true, imports: [NgxAiDevtoolsComponent], template: ` <main> <!-- Your app content --> </main> <!-- Devtools in custom position --> <ngx-ai-devtools /> `, }) export class AppComponent {} ``` ## Tool/Function Calling The devtools automatically parse and display function calls: ```typescript const completion = await this.openai.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: 'What is the weather in Paris?' }], tools: [ { type: 'function', function: { name: 'get_weather', description: 'Get current weather for a location', parameters: { type: 'object', properties: { location: { type: 'string', description: 'City name' }, unit: { type: 'string', enum: ['celsius', 'fahrenheit'] } }, required: ['location'] } } } ], }); // Tool calls appear in dedicated "Tool Use" tab in the panel ``` ## Provider Support
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub