Use Match for workbench dispatch

This commit is contained in:
elpresidank 2026-06-04 06:07:20 -05:00
parent dfc79bb050
commit e46fc64275
3 changed files with 44 additions and 27 deletions

View file

@ -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.

View file

@ -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,
);
}),
);

View file

@ -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<string, Record<string, unknown>>;
@ -284,22 +284,15 @@ function addDocument(state: MockState, metadata: DocumentMetadata): DocumentMeta
}
function dispatchRequest(state: MockState, service: string, request: Record<string, unknown>, 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<string, unknown>): unknown {