# @happyvertical/smrt-agents

Agent framework for building autonomous actors with lifecycle management, inter-agent messaging, interest-based discovery, scheduling, and multi-tenant bindings.

## Installation

```bash
pnpm add @happyvertical/smrt-agents
```

## Usage

```typescript
import { Agent, type AgentOptions } from '@happyvertical/smrt-agents';
import { smrt } from '@happyvertical/smrt-core';
import { getModuleConfig } from '@happyvertical/smrt-config';

@smrt()
class MyAgent extends Agent {
  protected config = getModuleConfig('my-agent', {
    cronSchedule: '0 2 * * *',
    maxRetries: 3,
  });

  itemsProcessed: number = 0;

  constructor(options: AgentOptions = {}) {
    super({
      ...options,
      interests: {
        objects: {
          Meeting: { filter: { status: 'upcoming' } },
          Document: { filter: { 'type in': ['agenda', 'minutes'] } },
        },
      },
    });
  }

  async validate(): Promise<void> {
    if (!this.config.cronSchedule) throw new Error('cronSchedule required');
  }

  async run(): Promise<void> {
    const items = await this.interesting();
    for (const { type, data } of items) {
      this.logger.info(`Processing ${type}: ${data.id}`);
    }
    this.itemsProcessed = items.length;
    await this.save();
  }
}

const agent = new MyAgent({ name: 'my-agent' });
await agent.execute(); // initialize() -> validate() -> run() -> shutdown()
```

If you are running a single-agent CLI or script and want built-in
`SIGTERM`/`SIGINT` handling, pass `manageProcessSignals: true` to the
constructor. Multi-agent hosts should leave that off and coordinate process
shutdown themselves.

## Scheduled Methods Vs Operator Actions

Use scheduled agent methods for the regular, repeatable maintenance path: the
work that should happen automatically every time the schedule fires. Keep those
methods idempotent and safe to rerun.

When operators need a composite catch-up or repair flow, expose that as an
explicit method such as `forage()`, `backfill()`, or `rebuildIndex()` instead of
overloading `run()` with manual-only behavior. Those operator actions can still
be enqueued through `@happyvertical/smrt-jobs`, but they should remain distinct
from the normal scheduled loop so it stays obvious which work is automatic and
which work is an intentional intervention.

## Schema-driven settings

Agent packages can declare portable, non-secret settings without shipping a
custom admin component. The manifest preserves the versioned schema and the
agent admin shell renders `AgentSettingsForm` as a fallback.

```typescript
static override uiSlots = {
  notifications: {
    id: 'notifications',
    label: 'Notifications',
    scope: 'persona',
    settingsSchema: {
      version: 1,
      fields: [
        {
          id: 'minimumSeverity',
          label: 'Minimum severity',
          type: 'select',
          options: [
            { value: 'info', label: 'Info' },
            { value: 'urgent', label: 'Urgent only' },
          ],
        },
      ],
    },
  },
} satisfies AgentUISlots;
```

`scope: 'persona'` persists under `AgentOptions.personaId`; `scope: 'agent'`
uses a saved Agent row id. An omitted scope chooses the persona when present and
otherwise preserves legacy Agent-row behavior. Credentials should not
be modeled as settings fields—use a package-specific write-only server boundary
such as `MessagingSettingsService`.

## API

### Main Export (`@happyvertical/smrt-agents`)

| Export | Description |
|--------|------------|
| `Agent` | Base agent class with lifecycle and interests |
| `AgentOptions` | Constructor options type |
| `AgentStatusType` | Status enum: idle/initializing/running/error/shutdown |
| `AgentConfig` | DB-persisted agent configuration model |
| `AgentConfigCollection` | Collection for AgentConfig |
| `AgentSchedule` | Cron-based schedule model (`_smrt_agent_schedules`) |
| `AgentScheduleCollection` | Collection for AgentSchedule |
| `ScheduleStatus` | Schedule status type |
| `TenantAgent` | Agent-to-tenant junction with hierarchy resolution |
| `TenantAgentCollection` | Collection for TenantAgent |
| `TenantAgentStatus` | Tenant agent status type |
| `ResolvedAgentAvailability` | Resolved availability after hierarchy walk |
| `mergeFilters` | Combine interest filters |
| `normalizeSort` | Normalize sort expressions |
| `InterestOptions` | Interest configuration type |
| `InterestFilter` | Filter definition type |
| `InterestResult` | Discovery result type |
| `ObjectInterestConfig` | Per-object interest config type |
| `ObjectFilter` | Object filter type |
| `InterestHandlerFn` | Interest handler function type |
| `AsyncQualifierFn` | Async post-filter qualifier type |
| `QueryFn` | Query function type |
| `AgentWithInterestsOptions` | Agent options with interests |
| `createReportDataSurfaceTools` | Principal-bound report discovery, query, lifecycle, drilldown, and export tools |
| `ReportDataSurfaceToolsOptions` | Server-owned report catalog and application-host seams |

