import { AgentCard } from '../types.js'; import { A2AStreamEventData } from './client.js'; import { Client } from './multitransport-client.js'; import { RequestOptions } from './multitransport-client.js'; export interface CallInterceptor { /** * Invoked before transport method. */ before(args: BeforeArgs): Promise; /** * Invoked after transport method. */ after(args: AfterArgs): Promise; } export interface BeforeArgs { /** * Identifies the client method invoked and its payload. * Payload inside the input object can be modified. */ readonly input: ClientCallInput; /** * Identifies the agent card cached on the client */ readonly agentCard: AgentCard; /** * If set by the interceptor, stops execution, invokes "after" * for executed interceptors and returns the result. Transport is not called. */ earlyReturn?: ClientCallResult; /** * Options passed to the client. */ options?: RequestOptions; } export interface AfterArgs { /** * Identifies the client method invoked and its result. * Payload inside the result object can be modified. */ readonly result: ClientCallResult; /** * Identifies the agent card cached on the client */ readonly agentCard: AgentCard; /** * If set by the interceptor, stops execution and returns result value, * remaining interceptors are not executed. */ earlyReturn?: boolean; /** * Options passed to the client. */ options?: RequestOptions; } export type ClientCallInput = MethodInput; export type ClientCallResult = MethodResult< Client, K, ResultsOverrides >; // Types below are helper types and are not exported to allow simplifying it without affecting // public API if necessary. They are exported via type aliases ClientXxx which can be replaced with explicit union if necessary. /** * For * * interface Foo { * f1(arg: string): Promise; * f2(arg: number): Promise; * } * * MethodInputs resolves to * * { * readonly method: "f1"; * value: string; * } | { * readonly method: "f2"; * value: number; * } */ type MethodInput = { [M in TMembers]: T[M] extends (options: RequestOptions | undefined) => unknown ? { readonly method: M; value?: never } : T[M] extends (payload: infer P) => unknown ? { readonly method: M; value: P } : never; }[TMembers]; /** * For * * interface Foo { * f1(): Promise; * f2(): Promise; * } * * MethodsResults resolves to * * { * readonly method: "f1"; * value: Result1; * } | { * readonly method: "f2"; * value: Result2; * } */ type MethodResult = { [M in TMembers]: M extends keyof TOverrides // If there is an override, use it directly. ? { readonly method: M; value: TOverrides[M] } : // Infer result, unwrap it from Promise and pack with method name. T[M] extends (payload: unknown) => infer R ? { readonly method: M; value: Awaited } : never; }[TMembers]; interface ResultsOverrides { // sendMessageStream and resubscribeTask return async iterators and are intercepted on each item, // which requires custom handling. sendMessageStream: A2AStreamEventData; resubscribeTask: A2AStreamEventData; }