From e46fc642750b759b95f115bd7e10af4e4a079865 Mon Sep 17 00:00:00 2001 From: elpresidank Date: Thu, 4 Jun 2026 06:07:20 -0500 Subject: [PATCH] Use Match for workbench dispatch --- ts/EFFECT_NATIVE_REWRITE_AUDIT.md | 25 +++++++++++++++++- ts/packages/workbench/src/atoms/workbench.ts | 19 +++++++------- ts/packages/workbench/src/qa/mock-api.ts | 27 ++++++++------------ 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/ts/EFFECT_NATIVE_REWRITE_AUDIT.md b/ts/EFFECT_NATIVE_REWRITE_AUDIT.md index 04898aed..07cb2344 100644 --- a/ts/EFFECT_NATIVE_REWRITE_AUDIT.md +++ b/ts/EFFECT_NATIVE_REWRITE_AUDIT.md @@ -1855,6 +1855,26 @@ Notes: - `cd ts && bun run lint` - `git diff --check` +### 2026-06-04: Workbench Match Dispatch Slice + +- Status: migrated and root-verified. +- Completed: + - `ts/packages/workbench/src/qa/mock-api.ts` now dispatches mock RPC + service requests with `effect/Match` and keeps the existing unknown-service + `{}` fallback. + - `ts/packages/workbench/src/atoms/workbench.ts` now dispatches chat submit + behavior for `graph-rag`, `document-rag`, and `agent` through + `Match.exhaustive` over the `ChatMode` union. + - The strict scan for native `switch` statements in `ts/packages` is clean: + `rg -n "\bswitch\s*\(" ts/packages --glob '*.ts' --glob '*.tsx'` returns + no matches. +- Verification: + - `cd ts && bun run check:tsgo` + - `cd ts && bun run build` + - `cd ts && bun run test` + - `cd ts && bun run lint` + - `git diff --check` + ## Subagent Findings To Preserve - MCP/workbench: @@ -1982,6 +2002,9 @@ Notes: - ConfigService and KnowledgeCore operation dispatch now use `effect/Match` with `Match.exhaustive`; FlowManager and Librarian operation dispatch now use `effect/Match` with runtime-preserving `Match.orElse` fallbacks. + - Native `switch` statements are now clean in `ts/packages`; future branch + drift should keep service dispatch on `effect/Match` or Schema tagged-union + helpers. - Client RPC/BaseApi connection-state fanout now uses `effect/SubscriptionRef`; remaining gateway/client P1 work is broader API design, not listener bookkeeping. @@ -2167,7 +2190,7 @@ Notes: ## Recommended PR Order 1. MCP protocol parity tests and legacy stdio flip/removal decision. -2. Flow/client RPC stream and remaining service operation `Match` follow-ups. +2. Flow/client RPC stream API design beyond callback/Promise compatibility. 3. Long-lived ref-backed `HashMap` state cleanup where clone helpers remain. 4. Sibling service `Effect.fn` normalization where arrow-returned generators still appear. diff --git a/ts/packages/workbench/src/atoms/workbench.ts b/ts/packages/workbench/src/atoms/workbench.ts index d6fba862..f1018450 100644 --- a/ts/packages/workbench/src/atoms/workbench.ts +++ b/ts/packages/workbench/src/atoms/workbench.ts @@ -2,7 +2,7 @@ import { Clipboard as BrowserClipboard } from "@effect/platform-browser"; import * as BrowserHttpClient from "@effect/platform-browser/BrowserHttpClient"; import * as BrowserKeyValueStore from "@effect/platform-browser/BrowserKeyValueStore"; import { BaseApi, type ConnectionState, type DocumentMetadata, type ExplainEvent, type StreamingMetadata, type Term, type Triple } from "@trustgraph/client"; -import { Cause, Clock, Context, Effect, Layer, Metric, Option, Random, Schema as S } from "effect"; +import { Cause, Clock, Context, Effect, Layer, Match, Metric, Option, Random, Schema as S } from "effect"; import * as Otlp from "effect/unstable/observability/Otlp"; import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; import * as Atom from "effect/unstable/reactivity/Atom"; @@ -1576,14 +1576,14 @@ export const submitMessageAtom = commandAtom<{ input: string }, void>( explainEvents.push(event); }; - switch (chatMode) { - case "graph-rag": + Match.value(chatMode).pipe( + Match.when("graph-rag", () => { flow.graphRagStreaming(trimmed, onChunk, onError, undefined, collection, onExplain); - break; - case "document-rag": + }), + Match.when("document-rag", () => { flow.documentRagStreaming(trimmed, onChunk, onError, undefined, collection, onExplain); - break; - case "agent": + }), + Match.when("agent", () => { flow.agent( trimmed, (chunk, complete) => { @@ -1633,8 +1633,9 @@ export const submitMessageAtom = commandAtom<{ input: string }, void>( onExplain, collection, ); - break; - } + }), + Match.exhaustive, + ); }), ); diff --git a/ts/packages/workbench/src/qa/mock-api.ts b/ts/packages/workbench/src/qa/mock-api.ts index e283d879..d27f52c9 100644 --- a/ts/packages/workbench/src/qa/mock-api.ts +++ b/ts/packages/workbench/src/qa/mock-api.ts @@ -1,5 +1,5 @@ import { makeBaseApiWithRpc, type BaseApi, type DocumentMetadata, type ProcessingMetadata, type StreamingMetadata, type Triple } from "@trustgraph/client"; -import { Clock, Effect, Option, Schema as S } from "effect"; +import { Clock, Effect, Match, Option, Schema as S } from "effect"; type ConfigValues = Record>; @@ -284,22 +284,15 @@ function addDocument(state: MockState, metadata: DocumentMetadata): DocumentMeta } function dispatchRequest(state: MockState, service: string, request: Record, flow: string | undefined): unknown { - switch (service) { - case "flow": - return dispatchFlow(state, request); - case "config": - return dispatchConfig(state, request); - case "librarian": - return dispatchLibrarian(state, request); - case "knowledge": - return dispatchKnowledge(state, request); - case "collection-management": - return dispatchCollections(state, request); - case "triples": - return dispatchTriples(state, request, flow); - default: - return {}; - } + return Match.value(service).pipe( + Match.when("flow", () => dispatchFlow(state, request)), + Match.when("config", () => dispatchConfig(state, request)), + Match.when("librarian", () => dispatchLibrarian(state, request)), + Match.when("knowledge", () => dispatchKnowledge(state, request)), + Match.when("collection-management", () => dispatchCollections(state, request)), + Match.when("triples", () => dispatchTriples(state, request, flow)), + Match.orElse(() => ({})), + ); } function dispatchFlow(state: MockState, request: Record): unknown {