@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
77 lines • 4.47 kB
TypeScript
import type { HistorySelection, HistoryWindow, HistoryWindowContext } from './spi/history-window.js';
import type { ModelProvider } from './spi/model-provider.js';
import type { ModelMessage } from './types.js';
/**
* Rough token count for one message: ~4 characters per token over its content and its serialized
* tool calls/results, plus a small per-message envelope allowance for the role and part framing.
*
* A heuristic on purpose. A real tokenizer is model-specific and would drag a provider dependency
* into the package, while a budget only has to be approximately right to keep a thread clear of the
* provider's hard limit — and it must be a PURE function, because it runs inside `select`. Pass
* `estimate` to {@link SlidingWindowHistory} to substitute a real one.
*/
export declare function estimateMessageTokens(message: ModelMessage): number;
export interface SlidingWindowHistoryOptions {
/**
* Max messages kept, counting from the most recent. Undefined → 40. The just-appended user
* message for this turn is always the last element of the array the loop hands in, so any
* `maxMessages >= 1` keeps it.
*/
maxMessages?: number;
/**
* Keep the newest messages whose estimated tokens fit this budget. Undefined → no token limit,
* so the message count alone decides. Both limits apply when both are set.
*/
maxTokens?: number;
/** Substitute for {@link estimateMessageTokens}. Must be pure — it runs inside `select`. */
estimate?: (message: ModelMessage) => number;
/**
* Folds the dropped messages into a leading summary instead of discarding them. Undefined → they
* are simply gone. {@link summarizeWithModel} is the built-in.
*/
summarize?: NonNullable<HistoryWindow['summarize']>;
/**
* How the summary is worded in the system prompt. Undefined → {@link renderHistorySummary}. Must be
* pure — it runs outside any checkpoint.
*/
renderSummary?: NonNullable<HistoryWindow['renderSummary']>;
}
/**
* Default {@link HistoryWindow}: keeps the newest messages that fit a message count and/or a token
* budget, and (optionally) folds the rest into a summary. Whichever limit cuts more wins.
*
* A naive slice is safe because each persisted message is self-contained: a tool call's result is
* never a separate message the loop hands the model (see `agent-loop.ts`'s mapping of
* `StoredMessage`), so a cut cannot orphan a tool result from its call.
*/
export declare class SlidingWindowHistory implements HistoryWindow {
/**
* Always a row count, so the bound always reaches the store: the token budget below can only cut
* MORE than this, and it cuts from the same end.
*/
readonly maxMessages: number;
private readonly maxTokens;
private readonly estimate;
readonly summarize?: NonNullable<HistoryWindow['summarize']>;
readonly renderSummary?: NonNullable<HistoryWindow['renderSummary']>;
constructor(options?: SlidingWindowHistoryOptions);
select(messages: ModelMessage[], _ctx: HistoryWindowContext): HistorySelection;
}
/**
* What a summarizer is told to produce when none is supplied. Written for a reader who will continue
* the conversation without seeing the messages themselves, so it asks for the parts a later turn
* still has to act on rather than a readable recap.
*/
export declare const DEFAULT_HISTORY_SUMMARY_INSTRUCTION = "Summarize this conversation for an assistant that will continue it without seeing these messages. Preserve decisions made, facts and constraints the user stated, identifiers and names mentioned, and anything left unresolved. Omit pleasantries. Reply with the summary only \u2014 no preamble, no headings.";
/**
* The default wording of a folded-history summary in the system prompt: the summary in a delimited
* block, followed by a note that the messages it stands in for are no longer sent verbatim.
*/
export declare function renderHistorySummary(summary: string): string;
/**
* A {@link HistoryWindow.summarize} backed by one extra, non-streamed model call. Writes to a
* discarding sink so the summary's tokens never reach the user's live stream, and reports its usage
* so the call lands in the ledger (and against the quota) like any other.
*/
export declare function summarizeWithModel(model: ModelProvider, instruction?: string): NonNullable<HistoryWindow['summarize']>;
//# sourceMappingURL=history-window.d.ts.map