61 lines
2.2 KiB
TypeScript
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();
|
|
}
|