mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
refactor(ts): remove non-client effect run boundaries
This commit is contained in:
parent
be2370ee7b
commit
174d636178
20 changed files with 126 additions and 106 deletions
|
|
@ -77,11 +77,6 @@ export interface AsyncProcessorRuntimeOptions<
|
||||||
) => Effect.Effect<void, RunError, RunRequirements>;
|
) => Effect.Effect<void, RunError, RunRequirements>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RegisteredSignalHandler {
|
|
||||||
readonly signal: NodeJS.Signals;
|
|
||||||
readonly handler: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeAsyncProcessor<
|
export function makeAsyncProcessor<
|
||||||
RunError = ProcessorLifecycleError,
|
RunError = ProcessorLifecycleError,
|
||||||
RunRequirements = never,
|
RunRequirements = never,
|
||||||
|
|
@ -94,41 +89,6 @@ export function makeAsyncProcessor<
|
||||||
const configHandlers: Array<EffectConfigHandler<RunError | ProcessorLifecycleError, RunRequirements>> = [];
|
const configHandlers: Array<EffectConfigHandler<RunError | ProcessorLifecycleError, RunRequirements>> = [];
|
||||||
const shutdownCallbacks: Array<() => Effect.Effect<void, Cause.UnknownError>> = [];
|
const shutdownCallbacks: Array<() => Effect.Effect<void, Cause.UnknownError>> = [];
|
||||||
let running = false;
|
let running = false;
|
||||||
let signalHandlers: RegisteredSignalHandler[] = [];
|
|
||||||
|
|
||||||
const registerProcessSignalHandlers = (): void => {
|
|
||||||
if (config.manageProcessSignals === false || signalHandlers.length > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const shutdown = () => {
|
|
||||||
Effect.runFork(
|
|
||||||
Effect.log(`[${config.id}] Shutting down...`).pipe(
|
|
||||||
Effect.flatMap(() => processor.stop),
|
|
||||||
Effect.mapError((error) => processorLifecycleError(config.id, "signal-shutdown", error)),
|
|
||||||
Effect.match({
|
|
||||||
onFailure: () => process.exit(1),
|
|
||||||
onSuccess: () => process.exit(0),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handlers: RegisteredSignalHandler[] = [
|
|
||||||
{ signal: "SIGINT", handler: shutdown },
|
|
||||||
{ signal: "SIGTERM", handler: shutdown },
|
|
||||||
];
|
|
||||||
for (const { signal, handler } of handlers) {
|
|
||||||
process.once(signal, handler);
|
|
||||||
}
|
|
||||||
signalHandlers = handlers;
|
|
||||||
};
|
|
||||||
|
|
||||||
const unregisterProcessSignalHandlers = (): void => {
|
|
||||||
for (const { signal, handler } of signalHandlers) {
|
|
||||||
process.off(signal, handler);
|
|
||||||
}
|
|
||||||
signalHandlers = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const processor: AsyncProcessorRuntime<RunError, RunRequirements> = {
|
const processor: AsyncProcessorRuntime<RunError, RunRequirements> = {
|
||||||
config,
|
config,
|
||||||
|
|
@ -152,7 +112,6 @@ export function makeAsyncProcessor<
|
||||||
const startProcessor = Effect.fn("trustgraph.processor.start")(function* () {
|
const startProcessor = Effect.fn("trustgraph.processor.start")(function* () {
|
||||||
yield* Effect.sync(() => {
|
yield* Effect.sync(() => {
|
||||||
running = true;
|
running = true;
|
||||||
registerProcessSignalHandlers();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
yield* processor.runEffect;
|
yield* processor.runEffect;
|
||||||
|
|
@ -169,7 +128,6 @@ export function makeAsyncProcessor<
|
||||||
const stopProcessor = Effect.fn("trustgraph.processor.stop")(function* () {
|
const stopProcessor = Effect.fn("trustgraph.processor.stop")(function* () {
|
||||||
yield* Effect.sync(() => {
|
yield* Effect.sync(() => {
|
||||||
running = false;
|
running = false;
|
||||||
unregisterProcessSignalHandlers();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const cb of shutdownCallbacks) {
|
for (const cb of shutdownCallbacks) {
|
||||||
|
|
|
||||||
|
|
@ -337,16 +337,13 @@ export const makeMcpToolConfigHandlers = (): ReadonlyArray<
|
||||||
export type McpToolService = FlowProcessorRuntime<McpToolRuntime>;
|
export type McpToolService = FlowProcessorRuntime<McpToolRuntime>;
|
||||||
|
|
||||||
export function makeMcpToolService(config: ProcessorConfig): McpToolService {
|
export function makeMcpToolService(config: ProcessorConfig): McpToolService {
|
||||||
const runtime = Effect.runSync(makeMcpToolRuntime);
|
|
||||||
const service = makeFlowProcessor(config, {
|
const service = makeFlowProcessor(config, {
|
||||||
specifications: makeMcpToolSpecs(),
|
specifications: makeMcpToolSpecs(),
|
||||||
provide: (effect) => effect.pipe(Effect.provideService(McpToolRuntime, runtime)),
|
provide: (effect) => effect.pipe(
|
||||||
});
|
Effect.provideServiceEffect(McpToolRuntime, makeMcpToolRuntime),
|
||||||
service.registerConfigHandler((pushedConfig, version) =>
|
|
||||||
onMcpConfig(pushedConfig, version).pipe(
|
|
||||||
Effect.provideService(McpToolRuntime, runtime),
|
|
||||||
),
|
),
|
||||||
);
|
});
|
||||||
|
service.registerConfigHandler(onMcpConfig);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -507,17 +507,13 @@ export const makeAgentConfigHandlers = (): ReadonlyArray<
|
||||||
export type AgentService = FlowProcessorRuntime<AgentRuntime>;
|
export type AgentService = FlowProcessorRuntime<AgentRuntime>;
|
||||||
|
|
||||||
export function makeAgentService(config: ProcessorConfig): AgentService {
|
export function makeAgentService(config: ProcessorConfig): AgentService {
|
||||||
const runtime = Effect.runSync(makeAgentRuntime);
|
|
||||||
const service = makeFlowProcessor(config, {
|
const service = makeFlowProcessor(config, {
|
||||||
specifications: makeAgentSpecs(),
|
specifications: makeAgentSpecs(),
|
||||||
provide: (effect) => effect.pipe(Effect.provideService(AgentRuntime, runtime)),
|
provide: (effect) => effect.pipe(
|
||||||
});
|
Effect.provideServiceEffect(AgentRuntime, makeAgentRuntime),
|
||||||
service.registerConfigHandler((pushedConfig, version) =>
|
|
||||||
onToolsConfig(pushedConfig, version).pipe(
|
|
||||||
Effect.provideService(AgentRuntime, runtime),
|
|
||||||
),
|
),
|
||||||
);
|
});
|
||||||
Effect.runSync(Effect.log("[AgentService] Service initialized"));
|
service.registerConfigHandler(onToolsConfig);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,9 @@ export const makeChunkingSpecs = (): ReadonlyArray<
|
||||||
export type ChunkingService = FlowProcessorRuntime;
|
export type ChunkingService = FlowProcessorRuntime;
|
||||||
|
|
||||||
export function makeChunkingService(config: ProcessorConfig): ChunkingService {
|
export function makeChunkingService(config: ProcessorConfig): ChunkingService {
|
||||||
const service = makeFlowProcessor(config, {
|
return makeFlowProcessor(config, {
|
||||||
specifications: makeChunkingSpecs(),
|
specifications: makeChunkingSpecs(),
|
||||||
});
|
});
|
||||||
Effect.runSync(Effect.log("[ChunkingService] Service initialized"));
|
|
||||||
return service;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChunkingService = makeChunkingService;
|
export const ChunkingService = makeChunkingService;
|
||||||
|
|
|
||||||
|
|
@ -237,11 +237,9 @@ export const makePdfDecoderSpecs = (): ReadonlyArray<Spec> => [
|
||||||
export type PdfDecoderService = FlowProcessorRuntime;
|
export type PdfDecoderService = FlowProcessorRuntime;
|
||||||
|
|
||||||
export function makePdfDecoderService(config: ProcessorConfig): PdfDecoderService {
|
export function makePdfDecoderService(config: ProcessorConfig): PdfDecoderService {
|
||||||
const service = makeFlowProcessor(config, {
|
return makeFlowProcessor(config, {
|
||||||
specifications: makePdfDecoderSpecs(),
|
specifications: makePdfDecoderSpecs(),
|
||||||
});
|
});
|
||||||
Effect.runSync(Effect.log("[PdfDecoder] Service initialized"));
|
|
||||||
return service;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PdfDecoderService = makePdfDecoderService;
|
export const PdfDecoderService = makePdfDecoderService;
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,11 @@ export const makeOllamaEmbeddingsEffect = Effect.fn("makeOllamaEmbeddingsEffect"
|
||||||
});
|
});
|
||||||
|
|
||||||
export function makeOllamaEmbeddings(config: OllamaEmbeddingsConfig): EmbeddingsServiceShape {
|
export function makeOllamaEmbeddings(config: OllamaEmbeddingsConfig): EmbeddingsServiceShape {
|
||||||
return Effect.runSync(makeOllamaEmbeddingsEffect(config));
|
return makeOllamaEmbeddingsFromConfig({
|
||||||
|
defaultModel: config.model ?? "mxbai-embed-large",
|
||||||
|
ollamaHost: config.ollamaHost ?? "http://localhost:11434",
|
||||||
|
fetchImpl: config.fetch ?? globalThis.fetch,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OllamaEmbeddingsLive(config: OllamaEmbeddingsConfig): Layer.Layer<Embeddings, EmbeddingsError> {
|
export function OllamaEmbeddingsLive(config: OllamaEmbeddingsConfig): Layer.Layer<Embeddings, EmbeddingsError> {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import type {
|
||||||
Spec,
|
Spec,
|
||||||
} from "@trustgraph/base";
|
} from "@trustgraph/base";
|
||||||
import {
|
import {
|
||||||
|
errorMessage,
|
||||||
makeFlowProcessor,
|
makeFlowProcessor,
|
||||||
makeConsumerSpec,
|
makeConsumerSpec,
|
||||||
makeProducerSpec,
|
makeProducerSpec,
|
||||||
|
|
@ -179,7 +180,7 @@ const onKnowledgeExtractMessage = Effect.fn("KnowledgeExtractService.onMessage")
|
||||||
const relationships = yield* extractRelationships(promptClient, llmClient, text).pipe(
|
const relationships = yield* extractRelationships(promptClient, llmClient, text).pipe(
|
||||||
Effect.catch((error: unknown) =>
|
Effect.catch((error: unknown) =>
|
||||||
Effect.logError("[KnowledgeExtract] Relationship extraction failed", {
|
Effect.logError("[KnowledgeExtract] Relationship extraction failed", {
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: errorMessage(error),
|
||||||
}).pipe(Effect.as(null)),
|
}).pipe(Effect.as(null)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -233,7 +234,7 @@ const onKnowledgeExtractMessage = Effect.fn("KnowledgeExtractService.onMessage")
|
||||||
const definitions = yield* extractDefinitions(promptClient, llmClient, text).pipe(
|
const definitions = yield* extractDefinitions(promptClient, llmClient, text).pipe(
|
||||||
Effect.catch((error: unknown) =>
|
Effect.catch((error: unknown) =>
|
||||||
Effect.logError("[KnowledgeExtract] Definition extraction failed", {
|
Effect.logError("[KnowledgeExtract] Definition extraction failed", {
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: errorMessage(error),
|
||||||
}).pipe(Effect.as(null)),
|
}).pipe(Effect.as(null)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -294,11 +295,9 @@ export const makeKnowledgeExtractSpecs = (): ReadonlyArray<Spec> => [
|
||||||
export type KnowledgeExtractService = FlowProcessorRuntime;
|
export type KnowledgeExtractService = FlowProcessorRuntime;
|
||||||
|
|
||||||
export function makeKnowledgeExtractService(config: ProcessorConfig): KnowledgeExtractService {
|
export function makeKnowledgeExtractService(config: ProcessorConfig): KnowledgeExtractService {
|
||||||
const service = makeFlowProcessor(config, {
|
return makeFlowProcessor(config, {
|
||||||
specifications: makeKnowledgeExtractSpecs(),
|
specifications: makeKnowledgeExtractSpecs(),
|
||||||
});
|
});
|
||||||
Effect.runSync(Effect.log("[KnowledgeExtract] Service initialized"));
|
|
||||||
return service;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KnowledgeExtractService = makeKnowledgeExtractService;
|
export const KnowledgeExtractService = makeKnowledgeExtractService;
|
||||||
|
|
@ -332,9 +331,6 @@ export function parseJsonResponse<T>(raw: string): T | null {
|
||||||
if (O.isSome(decoded)) return decoded.value as T;
|
if (O.isSome(decoded)) return decoded.value as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.runSync(Effect.logWarning("[KnowledgeExtract] Failed to parse JSON from LLM response", {
|
|
||||||
response: raw.slice(0, 300),
|
|
||||||
}));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,9 +339,6 @@ function parseRelationshipsResponse(raw: string): ReadonlyArray<ExtractedRelatio
|
||||||
const decoded = decodeExtractedRelationships(candidate);
|
const decoded = decodeExtractedRelationships(candidate);
|
||||||
if (O.isSome(decoded)) return decoded.value;
|
if (O.isSome(decoded)) return decoded.value;
|
||||||
}
|
}
|
||||||
Effect.runSync(Effect.logWarning("[KnowledgeExtract] Failed to parse relationships from LLM response", {
|
|
||||||
response: raw.slice(0, 300),
|
|
||||||
}));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -354,9 +347,6 @@ function parseDefinitionsResponse(raw: string): ReadonlyArray<ExtractedDefinitio
|
||||||
const decoded = decodeExtractedDefinitions(candidate);
|
const decoded = decodeExtractedDefinitions(candidate);
|
||||||
if (O.isSome(decoded)) return decoded.value;
|
if (O.isSome(decoded)) return decoded.value;
|
||||||
}
|
}
|
||||||
Effect.runSync(Effect.logWarning("[KnowledgeExtract] Failed to parse definitions from LLM response", {
|
|
||||||
response: raw.slice(0, 300),
|
|
||||||
}));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import {
|
||||||
errorMessage,
|
errorMessage,
|
||||||
makeAsyncProcessor,
|
makeAsyncProcessor,
|
||||||
makeProcessorProgram,
|
makeProcessorProgram,
|
||||||
|
loadProcessorRuntimeConfig,
|
||||||
topics,
|
topics,
|
||||||
DocumentMetadata as DocumentMetadataSchema,
|
DocumentMetadata as DocumentMetadataSchema,
|
||||||
ProcessingMetadata as ProcessingMetadataSchema,
|
ProcessingMetadata as ProcessingMetadataSchema,
|
||||||
|
|
@ -88,11 +89,20 @@ const librarianServiceError = (operation: string, cause: unknown): LibrarianServ
|
||||||
});
|
});
|
||||||
|
|
||||||
function resolveDataDir(config: LibrarianServiceConfig): string {
|
function resolveDataDir(config: LibrarianServiceConfig): string {
|
||||||
return config.dataDir ?? Effect.runSync(
|
return config.dataDir ?? "./data/librarian";
|
||||||
Config.string("LIBRARIAN_DATA_DIR").pipe(Config.withDefault("./data/librarian")),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadLibrarianServiceConfig = Effect.gen(function* () {
|
||||||
|
const config = yield* loadProcessorRuntimeConfig("librarian-svc", {
|
||||||
|
manageProcessSignals: false,
|
||||||
|
});
|
||||||
|
const dataDir = Option.getOrUndefined(yield* Config.string("LIBRARIAN_DATA_DIR").pipe(Config.option));
|
||||||
|
return {
|
||||||
|
...config,
|
||||||
|
...(dataDir === undefined ? {} : { dataDir }),
|
||||||
|
} satisfies LibrarianServiceConfig;
|
||||||
|
});
|
||||||
|
|
||||||
const currentEpochSeconds: Effect.Effect<number> = Clock.currentTimeMillis.pipe(
|
const currentEpochSeconds: Effect.Effect<number> = Clock.currentTimeMillis.pipe(
|
||||||
Effect.map((millis) => Math.floor(millis / 1000)),
|
Effect.map((millis) => Math.floor(millis / 1000)),
|
||||||
);
|
);
|
||||||
|
|
@ -1504,6 +1514,7 @@ export const LibrarianService = makeLibrarianService;
|
||||||
|
|
||||||
export const program = makeProcessorProgram({
|
export const program = makeProcessorProgram({
|
||||||
id: "librarian-svc",
|
id: "librarian-svc",
|
||||||
|
loadConfig: loadLibrarianServiceConfig,
|
||||||
make: (config) => makeLibrarianService(config),
|
make: (config) => makeLibrarianService(config),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,22 @@ const makeAzureOpenAIProviderFromClient = (
|
||||||
export function makeAzureOpenAIProvider(
|
export function makeAzureOpenAIProvider(
|
||||||
config: AzureOpenAIProcessorConfig,
|
config: AzureOpenAIProcessorConfig,
|
||||||
): LlmProvider<TextCompletionRuntimeError> {
|
): LlmProvider<TextCompletionRuntimeError> {
|
||||||
return Effect.runSync(makeAzureOpenAIProviderEffect(config));
|
const resolved = {
|
||||||
|
defaultModel: config.model ?? "gpt-4o",
|
||||||
|
defaultTemperature: config.temperature ?? 0.0,
|
||||||
|
maxOutput: config.maxOutput ?? 4096,
|
||||||
|
apiKey: config.apiKey ?? "",
|
||||||
|
endpoint: config.endpoint ?? "",
|
||||||
|
apiVersion: config.apiVersion ?? "2024-12-01-preview",
|
||||||
|
} satisfies ResolvedAzureOpenAIConfig;
|
||||||
|
return makeAzureOpenAIProviderFromClient(
|
||||||
|
resolved,
|
||||||
|
new AzureOpenAI({
|
||||||
|
apiKey: resolved.apiKey,
|
||||||
|
apiVersion: resolved.apiVersion,
|
||||||
|
endpoint: resolved.endpoint,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeAzureOpenAIProviderEffect = Effect.fn("makeAzureOpenAIProvider")(function*(
|
export const makeAzureOpenAIProviderEffect = Effect.fn("makeAzureOpenAIProvider")(function*(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
makeFlowProcessorProgram,
|
makeFlowProcessorProgram,
|
||||||
makeLlmSpecs,
|
makeLlmSpecs,
|
||||||
} from "@trustgraph/base";
|
} from "@trustgraph/base";
|
||||||
import { Effect, Layer, Redacted } from "effect";
|
import { Context, Effect, Layer, Redacted } from "effect";
|
||||||
import { FetchHttpClient } from "effect/unstable/http";
|
import { FetchHttpClient } from "effect/unstable/http";
|
||||||
import type {
|
import type {
|
||||||
TextCompletionConfigError,
|
TextCompletionConfigError,
|
||||||
|
|
@ -69,7 +69,32 @@ const makeClaudeLayer = (apiKey: string) =>
|
||||||
export function makeClaudeProvider(
|
export function makeClaudeProvider(
|
||||||
config: ClaudeProcessorConfig,
|
config: ClaudeProcessorConfig,
|
||||||
): LlmProvider<TextCompletionRuntimeError> {
|
): LlmProvider<TextCompletionRuntimeError> {
|
||||||
return Effect.runSync(Effect.scoped(makeClaudeProviderEffect(config)));
|
const resolved = {
|
||||||
|
defaultModel: config.model ?? "claude-sonnet-4-20250514",
|
||||||
|
defaultTemperature: config.temperature ?? 0.0,
|
||||||
|
maxOutput: config.maxOutput ?? 8192,
|
||||||
|
apiKey: config.apiKey ?? "",
|
||||||
|
} satisfies ResolvedClaudeConfig;
|
||||||
|
return makeLanguageModelProvider({
|
||||||
|
provider: "Claude",
|
||||||
|
defaultModel: resolved.defaultModel,
|
||||||
|
defaultTemperature: resolved.defaultTemperature,
|
||||||
|
context: Context.empty(),
|
||||||
|
makeLanguageModel: ({ model, temperature }) =>
|
||||||
|
Effect.scoped(
|
||||||
|
Layer.build(makeClaudeLayer(resolved.apiKey)).pipe(
|
||||||
|
Effect.flatMap((context) =>
|
||||||
|
AnthropicLanguageModel.make({
|
||||||
|
model,
|
||||||
|
config: {
|
||||||
|
max_tokens: resolved.maxOutput,
|
||||||
|
temperature,
|
||||||
|
},
|
||||||
|
}).pipe(Effect.provideContext(context))
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeClaudeProviderEffect = Effect.fn("makeClaudeProvider")(function* (
|
export const makeClaudeProviderEffect = Effect.fn("makeClaudeProvider")(function* (
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,16 @@ const makeMistralProviderFromClient = (
|
||||||
export function makeMistralProvider(
|
export function makeMistralProvider(
|
||||||
config: MistralProcessorConfig,
|
config: MistralProcessorConfig,
|
||||||
): LlmProvider<TextCompletionRuntimeError> {
|
): LlmProvider<TextCompletionRuntimeError> {
|
||||||
return Effect.runSync(makeMistralProviderEffect(config));
|
const resolved = {
|
||||||
|
defaultModel: config.model ?? "ministral-8b-latest",
|
||||||
|
defaultTemperature: config.temperature ?? 0.0,
|
||||||
|
maxOutput: config.maxOutput ?? 4096,
|
||||||
|
apiKey: config.apiKey ?? "",
|
||||||
|
} satisfies ResolvedMistralConfig;
|
||||||
|
return makeMistralProviderFromClient(
|
||||||
|
resolved,
|
||||||
|
new Mistral({ apiKey: resolved.apiKey }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeMistralProviderEffect = Effect.fn("makeMistralProvider")(function*(
|
export const makeMistralProviderEffect = Effect.fn("makeMistralProvider")(function*(
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,14 @@ const makeOllamaProviderFromClient = (
|
||||||
export function makeOllamaProvider(
|
export function makeOllamaProvider(
|
||||||
config: OllamaProcessorConfig,
|
config: OllamaProcessorConfig,
|
||||||
): LlmProvider<TextCompletionRuntimeError> {
|
): LlmProvider<TextCompletionRuntimeError> {
|
||||||
return Effect.runSync(makeOllamaProviderEffect(config));
|
const resolved = {
|
||||||
|
defaultModel: config.model ?? "qwen2.5:0.5b",
|
||||||
|
host: config.ollamaUrl ?? "http://localhost:11434",
|
||||||
|
} satisfies ResolvedOllamaConfig;
|
||||||
|
return makeOllamaProviderFromClient(
|
||||||
|
resolved,
|
||||||
|
new Ollama({ host: resolved.host }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeOllamaProviderEffect = Effect.fn("makeOllamaProvider")(function*(
|
export const makeOllamaProviderEffect = Effect.fn("makeOllamaProvider")(function*(
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,17 @@ const makeOpenAICompatibleProviderFromClient = (
|
||||||
export function makeOpenAICompatibleProvider(
|
export function makeOpenAICompatibleProvider(
|
||||||
config: OpenAICompatibleProcessorConfig,
|
config: OpenAICompatibleProcessorConfig,
|
||||||
): LlmProvider<TextCompletionRuntimeError> {
|
): LlmProvider<TextCompletionRuntimeError> {
|
||||||
return Effect.runSync(makeOpenAICompatibleProviderEffect(config));
|
const resolved = {
|
||||||
|
defaultModel: config.model ?? "default",
|
||||||
|
defaultTemperature: config.temperature ?? 0.0,
|
||||||
|
maxOutput: config.maxOutput ?? 4096,
|
||||||
|
apiKey: config.apiKey ?? "sk-no-key-required",
|
||||||
|
baseURL: config.baseUrl ?? "http://localhost:1234/v1",
|
||||||
|
} satisfies ResolvedOpenAICompatibleConfig;
|
||||||
|
return makeOpenAICompatibleProviderFromClient(
|
||||||
|
resolved,
|
||||||
|
new OpenAI({ baseURL: resolved.baseURL, apiKey: resolved.apiKey }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeOpenAICompatibleProviderEffect = Effect.fn("makeOpenAICompatibleProvider")(function*(
|
export const makeOpenAICompatibleProviderEffect = Effect.fn("makeOpenAICompatibleProvider")(function*(
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,20 @@ const makeOpenAIProviderFromClient = (
|
||||||
export function makeOpenAIProvider(
|
export function makeOpenAIProvider(
|
||||||
config: OpenAIProcessorConfig,
|
config: OpenAIProcessorConfig,
|
||||||
): LlmProvider<TextCompletionRuntimeError> {
|
): LlmProvider<TextCompletionRuntimeError> {
|
||||||
return Effect.runSync(makeOpenAIProviderEffect(config));
|
const resolved = {
|
||||||
|
defaultModel: config.model ?? "gpt-4o",
|
||||||
|
defaultTemperature: config.temperature ?? 0.0,
|
||||||
|
maxOutput: config.maxOutput ?? 4096,
|
||||||
|
apiKey: config.apiKey ?? "",
|
||||||
|
baseURL: config.baseUrl,
|
||||||
|
} satisfies ResolvedOpenAIConfig;
|
||||||
|
return makeOpenAIProviderFromClient(
|
||||||
|
resolved,
|
||||||
|
new OpenAI({
|
||||||
|
apiKey: resolved.apiKey,
|
||||||
|
baseURL: resolved.baseURL,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeOpenAIProviderEffect = Effect.fn("makeOpenAIProvider")(function*(
|
export const makeOpenAIProviderEffect = Effect.fn("makeOpenAIProvider")(function*(
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,6 @@ export function makePromptTemplateService(config: PromptTemplateConfig): PromptT
|
||||||
for (const handler of runtime.configHandlers) {
|
for (const handler of runtime.configHandlers) {
|
||||||
service.registerConfigHandler(handler);
|
service.registerConfigHandler(handler);
|
||||||
}
|
}
|
||||||
Effect.runSync(Effect.log("[PromptTemplate] Service initialized"));
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1269,10 +1269,6 @@ export const loadTrustGraphMcpConfig = Effect.fn("loadTrustGraphMcpConfig")(func
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const resolveTrustGraphMcpConfig = (
|
|
||||||
options: TrustGraphMcpOptions = {},
|
|
||||||
): TrustGraphMcpConfigShape => Effect.runSync(loadTrustGraphMcpConfig(options))
|
|
||||||
|
|
||||||
export class TrustGraphMcpConfig extends Context.Service<TrustGraphMcpConfig, TrustGraphMcpConfigShape>()(
|
export class TrustGraphMcpConfig extends Context.Service<TrustGraphMcpConfig, TrustGraphMcpConfigShape>()(
|
||||||
"@trustgraph/mcp/server-effect/TrustGraphMcpConfig",
|
"@trustgraph/mcp/server-effect/TrustGraphMcpConfig",
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -566,13 +566,11 @@ function parseConfigValue(value: unknown): unknown {
|
||||||
return typeof value === "string" ? parseJsonUnknown(value) ?? value : value;
|
return typeof value === "string" ? parseJsonUnknown(value) ?? value : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseConfigEntries<T>(raw: unknown, label: string): T[] {
|
function parseConfigEntries<T>(raw: unknown): T[] {
|
||||||
const entries: T[] = [];
|
const entries: T[] = [];
|
||||||
for (const item of mapConfigEntries(raw)) {
|
for (const item of mapConfigEntries(raw)) {
|
||||||
const config = parseJsonUnknown(item.value);
|
const config = parseJsonUnknown(item.value);
|
||||||
if (config === undefined) {
|
if (config !== undefined) {
|
||||||
Effect.runSync(Effect.logWarning(`[workbench-atoms] Failed to parse ${label}: ${item.key}`));
|
|
||||||
} else {
|
|
||||||
entries.push({ key: item.key, config } as T);
|
entries.push({ key: item.key, config } as T);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1751,7 +1749,7 @@ export const mcpServersAtom = queryAtom(
|
||||||
"mcpServers",
|
"mcpServers",
|
||||||
Effect.fn("trustgraph.workbench.mcpServers")(function*(_get, api) {
|
Effect.fn("trustgraph.workbench.mcpServers")(function*(_get, api) {
|
||||||
const values = yield* api.config().getValues("mcp");
|
const values = yield* api.config().getValues("mcp");
|
||||||
return parseConfigEntries<McpServerEntry>(values, "MCP server config");
|
return parseConfigEntries<McpServerEntry>(values);
|
||||||
}),
|
}),
|
||||||
{ reactivityKeys: ["config", "mcp"] },
|
{ reactivityKeys: ["config", "mcp"] },
|
||||||
).pipe(Atom.setIdleTTL("2 minutes"));
|
).pipe(Atom.setIdleTTL("2 minutes"));
|
||||||
|
|
@ -1760,7 +1758,7 @@ export const mcpToolsAtom = queryAtom(
|
||||||
"mcpTools",
|
"mcpTools",
|
||||||
Effect.fn("trustgraph.workbench.mcpTools")(function*(_get, api) {
|
Effect.fn("trustgraph.workbench.mcpTools")(function*(_get, api) {
|
||||||
const values = yield* api.config().getValues("tool");
|
const values = yield* api.config().getValues("tool");
|
||||||
return parseConfigEntries<ToolEntry>(values, "tool config");
|
return parseConfigEntries<ToolEntry>(values);
|
||||||
}),
|
}),
|
||||||
{ reactivityKeys: ["config", "tool"] },
|
{ reactivityKeys: ["config", "tool"] },
|
||||||
).pipe(Atom.setIdleTTL("2 minutes"));
|
).pipe(Atom.setIdleTTL("2 minutes"));
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import {
|
||||||
ErrorBoundary as ReactErrorBoundary,
|
ErrorBoundary as ReactErrorBoundary,
|
||||||
} from "react-error-boundary";
|
} from "react-error-boundary";
|
||||||
import { AlertTriangle, RefreshCw } from "lucide-react";
|
import { AlertTriangle, RefreshCw } from "lucide-react";
|
||||||
import { Effect } from "effect";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|
@ -46,9 +45,6 @@ export function ErrorBoundary({ children, fallback }: Props) {
|
||||||
return (
|
return (
|
||||||
<ReactErrorBoundary
|
<ReactErrorBoundary
|
||||||
fallbackRender={(props) => fallback ?? <DefaultFallback {...props} />}
|
fallbackRender={(props) => fallback ?? <DefaultFallback {...props} />}
|
||||||
onError={(error, info) => {
|
|
||||||
Effect.runSync(Effect.logError("[ErrorBoundary]", { error, componentStack: info.componentStack }));
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ReactErrorBoundary>
|
</ReactErrorBoundary>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { BaseApi, DocumentMetadata, ProcessingMetadata, StreamingMetadata, Triple } from "@trustgraph/client";
|
import type { BaseApi, DocumentMetadata, ProcessingMetadata, StreamingMetadata, Triple } from "@trustgraph/client";
|
||||||
import { makeBaseApiWithRpc, } from "@trustgraph/client";
|
import { makeBaseApiWithRpc, } from "@trustgraph/client";
|
||||||
import { Clock, Effect, Match, Option, Schema as S } from "effect";
|
import { Match, Option, Schema as S } from "effect";
|
||||||
|
|
||||||
type ConfigValues = Record<string, Record<string, unknown>>;
|
type ConfigValues = Record<string, Record<string, unknown>>;
|
||||||
|
|
||||||
|
|
@ -324,7 +324,7 @@ function configValues(state: MockState, type: string) {
|
||||||
|
|
||||||
function addDocument(state: MockState, metadata: DocumentMetadata): DocumentMetadata {
|
function addDocument(state: MockState, metadata: DocumentMetadata): DocumentMetadata {
|
||||||
const id = metadata.id ?? `qa-doc-${state.library.documents.length + 1}`;
|
const id = metadata.id ?? `qa-doc-${state.library.documents.length + 1}`;
|
||||||
const currentTimeSeconds = Math.floor(Effect.runSync(Clock.currentTimeMillis) / 1000);
|
const currentTimeSeconds = state.library.documents.length + 1;
|
||||||
const document = {
|
const document = {
|
||||||
...metadata,
|
...metadata,
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"exemptions":[],"baseline":[{"rule":"no-effect-run","path":"packages/base/src/processor/async-processor.ts","count":1},{"rule":"no-effect-run","path":"packages/client/src/socket/effect-rpc-client.ts","count":10},{"rule":"no-effect-run","path":"packages/client/src/socket/trustgraph-socket.ts","count":9},{"rule":"no-effect-run","path":"packages/flow/src/agent/mcp-tool/service.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/agent/react/service.ts","count":2},{"rule":"no-effect-run","path":"packages/flow/src/chunking/service.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/decoding/pdf-decoder.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/embeddings/ollama.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/extract/knowledge-extract.ts","count":4},{"rule":"no-effect-run","path":"packages/flow/src/librarian/service.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/model/text-completion/azure-openai.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/model/text-completion/claude.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/model/text-completion/mistral.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/model/text-completion/ollama.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/model/text-completion/openai-compatible.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/model/text-completion/openai.ts","count":1},{"rule":"no-effect-run","path":"packages/flow/src/prompt/template.ts","count":1},{"rule":"no-effect-run","path":"packages/mcp/src/server-effect.ts","count":1},{"rule":"no-effect-run","path":"packages/workbench/src/atoms/workbench.ts","count":1},{"rule":"no-effect-run","path":"packages/workbench/src/components/error-boundary.tsx","count":1},{"rule":"no-effect-run","path":"packages/workbench/src/qa/mock-api.ts","count":1},{"rule":"no-error-throw","path":"packages/workbench/src/main.tsx","count":1},{"rule":"no-error-throw","path":"scripts/seed-config.ts","count":1},{"rule":"no-error-throw","path":"scripts/seed-demo.ts","count":4},{"rule":"no-error-throw","path":"scripts/seed-flows.ts","count":2},{"rule":"no-error-throw","path":"scripts/test-pipeline.ts","count":2},{"rule":"no-native-fetch","path":"scripts/seed-config.ts","count":1},{"rule":"no-native-fetch","path":"scripts/seed-demo.ts","count":11},{"rule":"no-native-fetch","path":"scripts/seed-flows.ts","count":1},{"rule":"no-native-fetch","path":"scripts/test-pipeline.ts","count":5},{"rule":"no-native-json","path":"scripts/seed-config.ts","count":6},{"rule":"no-native-json","path":"scripts/seed-demo.ts","count":6},{"rule":"no-native-json","path":"scripts/seed-flows.ts","count":3},{"rule":"no-native-json","path":"scripts/test-pipeline.ts","count":6},{"rule":"no-native-sort","path":"packages/client/src/socket/trustgraph-socket.ts","count":2},{"rule":"no-native-sort","path":"packages/flow/src/config/service.ts","count":3},{"rule":"no-native-sort","path":"packages/flow/src/cores/service.ts","count":1},{"rule":"no-native-sort","path":"packages/flow/src/flow-manager/service.ts","count":1},{"rule":"no-native-sort","path":"packages/flow/src/librarian/service.ts","count":1},{"rule":"no-native-sort","path":"packages/flow/src/retrieval/graph-rag.ts","count":1},{"rule":"no-native-sort","path":"packages/workbench/src/atoms/workbench.ts","count":2},{"rule":"no-native-sort","path":"packages/workbench/src/components/chat/explain-graph.tsx","count":1},{"rule":"no-native-sort","path":"packages/workbench/src/pages/graph.tsx","count":1},{"rule":"no-native-sort","path":"packages/workbench/src/qa/mock-api.ts","count":1},{"rule":"no-native-sort","path":"scripts/inventory-native-classes.ts","count":1},{"rule":"no-native-sort","path":"scripts/seed-demo.ts","count":1},{"rule":"no-native-sort","path":"scripts/seed-flows.ts","count":1},{"rule":"no-native-timers","path":"scripts/test-pipeline.ts","count":2},{"rule":"no-node-fs-path","path":"scripts/create-test-pdf.ts","count":1},{"rule":"no-node-fs-path","path":"scripts/inventory-native-classes.ts","count":2},{"rule":"no-process-env","path":"scripts/seed-config.ts","count":2},{"rule":"no-process-env","path":"scripts/seed-demo.ts","count":5},{"rule":"no-process-env","path":"scripts/seed-flows.ts","count":1},{"rule":"no-process-env","path":"scripts/test-pipeline.ts","count":11},{"rule":"no-schema-suffix","path":"packages/base/src/schema/primitives.ts","count":1},{"rule":"schema-first-data","path":"packages/client/src/models/Triple.ts","count":6},{"rule":"schema-first-data","path":"packages/client/src/models/messages.ts","count":58},{"rule":"schema-first-data","path":"packages/client/src/socket/effect-rpc-client.ts","count":2},{"rule":"schema-first-data","path":"packages/client/src/socket/trustgraph-socket.ts","count":4}]}
|
{"exemptions":[],"baseline":[{"rule":"no-effect-run","path":"packages/client/src/socket/effect-rpc-client.ts","count":10},{"rule":"no-effect-run","path":"packages/client/src/socket/trustgraph-socket.ts","count":9},{"rule":"no-error-throw","path":"packages/workbench/src/main.tsx","count":1},{"rule":"no-error-throw","path":"scripts/seed-config.ts","count":1},{"rule":"no-error-throw","path":"scripts/seed-demo.ts","count":4},{"rule":"no-error-throw","path":"scripts/seed-flows.ts","count":2},{"rule":"no-error-throw","path":"scripts/test-pipeline.ts","count":2},{"rule":"no-native-fetch","path":"scripts/seed-config.ts","count":1},{"rule":"no-native-fetch","path":"scripts/seed-demo.ts","count":11},{"rule":"no-native-fetch","path":"scripts/seed-flows.ts","count":1},{"rule":"no-native-fetch","path":"scripts/test-pipeline.ts","count":5},{"rule":"no-native-json","path":"scripts/seed-config.ts","count":6},{"rule":"no-native-json","path":"scripts/seed-demo.ts","count":6},{"rule":"no-native-json","path":"scripts/seed-flows.ts","count":3},{"rule":"no-native-json","path":"scripts/test-pipeline.ts","count":6},{"rule":"no-native-sort","path":"packages/client/src/socket/trustgraph-socket.ts","count":2},{"rule":"no-native-sort","path":"packages/flow/src/config/service.ts","count":3},{"rule":"no-native-sort","path":"packages/flow/src/cores/service.ts","count":1},{"rule":"no-native-sort","path":"packages/flow/src/flow-manager/service.ts","count":1},{"rule":"no-native-sort","path":"packages/flow/src/librarian/service.ts","count":1},{"rule":"no-native-sort","path":"packages/flow/src/retrieval/graph-rag.ts","count":1},{"rule":"no-native-sort","path":"packages/workbench/src/atoms/workbench.ts","count":2},{"rule":"no-native-sort","path":"packages/workbench/src/components/chat/explain-graph.tsx","count":1},{"rule":"no-native-sort","path":"packages/workbench/src/pages/graph.tsx","count":1},{"rule":"no-native-sort","path":"packages/workbench/src/qa/mock-api.ts","count":1},{"rule":"no-native-sort","path":"scripts/inventory-native-classes.ts","count":1},{"rule":"no-native-sort","path":"scripts/seed-demo.ts","count":1},{"rule":"no-native-sort","path":"scripts/seed-flows.ts","count":1},{"rule":"no-native-timers","path":"scripts/test-pipeline.ts","count":2},{"rule":"no-node-fs-path","path":"scripts/create-test-pdf.ts","count":1},{"rule":"no-node-fs-path","path":"scripts/inventory-native-classes.ts","count":2},{"rule":"no-process-env","path":"scripts/seed-config.ts","count":2},{"rule":"no-process-env","path":"scripts/seed-demo.ts","count":5},{"rule":"no-process-env","path":"scripts/seed-flows.ts","count":1},{"rule":"no-process-env","path":"scripts/test-pipeline.ts","count":11},{"rule":"no-schema-suffix","path":"packages/base/src/schema/primitives.ts","count":1},{"rule":"schema-first-data","path":"packages/client/src/models/Triple.ts","count":6},{"rule":"schema-first-data","path":"packages/client/src/models/messages.ts","count":58},{"rule":"schema-first-data","path":"packages/client/src/socket/effect-rpc-client.ts","count":2},{"rule":"schema-first-data","path":"packages/client/src/socket/trustgraph-socket.ts","count":4}]}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue