Files
waggle-os/packages/hive-mind-hooks-hermes/src/hooks/stop.ts
Oleg Maslov b20b138fe4 moving
2026-09-02 10:14:22 +02:00

61 lines
2.2 KiB
TypeScript

/**
* Hermes stop hook — fired when an assistant turn completes. Summarizes the
* turn deterministically (no LLM call) and writes it as an `important` frame
* parented to the originating prompt frame when known. Thin entrypoint over
* the shared handler body.
*
* Native event: `post_llm_call` (fires once per turn after the loop
* completes, only if a final response was produced and the turn was not
* interrupted — the dependable per-turn Stop signal for a single-shot CLI
* run). The assistant text arrives at `extra.assistant_response`; the hermes
* adapter's `extractResponse` reads it. NOTE: `on_session_finalize` is the
* gateway-only path and is deliberately NOT used.
*
* Capture-only: emits no stdout (Hermes block/inject is via stdout JSON,
* not exit codes); fails open on any error and exits 0.
*/
import {
isDirectExecution,
makeStopHandler,
runHook,
type HookRunOptions,
} from '@waggle/hive-mind-hooks-core';
import { hermesAdapter } from '../adapter.js';
import { maybeCompactOnStop } from '../compact-on-stop.js';
export interface HermesStopOptions extends Partial<HookRunOptions> {
/** Injectable clock for the compact gate (tests). */
now?: () => number;
/** $HOME override for the compact state file (tests). */
home?: string;
/** Compact window override in ms (tests). */
compactWindowMs?: number;
}
export async function runStop(opts: HermesStopOptions = {}): Promise<void> {
const { now, home, compactWindowMs, ...runOpts } = opts;
const base = makeStopHandler(hermesAdapter);
const handler: typeof base = {
parse: base.parse,
async run(payload, ctx) {
// Primary save first — unchanged. If this throws, the compact step is
// skipped and the throw lands in runHook's fail-open catch (exit 0).
await base.run(payload, ctx);
// Best-effort maintenance layered after the save. Never throws/rejects,
// so it cannot affect the already-completed save or the exit code.
await maybeCompactOnStop(ctx, { now, home, windowMs: compactWindowMs });
return undefined;
},
};
return runHook(handler, {
name: 'stop',
loggerPrefix: 'hermes-hooks',
...runOpts,
});
}
if (isDirectExecution(import.meta.url)) {
void runStop();
}