/** * Shared parts of the paper and web-source tools: the off switch, the local * cache folder, API keys, and a fetch that keeps to each service's limits. * * These tools call public services at run time (OpenAlex, arXiv, SportRxiv, * Crossref, the Wayback Machine and the web page asked for). Nothing they fetch * goes into the repository, data/docs.db or a data release: metadata the tools * keep stays in the user's cache folder. */ export declare const USER_AGENT = "football-docs (+https://github.com/withqwerty/football-docs)"; export type Env = Record; export type TextContent = { type: "text"; text: string; }; export type ToolResponse = { isError?: boolean; content: TextContent[]; }; export declare function textResult(text: string, isError?: boolean): ToolResponse; /** Everything a paper tool touches outside the process. Tests replace each part. */ export type PaperContext = { env: Env; fetchImpl: typeof fetch; cacheDir: string; /** Wait before a call to a service with a minimum interval (arXiv). */ sleep: (ms: number) => Promise; now: () => number; /** Look up a key in the system keychain. Returns null when there is none. */ keychain: (name: string) => Promise; }; export type PaperOptions = Partial; /** FOOTBALL_DOCS_PAPERS=off turns every outbound paper and web lookup off. */ export declare function papersDisabled(env: Env): boolean; export declare const DISABLED_MESSAGE: string; export declare function defaultCacheDir(env?: Env): string; export declare function contextFrom(options?: PaperOptions): PaperContext; export declare function ensureCacheDir(dir: string): void; export declare function readCacheJson(dir: string, name: string): T | null; /** Write through a temporary file, so a crash never leaves half a file. */ export declare function writeCacheJson(dir: string, name: string, value: unknown): void; /** * Read a key from the environment, else from the keychain: * macOS: security add-generic-password -s football-docs -a NAME -w * Linux: secret-tool store --label=football-docs service football-docs key NAME */ export declare function apiKey(ctx: PaperContext, name: string): Promise; /** Services asked during one tool call, named in its reply. */ export declare class ServiceLog { private readonly entries; ok(service: string, detail?: string): void; failed(service: string, reason: string): void; get failures(): string[]; footer(): string; } export declare class FetchError extends Error { readonly status?: number | undefined; constructor(message: string, status?: number | undefined); } /** Forget the per-host timings. Tests only. */ export declare function resetRateLimits(): void; export declare const MAX_RESPONSE_BYTES: number; /** Read a body, stopping at maxBytes so one huge page cannot fill memory. */ export declare function readCapped(response: Response, maxBytes?: number): Promise; export type GetOptions = { headers?: Record; timeoutMs?: number; }; /** GET a public API. Throws FetchError with the status on a non-2xx reply. */ export declare function getResponse(ctx: PaperContext, url: string, options?: GetOptions): Promise; export declare function getText(ctx: PaperContext, url: string, options?: GetOptions): Promise; export declare function getJson(ctx: PaperContext, url: string, options?: GetOptions): Promise<{ body: T; headers: Headers; }>; export declare function reason(error: unknown): string; /** Strip tags and decode the entities that appear in OAI and API abstracts. */ export declare function plainText(value: string | undefined | null): string; export declare function truncate(text: string, max: number): string;