@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
78 lines • 3.85 kB
TypeScript
import type { LucidRawRunner } from '../stores/lucid.js';
/**
* Text channels' short-lived state, every entry with a TTL: the provider message ids already taken
* (so a webhook delivered twice starts one turn), a question waiting for the person's answer, an
* outcome already relayed.
*
* {@link InMemoryChannelStore} only sees its own process. With several replicas a retry, an answer
* or a settled proposal can land on another one, so use a shared store there:
* {@link lucidChannelStore} (the default when the agent's own store is Lucid),
* {@link redisChannelStore}, or your own.
*/
export interface ChannelStore {
/**
* Take `key` for `ttlMs` — atomically. `true` when it was free (now taken), `false` when someone
* already took it.
*/
claim(key: string, ttlMs: number): boolean | Promise<boolean>;
/** The live value under `key`, or `null`. */
get(key: string): string | null | Promise<string | null>;
/** Store `value` under `key` for `ttlMs`, replacing what was there. */
set(key: string, value: string, ttlMs: number): void | Promise<void>;
delete(key: string): void | Promise<void>;
}
/** Process-local {@link ChannelStore}: a single replica, tests, development. */
export declare class InMemoryChannelStore implements ChannelStore {
#private;
private readonly maxEntries;
/** @param maxEntries Past this many live keys, the oldest are forgotten first. */
constructor(maxEntries?: number);
claim(key: string, ttlMs: number): boolean;
get(key: string): string | null;
set(key: string, value: string, ttlMs: number): void;
delete(key: string): void;
}
/**
* The slice of a Redis client {@link redisChannelStore} uses — an `@adonisjs/redis` connection
* (ioredis) has it: `redisChannelStore(redis)` or `redisChannelStore(redis.connection('main'))`.
*/
export interface ChannelStoreRedis {
set(key: string, value: string, px: 'PX', ttlMs: number, nx: 'NX'): Promise<unknown>;
set(key: string, value: string, px: 'PX', ttlMs: number): Promise<unknown>;
get(key: string): Promise<string | null>;
del(key: string): Promise<unknown>;
}
/** A {@link ChannelStore} shared by every replica, over Redis (`SET … PX … NX` for claims). */
export declare function redisChannelStore(redis: ChannelStoreRedis, options?: {
prefix?: string;
}): ChannelStore;
export interface LucidChannelStoreOptions {
/** A named connection of the `Database` manager. Default: the one `db` is. */
connection?: string;
/** Default `agent_channel_state`. */
table?: string;
/**
* Create the table (and its index) on first use. Default `true`; `false` when a migration owns it
* (`createAgentTables` and the published migration create it under the default name).
*/
autoCreateTables?: boolean;
/** How often a claim also deletes expired rows. Default 10 minutes. */
purgeEveryMs?: number;
}
/** A Lucid `Database` (or one of its connections): raw SQL, and named connections when it has them. */
export type LucidChannelStoreDatabase = LucidRawRunner & {
connection?(name?: string): LucidRawRunner;
};
/**
* A {@link ChannelStore} in the app's SQL database through Lucid — shared by every replica, no Redis
* needed. One row per key in `agent_channel_state`; a claim is one `INSERT` that skips on a duplicate
* key (`ON CONFLICT DO NOTHING`, `INSERT IGNORE` on MySQL), so the primary key is the lock. Expired
* rows are deleted as claims come in (`purgeEveryMs`), and an expired key can be taken again.
*
* ```ts
* import db from '@adonisjs/lucid/services/db'
* channels.handle(adapter, { …, store: lucidChannelStore(db) })
* ```
*/
export declare function lucidChannelStore(database: LucidChannelStoreDatabase, options?: LucidChannelStoreOptions): ChannelStore;
//# sourceMappingURL=store.d.ts.map