Uh oh!
There was an error while loading. Please reload this page.
client: adopt official @modernrelay/omnigraph SDK + parallelize ego reads - #2
Conversation
…web fixes - @omnigraph/client: replace the hand-rolled fetch client with a thin facade over the official @modernrelay/omnigraph SDK (canonical POST /query + /mutate). Keeps the Client / OmnigraphHttpError surface so ServerSource and its tests are unchanged; reshapes the SDK's camelCase responses back to the existing snake_case ReadOutput / ChangeOutput. - ServerSource.readEgo: fire the center + per-edge incident reads concurrently (Promise.all) instead of a sequential loop — collapses (k+1) round-trips to ~1. - tui + client: fall back to OMNIGRAPH_BEARER_TOKEN when OMNIGRAPH_TOKEN is unset. - web/config: resolve a relative `?server=/og` to an absolute origin URL — the SDK builds requests via new URL(base+path), which requires an absolute base. - web: dev-only `/og` Vite proxy; drop React.StrictMode (workaround, see PR). - http.test.ts: cover the facade reshape + the error-message contract.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:ebc65c3c1b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "test": "vitest run" | ||
| }, | ||
| "dependencies": { | ||
| "@modernrelay/omnigraph": "^0.6.0", |
There was a problem hiding this comment.
Restore Node 20-compatible client installs
This new SDK dependency raises the effective runtime floor for @omnigraph/client: the root package still advertises engines.node: >=20, but the lockfile records @modernrelay/omnigraph@0.6.0 with engines: {node: '>=22'}. In Node 20/21 environments that follow the repo's advertised support, engine-strict installs/deploys will now fail before the TUI/client can run; please either bump the workspace/package engine to Node 22+ or depend on an SDK build that supports Node 20.
Useful? React with 👍 / 👎.
Uh oh!
There was an error while loading. Please reload this page.
| ); | ||
| return { | ||
| query_name: r.queryName, | ||
| target: r.target?.branch ?? r.target?.snapshot ?? "main", |
There was a problem hiding this comment.
Silent
"main" fallback when server returns no target
r.target?.branch ?? r.target?.snapshot ?? "main" silently coerces a {branch: null, snapshot: null} response (or a missing target field) to the string "main". If the server is operating on a non-main default branch, the UI will display the wrong branch name for the query result. The PR notes defer the proper fix, but it's worth tracking that the fallback can produce actively wrong output, not just a missing label.
| "test": "vitest run" | ||
| }, | ||
| "dependencies": { | ||
| "@modernrelay/omnigraph": "^0.6.0", |
There was a problem hiding this comment.
🚩 SDK requires Node ≥22 but repo declares Node ≥20
The new dependency @modernrelay/omnigraph@0.6.0 declares engines: { node: '>=22' } in the lockfile (pnpm-lock.yaml:239), while the root package.json:9 declares "node": ">=20". Someone running Node 20 or 21 (which satisfies the repo's engine constraint) would have an officially unsupported SDK. In practice engines is advisory unless engine-strict=true is set, and the SDK may well work on Node 20, but this is worth reconciling.
Was this helpful? React with 👍 or 👎 to provide feedback.
| // NOTE (dev workaround): StrictMode's double-invoke runs the effect cleanup, | ||
| // which calls runtime.dispose() — disposing the runtime mid initial-run so it | ||
| // never notifies and the page stays on the loading skeleton. Disabled here | ||
| // while pointing at a real server. Real fix belongs in App.tsx lifecycle. | ||
| createRoot(root).render(<App />); |
There was a problem hiding this comment.
🚩 StrictMode removal is a workaround, not a fix
The PR removes React.StrictMode wrapping with a comment explaining that double-invoke cleanup disposes the runtime prematurely. The comment itself acknowledges this is a dev workaround and that the real fix belongs in App.tsx lifecycle (e.g., using a ref to track whether dispose should actually run, or re-creating the runtime on re-mount). This isn't a bug in the PR per se, but losing StrictMode means double-render bugs won't be caught during development.
Was this helpful? React with 👍 or 👎 to provide feedback.
- Text/Quote `text_column` is now required (z.string().min(1)) — a Text/Quote cell with rows but no text column was silently rendering the empty fallback instead of failing validation. (#3) - validate: warn when a *required* (non-nullable) catalog param is bound to $state without a default — it resolves at runtime, which validate can't see, so flag it rather than passing silently. (#2) - validate: document that the server-bound checks are intentional — structural parse already runs offline above; the meaningful ref/param validation needs a resolvable source by design. (#1, accepted-by-design) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Replaces colombo's hand-rolled omnigraph HTTP client with the official
@modernrelay/omnigraphSDK, plus supporting fixes surfaced while wiring it against a live 0.6.x server.Changes
@omnigraph/client→ SDK transport.Clientis now a thin facade over the SDK'sOmnigraphclass (canonicalPOST /query+POST /mutate). It keeps the existingClient/OmnigraphHttpErrorsurface, soServerSourceand its tests are untouched, and reshapes the SDK's camelCase responses back to the existing snake_caseReadOutput/ChangeOutput. Removes the bespokefetch/json()plumbing.ServerSource.readEgoparallelized. The center + per-edge-type incident reads are mutually independent, so they now fire concurrently (Promise.all) instead of a sequential loop — collapses(k+1)round-trips into ~1 (measured ~4.6× faster over HTTPS).OMNIGRAPH_BEARER_TOKENwhenOMNIGRAPH_TOKENis unset (the conventional omnigraph env var).web/configresolves a relative?server=/ogto an absolute origin URL — the SDK builds requests vianew URL(base + path), which throws on a relative base (this is why the web path silently failed before)./ogVite proxy (same-origin, avoids CORS);server-demo.shdoc updated to/query.http.test.tscovers the facade reshape and theOmnigraphHttpErrormessage contract (401/network/conflict) that the web error-classifier matches on.Verification
pnpm --filter @omnigraph/client typecheck && test— green (28 tests, incl. the unchangedsource.test.ts).pnpm -r typecheck && pnpm -r build— green; tui/web compile untouched.POST /query+POST /mutateagainst a 0.6 server (200 + correct shapes; mutation→/query→ 400); TUI renders end-to-end; webvite buildbundles the SDK cleanly.Notes / follow-ups
React.StrictModeremoved inweb/main.tsxas a workaround: its dev double-invoke runs the effect cleanup, which callsruntime.dispose(), wedging the runtime on the loading skeleton. The proper fix is theApp.tsxlifecycle (don't dispose on the StrictMode cleanup) — left as a follow-up.Selectcontrol's$bindStatere-emits on each render → re-run loop. Both pre-date this PR; flagged for a separate fix.ReadOutput.targettype isstringbut the server returns{branch, snapshot}; coerced in the facade, proper typing deferred (ripples intoruntime).Note
Medium Risk
Core server I/O path changes (SDK + endpoint rename) with preserved error contracts; parallel ego reads increase concurrent load; StrictMode removal masks a lifecycle bug in dev only.
Overview
Replaces the hand-rolled omnigraph HTTP stack in
@omnigraph/clientwith@modernrelay/omnigraph, while keeping the existingClient/OmnigraphHttpErrorsurface soServerSource, tests, and the weberror-classifierstay on the same snake_case shapes and error message patterns. Transport now usesPOST /queryandPOST /mutatevia the SDK; the facade maps camelCase SDK responses back and re-wrapsNetworkError/OmnigraphError(includingAbortErrorpassthrough). Public input types renameread/changetoquery/mutatewithquery/nameinstead ofquery_source/query_name.ServerSource.readEgoruns center and incident reads concurrently withPromise.allinstead of a sequential loop, reducing round-trips for ego graph cells.Web/TUI/dev: relative
?server=/ogbases are resolved to an absolute URL before constructingClient; TUI andClientacceptOMNIGRAPH_BEARER_TOKENwhenOMNIGRAPH_TOKENis unset; Vite adds a dev/ogproxy;React.StrictModeis temporarily removed inmain.tsx;server-demo.shdocuments/queryand the new JSON body fieldquery.Tests: new
http.test.tscovers response reshaping and classifier-aligned error messages.Reviewed by Cursor Bugbot for commit ebc65c3. Bugbot is set up for automated code reviews on this repo. Configure here.
Greptile Summary
Replaces the hand-rolled HTTP client in
@omnigraph/clientwith the official@modernrelay/omnigraphSDK as the transport layer, while preserving the existingClient/OmnigraphHttpErrorsurface forServerSourceand the web error-classifier. Accompanying fixes address relative-server URL resolution in the web, token env-var fallback, and a dev Vite proxy.http.ts):Clientnow wraps the SDK'sOmnigraphclass;toHttpErrorre-wraps SDK error classes (NetworkError,OmnigraphError) back intoOmnigraphHttpErrorto keep the message-contract regexes the web classifier depends on.ReadInput/ChangeInputare renamedQueryInput/MutateInputto match the new endpoints (/query,/mutate).source.ts):readEgofires the center query and all incident queries concurrently viaPromise.allinstead of a sequential loop, collapsingk+1round-trips into ~1.React.StrictModeremoved (web/main.tsx): Documented as a temporary workaround — StrictMode's dev double-invoke triggersruntime.dispose(), keeping the page on the loading skeleton; the proper fix is deferred toApp.tsx.Confidence Score: 4/5
Safe to merge — the SDK swap is well-contained behind the existing Client facade, the error-contract tests confirm the web classifier regexes are preserved, and the ego-read parallelisation is behaviourally equivalent to the old sequential loop.
The changes are thorough and the test coverage for the new facade is solid. The two items worth a second look are the target coercion (acknowledged in the PR notes — falls back to main when server returns a null target, which could show the wrong branch in the UI if the server default is not main) and the CLAUDE.md description still pointing at the old /read and /change endpoints. Neither blocks merging, but the target fallback could confuse users on non-main default-branch setups.
CLAUDE.md (stale endpoint references); packages/client/src/http.ts line 97 (target fallback); packages/web/src/main.tsx (StrictMode removal, deferred fix noted).
Important Files Changed
Sequence Diagram
Reviews (1): Last reviewed commit: "client: adopt @modernrelay/omnigraph SDK..." | Re-trigger Greptile
Context used: