UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

125 lines (124 loc) • 8.32 kB
/** * The RUNNER convenience half of the consolidation driver: resolve the model * seat out of a deployment's `RunnerDeps` (explicit chat seat wins; else the `consolidate` role * chain) into the options `runMemoryConsolidationDriver` eats. * * Role resolution lives HERE and not in the engine-layer verb on purpose: the driver function's * own seat is an explicit chat function — models, roles and * tiers are runner vocabulary. The chain is `consolidate → summarize → coded refusal`, and the * refusal is deliberate: one consolidation run reads the whole library (~10⁵ prompt tokens), so * an unset role silently escalating to the most expensive `default` model would be the * bad-value-silence family. A deployment that already declared a cheap `summarize` tier has made * exactly the cost choice this role wants, so that hop stays; pointing `roles.consolidate` at the * main model is a legal explicit choice. */ import type { Model } from "../../internal/llm.js"; import type { Brain, ModelRoles, ModelRef, TaskSpec } from "../types.js"; import { type DistillerChatFn } from "../memory-engine/distiller.js"; import { type RunMemoryConsolidationOptions, type ConsolidationDriverEngine, type ConsolidationWriteJudge } from "../memory-engine/consolidation-driver.js"; import { type MemoryConsolidationOptions } from "../memory-engine/consolidation.js"; import type { LlmDistillerContract } from "../memory-engine/distiller.js"; import type { EngineNotice } from "../engine-notice.js"; /** The slice of `RunnerDeps` this resolver reads (pass the deps object itself). */ export interface MemoryConsolidationDriverDeps { brain: Brain; models?: Record<string, Model>; tiers?: Record<string, ModelRef>; roles?: ModelRoles; memoryConsolidation?: MemoryConsolidationOptions; memoryConsolidationDriver?: { chat?: { baseUrl: string; apiKey: string; model: string; } | DistillerChatFn; model?: string; contract?: LlmDistillerContract; maxCycles?: number; mintRepairBudget?: number; }; /** Optional per-model auth hook (the TaskSpec-shaped seat) for the role-resolved path. */ getApiKeyAndHeaders?: TaskSpec["getApiKeyAndHeaders"]; } /** * Resolve a deployment's driver options: `{ chat, model }` from the explicit seat or the role * chain, plus the deployment knobs (contract / maxCycles / mintRepairBudget) and the protocol * parameters (`memoryConsolidation`) threaded through verbatim. The result feeds * `runMemoryConsolidationDriver(engine, scope, { ...resolved, writeJudge })` (the write judge is the caller's seat, * never resolved from deps); every bad value refuses coded here or in the verb's own screen, never folds to a default. */ export declare function resolveMemoryConsolidationDriver(deps: MemoryConsolidationDriverDeps): Omit<RunMemoryConsolidationOptions, "writeJudge">; /** * "Is there ANY model seat to resolve a consolidation run from?" (the question the * `autoRunOnRecommendation` construction door asks). It mirrors {@link resolveMemoryConsolidationDriver}'s * seat BRANCH — an explicit chat seat (function or endpoint triple) OR a resolvable * `consolidate`/`summarize` role — WITHOUT the value validation (a present-but-alias model id is a * DIFFERENT bad value, caught loudly by the driver's own screen when it runs). False ⇔ the resolve * verb would throw its "no model seat" refusal. Pinned against that resolve for drift. */ export declare function consolidationSeatResolvable(deps: MemoryConsolidationDriverDeps): boolean; /** * The advisory-to-execution bridge: fire ONE host consolidation run for the * recommended `scope`, fire-and-forget. Called from the post-task settle tail (NOT the harvest tail) * exactly once, only when {@link RunnerDeps.autoRunOnRecommendation} is armed AND the terminal * harvest recommended consolidation. It NEVER throws and NEVER rejects: the driver's own R1–R7 * failure table settles the run (zero-write on mint failure, `_incomplete` on non-convergence), this * bridge only relays the run's advisory notices to `onNotice` and routes a seat/engine fault to * `onError(phase:"memory")`. Adds no failure semantics of its own — the trigger is the only new thing. * The write judge is the LEG's; its refusal is a person's standing rule at work, so it is a refusal NOTICE, never a fault. */ export declare function autoRunConsolidationFromRecommendation(args: { deps: MemoryConsolidationDriverDeps; engine: ConsolidationDriverEngine; scope: string; sessionId: string; writeJudge: ConsolidationWriteJudge; onNotice?: (notice: EngineNotice) => void; onError?: (err: unknown, ctx: { phase: "memory"; sessionId: string; }) => void; }): Promise<void>; /** * THE shipped default for `RunnerDeps.autoRunOnRecommendation` when the seat is * ABSENT: ON — the reference CLI's auto-dream form (auto-execute under the same 24h ∧ 5-session * threshold gate the recommendation edge already uses; an explicit `false` is the deployment's off * switch). One named value so the polarity is this one line; every sentence about the default names * this constant rather than spelling a polarity. Read ONLY through {@link autoRunOnRecommendationEffective}. */ export declare const AUTO_RUN_ON_RECOMMENDATION_DEFAULT = true; /** * The ONE resolver of "is auto-consolidation armed on this deployment", read by the * prepare door's manifest fact and by the settle-tail trigger (never re-derived at a call site): * - explicit `true` ⇒ armed (the door has already refused it unless it can run); * - explicit `false` ⇒ off — the deployment's own off switch, and it beats the default; * - ABSENT ⇒ {@link AUTO_RUN_ON_RECOMMENDATION_DEFAULT}, and ONLY where it can run (the protocol * switch wired AND a model seat resolvable) — the reference CLI's "auto-dream: off while * auto-memory is off": a default-on world must not arm a deployment that wired no consolidation; * - any other value ⇒ off (never arm on garbage; the door refuses it at prepare anyway). * * @contract memory.auto_consolidation.arming_has_one_resolver — whether a deployment's automatic consolidation is armed is answered here and nowhere else, a host that merely DISPLAYS the arming included: an ABSENT seat is not "off" (it reads the named default, and only where both seats are wired), so a reader branching on `RunnerDeps.autoRunOnRecommendation` alone is wrong in BOTH directions — it calls a default-armed deployment unarmed and a deployment with no consolidation armed. A deployment fact, never a per-session one; exported from the package root for that reason. */ export declare function autoRunOnRecommendationEffective(deps: MemoryConsolidationDriverDeps & { autoRunOnRecommendation?: unknown; }): boolean; /** * The settle tail's ONE question: does this scope's gate row hold a recommendation * that no completed run has consumed? Asked of the GATE ROW through the same predicate the * recommendation edge is the negation of ({@link recommendationUnconsumed}) — never of a single * harvest's report: a crossing recorded by an earlier checkpoint harvest of the same run, or by a * session whose settle never fired, is still owed a run here. (The report-based reading stranded such * a scope forever: the edge sat disarmed, nothing advanced `lastRunAt`.) A gate the engine cannot read * answers `false` — the verbs would refuse loudly on it anyway. */ export declare function scopeHasUnconsumedRecommendation(engine: Pick<ConsolidationDriverEngine, "readConsolidationGate">, scope: string): boolean; /** * The auto-consolidation ARMING door (bad-value loudness, three states), called from * the prepare config doors at construction on every leg. A garbage value refuses; a CONTRADICTION * (`true` with nothing to run) refuses — never folded to off, so an armed-but-unrunnable trigger (the * invisible-failure family) cannot ship: a deployment learns at boot, not one silently dropped * recommendation later. Lives beside {@link consolidationSeatResolvable}, the one question it asks. */ export declare function assertAutoConsolidationWirable(deps: MemoryConsolidationDriverDeps & { autoRunOnRecommendation?: unknown; }): void;