### Report Data-Surface Tools

`createReportDataSurfaceTools()` combines the generic read-only data-surface
tools with `reports.query`, `reports.refresh`, `reports.drilldown`, and
`reports.export`. Configure report constructors and all transport/action seams
on the server. Queries inherit authority exclusively from the live
`PrincipalRun`; visible commands require an exact browser acknowledgement, and
refresh/export retain application-owned authorization and audit hosts.
Discovery preserves each visible report field's kind, WHERE/HAVING filter
scope, and capabilities, plus the currently available report actions. When an
authenticated database is present, silent and visible reads return the
tenant-safe lifecycle-derived freshness state (including stale or
lock-skipped materializations). Advertised actions are filtered by the live
principal's tool allow-list and effective permissions; action hosts still
reauthorize before mutation.

### Server Export (`@happyvertical/smrt-agents/server`)

`createDataSurfaceActionAdapter()` provides server-only preview and confirmed
apply orchestration for the `smrt-ui` data-surface action contract. Browser
selections and action payloads are hints, never authority: each action declares
its input validator, confirmation policy, principal tool/RBAC operation, fresh
authorization and row-eligibility checks, and foreground or injected-background
execution.

Preview issues a short-lived opaque token bound to the principal, tenant,
surface/action, selection, query fingerprint, and revision. Apply verifies that
binding for confirmation-required actions and repeats its principal-bound checks
before returning accepted, skipped, and failed row outcomes. Actions declared
with `confirmation: 'none'` may apply directly with an idempotency key; every
other apply must include its current preview token. Callers must supply a durable shared
`DataSurfaceActionStateStore` with atomic token and idempotency operations.
`InMemoryDataSurfaceActionStateStore` is for single-process test harnesses only.
Background queues must invoke the supplied job `run()` callback so checks are
repeated at execution time.

### UI Export (`@happyvertical/smrt-agents/ui`)

| Export | Description |
|--------|------------|
| `AgentUIRegistry` | Singleton registry for agent admin panels |
| `createUIRegistry` | Factory for UI registries |
| `AgentUISlot` | UI slot definition type |
| `AgentUISlots` | Map of UI slots |
| `AgentSettingsSchema` | Versioned fallback settings form contract |
| `AgentAdminRoute` | Admin route metadata (path, component, load) |
| `AgentAdminExport` | Agent admin module export shape |
| `AgentAdminNavItem` | Navigation item for admin sidebar |
| `AgentAdminRootProps` | Props for admin root component |
| `AdminPanelBaseProps` | Props for admin panel components |
| `AgentManifestInfo` | Agent manifest metadata |
| `AgentRouteLoadContext` | Normalized SvelteKit load context |
| `AgentRouteLoadFn` | Server load function type |
| `AgentUIComponentRegistry` | Component registry type |
| `ComponentType` | Generic component type |

### Vite Export (`@happyvertical/smrt-agents/vite`)

| Export | Description |
|--------|------------|
| `vitePluginAgentRoutes` | Vite plugin for `virtual:smrt-agent-registrations` |
| `AgentRoutesPluginOptions` | Plugin options type |

## Dependencies

- `@happyvertical/smrt-core` -- ORM base classes
- `@happyvertical/smrt-config` -- Configuration management
- `@happyvertical/smrt-tenancy` -- Multi-tenant context
- `@happyvertical/ai` -- AI client (SDK)
- `@happyvertical/files` -- Filesystem utilities (SDK)
- `@happyvertical/utils` -- Shared utilities (SDK)
- `@happyvertical/smrt-ui` -- UI runtime (i18n client, primitives, module registry) for the optional `./svelte` components, including the agent-admin shells (`AgentAdminPanel`, `AgentAdminTabs`, `AgentSettingsShell`) that moved here from smrt-svelte in #1589
- Peer (optional): `svelte`
