Files
OpenMAIC/app
wyucandClaude Opus 5.5 a3c17b6116 feat(generation): host hooks for server-side generation runs (#1807)
* refactor(server): share the host hook registration checks

Move the misspelled-hook detection, the "did you mean" hint and the
bound-once hook reads out of the persistence hooks registry into
lib/server/host-hook-registration.ts, so another host hook registry can
validate its registrations the same way. No behavior change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(generation): host hooks for server-side generation runs

Add configureGenerationRunHooks, registered once from instrumentation.ts
register() like the persistence hooks, for a host that meters usage,
enforces a quota or keeps an audit trail around course generation:

- authorizeStart: admits or refuses a start on POST /api/generation-runs
  and POST /api/generate-classroom, after every built-in check, inside the
  create transaction; a refusal answers with the host's status, code,
  message and headers, and no run is created. Attributes it returns are
  stored on the run (generation-runs migration 5, host_attributes JSONB).
- wrapExecution: runs every claimed execution of a run (first claim,
  takeover, the claim after a Retry or an outline confirmation, media-only
  executions) and each background material extraction inside the host's
  context, with the run's stored attributes. A wrapper that refuses pauses
  the run at its step (Retry resumes it) or fails the extraction.
- classifyFailure: maps a host error to a stable code and says whether an
  automatic retry is worthwhile; consulted before the step retries, the
  outline stream's retries, the model fallback, media failures and
  extraction failures. A non-retryable host failure pauses the run at the
  step; the AI SDK's own retries of a retryable provider status stop at it
  too (callLLM and streamLLM put every model they hand the SDK, v2 or v3,
  and any model a prepareStep picks, behind a gate that raises it again as
  not retryable; frozen models included), callLLM's own retries stop at it
  and throw it rather than an earlier invalid result, and an outline stream
  that fails with it is not accepted on its partial outlines.
- onRunEvent: best-effort notifications after committed transitions
  (started, outline-ready, scene-appended, paused, completed, ended), in
  commit order within a process, each with the stored ownerId and the
  currentOwnerId the run was claimed into since (looked up for at most
  5 s; at most 1000 notifications queue per process, newer ones dropped
  with a counted warning); never awaited, and a failing listener never
  affects the run.

With nothing registered every path behaves as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 13:30:40 +08:00
..