/** Harness configuration and identity loading for the shared index client. */ import { PatternIndexClient } from "@commonfabric/pattern-index/client"; import type { HarnessPatternIndexConfig } from "../config.ts"; import type { HarnessFetch } from "../contracts/http-fetch.ts"; import { loadHarnessIdentity } from "../identity-key.ts"; /** * Builds the run's pattern-index client. The engine caches a healthy result * so a factory is called at most once per run; a construction failure * surfaces as an ordinary tool-output error, and the next tool call invokes * the factory again. */ export type HarnessPatternIndexClientFactory = () => Promise< PatternIndexClient >; /** * Default factory over `config`. Requests are signed with the run's Fabric * identity — the index authorizes the same principal the run writes to its * space as — so the keyfile path comes from the fabric session config, which * is why a pattern index without one is a configuration error. */ export const createHarnessPatternIndexClientFactory = ( config: HarnessPatternIndexConfig, identityKeyPath: string, fetchFn?: HarnessFetch, ): HarnessPatternIndexClientFactory => async () => { const identity = await loadHarnessIdentity(identityKeyPath); return new PatternIndexClient({ baseUrl: config.baseUrl, signer: identity, ...(fetchFn !== undefined ? { fetchFn } : {}), }); }; /** * Wraps `factory` so a healthy client is built once and shared by every * invocation in the run. An in-flight construction is shared too, but a * REJECTED construction clears the cache: the failure still reaches every * caller awaiting it, and the next tool call invokes the factory again rather * than replaying a terminal failure for the rest of the run. */ export const cacheHarnessPatternIndexClientFactory = ( factory: HarnessPatternIndexClientFactory, ): HarnessPatternIndexClientFactory => { let client: Promise | undefined; return () => { if (client === undefined) { const attempt: Promise = Promise.resolve() .then(factory) .catch((error) => { if (client === attempt) { client = undefined; } throw error; }); client = attempt; } return client; }; };