Repository navigation
dgem v0.4.0
Install the CLI
go install github.com/GoogleCloudPlatform/dgem@v0.4.0A go install build of v0.4.0 reports dgem version dev (the version is stamped by make build); build from a
checkout of the tag with make build to get dgem version v0.4.0 (revision 4368d3c, built <date>), or install
v0.4.1+ (go install github.com/GoogleCloudPlatform/dgem@latest
now reports the release version, and v0.4.1+ attaches prebuilt static CLI archives).
Serving image. No prebuilt images are published yet. Build the serving image from this tag in your own Google
Cloud project with GCP_PROJECT=<PROJECT> make cloudrun-build, then deploy it to Cloud Run GPU or Vertex AI (see
Build the Serving Image and the deploy guides).
Earlier versions were developed internally; this is the first release in this repository.
-
Pre-gated prior fusion and co-denoised evidence slots (
pkg/decisionindex,dgem systemone serve).
Questions on/v1/systemoneaccept optionalprior_logits(log-linear Product-of-Experts fusion via
--prior-weight,--hesitation-gate, and--prior-gate-mode confident|hesitant|proportional|always, preserving
pre-fusionraw_entropyandraw_normalized_entropyfor Stage 2 cascade gating) andevidence_prompt+
evidence_criteria(co-denoising a companion<question>_evidenceslot on the same diffusion canvas, plus
templates/multimodal/contact_sheet_verify.json.tmpl). -
Wide-option shortlist routing and cosine prior normalization (
pkg/decisionindex,dgem systemone serve).
--shortlist-topk(ShortlistFunc,PriorLogitsShortlist,LexicalOverlapShortlist) resolves wide choice
questions ($K > 26$ ) in a single forward pass over the top-$M$ options plus catch-all keys while preserving the
shortlist'snormalized_entropywhen lifting probabilities to all$K$ options (falling back to 2-stage bracket
tournaments whenprior_logitsis absent).NormalizeCosinePriorLogitsconverts bi-encoder cosine similarities
into temperature-scaled log-softmax priors (DefaultCosinePriorTemperature = 0.07), and--shortlist-contrastive
defaults tofalse. -
Decision Models Practitioner Guide (
docs/practitioners-guide.md). End-to-end architectural guide covering
Stage-1 restricted-softmax readout, normalized epistemic entropy ($\tilde{H}_m$ ), graduated production patterns,
empirical anti-patterns, and deployment topology selection across Apple Silicon, Cloud Run GPU, and Vertex AI. -
Genkit Go
v1.14.0examples (examples/). Runnable standalone module (examples/go.mod) bridging.json.tmpl
decision policies to Genkit'ssystemonex(POST /v1/systemone) plugin (examples/dgemgenkit/), including
hesitation-gated tool-approval interrupts (examples/genkit-tool-approval/) and two-stagegemini-3.8-flash
synthesis + concurrent bulkdgemevaluation (examples/genkit-bulk-synth/). -
Private (PSC) Vertex AI
:rawPredictand single-route serving. The serving image dispatches health
({"health": true}),/v1/systemoneand OpenAI-shaped chat decisions on its single/predictand/rawPredict
routes. The CLI, gateway,dgem systemone serve, regression matrix, synthetic probe and contract runner accept
private PSC Vertex endpoint URLs (http(s)://<ID>-<REGION>-<NUM>.prediction.p.vertexai.goog/v1/projects/.../endpoints/<ID>:rawPredict,
including plain HTTP on port 80 inside the VPC) and send every call to that single:rawPredictURL. -
Experimental 52-option label sets (
az_aa,az_lower). The serving image (DEFAULT_LABELS, requestlabels)
anddgem systemone serve --labelssupportaz_aa(A–ZthenAA–AZ) andaz_lower(A–Zthena–z,
requests of up to 10 questions) to read up to 52 choice options in one pass and bracket in 52-wide groups above that.
Defaultaz(A–Z, 26 options) is unchanged. -
Bulk / batch decision recipes and guide.
deploy/batch/adds ready-to-run Cloud Run Jobs, Dataflow (dgem_beam.py)
and fan-out workers (batch_worker.py, sendingX-DGem-KeyfromDGEM_SERVER_KEYin remote mode), documented in
To batch or not to batch. -
New policy template:
templates/github_spam_triage.json.tmpl(single-pass spam gate + 9-way category classification
for GitHub issues, PRs and discussions). -
Adapter server time telemetry:
evaluation_trace.server_mssumsdiagnostics.timing.total_msacross passes; the
matrix latency runner records server p90/p95/p99 alongside wall time. -
/v1/systemone: per-caller pass-through for requests the serving image can answer as sent.
--systemone-raw-users/DGEM_SYSTEMONE_RAW_USERS(comma-separated verified identities,*for all; default
none) forwards a listed caller's adapter-mode request unchanged when it has at most 8 questions, every choice and
score has 2-26 options or levels, and types are literallychoice/noul/score(mediais converted toimages).
Other requests still use the adapter. Why: the adapter builds a different prompt (a text state wrapped as JSON,
questions and options sorted, its own instructions) and response shape (no yes/no probabilities, sorted keys, no
model/usage) than the serving image, which changed a client's small-turn answers when score questions were added
to the adapter. The span log recordsdgem.systemone.mode(passthroughoradapter). -
Serving image: optional service key (
X-DGem-Key). WithDGEM_SERVER_KEYset (comma-separated to rotate),
everyPOSTneeds a matchingX-DGem-Keyheader;GET /healthstays open. UnlikeAPI_KEYit works on Vertex AI
and Cloud Run, whereAuthorizationcarries the Google token. ThedgemCLI, the gateway,dgem systemone serve,
scripts/matrix,probe.py,serving_speed.pyandcontract_diff.pysend the first entry of their own
DGEM_SERVER_KEY; the gateway never forwards a caller's header. The Vertex AI, Cloud Run, gateway and probe deploy
scripts set it from the Secret Manager secretdgem-server-keywhen it exists (SERVER_KEY_SECRETnames another).
Use it for any endpoint that more than your own services can reach, such as a Vertex AI dedicated endpoint
(Vertex AI). -
Gateway: caller authentication.
dgem serve --iap-audience(DGEM_IAP_AUDIENCE) verifies the IAP JWT on every
request (signature, audience, expiry) and takes the caller's identity from it, discarding identity headers sent by
the client;--api-keys(DGEM_GATEWAY_KEYS, headerX-DGem-Api-Key) serves self-hosted gateways without IAP.
With either set, requests without valid credentials get 401, with the same body whatever is configured (the
accepted methods are printed at startup).GET /healthstays open and reports only liveness, the version and
whether body logging is on. Behaviour change: it no longer listsdefault_backend,upstream_urlor
vertex_url;GET /api/backend-configreports them, the upstream URL ascloudrun_url.
deploy_cloudrun_gateway.shsets the Cloud Run IAP audience by default (VERIFY_IAP=0to skip). Callers set
DGEM_GATEWAY_KEY: the CLI sends it only to the gateway inDGEM_GATEWAY_URL(same scheme, host and port) and
dgem mcp --remoteto its remote. No dgem client keepsX-DGem-Api-KeyorX-DGem-Keyon a redirect to another
origin, and the gateway never forwards a caller's key upstream. Without either option the gateway warns at startup
when it listens on a non-loopback address. -
Image URLs are fetched by dgem, never by the serving image. The gateway (
/api/decide, MCP,/api/locate,
/v1/systemoneincluding?raw=1, and the/v1/chat/completionsproxy) fetches http(s) image URLs with its
public-address-only client and forwards data: URIs (unfetchable or non-image URLs: 422); the CLI fetches from the
caller's network and does the same. Behaviour change: the serving image refuses http(s) image URLs with 400 by
default (DGEM_IMAGE_URLS=deny;allowrestores the old behaviour), because vLLM runs with network egress and a URL
that passed the gateway's check could rebind or redirect to the metadata server or internal hosts. -
Audio and video are refused with 400 by the serving image, the gateway and
dgem systemone serve(audio,
video,input_audio,video_urland similar fields or chat content parts), instead of being answered as if they
were absent. Send video as sampled frames inimagesand audio as a transcript. -
Requests the model server refuses are 4xx, not 500/502. The serving image answers 422 (400 on the chat route)
when vLLM refuses a request, such as an image it can't fetch or decode or a prompt over the context length; the
gateway anddgem systemone servepass such refusals on with the server's message. Behaviour change:
/api/decidereturns 422 instead of 502 for them and no longer retries them as cold starts; unreachable or failing
servers stay 502. The gateway API reference documents the 400/401/422/502 meanings. -
/v1/systemoneadapter: score questions, one-option questions,media.-
scorequestions (criteriaan array of levels) are read with the rest in batches of at most 8; answers follow
the serving image's form (score= sum(i·p_i), probabilities keyed"0".."n-1",legend). Every answer now
carriesconfidence. - A choice with one option or a score with one level is answered without a model call.
-
media: [{mime_type, data}]withimage/*(data: URI or raw base64) is an alias forimages; other types get 400. -
Behaviour change: in adapter mode a body the adapter can't read (bad JSON,
questionsnot an object, criteria
of the wrong shape, unknown question type) gets 400 instead of silent pass-through; use?raw=1to send a body to
the serving image unchanged. Score questions with more than 26 levels or repeated levels get 422.
-
-
Gateway logs say why a request failed, and who sent it. Failed requests log the reason (
error, up to 300
characters) at WARNING (4xx) or ERROR (5xx) instead of INFO, on/v1/systemone,/api/decideand pass-through
routes. The verified caller (dgem.user) is recorded on/v1/systemone, on/mcp(a newdgem.gateway.mcpspan;
tool arguments are never logged) and from the start of/api/decide. Adapter requests log their shape without
content (question counts by type, max options, media entries, body size, forward passes)./mcpresponses carry
X-Dgem-Trace-Id. -
Gateway: opt-in request/response body logging, off by default.
DGEM_LOG_BODIES=responses|bothwith a required
DGEM_LOG_BODIES_UNTIL(RFC3339, at most 7 days ahead) andDGEM_LOG_BODIES_USERS(caller identities, or*),
optionalDGEM_LOG_BODIES_SAMPLE. Logs/v1/systemone,/api/decideand MCPtools/callbodies as
log_type: "dgem.bodies"lines (96 KB cap per body;data:URIs and long base64 replaced by a digest, in JSON and
non-JSON bodies; no headers or tokens). Invalid settings leave it off; the startup log shows the settings or why they
were refused, and/healthshows onlybody_logging.enabled. Setup, including a separate log bucket:
Observability. -
GCP tokens are cached only until they expire. Access and ID tokens were cached for a flat 45 minutes, so an
expired metadata-server token could be served: Vertex AI control-plane checks got 401 and a warm endpoint read as
quiesced. -
Gateway:
/v1/systemonekeeps images. The adapter dropped the request'simagesand answered text-only with
HTTP 200; it now sends them with every sub-request (batches and bracket rounds). Images must be data: URIs or
public http(s) URLs (local paths are rejected with 400, in the gateway and indgem systemone serve).
multipart/form-datauploads failed with400 invalid bodybecause the proxy forcedContent-Type: application/json; it now forwards the caller's content type. -
Gateway:
/v1/raw/chat/completionsremoved (410 Gone). dgem serves decisions; free-form generation had no
callers./v1/chat/completionson the gateway still makes decisions but is deprecated (Deprecationheader); use
/api/decideor/v1/systemone. -
Serving image:
- Responses report
diagnostics.constrained, which says how to read the per-questionentropyandlabel_mass.
With constrained reads (the default),entropyequals the entropy of the label probabilities andlabel_massis
always 1, so don't gate on it. - A read that needs more than 128 label tokens is refused with 422 instead of silently truncating vLLM's
logprob_token_ids. - The vision tower is on by default (
DISABLE_MM=0), as documented; setDISABLE_MM=1on an L4 with 32 GiB RAM. -
/v1/raw/chat/completionsanswers410 Gone. - Experimental
seed_token: "random" | "fixed"(per request,DEFAULT_SEED_TOKEN, or--seed-token):fixed
seeds every answer position with the padding token instead of a seeded random token. Defaultrandomis unchanged.
- Responses report
-
Answers always carry an entropy. The client fills each answer's
entropyfrom its probabilities; the Studio
could show 0% hesitation when the server didn't send one. -
Opt-in normalized cascade gate.
cascade_threshold_mode: "nats" | "normalized"onPOST /api/decide(or
X-DGem-Cascade-Threshold-Mode), MCP and the Studio Batch Eval.normalizedcompares H / ln K (default
threshold 0.16). The default staysnats(0.35). The two defaults are not equivalent operating points: 0.16
normalized escalates more (31% vs 22% on a 341-decision test mix); fit the threshold on your own traffic. -
SVG images are refused with a clear error (CLI, gateway 400,
/v1/systemone): the model server can't decode
SVG and answered 502. Docs use new PNG fixtures (fixtures/*.png); the Studio picker offers raster formats only. -
Templates keep the order of dict-form questions and options (they were reordered randomly per call).
-
dgem systemone serve:--option-order alpha|source(defaultalpha); server schema errors are passed on as
422 with the Decision Index kit's marker instead of 500; the openGET /healthreports only liveness and the version
(the upstream URL and adapter settings remain in the startup log). -
bench-intents: kept intents above 26 go through another bracket round instead of a final the server rejects
(full CLINC150). -
Docs: canvas size (128 rows as served, rounded to 16 per request), letter readout and the 26-option limit,
stage scheduling, prompt-cache advice fordocument_first, and what constrained reads do. -
Decision engine:
dgem decidecompiles.json.tmpldecision policies into one-pass multi-question readouts
(boolean,choice,score) with per-option probabilities, Shannon entropy and Hesitation %; conditional
questions (depends_on/ask_if), per-policytemperature, and taxonomy-expansion suggestions. -
Hesitation-gated cascade: low-hesitation answers are returned directly; the rest go to a Stage 2 Gemini model
(gemini-3.8-flashdefault,gemini-3.5-flash-lite) with a soft hint of dgem's answer by default
(stage2_prior: soft | full | none). -
Surfaces: CLI, HTTP gateway (
dgem serve:/api/decide,/v1/systemone,/api/locate), MCP server
(dgem mcp, Streamable HTTP/mcp), and the embedded Decision Studio. Backend routingvertex_first | vertex | cloudrun | localwith automatic failover. -
Gateway hardening: no CORS headers unless
--cors-origins(DGEM_CORS_ORIGINS) lists exact origins (*is
refused). Cross-site browserPOSTs and DNS-rebinding requests (a loopback connection carrying anotherHost) get
403;--allowed-hosts(DGEM_ALLOWED_HOSTS) admits a reverse proxy on the same machine. Template names must be
relative paths inside--templates-dir. The gateway fetches image URLs only from public addresses, checked when it
connects and on every redirect; it does not read local image paths from requests, and an image URL that does not
answer 2xx is an error. A per-requestvertex_urlis matched by project, region and endpoint ID, so another
project's endpoint with the same ID no longer receives the gateway's token; regional
https://<REGION>-aiplatform.googleapis.com/...:rawPredictURLs are accepted as well as dedicated endpoint hosts.
The serving image sendscharset=utf-8andnosniffon JSON responses. -
Loopback bind by default:
dgem serveanddgem systemone servelisten on127.0.0.1unless--hostsays
otherwise, so a laptop gateway is not reachable from the network by accident. On Cloud Run (K_SERVICE) and Vertex
(AIP_HTTP_PORT) the default is0.0.0.0, and the gateway image and the serving entrypoint pass--host 0.0.0.0
explicitly. To reach a gateway from another machine, pass--host 0.0.0.0and put it behind IAP/IAM. -
Images: approximate one-pass boxes, and guided locate (
dgem locate, MCPlocate_object): dgem answers
presence and grid cell, then Gemini returns the box; optional SAM masks. -
Serving image: vLLM structured generation with the dgem server patch (
deploy/cloudrun/):document_first
prompt layout, yes/no isolation (DEFAULT_ISOLATE=auto), in-flight limiting, 8k context on RTX PRO 6000,
idle-connection timeout. Deploy scripts for Vertex AI dedicated endpoints, Cloud Run GPU and GCE. -
Evaluation:
dgem bench-*harnesses and the regression matrix (scripts/bench_matrix.py,
benchmarks/matrix/matrix_example.json) to compare a candidate deployment with a baseline in one session.