UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

86 lines • 4.21 kB
import type { RolesPolicy } from '../spi/roles-policy.js'; import type { Actor, ToolSpec } from '../types.js'; /** * Tenant scope shape — a structural mirror of `@adonis-agora/authz`'s `TenantScope` * (`{ tenantId?: string }`). Kept local so the adapter references the authz package * only by structure, never by import (see {@link AuthzServiceLike}). */ export interface AuthzTenantScope { tenantId?: string; } /** * The structural slice of `@adonis-agora/authz`'s `AuthzService` this adapter needs: a * tenant-scoped, wildcard permission check. * * Typing it structurally (rather than `import type { AuthzService } from '@adonis-agora/authz'`) * is what keeps `@adonis-agora/authz` an OPTIONAL lazy peer — the adapter carries zero import of * the package, so it is pulled in only by an app that has already wired authz and hands its * `AuthzService` to the factory. The `./authz` subpath is the load boundary: the main entry never * references this file, so apps that don't use authz never load it. */ export interface AuthzServiceLike { /** * Does `user` hold `permission` (with wildcard matching, e.g. `posts.*` ⊇ `posts.edit`), * scoped to `options.scope`? Mirrors `AuthzService.can`. */ can(user: unknown, permission: string, options?: { scope?: AuthzTenantScope; }): Promise<boolean>; } /** Options for {@link AuthzToolAuthorizer} / {@link authzToolAuthorizer}. */ export interface AuthzToolAuthorizerConfig { /** * The `@adonis-agora/authz` `AuthzService` (or any structural match) the adapter consults for * each tool's declared `ability`. The app builds it from its own `config/authz.ts` and passes * the instance here — no host user entity is required. */ authz: AuthzServiceLike; /** * Maps an {@link Actor} onto the user object authz resolves a `SubjectRef` from. Defaults to * `{ id: actor.id }` — enough for authz's `defaultResolveSubjectRef` (which reads `.id`, defaulting * the type to `user`). Override to attach a polymorphic `type` or a host user entity. */ userFromActor?: (actor: Actor) => unknown; } /** Default {@link Actor} → authz subject mapping: the minimal `{ id }` authz needs to resolve a `SubjectRef`. */ export declare function defaultUserFromActor(actor: Actor): unknown; /** * A {@link RolesPolicy} (the agent's `ToolAuthorizer` seam) backed by `@adonis-agora/authz` * (AdonisJS Bouncer). For each tool it checks the actor against the tool's declared `ability` * via {@link AuthzServiceLike.can}, scoped to the actor's tenant. * * Security posture — FAIL-CLOSED: * - A tool that declares no `ability` is NEVER authorized (deny). Unlike the role-based default, * there is no ADMIN fallback: with authz selected, an un-annotated tool is simply not reachable. * - Any error thrown while resolving the decision denies. * * Tenant isolation: `actor.tenantRef` is passed as the authz **scope** (`{ tenantId }`), so a * permission granted in one tenant never authorizes a tool call made in another. When the actor has * no `tenantRef`, the check runs against the global scope (authz's default). * * The agent's double check — the offered-tools filter AND the invoke-time re-check inside * `ToolRegistry` — both run through this same `can(actor, tool)`, so offer and invoke stay * consistent. */ export declare class AuthzToolAuthorizer implements RolesPolicy { #private; constructor(config: AuthzToolAuthorizerConfig); can(actor: Actor, tool: ToolSpec): Promise<boolean>; } /** * Factory for an {@link AuthzToolAuthorizer}. Wire it in `config/agent.ts` as the tool authorizer, * replacing the ADMIN-only `DefaultToolAuthorizer`: * * ```ts * import { defineConfig } from '@adonis-agora/agent' * import { authzToolAuthorizer } from '@adonis-agora/agent/authz' * import authz from '@adonis-agora/authz/services/main' * * export default defineConfig({ * model: () => aiSdkModel(openai('gpt-4o-mini')), * authorizer: authzToolAuthorizer({ authz }), * }) * ``` */ export declare function authzToolAuthorizer(config: AuthzToolAuthorizerConfig): AuthzToolAuthorizer; //# sourceMappingURL=authz-tool-authorizer.d.ts.map