Skip to main content
A program that embeds gligabao (see Embedding in Go programs) can plug its own code into the server through hooks: Go callbacks supplied in gligabao.ServeOptions that gligabao calls at defined points. This page lists every hook that is available to external code. Not a callback, but also supplied by the embedding program: admin UI extensions (ServeOptions.AdminExtensions) add views and UI to the admin page. Everything else (the remember queue, the stores, the LLM clients) lives under internal/ and is not part of the public API; it cannot be hooked from outside the module.

System events

Types

gligabao.Hooks and gligabao.SystemEvent are aliases of the types in the monitoring package, which is outside internal/ so it can also be imported directly.

Behaviour

  • Installed for the lifetime of Serve. Serve installs ServeOptions.Hooks when it starts and removes them when it returns. There is no way to add or remove a hook while the server runs.
  • Several hook sets. ServeOptions.Hooks is a list; every set is called for each event, in the order of the list. A nil field is skipped. With no hook installed, events are dropped.
  • Synchronous. The callback runs on the goroutine that handles the request, before the HTTP response is written, so a slow callback slows the response. Keep it fast; hand slow work (network calls) to a goroutine or a buffered queue. (gligabao_int does this for its BetterStack sink.)
  • Concurrent. Requests are handled concurrently, so the callback must be safe for concurrent use.
  • Read-only event. The SystemEvent map must not be modified, and should not be retained after returning if you may change it: copy it first.
  • Panics are contained. A callback that panics does not affect the request or stop the remaining callbacks; the panic is silently discarded, so recover and log yourself if you want to know.
  • ctx is the context of the HTTP request that caused the event (cancelled if the client leaves).
  • Events are emitted by the regular endpoints and by their eval variants (POST /v1/gb/eval/remember, POST /v1/gb/eval/query), which use the same handlers.

Event types

eventType is <operation>.completed or <operation>.failed. Events carry counts and sizes, never the content (no text, query or answer). Values are string, int or int64. Fields common to all events: user_id, dataset, duration_ms (int64). A .failed event also has error (the error message, string).

remember.completed

A text was remembered (POST /v1/gb/remember with text).

remember.failed

The text pipeline failed (the request returned 502; nothing is stored). Fields: user_id, dataset, session_id, remember_run_id (the run in gb_remember_runs, see Remember manager), text_bytes, duration_ms, error.

remember_image.completed

An image was read (POST /v1/gb/remember with image). Fields: user_id, dataset, image_artifact_id, session_id, extraction_id, media_type, image_bytes, theme, text_blocks (text blocks read), duration_ms.

remember_image.failed

Fields: user_id, dataset, session_id, image_bytes, duration_ms, error.

query.completed

A question was answered (POST /v1/gb/query). Fields: user_id, dataset, session_id, query_bytes, evidence_entities, evidence_edges (the size of the evidence returned), duration_ms.

query.failed

Fields: user_id, dataset, session_id, query_bytes, duration_ms, error. It is emitted for any error of the query, including those answered with 400/404 (invalid user or dataset, dataset not found), not only 502.

timeseries.completed

Series were stored (POST /v1/gb/timeseries). Fields: user_id, dataset, series (number stored), duration_ms.

timeseries.failed

Fields: user_id, dataset, series (number in the request), duration_ms, error. Only emitted for a server error (500); an anchor that cannot be resolved (422) and other client errors emit nothing.

Example: metrics and alerts

A full example (logging every event with logrus and shipping it to BetterStack through a non-blocking sink) is systemEventHook in gligabao_int/gligabao_int/options.go.

Stability

The event types and field names above are what the server emits now. New fields may be added to an event, and new event types may be added, in any release: ignore what you do not know, and read fields with a checked type assertion (v, ok := ev["x"].(int)). A change to or removal of an existing event or field is called out in the changelog.

Timeseries providers

A provider is a callback, Fetch, with which remember pulls timeseries from a source of the embedding program’s, for the entities an LLM decides it covers. It is registered with ServeOptions.TimeseriesProviders:
Contract, in short: Fetch is called concurrently, with a 60 s timeout per call, must honour ctx, may return no series and no error when it has nothing, and a panic in it is caught and reported as an error. The providers are validated when Serve starts and it returns the error for a malformed one. Full description, validation rules and the request side: Timeseries.

Trained model deployers

A deployer is a callback, Deploy, that receives a trained model’s weights, as files in a directory on the local disk, and does with them whatever the embedding program wants: upload them to a service, copy them somewhere, convert them. gligabao does not know or care what; it only fetches the files and records the outcome. The full description of how deploying works is in Model deploying. Deployers are registered with ServeOptions.TrainedModelDeployers:
A deployment is asked for with POST /v1/gb/training/models/{id}/deployments and a body {"deployer": "bucket", "options": {...}}; options is a free-form JSON object that reaches the callback unchanged (req.Options). It is available in training mode (--training) only, like the rest of the training API.

Behaviour

  • gligabao fetches the files; the deployer does not. The weights live on the sidecar’s storage (Modal: the models volume). Before calling the deployer gligabao downloads every file of Model.Files from the sidecar (GET /models/file, see Sidecar training API) into Dir, and checks each against its recorded size and sha256. The deployer gets files that are complete and verified, and never talks to the sidecar.
  • Dir is an absolute path, <trained model deploy dir>/<job id> (serve --trained-model-deploy-dir, ServeOptions.TrainedModelDeployDir, default trained_models next to the database file). The files are at the paths Model.Files lists, relative to it (adapter_config.json, adapter_model.safetensors, tokenizer.model, …). gligabao never deletes it: it is kept for later deployments of the same model, which find the files in place (verified again) and download only what is missing or damaged. Clean it up yourself. The deployer must treat it as read only; copy or archive what it needs.
  • Synchronous. The request that asked for the deployment waits for the fetch and then for Deploy; its HTTP response is the stored deployment. Fetching a large model and a slow upload can take minutes: callers must not use a short timeout. ctx is the request’s context (cancelled if the client leaves), so Deploy should honour it.
  • Result. On success Ref identifies what the deployer made, in its own terms (e.g. the name of the uploaded model), and Details is anything else worth keeping; it must be JSON-encodable. Both are stored and returned with the deployment.
  • Failure. An error returned by Deploy (or a panic, which is caught) marks the deployment failed with the error text and answers 502. So does a failure to fetch the files. A failed deployment is not retried by gligabao.
  • Concurrent. Requests are handled concurrently, so Deploy must be safe for concurrent use, also for the same model. DeployID is unique to each call: use it if the deployer needs a unique name.
  • Recorded. Every deployment that reaches the fetch is stored in gb_trained_model_deployments (status running, then completed or failed; the deployer, its options, the directory, ref, details, the error, the duration) and listed by GET /v1/gb/training/models/{id}/deployments. A row still running long after it started was interrupted (the server restarted).
  • Validated at startup. Serve returns an error for a deployer with no Deploy, a Name that is not 1-64 letters, digits, _, - or . (starting with a letter or digit), or a duplicate name. At most 20.
  • System events. Each deployment emits training.model_deploy.completed or training.model_deploy.failed to the SystemEvent hook, with model_id, deploy_id, deployer, duration_ms (int64) and, on failure, error.
Endpoints: Trained models. How deploying works inside (fetching and verifying the files, the record of each deployment, the API, the limits): Model deploying.