{"id":51377195,"url":"https://github.com/ahmedkhan1/ngx-ai-devtools","last_synced_at":"2026-07-04T07:34:04.894Z","repository":{"id":365037702,"uuid":"1270236733","full_name":"ahmedkhan1/ngx-ai-devtools","owner":"ahmedkhan1","description":"Floating DevTools panel that intercepts OpenAI, Anthropic, Gemini, Mistral, Groq, and Cohere calls in your Angular app and shows you the prompt, response, tokens, cost, and tool use.","archived":false,"fork":false,"pushed_at":"2026-06-15T15:23:42.000Z","size":1453,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T16:29:12.379Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ahmedkhan1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-15T14:13:49.000Z","updated_at":"2026-06-15T15:27:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ahmedkhan1/ngx-ai-devtools","commit_stats":null,"previous_names":["ahmedkhan1/ngx-ai-devtools"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ahmedkhan1/ngx-ai-devtools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedkhan1%2Fngx-ai-devtools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedkhan1%2Fngx-ai-devtools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedkhan1%2Fngx-ai-devtools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedkhan1%2Fngx-ai-devtools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ahmedkhan1","download_url":"https://codeload.github.com/ahmedkhan1/ngx-ai-devtools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedkhan1%2Fngx-ai-devtools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35114172,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-03T14:00:27.941Z","updated_at":"2026-07-04T07:34:04.882Z","avatar_url":"https://github.com/ahmedkhan1.png","language":"TypeScript","funding_links":[],"categories":["Development Utilities"],"sub_categories":["AI"],"readme":"# ngx-ai-devtools\n\n\u003e Network-tab-style DevTools for LLM calls in Angular apps. See every prompt, response, token, and dollar your app spends — without leaving the browser.\n\n[![npm](https://img.shields.io/npm/v/ngx-ai-devtools.svg?style=flat-square\u0026color=f5a524)](https://www.npmjs.com/package/ngx-ai-devtools)\n[![license](https://img.shields.io/npm/l/ngx-ai-devtools.svg?style=flat-square)](LICENSE)\n[![Angular](https://img.shields.io/badge/Angular-18.1%2B-DD0031.svg?style=flat-square)](https://angular.dev)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/ngx-ai-devtools?style=flat-square\u0026color=4ade80)](https://bundlephobia.com/package/ngx-ai-devtools)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ahmedkhan1/ngx-ai-devtools/main/docs/screenshot.png\" alt=\"ngx-ai-devtools panel showing intercepted OpenAI, Anthropic, and Gemini calls with cost, tokens, and tool-use details\" width=\"100%\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ngx-ai-devtools.vercel.app/\"\u003e\u003cstrong\u003e→ Try the live demo\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA floating DevTools panel that intercepts every LLM call your Angular app makes — fetch, HttpClient, OpenAI SDK, Anthropic SDK, anything. Shows the prompt, response, tokens, cost, tool calls, and streaming deltas in real time. One provider call to install. Works in dev, staging, and production behind a feature flag.\n\n---\n\n## Install\n\n```bash\nnpm install ngx-ai-devtools\n```\n\nRequires **Angular 18.1+** (signals, standalone components, `@let`).\n\n---\n\n## Setup in 3 steps\n\n### Step 1 — Add the provider\n\n```ts\n// app.config.ts\nimport { ApplicationConfig } from '@angular/core';\nimport { provideAiDevtools } from 'ngx-ai-devtools';\nimport { environment } from './environments/environment';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideAiDevtools({\n      enabled: !environment.production,\n    }),\n  ],\n};\n```\n\n### Step 2 — Run your app\n\nA floating launcher pill appears in the bottom-right corner. That's it.\n\n### Step 3 — ⚠️ If your app uses a backend proxy, you MUST configure it\n\n**This is the most important step. Most Angular apps don't call OpenAI/Anthropic/Google directly from the browser** — they go through a backend like `/api/chat`. The library doesn't know about your custom paths until you tell it:\n\n```ts\nprovideAiDevtools({\n  enabled: !environment.production,\n  additionalEndpoints: [\n    { path: '/api/chat', provider: 'anthropic' },\n    { path: '/api/stream', provider: 'openai' },\n  ],\n});\n```\n\nIf you skip this step, your calls go through but **nothing shows up in the panel**. The library only intercepts URLs it recognizes.\n\nThe `provider` field tells the library which response shape to parse. Supported values: `'openai'`, `'anthropic'`, `'google'`, `'mistral'`, `'groq'`, `'cohere'`.\n\n**No route renames required.** Your existing paths stay exactly as they are.\n\nIf you'd rather keep the old string form (and your URL contains a provider keyword like `/api/anthropic/...`), that still works for backward compatibility.\n\nIf you call OpenAI/Anthropic/Google directly from the browser (no proxy), you can skip Step 3 — those URLs are auto-detected.\n\n---\n\n## Backend requirements for cost calculation\n\nThe library reads token counts from the provider's `usage` block. **If your backend strips or reshapes the response, tokens and cost will be blank in the panel.** The call, prompt, response, and latency still show — but cost depends on the provider's `usage` block surviving the round trip.\n\nYour backend must forward these fields untouched:\n\n| Provider | Required fields |\n|---|---|\n| OpenAI | `model`, `choices[0].message`, `choices[0].finish_reason`, `usage` |\n| Anthropic | `model`, `content`, `stop_reason`, `usage` |\n| Google | `candidates`, `usageMetadata` |\n\nThe simplest pattern is to forward the provider response untouched:\n\n```ts\n// Express / Node backend\napp.post('/api/openai/chat', async (req, res) =\u003e {\n  const upstream = await fetch('https://api.openai.com/v1/chat/completions', {\n    method: 'POST',\n    headers: { Authorization: `Bearer ${process.env.OPENAI_KEY}` },\n    body: JSON.stringify(req.body),\n  });\n  res.json(await upstream.json());  // ← forward as-is\n});\n```\n\n### OpenAI streaming gotcha\n\nBy default, OpenAI's **streaming** responses omit the `usage` block. Text streams correctly, but token counts and cost never arrive. To get usage on streams, pass `stream_options` in the request:\n\n```ts\n{\n  model: 'gpt-4o-mini',\n  stream: true,\n  stream_options: { include_usage: true },  // ← required for token counts on streams\n  messages: [...]\n}\n```\n\nAnthropic and Google include usage on streaming responses by default.\n\n---\n\n## All configuration options\n\n| Option | Type | Default | What it does |\n|---|---|---|---|\n| `enabled` | `boolean` | `true` | When `false`, no patching, no UI, no overhead. Gate on `!environment.production`. |\n| `additionalEndpoints` | `string[]` | `[]` | URL substrings to treat as LLM endpoints. Required for proxy/custom backends. |\n| `maxCalls` | `number` | `100` | Maximum calls retained in memory. Older drop FIFO. |\n| `persist` | `boolean` | `false` | Persist call history to `localStorage` across reloads. |\n| `autoMount` | `boolean` | `true` | Auto-inject the UI into `document.body`. Set `false` to place `\u003cngx-ai-devtools /\u003e` manually. |\n| `position` | `'bottom-right' \\| 'bottom-left' \\| 'top-right' \\| 'top-left'` | `'bottom-right'` | Launcher position. |\n| `redact` | `boolean` | `false` | Hide request/response bodies in the UI (still recorded). Useful for screenshots. |\n\nFull example:\n\n```ts\nprovideAiDevtools({\n  enabled: !environment.production,\n  additionalEndpoints: ['/api/openai', '/api/anthropic'],\n  maxCalls: 200,\n  persist: true,\n  position: 'bottom-left',\n  redact: false,\n});\n```\n\n---\n\n## Usage examples\n\n```ts\n// OpenAI SDK\nimport OpenAI from 'openai';\nconst openai = new OpenAI({ baseURL: '/api/openai', apiKey: 'unused' });\nawait openai.chat.completions.create({\n  model: 'gpt-4o',\n  messages: [{ role: 'user', content: 'Hello' }],\n});\n\n// Anthropic SDK\nimport Anthropic from '@anthropic-ai/sdk';\nconst anthropic = new Anthropic({ baseURL: '/api/anthropic', apiKey: 'unused' });\nawait anthropic.messages.create({\n  model: 'claude-sonnet-4-5',\n  max_tokens: 1024,\n  messages: [{ role: 'user', content: 'Hello' }],\n});\n\n// Raw fetch\nawait fetch('/api/openai/chat', {\n  method: 'POST',\n  body: JSON.stringify({ model: 'gpt-4o-mini', messages: [...] }),\n});\n\n// Angular HttpClient\nthis.http.post('/api/anthropic/messages', payload).subscribe();\n```\n\nAll of these get intercepted automatically once the path is in `additionalEndpoints`.\n\n---\n\n## Programmatic API\n\nThe store is a public signal-based service. Use it in your own components, dashboards, or budget alerts.\n\n```ts\nimport { Component, computed, inject } from '@angular/core';\nimport { AiDevtoolsService } from 'ngx-ai-devtools';\n\n@Component({\n  selector: 'app-cost-badge',\n  template: `\u003cspan\u003eSpent today: ${{ totalCost() | number:'1.4-4' }}\u003c/span\u003e`,\n})\nexport class CostBadge {\n  private svc = inject(AiDevtoolsService);\n  totalCost = computed(() =\u003e this.svc.stats().totalCost);\n}\n```\n\nThe service exposes:\n\n| Member | Type | Purpose |\n|---|---|---|\n| `calls` | `Signal\u003cLlmCall[]\u003e` | All recorded calls, newest first. |\n| `filtered` | `Signal\u003cLlmCall[]\u003e` | Current filtered view (matches the search box). |\n| `selected` | `Signal\u003cLlmCall \\| null\u003e` | Currently selected call in the detail pane. |\n| `stats` | `Signal\u003c{ count, totalCost, totalTokens, avgLatency }\u003e` | Running aggregates over the call list. |\n| `ui` | `Signal\u003c{ open, selectedId, filter }\u003e` | UI state of the panel. |\n| `clear()` | `() =\u003e void` | Drop all calls. |\n| `setOpen(b)` | `(boolean) =\u003e void` | Open or close the panel. |\n| `select(id)` | `(string \\| null) =\u003e void` | Select a call programmatically. |\n| `setFilter(s)` | `(string) =\u003e void` | Set the search filter. |\n| `replay(id)` | `(string) =\u003e Promise\u003cstring \\| null\u003e` | Re-issue a recorded call. |\n\nAll call records conform to the `LlmCall` type, exported from the package root.\n\n---\n\n## Provider support\n\n| Provider | Request parsing | Response parsing | Streaming | Cost |\n|---|---|---|---|---|\n| OpenAI | ✅ | ✅ | ✅ SSE deltas | ✅ |\n| Anthropic | ✅ | ✅ | ✅ named events + JSON deltas | ✅ |\n| Google Gemini | ✅ | ✅ | partial | ✅ |\n| Mistral | ✅ (OpenAI shape) | ✅ | ✅ | ✅ |\n| Groq | ✅ (OpenAI shape) | ✅ | ✅ | ✅ |\n| Cohere | detected only | partial | — | — |\n\nPricing data is in `src/lib/pricing.ts` and ships with current rates for the major models. If a model isn't in the table, the call still records — cost just stays blank rather than guessing. PRs welcome to keep prices fresh.\n\n---\n\n## How it works\n\nAt bootstrap, the library monkey-patches `window.fetch`. Calls to any URL matching a known provider (or your `additionalEndpoints`) are recorded into a signal store; everything else passes through untouched. For streaming responses, the body is `tee()`'d so the consumer still receives the original stream while the devtools consume a copy, parsing SSE events as they arrive.\n\nThe library doesn't tokenize anything itself. Token counts come from the provider's `usage` block (`prompt_tokens` / `completion_tokens` for OpenAI, `input_tokens` / `output_tokens` for Anthropic, `usageMetadata` for Google). Cost is `tokens × price_per_million / 1_000_000` against the local price table. If `usage` is missing, tokens and cost stay blank rather than guessing.\n\nThe UI mounts itself into `document.body` (or anywhere you place `\u003cngx-ai-devtools /\u003e`) and renders directly from the signal store with `OnPush` change detection. No global state library, no zone.js dependency, no extra runtime. In production builds where `enabled: false`, neither the patch nor the UI is installed.\n\n---\n\n## Demos\n\nTwo runnable demos ship in this repo. Use whichever fits your needs.\n\n### Mock demo — `projects/demo/`\n\nSimulated LLM calls with canned responses. **No API keys, no setup, no cost.** Best for seeing the UI in action and exploring the panel features.\n\n```bash\ngit clone https://github.com/ahmedkhan1/ngx-ai-devtools.git\ncd ngx-ai-devtools\nnpm install\nnpm start\n```\n\nOpen `http://localhost:4200`. Click the buttons. Click the launcher pill. This is what's running at [ngx-ai-devtools.vercel.app](https://ngx-ai-devtools.vercel.app/).\n\n### Real API demo — `projects/real-api-demo/`\n\nReal calls to OpenAI, Anthropic, and Google through a local Node proxy that holds your API keys server-side. Verifies real response shapes, real streaming chunks, real cost calculation.\n\n```bash\n# Terminal 1 — start the proxy\ncd proxy\ncp .env.example .env\n# Edit .env with your API keys\nnpm start\n\n# Terminal 2 — start the Angular app\ncd projects/real-api-demo\nnpm install\nnpm start\n```\n\nEach click costs real money (typically fractions of a cent on `gpt-4o-mini` or `claude-haiku-4-5`). Use this when you want to verify the library works end-to-end with your own provider account.\n\nSee `projects/real-api-demo/README.md` for full setup details.\n\n---\n\n## Why this exists\n\nDebugging LLM calls in the browser is genuinely painful. You make a call, something goes wrong, and now you're three tabs deep: Network panel for the request, a JSON viewer for the body, a calculator for the cost. Ten minutes later you tweak the prompt and do it all over again.\n\n`ngx-ai-devtools` puts all of that in one floating panel inside your app. Every call your code makes — prompt, response, tokens, cost, tool use, streaming — recorded as it happens, structured the way you'd structure it if you wrote the logger yourself. Which you probably have, twice, in two different projects.\n\nUse it in development to iterate on prompts. Use it in staging to verify what your app actually sends to the model. Use it in production behind a feature flag to debug live issues without redeploying. The library is one provider call, signal-based, zero RxJS, tree-shakeable to nothing when disabled.\n---\n\n## Roadmap\n\nOpen issues for what would help you most:\n\n- Cost budgets and alerts\n- Diff view between two calls\n- Tool-call result piping (showing what the tool returned to the model on the next turn)\n- Prompt-caching discount awareness (OpenAI's `cached_tokens` field)\n- Persistent storage beyond `localStorage`\n\n---\n\n## Development\n\n```bash\ngit clone https://github.com/ahmedkhan1/ngx-ai-devtools.git\ncd ngx-ai-devtools\nnpm install\nnpm start              # serves the mock demo\nnpm run build:lib      # produces dist/ngx-ai-devtools\nnpm run pack           # produces a .tgz you can install in another project\n```\n\nTo test a local build inside another Angular app:\n\n```bash\nnpm run build:lib \u0026\u0026 npm run pack\n# In the other project:\nnpm install /absolute/path/to/dist/ngx-ai-devtools/ngx-ai-devtools-0.1.4.tgz\n```\n\n---\n\n## Contributing\n\nIssues and pull requests welcome. Adding a new provider:\n\n1. Add a parser in `src/lib/providers/\u003cprovider\u003e.parser.ts` exporting `is\u003cProvider\u003e`, `parse\u003cProvider\u003eRequest`, `parse\u003cProvider\u003eResponse`, and (if streamed) `accumulate\u003cProvider\u003eStream`.\n2. Wire it into `src/lib/providers/index.ts`.\n3. Add the model's pricing to `src/lib/pricing.ts`.\n4. Add a card to `projects/demo/` so it can be tested in the browser.\n\nKeep the public surface small — every new option is one more thing to maintain.\n\n---\n\n## License\n\nMIT © [Ahmed Khan](https://github.com/ahmedkhan1)\n\nIf this saved you a frustrating afternoon, a star is a kind way to say thanks.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahmedkhan1%2Fngx-ai-devtools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fahmedkhan1%2Fngx-ai-devtools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahmedkhan1%2Fngx-ai-devtools/lists"}