@librechat/agents 3.4.0 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +165 -57
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +81 -33
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs +14 -0
- package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs.map +1 -0
- package/dist/cjs/graphs/createGraph.cjs +15 -0
- package/dist/cjs/graphs/createGraph.cjs.map +1 -0
- package/dist/cjs/graphs/index.cjs +1 -0
- package/dist/cjs/hooks/HookRegistry.cjs +83 -0
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
- package/dist/cjs/hooks/executeHooks.cjs +60 -14
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +2 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +3 -3
- package/dist/cjs/llm/invoke.cjs +2 -2
- package/dist/cjs/main.cjs +34 -24
- package/dist/cjs/messages/format.cjs +40 -23
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +130 -53
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +37 -2
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/summarization/node.cjs +6 -3
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +1 -1
- package/dist/cjs/tools/SubagentTool.cjs +4 -4
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +321 -95
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +1 -1
- package/dist/cjs/tools/eagerEventExecution.cjs +1 -0
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +2 -2
- package/dist/cjs/tools/search/rerankers.cjs +154 -1
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +4 -1
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +601 -0
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1114 -233
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +177 -0
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -0
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +278 -0
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -0
- package/dist/cjs/tools/subagent/index.cjs +1 -0
- package/dist/cjs/tools/subagent/runtimeLimits.cjs +5 -0
- package/dist/cjs/tools/subagent/runtimeLimits.cjs.map +1 -0
- package/dist/cjs/tools/toolOutputReferences.cjs +20 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +2 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +165 -57
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +81 -33
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/graphs/applyGraphRuntimeConfig.mjs +14 -0
- package/dist/esm/graphs/applyGraphRuntimeConfig.mjs.map +1 -0
- package/dist/esm/graphs/createGraph.mjs +15 -0
- package/dist/esm/graphs/createGraph.mjs.map +1 -0
- package/dist/esm/graphs/index.mjs +1 -0
- package/dist/esm/hooks/HookRegistry.mjs +83 -0
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
- package/dist/esm/hooks/executeHooks.mjs +60 -14
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +2 -1
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +2 -2
- package/dist/esm/main.mjs +21 -19
- package/dist/esm/messages/format.mjs +40 -23
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +131 -54
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +37 -2
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +2 -2
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/summarization/node.mjs +6 -3
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +1 -1
- package/dist/esm/tools/SubagentTool.mjs +4 -4
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +322 -96
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +1 -1
- package/dist/esm/tools/eagerEventExecution.mjs +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +2 -2
- package/dist/esm/tools/search/rerankers.mjs +154 -1
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +4 -1
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +597 -0
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1114 -233
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +170 -0
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -0
- package/dist/esm/tools/subagent/childGraphConfig.mjs +272 -0
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -0
- package/dist/esm/tools/subagent/index.mjs +1 -0
- package/dist/esm/tools/subagent/runtimeLimits.mjs +5 -0
- package/dist/esm/tools/subagent/runtimeLimits.mjs.map +1 -0
- package/dist/esm/tools/toolOutputReferences.mjs +20 -0
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +2 -2
- package/dist/types/agents/AgentContext.d.ts +1 -1
- package/dist/types/graphs/Graph.d.ts +22 -2
- package/dist/types/graphs/MultiAgentGraph.d.ts +7 -1
- package/dist/types/graphs/applyGraphRuntimeConfig.d.ts +3 -0
- package/dist/types/graphs/createGraph.d.ts +13 -0
- package/dist/types/graphs/graphFactory.d.ts +13 -0
- package/dist/types/graphs/index.d.ts +2 -0
- package/dist/types/hooks/HookRegistry.d.ts +10 -1
- package/dist/types/hooks/executeHooks.d.ts +5 -1
- package/dist/types/hooks/index.d.ts +2 -2
- package/dist/types/hooks/types.d.ts +12 -0
- package/dist/types/run.d.ts +6 -3
- package/dist/types/session/AgentSession.d.ts +1 -0
- package/dist/types/tools/SubagentTool.d.ts +1 -1
- package/dist/types/tools/ToolNode.d.ts +23 -15
- package/dist/types/tools/search/rerankers.d.ts +28 -0
- package/dist/types/tools/search/types.d.ts +38 -1
- package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +171 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +70 -36
- package/dist/types/tools/subagent/SubagentReplay.d.ts +85 -0
- package/dist/types/tools/subagent/childGraphConfig.d.ts +37 -0
- package/dist/types/tools/subagent/index.d.ts +1 -1
- package/dist/types/tools/subagent/runtimeLimits.d.ts +4 -0
- package/dist/types/tools/toolOutputReferences.d.ts +12 -0
- package/dist/types/types/graph.d.ts +189 -24
- package/dist/types/types/hitl.d.ts +15 -0
- package/package.json +8 -2
- package/src/agents/AgentContext.ts +1 -1
- package/src/graphs/Graph.ts +349 -104
- package/src/graphs/MultiAgentGraph.ts +149 -47
- package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +48 -9
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1 -1
- package/src/graphs/__tests__/Graph.subagentResumeState.test.ts +80 -0
- package/src/graphs/__tests__/MultiAgentGraph.test.ts +86 -0
- package/src/graphs/__tests__/composition.smoke.test.ts +152 -0
- package/src/graphs/__tests__/createGraph.test.ts +206 -0
- package/src/graphs/applyGraphRuntimeConfig.ts +25 -0
- package/src/graphs/createGraph.ts +32 -0
- package/src/graphs/graphFactory.ts +12 -0
- package/src/graphs/index.ts +2 -0
- package/src/hooks/HookRegistry.ts +151 -1
- package/src/hooks/__tests__/HookRegistry.test.ts +96 -0
- package/src/hooks/__tests__/executeHooks.test.ts +160 -0
- package/src/hooks/executeHooks.ts +133 -15
- package/src/hooks/index.ts +3 -1
- package/src/hooks/types.ts +16 -0
- package/src/messages/format.ts +54 -26
- package/src/messages/formatAgentMessages.reducer.test.ts +162 -0
- package/src/messages/formatAgentMessages.steer.test.ts +16 -11
- package/src/messages/formatAgentMessages.test.ts +7 -2
- package/src/run.ts +214 -56
- package/src/session/AgentSession.ts +52 -2
- package/src/session/__tests__/JsonlSessionStore.test.ts +53 -0
- package/src/specs/graph-subagent.live.test.ts +242 -0
- package/src/specs/graph-subagent.test.ts +322 -0
- package/src/specs/langfuse-routing.integration.test.ts +120 -1
- package/src/specs/subagent.test.ts +130 -4
- package/src/summarization/__tests__/node.test.ts +32 -14
- package/src/summarization/node.ts +15 -11
- package/src/tools/SubagentTool.ts +4 -4
- package/src/tools/ToolNode.ts +643 -157
- package/src/tools/__tests__/SubagentExecutor.test.ts +740 -15
- package/src/tools/__tests__/SubagentReplay.test.ts +329 -0
- package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +208 -2
- package/src/tools/__tests__/directToolHITLResumeScope.test.ts +512 -2
- package/src/tools/__tests__/hitl.test.ts +234 -5
- package/src/tools/__tests__/subagentHooks.test.ts +1126 -61
- package/src/tools/__tests__/toolOutputReferences.test.ts +19 -2
- package/src/tools/search/rag-api-reranker.test.ts +891 -0
- package/src/tools/search/rerankers.ts +260 -0
- package/src/tools/search/tool.ts +6 -0
- package/src/tools/search/types.ts +45 -1
- package/src/tools/subagent/SubagentExecutionRegistry.ts +1159 -0
- package/src/tools/subagent/SubagentExecutor.ts +2232 -312
- package/src/tools/subagent/SubagentReplay.ts +584 -0
- package/src/tools/subagent/__tests__/SubagentExecutionRegistry.test.ts +637 -0
- package/src/tools/subagent/__tests__/SubagentExecutor.lazy.test.ts +3054 -0
- package/src/tools/subagent/__tests__/childGraphConfig.test.ts +521 -0
- package/src/tools/subagent/childGraphConfig.ts +694 -0
- package/src/tools/subagent/index.ts +6 -0
- package/src/tools/subagent/runtimeLimits.ts +7 -0
- package/src/tools/toolOutputReferences.ts +40 -1
- package/src/types/graph.ts +222 -24
- package/src/types/hitl.ts +16 -0
|
@@ -225,6 +225,250 @@ export class CohereReranker extends BaseReranker {
|
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/** rag_api's `/v1/rerank` contract caps candidates at 50 and `top_n` at 25;
|
|
229
|
+
* violating either is a client bug, not a server error, so both are clamped
|
|
230
|
+
* locally with a debug log instead of erroring. */
|
|
231
|
+
const RAG_API_MAX_CANDIDATES = 50;
|
|
232
|
+
const RAG_API_MAX_TOP_N = 25;
|
|
233
|
+
const RAG_API_DEFAULT_PROFILE = 'fast-v1';
|
|
234
|
+
|
|
235
|
+
const getDefaultRagApiUrl = (): string | undefined =>
|
|
236
|
+
process.env.RAG_API_URL != null && process.env.RAG_API_URL !== ''
|
|
237
|
+
? process.env.RAG_API_URL
|
|
238
|
+
: undefined;
|
|
239
|
+
|
|
240
|
+
const toRagApiCandidate = (
|
|
241
|
+
text: string,
|
|
242
|
+
index: number
|
|
243
|
+
): t.RagApiRerankCandidate => ({ id: String(index), text, base_score: 0 });
|
|
244
|
+
|
|
245
|
+
/** A single source split into overlapping chunks routinely exceeds the
|
|
246
|
+
* contract limit, so documents are capped before any candidate is built:
|
|
247
|
+
* only the submittable window is ever allocated. */
|
|
248
|
+
const buildRagApiCandidates = (
|
|
249
|
+
documents: string[],
|
|
250
|
+
logger: t.Logger
|
|
251
|
+
): t.RagApiRerankCandidate[] => {
|
|
252
|
+
if (documents.length <= RAG_API_MAX_CANDIDATES) {
|
|
253
|
+
return documents.map(toRagApiCandidate);
|
|
254
|
+
}
|
|
255
|
+
logger.debug(
|
|
256
|
+
`rag_api fast-v1 accepts at most ${RAG_API_MAX_CANDIDATES} candidates; truncating ${documents.length} to ${RAG_API_MAX_CANDIDATES}.`
|
|
257
|
+
);
|
|
258
|
+
return documents.slice(0, RAG_API_MAX_CANDIDATES).map(toRagApiCandidate);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const clampRagApiTopN = (topN: number, logger: t.Logger): number => {
|
|
262
|
+
if (topN <= RAG_API_MAX_TOP_N) {
|
|
263
|
+
return topN;
|
|
264
|
+
}
|
|
265
|
+
logger.debug(
|
|
266
|
+
`rag_api fast-v1 accepts top_n <= ${RAG_API_MAX_TOP_N}; clamping ${topN} to ${RAG_API_MAX_TOP_N}.`
|
|
267
|
+
);
|
|
268
|
+
return RAG_API_MAX_TOP_N;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/** Deterministic tie ordering: rank by score descending, breaking ties on
|
|
272
|
+
* original candidate index rather than relying on rag_api's response order. */
|
|
273
|
+
const sortRagApiResults = (
|
|
274
|
+
results: t.RagApiRerankResult[]
|
|
275
|
+
): t.RagApiRerankResult[] =>
|
|
276
|
+
[...results].sort((a, b) => b.score - a.score || a.index - b.index);
|
|
277
|
+
|
|
278
|
+
/** Indices are only meaningful against the candidates actually submitted:
|
|
279
|
+
* anything beyond `candidateCount` refers to text the server never saw. */
|
|
280
|
+
const isValidRagApiResult = (
|
|
281
|
+
result: t.RagApiRerankResult | undefined,
|
|
282
|
+
candidateCount: number
|
|
283
|
+
): result is t.RagApiRerankResult =>
|
|
284
|
+
result != null &&
|
|
285
|
+
typeof result.index === 'number' &&
|
|
286
|
+
Number.isInteger(result.index) &&
|
|
287
|
+
result.index >= 0 &&
|
|
288
|
+
result.index < candidateCount &&
|
|
289
|
+
typeof result.score === 'number' &&
|
|
290
|
+
Number.isFinite(result.score);
|
|
291
|
+
|
|
292
|
+
/** A repeated index would map one document into several `top_n` slots and
|
|
293
|
+
* silently drop distinct results, so a duplicate invalidates the batch just
|
|
294
|
+
* like any other malformed row. Seen indices are tracked in the same pass
|
|
295
|
+
* that validates each row. */
|
|
296
|
+
const isValidRagApiBatch = (
|
|
297
|
+
results: t.RagApiRerankResult[],
|
|
298
|
+
candidateCount: number
|
|
299
|
+
): boolean => {
|
|
300
|
+
const seenIndices = new Set<number>();
|
|
301
|
+
return results.every((result) => {
|
|
302
|
+
if (!isValidRagApiResult(result, candidateCount)) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
if (seenIndices.has(result.index)) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
seenIndices.add(result.index);
|
|
309
|
+
return true;
|
|
310
|
+
});
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/** Bounds the whole rerank round trip, token acquisition included: the
|
|
314
|
+
* supplier mints its token over the network, so awaiting it before axios
|
|
315
|
+
* starts would leave the search unbounded whenever an auth service stalls.
|
|
316
|
+
* The signal reaches both legs, so returning a fallback also cancels whatever
|
|
317
|
+
* is still in flight rather than leaving a request running past its caller.
|
|
318
|
+
* A non-positive timeout keeps axios' "no timeout" semantics. */
|
|
319
|
+
const withRerankDeadline = <T>(
|
|
320
|
+
operation: (signal?: AbortSignal) => Promise<T>,
|
|
321
|
+
timeout: number
|
|
322
|
+
): Promise<T> => {
|
|
323
|
+
if (timeout <= 0) {
|
|
324
|
+
return operation();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const controller = new AbortController();
|
|
328
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
329
|
+
const deadline = new Promise<never>((_resolve, reject) => {
|
|
330
|
+
timer = setTimeout(() => {
|
|
331
|
+
controller.abort();
|
|
332
|
+
reject(new Error(`rag_api rerank exceeded its ${timeout}ms timeout.`));
|
|
333
|
+
}, timeout);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const pending = operation(controller.signal);
|
|
337
|
+
pending.catch(() => undefined);
|
|
338
|
+
|
|
339
|
+
return Promise.race([pending, deadline]).finally(() => clearTimeout(timer));
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Calls the public `danny-avila/rag_api` `/v1/rerank` endpoint (the
|
|
344
|
+
* `fast-v1` profile). Auth is supplied per call by a token supplier (a
|
|
345
|
+
* short-lived JWT minted by the host app) rather than a static key. A
|
|
346
|
+
* reranker failure must never throw into the search flow: on a missing
|
|
347
|
+
* base URL/token supplier, a timeout (covering token acquisition as well as
|
|
348
|
+
* the request), a non-2xx response, or any malformed payload, this falls back
|
|
349
|
+
* to the candidates' original order via {@link BaseReranker.getDefaultRanking}.
|
|
350
|
+
*/
|
|
351
|
+
export class RagApiReranker extends BaseReranker {
|
|
352
|
+
private baseUrl?: string;
|
|
353
|
+
private tokenSupplier?: t.RagApiTokenSupplier;
|
|
354
|
+
private profile: string;
|
|
355
|
+
private timeout: number;
|
|
356
|
+
private httpAgent?: t.HttpAgent;
|
|
357
|
+
private httpsAgent?: t.HttpsAgent;
|
|
358
|
+
|
|
359
|
+
constructor({
|
|
360
|
+
baseUrl = getDefaultRagApiUrl(),
|
|
361
|
+
tokenSupplier,
|
|
362
|
+
profile = RAG_API_DEFAULT_PROFILE,
|
|
363
|
+
timeout = DEFAULT_RERANKER_TIMEOUT,
|
|
364
|
+
logger,
|
|
365
|
+
httpAgent,
|
|
366
|
+
httpsAgent,
|
|
367
|
+
}: {
|
|
368
|
+
baseUrl?: string;
|
|
369
|
+
tokenSupplier?: t.RagApiTokenSupplier;
|
|
370
|
+
profile?: string;
|
|
371
|
+
timeout?: number;
|
|
372
|
+
logger?: t.Logger;
|
|
373
|
+
} & t.HttpAgentConfig) {
|
|
374
|
+
super(logger);
|
|
375
|
+
this.baseUrl = baseUrl?.replace(/\/+$/, '');
|
|
376
|
+
this.tokenSupplier = tokenSupplier;
|
|
377
|
+
this.profile = profile;
|
|
378
|
+
this.timeout = timeout;
|
|
379
|
+
this.httpAgent = httpAgent;
|
|
380
|
+
this.httpsAgent = httpsAgent;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async rerank(
|
|
384
|
+
query: string,
|
|
385
|
+
documents: string[],
|
|
386
|
+
topK: number = 5
|
|
387
|
+
): Promise<t.Highlight[]> {
|
|
388
|
+
if (documents.length === 0) {
|
|
389
|
+
return [];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
this.logger.debug(
|
|
393
|
+
`Reranking ${documents.length} chunks with rag_api (${this.profile}) using base URL: ${this.baseUrl}`
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
const baseUrl = this.baseUrl;
|
|
397
|
+
if (baseUrl == null || baseUrl === '') {
|
|
398
|
+
this.logger.warn('RAG_API_URL is not set. Using default ranking.');
|
|
399
|
+
return this.getDefaultRanking(documents, topK);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const tokenSupplier = this.tokenSupplier;
|
|
403
|
+
if (tokenSupplier == null) {
|
|
404
|
+
this.logger.warn(
|
|
405
|
+
'No rag_api token supplier configured. Using default ranking.'
|
|
406
|
+
);
|
|
407
|
+
return this.getDefaultRanking(documents, topK);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const candidates = buildRagApiCandidates(documents, this.logger);
|
|
411
|
+
const topN = clampRagApiTopN(Math.max(0, topK), this.logger);
|
|
412
|
+
const requestData: t.RagApiRerankRequestBody = {
|
|
413
|
+
profile: this.profile,
|
|
414
|
+
query,
|
|
415
|
+
candidates,
|
|
416
|
+
top_n: topN,
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
const data = await withRerankDeadline(async (signal) => {
|
|
421
|
+
const token = await tokenSupplier(signal);
|
|
422
|
+
const response = await axios.post<t.RagApiRerankResponse | undefined>(
|
|
423
|
+
`${baseUrl}/v1/rerank`,
|
|
424
|
+
requestData,
|
|
425
|
+
{
|
|
426
|
+
headers: {
|
|
427
|
+
'Content-Type': 'application/json',
|
|
428
|
+
Authorization: `Bearer ${token}`,
|
|
429
|
+
},
|
|
430
|
+
timeout: this.timeout,
|
|
431
|
+
httpAgent: this.httpAgent,
|
|
432
|
+
httpsAgent: this.httpsAgent,
|
|
433
|
+
signal,
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
return response.data;
|
|
437
|
+
}, this.timeout);
|
|
438
|
+
|
|
439
|
+
this.logger.debug('rag_api rerank model:', data?.model);
|
|
440
|
+
|
|
441
|
+
const rawResults = data?.results;
|
|
442
|
+
if (!Array.isArray(rawResults) || rawResults.length === 0) {
|
|
443
|
+
this.logger.warn(
|
|
444
|
+
'Unexpected response format from rag_api rerank. Using default ranking.'
|
|
445
|
+
);
|
|
446
|
+
return this.getDefaultRanking(documents, topK);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (!isValidRagApiBatch(rawResults, candidates.length)) {
|
|
450
|
+
this.logger.warn(
|
|
451
|
+
'rag_api rerank response contained no valid results. Using default ranking.'
|
|
452
|
+
);
|
|
453
|
+
return this.getDefaultRanking(documents, topK);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return sortRagApiResults(rawResults)
|
|
457
|
+
.slice(0, topN)
|
|
458
|
+
.map((result) => ({
|
|
459
|
+
text: documents[result.index],
|
|
460
|
+
score: result.score,
|
|
461
|
+
}));
|
|
462
|
+
} catch (error) {
|
|
463
|
+
this.logger.error(
|
|
464
|
+
'Error using rag_api reranker',
|
|
465
|
+
formatErrorForLog(error)
|
|
466
|
+
);
|
|
467
|
+
return this.getDefaultRanking(documents, topK);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
228
472
|
export class InfinityReranker extends BaseReranker {
|
|
229
473
|
constructor(logger?: t.Logger) {
|
|
230
474
|
super(logger);
|
|
@@ -253,6 +497,9 @@ export const createReranker = (
|
|
|
253
497
|
jinaApiKey?: string;
|
|
254
498
|
jinaApiUrl?: string;
|
|
255
499
|
cohereApiKey?: string;
|
|
500
|
+
ragApiUrl?: string;
|
|
501
|
+
ragApiTokenSupplier?: t.RagApiTokenSupplier;
|
|
502
|
+
ragApiProfile?: string;
|
|
256
503
|
rerankerTimeout?: number;
|
|
257
504
|
logger?: t.Logger;
|
|
258
505
|
} & t.HttpAgentConfig
|
|
@@ -262,6 +509,9 @@ export const createReranker = (
|
|
|
262
509
|
jinaApiKey,
|
|
263
510
|
jinaApiUrl,
|
|
264
511
|
cohereApiKey,
|
|
512
|
+
ragApiUrl,
|
|
513
|
+
ragApiTokenSupplier,
|
|
514
|
+
ragApiProfile,
|
|
265
515
|
rerankerTimeout,
|
|
266
516
|
logger,
|
|
267
517
|
httpAgent,
|
|
@@ -289,6 +539,16 @@ export const createReranker = (
|
|
|
289
539
|
httpAgent,
|
|
290
540
|
httpsAgent,
|
|
291
541
|
});
|
|
542
|
+
case 'rag-api':
|
|
543
|
+
return new RagApiReranker({
|
|
544
|
+
baseUrl: ragApiUrl,
|
|
545
|
+
tokenSupplier: ragApiTokenSupplier,
|
|
546
|
+
profile: ragApiProfile,
|
|
547
|
+
timeout: rerankerTimeout,
|
|
548
|
+
logger: defaultLogger,
|
|
549
|
+
httpAgent,
|
|
550
|
+
httpsAgent,
|
|
551
|
+
});
|
|
292
552
|
case 'infinity':
|
|
293
553
|
return new InfinityReranker(defaultLogger);
|
|
294
554
|
case 'none':
|
package/src/tools/search/tool.ts
CHANGED
|
@@ -452,6 +452,9 @@ export const createSearchTool = (
|
|
|
452
452
|
jinaApiKey,
|
|
453
453
|
jinaApiUrl,
|
|
454
454
|
cohereApiKey,
|
|
455
|
+
ragApiUrl,
|
|
456
|
+
ragApiTokenSupplier,
|
|
457
|
+
ragApiProfile,
|
|
455
458
|
httpAgent,
|
|
456
459
|
httpsAgent,
|
|
457
460
|
onSearchResults: _onSearchResults,
|
|
@@ -571,6 +574,9 @@ export const createSearchTool = (
|
|
|
571
574
|
jinaApiKey,
|
|
572
575
|
jinaApiUrl,
|
|
573
576
|
cohereApiKey,
|
|
577
|
+
ragApiUrl,
|
|
578
|
+
ragApiTokenSupplier,
|
|
579
|
+
ragApiProfile,
|
|
574
580
|
rerankerTimeout,
|
|
575
581
|
httpAgent,
|
|
576
582
|
httpsAgent,
|
|
@@ -32,7 +32,7 @@ export type ScraperProvider =
|
|
|
32
32
|
| 'tavily'
|
|
33
33
|
| 'crw'
|
|
34
34
|
| 'keenable';
|
|
35
|
-
export type RerankerType = 'infinity' | 'jina' | 'cohere' | 'none';
|
|
35
|
+
export type RerankerType = 'infinity' | 'jina' | 'cohere' | 'rag-api' | 'none';
|
|
36
36
|
|
|
37
37
|
export interface Highlight {
|
|
38
38
|
score: number;
|
|
@@ -353,6 +353,41 @@ export interface CohereRerankerResponse {
|
|
|
353
353
|
};
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
/** Mints a short-lived JWT per call; rag_api tokens are never cached or
|
|
357
|
+
* reused across requests by the reranker itself. Receives the rerank
|
|
358
|
+
* deadline's `AbortSignal` so a supplier minting its token over the network
|
|
359
|
+
* can cancel that request when the deadline fires instead of leaving it
|
|
360
|
+
* running past its caller. The argument is optional: zero-argument suppliers
|
|
361
|
+
* remain valid. */
|
|
362
|
+
export type RagApiTokenSupplier = (
|
|
363
|
+
signal?: AbortSignal
|
|
364
|
+
) => string | Promise<string>;
|
|
365
|
+
|
|
366
|
+
export interface RagApiRerankCandidate {
|
|
367
|
+
id: string;
|
|
368
|
+
text: string;
|
|
369
|
+
base_score: number;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface RagApiRerankRequestBody {
|
|
373
|
+
profile: string;
|
|
374
|
+
query: string;
|
|
375
|
+
candidates: RagApiRerankCandidate[];
|
|
376
|
+
top_n: number;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export interface RagApiRerankResult {
|
|
380
|
+
id: string;
|
|
381
|
+
index: number;
|
|
382
|
+
score: number;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export interface RagApiRerankResponse {
|
|
386
|
+
profile: string;
|
|
387
|
+
model: string;
|
|
388
|
+
results: RagApiRerankResult[];
|
|
389
|
+
}
|
|
390
|
+
|
|
356
391
|
export type SafeSearchLevel = 0 | 1 | 2;
|
|
357
392
|
|
|
358
393
|
export type Logger = WinstonLogger;
|
|
@@ -375,6 +410,15 @@ export interface SearchToolConfig
|
|
|
375
410
|
jinaApiKey?: string;
|
|
376
411
|
jinaApiUrl?: string;
|
|
377
412
|
cohereApiKey?: string;
|
|
413
|
+
/** Base URL of the public `rag_api` service (`RAG_API_URL` env fallback).
|
|
414
|
+
* Requests post to `${ragApiUrl}/v1/rerank`. */
|
|
415
|
+
ragApiUrl?: string;
|
|
416
|
+
/** Resolves a short-lived rag_api JWT immediately before each rerank call.
|
|
417
|
+
* Required for the `'rag-api'` reranker type — without it, reranking falls
|
|
418
|
+
* back to default (unranked) ordering. */
|
|
419
|
+
ragApiTokenSupplier?: RagApiTokenSupplier;
|
|
420
|
+
/** rag_api rerank profile. Defaults to `'fast-v1'`. */
|
|
421
|
+
ragApiProfile?: string;
|
|
378
422
|
rerankerType?: RerankerType;
|
|
379
423
|
/** Timeout (ms) for rerank API requests. Defaults to 10,000. */
|
|
380
424
|
rerankerTimeout?: number;
|