mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
- biome.json (2.4.16, linter-only) wired as "lint" in all six packages - scripts/check-effect-laws.ts: Effect-native law enforcement encoding the adapted beep-effect effect-first/schema-first laws (no native JSON/switch/ sort/fetch/timers, no process.env, no throw new, no Effect.run* outside boundaries, no Schema-suffixed constants, no node:fs/path, AST-based pure-data interface detection per law 38/39) - ratcheting baseline allowlist (95 entries / 290 findings) that must shrink to documented exemptions only; stale counts fail the gate - root lint chains turbo lint + law check + native-class inventory - fix all 163 initial Biome findings: import-type style, templates, two `any`s, ten non-null assertions (librarian getService gate, A.matchRight in atoms, ensureNode returning nodes, main.tsx mount guard) Gates: lint, check:tsgo, build, test (force, 11 tasks) all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
/**
|
|
* Request/response specification — declares a request/response client for a flow.
|
|
*
|
|
* Enables FlowProcessor handlers to make request/response calls to other services
|
|
* (e.g., calling the prompt service or LLM from within a knowledge extraction handler).
|
|
*
|
|
* Python reference: trustgraph-base/trustgraph/base/prompt_client_spec.py
|
|
*/
|
|
|
|
import { Effect } from "effect";
|
|
import type { SpecRuntimeRequirements } from "./types.js";
|
|
import type { Flow, FlowDefinition } from "../processor/flow.js";
|
|
import type {
|
|
FlowResourceNotFoundError,
|
|
PubSubError,
|
|
} from "../errors.js";
|
|
import {
|
|
flowResourceNotFoundError,
|
|
} from "../errors.js";
|
|
import type {
|
|
EffectRequestResponse,
|
|
} from "../messaging/runtime.js";
|
|
import {
|
|
RequestResponseFactory,
|
|
} from "../messaging/runtime.js";
|
|
|
|
declare const RequestResponseSpecType: unique symbol;
|
|
|
|
export interface RequestResponseSpec<TReq, TRes> {
|
|
readonly [RequestResponseSpecType]?: {
|
|
readonly request: TReq;
|
|
readonly response: TRes;
|
|
};
|
|
readonly name: string;
|
|
readonly addEffect: <Requirements = never>(
|
|
flow: Flow<Requirements>,
|
|
definition: FlowDefinition,
|
|
) => Effect.Effect<void, PubSubError, SpecRuntimeRequirements | Requirements>;
|
|
readonly requestorEffect: <Requirements = never>(
|
|
flow: Flow<Requirements>,
|
|
) => Effect.Effect<EffectRequestResponse<TReq, TRes>, FlowResourceNotFoundError>;
|
|
}
|
|
|
|
export function makeRequestResponseSpec<TReq, TRes>(
|
|
name: string,
|
|
requestTopicName: string,
|
|
responseTopicName: string,
|
|
): RequestResponseSpec<TReq, TRes> {
|
|
const requestors = new WeakMap<object, EffectRequestResponse<TReq, TRes>>();
|
|
|
|
const registerRequestor = <Requirements>(
|
|
flow: Flow<Requirements>,
|
|
requestor: EffectRequestResponse<TReq, TRes>,
|
|
) =>
|
|
Effect.sync(() => {
|
|
requestors.set(flow, requestor);
|
|
});
|
|
|
|
const unregisterRequestor = <Requirements>(
|
|
flow: Flow<Requirements>,
|
|
requestor: EffectRequestResponse<TReq, TRes>,
|
|
) =>
|
|
Effect.sync(() => {
|
|
if (requestors.get(flow) === requestor) {
|
|
requestors.delete(flow);
|
|
}
|
|
});
|
|
|
|
const requestorEffect = <Requirements>(
|
|
flow: Flow<Requirements>,
|
|
): Effect.Effect<EffectRequestResponse<TReq, TRes>, FlowResourceNotFoundError> => {
|
|
const requestor = requestors.get(flow);
|
|
return requestor === undefined
|
|
? Effect.fail(flowResourceNotFoundError(flow.name, "requestor", name))
|
|
: Effect.succeed(requestor);
|
|
};
|
|
|
|
const addEffect = Effect.fn("RequestResponseSpec.addEffect")(function* <Requirements = never>(
|
|
flow: Flow<Requirements>,
|
|
definition: FlowDefinition,
|
|
) {
|
|
const requestTopic = definition.topics?.[requestTopicName] ?? requestTopicName;
|
|
const responseTopic = definition.topics?.[responseTopicName] ?? responseTopicName;
|
|
const factory = yield* RequestResponseFactory;
|
|
const requestor = yield* factory.make<TReq, TRes>({
|
|
requestTopic,
|
|
responseTopic,
|
|
subscription: `${flow.processorId}-${flow.name}-${name}`,
|
|
});
|
|
flow.registerRequestor(name, requestor);
|
|
yield* registerRequestor(flow, requestor);
|
|
yield* Effect.addFinalizer(() => unregisterRequestor(flow, requestor));
|
|
});
|
|
|
|
return {
|
|
name,
|
|
requestorEffect,
|
|
addEffect,
|
|
};
|
|
}
|