{"_id":"@bernierllc/admin-agent-service","_rev":"3-a4c2691dd5c8e7080ca258190fb800cb","name":"@bernierllc/admin-agent-service","dist-tags":{"latest":"0.1.1"},"versions":{"0.0.1":{"name":"@bernierllc/admin-agent-service","version":"0.0.1","keywords":["oidc","trusted-publishing","setup"],"_id":"@bernierllc/admin-agent-service@0.0.1","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"c563a766b5b7691cdcc9ce94ab13bed8ce103794","tarball":"https://registry.npmjs.org/@bernierllc/admin-agent-service/-/admin-agent-service-0.0.1.tgz","fileCount":2,"integrity":"sha512-JbfCmilXZFjn3WiqWNR6N32EluD/UYIzFPnZjinciRu7psGmAfJqJSiM09pPtzfAJvVtEhz8sha3kwHmqs/5fw==","signatures":[{"sig":"MEUCIQDBJme08RzrXOrH7S/6jEQ9+5RvNQcSUA0VIU0d62xYrgIgQHO7curXmFixFjlh0b23jD/q6OmzKeJXyDbnKyc+664=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2087},"_npmUser":{"name":"mkbernier","email":"mkbernier@gmail.com"},"_npmVersion":"11.12.1","description":"OIDC trusted publishing setup package for @bernierllc/admin-agent-service","directories":{},"_nodeVersion":"25.9.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/admin-agent-service_0.0.1_1781976309311_0.7641288359983647","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@bernierllc/admin-agent-service","version":"0.1.0","keywords":["admin","agent","ai","orchestrator","service","bernierllc"],"author":{"name":"Bernier LLC"},"license":"Bernier LLC","_id":"@bernierllc/admin-agent-service@0.1.0","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"homepage":"https://github.com/bernier-llc/tools#readme","bugs":{"url":"https://github.com/bernier-llc/tools/issues"},"dist":{"shasum":"bd66510067ac8550002bfee70aa7e48b7f9d2312","tarball":"https://registry.npmjs.org/@bernierllc/admin-agent-service/-/admin-agent-service-0.1.0.tgz","fileCount":18,"integrity":"sha512-Iolfyb2MKGUdB8nI/LofjREAb9fgbZUYn/v25f21dkL9BbNKhlKLgxE9D89cfPNd/Iuyqvp11baVpqCNp/MXuw==","signatures":[{"sig":"MEYCIQD2nlPWFtlgHU5jWI+d73uHwa3TXLsVj0L9yNpjirtXNwIhANFPH3fffEX3mLQAADHXM/cpE3FDt9bJKkPlel9OPzPl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76845},"main":"dist/index.js","_from":"file:bernierllc-admin-agent-service-0.1.0.tgz","types":"dist/index.d.ts","browser":false,"engines":{"node":">=18.0.0"},"scripts":{"dev":"tsc --watch","lint":"eslint src/**/*.ts","test":"jest","build":"tsc","clean":"rimraf dist","prebuild":"npm run clean","test:run":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5d143489-eb36-407c-a67d-dd149de05cf2"}},"_resolved":"/home/runner/work/tools/tools/packages/service/admin-agent-service/bernierllc-admin-agent-service-0.1.0.tgz","_integrity":"sha512-Iolfyb2MKGUdB8nI/LofjREAb9fgbZUYn/v25f21dkL9BbNKhlKLgxE9D89cfPNd/Iuyqvp11baVpqCNp/MXuw==","bernierllc":{"runtime":"node","category":"service","integration":{"logger":"integrated","neverhub":"required","neveradmin":"optional"}},"repository":{"url":"git+https://github.com/bernier-llc/tools.git","type":"git"},"_npmVersion":"11.17.0","description":"Orchestrator composing ai-agent-runtime, agent-tool-registry, agent-changeset, and agent-conversation-store into a configurable AdminAgent","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@bernierllc/logger":"1.7.0","@bernierllc/agent-changeset":"0.2.0","@bernierllc/ai-agent-runtime":"0.2.0","@bernierllc/ai-provider-router":"1.7.0","@bernierllc/agent-tool-registry":"0.2.0","@bernierllc/agent-conversation-store":"0.2.0","@bernierllc/chat-agent-prompt-manager":"1.5.0","@bernierllc/chat-agent-persona-manager":"1.4.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.6.4","rimraf":"^5.0.1","ts-jest":"^29.1.1","typescript":"^5.2.2","@types/jest":"^29.5.5","@types/node":"^20.6.0"},"peerDependencies":{"@bernierllc/neverhub-adapter":"0.4.0"},"peerDependenciesMeta":{"@bernierllc/neverhub-adapter":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/admin-agent-service_0.1.0_1781977237917_0.47739996958093234","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bernierllc/admin-agent-service","version":"0.1.1","description":"Orchestrator composing ai-agent-runtime, agent-tool-registry, agent-changeset, and agent-conversation-store into a configurable AdminAgent","main":"dist/index.js","types":"dist/index.d.ts","browser":false,"keywords":["admin","agent","ai","orchestrator","service","bernierllc"],"author":{"name":"Bernier LLC"},"license":"Bernier LLC","dependencies":{"@bernierllc/agent-conversation-store":"0.2.1","@bernierllc/agent-tool-registry":"0.2.1","@bernierllc/ai-agent-runtime":"0.2.1","@bernierllc/ai-provider-router":"1.7.1","@bernierllc/chat-agent-persona-manager":"1.4.0","@bernierllc/agent-changeset":"0.2.1","@bernierllc/chat-agent-prompt-manager":"1.5.1","@bernierllc/logger":"1.7.1"},"peerDependencies":{"@bernierllc/neverhub-adapter":"0.4.1"},"peerDependenciesMeta":{"@bernierllc/neverhub-adapter":{"optional":true}},"devDependencies":{"@types/jest":"^29.5.5","@types/node":"^20.6.0","jest":"^29.6.4","rimraf":"^5.0.1","ts-jest":"^29.1.1","typescript":"^5.2.2"},"repository":{"type":"git","url":"git+https://github.com/bernier-llc/tools.git"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"bernierllc":{"runtime":"node","category":"service","integration":{"neverhub":"required","neveradmin":"optional","logger":"integrated"}},"scripts":{"build":"tsc","dev":"tsc --watch","test":"jest","test:watch":"jest --watch","test:run":"jest","test:coverage":"jest --coverage","lint":"eslint src/**/*.ts","clean":"rimraf dist","prebuild":"npm run clean"},"_id":"@bernierllc/admin-agent-service@0.1.1","bugs":{"url":"https://github.com/bernier-llc/tools/issues"},"homepage":"https://github.com/bernier-llc/tools#readme","_integrity":"sha512-ZTRYwYyrjUEBgZdpCDyxFfbeFnYGGV5Q6/SJ10f90bWfKc9832SLAmHjJ7FtKFWJqheaIwgnlP3zQYaFzUeAwg==","_resolved":"/home/runner/work/tools/tools/packages/service/admin-agent-service/bernierllc-admin-agent-service-0.1.1.tgz","_from":"file:bernierllc-admin-agent-service-0.1.1.tgz","_nodeVersion":"24.18.0","_npmVersion":"12.0.1","dist":{"integrity":"sha512-ZTRYwYyrjUEBgZdpCDyxFfbeFnYGGV5Q6/SJ10f90bWfKc9832SLAmHjJ7FtKFWJqheaIwgnlP3zQYaFzUeAwg==","shasum":"5ff5e7b4c226c8b60993c500ecee42bbc4fcc360","tarball":"https://registry.npmjs.org/@bernierllc/admin-agent-service/-/admin-agent-service-0.1.1.tgz","fileCount":18,"unpackedSize":76845,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDvoF9/2qPtL6R37ryx7Qb0+w7a39hxp35IZqrt71bw3AIgPseteIGj2PT3LSL1Cj7NDtpDQjOheTuGO1MwMLalLp0="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5d143489-eb36-407c-a67d-dd149de05cf2"}},"directories":{},"maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/admin-agent-service_0.1.1_1784015749023_0.4349440379971312"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-20T17:25:09.166Z","modified":"2026-07-14T07:55:49.284Z","0.0.1":"2026-06-20T17:25:09.457Z","0.1.0":"2026-06-20T17:40:38.072Z","0.1.1":"2026-07-14T07:55:49.145Z"},"bugs":{"url":"https://github.com/bernier-llc/tools/issues"},"author":{"name":"Bernier LLC"},"license":"Bernier LLC","homepage":"https://github.com/bernier-llc/tools#readme","keywords":["admin","agent","ai","orchestrator","service","bernierllc"],"repository":{"type":"git","url":"git+https://github.com/bernier-llc/tools.git"},"description":"Orchestrator composing ai-agent-runtime, agent-tool-registry, agent-changeset, and agent-conversation-store into a configurable AdminAgent","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"readme":"# @bernierllc/admin-agent-service\n\nOrchestrator composing `ai-agent-runtime`, `agent-tool-registry`, `agent-changeset`, and `agent-conversation-store` into a configurable `AdminAgent` — the single surface consumers call for privileged LLM-powered admin sessions.\n\n## Installation\n\n```bash\nnpm install @bernierllc/admin-agent-service\n```\n\n## Quick Start\n\n```typescript\nimport { createAdminAgent } from '@bernierllc/admin-agent-service';\nimport { InMemoryConversationStore } from '@bernierllc/agent-conversation-store';\n\n// 1. Define your domain tools\nconst listBookingsTool = {\n  name: 'list-bookings',\n  description: 'Lists bookings for an organisation.',\n  inputSchema: { type: 'object', properties: { limit: { type: 'number' } } },\n  permissions: ['admin:read'],\n  execute: async (input, context) => ({\n    success: true,\n    message: 'Fetched bookings',\n    data: await db.bookings.findMany({ orgId: context.metadata?.orgId, take: input.limit }),\n  }),\n};\n\n// 2. Create the agent\nconst agent = createAdminAgent({\n  provider: myOpenAIProvider,        // any @bernierllc/ai-provider-core AIProvider\n  tools: [listBookingsTool],\n  permissionResolver: async (ctx) => resolvePerms(ctx.roles),\n  store: new InMemoryConversationStore(),\n});\n\n// 3. Stream the response\nfor await (const event of agent.chat('List my bookings', { userId: 'u1', orgId: 'org1' })) {\n  if (event.type === 'text-delta')     process.stdout.write(event.delta);\n  if (event.type === 'done')           console.log('\\n✓ finished');\n  if (event.type === 'change-summary') console.log(event.summary.plainText);\n}\n```\n\n## Usage\n\n### Feature Gate\n\nPrevent access when an org's AI feature flag is disabled:\n\n```typescript\nconst featureGateHook = {\n  isEnabled: async (feature, ctx) => featureFlags.isEnabled(feature, ctx.orgId),\n};\n\nconst agent = createAdminAgent({\n  ...config,\n  featureGateHook,\n  featureName: 'ai_admin_chat', // defaults to 'ai_chat'\n});\n```\n\nWhen the gate returns `false`, `chat()` yields `{ type: 'feature-disabled', feature: 'ai_admin_chat' }` and returns.\n\n### Rate Limiting\n\nThrottle requests per org:\n\n```typescript\nconst rateLimitHook = {\n  check: async (key, limit, windowSeconds) => redis.rateLimiter.allow(key, limit, windowSeconds),\n};\n\nconst agent = createAdminAgent({\n  ...config,\n  rateLimitHook,\n  rateLimit: 20,              // max 20 requests (default)\n  rateLimitWindowSeconds: 60, // per 60-second window (default)\n});\n```\n\nWhen the limit is exceeded, `chat()` yields `{ type: 'rate-limited', retryAfterSeconds: 60 }` and returns.\n\n### Custom System Prompt\n\n```typescript\nconst agent = createAdminAgent({\n  ...config,\n  systemPromptBuilder: async (authCtx, orgCtx) => `\n    You are an admin assistant for ${orgCtx.name}.\n    User: ${authCtx.userId} | Roles: ${authCtx.roles?.join(', ')}.\n    Today is ${new Date().toLocaleDateString()}.\n  `.trim(),\n});\n```\n\n### Conversation Persistence\n\n`chat()` automatically:\n- Calls `store.findLatest(context, orgId)` to resume an existing conversation\n- Persists the incoming user message before starting the LLM loop\n- Persists tool-call summaries after each agentic turn\n- Persists the final assistant text after `done`\n\nPass any `ConversationStore` adapter (SQL, Redis, Prisma, etc.) implementing the interface from `@bernierllc/agent-conversation-store`.\n\n### Tool Permissions\n\nEach `ToolDefinition` declares `permissions: string[]`. The `permissionResolver` callback returns the current user's granted permissions. The `agent-tool-registry` enforces the match before executing any tool — no permission means the LLM gets an error result and continues.\n\n```typescript\nconst tool = {\n  name: 'delete-record',\n  permissions: ['admin:delete'],  // caller must hold this permission\n  execute: async (input, ctx) => { /* ... */ },\n};\n\nconst agent = createAdminAgent({\n  ...config,\n  permissionResolver: async (ctx) => {\n    if (ctx.roles?.includes('super-admin')) return ['admin:read', 'admin:write', 'admin:delete'];\n    if (ctx.roles?.includes('admin')) return ['admin:read', 'admin:write'];\n    return ['admin:read'];\n  },\n});\n```\n\n### Change Summary\n\nAfter every `chat()` run completes, a `change-summary` event is emitted:\n\n```typescript\nfor await (const event of agent.chat('Delete that booking', auth)) {\n  if (event.type === 'change-summary') {\n    // Inject summary into UI or next LLM context\n    console.log(event.summary.plainText);\n    // \"1 change: admin.delete-booking — Booking #42 deleted.\"\n  }\n}\n```\n\n### Abort / Timeout\n\nPass an `AbortSignal` to cancel mid-flight:\n\n```typescript\nconst controller = new AbortController();\nsetTimeout(() => controller.abort(), 30_000); // 30-second hard limit\n\nfor await (const event of agent.chat('...', auth, controller.signal)) {\n  // ...\n}\n```\n\n## API\n\n### `createAdminAgent(config: AdminAgentConfig): AdminAgent`\n\nFactory function. Validates config synchronously and returns an `AdminAgent` instance.\n\nThrows `AdminAgentConfigError` when required fields are missing or invalid.\n\n### `AdminAgentConfig`\n\n| Field | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `provider` | `AIProvider` | ✅ | — | LLM provider (any `@bernierllc/ai-provider-core` implementation) |\n| `tools` | `ToolDefinition[]` | ✅ | — | Consumer-defined domain tools |\n| `permissionResolver` | `(ctx) => Promise<string[]>` | ✅ | — | Maps auth context to granted permission strings |\n| `store` | `ConversationStore` | ✅ | — | Conversation persistence adapter |\n| `conversationContext` | `string` | | `'admin_assistant'` | Label for `findLatest()` conversation lookup |\n| `persona` | `PersonaConfig` | | — | Static persona / prompt from `chat-agent-persona-manager` |\n| `systemPromptBuilder` | `(auth, org) => Promise<string>` | | — | Dynamic system prompt builder (overrides persona.prompt) |\n| `maxTurns` | `number` | | `10` | Maximum LLM turns per `chat()` call |\n| `timeoutMs` | `number` | | `30000` | Per-LLM-call timeout in milliseconds |\n| `featureGateHook` | `FeatureGateHook` | | — | Optional feature-flag integration |\n| `featureName` | `string` | | `'ai_chat'` | Feature name passed to `featureGateHook.isEnabled()` |\n| `rateLimitHook` | `RateLimitHook` | | — | Optional rate-limiting integration |\n| `rateLimit` | `number` | | `20` | Max requests per window |\n| `rateLimitWindowSeconds` | `number` | | `60` | Rolling window duration |\n| `neverhubAdapter` | `NeverHubAdapter` | | — | Pre-configured NeverHub adapter (skips auto-detection) |\n\n### `AdminAgent`\n\n```typescript\ninterface AdminAgent {\n  chat(\n    userMessage: string,\n    authContext: AuthContext,\n    signal?: AbortSignal\n  ): AsyncIterable<AdminAgentEvent>;\n}\n```\n\n### `AdminAgentEvent` (union)\n\n| `type` | Additional fields | Emitted when |\n|--------|-------------------|--------------|\n| `text-delta` | `delta: string` | LLM emits a text token |\n| `tool-call-start` | `toolName, toolCallId, input` | Tool execution begins |\n| `tool-call-result` | `toolName, toolCallId, result` | Tool execution completes |\n| `turn-complete` | `turnIndex, totalTokens` | One LLM turn ends |\n| `done` | `finalText, totalTurns, totalTokens` | All turns complete |\n| `error` | `error: AgentRuntimeError` | Runtime or provider error |\n| `change-summary` | `summary: RollupSummary` | After `done` — changeset summary |\n| `feature-disabled` | `feature: string` | Feature gate returned false |\n| `rate-limited` | `retryAfterSeconds: number` | Rate limit exceeded |\n\n### `AuthContext`\n\n```typescript\ninterface AuthContext {\n  userId: string;\n  orgId: string;\n  roles?: string[];\n  metadata?: Record<string, unknown>;\n}\n```\n\n## Error Classes\n\nAll errors extend `AdminAgentServiceError` and carry an ES2022 `Error.cause` chain.\n\n```typescript\nimport {\n  AdminAgentServiceError,\n  AdminAgentConfigError,\n  AdminAgentFeatureDisabledError,\n  AdminAgentRateLimitedError,\n  AdminAgentPermissionError,\n} from '@bernierllc/admin-agent-service';\n```\n\n| Class | Code | Thrown when |\n|-------|------|-------------|\n| `AdminAgentServiceError` | `ADMIN_AGENT_SERVICE_ERROR` | Base — unexpected runtime errors |\n| `AdminAgentConfigError` | `INVALID_CONFIG` | Required config fields missing |\n| `AdminAgentFeatureDisabledError` | `FEATURE_DISABLED` | Feature gate hook throws unexpectedly |\n| `AdminAgentRateLimitedError` | `RATE_LIMITED` | Rate limit hook throws unexpectedly |\n| `AdminAgentPermissionError` | `PERMISSION_DENIED` | Permission resolver throws unexpectedly |\n\nNote: when hooks return `false` (controlled denial), the service yields `feature-disabled` / `rate-limited` events instead of throwing.\n\n## Integration Documentation\n\n### NeverHub Integration\n\n`admin-agent-service` includes optional NeverHub integration for telemetry and service registration. Core functionality works with or without NeverHub.\n\n**Graceful degradation**: If NeverHub is unavailable, initialization failures are caught and logged. The agent continues functioning without NeverHub events.\n\n**Auto-detection** (default):\n\n```typescript\n// No extra config needed — NeverHub is auto-detected via environment variables:\n// NEVERHUB_API_URL, NEVERHUB_ENDPOINT, or NEVERHUB_HOST\nconst agent = createAdminAgent(config);\n```\n\n**Pre-configured adapter** (advanced):\n\n```typescript\nimport { NeverHubAdapter } from '@bernierllc/neverhub-adapter';\n\nconst neverhubAdapter = new NeverHubAdapter();\nconst agent = createAdminAgent({ ...config, neverhubAdapter });\n```\n\n**Events published**:\n- `admin_agent.conversation.started` — first conversation created for an org\n- `admin_agent.turn.complete` — each LLM turn completion\n- `admin_agent.done` — run finished with change count\n- `admin_agent.feature_disabled` — feature gate blocked request\n- `admin_agent.rate_limited` — rate limit blocked request\n- `admin_agent.error` — runtime error occurred\n\n### Logger Integration\n\nUses `@bernierllc/logger` for structured JSON logging. Log level is controlled by the `LOG_LEVEL` environment variable (default: `info`).\n\nKey log events:\n- `info: \"Started new conversation\"` — first org conversation\n- `info: \"Resuming existing conversation\"` — existing conversation found\n- `warn: \"Feature gate blocked request\"` — feature-disabled path\n- `warn: \"Rate limit exceeded\"` — rate-limited path\n- `warn: \"NeverHub initialization failed (non-fatal)\"` — NeverHub unavailable\n- `error: \"Agent runtime error\"` — LLM error event\n- `error: \"Failed to persist tool-call messages (non-fatal)\"` — store error during turn\n\n## License\n\nCopyright (c) 2025 Bernier LLC\n\nThis file is licensed to the client under a limited-use license.\nThe client may use and modify this code *only within the scope of the project it was delivered for*.\nRedistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.\n","readmeFilename":"README.md"}