@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
79 lines • 3.84 kB
TypeScript
import type { LucidClientLike, LucidRawRunner } from '../stores/lucid.js';
/**
* A2A conversation state the agent tables do not carry: who a `contextId` belongs to, and the reply
* each `messageId` got (PACT §4.2, §4.3).
*
* A context belongs to a brand (the exposed agent) and to one personal-agent user — the pair
* `(agent issuer, sub)`. Once a turn in it has run under a delegation, it is also bound to that
* account: a token for another account is refused there, so one conversation never mixes two users'
* data (§5.5).
*/
export interface A2aContext {
/** The `contextId` — the agent thread's id. */
id: string;
/** The exposed agent (the "brand" in `/a2a/{brand}`). */
brand: string;
agentIssuer: string;
agentSub: string;
/** The account a delegated turn ran as; `null` until one does. */
accountRef: string | null;
}
/** Where a `messageId` stands: never seen (now claimed), still running, or answered. */
export type MessageClaim = {
status: 'claimed';
} | {
status: 'pending';
} | {
status: 'done';
reply: unknown;
};
export interface A2aStore {
getContext(id: string): Promise<A2aContext | null>;
createContext(context: A2aContext): Promise<void>;
/**
* Bind the context to `accountRef` unless it is already bound. `true` when it is now bound to
* `accountRef` (either way), `false` when it was bound to someone else.
*/
bindAccount(id: string, accountRef: string): Promise<boolean>;
/** Claim `messageId` in the context — atomically, so two deliveries of one message run once. */
claimMessage(contextId: string, messageId: string): Promise<MessageClaim>;
/** Store the reply a claimed message got, for its retries. */
completeMessage(contextId: string, messageId: string, reply: unknown): Promise<void>;
/** Drop a claim whose turn failed, so a retry runs it again instead of finding nothing. */
releaseMessage(contextId: string, messageId: string): Promise<void>;
}
/** Process-local {@link A2aStore} — tests and single-instance dev. */
export declare class InMemoryA2aStore implements A2aStore {
#private;
getContext(id: string): Promise<A2aContext | null>;
createContext(context: A2aContext): Promise<void>;
bindAccount(id: string, accountRef: string): Promise<boolean>;
claimMessage(contextId: string, messageId: string): Promise<MessageClaim>;
completeMessage(contextId: string, messageId: string, reply: unknown): Promise<void>;
releaseMessage(contextId: string, messageId: string): Promise<void>;
}
export declare const A2A_TABLES: {
readonly contexts: 'agent_a2a_context';
readonly messages: 'agent_a2a_message';
};
/**
* `CREATE TABLE IF NOT EXISTS` DDL for the two A2A tables — same portable dialect as the agent
* tables (quoted identifiers, epoch-ms `BIGINT`, `TEXT` JSON). The message table's primary key IS the
* idempotency lock: two deliveries of one `messageId` race on the insert and one loses.
*/
export declare function a2aTableStatements(): string[];
/** Create the A2A tables if missing. Idempotent. */
export declare function ensureA2aTables(db: LucidRawRunner): Promise<void>;
/** {@link A2aStore} over Lucid (any of SQLite / Postgres / MySQL). */
export declare class LucidA2aStore implements A2aStore {
#private;
private readonly db;
constructor(db: LucidClientLike);
getContext(id: string): Promise<A2aContext | null>;
createContext(context: A2aContext): Promise<void>;
bindAccount(id: string, accountRef: string): Promise<boolean>;
claimMessage(contextId: string, messageId: string): Promise<MessageClaim>;
completeMessage(contextId: string, messageId: string, reply: unknown): Promise<void>;
releaseMessage(contextId: string, messageId: string): Promise<void>;
}
//# sourceMappingURL=store.d.ts.map